From f39939673717430f2ac438a9ed7410fadc6e51cd Mon Sep 17 00:00:00 2001 From: Matthias Hertel Date: Thu, 9 Jul 2026 16:48:33 +0200 Subject: [PATCH] Revert "Bump ExecuTorch pack to 1.3.1-rc8 (#14)" This reverts commit 21acbafe17e6a7bbdaf96699c6c110e925cffd9f. --- .github/workflows/Build_RPS_AppKit-E8.yml | 2 +- .github/workflows/Build_RPS_Variants.yml | 2 +- .github/workflows/Test_RPS_SSE-320-U85.yml | 2 +- .../algorithm/ML/ai_layer/ai_layer.clayer.yml | 17 +- .../Documentation/README.md | 28 +- .../LICENSE | 29 + .../PyTorch.ExecuTorch.pdsc | 713 +- .../executorch_selected_kernels/Functions.h | 28 + .../NativeFunctions.h | 20 + ...egisterCodegenUnboxedKernelsEverything.cpp | 49 + .../RegisterCodegenUnboxedKernels_0.cpp | 49 + .../RegisterKernels.h | 22 + .../selected_operators.yaml | 23 + .../include/c10/BUCK | 8 + .../include/c10/TARGETS | 8 + .../include/c10/macros/Export.h | 0 .../include/c10/macros/Macros.h | 0 .../include/c10/targets.bzl | 139 + .../include/c10/util/BFloat16-inl.h | 0 .../include/c10/util/BFloat16-math.h | 0 .../include/c10/util/BFloat16.h | 0 .../include/c10/util/Half-inl.h | 0 .../include/c10/util/Half.h | 0 .../include/c10/util/TypeSafeSignMath.h | 0 .../include/c10/util/bit_cast.h | 0 .../include/c10/util/complex.h | 0 .../include/c10/util/complex_math.h | 35 - .../include/c10/util/complex_utils.h | 0 .../include/c10/util/floating_point_utils.h | 0 .../include/c10/util/irange.h | 0 .../include/c10/util/llvmMathExtras.h | 0 .../include/c10/util/overflows.h | 0 .../include/c10/util/safe_numerics.h | 0 .../executorch/backends/arm/CMakeLists.txt | 115 + .../include/executorch/backends/arm/MODELS.md | 20 + .../include/executorch/backends/arm/README.md | 237 + .../include/executorch/backends/arm/TARGETS | 119 + .../executorch/backends/arm/_passes/TARGETS | 19 + .../backends/arm/_passes/__init__.py | 134 + .../backends/arm/_passes/_debug_passes.py | 58 + .../arm/_passes/annotate_decomposed_matmul.py | 127 + .../_passes/annotate_output_dim_order_pass.py | 26 + .../backends/arm/_passes/arm_pass.py | 95 + .../backends/arm/_passes/arm_pass_manager.py | 462 + .../backends/arm/_passes/arm_pass_utils.py | 281 + .../arm/_passes/broadcast_args_pass.py | 72 + .../backends/arm/_passes/cast_int64_pass.py | 70 + .../arm/_passes/cast_to_int32_pass.py | 67 + .../arm/_passes/conv1d_unsqueeze_pass.py | 98 + .../arm/_passes/convert_elu_params.py | 67 + .../_passes/convert_expand_copy_to_repeat.py | 77 + .../_passes/convert_full_like_to_full_pass.py | 42 + .../convert_int64_const_ops_to_int32.py | 81 + .../convert_int64_output_ops_to_int32.py | 155 + .../arm/_passes/convert_minmax_pass.py | 166 + .../convert_permute_singleton_to_view_pass.py | 64 + .../arm/_passes/convert_split_to_slice.py | 132 + .../arm/_passes/convert_squeezes_to_view.py | 36 + .../arm/_passes/convert_to_clamp_pass.py | 45 + .../arm/_passes/decompose_acosh_pass.py | 77 + .../decompose_adaptive_avg_pool2d_pass.py | 112 + .../_passes/decompose_add_sub_alpha_pass.py | 98 + .../arm/_passes/decompose_addmm_pass.py | 72 + .../arm/_passes/decompose_any_pass.py | 114 + .../_passes/decompose_asin_and_acos_pass.py | 236 + .../arm/_passes/decompose_asinh_pass.py | 74 + .../arm/_passes/decompose_atan_pass.py | 142 + .../arm/_passes/decompose_atanh_pass.py | 86 + .../arm/_passes/decompose_avg_pool2d_pass.py | 154 + .../_passes/decompose_batch_norm_no_stats.py | 233 + .../arm/_passes/decompose_cosh_pass.py | 72 + .../decompose_cosine_similarity_pass.py | 92 + .../arm/_passes/decompose_cumsum_pass.py | 167 + .../arm/_passes/decompose_div_pass.py | 61 + .../arm/_passes/decompose_div_tensor_mode.py | 94 + .../arm/_passes/decompose_elu_pass.py | 107 + .../arm/_passes/decompose_embedding_pass.py | 126 + .../arm/_passes/decompose_expm1_pass.py | 163 + .../_passes/decompose_floor_divide_pass.py | 75 + .../arm/_passes/decompose_gelu_pass.py | 172 + .../arm/_passes/decompose_glu_pass.py | 81 + .../_passes/decompose_grouped_conv_pass.py | 185 + .../arm/_passes/decompose_groupnorm_pass.py | 227 + .../decompose_int16_activation_conv_pass.py | 137 + .../arm/_passes/decompose_int_pow_pass.py | 64 + .../arm/_passes/decompose_layernorm_pass.py | 203 + .../arm/_passes/decompose_leaky_relu_pass.py | 76 + .../decompose_linalg_vector_norm_pass.py | 92 + .../arm/_passes/decompose_linear_pass.py | 109 + .../arm/_passes/decompose_log1p_pass.py | 97 + .../arm/_passes/decompose_logit_pass.py | 119 + .../arm/_passes/decompose_masked_fill_pass.py | 58 + .../decompose_maxpool2d_with_dilation_pass.py | 218 + .../arm/_passes/decompose_meandim_pass.py | 283 + .../backends/arm/_passes/decompose_ne_pass.py | 74 + .../arm/_passes/decompose_quant_nodes.py | 156 + .../arm/_passes/decompose_remainder_pass.py | 70 + .../arm/_passes/decompose_round_pass.py | 96 + .../arm/_passes/decompose_sdpa_pass.py | 36 + .../backends/arm/_passes/decompose_select.py | 75 + .../_passes/decompose_select_scatter_pass.py | 143 + .../arm/_passes/decompose_sign_pass.py | 78 + .../arm/_passes/decompose_silu_pass.py | 41 + .../arm/_passes/decompose_sinh_pass.py | 77 + .../arm/_passes/decompose_softmax_pass.py | 93 + .../decompose_softmax_unstable_pass.py | 86 + .../arm/_passes/decompose_sqrt_pass.py | 53 + .../arm/_passes/decompose_sum_pass.py | 93 + .../arm/_passes/decompose_tan_pass.py | 51 + .../decompose_tosa_unsupported_clamp_pass.py | 97 + .../arm/_passes/decompose_var_pass.py | 109 + .../decorate_fp32_to_int32_casting_pass.py | 88 + .../fold_qdq_with_annotated_qparams_pass.py | 394 + .../arm/_passes/fuse_batch_norm2d_pass.py | 241 + .../arm/_passes/fuse_constant_ops_pass.py | 272 + .../arm/_passes/fuse_duplicate_users_pass.py | 165 + .../_passes/fuse_equal_placeholders_pass.py | 104 + .../_passes/fuse_quantized_activation_pass.py | 80 + .../_passes/fuse_view_copy_transform_pass.py | 14 + ...rt_int32_casts_after_int64_placeholders.py | 130 + .../arm/_passes/insert_rescales_pass.py | 584 + .../backends/arm/_passes/insert_table_ops.py | 305 + .../arm/_passes/match_arg_dtype_pass.py | 104 + .../arm/_passes/match_arg_ranks_pass.py | 114 + .../backends/arm/_passes/mm_to_bmm_pass.py | 104 + .../normalize_while_initial_args_pass.py | 113 + .../arm/_passes/promote_bool_operands_pass.py | 88 + .../backends/arm/_passes/quant_args.py | 125 + .../arm/_passes/remove_getitem_pass.py | 14 + .../arm/_passes/remove_graph_asserts_pass.py | 18 + .../backends/arm/_passes/remove_noop_pass.py | 40 + .../replace_inf_and_limit_values_pass.py | 73 + .../replace_scalar_with_tensor_pass.py | 121 + ...te_bool_bitwise_not_to_logical_not_pass.py | 43 + ...rewrite_bool_to_fp32_cast_via_int8_pass.py | 77 + .../backends/arm/_passes/rewrite_conv_pass.py | 336 + .../backends/arm/_passes/rewrite_matmul.py | 98 + .../backends/arm/_passes/rewrite_upsample.py | 93 + .../arm/_passes/scalars_to_attribute_pass.py | 97 + .../arm/_passes/size_adjust_input_pass.py | 227 + .../arm/_passes/to_tosa_memory_format_pass.py | 454 + .../_passes/unsqueeze_before_repeat_pass.py | 66 + .../unsqueeze_scalar_placeholders_pass.py | 85 + .../executorch/backends/arm/arm_vela.py | 137 + .../backends/arm/common/__init__.py | 4 + .../backends/arm/common/annotation_meta.py | 39 + .../backends/arm/common/arm_compile_spec.py | 271 + .../executorch/backends/arm/common/debug.py | 79 + .../backends/arm/common/pipeline_config.py | 59 + .../executorch/backends/arm/common/type.py | 28 + .../executorch/backends/arm/constants.py | 48 + .../executorch/backends/arm/debug/TARGETS | 14 + .../executorch/backends/arm/debug/__init__.py | 4 + .../executorch/backends/arm/debug/schema.py | 145 + .../backends/arm/ethosu/__init__.py | 11 + .../executorch/backends/arm/ethosu/backend.py | 115 + .../backends/arm/ethosu/compile_spec.py | 117 + .../backends/arm/ethosu/partitioner.py | 35 + .../backends/arm/operator_support/TARGETS | 14 + .../backends/arm/operator_support/__init__.py | 23 + .../clone_dim_order_support.py | 82 + .../operator_support/control_flow_support.py | 162 + .../operator_support/convolution_support.py | 160 + .../arm/operator_support/embedding_support.py | 61 + .../arm/operator_support/ethos_u55_support.py | 598 + .../operator_support/index_select_support.py | 60 + .../operator_support/index_tensor_support.py | 160 + .../arm/operator_support/minmax_support.py | 61 + .../arm/operator_support/pool_2d_support.py | 214 + .../operator_support/reduce_sum_support.py | 76 + .../operator_support/right_shift_support.py | 52 + .../operator_support/slice_copy_support.py | 48 + .../to_dim_order_copy_support.py | 200 + .../tosa_profile_supported_op_lists.py | 251 + .../tosa_supported_operators.py | 748 + .../arm/operator_support/where_support.py | 77 + .../executorch/backends/arm/operators/TARGETS | 40 + .../backends/arm/operators/__init__.py | 71 + .../backends/arm/operators/node_visitor.py | 177 + .../backends/arm/operators/op_abs.py | 59 + .../backends/arm/operators/op_add.py | 60 + .../backends/arm/operators/op_amax.py | 72 + .../backends/arm/operators/op_amin.py | 73 + .../backends/arm/operators/op_any.py | 61 + .../backends/arm/operators/op_avg_pool2d.py | 142 + .../backends/arm/operators/op_bitwise_not.py | 62 + .../backends/arm/operators/op_cat.py | 68 + .../backends/arm/operators/op_ceil.py | 56 + .../backends/arm/operators/op_clamp.py | 118 + .../backends/arm/operators/op_cond_if.py | 56 + .../arm/operators/op_constant_pad_nd.py | 117 + .../backends/arm/operators/op_cos.py | 49 + .../backends/arm/operators/op_eq.py | 64 + .../backends/arm/operators/op_erf.py | 54 + .../backends/arm/operators/op_exp.py | 54 + .../backends/arm/operators/op_floor.py | 56 + .../backends/arm/operators/op_ge.py | 64 + .../backends/arm/operators/op_gt.py | 64 + .../backends/arm/operators/op_index_select.py | 109 + .../backends/arm/operators/op_index_tensor.py | 247 + .../backends/arm/operators/op_le.py | 64 + .../backends/arm/operators/op_log.py | 50 + .../backends/arm/operators/op_logical_not.py | 62 + .../backends/arm/operators/op_lt.py | 64 + .../backends/arm/operators/op_max_pool2d.py | 108 + .../backends/arm/operators/op_maximum.py | 66 + .../backends/arm/operators/op_minimum.py | 67 + .../backends/arm/operators/op_mul.py | 61 + .../backends/arm/operators/op_neg.py | 92 + .../backends/arm/operators/op_permute.py | 150 + .../backends/arm/operators/op_pow.py | 63 + .../backends/arm/operators/op_reciprocal.py | 51 + .../backends/arm/operators/op_repeat.py | 77 + .../arm/operators/op_rshift_tensor.py | 62 + .../backends/arm/operators/op_rsqrt.py | 51 + .../backends/arm/operators/op_sigmoid.py | 50 + .../backends/arm/operators/op_sin.py | 49 + .../backends/arm/operators/op_slice.py | 151 + .../backends/arm/operators/op_sub.py | 63 + .../backends/arm/operators/op_sum.py | 64 + .../backends/arm/operators/op_tanh.py | 51 + .../arm/operators/op_to_dim_order_copy.py | 49 + .../backends/arm/operators/op_tosa_conv2d.py | 139 + .../backends/arm/operators/op_tosa_conv3d.py | 24 + .../arm/operators/op_tosa_depthwise_conv2d.py | 32 + .../backends/arm/operators/op_tosa_matmul.py | 102 + .../backends/arm/operators/op_tosa_rescale.py | 261 + .../backends/arm/operators/op_tosa_resize.py | 124 + .../backends/arm/operators/op_tosa_table.py | 72 + .../arm/operators/op_tosa_transpose.py | 71 + .../backends/arm/operators/op_view.py | 81 + .../backends/arm/operators/op_where.py | 75 + .../backends/arm/operators/op_while.py | 103 + .../operators/operator_validation_utils.py | 201 + .../backends/arm/operators/ops_binary.py | 112 + .../backends/arm/operators/ops_identity.py | 80 + .../executorch/backends/arm/process_node.py | 230 + .../executorch/backends/arm/quantizer/TARGETS | 54 + .../backends/arm/quantizer/__init__.py | 35 + .../backends/arm/quantizer/arm_quantizer.py | 710 + .../arm/quantizer/arm_quantizer_utils.py | 76 + .../arm/quantizer/quantization_annotator.py | 815 + .../arm/quantizer/quantization_config.py | 228 + .../backends/arm/requirements-arm-ethos-u.txt | 6 + .../arm/requirements-arm-models-test.txt | 6 + .../backends/arm/requirements-arm-tosa.txt | 7 + .../backends/arm/requirements-arm-vgf.txt | 8 + .../executorch/backends/arm/runtime/BUCK | 5 + .../backends/arm/runtime/EthosUBackend.cpp | 579 + .../executorch/backends/arm/runtime/TARGETS | 5 + .../backends/arm/runtime/VGFBackend.cpp | 93 +- .../backends/arm/runtime/VGFSetup.cpp | 72 +- .../backends/arm/runtime/VGFSetup.h | 7 +- .../backends/arm/runtime/VelaBinStream.cpp | 6 +- .../backends/arm/runtime/VelaBinStream.h | 0 .../backends/arm/runtime/targets.bzl | 31 + .../arm/scripts/TOSA_minimal_example.ipynb | 266 + .../arm/scripts/build_executor_runner.sh | 197 + .../arm/scripts/build_executor_runner_vkml.sh | 100 + .../backends/arm/scripts/build_executorch.sh | 93 + .../arm/scripts/build_portable_kernels.sh | 7 + .../arm/scripts/collect_testname_resources.py | 194 + .../backends/arm/scripts/corstone_utils.cmake | 463 + .../backends/arm/scripts/fvp_utils.sh | 134 + .../arm/scripts/install_models_for_test.sh | 21 + .../backends/arm/scripts/mlsdk_utils.sh | 258 + .../backends/arm/scripts/parse_test_names.py | 271 + .../backends/arm/scripts/pre-commit | 13 + .../executorch/backends/arm/scripts/pre-push | 215 + .../backends/arm/scripts/run_fvp.sh | 161 + .../backends/arm/scripts/run_vkml.sh | 97 + .../backends/arm/scripts/setup-dev-env.sh | 9 + .../backends/arm/scripts/toolchain_utils.sh | 93 + .../executorch/backends/arm/scripts/utils.sh | 145 + .../backends/arm/scripts/vulkan_utils.sh | 163 + .../executorch/backends/arm/test/.coveragerc | 8 + .../executorch/backends/arm/test/TARGETS | 86 + .../executorch/backends/arm/test/common.py | 302 + .../executorch/backends/arm/test/conftest.py | 134 + .../executorch/backends/arm/test/misc/TARGETS | 16 + .../arm/test/misc/test_bn_relu_folding_qat.py | 124 + .../test/misc/test_call_operator_submodule.py | 72 + .../arm/test/misc/test_compile_spec.py | 55 + .../test/misc/test_conv_relu_residual_add.py | 108 + .../arm/test/misc/test_custom_partition.py | 183 + .../arm/test/misc/test_debug_feats.py | 316 + .../backends/arm/test/misc/test_debug_hook.py | 186 + .../backends/arm/test/misc/test_dim_order.py | 127 + .../misc/test_dw_convs_with_shared_weights.py | 46 + .../test/misc/test_extract_io_params_tosa.py | 92 + .../backends/arm/test/misc/test_int64.py | 112 + .../arm/test/misc/test_lifted_tensor.py | 146 + .../arm/test/misc/test_mixed_type_lowering.py | 83 + .../arm/test/misc/test_model_evaluator.py | 58 + .../arm/test/misc/test_multiple_delegates.py | 53 + .../arm/test/misc/test_multiple_outputs.py | 70 + .../test/misc/test_non_persistent_buffers.py | 49 + .../arm/test/misc/test_outputs_order.py | 122 + ...test_partition_decomposed_quantized_ops.py | 181 + .../test/misc/test_pass_pipeline_config.py | 35 + .../arm/test/misc/test_pass_required_order.py | 97 + .../arm/test/misc/test_qat_training_loop.py | 100 + .../arm/test/misc/test_quant_custom_meta.py | 105 + .../arm/test/misc/test_rescale_range.py | 130 + .../arm/test/misc/test_save_exported_model.py | 64 + .../arm/test/misc/test_tosa_dialect_conv2d.py | 220 + .../test/misc/test_tosa_dialect_dw_conv2d.py | 227 + .../backends/arm/test/misc/test_tosa_spec.py | 169 + .../stable_diffusion_module_test_configs.py | 114 + .../test_CLIPTextModelWithProjection.py | 168 + .../test_SD3Transformer2DModel.py | 193 + .../stable_diffusion/test_T5EncoderModel.py | 161 + .../test_vae_AutoencoderKL.py | 118 + .../arm/test/models/test_conformer.py | 138 + .../arm/test/models/test_deit_tiny_arm.py | 120 + .../backends/arm/test/models/test_dl3_arm.py | 118 + .../arm/test/models/test_inception_v3_arm.py | 120 + .../backends/arm/test/models/test_llama.py | 227 + .../backends/arm/test/models/test_lstm_arm.py | 194 + .../arm/test/models/test_mobilenet_v2_arm.py | 179 + .../arm/test/models/test_mobilenet_v3_arm.py | 113 + .../arm/test/models/test_nn_functional.py | 124 + .../arm/test/models/test_nn_modules.py | 161 + .../backends/arm/test/models/test_nss.py | 146 + .../backends/arm/test/models/test_resnet18.py | 98 + .../arm/test/models/test_torch_functions.py | 151 + .../backends/arm/test/models/test_w2l_arm.py | 136 + .../backends/arm/test/ops/test_abs.py | 101 + .../backends/arm/test/ops/test_acos.py | 121 + .../backends/arm/test/ops/test_acosh.py | 137 + .../arm/test/ops/test_adaptive_avg_pool2d.py | 242 + .../backends/arm/test/ops/test_add.py | 291 + .../backends/arm/test/ops/test_addmm.py | 285 + .../backends/arm/test/ops/test_alias_copy.py | 114 + .../backends/arm/test/ops/test_amax.py | 191 + .../backends/arm/test/ops/test_amin.py | 205 + .../backends/arm/test/ops/test_any.py | 210 + .../backends/arm/test/ops/test_arange.py | 258 + .../backends/arm/test/ops/test_asin.py | 105 + .../backends/arm/test/ops/test_asinh.py | 104 + .../backends/arm/test/ops/test_at.py | 256 + .../backends/arm/test/ops/test_atan.py | 111 + .../backends/arm/test/ops/test_atanh.py | 112 + .../backends/arm/test/ops/test_avg_pool2d.py | 295 + .../backends/arm/test/ops/test_batch_norm.py | 385 + .../backends/arm/test/ops/test_bitwise.py | 672 + .../backends/arm/test/ops/test_bitwise_not.py | 115 + .../backends/arm/test/ops/test_bmm.py | 193 + .../backends/arm/test/ops/test_cat.py | 219 + .../backends/arm/test/ops/test_ceil.py | 125 + .../backends/arm/test/ops/test_clamp.py | 474 + .../backends/arm/test/ops/test_clone.py | 150 + .../backends/arm/test/ops/test_cond.py | 338 + .../arm/test/ops/test_constant_pad_nd.py | 119 + .../backends/arm/test/ops/test_conv1d.py | 356 + .../backends/arm/test/ops/test_conv2d.py | 592 + .../backends/arm/test/ops/test_conv3d.py | 711 + .../backends/arm/test/ops/test_conv_combos.py | 668 + .../arm/test/ops/test_conv_constant_pad_nd.py | 145 + .../backends/arm/test/ops/test_copy.py | 171 + .../backends/arm/test/ops/test_cos.py | 115 + .../backends/arm/test/ops/test_cosh.py | 111 + .../backends/arm/test/ops/test_cumsum.py | 122 + .../arm/test/ops/test_depthwise_conv.py | 404 + .../backends/arm/test/ops/test_div.py | 151 + .../arm/test/ops/test_div_tensor_mode.py | 151 + .../backends/arm/test/ops/test_elu.py | 133 + .../backends/arm/test/ops/test_embedding.py | 146 + .../backends/arm/test/ops/test_eq.py | 286 + .../backends/arm/test/ops/test_erf.py | 96 + .../backends/arm/test/ops/test_exp.py | 110 + .../backends/arm/test/ops/test_expand.py | 153 + .../backends/arm/test/ops/test_expm1.py | 113 + .../backends/arm/test/ops/test_eye.py | 156 + .../backends/arm/test/ops/test_fill_scalar.py | 108 + .../backends/arm/test/ops/test_floor.py | 125 + .../backends/arm/test/ops/test_floor_div.py | 156 + .../backends/arm/test/ops/test_full.py | 255 + .../backends/arm/test/ops/test_ge.py | 292 + .../backends/arm/test/ops/test_gelu.py | 156 + .../backends/arm/test/ops/test_glu.py | 130 + .../backends/arm/test/ops/test_group_norm.py | 200 + .../backends/arm/test/ops/test_gt.py | 293 + .../backends/arm/test/ops/test_hardsigmoid.py | 114 + .../backends/arm/test/ops/test_hardswish.py | 104 + .../backends/arm/test/ops/test_hardtanh.py | 113 + .../arm/test/ops/test_index_select.py | 177 + .../arm/test/ops/test_index_tensor.py | 467 + .../backends/arm/test/ops/test_layer_norm.py | 186 + .../backends/arm/test/ops/test_le.py | 296 + .../backends/arm/test/ops/test_leaky_relu.py | 125 + .../arm/test/ops/test_linalg_vector_norm.py | 160 + .../backends/arm/test/ops/test_linear.py | 389 + .../backends/arm/test/ops/test_log.py | 100 + .../backends/arm/test/ops/test_log1p.py | 78 + .../backends/arm/test/ops/test_logical.py | 429 + .../backends/arm/test/ops/test_logit.py | 119 + .../backends/arm/test/ops/test_logsoftmax.py | 124 + .../backends/arm/test/ops/test_lshift.py | 220 + .../backends/arm/test/ops/test_lt.py | 293 + .../backends/arm/test/ops/test_masked_fill.py | 171 + .../backends/arm/test/ops/test_matmul.py | 289 + .../backends/arm/test/ops/test_max_pool.py | 329 + .../backends/arm/test/ops/test_maximum.py | 98 + .../backends/arm/test/ops/test_mean_dim.py | 388 + .../backends/arm/test/ops/test_minimum.py | 98 + .../backends/arm/test/ops/test_mm.py | 93 + .../backends/arm/test/ops/test_mul.py | 376 + .../arm/test/ops/test_multihead_attention.py | 138 + .../backends/arm/test/ops/test_ne.py | 243 + .../backends/arm/test/ops/test_neg.py | 99 + .../backends/arm/test/ops/test_ones.py | 152 + .../backends/arm/test/ops/test_permute.py | 256 + .../arm/test/ops/test_pixel_shuffling.py | 237 + .../backends/arm/test/ops/test_pow.py | 204 + .../backends/arm/test/ops/test_reciprocal.py | 112 + .../backends/arm/test/ops/test_relu.py | 166 + .../backends/arm/test/ops/test_remainder.py | 199 + .../backends/arm/test/ops/test_repeat.py | 162 + .../backends/arm/test/ops/test_round.py | 111 + .../backends/arm/test/ops/test_rshift.py | 226 + .../backends/arm/test/ops/test_rsqrt.py | 153 + .../backends/arm/test/ops/test_rsub.py | 126 + .../arm/test/ops/test_scalar_tensor.py | 135 + .../backends/arm/test/ops/test_scalars.py | 438 + .../backends/arm/test/ops/test_sdpa.py | 73 + .../backends/arm/test/ops/test_select.py | 219 + .../arm/test/ops/test_select_scatter.py | 173 + .../backends/arm/test/ops/test_sigmoid.py | 357 + .../arm/test/ops/test_sigmoid_32bit.py | 177 + .../backends/arm/test/ops/test_sign.py | 113 + .../backends/arm/test/ops/test_silu.py | 174 + .../backends/arm/test/ops/test_sin.py | 108 + .../backends/arm/test/ops/test_sinh.py | 103 + .../backends/arm/test/ops/test_slice.py | 217 + .../backends/arm/test/ops/test_softmax.py | 121 + .../backends/arm/test/ops/test_split.py | 312 + .../backends/arm/test/ops/test_sqrt.py | 112 + .../backends/arm/test/ops/test_squeeze.py | 291 + .../backends/arm/test/ops/test_stack.py | 150 + .../backends/arm/test/ops/test_sub.py | 366 + .../backends/arm/test/ops/test_sum.py | 161 + .../backends/arm/test/ops/test_t_copy.py | 115 + .../backends/arm/test/ops/test_tan.py | 146 + .../backends/arm/test/ops/test_tanh.py | 169 + .../backends/arm/test/ops/test_to_copy.py | 296 + .../arm/test/ops/test_transpose_copy.py | 114 + .../arm/test/ops/test_unary_combos.py | 144 + .../backends/arm/test/ops/test_unbind.py | 82 + .../backends/arm/test/ops/test_unflatten.py | 107 + .../backends/arm/test/ops/test_unsqueeze.py | 107 + .../arm/test/ops/test_upsample_bilinear2d.py | 443 + .../arm/test/ops/test_upsample_nearest2d.py | 520 + .../backends/arm/test/ops/test_var.py | 394 + .../backends/arm/test/ops/test_view.py | 253 + .../backends/arm/test/ops/test_where.py | 285 + .../backends/arm/test/ops/test_while.py | 264 + .../backends/arm/test/ops/test_zeros.py | 158 + .../test/passes/test_broadcast_args_pass.py | 57 + .../arm/test/passes/test_cast_int64_pass.py | 49 + .../test_convert_expand_copy_to_repeat.py | 51 + .../test_convert_int64_const_ops_to_int32.py | 529 + .../test_convert_int64_output_ops_to_int32.py | 129 + ..._convert_permute_singleton_to_view_pass.py | 100 + .../passes/test_convert_split_to_slice.py | 75 + .../arm/test/passes/test_convert_to_clamp.py | 92 + .../passes/test_decompose_avg_pool2d_pass.py | 82 + .../test_decompose_cosine_similarity_pass.py | 58 + .../test/passes/test_decompose_div_pass.py | 70 + .../passes/test_decompose_int_pow_pass.py | 80 + .../passes/test_decompose_layernorm_pass.py | 69 + .../test_decompose_linalg_vector_norm_pass.py | 107 + .../passes/test_decompose_meandim_pass.py | 137 + .../test/passes/test_decompose_quant_nodes.py | 44 + .../passes/test_decompose_softmax_pass.py | 103 + ...t_decompose_tosa_unsupported_clamp_pass.py | 73 + .../test/passes/test_decompose_var_pass.py | 89 + ...est_decorate_fp32_to_int32_casting_pass.py | 85 + .../arm/test/passes/test_fold_qdq_pass.py | 51 + .../test/passes/test_fuse_batchnorm_pass.py | 164 + .../passes/test_fuse_constant_ops_pass.py | 177 + .../passes/test_fuse_duplicate_users_pass.py | 70 + .../test_fuse_equal_placeholders_ops_pass.py | 170 + .../arm/test/passes/test_fuse_view_copy.py | 82 + ...t32_casts_after_int64_placeholders_pass.py | 114 + .../passes/test_insert_rescale_i32_pass.py | 107 + .../test/passes/test_insert_table_ops_pass.py | 47 + .../passes/test_int32_cast_embedding_pass.py | 46 + .../test/passes/test_ioquantization_pass.py | 48 + .../passes/test_promote_bool_operands_pass.py | 103 + .../arm/test/passes/test_remove_clone_pass.py | 45 + .../passes/test_replace_inf_values_pass.py | 96 + .../arm/test/passes/test_rescale_pass.py | 81 + .../arm/test/passes/test_rewrite_conv_pass.py | 20 + .../test/passes/test_to_tosa_memory_format.py | 213 + .../test_unsqueeze_before_repeat_pass.py | 62 + .../executorch/backends/arm/test/pytest.ini | 5 + .../test/quantizer/test_conv_relu_fusing.py | 118 + .../test/quantizer/test_generic_annotater.py | 109 + .../quantizer/test_partial_quantization.py | 104 + .../quantizer/test_selective_quantization.py | 212 + .../test/quantizer/test_set_module_name.py | 158 + .../quantizer/test_tosa_quantizer_validate.py | 55 + .../backends/arm/test/runner_utils.py | 840 + .../backends/arm/test/setup_testing.sh | 32 + .../backends/arm/test/setup_testing_vkml.sh | 14 + .../executorch/backends/arm/test/targets.bzl | 79 + .../backends/arm/test/test_arm_baremetal.sh | 347 + .../backends/arm/test/test_arm_ootb.sh | 140 + .../arm/test/test_memory_allocator_log.py | 170 + .../backends/arm/test/test_model.py | 345 + .../backends/arm/test/tester/__init__.py | 6 + .../arm/test/tester/analyze_output_utils.py | 346 + .../backends/arm/test/tester/arm_tester.py | 1149 + .../backends/arm/test/tester/quantize.py | 43 + .../backends/arm/test/tester/serialize.py | 78 + .../backends/arm/test/tester/test_pipeline.py | 1190 + .../ethos-u-core-driver/.clang-format | 144 + .../ethos-u-core-driver/.gitignore | 1 + .../ethos-u-core-driver/CMakeLists.txt | 114 + .../ethos-u-core-driver/LICENSE.txt} | 5 +- .../third-party/ethos-u-core-driver/README.md | 330 + .../ethos-u-core-driver/SECURITY.md | 85 + .../include/ethosu_driver.h | 399 + .../include/ethosu_types.h | 84 + .../ethos-u-core-driver/include/pmu_ethosu.h | 515 + .../src/ethosu55_interface.h | 26197 ++++++++++++++++ .../src/ethosu65_interface.h | 26060 +++++++++++++++ .../src/ethosu85_interface.h | 24620 +++++++++++++++ .../src/ethosu_config_u55.h | 124 + .../src/ethosu_config_u65.h | 124 + .../src/ethosu_config_u85.h | 112 + .../ethos-u-core-driver/src/ethosu_device.h | 115 + .../src/ethosu_device_u55_u65.c | 373 + .../src/ethosu_device_u85.c | 373 + .../ethos-u-core-driver/src/ethosu_driver.c | 808 + .../src/ethosu_interface.h | 32 + .../ethos-u-core-driver/src/ethosu_log.h | 82 + .../ethos-u-core-driver/src/ethosu_pmu.c | 316 + .../ethos-u-core-driver/zephyr/module.yml | 6 + .../executorch/backends/arm/tosa/TARGETS | 80 + .../executorch/backends/arm/tosa/__init__.py | 9 + .../executorch/backends/arm/tosa/backend.py | 443 + .../backends/arm/tosa/compile_spec.py | 48 + .../backends/arm/tosa/dialect/TARGETS | 36 + .../backends/arm/tosa/dialect/__init__.py | 15 + .../backends/arm/tosa/dialect/lib.py | 85 + .../backends/arm/tosa/dialect/ops/conv2d.py | 111 + .../backends/arm/tosa/dialect/ops/conv3d.py | 74 + .../arm/tosa/dialect/ops/depthwise_conv2d.py | 56 + .../backends/arm/tosa/dialect/ops/matmul.py | 56 + .../backends/arm/tosa/dialect/ops/rescale.py | 53 + .../backends/arm/tosa/dialect/ops/resize.py | 66 + .../backends/arm/tosa/dialect/ops/table.py | 53 + .../arm/tosa/dialect/ops/transpose.py | 35 + .../arm/tosa/dialect/ops_registration.py | 68 + .../executorch/backends/arm/tosa/mapping.py | 309 + .../backends/arm/tosa/partitioner.py | 486 + .../backends/arm/tosa/schemas/README.md | 5 + .../backends/arm/tosa/schemas/__init__.py | 4 + .../backends/arm/tosa/schemas/tosa_1.0.fbs | 559 + .../backends/arm/tosa/specification.py | 406 + .../executorch/backends/arm/tosa/utils.py | 304 + .../executorch/backends/arm/util/_factory.py | 59 + .../backends/arm/util/arm_model_evaluator.py | 388 + .../executorch/backends/arm/vgf/__init__.py | 11 + .../executorch/backends/arm/vgf/backend.py | 172 + .../backends/arm/vgf/compile_spec.py | 73 + .../backends/arm/vgf/model_converter.py | 34 + .../backends/arm/vgf/partitioner.py | 35 + .../backends/cortex_m/CMakeLists.txt | 108 + .../executorch/backends/cortex_m/README.md | 3 + .../executorch/backends/cortex_m/ops/BUCK | 11 + .../executorch/backends/cortex_m/ops/TARGETS | 24 + .../ops/cmsis_scratch_buffer_context.h | 4 +- .../cortex_m/ops/cortex_m_ops_common.h | 231 + .../cortex_m/ops/op_dequantize_per_tensor.cpp | 196 + .../backends/cortex_m/ops/op_maximum.cpp | 5 + .../backends/cortex_m/ops/op_minimum.cpp | 5 + .../cortex_m/ops/op_quantize_per_tensor.cpp | 235 + .../cortex_m/ops/op_quantized_add.cpp | 59 +- .../cortex_m/ops/op_quantized_avg_pool2d.cpp | 86 + .../cortex_m/ops/op_quantized_conv2d.cpp | 56 +- .../ops/op_quantized_depthwise_conv2d.cpp | 21 +- .../cortex_m/ops/op_quantized_linear.cpp | 36 +- .../cortex_m/ops/op_quantized_mul.cpp | 31 +- .../backends/cortex_m/ops/op_softmax.cpp | 13 +- .../backends/cortex_m/ops/op_transpose.cpp | 9 +- .../backends/cortex_m/ops/operators.py | 890 + .../backends/cortex_m/ops/operators.yaml | 33 +- .../backends/cortex_m/ops/targets.bzl | 80 + .../backends/cortex_m/passes/TARGETS | 35 + .../backends/cortex_m/passes/__init__.py | 12 + .../cortex_m/passes/activation_fusion_pass.py | 181 + .../cortex_m/passes/clamp_hardswish_pass.py | 37 + .../passes/convert_to_cortex_m_pass.py | 318 + .../cortex_m/passes/cortex_m_pass_manager.py | 73 + .../passes/decompose_hardswish_pass.py | 127 + .../backends/cortex_m/passes/passes_utils.py | 226 + .../passes/quantized_op_fusion_pass.py | 255 + .../passes/replace_quant_nodes_pass.py | 67 + .../backends/cortex_m/quantizer/TARGETS | 36 + .../backends/cortex_m/quantizer/__init__.py | 18 + .../cortex_m/quantizer/operator_configs.py | 74 + .../quantizer/quantization_configs.py | 121 + .../backends/cortex_m/quantizer/quantizer.py | 500 + .../executorch/backends/cortex_m/test/BUCK | 11 + .../executorch/backends/cortex_m/test/TARGETS | 25 + .../cortex_m/test/build_test_runner.sh | 33 + .../cortex_m/test/misc/test_quantization.py | 359 + .../backends/cortex_m/test/models/__init__.py | 4 + .../cortex_m/test/models/test_mobilenet_v3.py | 74 + .../test/op_dequantize_per_tensor_test.cpp | 55 + .../test/op_quantize_per_tensor_test.cpp | 55 + .../backends/cortex_m/test/ops/__init__.py | 4 + .../cortex_m/test/ops/test_activation.py | 528 + .../backends/cortex_m/test/ops/test_add.py | 182 + .../cortex_m/test/ops/test_avg_pool2d.py | 99 + .../backends/cortex_m/test/ops/test_conv.py | 342 + .../backends/cortex_m/test/ops/test_linear.py | 130 + .../backends/cortex_m/test/ops/test_lstm.py | 98 + .../cortex_m/test/ops/test_maximum.py | 83 + .../cortex_m/test/ops/test_minimum.py | 104 + .../backends/cortex_m/test/ops/test_mul.py | 156 + .../cortex_m/test/ops/test_softmax.py | 84 + .../cortex_m/test/ops/test_transpose.py | 102 + .../backends/cortex_m/test/targets.bzl | 41 + .../test/test_helpers_passes_utils.py | 103 + .../cortex_m/test/test_replace_quant_nodes.py | 134 + .../backends/cortex_m/test/tester.py | 113 + .../executorch/extension/data_loader/BUCK | 8 + .../extension/data_loader/CMakeLists.txt | 51 + .../executorch/extension/data_loader/TARGETS | 8 + .../data_loader/buffer_data_loader.h | 7 +- .../data_loader/file_data_loader.cpp | 70 +- .../extension/data_loader/file_data_loader.h | 0 .../file_descriptor_data_loader.cpp | 13 +- .../data_loader/file_descriptor_data_loader.h | 0 .../executorch}/extension/data_loader/mman.h | 46 - .../extension/data_loader/mman_windows.cpp | 0 .../extension/data_loader/mman_windows.h | 0 .../data_loader/mmap_data_loader.cpp | 12 +- .../extension/data_loader/mmap_data_loader.h | 4 - .../data_loader/shared_ptr_data_loader.h | 7 +- .../extension/data_loader/targets.bzl | 70 + .../extension/data_loader/test/BUCK | 6 + .../extension/data_loader/test/CMakeLists.txt | 29 + .../extension/data_loader/test/TARGETS | 8 + .../test/buffer_data_loader_test.cpp | 188 + .../test/file_data_loader_test.cpp | 250 + .../test/file_descriptor_data_loader_test.cpp | 360 + .../test/mmap_data_loader_test.cpp | 489 + .../test/shared_ptr_data_loader_test.cpp | 142 + .../extension/data_loader/test/targets.bzl | 61 + .../extension/memory_allocator/BUCK | 8 + .../extension/memory_allocator/CMakeLists.txt | 49 + .../extension/memory_allocator/TARGETS | 8 + .../cpu_caching_malloc_allocator.cpp | 0 .../cpu_caching_malloc_allocator.h | 0 .../malloc_memory_allocator.h | 0 .../memory_allocator/memory_allocator_utils.h | 0 .../extension/memory_allocator/targets.bzl | 35 + .../extension/memory_allocator/test/BUCK | 8 + .../memory_allocator/test/CMakeLists.txt | 24 + .../extension/memory_allocator/test/TARGETS | 8 + .../cpu_caching_malloc_allocator_test.cpp | 362 + .../test/malloc_memory_allocator_test.cpp | 145 + .../memory_allocator/test/targets.bzl | 27 + .../executorch/extension/runner_util/BUCK | 8 + .../extension/runner_util/CMakeLists.txt | 39 + .../executorch/extension/runner_util/TARGETS | 8 + .../extension/runner_util/inputs.cpp | 48 +- .../executorch/extension/runner_util/inputs.h | 0 .../extension/runner_util/inputs_aten.cpp | 0 .../extension/runner_util/inputs_portable.cpp | 0 .../extension/runner_util/targets.bzl | 25 + .../extension/runner_util/test/BUCK | 8 + .../extension/runner_util/test/CMakeLists.txt | 50 + .../extension/runner_util/test/TARGETS | 8 + .../runner_util/test/inputs_test.cpp | 188 + .../extension/runner_util/test/targets.bzl | 32 + .../include/executorch/kernels/portable/BUCK | 8 + .../kernels/portable/CMakeLists.txt | 107 + .../executorch/kernels/portable/README.md | 1 + .../executorch/kernels/portable/TARGETS | 8 + .../executorch/kernels/portable/cpu/BUCK | 8 + .../executorch/kernels/portable/cpu/TARGETS | 8 + .../kernels/portable/cpu/math_constants.h | 0 .../portable/cpu/op__clone_dim_order.cpp | 0 .../portable/cpu/op__empty_dim_order.cpp | 0 .../portable/cpu/op__to_dim_order_copy.cpp | 80 + .../kernels/portable/cpu/op_abs.cpp | 0 .../kernels/portable/cpu/op_acos.cpp | 0 .../kernels/portable/cpu/op_acosh.cpp | 0 .../kernels/portable/cpu/op_add.cpp | 0 .../kernels/portable/cpu/op_addmm.cpp | 0 .../kernels/portable/cpu/op_alias_copy.cpp | 0 .../kernels/portable/cpu/op_allclose.cpp | 6 +- .../kernels/portable/cpu/op_amax.cpp | 0 .../kernels/portable/cpu/op_amin.cpp | 0 .../kernels/portable/cpu/op_any.cpp | 0 .../kernels/portable/cpu/op_arange.cpp | 0 .../kernels/portable/cpu/op_argmax.cpp | 0 .../kernels/portable/cpu/op_argmin.cpp | 0 .../portable/cpu/op_as_strided_copy.cpp | 0 .../kernels/portable/cpu/op_asin.cpp | 0 .../kernels/portable/cpu/op_asinh.cpp | 0 .../kernels/portable/cpu/op_atan.cpp | 0 .../kernels/portable/cpu/op_atan2.cpp | 0 .../kernels/portable/cpu/op_atanh.cpp | 0 .../kernels/portable/cpu/op_avg_pool2d.cpp | 0 .../kernels/portable/cpu/op_bitwise_and.cpp | 0 .../portable/cpu/op_bitwise_left_shift.cpp | 0 .../kernels/portable/cpu/op_bitwise_not.cpp | 0 .../kernels/portable/cpu/op_bitwise_or.cpp | 0 .../portable/cpu/op_bitwise_right_shift.cpp | 0 .../kernels/portable/cpu/op_bitwise_xor.cpp | 0 .../kernels/portable/cpu/op_bmm.cpp | 0 .../kernels/portable/cpu/op_cat.cpp | 0 .../kernels/portable/cpu/op_cdist_forward.cpp | 0 .../kernels/portable/cpu/op_ceil.cpp | 0 .../kernels/portable/cpu/op_clamp.cpp | 0 .../kernels/portable/cpu/op_clone.cpp | 0 .../portable/cpu/op_constant_pad_nd.cpp | 39 +- .../kernels/portable/cpu/op_convolution.cpp | 16 +- .../portable/cpu/op_convolution_backward.cpp | 0 .../kernels/portable/cpu/op_copy.cpp | 0 .../kernels/portable/cpu/op_cos.cpp | 0 .../kernels/portable/cpu/op_cosh.cpp | 0 .../kernels/portable/cpu/op_cumsum.cpp | 0 .../kernels/portable/cpu/op_detach_copy.cpp | 0 .../kernels/portable/cpu/op_diagonal_copy.cpp | 0 .../kernels/portable/cpu/op_div.cpp | 47 +- .../kernels/portable/cpu/op_elu.cpp | 0 .../kernels/portable/cpu/op_embedding.cpp | 0 .../kernels/portable/cpu/op_empty.cpp | 0 .../executorch/kernels/portable/cpu/op_eq.cpp | 0 .../kernels/portable/cpu/op_erf.cpp | 0 .../kernels/portable/cpu/op_exp.cpp | 0 .../kernels/portable/cpu/op_expand_copy.cpp | 0 .../kernels/portable/cpu/op_expm1.cpp | 0 .../kernels/portable/cpu/op_fill.cpp | 0 .../kernels/portable/cpu/op_flip.cpp | 0 .../kernels/portable/cpu/op_floor.cpp | 0 .../kernels/portable/cpu/op_floor_divide.cpp | 0 .../kernels/portable/cpu/op_fmod.cpp | 0 .../kernels/portable/cpu/op_full.cpp | 0 .../kernels/portable/cpu/op_full_like.cpp | 0 .../kernels/portable/cpu/op_gather.cpp | 0 .../executorch/kernels/portable/cpu/op_ge.cpp | 0 .../kernels/portable/cpu/op_gelu.cpp | 0 .../kernels/portable/cpu/op_glu.cpp | 0 .../portable/cpu/op_grid_sampler_2d.cpp | 99 +- .../executorch/kernels/portable/cpu/op_gt.cpp | 0 .../kernels/portable/cpu/op_hardtanh.cpp | 0 .../kernels/portable/cpu/op_index.cpp | 0 .../kernels/portable/cpu/op_index_put.cpp | 0 .../kernels/portable/cpu/op_index_select.cpp | 0 .../kernels/portable/cpu/op_isinf.cpp | 0 .../kernels/portable/cpu/op_isnan.cpp | 0 .../executorch/kernels/portable/cpu/op_le.cpp | 0 .../kernels/portable/cpu/op_leaky_relu.cpp | 0 .../portable/cpu/op_lift_fresh_copy.cpp | 0 .../kernels/portable/cpu/op_log.cpp | 0 .../kernels/portable/cpu/op_log10.cpp | 0 .../kernels/portable/cpu/op_log1p.cpp | 0 .../kernels/portable/cpu/op_log2.cpp | 0 .../kernels/portable/cpu/op_log_softmax.cpp | 0 .../kernels/portable/cpu/op_logical_and.cpp | 0 .../kernels/portable/cpu/op_logical_not.cpp | 0 .../kernels/portable/cpu/op_logical_or.cpp | 0 .../kernels/portable/cpu/op_logical_xor.cpp | 0 .../kernels/portable/cpu/op_logit.cpp | 0 .../executorch/kernels/portable/cpu/op_lt.cpp | 0 .../kernels/portable/cpu/op_masked_fill.cpp | 0 .../portable/cpu/op_masked_scatter.cpp | 0 .../kernels/portable/cpu/op_masked_select.cpp | 0 .../kernels/portable/cpu/op_max.cpp | 0 .../cpu/op_max_pool2d_with_indices.cpp | 0 .../op_max_pool2d_with_indices_backward.cpp | 0 .../kernels/portable/cpu/op_maximum.cpp | 0 .../kernels/portable/cpu/op_mean.cpp | 30 - .../kernels/portable/cpu/op_min.cpp | 0 .../kernels/portable/cpu/op_minimum.cpp | 0 .../executorch/kernels/portable/cpu/op_mm.cpp | 0 .../kernels/portable/cpu/op_mul.cpp | 0 .../kernels/portable/cpu/op_narrow_copy.cpp | 0 .../portable/cpu/op_native_batch_norm.cpp | 5 - .../portable/cpu/op_native_dropout.cpp | 0 .../portable/cpu/op_native_group_norm.cpp | 4 +- .../portable/cpu/op_native_layer_norm.cpp | 51 +- .../executorch/kernels/portable/cpu/op_ne.cpp | 0 .../kernels/portable/cpu/op_neg.cpp | 0 .../kernels/portable/cpu/op_nonzero.cpp | 0 .../kernels/portable/cpu/op_ones.cpp | 0 .../kernels/portable/cpu/op_pdist_forward.cpp | 0 .../kernels/portable/cpu/op_permute_copy.cpp | 0 .../kernels/portable/cpu/op_pixel_shuffle.cpp | 0 .../portable/cpu/op_pixel_unshuffle.cpp | 0 .../kernels/portable/cpu/op_pow.cpp | 0 .../kernels/portable/cpu/op_prod.cpp | 0 .../kernels/portable/cpu/op_rand.cpp | 0 .../kernels/portable/cpu/op_randn.cpp | 0 .../kernels/portable/cpu/op_reciprocal.cpp | 0 .../portable/cpu/op_reflection_pad1d.cpp | 0 .../portable/cpu/op_reflection_pad2d.cpp | 0 .../portable/cpu/op_reflection_pad3d.cpp | 0 .../kernels/portable/cpu/op_relu.cpp | 0 .../kernels/portable/cpu/op_remainder.cpp | 0 .../kernels/portable/cpu/op_repeat.cpp | 0 .../portable/cpu/op_repeat_interleave.cpp | 0 .../portable/cpu/op_replication_pad1d.cpp | 0 .../portable/cpu/op_replication_pad2d.cpp | 0 .../portable/cpu/op_replication_pad3d.cpp | 0 .../kernels/portable/cpu/op_roll.cpp | 0 .../kernels/portable/cpu/op_round.cpp | 0 .../kernels/portable/cpu/op_rsqrt.cpp | 0 .../kernels/portable/cpu/op_rsub.cpp | 0 .../kernels/portable/cpu/op_scalar_tensor.cpp | 0 .../kernels/portable/cpu/op_scatter.cpp | 0 .../kernels/portable/cpu/op_scatter_add.cpp | 0 .../kernels/portable/cpu/op_select_copy.cpp | 0 .../portable/cpu/op_select_scatter.cpp | 0 .../kernels/portable/cpu/op_sigmoid.cpp | 0 .../kernels/portable/cpu/op_sign.cpp | 0 .../kernels/portable/cpu/op_sin.cpp | 0 .../kernels/portable/cpu/op_sinh.cpp | 0 .../kernels/portable/cpu/op_slice_copy.cpp | 0 .../kernels/portable/cpu/op_slice_scatter.cpp | 0 .../kernels/portable/cpu/op_softmax.cpp | 0 .../kernels/portable/cpu/op_split_copy.cpp | 0 .../portable/cpu/op_split_with_sizes_copy.cpp | 0 .../kernels/portable/cpu/op_sqrt.cpp | 0 .../kernels/portable/cpu/op_squeeze_copy.cpp | 0 .../kernels/portable/cpu/op_stack.cpp | 0 .../kernels/portable/cpu/op_sub.cpp | 0 .../kernels/portable/cpu/op_sum.cpp | 30 - .../kernels/portable/cpu/op_t_copy.cpp | 0 .../kernels/portable/cpu/op_tan.cpp | 0 .../kernels/portable/cpu/op_tanh.cpp | 0 .../kernels/portable/cpu/op_to_copy.cpp | 0 .../kernels/portable/cpu/op_topk.cpp | 0 .../portable/cpu/op_transpose_copy.cpp | 0 .../kernels/portable/cpu/op_tril.cpp | 0 .../kernels/portable/cpu/op_trunc.cpp | 0 .../kernels/portable/cpu/op_unbind_copy.cpp | 0 .../kernels/portable/cpu/op_unfold_copy.cpp | 0 .../portable/cpu/op_unsqueeze_copy.cpp | 0 .../portable/cpu/op_upsample_bilinear2d.cpp | 0 .../cpu/op_upsample_bilinear2d_aa.cpp | 0 .../portable/cpu/op_upsample_nearest2d.cpp | 0 .../kernels/portable/cpu/op_var.cpp | 0 .../portable/cpu/op_view_as_real_copy.cpp | 0 .../kernels/portable/cpu/op_view_copy.cpp | 0 .../kernels/portable/cpu/op_where.cpp | 0 .../kernels/portable/cpu/op_zeros.cpp | 0 .../kernels/portable/cpu/pattern/BUCK | 8 + .../kernels/portable/cpu/pattern/TARGETS | 8 + .../kernels/portable/cpu/pattern/bitwise_op.h | 0 .../portable/cpu/pattern/comparison_op.h | 0 .../kernels/portable/cpu/pattern/logical_op.h | 0 .../kernels/portable/cpu/pattern/pattern.h | 0 .../kernels/portable/cpu/pattern/targets.bzl | 64 + .../unary_ufunc_realhbbf16_to_bool.cpp | 0 .../unary_ufunc_realhbbf16_to_floathbf16.cpp | 0 .../cpu/pattern/unary_ufunc_realhbf16.cpp | 0 .../kernels/portable/cpu/scalar_utils.h | 4 +- .../kernels/portable/cpu/selective_build.h | 0 .../kernels/portable/cpu/targets.bzl | 89 + .../executorch/kernels/portable/cpu/test/BUCK | 8 + .../kernels/portable/cpu/test/TARGETS | 8 + .../portable/cpu/test/scalar_utils_test.cpp | 73 + .../kernels/portable/cpu/test/targets.bzl | 29 + .../portable/cpu/test/vec_ops_test.cpp | 362 + .../executorch/kernels/portable/cpu/util/BUCK | 8 + .../kernels/portable/cpu/util/CMakeLists.txt | 43 + .../kernels/portable/cpu/util/TARGETS | 8 + .../portable/cpu/util/activation_ops_util.cpp | 0 .../portable/cpu/util/activation_ops_util.h | 0 .../portable/cpu/util/advanced_index_util.cpp | 0 .../portable/cpu/util/advanced_index_util.h | 0 .../kernels/portable/cpu/util/arange_util.cpp | 0 .../kernels/portable/cpu/util/arange_util.h | 0 .../cpu/util/broadcast_indexes_range.h | 0 .../portable/cpu/util/broadcast_util.cpp | 0 .../portable/cpu/util/broadcast_util.h | 0 .../portable/cpu/util/copy_ops_util.cpp | 0 .../kernels/portable/cpu/util/copy_ops_util.h | 0 .../portable/cpu/util/delinearize_index.cpp | 0 .../portable/cpu/util/delinearize_index.h | 0 .../portable/cpu/util/distance_util.cpp | 0 .../kernels/portable/cpu/util/distance_util.h | 2 +- .../kernels/portable/cpu/util/dtype_util.cpp | 0 .../kernels/portable/cpu/util/dtype_util.h | 0 .../portable/cpu/util/elementwise_util.h | 0 .../portable/cpu/util/functional_util.h | 0 .../cpu/util/grid_sampler_2d_util.cpp | 0 .../portable/cpu/util/grid_sampler_2d_util.h | 0 .../kernels/portable/cpu/util/index_util.cpp | 0 .../kernels/portable/cpu/util/index_util.h | 0 .../portable/cpu/util/kernel_ops_util.cpp | 55 - .../portable/cpu/util/kernel_ops_util.h | 21 +- .../kernels/portable/cpu/util/math_util.h | 3 +- .../portable/cpu/util/matmul_ops_util.cpp | 0 .../portable/cpu/util/matmul_ops_util.h | 0 .../cpu/util/normalization_ops_util.cpp | 0 .../cpu/util/normalization_ops_util.h | 44 - .../portable/cpu/util/padding_util.cpp | 0 .../kernels/portable/cpu/util/padding_util.h | 0 .../kernels/portable/cpu/util/reduce_util.cpp | 0 .../kernels/portable/cpu/util/reduce_util.h | 0 .../kernels/portable/cpu/util/repeat_util.cpp | 0 .../kernels/portable/cpu/util/repeat_util.h | 0 .../portable/cpu/util/select_copy_util.cpp | 0 .../portable/cpu/util/select_copy_util.h | 0 .../kernels/portable/cpu/util/slice_util.cpp | 0 .../kernels/portable/cpu/util/slice_util.h | 0 .../kernels/portable/cpu/util/stack_util.cpp | 0 .../kernels/portable/cpu/util/stack_util.h | 0 .../kernels/portable/cpu/util/targets.bzl | 383 + .../kernels/portable/cpu/util/test/BUCK | 8 + .../portable/cpu/util/test/CMakeLists.txt | 29 + .../kernels/portable/cpu/util/test/TARGETS | 8 + .../test/broadcast_indexes_range_test.cpp | 266 + .../portable/cpu/util/test/broadcast_test.cpp | 202 + .../portable/cpu/util/test/reduce_test.cpp | 583 + .../portable/cpu/util/test/targets.bzl | 45 + .../cpu/util/test/vectorized_math_test.cpp | 95 + .../portable/cpu/util/transpose_util.h | 0 .../portable/cpu/util/upsample_util.cpp | 0 .../kernels/portable/cpu/util/upsample_util.h | 11 +- .../portable/cpu/util/vectorized_math.h | 2 +- .../kernels/portable/cpu/vec_ops.h | 10 +- .../kernels/portable/custom_ops.yaml | 0 .../kernels/portable/find_op_header.sh | 51 + .../kernels/portable/functions.yaml | 17 +- .../executorch/kernels/portable/targets.bzl | 94 + .../executorch/kernels/portable/test/BUCK | 8 + .../executorch/kernels/portable/test/TARGETS | 28 + .../test/dtype_selective_build_test.cpp | 75 + .../portable/test/op_allclose_test.cpp | 332 + .../kernels/portable/test/op_div_test.cpp | 120 + .../kernels/portable/test/op_gelu_test.cpp | 72 + .../portable/test/op_grid_sampler_2d_test.py | 234 + .../kernels/portable/test/op_mul_test.cpp | 72 + .../test/op_upsample_bilinear2d_aa_test.py | 346 + .../test/op_upsample_bilinear2d_test.py | 87 + .../test/op_upsample_nearest2d_test.py | 71 + .../test/register_ops_aot_for_test.cpp | 153 + .../portable/test/supported_features_def.yaml | 1 + .../kernels/portable/test/targets.bzl | 101 + .../test/test_grid_sampler_2d_executorch.py | 458 + .../include/executorch/kernels/prim_ops/BUCK | 8 + .../executorch/kernels/prim_ops/TARGETS | 7 + .../kernels/prim_ops/et_copy_index.cpp | 0 .../kernels/prim_ops/et_copy_index.h | 0 .../executorch/kernels/prim_ops/et_view.cpp | 0 .../executorch/kernels/prim_ops/et_view.h | 0 .../kernels/prim_ops/register_prim_ops.cpp | 12 +- .../prim_ops/selective_build_prim_ops.h | 0 .../executorch/kernels/prim_ops/targets.bzl | 78 + .../executorch/kernels/prim_ops/test/BUCK | 0 .../kernels/prim_ops/test/CMakeLists.txt | 23 + .../executorch/kernels/prim_ops/test/TARGETS | 37 + .../kernels/prim_ops/test/prim_ops_test.cpp | 932 + .../kernels/prim_ops/test/prim_ops_test.py | 23 + .../include/executorch/kernels/quantized/BUCK | 5 + .../kernels/quantized/CMakeLists.txt | 158 + .../executorch/kernels/quantized/README.md | 12 + .../executorch/kernels/quantized/TARGETS | 5 + .../executorch/kernels/quantized/__init__.py | 21 + .../executorch/kernels/quantized/cpu/BUCK | 5 + .../executorch/kernels/quantized/cpu/TARGETS | 5 + .../kernels/quantized/cpu/embeddingxb.cpp | 0 .../kernels/quantized/cpu/embeddingxb.h | 0 .../kernels/quantized/cpu/op_add.cpp | 0 .../quantized/cpu/op_choose_qparams.cpp | 0 .../kernels/quantized/cpu/op_dequantize.cpp | 0 .../kernels/quantized/cpu/op_embedding.cpp | 0 .../kernels/quantized/cpu/op_embedding2b.cpp | 0 .../kernels/quantized/cpu/op_embedding4b.cpp | 0 .../kernels/quantized/cpu/op_mixed_linear.cpp | 0 .../kernels/quantized/cpu/op_mixed_mm.cpp | 0 .../kernels/quantized/cpu/op_quantize.cpp | 0 .../kernels/quantized/cpu/targets.bzl | 102 + .../kernels/quantized/quantized.yaml | 0 .../executorch/kernels/quantized/targets.bzl | 130 + .../executorch/kernels/quantized/test/BUCK | 5 + .../executorch/kernels/quantized/test/TARGETS | 51 + .../kernels/quantized/test/op_add_test.cpp | 413 + .../quantized/test/op_choose_qparams_test.cpp | 260 + .../quantized/test/op_dequantize_test.cpp | 321 + .../quantized/test/op_embedding2b_test.cpp | 236 + .../quantized/test/op_embedding4b_test.cpp | 201 + .../quantized/test/op_embedding_test.cpp | 410 + .../quantized/test/op_mixed_linear_test.cpp | 142 + .../quantized/test/op_mixed_mm_test.cpp | 71 + .../quantized/test/op_quantize_test.cpp | 983 + .../test/quantized_ops_aot_register.cpp | 137 + .../test/supported_features_def.yaml | 1 + .../kernels/quantized/test/targets.bzl | 41 + .../quantized/test/test_out_variants.py | 100 + .../test/test_quant_dequant_per_token.py | 149 + .../include/executorch/runtime/backend/BUCK | 5 + .../executorch/runtime/backend/TARGETS | 8 + .../backend/backend_execution_context.h | 0 .../runtime/backend/backend_init_context.h | 59 +- .../runtime/backend/backend_option_context.h | 0 .../executorch/runtime/backend/interface.cpp | 0 .../executorch/runtime/backend/interface.h | 0 .../executorch/runtime/backend/options.h | 0 .../executorch/runtime/backend/targets.bzl | 33 + .../executorch/runtime/backend/test/BUCK | 8 + .../executorch/runtime/backend/test/TARGETS | 8 + .../test/backend_interface_update_test.cpp | 402 + .../backend/test/backend_options_test.cpp | 164 + .../runtime/backend/test/targets.bzl | 26 + .../include/executorch/runtime/core/BUCK | 8 + .../include/executorch/runtime/core/TARGETS | 8 + .../executorch}/runtime/core/array_ref.h | 4 +- .../executorch/runtime/core/data_loader.h | 0 .../include/executorch/runtime/core/defines.h | 0 .../include/executorch}/runtime/core/error.h | 6 - .../executorch/runtime/core/evalue.cpp | 25 - .../include/executorch/runtime/core/evalue.h | 277 +- .../executorch/runtime/core/event_tracer.h | 0 .../runtime/core/event_tracer_hooks.h | 0 .../core/event_tracer_hooks_delegate.h | 0 .../executorch/runtime/core/exec_aten/BUCK | 8 + .../executorch/runtime/core/exec_aten/TARGETS | 8 + .../runtime/core/exec_aten/exec_aten.h | 31 - .../runtime/core/exec_aten/targets.bzl | 21 + .../runtime/core/exec_aten/testing_util/BUCK | 8 + .../core/exec_aten/testing_util/README.md | 4 + .../core/exec_aten/testing_util/TARGETS | 8 + .../core/exec_aten/testing_util/targets.bzl | 32 + .../exec_aten/testing_util/tensor_factory.h | 1133 + .../exec_aten/testing_util/tensor_util.cpp | 353 + .../core/exec_aten/testing_util/tensor_util.h | 378 + .../core/exec_aten/testing_util/test/BUCK | 8 + .../testing_util/test/CMakeLists.txt | 26 + .../core/exec_aten/testing_util/test/TARGETS | 8 + .../exec_aten/testing_util/test/targets.bzl | 30 + .../testing_util/test/tensor_factory_test.cpp | 1229 + .../testing_util/test/tensor_util_test.cpp | 848 + .../runtime/core/exec_aten/util/BUCK | 8 + .../runtime/core/exec_aten/util/README.md | 2 + .../runtime/core/exec_aten/util/TARGETS | 8 + .../core/exec_aten/util/dim_order_util.h | 16 +- .../core/exec_aten/util/scalar_type_util.h | 0 .../runtime/core/exec_aten/util/targets.bzl | 85 + .../exec_aten/util/tensor_dimension_limit.h | 0 .../util/tensor_shape_to_c_string.cpp | 0 .../exec_aten/util/tensor_shape_to_c_string.h | 0 .../runtime/core/exec_aten/util/tensor_util.h | 0 .../core/exec_aten/util/tensor_util_aten.cpp | 0 .../exec_aten/util/tensor_util_portable.cpp | 0 .../runtime/core/exec_aten/util/test/BUCK | 8 + .../core/exec_aten/util/test/CMakeLists.txt | 28 + .../runtime/core/exec_aten/util/test/TARGETS | 8 + .../util/test/dim_order_util_test.cpp | 289 + .../util/test/operator_impl_example_test.cpp | 187 + .../util/test/scalar_type_util_test.cpp | 222 + .../core/exec_aten/util/test/targets.bzl | 60 + .../test/tensor_shape_to_c_string_test.cpp | 89 + .../exec_aten/util/test/tensor_util_test.cpp | 608 + .../executorch/runtime/core/freeable_buffer.h | 0 .../executorch/runtime/core/function_ref.h | 0 .../runtime/core/hierarchical_allocator.h | 6 +- .../runtime/core/memory_allocator.h | 0 .../executorch/runtime/core/named_data_map.h | 0 .../runtime/core/portable_type/BUCK | 8 + .../runtime/core/portable_type/TARGETS | 8 + .../runtime/core/portable_type/bfloat16.h | 0 .../core/portable_type/bfloat16_math.h | 0 .../runtime/core/portable_type/bits_types.h | 0 .../runtime/core/portable_type/c10/README.md | 20 + .../runtime/core/portable_type/c10/c10/BUCK | 8 + .../core/portable_type/c10/c10/TARGETS | 8 + .../portable_type/c10/c10/macros/Export.h | 0 .../portable_type/c10/c10/macros/Macros.h | 0 .../core/portable_type/c10/c10/targets.bzl | 139 + .../portable_type/c10/c10/util/BFloat16-inl.h | 0 .../c10/c10/util/BFloat16-math.h | 0 .../portable_type/c10/c10/util/BFloat16.h | 0 .../portable_type/c10/c10/util/Half-inl.h | 0 .../core/portable_type/c10/c10/util/Half.h | 0 .../c10/c10/util/TypeSafeSignMath.h | 0 .../portable_type/c10/c10/util/bit_cast.h | 0 .../core/portable_type/c10/c10/util/complex.h | 0 .../portable_type/c10/c10/util/complex_math.h | 35 - .../c10/c10/util/complex_utils.h | 0 .../c10/c10/util/floating_point_utils.h | 0 .../core/portable_type/c10/c10/util/irange.h | 0 .../c10/c10/util/llvmMathExtras.h | 0 .../portable_type/c10/c10/util/overflows.h | 0 .../c10/c10/util/safe_numerics.h | 0 .../portable_type/c10/torch/headeronly/BUCK | 5 + .../c10/torch/headeronly/TARGETS | 5 + .../c10}/torch/headeronly/macros/Export.h | 8 + .../c10/torch/headeronly/macros/Macros.h | 79 +- .../c10/torch/headeronly/targets.bzl | 14 + .../c10/torch/headeronly/util/BFloat16.h | 13 +- .../c10/torch/headeronly/util/Half.h | 0 .../torch/headeronly/util/TypeSafeSignMath.h | 0 .../c10/torch/headeronly/util/bit_cast.h | 0 .../c10/torch/headeronly/util/complex.h | 0 .../headeronly/util/floating_point_utils.h | 0 .../runtime/core/portable_type/complex.h | 0 .../runtime/core/portable_type/device.h | 37 +- .../runtime/core/portable_type/half.h | 0 .../runtime/core/portable_type/optional.h | 0 .../runtime/core/portable_type/qint_types.h | 0 .../runtime/core/portable_type/scalar.h | 0 .../runtime/core/portable_type/scalar_type.h | 0 .../runtime/core/portable_type/string_view.h | 0 .../runtime/core/portable_type/targets.bzl | 67 + .../runtime/core/portable_type/tensor.h | 0 .../core/portable_type/tensor_impl.cpp | 49 +- .../runtime/core/portable_type/tensor_impl.h | 38 +- .../core/portable_type/tensor_options.h | 0 .../runtime/core/portable_type/test/BUCK | 8 + .../core/portable_type/test/CMakeLists.txt | 32 + .../runtime/core/portable_type/test/TARGETS | 8 + .../core/portable_type/test/bfloat16_test.cpp | 209 + .../test/dont_shadow_complex_test.c | 9 + .../core/portable_type/test/half_test.cpp | 213 + .../core/portable_type/test/optional_test.cpp | 142 + .../core/portable_type/test/scalar_test.cpp | 47 + .../core/portable_type/test/targets.bzl | 58 + .../portable_type/test/tensor_impl_test.cpp | 460 + .../core/portable_type/test/tensor_test.cpp | 80 + .../include/executorch/runtime/core/result.h | 0 .../include/executorch/runtime/core/span.h | 0 .../include/executorch/runtime/core/tag.cpp | 0 .../include/executorch/runtime/core/tag.h | 0 .../executorch/runtime/core/targets.bzl | 157 + .../runtime/core/tensor_layout.cpp | 17 +- .../executorch/runtime/core/tensor_layout.h | 0 .../runtime/core/tensor_shape_dynamism.h | 0 .../include/executorch/runtime/core/test/BUCK | 8 + .../runtime/core/test/CMakeLists.txt | 34 + .../executorch/runtime/core/test/TARGETS | 8 + .../runtime/core/test/array_ref_test.cpp | 22 + .../runtime/core/test/error_handling_test.cpp | 214 + .../runtime/core/test/evalue_test.cpp | 410 + .../runtime/core/test/event_tracer_test.cpp | 345 + .../core/test/freeable_buffer_test.cpp | 269 + .../runtime/core/test/function_ref_test.cpp | 59 + .../core/test/hierarchical_allocator_test.cpp | 143 + .../core/test/memory_allocator_test.cpp | 267 + .../runtime/core/test/span_test.cpp | 79 + .../executorch/runtime/core/test/tag_test.cpp | 94 + .../executorch/runtime/core/test/targets.bzl | 130 + .../runtime/core/test/tensor_layout_test.cpp | 78 + .../test/tensor_shape_dynamism_test_aten.cpp | 25 + .../executorch/runtime/core/testing_util/BUCK | 8 + .../runtime/core/testing_util/TARGETS | 8 + .../core/testing_util/error_matchers.cpp | 23 + .../core/testing_util/error_matchers.h | 303 + .../runtime/core/testing_util/targets.bzl | 25 + .../runtime/core/testing_util/test/BUCK | 8 + .../runtime/core/testing_util/test/TARGETs | 8 + .../core/testing_util/test/targets.bzl | 19 + .../testing_util/test/test_error_matchers.cpp | 134 + .../include/executorch/runtime/executor/BUCK | 8 + .../executorch/runtime/executor/TARGETS | 8 + .../runtime/executor/memory_manager.h | 0 .../runtime/executor/merged_data_map.h | 0 .../executorch/runtime/executor/method.cpp | 182 +- .../executorch/runtime/executor/method.h | 16 +- .../runtime/executor/method_meta.cpp | 85 +- .../runtime/executor/method_meta.h | 14 - .../executor/platform_memory_allocator.h | 17 +- .../executorch}/runtime/executor/program.cpp | 189 +- .../executorch}/runtime/executor/program.h | 15 +- .../runtime/executor/pte_data_map.cpp | 0 .../runtime/executor/pte_data_map.h | 0 .../executorch/runtime/executor/targets.bzl | 127 + .../runtime/executor/tensor_parser.h | 6 +- .../runtime/executor/tensor_parser_aten.cpp | 0 .../executor/tensor_parser_exec_aten.cpp | 38 +- .../executor/tensor_parser_portable.cpp | 16 +- .../executorch/runtime/executor/test/BUCK | 8 + .../runtime/executor/test/CMakeLists.txt | 194 + .../executorch/runtime/executor/test/TARGETS | 8 + .../test/allocation_failure_stress_test.cpp | 137 + .../test/backend_data_separation_test.cpp | 116 + .../test/backend_integration_test.cpp | 745 + .../runtime/executor/test/executor_test.cpp | 275 + .../executor/test/kernel_integration_test.cpp | 385 + .../executor/test/kernel_resolution_test.cpp | 123 + .../executor/test/managed_memory_manager.h | 68 + .../executor/test/memory_manager_test.cpp | 95 + .../executor/test/merged_data_map_test.cpp | 148 + .../executor/test/method_meta_test.cpp | 216 + .../runtime/executor/test/method_test.cpp | 547 + .../runtime/executor/test/program_test.cpp | 595 + .../executor/test/pte_data_map_test.cpp | 277 + .../runtime/executor/test/targets.bzl | 300 + .../executor/test/tensor_parser_test.cpp | 190 + .../test/test_backend_compiler_lib.cpp | 237 + .../test_backend_with_delegate_mapping.cpp | 176 + .../include/executorch/runtime/kernel/BUCK | 8 + .../include/executorch/runtime/kernel/TARGETS | 8 + .../runtime/kernel/kernel_includes.h | 0 .../runtime/kernel/kernel_runtime_context.h | 0 .../runtime/kernel/operator_registry.cpp | 46 +- .../runtime/kernel/operator_registry.h | 20 +- .../executorch/runtime/kernel/targets.bzl | 97 + .../executorch/runtime/kernel/test/BUCK | 8 + .../runtime/kernel/test/CMakeLists.txt | 55 + .../executorch/runtime/kernel/test/TARGETS | 8 + .../runtime/kernel/test/functions.yaml | 13 + .../test/kernel_double_registration_test.cpp | 43 + .../test/kernel_runtime_context_test.cpp | 102 + .../operator_registry_max_kernel_num_test.cpp | 53 + .../kernel/test/operator_registry_test.cpp | 517 + .../runtime/kernel/test/targets.bzl | 116 + .../test/test_generated_lib_and_aten.cpp | 45 + .../test/test_kernel_manual_registration.cpp | 40 + .../runtime/kernel/test/test_util.h | 40 + .../kernel/thread_parallel_interface.h | 0 .../include/executorch/runtime/platform/BUCK | 8 + .../executorch/runtime/platform/TARGETS | 8 + .../executorch/runtime/platform/abort.cpp | 0 .../executorch/runtime/platform/abort.h | 0 .../executorch/runtime/platform/assert.h | 0 .../executorch/runtime/platform/clock.h | 0 .../runtime/platform/compat_unistd.h | 0 .../executorch}/runtime/platform/compiler.h | 2 +- .../runtime/platform/default/android.cpp | 0 .../runtime/platform/default/minimal.cpp | 29 +- .../runtime/platform/default/posix.cpp | 0 .../runtime/platform/default/zephyr.cpp | 0 .../executorch/runtime/platform/log.bzl | 22 + .../executorch/runtime/platform/log.cpp | 0 .../include/executorch/runtime/platform/log.h | 0 .../executorch/runtime/platform/platform.cpp | 0 .../executorch/runtime/platform/platform.h | 0 .../executorch/runtime/platform/profiler.cpp | 0 .../executorch/runtime/platform/profiler.h | 0 .../executorch/runtime/platform/runtime.cpp | 0 .../executorch/runtime/platform/runtime.h | 0 .../executorch/runtime/platform/system.h | 0 .../executorch/runtime/platform/targets.bzl | 120 + .../executorch/runtime/platform/test/BUCK | 8 + .../runtime/platform/test/CMakeLists.txt | 47 + .../executorch/runtime/platform/test/TARGETS | 8 + .../runtime/platform/test/clock_test.cpp | 37 + .../platform/test/executor_pal_death_test.cpp | 36 + .../test/executor_pal_override_test.cpp | 135 + .../executor_pal_runtime_override_test.cpp | 130 + ...cutor_pal_static_runtime_override_test.cpp | 94 + .../platform/test/executor_pal_test.cpp | 35 + .../runtime/platform/test/logging_test.cpp | 88 + .../runtime/platform/test/pal_spy.h | 86 + .../runtime/platform/test/stub_platform.cpp | 102 + .../runtime/platform/test/stub_platform.h | 76 + .../runtime/platform/test/targets.bzl | 109 + .../executorch/runtime/platform/types.h | 0 .../executorch}/schema/extended_header.cpp | 5 - .../executorch/schema/extended_header.h | 0 .../include/executorch/schema/program.fbs | 47 +- .../executorch/schema/program_generated.h | 167 +- .../executorch}/schema/scalar_type.fbs | 2 +- .../executorch/schema/scalar_type_generated.h | 6 +- .../include/flatbuffers/allocator.h | 0 .../include/flatbuffers/array.h | 0 .../include/flatbuffers/base.h | 0 .../include/flatbuffers/buffer.h | 0 .../include/flatbuffers/buffer_ref.h | 0 .../include/flatbuffers/code_generator.h | 0 .../include/flatbuffers/code_generators.h | 0 .../include/flatbuffers/default_allocator.h | 0 .../include/flatbuffers/detached_buffer.h | 0 .../include/flatbuffers/file_manager.h | 0 .../include/flatbuffers/flatbuffer_builder.h | 0 .../include/flatbuffers/flatbuffers.h | 0 .../include/flatbuffers/flatc.h | 0 .../include/flatbuffers/flex_flat_util.h | 0 .../include/flatbuffers/flexbuffers.h | 0 .../include/flatbuffers/grpc.h | 0 .../include/flatbuffers/hash.h | 0 .../include/flatbuffers/idl.h | 0 .../include/flatbuffers/minireflect.h | 0 .../include/flatbuffers/pch/flatc_pch.h | 0 .../include/flatbuffers/pch/pch.h | 0 .../include/flatbuffers/reflection.h | 0 .../flatbuffers/reflection_generated.h | 0 .../include/flatbuffers/registry.h | 0 .../include/flatbuffers/stl_emulation.h | 0 .../include/flatbuffers/string.h | 0 .../include/flatbuffers/struct.h | 0 .../include/flatbuffers/table.h | 0 .../include/flatbuffers/util.h | 0 .../include/flatbuffers/vector.h | 0 .../include/flatbuffers/vector_downward.h | 0 .../include/flatbuffers/verifier.h | 0 .../include/torch/headeronly/BUCK | 5 + .../include/torch/headeronly/TARGETS | 5 + .../include}/torch/headeronly/macros/Export.h | 8 + .../include/torch/headeronly/macros/Macros.h | 79 +- .../include/torch/headeronly/targets.bzl | 14 + .../include/torch/headeronly/util/BFloat16.h | 13 +- .../include/torch/headeronly/util/Half.h | 0 .../torch/headeronly/util/TypeSafeSignMath.h | 0 .../include/torch/headeronly/util/bit_cast.h | 0 .../include/torch/headeronly/util/complex.h | 0 .../headeronly/util/floating_point_utils.h | 0 .../meta/selected_operators.yaml | 23 + .../src/backends/arm/CMakeLists.txt | 115 + .../src/backends/arm/MODELS.md | 20 + .../src/backends/arm/README.md | 237 + .../src/backends/arm/TARGETS | 119 + .../src/backends/arm/_passes/TARGETS | 19 + .../src/backends/arm/_passes/__init__.py | 134 + .../src/backends/arm/_passes/_debug_passes.py | 58 + .../arm/_passes/annotate_decomposed_matmul.py | 127 + .../_passes/annotate_output_dim_order_pass.py | 26 + .../src/backends/arm/_passes/arm_pass.py | 95 + .../backends/arm/_passes/arm_pass_manager.py | 462 + .../backends/arm/_passes/arm_pass_utils.py | 281 + .../arm/_passes/broadcast_args_pass.py | 72 + .../backends/arm/_passes/cast_int64_pass.py | 70 + .../arm/_passes/cast_to_int32_pass.py | 67 + .../arm/_passes/conv1d_unsqueeze_pass.py | 98 + .../arm/_passes/convert_elu_params.py | 67 + .../_passes/convert_expand_copy_to_repeat.py | 77 + .../_passes/convert_full_like_to_full_pass.py | 42 + .../convert_int64_const_ops_to_int32.py | 81 + .../convert_int64_output_ops_to_int32.py | 155 + .../arm/_passes/convert_minmax_pass.py | 166 + .../convert_permute_singleton_to_view_pass.py | 64 + .../arm/_passes/convert_split_to_slice.py | 132 + .../arm/_passes/convert_squeezes_to_view.py | 36 + .../arm/_passes/convert_to_clamp_pass.py | 45 + .../arm/_passes/decompose_acosh_pass.py | 77 + .../decompose_adaptive_avg_pool2d_pass.py | 112 + .../_passes/decompose_add_sub_alpha_pass.py | 98 + .../arm/_passes/decompose_addmm_pass.py | 72 + .../arm/_passes/decompose_any_pass.py | 114 + .../_passes/decompose_asin_and_acos_pass.py | 236 + .../arm/_passes/decompose_asinh_pass.py | 74 + .../arm/_passes/decompose_atan_pass.py | 142 + .../arm/_passes/decompose_atanh_pass.py | 86 + .../arm/_passes/decompose_avg_pool2d_pass.py | 154 + .../_passes/decompose_batch_norm_no_stats.py | 233 + .../arm/_passes/decompose_cosh_pass.py | 72 + .../decompose_cosine_similarity_pass.py | 92 + .../arm/_passes/decompose_cumsum_pass.py | 167 + .../arm/_passes/decompose_div_pass.py | 61 + .../arm/_passes/decompose_div_tensor_mode.py | 94 + .../arm/_passes/decompose_elu_pass.py | 107 + .../arm/_passes/decompose_embedding_pass.py | 126 + .../arm/_passes/decompose_expm1_pass.py | 163 + .../_passes/decompose_floor_divide_pass.py | 75 + .../arm/_passes/decompose_gelu_pass.py | 172 + .../arm/_passes/decompose_glu_pass.py | 81 + .../_passes/decompose_grouped_conv_pass.py | 185 + .../arm/_passes/decompose_groupnorm_pass.py | 227 + .../decompose_int16_activation_conv_pass.py | 137 + .../arm/_passes/decompose_int_pow_pass.py | 64 + .../arm/_passes/decompose_layernorm_pass.py | 203 + .../arm/_passes/decompose_leaky_relu_pass.py | 76 + .../decompose_linalg_vector_norm_pass.py | 92 + .../arm/_passes/decompose_linear_pass.py | 109 + .../arm/_passes/decompose_log1p_pass.py | 97 + .../arm/_passes/decompose_logit_pass.py | 119 + .../arm/_passes/decompose_masked_fill_pass.py | 58 + .../decompose_maxpool2d_with_dilation_pass.py | 218 + .../arm/_passes/decompose_meandim_pass.py | 283 + .../backends/arm/_passes/decompose_ne_pass.py | 74 + .../arm/_passes/decompose_quant_nodes.py | 156 + .../arm/_passes/decompose_remainder_pass.py | 70 + .../arm/_passes/decompose_round_pass.py | 96 + .../arm/_passes/decompose_sdpa_pass.py | 36 + .../backends/arm/_passes/decompose_select.py | 75 + .../_passes/decompose_select_scatter_pass.py | 143 + .../arm/_passes/decompose_sign_pass.py | 78 + .../arm/_passes/decompose_silu_pass.py | 41 + .../arm/_passes/decompose_sinh_pass.py | 77 + .../arm/_passes/decompose_softmax_pass.py | 93 + .../decompose_softmax_unstable_pass.py | 86 + .../arm/_passes/decompose_sqrt_pass.py | 53 + .../arm/_passes/decompose_sum_pass.py | 93 + .../arm/_passes/decompose_tan_pass.py | 51 + .../decompose_tosa_unsupported_clamp_pass.py | 97 + .../arm/_passes/decompose_var_pass.py | 109 + .../decorate_fp32_to_int32_casting_pass.py | 88 + .../fold_qdq_with_annotated_qparams_pass.py | 394 + .../arm/_passes/fuse_batch_norm2d_pass.py | 241 + .../arm/_passes/fuse_constant_ops_pass.py | 272 + .../arm/_passes/fuse_duplicate_users_pass.py | 165 + .../_passes/fuse_equal_placeholders_pass.py | 104 + .../_passes/fuse_quantized_activation_pass.py | 80 + .../_passes/fuse_view_copy_transform_pass.py | 14 + ...rt_int32_casts_after_int64_placeholders.py | 130 + .../arm/_passes/insert_rescales_pass.py | 584 + .../backends/arm/_passes/insert_table_ops.py | 305 + .../arm/_passes/match_arg_dtype_pass.py | 104 + .../arm/_passes/match_arg_ranks_pass.py | 114 + .../backends/arm/_passes/mm_to_bmm_pass.py | 104 + .../normalize_while_initial_args_pass.py | 113 + .../arm/_passes/promote_bool_operands_pass.py | 88 + .../src/backends/arm/_passes/quant_args.py | 125 + .../arm/_passes/remove_getitem_pass.py | 14 + .../arm/_passes/remove_graph_asserts_pass.py | 18 + .../backends/arm/_passes/remove_noop_pass.py | 40 + .../replace_inf_and_limit_values_pass.py | 73 + .../replace_scalar_with_tensor_pass.py | 121 + ...te_bool_bitwise_not_to_logical_not_pass.py | 43 + ...rewrite_bool_to_fp32_cast_via_int8_pass.py | 77 + .../backends/arm/_passes/rewrite_conv_pass.py | 336 + .../backends/arm/_passes/rewrite_matmul.py | 98 + .../backends/arm/_passes/rewrite_upsample.py | 93 + .../arm/_passes/scalars_to_attribute_pass.py | 97 + .../arm/_passes/size_adjust_input_pass.py | 227 + .../arm/_passes/to_tosa_memory_format_pass.py | 454 + .../_passes/unsqueeze_before_repeat_pass.py | 66 + .../unsqueeze_scalar_placeholders_pass.py | 85 + .../src/backends/arm/arm_vela.py | 137 + .../src/backends/arm/common/__init__.py | 4 + .../backends/arm/common/annotation_meta.py | 39 + .../backends/arm/common/arm_compile_spec.py | 271 + .../src/backends/arm/common/debug.py | 79 + .../backends/arm/common/pipeline_config.py | 59 + .../src/backends/arm/common/type.py | 28 + .../src/backends/arm/constants.py | 48 + .../src/backends/arm/debug/TARGETS | 14 + .../src/backends/arm/debug/__init__.py | 4 + .../src/backends/arm/debug/schema.py | 145 + .../src/backends/arm/ethosu/__init__.py | 11 + .../src/backends/arm/ethosu/backend.py | 115 + .../src/backends/arm/ethosu/compile_spec.py | 117 + .../src/backends/arm/ethosu/partitioner.py | 35 + .../src/backends/arm/operator_support/TARGETS | 14 + .../backends/arm/operator_support/__init__.py | 23 + .../clone_dim_order_support.py | 82 + .../operator_support/control_flow_support.py | 162 + .../operator_support/convolution_support.py | 160 + .../arm/operator_support/embedding_support.py | 61 + .../arm/operator_support/ethos_u55_support.py | 598 + .../operator_support/index_select_support.py | 60 + .../operator_support/index_tensor_support.py | 160 + .../arm/operator_support/minmax_support.py | 61 + .../arm/operator_support/pool_2d_support.py | 214 + .../operator_support/reduce_sum_support.py | 76 + .../operator_support/right_shift_support.py | 52 + .../operator_support/slice_copy_support.py | 48 + .../to_dim_order_copy_support.py | 200 + .../tosa_profile_supported_op_lists.py | 251 + .../tosa_supported_operators.py | 748 + .../arm/operator_support/where_support.py | 77 + .../src/backends/arm/operators/TARGETS | 40 + .../src/backends/arm/operators/__init__.py | 71 + .../backends/arm/operators/node_visitor.py | 177 + .../src/backends/arm/operators/op_abs.py | 59 + .../src/backends/arm/operators/op_add.py | 60 + .../src/backends/arm/operators/op_amax.py | 72 + .../src/backends/arm/operators/op_amin.py | 73 + .../src/backends/arm/operators/op_any.py | 61 + .../backends/arm/operators/op_avg_pool2d.py | 142 + .../backends/arm/operators/op_bitwise_not.py | 62 + .../src/backends/arm/operators/op_cat.py | 68 + .../src/backends/arm/operators/op_ceil.py | 56 + .../src/backends/arm/operators/op_clamp.py | 118 + .../src/backends/arm/operators/op_cond_if.py | 56 + .../arm/operators/op_constant_pad_nd.py | 117 + .../src/backends/arm/operators/op_cos.py | 49 + .../src/backends/arm/operators/op_eq.py | 64 + .../src/backends/arm/operators/op_erf.py | 54 + .../src/backends/arm/operators/op_exp.py | 54 + .../src/backends/arm/operators/op_floor.py | 56 + .../src/backends/arm/operators/op_ge.py | 64 + .../src/backends/arm/operators/op_gt.py | 64 + .../backends/arm/operators/op_index_select.py | 109 + .../backends/arm/operators/op_index_tensor.py | 247 + .../src/backends/arm/operators/op_le.py | 64 + .../src/backends/arm/operators/op_log.py | 50 + .../backends/arm/operators/op_logical_not.py | 62 + .../src/backends/arm/operators/op_lt.py | 64 + .../backends/arm/operators/op_max_pool2d.py | 108 + .../src/backends/arm/operators/op_maximum.py | 66 + .../src/backends/arm/operators/op_minimum.py | 67 + .../src/backends/arm/operators/op_mul.py | 61 + .../src/backends/arm/operators/op_neg.py | 92 + .../src/backends/arm/operators/op_permute.py | 150 + .../src/backends/arm/operators/op_pow.py | 63 + .../backends/arm/operators/op_reciprocal.py | 51 + .../src/backends/arm/operators/op_repeat.py | 77 + .../arm/operators/op_rshift_tensor.py | 62 + .../src/backends/arm/operators/op_rsqrt.py | 51 + .../src/backends/arm/operators/op_sigmoid.py | 50 + .../src/backends/arm/operators/op_sin.py | 49 + .../src/backends/arm/operators/op_slice.py | 151 + .../src/backends/arm/operators/op_sub.py | 63 + .../src/backends/arm/operators/op_sum.py | 64 + .../src/backends/arm/operators/op_tanh.py | 51 + .../arm/operators/op_to_dim_order_copy.py | 49 + .../backends/arm/operators/op_tosa_conv2d.py | 139 + .../backends/arm/operators/op_tosa_conv3d.py | 24 + .../arm/operators/op_tosa_depthwise_conv2d.py | 32 + .../backends/arm/operators/op_tosa_matmul.py | 102 + .../backends/arm/operators/op_tosa_rescale.py | 261 + .../backends/arm/operators/op_tosa_resize.py | 124 + .../backends/arm/operators/op_tosa_table.py | 72 + .../arm/operators/op_tosa_transpose.py | 71 + .../src/backends/arm/operators/op_view.py | 81 + .../src/backends/arm/operators/op_where.py | 75 + .../src/backends/arm/operators/op_while.py | 103 + .../operators/operator_validation_utils.py | 201 + .../src/backends/arm/operators/ops_binary.py | 112 + .../backends/arm/operators/ops_identity.py | 80 + .../src/backends/arm/process_node.py | 230 + .../src/backends/arm/quantizer/TARGETS | 54 + .../src/backends/arm/quantizer/__init__.py | 35 + .../backends/arm/quantizer/arm_quantizer.py | 710 + .../arm/quantizer/arm_quantizer_utils.py | 76 + .../arm/quantizer/quantization_annotator.py | 815 + .../arm/quantizer/quantization_config.py | 228 + .../backends/arm/requirements-arm-ethos-u.txt | 6 + .../arm/requirements-arm-models-test.txt | 6 + .../backends/arm/requirements-arm-tosa.txt | 7 + .../src/backends/arm/requirements-arm-vgf.txt | 8 + .../src/backends/arm/runtime/BUCK | 5 + .../backends/arm/runtime/EthosUBackend.cpp | 618 + .../src/backends/arm/runtime/TARGETS | 5 + .../src}/backends/arm/runtime/VGFBackend.cpp | 93 +- .../src/backends/arm/runtime/VGFSetup.cpp | 72 +- .../src}/backends/arm/runtime/VGFSetup.h | 7 +- .../backends/arm/runtime/VelaBinStream.cpp | 6 +- .../src/backends/arm/runtime/VelaBinStream.h | 0 .../src/backends/arm/runtime/targets.bzl | 31 + .../arm/scripts/TOSA_minimal_example.ipynb | 266 + .../arm/scripts/build_executor_runner.sh | 197 + .../arm/scripts/build_executor_runner_vkml.sh | 100 + .../backends/arm/scripts/build_executorch.sh | 93 + .../arm/scripts/build_portable_kernels.sh | 7 + .../arm/scripts/collect_testname_resources.py | 194 + .../backends/arm/scripts/corstone_utils.cmake | 463 + .../src/backends/arm/scripts/fvp_utils.sh | 134 + .../arm/scripts/install_models_for_test.sh | 21 + .../src/backends/arm/scripts/mlsdk_utils.sh | 258 + .../backends/arm/scripts/parse_test_names.py | 271 + .../src/backends/arm/scripts/pre-commit | 13 + .../src/backends/arm/scripts/pre-push | 215 + .../src/backends/arm/scripts/run_fvp.sh | 161 + .../src/backends/arm/scripts/run_vkml.sh | 97 + .../src/backends/arm/scripts/setup-dev-env.sh | 9 + .../backends/arm/scripts/toolchain_utils.sh | 93 + .../src/backends/arm/scripts/utils.sh | 145 + .../src/backends/arm/scripts/vulkan_utils.sh | 163 + .../src/backends/arm/test/.coveragerc | 8 + .../src/backends/arm/test/TARGETS | 86 + .../src/backends/arm/test/common.py | 302 + .../src/backends/arm/test/conftest.py | 134 + .../src/backends/arm/test/misc/TARGETS | 16 + .../arm/test/misc/test_bn_relu_folding_qat.py | 124 + .../test/misc/test_call_operator_submodule.py | 72 + .../arm/test/misc/test_compile_spec.py | 55 + .../test/misc/test_conv_relu_residual_add.py | 108 + .../arm/test/misc/test_custom_partition.py | 183 + .../arm/test/misc/test_debug_feats.py | 316 + .../backends/arm/test/misc/test_debug_hook.py | 186 + .../backends/arm/test/misc/test_dim_order.py | 127 + .../misc/test_dw_convs_with_shared_weights.py | 46 + .../test/misc/test_extract_io_params_tosa.py | 92 + .../src/backends/arm/test/misc/test_int64.py | 112 + .../arm/test/misc/test_lifted_tensor.py | 146 + .../arm/test/misc/test_mixed_type_lowering.py | 83 + .../arm/test/misc/test_model_evaluator.py | 58 + .../arm/test/misc/test_multiple_delegates.py | 53 + .../arm/test/misc/test_multiple_outputs.py | 70 + .../test/misc/test_non_persistent_buffers.py | 49 + .../arm/test/misc/test_outputs_order.py | 122 + ...test_partition_decomposed_quantized_ops.py | 181 + .../test/misc/test_pass_pipeline_config.py | 35 + .../arm/test/misc/test_pass_required_order.py | 97 + .../arm/test/misc/test_qat_training_loop.py | 100 + .../arm/test/misc/test_quant_custom_meta.py | 105 + .../arm/test/misc/test_rescale_range.py | 130 + .../arm/test/misc/test_save_exported_model.py | 64 + .../arm/test/misc/test_tosa_dialect_conv2d.py | 220 + .../test/misc/test_tosa_dialect_dw_conv2d.py | 227 + .../backends/arm/test/misc/test_tosa_spec.py | 169 + .../stable_diffusion_module_test_configs.py | 114 + .../test_CLIPTextModelWithProjection.py | 168 + .../test_SD3Transformer2DModel.py | 193 + .../stable_diffusion/test_T5EncoderModel.py | 161 + .../test_vae_AutoencoderKL.py | 118 + .../arm/test/models/test_conformer.py | 138 + .../arm/test/models/test_deit_tiny_arm.py | 120 + .../backends/arm/test/models/test_dl3_arm.py | 118 + .../arm/test/models/test_inception_v3_arm.py | 120 + .../backends/arm/test/models/test_llama.py | 227 + .../backends/arm/test/models/test_lstm_arm.py | 194 + .../arm/test/models/test_mobilenet_v2_arm.py | 179 + .../arm/test/models/test_mobilenet_v3_arm.py | 113 + .../arm/test/models/test_nn_functional.py | 124 + .../arm/test/models/test_nn_modules.py | 161 + .../src/backends/arm/test/models/test_nss.py | 146 + .../backends/arm/test/models/test_resnet18.py | 98 + .../arm/test/models/test_torch_functions.py | 151 + .../backends/arm/test/models/test_w2l_arm.py | 136 + .../src/backends/arm/test/ops/test_abs.py | 101 + .../src/backends/arm/test/ops/test_acos.py | 121 + .../src/backends/arm/test/ops/test_acosh.py | 137 + .../arm/test/ops/test_adaptive_avg_pool2d.py | 242 + .../src/backends/arm/test/ops/test_add.py | 291 + .../src/backends/arm/test/ops/test_addmm.py | 285 + .../backends/arm/test/ops/test_alias_copy.py | 114 + .../src/backends/arm/test/ops/test_amax.py | 191 + .../src/backends/arm/test/ops/test_amin.py | 205 + .../src/backends/arm/test/ops/test_any.py | 210 + .../src/backends/arm/test/ops/test_arange.py | 258 + .../src/backends/arm/test/ops/test_asin.py | 105 + .../src/backends/arm/test/ops/test_asinh.py | 104 + .../src/backends/arm/test/ops/test_at.py | 256 + .../src/backends/arm/test/ops/test_atan.py | 111 + .../src/backends/arm/test/ops/test_atanh.py | 112 + .../backends/arm/test/ops/test_avg_pool2d.py | 295 + .../backends/arm/test/ops/test_batch_norm.py | 385 + .../src/backends/arm/test/ops/test_bitwise.py | 672 + .../backends/arm/test/ops/test_bitwise_not.py | 115 + .../src/backends/arm/test/ops/test_bmm.py | 193 + .../src/backends/arm/test/ops/test_cat.py | 219 + .../src/backends/arm/test/ops/test_ceil.py | 125 + .../src/backends/arm/test/ops/test_clamp.py | 474 + .../src/backends/arm/test/ops/test_clone.py | 150 + .../src/backends/arm/test/ops/test_cond.py | 338 + .../arm/test/ops/test_constant_pad_nd.py | 119 + .../src/backends/arm/test/ops/test_conv1d.py | 356 + .../src/backends/arm/test/ops/test_conv2d.py | 592 + .../src/backends/arm/test/ops/test_conv3d.py | 711 + .../backends/arm/test/ops/test_conv_combos.py | 668 + .../arm/test/ops/test_conv_constant_pad_nd.py | 145 + .../src/backends/arm/test/ops/test_copy.py | 171 + .../src/backends/arm/test/ops/test_cos.py | 115 + .../src/backends/arm/test/ops/test_cosh.py | 111 + .../src/backends/arm/test/ops/test_cumsum.py | 122 + .../arm/test/ops/test_depthwise_conv.py | 404 + .../src/backends/arm/test/ops/test_div.py | 151 + .../arm/test/ops/test_div_tensor_mode.py | 151 + .../src/backends/arm/test/ops/test_elu.py | 133 + .../backends/arm/test/ops/test_embedding.py | 146 + .../src/backends/arm/test/ops/test_eq.py | 286 + .../src/backends/arm/test/ops/test_erf.py | 96 + .../src/backends/arm/test/ops/test_exp.py | 110 + .../src/backends/arm/test/ops/test_expand.py | 153 + .../src/backends/arm/test/ops/test_expm1.py | 113 + .../src/backends/arm/test/ops/test_eye.py | 156 + .../backends/arm/test/ops/test_fill_scalar.py | 108 + .../src/backends/arm/test/ops/test_floor.py | 125 + .../backends/arm/test/ops/test_floor_div.py | 156 + .../src/backends/arm/test/ops/test_full.py | 255 + .../src/backends/arm/test/ops/test_ge.py | 292 + .../src/backends/arm/test/ops/test_gelu.py | 156 + .../src/backends/arm/test/ops/test_glu.py | 130 + .../backends/arm/test/ops/test_group_norm.py | 200 + .../src/backends/arm/test/ops/test_gt.py | 293 + .../backends/arm/test/ops/test_hardsigmoid.py | 114 + .../backends/arm/test/ops/test_hardswish.py | 104 + .../backends/arm/test/ops/test_hardtanh.py | 113 + .../arm/test/ops/test_index_select.py | 177 + .../arm/test/ops/test_index_tensor.py | 467 + .../backends/arm/test/ops/test_layer_norm.py | 186 + .../src/backends/arm/test/ops/test_le.py | 296 + .../backends/arm/test/ops/test_leaky_relu.py | 125 + .../arm/test/ops/test_linalg_vector_norm.py | 160 + .../src/backends/arm/test/ops/test_linear.py | 389 + .../src/backends/arm/test/ops/test_log.py | 100 + .../src/backends/arm/test/ops/test_log1p.py | 78 + .../src/backends/arm/test/ops/test_logical.py | 429 + .../src/backends/arm/test/ops/test_logit.py | 119 + .../backends/arm/test/ops/test_logsoftmax.py | 124 + .../src/backends/arm/test/ops/test_lshift.py | 220 + .../src/backends/arm/test/ops/test_lt.py | 293 + .../backends/arm/test/ops/test_masked_fill.py | 171 + .../src/backends/arm/test/ops/test_matmul.py | 289 + .../backends/arm/test/ops/test_max_pool.py | 329 + .../src/backends/arm/test/ops/test_maximum.py | 98 + .../backends/arm/test/ops/test_mean_dim.py | 388 + .../src/backends/arm/test/ops/test_minimum.py | 98 + .../src/backends/arm/test/ops/test_mm.py | 93 + .../src/backends/arm/test/ops/test_mul.py | 376 + .../arm/test/ops/test_multihead_attention.py | 138 + .../src/backends/arm/test/ops/test_ne.py | 243 + .../src/backends/arm/test/ops/test_neg.py | 99 + .../src/backends/arm/test/ops/test_ones.py | 152 + .../src/backends/arm/test/ops/test_permute.py | 256 + .../arm/test/ops/test_pixel_shuffling.py | 237 + .../src/backends/arm/test/ops/test_pow.py | 204 + .../backends/arm/test/ops/test_reciprocal.py | 112 + .../src/backends/arm/test/ops/test_relu.py | 166 + .../backends/arm/test/ops/test_remainder.py | 199 + .../src/backends/arm/test/ops/test_repeat.py | 162 + .../src/backends/arm/test/ops/test_round.py | 111 + .../src/backends/arm/test/ops/test_rshift.py | 226 + .../src/backends/arm/test/ops/test_rsqrt.py | 153 + .../src/backends/arm/test/ops/test_rsub.py | 126 + .../arm/test/ops/test_scalar_tensor.py | 135 + .../src/backends/arm/test/ops/test_scalars.py | 438 + .../src/backends/arm/test/ops/test_sdpa.py | 73 + .../src/backends/arm/test/ops/test_select.py | 219 + .../arm/test/ops/test_select_scatter.py | 173 + .../src/backends/arm/test/ops/test_sigmoid.py | 357 + .../arm/test/ops/test_sigmoid_32bit.py | 177 + .../src/backends/arm/test/ops/test_sign.py | 113 + .../src/backends/arm/test/ops/test_silu.py | 174 + .../src/backends/arm/test/ops/test_sin.py | 108 + .../src/backends/arm/test/ops/test_sinh.py | 103 + .../src/backends/arm/test/ops/test_slice.py | 217 + .../src/backends/arm/test/ops/test_softmax.py | 121 + .../src/backends/arm/test/ops/test_split.py | 312 + .../src/backends/arm/test/ops/test_sqrt.py | 112 + .../src/backends/arm/test/ops/test_squeeze.py | 291 + .../src/backends/arm/test/ops/test_stack.py | 150 + .../src/backends/arm/test/ops/test_sub.py | 366 + .../src/backends/arm/test/ops/test_sum.py | 161 + .../src/backends/arm/test/ops/test_t_copy.py | 115 + .../src/backends/arm/test/ops/test_tan.py | 146 + .../src/backends/arm/test/ops/test_tanh.py | 169 + .../src/backends/arm/test/ops/test_to_copy.py | 296 + .../arm/test/ops/test_transpose_copy.py | 114 + .../arm/test/ops/test_unary_combos.py | 144 + .../src/backends/arm/test/ops/test_unbind.py | 82 + .../backends/arm/test/ops/test_unflatten.py | 107 + .../backends/arm/test/ops/test_unsqueeze.py | 107 + .../arm/test/ops/test_upsample_bilinear2d.py | 443 + .../arm/test/ops/test_upsample_nearest2d.py | 520 + .../src/backends/arm/test/ops/test_var.py | 394 + .../src/backends/arm/test/ops/test_view.py | 253 + .../src/backends/arm/test/ops/test_where.py | 285 + .../src/backends/arm/test/ops/test_while.py | 264 + .../src/backends/arm/test/ops/test_zeros.py | 158 + .../test/passes/test_broadcast_args_pass.py | 57 + .../arm/test/passes/test_cast_int64_pass.py | 49 + .../test_convert_expand_copy_to_repeat.py | 51 + .../test_convert_int64_const_ops_to_int32.py | 529 + .../test_convert_int64_output_ops_to_int32.py | 129 + ..._convert_permute_singleton_to_view_pass.py | 100 + .../passes/test_convert_split_to_slice.py | 75 + .../arm/test/passes/test_convert_to_clamp.py | 92 + .../passes/test_decompose_avg_pool2d_pass.py | 82 + .../test_decompose_cosine_similarity_pass.py | 58 + .../test/passes/test_decompose_div_pass.py | 70 + .../passes/test_decompose_int_pow_pass.py | 80 + .../passes/test_decompose_layernorm_pass.py | 69 + .../test_decompose_linalg_vector_norm_pass.py | 107 + .../passes/test_decompose_meandim_pass.py | 137 + .../test/passes/test_decompose_quant_nodes.py | 44 + .../passes/test_decompose_softmax_pass.py | 103 + ...t_decompose_tosa_unsupported_clamp_pass.py | 73 + .../test/passes/test_decompose_var_pass.py | 89 + ...est_decorate_fp32_to_int32_casting_pass.py | 85 + .../arm/test/passes/test_fold_qdq_pass.py | 51 + .../test/passes/test_fuse_batchnorm_pass.py | 164 + .../passes/test_fuse_constant_ops_pass.py | 177 + .../passes/test_fuse_duplicate_users_pass.py | 70 + .../test_fuse_equal_placeholders_ops_pass.py | 170 + .../arm/test/passes/test_fuse_view_copy.py | 82 + ...t32_casts_after_int64_placeholders_pass.py | 114 + .../passes/test_insert_rescale_i32_pass.py | 107 + .../test/passes/test_insert_table_ops_pass.py | 47 + .../passes/test_int32_cast_embedding_pass.py | 46 + .../test/passes/test_ioquantization_pass.py | 48 + .../passes/test_promote_bool_operands_pass.py | 103 + .../arm/test/passes/test_remove_clone_pass.py | 45 + .../passes/test_replace_inf_values_pass.py | 96 + .../arm/test/passes/test_rescale_pass.py | 81 + .../arm/test/passes/test_rewrite_conv_pass.py | 20 + .../test/passes/test_to_tosa_memory_format.py | 213 + .../test_unsqueeze_before_repeat_pass.py | 62 + .../src/backends/arm/test/pytest.ini | 5 + .../test/quantizer/test_conv_relu_fusing.py | 118 + .../test/quantizer/test_generic_annotater.py | 109 + .../quantizer/test_partial_quantization.py | 104 + .../quantizer/test_selective_quantization.py | 212 + .../test/quantizer/test_set_module_name.py | 158 + .../quantizer/test_tosa_quantizer_validate.py | 55 + .../src/backends/arm/test/runner_utils.py | 840 + .../src/backends/arm/test/setup_testing.sh | 32 + .../backends/arm/test/setup_testing_vkml.sh | 14 + .../src/backends/arm/test/targets.bzl | 79 + .../backends/arm/test/test_arm_baremetal.sh | 347 + .../src/backends/arm/test/test_arm_ootb.sh | 140 + .../arm/test/test_memory_allocator_log.py | 170 + .../src/backends/arm/test/test_model.py | 345 + .../src/backends/arm/test/tester/__init__.py | 6 + .../arm/test/tester/analyze_output_utils.py | 346 + .../backends/arm/test/tester/arm_tester.py | 1149 + .../src/backends/arm/test/tester/quantize.py | 43 + .../src/backends/arm/test/tester/serialize.py | 78 + .../backends/arm/test/tester/test_pipeline.py | 1190 + .../ethos-u-core-driver/.clang-format | 144 + .../ethos-u-core-driver/.gitignore | 1 + .../ethos-u-core-driver/CMakeLists.txt | 114 + .../ethos-u-core-driver/LICENSE.txt | 201 + .../third-party/ethos-u-core-driver/README.md | 330 + .../ethos-u-core-driver/SECURITY.md | 85 + .../include/ethosu_driver.h | 399 + .../include/ethosu_types.h | 84 + .../ethos-u-core-driver/include/pmu_ethosu.h | 515 + .../src/ethosu55_interface.h | 26197 ++++++++++++++++ .../src/ethosu65_interface.h | 26060 +++++++++++++++ .../src/ethosu85_interface.h | 24620 +++++++++++++++ .../src/ethosu_config_u55.h | 124 + .../src/ethosu_config_u65.h | 124 + .../src/ethosu_config_u85.h | 112 + .../ethos-u-core-driver/src/ethosu_device.h | 115 + .../src/ethosu_device_u55_u65.c | 373 + .../src/ethosu_device_u85.c | 373 + .../ethos-u-core-driver/src/ethosu_driver.c | 808 + .../src/ethosu_interface.h | 32 + .../ethos-u-core-driver/src/ethosu_log.h | 82 + .../ethos-u-core-driver/src/ethosu_pmu.c | 316 + .../ethos-u-core-driver/zephyr/module.yml | 6 + .../src/backends/arm/tosa/TARGETS | 80 + .../src/backends/arm/tosa/__init__.py | 9 + .../src/backends/arm/tosa/backend.py | 443 + .../src/backends/arm/tosa/compile_spec.py | 48 + .../src/backends/arm/tosa/dialect/TARGETS | 36 + .../src/backends/arm/tosa/dialect/__init__.py | 15 + .../src/backends/arm/tosa/dialect/lib.py | 85 + .../backends/arm/tosa/dialect/ops/conv2d.py | 111 + .../backends/arm/tosa/dialect/ops/conv3d.py | 74 + .../arm/tosa/dialect/ops/depthwise_conv2d.py | 56 + .../backends/arm/tosa/dialect/ops/matmul.py | 56 + .../backends/arm/tosa/dialect/ops/rescale.py | 53 + .../backends/arm/tosa/dialect/ops/resize.py | 66 + .../backends/arm/tosa/dialect/ops/table.py | 53 + .../arm/tosa/dialect/ops/transpose.py | 35 + .../arm/tosa/dialect/ops_registration.py | 68 + .../src/backends/arm/tosa/mapping.py | 309 + .../src/backends/arm/tosa/partitioner.py | 486 + .../src/backends/arm/tosa/schemas/README.md | 5 + .../src/backends/arm/tosa/schemas/__init__.py | 4 + .../backends/arm/tosa/schemas/tosa_1.0.fbs | 559 + .../src/backends/arm/tosa/specification.py | 406 + .../src/backends/arm/tosa/utils.py | 304 + .../src/backends/arm/util/_factory.py | 59 + .../backends/arm/util/arm_model_evaluator.py | 388 + .../src/backends/arm/vgf/__init__.py | 11 + .../src/backends/arm/vgf/backend.py | 172 + .../src/backends/arm/vgf/compile_spec.py | 73 + .../src/backends/arm/vgf/model_converter.py | 34 + .../src/backends/arm/vgf/partitioner.py | 35 + .../src/backends/cortex_m/CMakeLists.txt | 108 + .../src/backends/cortex_m/README.md | 3 + .../src/backends/cortex_m/ops/BUCK | 11 + .../src/backends/cortex_m/ops/TARGETS | 24 + .../ops/cmsis_scratch_buffer_context.h | 4 +- .../cortex_m/ops/cortex_m_ops_common.h | 231 + .../cortex_m/ops/op_dequantize_per_tensor.cpp | 196 + .../src/backends/cortex_m/ops/op_maximum.cpp | 5 + .../src/backends/cortex_m/ops/op_minimum.cpp | 5 + .../cortex_m/ops/op_quantize_per_tensor.cpp | 235 + .../cortex_m/ops/op_quantized_add.cpp | 59 +- .../cortex_m/ops/op_quantized_avg_pool2d.cpp | 86 + .../cortex_m/ops/op_quantized_conv2d.cpp | 56 +- .../ops/op_quantized_depthwise_conv2d.cpp | 21 +- .../cortex_m/ops/op_quantized_linear.cpp | 36 +- .../cortex_m/ops/op_quantized_mul.cpp | 31 +- .../src}/backends/cortex_m/ops/op_softmax.cpp | 13 +- .../backends/cortex_m/ops/op_transpose.cpp | 9 +- .../src/backends/cortex_m/ops/operators.py | 890 + .../src/backends/cortex_m/ops/operators.yaml | 33 +- .../src/backends/cortex_m/ops/targets.bzl | 80 + .../src/backends/cortex_m/passes/TARGETS | 35 + .../src/backends/cortex_m/passes/__init__.py | 12 + .../cortex_m/passes/activation_fusion_pass.py | 181 + .../cortex_m/passes/clamp_hardswish_pass.py | 37 + .../passes/convert_to_cortex_m_pass.py | 318 + .../cortex_m/passes/cortex_m_pass_manager.py | 73 + .../passes/decompose_hardswish_pass.py | 127 + .../backends/cortex_m/passes/passes_utils.py | 226 + .../passes/quantized_op_fusion_pass.py | 255 + .../passes/replace_quant_nodes_pass.py | 67 + .../src/backends/cortex_m/quantizer/TARGETS | 36 + .../backends/cortex_m/quantizer/__init__.py | 18 + .../cortex_m/quantizer/operator_configs.py | 74 + .../quantizer/quantization_configs.py | 121 + .../backends/cortex_m/quantizer/quantizer.py | 500 + .../src/backends/cortex_m/test/BUCK | 11 + .../src/backends/cortex_m/test/TARGETS | 25 + .../cortex_m/test/build_test_runner.sh | 33 + .../cortex_m/test/misc/test_quantization.py | 359 + .../backends/cortex_m/test/models/__init__.py | 4 + .../cortex_m/test/models/test_mobilenet_v3.py | 74 + .../test/op_dequantize_per_tensor_test.cpp | 55 + .../test/op_quantize_per_tensor_test.cpp | 55 + .../backends/cortex_m/test/ops/__init__.py | 4 + .../cortex_m/test/ops/test_activation.py | 528 + .../backends/cortex_m/test/ops/test_add.py | 182 + .../cortex_m/test/ops/test_avg_pool2d.py | 99 + .../backends/cortex_m/test/ops/test_conv.py | 342 + .../backends/cortex_m/test/ops/test_linear.py | 130 + .../backends/cortex_m/test/ops/test_lstm.py | 98 + .../cortex_m/test/ops/test_maximum.py | 83 + .../cortex_m/test/ops/test_minimum.py | 104 + .../backends/cortex_m/test/ops/test_mul.py | 156 + .../cortex_m/test/ops/test_softmax.py | 84 + .../cortex_m/test/ops/test_transpose.py | 102 + .../src/backends/cortex_m/test/targets.bzl | 41 + .../test/test_helpers_passes_utils.py | 103 + .../cortex_m/test/test_replace_quant_nodes.py | 134 + .../src/backends/cortex_m/test/tester.py | 113 + .../src/extension/data_loader/BUCK | 8 + .../src/extension/data_loader/CMakeLists.txt | 51 + .../src/extension/data_loader/TARGETS | 8 + .../data_loader/buffer_data_loader.h | 7 +- .../data_loader/file_data_loader.cpp | 70 +- .../extension/data_loader/file_data_loader.h | 0 .../file_descriptor_data_loader.cpp | 13 +- .../data_loader/file_descriptor_data_loader.h | 0 .../src}/extension/data_loader/mman.h | 46 - .../extension/data_loader/mman_windows.cpp | 0 .../src/extension/data_loader/mman_windows.h | 0 .../data_loader/mmap_data_loader.cpp | 12 +- .../extension/data_loader/mmap_data_loader.h | 4 - .../data_loader/shared_ptr_data_loader.h | 7 +- .../src/extension/data_loader/targets.bzl | 70 + .../src/extension/data_loader/test/BUCK | 6 + .../extension/data_loader/test/CMakeLists.txt | 29 + .../src/extension/data_loader/test/TARGETS | 8 + .../test/buffer_data_loader_test.cpp | 188 + .../test/file_data_loader_test.cpp | 250 + .../test/file_descriptor_data_loader_test.cpp | 360 + .../test/mmap_data_loader_test.cpp | 489 + .../test/shared_ptr_data_loader_test.cpp | 142 + .../extension/data_loader/test/targets.bzl | 61 + .../src/extension/memory_allocator/BUCK | 8 + .../extension/memory_allocator/CMakeLists.txt | 49 + .../src/extension/memory_allocator/TARGETS | 8 + .../cpu_caching_malloc_allocator.cpp | 0 .../cpu_caching_malloc_allocator.h | 0 .../malloc_memory_allocator.h | 0 .../memory_allocator/memory_allocator_utils.h | 0 .../extension/memory_allocator/targets.bzl | 35 + .../src/extension/memory_allocator/test/BUCK | 8 + .../memory_allocator/test/CMakeLists.txt | 24 + .../extension/memory_allocator/test/TARGETS | 8 + .../cpu_caching_malloc_allocator_test.cpp | 362 + .../test/malloc_memory_allocator_test.cpp | 145 + .../memory_allocator/test/targets.bzl | 27 + .../src/extension/runner_util/BUCK | 8 + .../src/extension/runner_util/CMakeLists.txt | 39 + .../src/extension/runner_util/TARGETS | 8 + .../src}/extension/runner_util/inputs.cpp | 48 +- .../src/extension/runner_util/inputs.h | 0 .../src/extension/runner_util/inputs_aten.cpp | 0 .../extension/runner_util/inputs_portable.cpp | 0 .../src/extension/runner_util/targets.bzl | 25 + .../src/extension/runner_util/test/BUCK | 8 + .../extension/runner_util/test/CMakeLists.txt | 50 + .../src/extension/runner_util/test/TARGETS | 8 + .../runner_util/test/inputs_test.cpp | 188 + .../extension/runner_util/test/targets.bzl | 32 + .../src/kernels/portable/BUCK | 8 + .../src/kernels/portable/CMakeLists.txt | 107 + .../src/kernels/portable/README.md | 1 + .../src/kernels/portable/TARGETS | 8 + .../src/kernels/portable/cpu/BUCK | 8 + .../src/kernels/portable/cpu/TARGETS | 8 + .../src/kernels/portable/cpu/math_constants.h | 0 .../portable/cpu/op__clone_dim_order.cpp | 0 .../portable/cpu/op__empty_dim_order.cpp | 0 .../portable/cpu/op__to_dim_order_copy.cpp | 80 + .../src/kernels/portable/cpu/op_abs.cpp | 0 .../src/kernels/portable/cpu/op_acos.cpp | 0 .../src/kernels/portable/cpu/op_acosh.cpp | 0 .../src/kernels/portable/cpu/op_add.cpp | 0 .../src/kernels/portable/cpu/op_addmm.cpp | 0 .../kernels/portable/cpu/op_alias_copy.cpp | 0 .../src}/kernels/portable/cpu/op_allclose.cpp | 6 +- .../src/kernels/portable/cpu/op_amax.cpp | 0 .../src/kernels/portable/cpu/op_amin.cpp | 0 .../src/kernels/portable/cpu/op_any.cpp | 0 .../src/kernels/portable/cpu/op_arange.cpp | 0 .../src/kernels/portable/cpu/op_argmax.cpp | 0 .../src/kernels/portable/cpu/op_argmin.cpp | 0 .../portable/cpu/op_as_strided_copy.cpp | 0 .../src/kernels/portable/cpu/op_asin.cpp | 0 .../src/kernels/portable/cpu/op_asinh.cpp | 0 .../src/kernels/portable/cpu/op_atan.cpp | 0 .../src/kernels/portable/cpu/op_atan2.cpp | 0 .../src/kernels/portable/cpu/op_atanh.cpp | 0 .../kernels/portable/cpu/op_avg_pool2d.cpp | 0 .../kernels/portable/cpu/op_bitwise_and.cpp | 0 .../portable/cpu/op_bitwise_left_shift.cpp | 0 .../kernels/portable/cpu/op_bitwise_not.cpp | 0 .../kernels/portable/cpu/op_bitwise_or.cpp | 0 .../portable/cpu/op_bitwise_right_shift.cpp | 0 .../kernels/portable/cpu/op_bitwise_xor.cpp | 0 .../src/kernels/portable/cpu/op_bmm.cpp | 0 .../src/kernels/portable/cpu/op_cat.cpp | 0 .../kernels/portable/cpu/op_cdist_forward.cpp | 0 .../src/kernels/portable/cpu/op_ceil.cpp | 0 .../src/kernels/portable/cpu/op_clamp.cpp | 0 .../src/kernels/portable/cpu/op_clone.cpp | 0 .../portable/cpu/op_constant_pad_nd.cpp | 39 +- .../kernels/portable/cpu/op_convolution.cpp | 16 +- .../portable/cpu/op_convolution_backward.cpp | 0 .../src/kernels/portable/cpu/op_copy.cpp | 0 .../src/kernels/portable/cpu/op_cos.cpp | 0 .../src/kernels/portable/cpu/op_cosh.cpp | 0 .../src/kernels/portable/cpu/op_cumsum.cpp | 0 .../kernels/portable/cpu/op_detach_copy.cpp | 0 .../kernels/portable/cpu/op_diagonal_copy.cpp | 0 .../src/kernels/portable/cpu/op_div.cpp | 47 +- .../src/kernels/portable/cpu/op_elu.cpp | 0 .../src/kernels/portable/cpu/op_embedding.cpp | 0 .../src/kernels/portable/cpu/op_empty.cpp | 0 .../src/kernels/portable/cpu/op_eq.cpp | 0 .../src/kernels/portable/cpu/op_erf.cpp | 0 .../src/kernels/portable/cpu/op_exp.cpp | 0 .../kernels/portable/cpu/op_expand_copy.cpp | 0 .../src/kernels/portable/cpu/op_expm1.cpp | 0 .../src/kernels/portable/cpu/op_fill.cpp | 0 .../src/kernels/portable/cpu/op_flip.cpp | 0 .../src/kernels/portable/cpu/op_floor.cpp | 0 .../kernels/portable/cpu/op_floor_divide.cpp | 0 .../src/kernels/portable/cpu/op_fmod.cpp | 0 .../src/kernels/portable/cpu/op_full.cpp | 0 .../src/kernels/portable/cpu/op_full_like.cpp | 0 .../src/kernels/portable/cpu/op_gather.cpp | 0 .../src/kernels/portable/cpu/op_ge.cpp | 0 .../src/kernels/portable/cpu/op_gelu.cpp | 0 .../src/kernels/portable/cpu/op_glu.cpp | 0 .../portable/cpu/op_grid_sampler_2d.cpp | 99 +- .../src/kernels/portable/cpu/op_gt.cpp | 0 .../src/kernels/portable/cpu/op_hardtanh.cpp | 0 .../src/kernels/portable/cpu/op_index.cpp | 0 .../src/kernels/portable/cpu/op_index_put.cpp | 0 .../kernels/portable/cpu/op_index_select.cpp | 0 .../src/kernels/portable/cpu/op_isinf.cpp | 0 .../src/kernels/portable/cpu/op_isnan.cpp | 0 .../src/kernels/portable/cpu/op_le.cpp | 0 .../kernels/portable/cpu/op_leaky_relu.cpp | 0 .../portable/cpu/op_lift_fresh_copy.cpp | 0 .../src/kernels/portable/cpu/op_log.cpp | 0 .../src/kernels/portable/cpu/op_log10.cpp | 0 .../src/kernels/portable/cpu/op_log1p.cpp | 0 .../src/kernels/portable/cpu/op_log2.cpp | 0 .../kernels/portable/cpu/op_log_softmax.cpp | 0 .../kernels/portable/cpu/op_logical_and.cpp | 0 .../kernels/portable/cpu/op_logical_not.cpp | 0 .../kernels/portable/cpu/op_logical_or.cpp | 0 .../kernels/portable/cpu/op_logical_xor.cpp | 0 .../src/kernels/portable/cpu/op_logit.cpp | 0 .../src/kernels/portable/cpu/op_lt.cpp | 0 .../kernels/portable/cpu/op_masked_fill.cpp | 0 .../portable/cpu/op_masked_scatter.cpp | 0 .../kernels/portable/cpu/op_masked_select.cpp | 0 .../src/kernels/portable/cpu/op_max.cpp | 0 .../cpu/op_max_pool2d_with_indices.cpp | 0 .../op_max_pool2d_with_indices_backward.cpp | 0 .../src/kernels/portable/cpu/op_maximum.cpp | 0 .../src/kernels/portable/cpu/op_mean.cpp | 30 - .../src/kernels/portable/cpu/op_min.cpp | 0 .../src/kernels/portable/cpu/op_minimum.cpp | 0 .../src/kernels/portable/cpu/op_mm.cpp | 0 .../src/kernels/portable/cpu/op_mul.cpp | 0 .../kernels/portable/cpu/op_narrow_copy.cpp | 0 .../portable/cpu/op_native_batch_norm.cpp | 5 - .../portable/cpu/op_native_dropout.cpp | 0 .../portable/cpu/op_native_group_norm.cpp | 4 +- .../portable/cpu/op_native_layer_norm.cpp | 51 +- .../src/kernels/portable/cpu/op_ne.cpp | 0 .../src/kernels/portable/cpu/op_neg.cpp | 0 .../src/kernels/portable/cpu/op_nonzero.cpp | 0 .../src/kernels/portable/cpu/op_ones.cpp | 0 .../kernels/portable/cpu/op_pdist_forward.cpp | 0 .../kernels/portable/cpu/op_permute_copy.cpp | 0 .../kernels/portable/cpu/op_pixel_shuffle.cpp | 0 .../portable/cpu/op_pixel_unshuffle.cpp | 0 .../src/kernels/portable/cpu/op_pow.cpp | 0 .../src/kernels/portable/cpu/op_prod.cpp | 0 .../src/kernels/portable/cpu/op_rand.cpp | 0 .../src/kernels/portable/cpu/op_randn.cpp | 0 .../kernels/portable/cpu/op_reciprocal.cpp | 0 .../portable/cpu/op_reflection_pad1d.cpp | 0 .../portable/cpu/op_reflection_pad2d.cpp | 0 .../portable/cpu/op_reflection_pad3d.cpp | 0 .../src/kernels/portable/cpu/op_relu.cpp | 0 .../src/kernels/portable/cpu/op_remainder.cpp | 0 .../src/kernels/portable/cpu/op_repeat.cpp | 0 .../portable/cpu/op_repeat_interleave.cpp | 0 .../portable/cpu/op_replication_pad1d.cpp | 0 .../portable/cpu/op_replication_pad2d.cpp | 0 .../portable/cpu/op_replication_pad3d.cpp | 0 .../src/kernels/portable/cpu/op_roll.cpp | 0 .../src/kernels/portable/cpu/op_round.cpp | 0 .../src/kernels/portable/cpu/op_rsqrt.cpp | 0 .../src/kernels/portable/cpu/op_rsub.cpp | 0 .../kernels/portable/cpu/op_scalar_tensor.cpp | 0 .../src/kernels/portable/cpu/op_scatter.cpp | 0 .../kernels/portable/cpu/op_scatter_add.cpp | 0 .../kernels/portable/cpu/op_select_copy.cpp | 0 .../portable/cpu/op_select_scatter.cpp | 0 .../src/kernels/portable/cpu/op_sigmoid.cpp | 0 .../src/kernels/portable/cpu/op_sign.cpp | 0 .../src/kernels/portable/cpu/op_sin.cpp | 0 .../src/kernels/portable/cpu/op_sinh.cpp | 0 .../kernels/portable/cpu/op_slice_copy.cpp | 0 .../kernels/portable/cpu/op_slice_scatter.cpp | 0 .../src/kernels/portable/cpu/op_softmax.cpp | 0 .../kernels/portable/cpu/op_split_copy.cpp | 0 .../portable/cpu/op_split_with_sizes_copy.cpp | 0 .../src/kernels/portable/cpu/op_sqrt.cpp | 0 .../kernels/portable/cpu/op_squeeze_copy.cpp | 0 .../src/kernels/portable/cpu/op_stack.cpp | 0 .../src/kernels/portable/cpu/op_sub.cpp | 0 .../src}/kernels/portable/cpu/op_sum.cpp | 30 - .../src/kernels/portable/cpu/op_t_copy.cpp | 0 .../src/kernels/portable/cpu/op_tan.cpp | 0 .../src/kernels/portable/cpu/op_tanh.cpp | 0 .../src/kernels/portable/cpu/op_to_copy.cpp | 0 .../src/kernels/portable/cpu/op_topk.cpp | 0 .../portable/cpu/op_transpose_copy.cpp | 0 .../src/kernels/portable/cpu/op_tril.cpp | 0 .../src/kernels/portable/cpu/op_trunc.cpp | 0 .../kernels/portable/cpu/op_unbind_copy.cpp | 0 .../kernels/portable/cpu/op_unfold_copy.cpp | 0 .../portable/cpu/op_unsqueeze_copy.cpp | 0 .../portable/cpu/op_upsample_bilinear2d.cpp | 0 .../cpu/op_upsample_bilinear2d_aa.cpp | 0 .../portable/cpu/op_upsample_nearest2d.cpp | 0 .../src/kernels/portable/cpu/op_var.cpp | 0 .../portable/cpu/op_view_as_real_copy.cpp | 0 .../src/kernels/portable/cpu/op_view_copy.cpp | 0 .../src/kernels/portable/cpu/op_where.cpp | 0 .../src/kernels/portable/cpu/op_zeros.cpp | 0 .../src/kernels/portable/cpu/pattern/BUCK | 8 + .../src/kernels/portable/cpu/pattern/TARGETS | 8 + .../kernels/portable/cpu/pattern/bitwise_op.h | 0 .../portable/cpu/pattern/comparison_op.h | 0 .../kernels/portable/cpu/pattern/logical_op.h | 0 .../kernels/portable/cpu/pattern/pattern.h | 0 .../kernels/portable/cpu/pattern/targets.bzl | 64 + .../unary_ufunc_realhbbf16_to_bool.cpp | 0 .../unary_ufunc_realhbbf16_to_floathbf16.cpp | 0 .../cpu/pattern/unary_ufunc_realhbf16.cpp | 0 .../src/kernels/portable/cpu/scalar_utils.h | 4 +- .../kernels/portable/cpu/selective_build.h | 0 .../src/kernels/portable/cpu/targets.bzl | 89 + .../src/kernels/portable/cpu/test/BUCK | 8 + .../src/kernels/portable/cpu/test/TARGETS | 8 + .../portable/cpu/test/scalar_utils_test.cpp | 73 + .../src/kernels/portable/cpu/test/targets.bzl | 29 + .../portable/cpu/test/vec_ops_test.cpp | 362 + .../src/kernels/portable/cpu/util/BUCK | 8 + .../kernels/portable/cpu/util/CMakeLists.txt | 43 + .../src/kernels/portable/cpu/util/TARGETS | 8 + .../portable/cpu/util/activation_ops_util.cpp | 0 .../portable/cpu/util/activation_ops_util.h | 0 .../portable/cpu/util/advanced_index_util.cpp | 0 .../portable/cpu/util/advanced_index_util.h | 0 .../kernels/portable/cpu/util/arange_util.cpp | 0 .../kernels/portable/cpu/util/arange_util.h | 0 .../cpu/util/broadcast_indexes_range.h | 0 .../portable/cpu/util/broadcast_util.cpp | 0 .../portable/cpu/util/broadcast_util.h | 0 .../portable/cpu/util/copy_ops_util.cpp | 0 .../kernels/portable/cpu/util/copy_ops_util.h | 0 .../portable/cpu/util/delinearize_index.cpp | 0 .../portable/cpu/util/delinearize_index.h | 0 .../portable/cpu/util/distance_util.cpp | 0 .../kernels/portable/cpu/util/distance_util.h | 2 +- .../kernels/portable/cpu/util/dtype_util.cpp | 0 .../kernels/portable/cpu/util/dtype_util.h | 0 .../portable/cpu/util/elementwise_util.h | 0 .../portable/cpu/util/functional_util.h | 0 .../cpu/util/grid_sampler_2d_util.cpp | 0 .../portable/cpu/util/grid_sampler_2d_util.h | 0 .../kernels/portable/cpu/util/index_util.cpp | 0 .../kernels/portable/cpu/util/index_util.h | 0 .../portable/cpu/util/kernel_ops_util.cpp | 55 - .../portable/cpu/util/kernel_ops_util.h | 21 +- .../src/kernels/portable/cpu/util/math_util.h | 3 +- .../portable/cpu/util/matmul_ops_util.cpp | 0 .../portable/cpu/util/matmul_ops_util.h | 0 .../cpu/util/normalization_ops_util.cpp | 0 .../cpu/util/normalization_ops_util.h | 44 - .../portable/cpu/util/padding_util.cpp | 0 .../kernels/portable/cpu/util/padding_util.h | 0 .../kernels/portable/cpu/util/reduce_util.cpp | 0 .../kernels/portable/cpu/util/reduce_util.h | 0 .../kernels/portable/cpu/util/repeat_util.cpp | 0 .../kernels/portable/cpu/util/repeat_util.h | 0 .../portable/cpu/util/select_copy_util.cpp | 0 .../portable/cpu/util/select_copy_util.h | 0 .../kernels/portable/cpu/util/slice_util.cpp | 0 .../kernels/portable/cpu/util/slice_util.h | 0 .../kernels/portable/cpu/util/stack_util.cpp | 0 .../kernels/portable/cpu/util/stack_util.h | 0 .../src/kernels/portable/cpu/util/targets.bzl | 383 + .../src/kernels/portable/cpu/util/test/BUCK | 8 + .../portable/cpu/util/test/CMakeLists.txt | 29 + .../kernels/portable/cpu/util/test/TARGETS | 8 + .../test/broadcast_indexes_range_test.cpp | 266 + .../portable/cpu/util/test/broadcast_test.cpp | 202 + .../portable/cpu/util/test/reduce_test.cpp | 583 + .../portable/cpu/util/test/targets.bzl | 45 + .../cpu/util/test/vectorized_math_test.cpp | 95 + .../portable/cpu/util/transpose_util.h | 0 .../portable/cpu/util/upsample_util.cpp | 0 .../kernels/portable/cpu/util/upsample_util.h | 11 +- .../portable/cpu/util/vectorized_math.h | 2 +- .../src}/kernels/portable/cpu/vec_ops.h | 10 +- .../src/kernels/portable/custom_ops.yaml | 0 .../src/kernels/portable/find_op_header.sh | 51 + .../src/kernels/portable/functions.yaml | 17 +- .../src/kernels/portable/targets.bzl | 94 + .../src/kernels/portable/test/BUCK | 8 + .../src/kernels/portable/test/TARGETS | 28 + .../test/dtype_selective_build_test.cpp | 75 + .../portable/test/op_allclose_test.cpp | 332 + .../src/kernels/portable/test/op_div_test.cpp | 120 + .../kernels/portable/test/op_gelu_test.cpp | 72 + .../portable/test/op_grid_sampler_2d_test.py | 234 + .../src/kernels/portable/test/op_mul_test.cpp | 72 + .../test/op_upsample_bilinear2d_aa_test.py | 346 + .../test/op_upsample_bilinear2d_test.py | 87 + .../test/op_upsample_nearest2d_test.py | 71 + .../test/register_ops_aot_for_test.cpp | 153 + .../portable/test/supported_features_def.yaml | 1 + .../src/kernels/portable/test/targets.bzl | 101 + .../test/test_grid_sampler_2d_executorch.py | 458 + .../src/kernels/prim_ops/BUCK | 8 + .../src/kernels/prim_ops/TARGETS | 7 + .../src/kernels/prim_ops/et_copy_index.cpp | 0 .../src/kernels/prim_ops/et_copy_index.h | 0 .../src/kernels/prim_ops/et_view.cpp | 0 .../src/kernels/prim_ops/et_view.h | 0 .../kernels/prim_ops/register_prim_ops.cpp | 12 +- .../prim_ops/selective_build_prim_ops.h | 0 .../src/kernels/prim_ops/targets.bzl | 78 + .../src/kernels/prim_ops/test/BUCK | 0 .../src/kernels/prim_ops/test/CMakeLists.txt | 23 + .../src/kernels/prim_ops/test/TARGETS | 37 + .../kernels/prim_ops/test/prim_ops_test.cpp | 932 + .../kernels/prim_ops/test/prim_ops_test.py | 23 + .../src/kernels/quantized/BUCK | 5 + .../src/kernels/quantized/CMakeLists.txt | 158 + .../src/kernels/quantized/README.md | 12 + .../src/kernels/quantized/TARGETS | 5 + .../src/kernels/quantized/__init__.py | 21 + .../src/kernels/quantized/cpu/BUCK | 5 + .../src/kernels/quantized/cpu/TARGETS | 5 + .../src/kernels/quantized/cpu/embeddingxb.cpp | 0 .../src/kernels/quantized/cpu/embeddingxb.h | 0 .../src/kernels/quantized/cpu/op_add.cpp | 0 .../quantized/cpu/op_choose_qparams.cpp | 0 .../kernels/quantized/cpu/op_dequantize.cpp | 0 .../kernels/quantized/cpu/op_embedding.cpp | 0 .../kernels/quantized/cpu/op_embedding2b.cpp | 0 .../kernels/quantized/cpu/op_embedding4b.cpp | 0 .../kernels/quantized/cpu/op_mixed_linear.cpp | 0 .../src/kernels/quantized/cpu/op_mixed_mm.cpp | 0 .../src/kernels/quantized/cpu/op_quantize.cpp | 0 .../src/kernels/quantized/cpu/targets.bzl | 102 + .../src/kernels/quantized/quantized.yaml | 0 .../src/kernels/quantized/targets.bzl | 130 + .../src/kernels/quantized/test/BUCK | 5 + .../src/kernels/quantized/test/TARGETS | 51 + .../kernels/quantized/test/op_add_test.cpp | 413 + .../quantized/test/op_choose_qparams_test.cpp | 260 + .../quantized/test/op_dequantize_test.cpp | 321 + .../quantized/test/op_embedding2b_test.cpp | 236 + .../quantized/test/op_embedding4b_test.cpp | 201 + .../quantized/test/op_embedding_test.cpp | 410 + .../quantized/test/op_mixed_linear_test.cpp | 142 + .../quantized/test/op_mixed_mm_test.cpp | 71 + .../quantized/test/op_quantize_test.cpp | 983 + .../test/quantized_ops_aot_register.cpp | 137 + .../test/supported_features_def.yaml | 1 + .../src/kernels/quantized/test/targets.bzl | 41 + .../quantized/test/test_out_variants.py | 100 + .../test/test_quant_dequant_per_token.py | 149 + .../src/registration/RegisterAllKernels.cpp | 5437 ++++ .../src/runtime/backend/BUCK | 5 + .../src/runtime/backend/TARGETS | 8 + .../backend/backend_execution_context.h | 0 .../runtime/backend/backend_init_context.h | 59 +- .../runtime/backend/backend_option_context.h | 0 .../src/runtime/backend/interface.cpp | 0 .../src/runtime/backend/interface.h | 0 .../src/runtime/backend/options.h | 0 .../src/runtime/backend/targets.bzl | 33 + .../src/runtime/backend/test/BUCK | 8 + .../src/runtime/backend/test/TARGETS | 8 + .../test/backend_interface_update_test.cpp | 402 + .../backend/test/backend_options_test.cpp | 164 + .../src/runtime/backend/test/targets.bzl | 26 + .../src/runtime/core/BUCK | 8 + .../src/runtime/core/TARGETS | 8 + .../src}/runtime/core/array_ref.h | 4 +- .../src/runtime/core/data_loader.h | 0 .../src/runtime/core/defines.h | 0 .../src}/runtime/core/error.h | 6 - .../src/runtime/core/evalue.cpp | 25 - .../src/runtime/core/evalue.h | 277 +- .../src/runtime/core/event_tracer.h | 0 .../src/runtime/core/event_tracer_hooks.h | 0 .../core/event_tracer_hooks_delegate.h | 0 .../src/runtime/core/exec_aten/BUCK | 8 + .../src/runtime/core/exec_aten/TARGETS | 8 + .../src/runtime/core/exec_aten/exec_aten.h | 31 - .../src/runtime/core/exec_aten/targets.bzl | 21 + .../runtime/core/exec_aten/testing_util/BUCK | 8 + .../core/exec_aten/testing_util/README.md | 4 + .../core/exec_aten/testing_util/TARGETS | 8 + .../core/exec_aten/testing_util/targets.bzl | 32 + .../exec_aten/testing_util/tensor_factory.h | 1133 + .../exec_aten/testing_util/tensor_util.cpp | 353 + .../core/exec_aten/testing_util/tensor_util.h | 378 + .../core/exec_aten/testing_util/test/BUCK | 8 + .../testing_util/test/CMakeLists.txt | 26 + .../core/exec_aten/testing_util/test/TARGETS | 8 + .../exec_aten/testing_util/test/targets.bzl | 30 + .../testing_util/test/tensor_factory_test.cpp | 1229 + .../testing_util/test/tensor_util_test.cpp | 848 + .../src/runtime/core/exec_aten/util/BUCK | 8 + .../src/runtime/core/exec_aten/util/README.md | 2 + .../src/runtime/core/exec_aten/util/TARGETS | 8 + .../core/exec_aten/util/dim_order_util.h | 16 +- .../core/exec_aten/util/scalar_type_util.h | 0 .../runtime/core/exec_aten/util/targets.bzl | 85 + .../exec_aten/util/tensor_dimension_limit.h | 0 .../util/tensor_shape_to_c_string.cpp | 0 .../exec_aten/util/tensor_shape_to_c_string.h | 0 .../runtime/core/exec_aten/util/tensor_util.h | 0 .../core/exec_aten/util/tensor_util_aten.cpp | 0 .../exec_aten/util/tensor_util_portable.cpp | 0 .../src/runtime/core/exec_aten/util/test/BUCK | 8 + .../core/exec_aten/util/test/CMakeLists.txt | 28 + .../runtime/core/exec_aten/util/test/TARGETS | 8 + .../util/test/dim_order_util_test.cpp | 289 + .../util/test/operator_impl_example_test.cpp | 187 + .../util/test/scalar_type_util_test.cpp | 222 + .../core/exec_aten/util/test/targets.bzl | 60 + .../test/tensor_shape_to_c_string_test.cpp | 89 + .../exec_aten/util/test/tensor_util_test.cpp | 608 + .../src/runtime/core/freeable_buffer.h | 0 .../src/runtime/core/function_ref.h | 0 .../runtime/core/hierarchical_allocator.h | 6 +- .../src/runtime/core/memory_allocator.h | 0 .../src/runtime/core/named_data_map.h | 0 .../src/runtime/core/portable_type/BUCK | 8 + .../src/runtime/core/portable_type/TARGETS | 8 + .../src/runtime/core/portable_type/bfloat16.h | 0 .../core/portable_type/bfloat16_math.h | 0 .../runtime/core/portable_type/bits_types.h | 0 .../runtime/core/portable_type/c10/README.md | 20 + .../runtime/core/portable_type/c10/c10/BUCK | 8 + .../core/portable_type/c10/c10/TARGETS | 8 + .../portable_type/c10/c10/macros/Export.h | 0 .../portable_type/c10/c10/macros/Macros.h | 0 .../core/portable_type/c10/c10/targets.bzl | 139 + .../portable_type/c10/c10/util/BFloat16-inl.h | 0 .../c10/c10/util/BFloat16-math.h | 0 .../portable_type/c10/c10/util/BFloat16.h | 0 .../portable_type/c10/c10/util/Half-inl.h | 0 .../core/portable_type/c10/c10/util/Half.h | 0 .../c10/c10/util/TypeSafeSignMath.h | 0 .../portable_type/c10/c10/util/bit_cast.h | 0 .../core/portable_type/c10/c10/util/complex.h | 0 .../portable_type/c10/c10/util/complex_math.h | 35 - .../c10/c10/util/complex_utils.h | 0 .../c10/c10/util/floating_point_utils.h | 0 .../core/portable_type/c10/c10/util/irange.h | 0 .../c10/c10/util/llvmMathExtras.h | 0 .../portable_type/c10/c10/util/overflows.h | 0 .../c10/c10/util/safe_numerics.h | 0 .../portable_type/c10/torch/headeronly/BUCK | 5 + .../c10/torch/headeronly/TARGETS | 5 + .../c10/torch/headeronly/macros/Export.h | 8 + .../c10/torch/headeronly/macros/Macros.h | 79 +- .../c10/torch/headeronly/targets.bzl | 14 + .../c10/torch/headeronly/util/BFloat16.h | 13 +- .../c10/torch/headeronly/util/Half.h | 0 .../torch/headeronly/util/TypeSafeSignMath.h | 0 .../c10/torch/headeronly/util/bit_cast.h | 0 .../c10/torch/headeronly/util/complex.h | 0 .../headeronly/util/floating_point_utils.h | 0 .../src/runtime/core/portable_type/complex.h | 0 .../src}/runtime/core/portable_type/device.h | 37 +- .../src/runtime/core/portable_type/half.h | 0 .../src/runtime/core/portable_type/optional.h | 0 .../runtime/core/portable_type/qint_types.h | 0 .../src/runtime/core/portable_type/scalar.h | 0 .../runtime/core/portable_type/scalar_type.h | 0 .../runtime/core/portable_type/string_view.h | 0 .../runtime/core/portable_type/targets.bzl | 67 + .../src/runtime/core/portable_type/tensor.h | 0 .../core/portable_type/tensor_impl.cpp | 49 +- .../runtime/core/portable_type/tensor_impl.h | 38 +- .../core/portable_type/tensor_options.h | 0 .../src/runtime/core/portable_type/test/BUCK | 8 + .../core/portable_type/test/CMakeLists.txt | 32 + .../runtime/core/portable_type/test/TARGETS | 8 + .../core/portable_type/test/bfloat16_test.cpp | 209 + .../test/dont_shadow_complex_test.c | 9 + .../core/portable_type/test/half_test.cpp | 213 + .../core/portable_type/test/optional_test.cpp | 142 + .../core/portable_type/test/scalar_test.cpp | 47 + .../core/portable_type/test/targets.bzl | 58 + .../portable_type/test/tensor_impl_test.cpp | 460 + .../core/portable_type/test/tensor_test.cpp | 80 + .../src/runtime/core/result.h | 0 .../src/runtime/core/span.h | 0 .../src/runtime/core/tag.cpp | 0 .../src/runtime/core/tag.h | 0 .../src/runtime/core/targets.bzl | 157 + .../src}/runtime/core/tensor_layout.cpp | 17 +- .../src/runtime/core/tensor_layout.h | 0 .../src/runtime/core/tensor_shape_dynamism.h | 0 .../src/runtime/core/test/BUCK | 8 + .../src/runtime/core/test/CMakeLists.txt | 34 + .../src/runtime/core/test/TARGETS | 8 + .../src/runtime/core/test/array_ref_test.cpp | 22 + .../runtime/core/test/error_handling_test.cpp | 214 + .../src/runtime/core/test/evalue_test.cpp | 410 + .../runtime/core/test/event_tracer_test.cpp | 345 + .../core/test/freeable_buffer_test.cpp | 269 + .../runtime/core/test/function_ref_test.cpp | 59 + .../core/test/hierarchical_allocator_test.cpp | 143 + .../core/test/memory_allocator_test.cpp | 267 + .../src/runtime/core/test/span_test.cpp | 79 + .../src/runtime/core/test/tag_test.cpp | 94 + .../src/runtime/core/test/targets.bzl | 130 + .../runtime/core/test/tensor_layout_test.cpp | 78 + .../test/tensor_shape_dynamism_test_aten.cpp | 25 + .../src/runtime/core/testing_util/BUCK | 8 + .../src/runtime/core/testing_util/TARGETS | 8 + .../core/testing_util/error_matchers.cpp | 23 + .../core/testing_util/error_matchers.h | 303 + .../src/runtime/core/testing_util/targets.bzl | 25 + .../src/runtime/core/testing_util/test/BUCK | 8 + .../runtime/core/testing_util/test/TARGETs | 8 + .../core/testing_util/test/targets.bzl | 19 + .../testing_util/test/test_error_matchers.cpp | 134 + .../src/runtime/executor/BUCK | 8 + .../src/runtime/executor/TARGETS | 8 + .../src/runtime/executor/memory_manager.h | 0 .../src/runtime/executor/merged_data_map.h | 0 .../src/runtime/executor/method.cpp | 182 +- .../src/runtime/executor/method.h | 16 +- .../src}/runtime/executor/method_meta.cpp | 85 +- .../src}/runtime/executor/method_meta.h | 14 - .../executor/platform_memory_allocator.h | 17 +- .../src}/runtime/executor/program.cpp | 189 +- .../src}/runtime/executor/program.h | 15 +- .../src/runtime/executor/pte_data_map.cpp | 0 .../src/runtime/executor/pte_data_map.h | 0 .../src/runtime/executor/targets.bzl | 127 + .../src}/runtime/executor/tensor_parser.h | 6 +- .../runtime/executor/tensor_parser_aten.cpp | 0 .../executor/tensor_parser_exec_aten.cpp | 38 +- .../executor/tensor_parser_portable.cpp | 16 +- .../src/runtime/executor/test/BUCK | 8 + .../src/runtime/executor/test/CMakeLists.txt | 194 + .../src/runtime/executor/test/TARGETS | 8 + .../test/allocation_failure_stress_test.cpp | 137 + .../test/backend_data_separation_test.cpp | 116 + .../test/backend_integration_test.cpp | 745 + .../runtime/executor/test/executor_test.cpp | 275 + .../executor/test/kernel_integration_test.cpp | 385 + .../executor/test/kernel_resolution_test.cpp | 123 + .../executor/test/managed_memory_manager.h | 68 + .../executor/test/memory_manager_test.cpp | 95 + .../executor/test/merged_data_map_test.cpp | 148 + .../executor/test/method_meta_test.cpp | 216 + .../src/runtime/executor/test/method_test.cpp | 547 + .../runtime/executor/test/program_test.cpp | 595 + .../executor/test/pte_data_map_test.cpp | 277 + .../src/runtime/executor/test/targets.bzl | 300 + .../executor/test/tensor_parser_test.cpp | 190 + .../test/test_backend_compiler_lib.cpp | 237 + .../test_backend_with_delegate_mapping.cpp | 176 + .../src/runtime/kernel/BUCK | 8 + .../src/runtime/kernel/TARGETS | 8 + .../src/runtime/kernel/kernel_includes.h | 0 .../runtime/kernel/kernel_runtime_context.h | 0 .../src}/runtime/kernel/operator_registry.cpp | 46 +- .../src/runtime/kernel/operator_registry.h | 20 +- .../src/runtime/kernel/targets.bzl | 97 + .../src/runtime/kernel/test/BUCK | 8 + .../src/runtime/kernel/test/CMakeLists.txt | 55 + .../src/runtime/kernel/test/TARGETS | 8 + .../src/runtime/kernel/test/functions.yaml | 13 + .../test/kernel_double_registration_test.cpp | 43 + .../test/kernel_runtime_context_test.cpp | 102 + .../operator_registry_max_kernel_num_test.cpp | 53 + .../kernel/test/operator_registry_test.cpp | 517 + .../src/runtime/kernel/test/targets.bzl | 116 + .../test/test_generated_lib_and_aten.cpp | 45 + .../test/test_kernel_manual_registration.cpp | 40 + .../src/runtime/kernel/test/test_util.h | 40 + .../kernel/thread_parallel_interface.h | 0 .../src/runtime/platform/BUCK | 8 + .../src/runtime/platform/TARGETS | 8 + .../src/runtime/platform/abort.cpp | 0 .../src/runtime/platform/abort.h | 0 .../src/runtime/platform/assert.h | 0 .../src/runtime/platform/clock.h | 0 .../src/runtime/platform/compat_unistd.h | 0 .../src}/runtime/platform/compiler.h | 2 +- .../src/runtime/platform/default/android.cpp | 0 .../src}/runtime/platform/default/minimal.cpp | 29 +- .../src/runtime/platform/default/posix.cpp | 0 .../src/runtime/platform/default/zephyr.cpp | 0 .../src/runtime/platform/log.bzl | 22 + .../src/runtime/platform/log.cpp | 0 .../src/runtime/platform/log.h | 0 .../src/runtime/platform/platform.cpp | 0 .../src/runtime/platform/platform.h | 0 .../src/runtime/platform/profiler.cpp | 0 .../src/runtime/platform/profiler.h | 0 .../src/runtime/platform/runtime.cpp | 0 .../src/runtime/platform/runtime.h | 0 .../src/runtime/platform/system.h | 0 .../src/runtime/platform/targets.bzl | 120 + .../src/runtime/platform/test/BUCK | 8 + .../src/runtime/platform/test/CMakeLists.txt | 47 + .../src/runtime/platform/test/TARGETS | 8 + .../src/runtime/platform/test/clock_test.cpp | 37 + .../platform/test/executor_pal_death_test.cpp | 36 + .../test/executor_pal_override_test.cpp | 135 + .../executor_pal_runtime_override_test.cpp | 130 + ...cutor_pal_static_runtime_override_test.cpp | 94 + .../platform/test/executor_pal_test.cpp | 35 + .../runtime/platform/test/logging_test.cpp | 88 + .../src/runtime/platform/test/pal_spy.h | 86 + .../runtime/platform/test/stub_platform.cpp | 102 + .../src/runtime/platform/test/stub_platform.h | 76 + .../src/runtime/platform/test/targets.bzl | 109 + .../src/runtime/platform/types.h | 0 .../src}/schema/extended_header.cpp | 5 - .../src/schema/extended_header.h | 0 .../src/schema/program.fbs | 47 +- .../src/schema/program_generated.h | 167 +- .../src}/schema/scalar_type.fbs | 2 +- .../src/schema/scalar_type_generated.h | 6 +- .../src/stubs/posix_stub.cpp | 56 + .../src/stubs/random_ops_stubs.cpp | 65 + packs/PyTorch.ExecuTorch.1.3.1-rc8/LICENSE | 37 - .../armclang_shims/sys/types.h | 43 - .../backends/arm/runtime/EthosUBackend.cpp | 441 - .../arm/runtime/EthosUBackend_Cortex_A.cpp | 427 - .../arm/runtime/EthosUBackend_Cortex_M.cpp | 171 - .../arm/runtime/EthosUBackend_Internal.h | 108 - .../arm/runtime/EthosUBackend_IoMemcpy.cpp | 19 - .../cortex_m/ops/cortex_m_ops_common.h | 391 - .../cortex_m/ops/op_dequantize_per_tensor.cpp | 245 - .../backends/cortex_m/ops/op_pad.cpp | 99 - .../cortex_m/ops/op_quantize_per_tensor.cpp | 294 - .../cortex_m/ops/op_quantized_avg_pool2d.cpp | 78 - .../ops/op_quantized_batch_matmul.cpp | 146 - .../cortex_m/ops/op_quantized_max_pool2d.cpp | 98 - .../ops/op_quantized_transpose_conv2d.cpp | 247 - .../portable/cpu/op__adaptive_avg_pool2d.cpp | 127 - .../portable/cpu/op__conj_physical.cpp | 50 - .../portable/cpu/op__to_dim_order_copy.cpp | 128 - .../kernels/portable/cpu/op_var_mean.cpp | 160 - .../runtime/backend/backend_options_map.h | 229 - .../runtime/core/device_allocator.cpp | 56 - .../runtime/core/device_allocator.h | 198 - .../runtime/core/device_memory_buffer.cpp | 35 - .../runtime/core/device_memory_buffer.h | 129 - .../executorch/runtime/core/version.h.in | 43 - .../runtime/executor/program_validation.cpp | 242 - .../runtime/executor/program_validation.h | 51 - .../backends/arm/runtime/EthosUBackend.cpp | 441 - .../arm/runtime/EthosUBackend_Cortex_A.cpp | 427 - .../arm/runtime/EthosUBackend_Cortex_M.cpp | 171 - .../arm/runtime/EthosUBackend_Internal.h | 108 - .../arm/runtime/EthosUBackend_IoMemcpy.cpp | 19 - .../cortex_m/ops/cortex_m_ops_common.h | 391 - .../cortex_m/ops/op_dequantize_per_tensor.cpp | 245 - .../src/backends/cortex_m/ops/op_pad.cpp | 99 - .../cortex_m/ops/op_quantize_per_tensor.cpp | 294 - .../cortex_m/ops/op_quantized_avg_pool2d.cpp | 78 - .../ops/op_quantized_batch_matmul.cpp | 146 - .../cortex_m/ops/op_quantized_max_pool2d.cpp | 98 - .../ops/op_quantized_transpose_conv2d.cpp | 247 - .../portable/cpu/op__adaptive_avg_pool2d.cpp | 127 - .../portable/cpu/op__conj_physical.cpp | 50 - .../portable/cpu/op__to_dim_order_copy.cpp | 128 - .../src/kernels/portable/cpu/op_var_mean.cpp | 160 - .../src/registration/RegisterAllKernels.cpp | 8136 ----- .../src/runtime/backend/backend_options_map.h | 229 - .../src/runtime/core/device_allocator.cpp | 56 - .../src/runtime/core/device_allocator.h | 198 - .../src/runtime/core/device_memory_buffer.cpp | 35 - .../src/runtime/core/device_memory_buffer.h | 129 - .../src/runtime/core/version.h.in | 43 - .../runtime/executor/program_validation.cpp | 242 - .../src/runtime/executor/program_validation.h | 51 - 2601 files changed, 397746 insertions(+), 21684 deletions(-) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/Documentation/README.md (63%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/LICENSE rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/PyTorch.ExecuTorch.pdsc (70%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/Functions.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/NativeFunctions.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernelsEverything.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernels_0.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterKernels.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/selected_operators.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/macros/Export.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/macros/Macros.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/BFloat16-inl.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/BFloat16-math.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/BFloat16.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/Half-inl.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/Half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/TypeSafeSignMath.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/bit_cast.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/complex_math.h (88%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/complex_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/floating_point_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/irange.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/llvmMathExtras.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/overflows.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/c10/util/safe_numerics.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/MODELS.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/_debug_passes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_decomposed_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_output_dim_order_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_manager.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/broadcast_args_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_int64_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_to_int32_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/conv1d_unsqueeze_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_elu_params.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_expand_copy_to_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_full_like_to_full_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_const_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_output_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_minmax_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_permute_singleton_to_view_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_split_to_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_squeezes_to_view.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_to_clamp_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_acosh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_add_sub_alpha_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_addmm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_any_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asin_and_acos_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asinh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atan_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atanh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_avg_pool2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_batch_norm_no_stats.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosine_similarity_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cumsum_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_tensor_mode.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_elu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_embedding_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_expm1_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_floor_divide_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_gelu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_glu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_grouped_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_groupnorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int16_activation_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int_pow_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_layernorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_leaky_relu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linalg_vector_norm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linear_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_log1p_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_logit_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_masked_fill_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_meandim_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_ne_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_quant_nodes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_remainder_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_round_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sdpa_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select_scatter_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sign_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_silu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sinh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_unstable_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sqrt_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sum_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tan_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_var_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_batch_norm2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_constant_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_duplicate_users_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_equal_placeholders_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_quantized_activation_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_view_copy_transform_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_rescales_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_table_ops.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_dtype_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_ranks_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/mm_to_bmm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/normalize_while_initial_args_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/promote_bool_operands_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/quant_args.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_getitem_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_graph_asserts_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_noop_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_inf_and_limit_values_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_scalar_with_tensor_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_upsample.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/scalars_to_attribute_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/size_adjust_input_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/to_tosa_memory_format_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_before_repeat_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/arm_vela.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/annotation_meta.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/arm_compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/debug.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/pipeline_config.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/type.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/constants.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/schema.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/backend.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/partitioner.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/clone_dim_order_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/control_flow_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/convolution_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/embedding_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/ethos_u55_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_select_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_tensor_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/minmax_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/pool_2d_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/reduce_sum_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/right_shift_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/slice_copy_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/to_dim_order_copy_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_profile_supported_op_lists.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_supported_operators.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/where_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/node_visitor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_abs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_any.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_bitwise_not.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ceil.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_clamp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cond_if.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_constant_pad_nd.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_eq.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_erf.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_exp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_floor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ge.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_gt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_le.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_log.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_logical_not.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_lt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_max_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_maximum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_minimum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_mul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_neg.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_permute.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_pow.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_reciprocal.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rshift_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rsqrt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sigmoid.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sub.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_to_dim_order_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv3d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_depthwise_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_rescale.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_resize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_table.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_transpose.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_view.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_where.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_while.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/operator_validation_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_binary.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_identity.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/process_node.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_annotator.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_config.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-ethos-u.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-models-test.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-tosa.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-vgf.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/EthosUBackend.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/backends/arm/runtime/VGFBackend.cpp (85%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/arm/runtime/VGFSetup.cpp (93%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/backends/arm/runtime/VGFSetup.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/arm/runtime/VelaBinStream.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/arm/runtime/VelaBinStream.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/TOSA_minimal_example.ipynb create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner_vkml.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executorch.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_portable_kernels.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/collect_testname_resources.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/corstone_utils.cmake create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/fvp_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/install_models_for_test.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/mlsdk_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/parse_test_names.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-commit create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-push create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_fvp.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_vkml.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/setup-dev-env.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/toolchain_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/vulkan_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/.coveragerc create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/common.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/conftest.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_bn_relu_folding_qat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_call_operator_submodule.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_conv_relu_residual_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_custom_partition.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_feats.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_hook.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dim_order.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dw_convs_with_shared_weights.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_extract_io_params_tosa.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_int64.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_lifted_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_mixed_type_lowering.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_model_evaluator.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_delegates.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_outputs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_non_persistent_buffers.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_outputs_order.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_pipeline_config.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_required_order.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_qat_training_loop.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_quant_custom_meta.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_rescale_range.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_save_exported_model.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_conformer.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_deit_tiny_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_dl3_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_inception_v3_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_llama.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_lstm_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v2_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v3_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_functional.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_modules.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nss.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_resnet18.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_torch_functions.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_w2l_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_abs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acosh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_adaptive_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_addmm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_alias_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_any.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_arange.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asinh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_at.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atan.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_batch_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise_not.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bmm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ceil.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clamp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clone.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cond.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_constant_pad_nd.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv1d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv3d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_combos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_constant_pad_nd.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cosh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cumsum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_depthwise_conv.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div_tensor_mode.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_elu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_embedding.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eq.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_erf.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_exp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expand.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expm1.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eye.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_fill_scalar.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor_div.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_full.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ge.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gelu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_glu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_group_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardsigmoid.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardswish.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardtanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_layer_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_le.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_leaky_relu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linalg_vector_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linear.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log1p.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logical.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logit.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logsoftmax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lshift.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_masked_fill.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_max_pool.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_maximum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mean_dim.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_minimum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_multihead_attention.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ne.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_neg.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ones.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_permute.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pixel_shuffling.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pow.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_reciprocal.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_relu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_remainder.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_round.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rshift.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsqrt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsub.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalar_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalars.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sdpa.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select_scatter.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid_32bit.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sign.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_silu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sinh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_softmax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_split.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sqrt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_squeeze.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_stack.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sub.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_t_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tan.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_to_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_transpose_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unary_combos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unbind.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unflatten.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unsqueeze.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_bilinear2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_nearest2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_var.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_view.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_where.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_while.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_zeros.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_broadcast_args_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_cast_int64_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_split_to_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_to_clamp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_div_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_int_pow_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_layernorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_meandim_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_quant_nodes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_softmax_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_var_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fold_qdq_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_batchnorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_constant_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_duplicate_users_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_view_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_rescale_i32_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_table_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_int32_cast_embedding_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_ioquantization_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_promote_bool_operands_pass.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_remove_clone_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_replace_inf_values_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rescale_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rewrite_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_to_tosa_memory_format.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/pytest.ini create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_conv_relu_fusing.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_generic_annotater.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_partial_quantization.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_selective_quantization.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_set_module_name.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_tosa_quantizer_validate.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/runner_utils.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing_vkml.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/targets.bzl create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_baremetal.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_ootb.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_memory_allocator_log.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_model.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/analyze_output_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/arm_tester.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/quantize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/serialize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/test_pipeline.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.clang-format create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.gitignore create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/LICENSE => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt} (99%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/SECURITY.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/backend.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/lib.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv3d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/depthwise_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/rescale.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/resize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/table.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/transpose.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops_registration.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/mapping.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/partitioner.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/tosa_1.0.fbs create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/specification.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/_factory.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/arm_model_evaluator.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/backend.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/model_converter.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/partitioner.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/backends/cortex_m/ops/cmsis_scratch_buffer_context.h (99%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_maximum.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_minimum.cpp (97%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_quantized_add.cpp (74%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_quantized_conv2d.cpp (84%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_quantized_linear.cpp (80%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_quantized_mul.cpp (81%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/backends/cortex_m/ops/op_softmax.cpp (93%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/op_transpose.cpp (95%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/operators.py rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/backends/cortex_m/ops/operators.yaml (56%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/activation_fusion_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/clamp_hardswish_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/convert_to_cortex_m_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/cortex_m_pass_manager.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/decompose_hardswish_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/passes_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/quantized_op_fusion_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/replace_quant_nodes_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/operator_configs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantization_configs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantizer.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/TARGETS create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/build_test_runner.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/misc/test_quantization.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/test_mobilenet_v3.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_quantize_per_tensor_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_activation.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_conv.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_linear.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_lstm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_maximum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_minimum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_mul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_softmax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_transpose.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_helpers_passes_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_replace_quant_nodes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/tester.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/data_loader/buffer_data_loader.h (91%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/data_loader/file_data_loader.cpp (90%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/data_loader/file_data_loader.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/extension/data_loader/file_descriptor_data_loader.cpp (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/data_loader/file_descriptor_data_loader.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/extension/data_loader/mman.h (54%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/data_loader/mman_windows.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/data_loader/mman_windows.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/extension/data_loader/mmap_data_loader.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/extension/data_loader/mmap_data_loader.h (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/extension/data_loader/shared_ptr_data_loader.h (88%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/buffer_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_descriptor_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/mmap_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/shared_ptr_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/memory_allocator/malloc_memory_allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/memory_allocator/memory_allocator_utils.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/malloc_memory_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/extension/runner_util/inputs.cpp (78%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/runner_util/inputs.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/runner_util/inputs_aten.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/extension/runner_util/inputs_portable.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/inputs_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/math_constants.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op__clone_dim_order.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op__empty_dim_order.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_abs.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_acos.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_acosh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_add.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_addmm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_alias_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/op_allclose.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_amax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_amin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_any.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_arange.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_argmax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_argmin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_as_strided_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_asin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_asinh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_atan.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_atan2.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_atanh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_avg_pool2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_bitwise_and.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_bitwise_left_shift.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_bitwise_not.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_bitwise_or.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_bitwise_right_shift.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_bitwise_xor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_bmm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_cat.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_cdist_forward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_ceil.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_clamp.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_clone.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/op_constant_pad_nd.cpp (87%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/op_convolution.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_convolution_backward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_cos.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_cosh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_cumsum.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_detach_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_diagonal_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_div.cpp (85%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_elu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_embedding.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_empty.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_eq.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_erf.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_exp.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_expand_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_expm1.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_fill.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_flip.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_floor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_floor_divide.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_fmod.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_full.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_full_like.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_gather.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_ge.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_gelu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_glu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_grid_sampler_2d.cpp (83%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_gt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_hardtanh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_index.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_index_put.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_index_select.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_isinf.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_isnan.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_le.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_leaky_relu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_lift_fresh_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_log.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_log10.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_log1p.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_log2.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_log_softmax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_logical_and.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_logical_not.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_logical_or.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_logical_xor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_logit.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_lt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_masked_fill.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_masked_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_masked_select.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_max.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_maximum.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_mean.cpp (67%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_min.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_minimum.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_mm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_mul.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_narrow_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_native_batch_norm.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_native_dropout.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/op_native_group_norm.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_native_layer_norm.cpp (77%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_ne.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_neg.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_nonzero.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_ones.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_pdist_forward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_permute_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_pixel_shuffle.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_pixel_unshuffle.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_pow.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_prod.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_rand.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_randn.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_reciprocal.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_reflection_pad1d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_reflection_pad2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_reflection_pad3d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_relu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_remainder.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_repeat.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_repeat_interleave.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_replication_pad1d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_replication_pad2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_replication_pad3d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_roll.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_round.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_rsqrt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_rsub.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_scalar_tensor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_scatter_add.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_select_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_select_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_sigmoid.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_sign.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_sin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_sinh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_slice_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_slice_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_softmax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_split_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_split_with_sizes_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_sqrt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_squeeze_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_stack.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_sub.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/op_sum.cpp (73%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_t_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_tan.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_tanh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_to_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_topk.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_transpose_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_tril.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_trunc.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_unbind_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_unfold_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_unsqueeze_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_upsample_nearest2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_var.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_view_as_real_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_view_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_where.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/op_zeros.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/pattern/bitwise_op.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/pattern/comparison_op.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/pattern/logical_op.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/pattern/pattern.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/scalar_utils.h (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/selective_build.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/scalar_utils_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/vec_ops_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/activation_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/activation_ops_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/advanced_index_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/advanced_index_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/arange_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/arange_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/broadcast_indexes_range.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/broadcast_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/broadcast_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/copy_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/copy_ops_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/delinearize_index.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/delinearize_index.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/distance_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/util/distance_util.h (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/dtype_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/dtype_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/elementwise_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/functional_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/index_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/index_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/util/kernel_ops_util.cpp (91%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/kernel_ops_util.h (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/math_util.h (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/matmul_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/matmul_ops_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/normalization_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/normalization_ops_util.h (50%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/padding_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/padding_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/reduce_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/reduce_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/repeat_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/repeat_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/select_copy_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/select_copy_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/slice_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/slice_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/stack_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/stack_util.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/reduce_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/vectorized_math_test.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/transpose_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/upsample_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/util/upsample_util.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/cpu/util/vectorized_math.h (99%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/kernels/portable/cpu/vec_ops.h (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/custom_ops.yaml (100%) create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/find_op_header.sh rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/portable/functions.yaml (98%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/dtype_selective_build_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_allclose_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_div_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_gelu_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_grid_sampler_2d_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_mul_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_aa_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_nearest2d_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/register_ops_aot_for_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/supported_features_def.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/test_grid_sampler_2d_executorch.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/prim_ops/et_copy_index.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/prim_ops/et_copy_index.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/prim_ops/et_view.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/prim_ops/et_view.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/prim_ops/register_prim_ops.cpp (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/prim_ops/selective_build_prim_ops.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/embeddingxb.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/embeddingxb.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_add.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_choose_qparams.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_dequantize.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_embedding.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_embedding2b.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_embedding4b.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_mixed_linear.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_mixed_mm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/cpu/op_quantize.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/kernels/quantized/quantized.yaml (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_add_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_choose_qparams_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_dequantize_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding2b_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding4b_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_linear_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_mm_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_quantize_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/quantized_ops_aot_register.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/supported_features_def.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_out_variants.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_quant_dequant_per_token.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/backend/backend_execution_context.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/backend/backend_init_context.h (59%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/backend/backend_option_context.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/backend/interface.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/backend/interface.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/backend/options.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_interface_update_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_options_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/array_ref.h (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/data_loader.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/defines.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/error.h (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/evalue.cpp (54%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/evalue.h (69%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/event_tracer.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/event_tracer_hooks.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/event_tracer_hooks_delegate.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/exec_aten.h (84%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_factory.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/exec_aten/util/dim_order_util.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/util/tensor_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/util/tensor_util_aten.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/exec_aten/util/tensor_util_portable.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/dim_order_util_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_util_test.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/freeable_buffer.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/function_ref.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/hierarchical_allocator.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/memory_allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/named_data_map.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/bfloat16.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/bfloat16_math.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/bits_types.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/complex_math.h (88%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/complex_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/overflows.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/c10/util/safe_numerics.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10}/torch/headeronly/macros/Export.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h (90%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/Half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/portable_type/device.h (57%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/optional.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/qint_types.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/scalar.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/scalar_type.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/string_view.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/tensor.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/portable_type/tensor_impl.cpp (79%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/tensor_impl.h (88%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/portable_type/tensor_options.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/bfloat16_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/dont_shadow_complex_test.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/half_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/optional_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/scalar_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_impl_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_test.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/result.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/span.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/tag.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/tag.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/core/tensor_layout.cpp (77%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/tensor_layout.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/core/tensor_shape_dynamism.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/array_ref_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/error_handling_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/evalue_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/event_tracer_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/freeable_buffer_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/function_ref_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/hierarchical_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/memory_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/span_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tag_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_layout_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_shape_dynamism_test_aten.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/TARGETs create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/test_error_matchers.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/memory_manager.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/merged_data_map.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/method.cpp (90%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/method.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/executor/method_meta.cpp (79%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/executor/method_meta.h (92%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/executor/platform_memory_allocator.h (85%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/executor/program.cpp (76%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/executor/program.h (93%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/pte_data_map.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/pte_data_map.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/executor/tensor_parser.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/tensor_parser_aten.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/executor/tensor_parser_exec_aten.cpp (87%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/executor/tensor_parser_portable.cpp (90%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/allocation_failure_stress_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_data_separation_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_integration_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/executor_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_integration_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_resolution_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/managed_memory_manager.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/memory_manager_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/merged_data_map_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_meta_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/program_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/pte_data_map_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/tensor_parser_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_compiler_lib.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_with_delegate_mapping.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/kernel/kernel_includes.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/kernel/kernel_runtime_context.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/kernel/operator_registry.cpp (82%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/kernel/operator_registry.h (93%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/functions.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_double_registration_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_runtime_context_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_generated_lib_and_aten.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_kernel_manual_registration.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_util.h rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/kernel/thread_parallel_interface.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/abort.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/abort.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/assert.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/clock.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/compat_unistd.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/platform/compiler.h (99%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/default/android.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/runtime/platform/default/minimal.cpp (53%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/default/posix.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/default/zephyr.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/log.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/log.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/platform.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/platform.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/profiler.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/profiler.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/runtime.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/runtime.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/system.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/clock_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_death_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_override_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_runtime_override_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_static_runtime_override_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/logging_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/pal_spy.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/runtime/platform/types.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/schema/extended_header.cpp (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/schema/extended_header.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/schema/program.fbs (88%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/schema/program_generated.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch}/schema/scalar_type.fbs (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/executorch/schema/scalar_type_generated.h (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/array.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/base.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/buffer.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/buffer_ref.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/code_generator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/code_generators.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/default_allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/detached_buffer.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/file_manager.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/flatbuffer_builder.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/flatbuffers.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/flatc.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/flex_flat_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/flexbuffers.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/grpc.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/hash.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/idl.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/minireflect.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/pch/flatc_pch.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/pch/pch.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/reflection.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/reflection_generated.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/registry.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/stl_emulation.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/string.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/struct.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/table.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/vector.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/vector_downward.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/flatbuffers/verifier.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10 => PyTorch.ExecuTorch.1.1.0-rc1-build.12/include}/torch/headeronly/macros/Export.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/torch/headeronly/macros/Macros.h (90%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/torch/headeronly/util/BFloat16.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/torch/headeronly/util/Half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/torch/headeronly/util/TypeSafeSignMath.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/torch/headeronly/util/bit_cast.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/torch/headeronly/util/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/include/torch/headeronly/util/floating_point_utils.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/meta/selected_operators.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/MODELS.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/_debug_passes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_decomposed_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_output_dim_order_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_manager.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/broadcast_args_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_int64_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_to_int32_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/conv1d_unsqueeze_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_elu_params.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_expand_copy_to_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_full_like_to_full_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_const_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_output_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_minmax_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_permute_singleton_to_view_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_split_to_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_squeezes_to_view.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_to_clamp_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_acosh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_add_sub_alpha_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_addmm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_any_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asin_and_acos_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asinh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atan_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atanh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_avg_pool2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_batch_norm_no_stats.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosine_similarity_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cumsum_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_tensor_mode.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_elu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_embedding_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_expm1_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_floor_divide_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_gelu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_glu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_grouped_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_groupnorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int16_activation_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int_pow_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_layernorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_leaky_relu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linalg_vector_norm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linear_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_log1p_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_logit_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_masked_fill_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_meandim_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_ne_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_quant_nodes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_remainder_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_round_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sdpa_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select_scatter_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sign_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_silu_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sinh_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_unstable_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sqrt_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sum_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tan_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_var_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_batch_norm2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_constant_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_duplicate_users_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_equal_placeholders_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_quantized_activation_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_view_copy_transform_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_rescales_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_table_ops.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_dtype_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_ranks_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/mm_to_bmm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/normalize_while_initial_args_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/promote_bool_operands_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/quant_args.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_getitem_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_graph_asserts_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_noop_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_inf_and_limit_values_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_scalar_with_tensor_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_upsample.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/scalars_to_attribute_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/size_adjust_input_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/to_tosa_memory_format_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_before_repeat_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/arm_vela.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/annotation_meta.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/arm_compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/debug.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/pipeline_config.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/type.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/constants.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/schema.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/backend.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/partitioner.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/clone_dim_order_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/control_flow_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/convolution_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/embedding_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/ethos_u55_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_select_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_tensor_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/minmax_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/pool_2d_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/reduce_sum_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/right_shift_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/slice_copy_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/to_dim_order_copy_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_profile_supported_op_lists.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_supported_operators.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/where_support.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/node_visitor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_abs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_any.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_bitwise_not.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ceil.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_clamp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cond_if.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_constant_pad_nd.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_eq.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_erf.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_exp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_floor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ge.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_gt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_le.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_log.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_logical_not.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_lt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_max_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_maximum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_minimum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_mul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_neg.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_permute.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_pow.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_reciprocal.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rshift_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rsqrt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sigmoid.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sub.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_to_dim_order_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv3d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_depthwise_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_rescale.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_resize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_table.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_transpose.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_view.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_where.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_while.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/operator_validation_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_binary.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_identity.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/process_node.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_annotator.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_config.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-ethos-u.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-models-test.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-tosa.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-vgf.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/EthosUBackend.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/backends/arm/runtime/VGFBackend.cpp (85%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/arm/runtime/VGFSetup.cpp (93%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/backends/arm/runtime/VGFSetup.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/arm/runtime/VelaBinStream.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/arm/runtime/VelaBinStream.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/TOSA_minimal_example.ipynb create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner_vkml.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executorch.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_portable_kernels.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/collect_testname_resources.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/corstone_utils.cmake create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/fvp_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/install_models_for_test.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/mlsdk_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/parse_test_names.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-commit create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-push create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_fvp.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_vkml.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/setup-dev-env.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/toolchain_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/vulkan_utils.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/.coveragerc create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/common.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/conftest.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_bn_relu_folding_qat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_call_operator_submodule.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_conv_relu_residual_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_custom_partition.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_feats.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_hook.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dim_order.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dw_convs_with_shared_weights.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_extract_io_params_tosa.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_int64.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_lifted_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_mixed_type_lowering.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_model_evaluator.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_delegates.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_outputs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_non_persistent_buffers.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_outputs_order.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_pipeline_config.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_required_order.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_qat_training_loop.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_quant_custom_meta.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_rescale_range.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_save_exported_model.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_conformer.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_deit_tiny_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_dl3_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_inception_v3_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_llama.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_lstm_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v2_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v3_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_functional.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_modules.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nss.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_resnet18.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_torch_functions.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_w2l_arm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_abs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acosh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_adaptive_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_addmm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_alias_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_any.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_arange.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asinh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_at.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atan.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_batch_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise_not.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bmm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ceil.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clamp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clone.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cond.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_constant_pad_nd.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv1d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv3d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_combos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_constant_pad_nd.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cosh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cumsum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_depthwise_conv.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div_tensor_mode.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_elu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_embedding.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eq.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_erf.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_exp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expand.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expm1.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eye.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_fill_scalar.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor_div.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_full.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ge.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gelu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_glu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_group_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardsigmoid.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardswish.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardtanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_layer_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_le.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_leaky_relu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linalg_vector_norm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linear.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log1p.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logical.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logit.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logsoftmax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lshift.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_masked_fill.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_max_pool.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_maximum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mean_dim.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_minimum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_multihead_attention.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ne.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_neg.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ones.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_permute.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pixel_shuffling.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pow.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_reciprocal.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_relu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_remainder.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_round.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rshift.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsqrt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsub.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalar_tensor.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalars.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sdpa.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select_scatter.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid_32bit.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sign.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_silu.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sin.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sinh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_softmax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_split.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sqrt.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_squeeze.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_stack.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sub.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_t_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tan.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tanh.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_to_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_transpose_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unary_combos.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unbind.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unflatten.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unsqueeze.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_bilinear2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_nearest2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_var.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_view.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_where.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_while.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_zeros.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_broadcast_args_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_cast_int64_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_split_to_slice.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_to_clamp.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_div_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_int_pow_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_layernorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_meandim_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_quant_nodes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_softmax_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_var_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fold_qdq_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_batchnorm_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_constant_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_duplicate_users_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_view_copy.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_rescale_i32_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_table_ops_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_int32_cast_embedding_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_ioquantization_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_promote_bool_operands_pass.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_remove_clone_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_replace_inf_values_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rescale_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rewrite_conv_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_to_tosa_memory_format.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/pytest.ini create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_conv_relu_fusing.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_generic_annotater.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_partial_quantization.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_selective_quantization.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_set_module_name.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_tosa_quantizer_validate.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/runner_utils.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing_vkml.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/targets.bzl create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_baremetal.sh create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_ootb.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_memory_allocator_log.py create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_model.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/analyze_output_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/arm_tester.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/quantize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/serialize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/test_pipeline.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.clang-format create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.gitignore create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/SECURITY.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/backend.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/lib.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv3d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/depthwise_conv2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/matmul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/rescale.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/resize.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/table.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/transpose.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops_registration.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/mapping.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/partitioner.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/tosa_1.0.fbs create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/specification.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/_factory.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/arm_model_evaluator.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/backend.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/compile_spec.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/model_converter.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/partitioner.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/backends/cortex_m/ops/cmsis_scratch_buffer_context.h (99%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/cortex_m_ops_common.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_maximum.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_minimum.cpp (97%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_quantized_add.cpp (74%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_quantized_conv2d.cpp (84%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_quantized_linear.cpp (80%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_quantized_mul.cpp (81%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/backends/cortex_m/ops/op_softmax.cpp (93%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/op_transpose.cpp (95%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/operators.py rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/backends/cortex_m/ops/operators.yaml (56%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/activation_fusion_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/clamp_hardswish_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/convert_to_cortex_m_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/cortex_m_pass_manager.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/decompose_hardswish_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/passes_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/quantized_op_fusion_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/replace_quant_nodes_pass.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/operator_configs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantization_configs.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantizer.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/TARGETS create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/build_test_runner.sh create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/misc/test_quantization.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/test_mobilenet_v3.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_quantize_per_tensor_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_activation.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_add.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_avg_pool2d.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_conv.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_linear.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_lstm.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_maximum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_minimum.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_mul.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_softmax.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_transpose.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_helpers_passes_utils.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_replace_quant_nodes.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/tester.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/data_loader/buffer_data_loader.h (91%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/data_loader/file_data_loader.cpp (90%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/data_loader/file_data_loader.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/extension/data_loader/file_descriptor_data_loader.cpp (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/data_loader/file_descriptor_data_loader.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/extension/data_loader/mman.h (54%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/data_loader/mman_windows.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/data_loader/mman_windows.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/extension/data_loader/mmap_data_loader.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/extension/data_loader/mmap_data_loader.h (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/extension/data_loader/shared_ptr_data_loader.h (88%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/buffer_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_descriptor_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/mmap_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/shared_ptr_data_loader_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/memory_allocator/cpu_caching_malloc_allocator.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/memory_allocator/cpu_caching_malloc_allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/memory_allocator/malloc_memory_allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/memory_allocator/memory_allocator_utils.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/malloc_memory_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/extension/runner_util/inputs.cpp (78%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/runner_util/inputs.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/runner_util/inputs_aten.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/extension/runner_util/inputs_portable.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/inputs_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/math_constants.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op__clone_dim_order.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op__empty_dim_order.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__to_dim_order_copy.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_abs.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_acos.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_acosh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_add.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_addmm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_alias_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/op_allclose.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_amax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_amin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_any.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_arange.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_argmax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_argmin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_as_strided_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_asin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_asinh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_atan.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_atan2.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_atanh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_avg_pool2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_bitwise_and.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_bitwise_left_shift.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_bitwise_not.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_bitwise_or.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_bitwise_right_shift.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_bitwise_xor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_bmm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_cat.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_cdist_forward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_ceil.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_clamp.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_clone.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/op_constant_pad_nd.cpp (87%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/op_convolution.cpp (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_convolution_backward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_cos.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_cosh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_cumsum.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_detach_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_diagonal_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_div.cpp (85%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_elu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_embedding.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_empty.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_eq.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_erf.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_exp.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_expand_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_expm1.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_fill.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_flip.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_floor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_floor_divide.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_fmod.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_full.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_full_like.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_gather.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_ge.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_gelu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_glu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_grid_sampler_2d.cpp (83%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_gt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_hardtanh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_index.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_index_put.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_index_select.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_isinf.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_isnan.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_le.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_leaky_relu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_lift_fresh_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_log.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_log10.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_log1p.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_log2.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_log_softmax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_logical_and.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_logical_not.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_logical_or.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_logical_xor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_logit.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_lt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_masked_fill.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_masked_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_masked_select.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_max.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_max_pool2d_with_indices.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_maximum.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_mean.cpp (67%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_min.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_minimum.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_mm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_mul.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_narrow_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_native_batch_norm.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_native_dropout.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/op_native_group_norm.cpp (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_native_layer_norm.cpp (77%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_ne.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_neg.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_nonzero.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_ones.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_pdist_forward.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_permute_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_pixel_shuffle.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_pixel_unshuffle.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_pow.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_prod.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_rand.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_randn.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_reciprocal.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_reflection_pad1d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_reflection_pad2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_reflection_pad3d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_relu.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_remainder.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_repeat.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_repeat_interleave.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_replication_pad1d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_replication_pad2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_replication_pad3d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_roll.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_round.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_rsqrt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_rsub.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_scalar_tensor.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_scatter_add.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_select_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_select_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_sigmoid.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_sign.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_sin.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_sinh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_slice_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_slice_scatter.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_softmax.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_split_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_split_with_sizes_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_sqrt.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_squeeze_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_stack.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_sub.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/op_sum.cpp (73%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_t_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_tan.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_tanh.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_to_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_topk.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_transpose_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_tril.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_trunc.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_unbind_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_unfold_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_unsqueeze_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_upsample_bilinear2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_upsample_nearest2d.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_var.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_view_as_real_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_view_copy.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_where.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/op_zeros.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/pattern/bitwise_op.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/pattern/comparison_op.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/pattern/logical_op.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/pattern/pattern.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/scalar_utils.h (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/selective_build.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/scalar_utils_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/vec_ops_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/activation_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/activation_ops_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/advanced_index_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/advanced_index_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/arange_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/arange_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/broadcast_indexes_range.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/broadcast_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/broadcast_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/copy_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/copy_ops_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/delinearize_index.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/delinearize_index.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/distance_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/util/distance_util.h (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/dtype_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/dtype_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/elementwise_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/functional_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/grid_sampler_2d_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/grid_sampler_2d_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/index_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/index_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/util/kernel_ops_util.cpp (91%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/kernel_ops_util.h (95%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/math_util.h (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/matmul_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/matmul_ops_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/normalization_ops_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/normalization_ops_util.h (50%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/padding_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/padding_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/reduce_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/reduce_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/repeat_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/repeat_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/select_copy_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/select_copy_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/slice_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/slice_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/stack_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/stack_util.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/reduce_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/vectorized_math_test.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/transpose_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/upsample_util.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/util/upsample_util.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/cpu/util/vectorized_math.h (99%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/kernels/portable/cpu/vec_ops.h (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/custom_ops.yaml (100%) create mode 100755 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/find_op_header.sh rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/portable/functions.yaml (98%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/dtype_selective_build_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_allclose_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_div_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_gelu_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_grid_sampler_2d_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_mul_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_aa_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_nearest2d_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/register_ops_aot_for_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/supported_features_def.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/test_grid_sampler_2d_executorch.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/prim_ops/et_copy_index.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/prim_ops/et_copy_index.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/prim_ops/et_view.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/prim_ops/et_view.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/prim_ops/register_prim_ops.cpp (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/prim_ops/selective_build_prim_ops.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/__init__.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/embeddingxb.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/embeddingxb.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_add.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_choose_qparams.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_dequantize.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_embedding.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_embedding2b.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_embedding4b.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_mixed_linear.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_mixed_mm.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/cpu/op_quantize.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/kernels/quantized/quantized.yaml (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_add_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_choose_qparams_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_dequantize_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding2b_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding4b_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_linear_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_mm_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_quantize_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/quantized_ops_aot_register.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/supported_features_def.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_out_variants.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_quant_dequant_per_token.py create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/registration/RegisterAllKernels.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/backend/backend_execution_context.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/backend/backend_init_context.h (59%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/backend/backend_option_context.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/backend/interface.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/backend/interface.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/backend/options.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_interface_update_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_options_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/array_ref.h (98%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/data_loader.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/defines.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/error.h (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/evalue.cpp (54%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/evalue.h (69%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/event_tracer.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/event_tracer_hooks.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/event_tracer_hooks_delegate.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/exec_aten.h (84%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_factory.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/exec_aten/util/dim_order_util.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/util/scalar_type_util.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/util/tensor_dimension_limit.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/util/tensor_util.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/util/tensor_util_aten.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/exec_aten/util/tensor_util_portable.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/dim_order_util_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_util_test.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/freeable_buffer.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/function_ref.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/hierarchical_allocator.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/memory_allocator.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/named_data_map.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/bfloat16.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/bfloat16_math.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/bits_types.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/README.md create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/macros/Export.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/macros/Macros.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/BFloat16-math.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/BFloat16.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/Half-inl.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/Half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/bit_cast.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/complex_math.h (88%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/complex_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/floating_point_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/irange.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/overflows.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/c10/util/safe_numerics.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h (90%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/torch/headeronly/util/Half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/torch/headeronly/util/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/complex.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/portable_type/device.h (57%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/half.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/optional.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/qint_types.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/scalar.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/scalar_type.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/string_view.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/tensor.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/portable_type/tensor_impl.cpp (79%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/tensor_impl.h (88%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/portable_type/tensor_options.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/bfloat16_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/dont_shadow_complex_test.c create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/half_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/optional_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/scalar_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_impl_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_test.cpp rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/result.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/span.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/tag.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/tag.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/core/tensor_layout.cpp (77%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/tensor_layout.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/core/tensor_shape_dynamism.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/array_ref_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/error_handling_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/evalue_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/event_tracer_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/freeable_buffer_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/function_ref_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/hierarchical_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/memory_allocator_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/span_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tag_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_layout_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_shape_dynamism_test_aten.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/TARGETs create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/test_error_matchers.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/memory_manager.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/merged_data_map.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/method.cpp (90%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/method.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/executor/method_meta.cpp (79%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/executor/method_meta.h (92%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/executor/platform_memory_allocator.h (85%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/executor/program.cpp (76%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/executor/program.h (93%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/pte_data_map.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/pte_data_map.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/executor/tensor_parser.h (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/tensor_parser_aten.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/executor/tensor_parser_exec_aten.cpp (87%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/executor/tensor_parser_portable.cpp (90%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/allocation_failure_stress_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_data_separation_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_integration_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/executor_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_integration_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_resolution_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/managed_memory_manager.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/memory_manager_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/merged_data_map_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_meta_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/program_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/pte_data_map_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/tensor_parser_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_compiler_lib.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_with_delegate_mapping.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/kernel/kernel_includes.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/kernel/kernel_runtime_context.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/kernel/operator_registry.cpp (82%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/kernel/operator_registry.h (93%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/functions.yaml create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_double_registration_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_runtime_context_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_generated_lib_and_aten.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_kernel_manual_registration.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_util.h rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/kernel/thread_parallel_interface.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/TARGETS rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/abort.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/abort.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/assert.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/clock.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/compat_unistd.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/platform/compiler.h (99%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/default/android.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/runtime/platform/default/minimal.cpp (53%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/default/posix.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/default/zephyr.cpp (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/log.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/log.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/platform.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/platform.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/profiler.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/profiler.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/runtime.cpp (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/runtime.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/system.h (100%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/targets.bzl create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/BUCK create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/CMakeLists.txt create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/TARGETS create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/clock_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_death_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_override_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_runtime_override_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_static_runtime_override_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/logging_test.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/pal_spy.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.h create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/targets.bzl rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/runtime/platform/types.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/schema/extended_header.cpp (96%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/schema/extended_header.h (100%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/schema/program.fbs (88%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/schema/program_generated.h (94%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8/include/executorch => PyTorch.ExecuTorch.1.1.0-rc1-build.12/src}/schema/scalar_type.fbs (97%) rename packs/{PyTorch.ExecuTorch.1.3.1-rc8 => PyTorch.ExecuTorch.1.1.0-rc1-build.12}/src/schema/scalar_type_generated.h (95%) create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/posix_stub.cpp create mode 100644 packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/random_ops_stubs.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/LICENSE delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/armclang_shims/sys/types.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_A.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_M.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Internal.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_pad.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_batch_matmul.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_max_pool2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__conj_physical.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_var_mean.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_options_map.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/version.h.in delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_A.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_M.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Internal.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/cortex_m_ops_common.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_pad.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_batch_matmul.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_max_pool2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__conj_physical.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__to_dim_order_copy.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_var_mean.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/registration/RegisterAllKernels.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_options_map.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.h delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/version.h.in delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.cpp delete mode 100644 packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.h diff --git a/.github/workflows/Build_RPS_AppKit-E8.yml b/.github/workflows/Build_RPS_AppKit-E8.yml index 9fce725..32a9e3c 100644 --- a/.github/workflows/Build_RPS_AppKit-E8.yml +++ b/.github/workflows/Build_RPS_AppKit-E8.yml @@ -57,7 +57,7 @@ jobs: - name: Add Beta packs working-directory: ./ run: | - cpackget add ./packs/PyTorch.ExecuTorch.1.3.1-rc8/PyTorch.ExecuTorch.pdsc --agree-embedded-license + cpackget add ./packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/PyTorch.ExecuTorch.pdsc --agree-embedded-license - name: Build the target-set working-directory: ./RockPaperScissors/AppKit-E8_USB diff --git a/.github/workflows/Build_RPS_Variants.yml b/.github/workflows/Build_RPS_Variants.yml index 020826b..cc5c60a 100644 --- a/.github/workflows/Build_RPS_Variants.yml +++ b/.github/workflows/Build_RPS_Variants.yml @@ -70,7 +70,7 @@ jobs: - name: Add Beta packs working-directory: ./ run: | - cpackget add ./packs/PyTorch.ExecuTorch.1.3.1-rc8/PyTorch.ExecuTorch.pdsc --agree-embedded-license + cpackget add ./packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/PyTorch.ExecuTorch.pdsc --agree-embedded-license - name: ${{matrix.context.tool}} Build-Test for context ${{matrix.context.proj}}.${{matrix.context.build-type}}+${{matrix.context.target-type}} working-directory: ${{matrix.context.dir}} diff --git a/.github/workflows/Test_RPS_SSE-320-U85.yml b/.github/workflows/Test_RPS_SSE-320-U85.yml index e15d387..5531d62 100644 --- a/.github/workflows/Test_RPS_SSE-320-U85.yml +++ b/.github/workflows/Test_RPS_SSE-320-U85.yml @@ -61,7 +61,7 @@ jobs: - name: Add Beta packs working-directory: ./ run: | - cpackget add ./packs/PyTorch.ExecuTorch.1.3.1-rc8/PyTorch.ExecuTorch.pdsc --agree-embedded-license + cpackget add ./packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/PyTorch.ExecuTorch.pdsc --agree-embedded-license - name: Build the target-set working-directory: ./RockPaperScissors/AppKit-E8_USB diff --git a/RockPaperScissors/AppKit-E8_USB/algorithm/ML/ai_layer/ai_layer.clayer.yml b/RockPaperScissors/AppKit-E8_USB/algorithm/ML/ai_layer/ai_layer.clayer.yml index b9ee4c2..1592a4d 100644 --- a/RockPaperScissors/AppKit-E8_USB/algorithm/ML/ai_layer/ai_layer.clayer.yml +++ b/RockPaperScissors/AppKit-E8_USB/algorithm/ML/ai_layer/ai_layer.clayer.yml @@ -4,24 +4,25 @@ layer: packs: - pack: PyTorch::ExecuTorch - path: ../../../../../packs/PyTorch.ExecuTorch.1.3.1-rc8 + path: ../../../../../packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12 define: - ET_LOG_ENABLED : 0 components: - # ExecuTorch core runtime. Runtime now ships the weak PAL (minimal.cpp), - # so the 1.1.0 "Platform Bare-Metal" posix stub is no longer needed. + # ExecuTorch core runtime - component: Machine Learning:ExecuTorch:Runtime - component: Machine Learning:ExecuTorch:Kernel Utils - component: Machine Learning:ExecuTorch:Kernel Registration # Ethos-U NPU backend - component: Machine Learning:ExecuTorch:Backend EthosU - # Quantized operators used by the RPS model. 1.3.x moves operators to the - # "ExecuTorch Operators" Cgroup and #ifdef-guards each registration, so the - # 1.1.0 "Stubs RandomOps" component is no longer needed. - - component: Machine Learning:ExecuTorch Operators:Quantized quantize - - component: Machine Learning:ExecuTorch Operators:Quantized dequantize + # Bare-metal PAL stubs (replaces posix.cpp) + - component: Machine Learning:ExecuTorch:Platform Bare-Metal + # Random op stubs (no std::random_device on bare-metal) + - component: Machine Learning:ExecuTorch:Stubs RandomOps + # Quantized operators used by the RPS model + - component: Machine Learning:ExecuTorch:Operators Quantized quantize + - component: Machine Learning:ExecuTorch:Operators Quantized dequantize groups: # AI Model - replace this group with a ModelNova-generated model pack diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/Documentation/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/Documentation/README.md similarity index 63% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/Documentation/README.md rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/Documentation/README.md index d1c2af5..1a945fc 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/Documentation/README.md +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/Documentation/README.md @@ -2,7 +2,7 @@ ## Overview -ExecuTorch is the PyTorch Edge Runtime, enabling efficient on-device AI inference. This pack is the Cortex-M / bare-metal distribution. +ExecuTorch is the PyTorch Edge Runtime, enabling efficient on-device AI inference on Arm Cortex-M processors. This pack provides: - **Core Runtime**: Program loading and execution @@ -28,12 +28,10 @@ This pack provides: - component: Machine Learning:ExecuTorch:Runtime - component: Machine Learning:ExecuTorch:Kernel Utils - # Backend (choose one or more). CMSIS component IDs use a single - # colon between Cclass / Cgroup / Csub, with a space (not "::") - # inside the Csub name. - - component: Machine Learning:ExecuTorch:Backend EthosU + # Backend (choose one or more) + - component: Machine Learning:ExecuTorch:Backend::EthosU # or - - component: Machine Learning:ExecuTorch:Backend CortexM + - component: Machine Learning:ExecuTorch:Backend::CortexM ``` 3. Include ExecuTorch headers in your code: @@ -44,20 +42,16 @@ This pack provides: ### Model Integration -Operators are included as individual CMSIS components, one per -`op_*.cpp`. Add the ones your model uses: +For automatic operator selection, use a Model Pack generated from your `.pte` file. The model pack declares dependencies on required operators, which are automatically resolved. +Alternatively, manually add required operators: ```yaml components: - - component: Machine Learning:ExecuTorch Operators:Portable add - - component: Machine Learning:ExecuTorch Operators:Portable mul + - component: Machine Learning:ExecuTorch:Operators::Portable::add + - component: Machine Learning:ExecuTorch:Operators::Portable::mul # ... other operators used by your model ``` -You can also generate this list automatically: a Model Pack produced -from your `.pte` file declares dependencies on the operators the model -needs, and the toolchain resolves them against this pack's components. - ## Memory Requirements | Component | Flash (approx) | RAM (approx) | @@ -73,9 +67,9 @@ Actual requirements depend on: ## Compiler Support -Tested with `arm-none-eabi-gcc` 13.x+ via the avh-mlops vcpkg toolchain. -Other Arm-Cortex-M toolchains (Arm Compiler 6, LLVM Embedded) are expected -to work but are not currently exercised by the pack's CI. +- **GCC**: arm-none-eabi-gcc 13.x+ +- **Arm Compiler 6**: armclang 6.24+ +- **LLVM/Clang**: Arm Compiler for Embedded ## Dependencies diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/LICENSE b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/LICENSE new file mode 100644 index 0000000..767f40b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) Meta Platforms, Inc. and affiliates. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/PyTorch.ExecuTorch.pdsc b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/PyTorch.ExecuTorch.pdsc similarity index 70% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/PyTorch.ExecuTorch.pdsc rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/PyTorch.ExecuTorch.pdsc index ef6075e..d199058 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/PyTorch.ExecuTorch.pdsc +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/PyTorch.ExecuTorch.pdsc @@ -1,11 +1,5 @@ - - @@ -13,13 +7,13 @@ ExecuTorch ExecuTorch: PyTorch Edge Runtime for on-device AI inference on Arm Cortex-M processors. - https://github.com/pytorch/executorch/releases/download/1.3.1-rc8/ + https://github.com/pytorch/executorch/releases/download/1.1.0-rc1-build.12/ LICENSE https://github.com/pytorch/executorch.git - - ExecuTorch 1.3.1-rc8 - PyTorch Edge Runtime + + ExecuTorch 1.1.0-rc1-build.12 - PyTorch Edge Runtime - Portable operators for Cortex-M - Ethos-U NPU backend support - Cortex-M optimized kernels @@ -36,7 +30,6 @@ Software Components for Machine Learning ExecuTorch PyTorch Edge Runtime - ExecuTorch Operator Components @@ -53,7 +46,7 @@ - + GNU Compiler @@ -88,24 +81,16 @@ - Ethos-U NPU backend (Cortex-M host, bare-metal) + Ethos-U NPU backend - - Operator: adaptive_avg_pool2d - - Operator: clone_dim_order - - Operator: conj_physical - - Operator: empty_dim_order @@ -758,10 +743,6 @@ Operator: var - - Operator: var_mean - - Operator: view_as_real_copy @@ -814,89 +795,11 @@ Operator: quantize - - Operator: dequantize_per_tensor - - - - Operator: maximum - - - - - Operator: minimum - - - - - Operator: pad - - - - - Operator: quantize_per_tensor - - - - Operator: quantized_add - - - - - Operator: quantized_avg_pool2d - - - - - Operator: quantized_batch_matmul - - - - - Operator: quantized_conv2d - - - - - Operator: quantized_depthwise_conv2d - - - - - Operator: quantized_linear - - - - - Operator: quantized_max_pool2d - - - - - Operator: quantized_mul - - - - - Operator: quantized_transpose_conv2d - - - - - Operator: softmax - - - - - Operator: transpose - - - - + ExecuTorch Core Runtime - Required for all ExecuTorch applications #define RTE_ML_EXECUTORCH_RUNTIME /* ExecuTorch Runtime */ @@ -909,8 +812,6 @@ - - @@ -920,7 +821,6 @@ - @@ -932,19 +832,12 @@ - - - - + ExecuTorch Kernel Registration Utilities #define RTE_ML_EXECUTORCH_KERNEL_UTILS /* ExecuTorch Kernel Utils */ @@ -970,9 +863,6 @@ - - - @@ -983,7 +873,7 @@ which is defined by the corresponding operator component. This allows selective registration based on which operators are selected. --> - + ExecuTorch Kernel Registration - Registers all selected operators #define RTE_ML_EXECUTORCH_KERNEL_REGISTRATION /* ExecuTorch Kernel Registration */ @@ -994,17 +884,7 @@ - - ExecuTorch Portable Operator: adaptive_avg_pool2d - - #define RTE_ML_EXECUTORCH_OP_PORTABLE_ADAPTIVE_AVG_POOL2D /* ExecuTorch op_adaptive_avg_pool2d */ - - - - - - - + ExecuTorch Portable Operator: clone_dim_order #define RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE_DIM_ORDER /* ExecuTorch op_clone_dim_order */ @@ -1014,17 +894,7 @@ - - ExecuTorch Portable Operator: conj_physical - - #define RTE_ML_EXECUTORCH_OP_PORTABLE_CONJ_PHYSICAL /* ExecuTorch op_conj_physical */ - - - - - - - + ExecuTorch Portable Operator: empty_dim_order #define RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY_DIM_ORDER /* ExecuTorch op_empty_dim_order */ @@ -1034,7 +904,7 @@ - + ExecuTorch Portable Operator: to_dim_order_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_TO_DIM_ORDER_COPY /* ExecuTorch op_to_dim_order_copy */ @@ -1044,7 +914,7 @@ - + ExecuTorch Portable Operator: abs #define RTE_ML_EXECUTORCH_OP_PORTABLE_ABS /* ExecuTorch op_abs */ @@ -1054,7 +924,7 @@ - + ExecuTorch Portable Operator: acos #define RTE_ML_EXECUTORCH_OP_PORTABLE_ACOS /* ExecuTorch op_acos */ @@ -1064,7 +934,7 @@ - + ExecuTorch Portable Operator: acosh #define RTE_ML_EXECUTORCH_OP_PORTABLE_ACOSH /* ExecuTorch op_acosh */ @@ -1074,7 +944,7 @@ - + ExecuTorch Portable Operator: add #define RTE_ML_EXECUTORCH_OP_PORTABLE_ADD /* ExecuTorch op_add */ @@ -1084,7 +954,7 @@ - + ExecuTorch Portable Operator: addmm #define RTE_ML_EXECUTORCH_OP_PORTABLE_ADDMM /* ExecuTorch op_addmm */ @@ -1094,7 +964,7 @@ - + ExecuTorch Portable Operator: alias_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_ALIAS_COPY /* ExecuTorch op_alias_copy */ @@ -1104,7 +974,7 @@ - + ExecuTorch Portable Operator: allclose #define RTE_ML_EXECUTORCH_OP_PORTABLE_ALLCLOSE /* ExecuTorch op_allclose */ @@ -1114,7 +984,7 @@ - + ExecuTorch Portable Operator: amax #define RTE_ML_EXECUTORCH_OP_PORTABLE_AMAX /* ExecuTorch op_amax */ @@ -1124,7 +994,7 @@ - + ExecuTorch Portable Operator: amin #define RTE_ML_EXECUTORCH_OP_PORTABLE_AMIN /* ExecuTorch op_amin */ @@ -1134,7 +1004,7 @@ - + ExecuTorch Portable Operator: any #define RTE_ML_EXECUTORCH_OP_PORTABLE_ANY /* ExecuTorch op_any */ @@ -1144,7 +1014,7 @@ - + ExecuTorch Portable Operator: arange #define RTE_ML_EXECUTORCH_OP_PORTABLE_ARANGE /* ExecuTorch op_arange */ @@ -1154,7 +1024,7 @@ - + ExecuTorch Portable Operator: argmax #define RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMAX /* ExecuTorch op_argmax */ @@ -1164,7 +1034,7 @@ - + ExecuTorch Portable Operator: argmin #define RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMIN /* ExecuTorch op_argmin */ @@ -1174,7 +1044,7 @@ - + ExecuTorch Portable Operator: as_strided_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_AS_STRIDED_COPY /* ExecuTorch op_as_strided_copy */ @@ -1184,7 +1054,7 @@ - + ExecuTorch Portable Operator: asin #define RTE_ML_EXECUTORCH_OP_PORTABLE_ASIN /* ExecuTorch op_asin */ @@ -1194,7 +1064,7 @@ - + ExecuTorch Portable Operator: asinh #define RTE_ML_EXECUTORCH_OP_PORTABLE_ASINH /* ExecuTorch op_asinh */ @@ -1204,7 +1074,7 @@ - + ExecuTorch Portable Operator: atan #define RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN /* ExecuTorch op_atan */ @@ -1214,7 +1084,7 @@ - + ExecuTorch Portable Operator: atan2 #define RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN2 /* ExecuTorch op_atan2 */ @@ -1224,7 +1094,7 @@ - + ExecuTorch Portable Operator: atanh #define RTE_ML_EXECUTORCH_OP_PORTABLE_ATANH /* ExecuTorch op_atanh */ @@ -1234,7 +1104,7 @@ - + ExecuTorch Portable Operator: avg_pool2d #define RTE_ML_EXECUTORCH_OP_PORTABLE_AVG_POOL2D /* ExecuTorch op_avg_pool2d */ @@ -1244,7 +1114,7 @@ - + ExecuTorch Portable Operator: bitwise_and #define RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_AND /* ExecuTorch op_bitwise_and */ @@ -1254,7 +1124,7 @@ - + ExecuTorch Portable Operator: bitwise_left_shift #define RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_LEFT_SHIFT /* ExecuTorch op_bitwise_left_shift */ @@ -1264,7 +1134,7 @@ - + ExecuTorch Portable Operator: bitwise_not #define RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_NOT /* ExecuTorch op_bitwise_not */ @@ -1274,7 +1144,7 @@ - + ExecuTorch Portable Operator: bitwise_or #define RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_OR /* ExecuTorch op_bitwise_or */ @@ -1284,7 +1154,7 @@ - + ExecuTorch Portable Operator: bitwise_right_shift #define RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_RIGHT_SHIFT /* ExecuTorch op_bitwise_right_shift */ @@ -1294,7 +1164,7 @@ - + ExecuTorch Portable Operator: bitwise_xor #define RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_XOR /* ExecuTorch op_bitwise_xor */ @@ -1304,7 +1174,7 @@ - + ExecuTorch Portable Operator: bmm #define RTE_ML_EXECUTORCH_OP_PORTABLE_BMM /* ExecuTorch op_bmm */ @@ -1314,7 +1184,7 @@ - + ExecuTorch Portable Operator: cat #define RTE_ML_EXECUTORCH_OP_PORTABLE_CAT /* ExecuTorch op_cat */ @@ -1324,7 +1194,7 @@ - + ExecuTorch Portable Operator: cdist_forward #define RTE_ML_EXECUTORCH_OP_PORTABLE_CDIST_FORWARD /* ExecuTorch op_cdist_forward */ @@ -1334,7 +1204,7 @@ - + ExecuTorch Portable Operator: ceil #define RTE_ML_EXECUTORCH_OP_PORTABLE_CEIL /* ExecuTorch op_ceil */ @@ -1344,7 +1214,7 @@ - + ExecuTorch Portable Operator: clamp #define RTE_ML_EXECUTORCH_OP_PORTABLE_CLAMP /* ExecuTorch op_clamp */ @@ -1354,7 +1224,7 @@ - + ExecuTorch Portable Operator: clone #define RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE /* ExecuTorch op_clone */ @@ -1364,7 +1234,7 @@ - + ExecuTorch Portable Operator: constant_pad_nd #define RTE_ML_EXECUTORCH_OP_PORTABLE_CONSTANT_PAD_ND /* ExecuTorch op_constant_pad_nd */ @@ -1374,7 +1244,7 @@ - + ExecuTorch Portable Operator: convolution #define RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION /* ExecuTorch op_convolution */ @@ -1384,7 +1254,7 @@ - + ExecuTorch Portable Operator: convolution_backward #define RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION_BACKWARD /* ExecuTorch op_convolution_backward */ @@ -1394,7 +1264,7 @@ - + ExecuTorch Portable Operator: copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_COPY /* ExecuTorch op_copy */ @@ -1404,7 +1274,7 @@ - + ExecuTorch Portable Operator: cos #define RTE_ML_EXECUTORCH_OP_PORTABLE_COS /* ExecuTorch op_cos */ @@ -1414,7 +1284,7 @@ - + ExecuTorch Portable Operator: cosh #define RTE_ML_EXECUTORCH_OP_PORTABLE_COSH /* ExecuTorch op_cosh */ @@ -1424,7 +1294,7 @@ - + ExecuTorch Portable Operator: cumsum #define RTE_ML_EXECUTORCH_OP_PORTABLE_CUMSUM /* ExecuTorch op_cumsum */ @@ -1434,7 +1304,7 @@ - + ExecuTorch Portable Operator: detach_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_DETACH_COPY /* ExecuTorch op_detach_copy */ @@ -1444,7 +1314,7 @@ - + ExecuTorch Portable Operator: diagonal_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_DIAGONAL_COPY /* ExecuTorch op_diagonal_copy */ @@ -1454,7 +1324,7 @@ - + ExecuTorch Portable Operator: div #define RTE_ML_EXECUTORCH_OP_PORTABLE_DIV /* ExecuTorch op_div */ @@ -1464,7 +1334,7 @@ - + ExecuTorch Portable Operator: elu #define RTE_ML_EXECUTORCH_OP_PORTABLE_ELU /* ExecuTorch op_elu */ @@ -1474,7 +1344,7 @@ - + ExecuTorch Portable Operator: embedding #define RTE_ML_EXECUTORCH_OP_PORTABLE_EMBEDDING /* ExecuTorch op_embedding */ @@ -1484,7 +1354,7 @@ - + ExecuTorch Portable Operator: empty #define RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY /* ExecuTorch op_empty */ @@ -1494,7 +1364,7 @@ - + ExecuTorch Portable Operator: eq #define RTE_ML_EXECUTORCH_OP_PORTABLE_EQ /* ExecuTorch op_eq */ @@ -1504,7 +1374,7 @@ - + ExecuTorch Portable Operator: erf #define RTE_ML_EXECUTORCH_OP_PORTABLE_ERF /* ExecuTorch op_erf */ @@ -1514,7 +1384,7 @@ - + ExecuTorch Portable Operator: exp #define RTE_ML_EXECUTORCH_OP_PORTABLE_EXP /* ExecuTorch op_exp */ @@ -1524,7 +1394,7 @@ - + ExecuTorch Portable Operator: expand_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_EXPAND_COPY /* ExecuTorch op_expand_copy */ @@ -1534,7 +1404,7 @@ - + ExecuTorch Portable Operator: expm1 #define RTE_ML_EXECUTORCH_OP_PORTABLE_EXPM1 /* ExecuTorch op_expm1 */ @@ -1544,7 +1414,7 @@ - + ExecuTorch Portable Operator: fill #define RTE_ML_EXECUTORCH_OP_PORTABLE_FILL /* ExecuTorch op_fill */ @@ -1554,7 +1424,7 @@ - + ExecuTorch Portable Operator: flip #define RTE_ML_EXECUTORCH_OP_PORTABLE_FLIP /* ExecuTorch op_flip */ @@ -1564,7 +1434,7 @@ - + ExecuTorch Portable Operator: floor #define RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR /* ExecuTorch op_floor */ @@ -1574,7 +1444,7 @@ - + ExecuTorch Portable Operator: floor_divide #define RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR_DIVIDE /* ExecuTorch op_floor_divide */ @@ -1584,7 +1454,7 @@ - + ExecuTorch Portable Operator: fmod #define RTE_ML_EXECUTORCH_OP_PORTABLE_FMOD /* ExecuTorch op_fmod */ @@ -1594,7 +1464,7 @@ - + ExecuTorch Portable Operator: full #define RTE_ML_EXECUTORCH_OP_PORTABLE_FULL /* ExecuTorch op_full */ @@ -1604,7 +1474,7 @@ - + ExecuTorch Portable Operator: full_like #define RTE_ML_EXECUTORCH_OP_PORTABLE_FULL_LIKE /* ExecuTorch op_full_like */ @@ -1614,7 +1484,7 @@ - + ExecuTorch Portable Operator: gather #define RTE_ML_EXECUTORCH_OP_PORTABLE_GATHER /* ExecuTorch op_gather */ @@ -1624,7 +1494,7 @@ - + ExecuTorch Portable Operator: ge #define RTE_ML_EXECUTORCH_OP_PORTABLE_GE /* ExecuTorch op_ge */ @@ -1634,7 +1504,7 @@ - + ExecuTorch Portable Operator: gelu #define RTE_ML_EXECUTORCH_OP_PORTABLE_GELU /* ExecuTorch op_gelu */ @@ -1644,7 +1514,7 @@ - + ExecuTorch Portable Operator: glu #define RTE_ML_EXECUTORCH_OP_PORTABLE_GLU /* ExecuTorch op_glu */ @@ -1654,7 +1524,7 @@ - + ExecuTorch Portable Operator: grid_sampler_2d #define RTE_ML_EXECUTORCH_OP_PORTABLE_GRID_SAMPLER_2D /* ExecuTorch op_grid_sampler_2d */ @@ -1664,7 +1534,7 @@ - + ExecuTorch Portable Operator: gt #define RTE_ML_EXECUTORCH_OP_PORTABLE_GT /* ExecuTorch op_gt */ @@ -1674,7 +1544,7 @@ - + ExecuTorch Portable Operator: hardtanh #define RTE_ML_EXECUTORCH_OP_PORTABLE_HARDTANH /* ExecuTorch op_hardtanh */ @@ -1684,7 +1554,7 @@ - + ExecuTorch Portable Operator: index #define RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX /* ExecuTorch op_index */ @@ -1694,7 +1564,7 @@ - + ExecuTorch Portable Operator: index_put #define RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_PUT /* ExecuTorch op_index_put */ @@ -1704,7 +1574,7 @@ - + ExecuTorch Portable Operator: index_select #define RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_SELECT /* ExecuTorch op_index_select */ @@ -1714,7 +1584,7 @@ - + ExecuTorch Portable Operator: isinf #define RTE_ML_EXECUTORCH_OP_PORTABLE_ISINF /* ExecuTorch op_isinf */ @@ -1724,7 +1594,7 @@ - + ExecuTorch Portable Operator: isnan #define RTE_ML_EXECUTORCH_OP_PORTABLE_ISNAN /* ExecuTorch op_isnan */ @@ -1734,7 +1604,7 @@ - + ExecuTorch Portable Operator: le #define RTE_ML_EXECUTORCH_OP_PORTABLE_LE /* ExecuTorch op_le */ @@ -1744,7 +1614,7 @@ - + ExecuTorch Portable Operator: leaky_relu #define RTE_ML_EXECUTORCH_OP_PORTABLE_LEAKY_RELU /* ExecuTorch op_leaky_relu */ @@ -1754,7 +1624,7 @@ - + ExecuTorch Portable Operator: lift_fresh_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_LIFT_FRESH_COPY /* ExecuTorch op_lift_fresh_copy */ @@ -1764,7 +1634,7 @@ - + ExecuTorch Portable Operator: log #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOG /* ExecuTorch op_log */ @@ -1774,7 +1644,7 @@ - + ExecuTorch Portable Operator: log10 #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOG10 /* ExecuTorch op_log10 */ @@ -1784,7 +1654,7 @@ - + ExecuTorch Portable Operator: log1p #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOG1P /* ExecuTorch op_log1p */ @@ -1794,7 +1664,7 @@ - + ExecuTorch Portable Operator: log2 #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOG2 /* ExecuTorch op_log2 */ @@ -1804,7 +1674,7 @@ - + ExecuTorch Portable Operator: log_softmax #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOG_SOFTMAX /* ExecuTorch op_log_softmax */ @@ -1814,7 +1684,7 @@ - + ExecuTorch Portable Operator: logical_and #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_AND /* ExecuTorch op_logical_and */ @@ -1824,7 +1694,7 @@ - + ExecuTorch Portable Operator: logical_not #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_NOT /* ExecuTorch op_logical_not */ @@ -1834,7 +1704,7 @@ - + ExecuTorch Portable Operator: logical_or #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_OR /* ExecuTorch op_logical_or */ @@ -1844,7 +1714,7 @@ - + ExecuTorch Portable Operator: logical_xor #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_XOR /* ExecuTorch op_logical_xor */ @@ -1854,7 +1724,7 @@ - + ExecuTorch Portable Operator: logit #define RTE_ML_EXECUTORCH_OP_PORTABLE_LOGIT /* ExecuTorch op_logit */ @@ -1864,7 +1734,7 @@ - + ExecuTorch Portable Operator: lt #define RTE_ML_EXECUTORCH_OP_PORTABLE_LT /* ExecuTorch op_lt */ @@ -1874,7 +1744,7 @@ - + ExecuTorch Portable Operator: masked_fill #define RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_FILL /* ExecuTorch op_masked_fill */ @@ -1884,7 +1754,7 @@ - + ExecuTorch Portable Operator: masked_scatter #define RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SCATTER /* ExecuTorch op_masked_scatter */ @@ -1894,7 +1764,7 @@ - + ExecuTorch Portable Operator: masked_select #define RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SELECT /* ExecuTorch op_masked_select */ @@ -1904,7 +1774,7 @@ - + ExecuTorch Portable Operator: max #define RTE_ML_EXECUTORCH_OP_PORTABLE_MAX /* ExecuTorch op_max */ @@ -1914,7 +1784,7 @@ - + ExecuTorch Portable Operator: max_pool2d_with_indices #define RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES /* ExecuTorch op_max_pool2d_with_indices */ @@ -1924,7 +1794,7 @@ - + ExecuTorch Portable Operator: max_pool2d_with_indices_backward #define RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES_BACKWARD /* ExecuTorch op_max_pool2d_with_indices_backward */ @@ -1934,7 +1804,7 @@ - + ExecuTorch Portable Operator: maximum #define RTE_ML_EXECUTORCH_OP_PORTABLE_MAXIMUM /* ExecuTorch op_maximum */ @@ -1944,7 +1814,7 @@ - + ExecuTorch Portable Operator: mean #define RTE_ML_EXECUTORCH_OP_PORTABLE_MEAN /* ExecuTorch op_mean */ @@ -1954,7 +1824,7 @@ - + ExecuTorch Portable Operator: min #define RTE_ML_EXECUTORCH_OP_PORTABLE_MIN /* ExecuTorch op_min */ @@ -1964,7 +1834,7 @@ - + ExecuTorch Portable Operator: minimum #define RTE_ML_EXECUTORCH_OP_PORTABLE_MINIMUM /* ExecuTorch op_minimum */ @@ -1974,7 +1844,7 @@ - + ExecuTorch Portable Operator: mm #define RTE_ML_EXECUTORCH_OP_PORTABLE_MM /* ExecuTorch op_mm */ @@ -1984,7 +1854,7 @@ - + ExecuTorch Portable Operator: mul #define RTE_ML_EXECUTORCH_OP_PORTABLE_MUL /* ExecuTorch op_mul */ @@ -1994,7 +1864,7 @@ - + ExecuTorch Portable Operator: narrow_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_NARROW_COPY /* ExecuTorch op_narrow_copy */ @@ -2004,7 +1874,7 @@ - + ExecuTorch Portable Operator: native_batch_norm #define RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_BATCH_NORM /* ExecuTorch op_native_batch_norm */ @@ -2014,7 +1884,7 @@ - + ExecuTorch Portable Operator: native_dropout #define RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_DROPOUT /* ExecuTorch op_native_dropout */ @@ -2024,7 +1894,7 @@ - + ExecuTorch Portable Operator: native_group_norm #define RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_GROUP_NORM /* ExecuTorch op_native_group_norm */ @@ -2034,7 +1904,7 @@ - + ExecuTorch Portable Operator: native_layer_norm #define RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_LAYER_NORM /* ExecuTorch op_native_layer_norm */ @@ -2044,7 +1914,7 @@ - + ExecuTorch Portable Operator: ne #define RTE_ML_EXECUTORCH_OP_PORTABLE_NE /* ExecuTorch op_ne */ @@ -2054,7 +1924,7 @@ - + ExecuTorch Portable Operator: neg #define RTE_ML_EXECUTORCH_OP_PORTABLE_NEG /* ExecuTorch op_neg */ @@ -2064,7 +1934,7 @@ - + ExecuTorch Portable Operator: nonzero #define RTE_ML_EXECUTORCH_OP_PORTABLE_NONZERO /* ExecuTorch op_nonzero */ @@ -2074,7 +1944,7 @@ - + ExecuTorch Portable Operator: ones #define RTE_ML_EXECUTORCH_OP_PORTABLE_ONES /* ExecuTorch op_ones */ @@ -2084,7 +1954,7 @@ - + ExecuTorch Portable Operator: pdist_forward #define RTE_ML_EXECUTORCH_OP_PORTABLE_PDIST_FORWARD /* ExecuTorch op_pdist_forward */ @@ -2094,7 +1964,7 @@ - + ExecuTorch Portable Operator: permute_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_PERMUTE_COPY /* ExecuTorch op_permute_copy */ @@ -2104,7 +1974,7 @@ - + ExecuTorch Portable Operator: pixel_shuffle #define RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_SHUFFLE /* ExecuTorch op_pixel_shuffle */ @@ -2114,7 +1984,7 @@ - + ExecuTorch Portable Operator: pixel_unshuffle #define RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_UNSHUFFLE /* ExecuTorch op_pixel_unshuffle */ @@ -2124,7 +1994,7 @@ - + ExecuTorch Portable Operator: pow #define RTE_ML_EXECUTORCH_OP_PORTABLE_POW /* ExecuTorch op_pow */ @@ -2134,7 +2004,7 @@ - + ExecuTorch Portable Operator: prod #define RTE_ML_EXECUTORCH_OP_PORTABLE_PROD /* ExecuTorch op_prod */ @@ -2144,7 +2014,7 @@ - + ExecuTorch Portable Operator: rand #define RTE_ML_EXECUTORCH_OP_PORTABLE_RAND /* ExecuTorch op_rand */ @@ -2154,7 +2024,7 @@ - + ExecuTorch Portable Operator: randn #define RTE_ML_EXECUTORCH_OP_PORTABLE_RANDN /* ExecuTorch op_randn */ @@ -2164,7 +2034,7 @@ - + ExecuTorch Portable Operator: reciprocal #define RTE_ML_EXECUTORCH_OP_PORTABLE_RECIPROCAL /* ExecuTorch op_reciprocal */ @@ -2174,7 +2044,7 @@ - + ExecuTorch Portable Operator: reflection_pad1d #define RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD1D /* ExecuTorch op_reflection_pad1d */ @@ -2184,7 +2054,7 @@ - + ExecuTorch Portable Operator: reflection_pad2d #define RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD2D /* ExecuTorch op_reflection_pad2d */ @@ -2194,7 +2064,7 @@ - + ExecuTorch Portable Operator: reflection_pad3d #define RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD3D /* ExecuTorch op_reflection_pad3d */ @@ -2204,7 +2074,7 @@ - + ExecuTorch Portable Operator: relu #define RTE_ML_EXECUTORCH_OP_PORTABLE_RELU /* ExecuTorch op_relu */ @@ -2214,7 +2084,7 @@ - + ExecuTorch Portable Operator: remainder #define RTE_ML_EXECUTORCH_OP_PORTABLE_REMAINDER /* ExecuTorch op_remainder */ @@ -2224,7 +2094,7 @@ - + ExecuTorch Portable Operator: repeat #define RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT /* ExecuTorch op_repeat */ @@ -2234,7 +2104,7 @@ - + ExecuTorch Portable Operator: repeat_interleave #define RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT_INTERLEAVE /* ExecuTorch op_repeat_interleave */ @@ -2244,7 +2114,7 @@ - + ExecuTorch Portable Operator: replication_pad1d #define RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD1D /* ExecuTorch op_replication_pad1d */ @@ -2254,7 +2124,7 @@ - + ExecuTorch Portable Operator: replication_pad2d #define RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD2D /* ExecuTorch op_replication_pad2d */ @@ -2264,7 +2134,7 @@ - + ExecuTorch Portable Operator: replication_pad3d #define RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD3D /* ExecuTorch op_replication_pad3d */ @@ -2274,7 +2144,7 @@ - + ExecuTorch Portable Operator: roll #define RTE_ML_EXECUTORCH_OP_PORTABLE_ROLL /* ExecuTorch op_roll */ @@ -2284,7 +2154,7 @@ - + ExecuTorch Portable Operator: round #define RTE_ML_EXECUTORCH_OP_PORTABLE_ROUND /* ExecuTorch op_round */ @@ -2294,7 +2164,7 @@ - + ExecuTorch Portable Operator: rsqrt #define RTE_ML_EXECUTORCH_OP_PORTABLE_RSQRT /* ExecuTorch op_rsqrt */ @@ -2304,7 +2174,7 @@ - + ExecuTorch Portable Operator: rsub #define RTE_ML_EXECUTORCH_OP_PORTABLE_RSUB /* ExecuTorch op_rsub */ @@ -2314,7 +2184,7 @@ - + ExecuTorch Portable Operator: scalar_tensor #define RTE_ML_EXECUTORCH_OP_PORTABLE_SCALAR_TENSOR /* ExecuTorch op_scalar_tensor */ @@ -2324,7 +2194,7 @@ - + ExecuTorch Portable Operator: scatter #define RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER /* ExecuTorch op_scatter */ @@ -2334,7 +2204,7 @@ - + ExecuTorch Portable Operator: scatter_add #define RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER_ADD /* ExecuTorch op_scatter_add */ @@ -2344,7 +2214,7 @@ - + ExecuTorch Portable Operator: select_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_COPY /* ExecuTorch op_select_copy */ @@ -2354,7 +2224,7 @@ - + ExecuTorch Portable Operator: select_scatter #define RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_SCATTER /* ExecuTorch op_select_scatter */ @@ -2364,7 +2234,7 @@ - + ExecuTorch Portable Operator: sigmoid #define RTE_ML_EXECUTORCH_OP_PORTABLE_SIGMOID /* ExecuTorch op_sigmoid */ @@ -2374,7 +2244,7 @@ - + ExecuTorch Portable Operator: sign #define RTE_ML_EXECUTORCH_OP_PORTABLE_SIGN /* ExecuTorch op_sign */ @@ -2384,7 +2254,7 @@ - + ExecuTorch Portable Operator: sin #define RTE_ML_EXECUTORCH_OP_PORTABLE_SIN /* ExecuTorch op_sin */ @@ -2394,7 +2264,7 @@ - + ExecuTorch Portable Operator: sinh #define RTE_ML_EXECUTORCH_OP_PORTABLE_SINH /* ExecuTorch op_sinh */ @@ -2404,7 +2274,7 @@ - + ExecuTorch Portable Operator: slice_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_COPY /* ExecuTorch op_slice_copy */ @@ -2414,7 +2284,7 @@ - + ExecuTorch Portable Operator: slice_scatter #define RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_SCATTER /* ExecuTorch op_slice_scatter */ @@ -2424,7 +2294,7 @@ - + ExecuTorch Portable Operator: softmax #define RTE_ML_EXECUTORCH_OP_PORTABLE_SOFTMAX /* ExecuTorch op_softmax */ @@ -2434,7 +2304,7 @@ - + ExecuTorch Portable Operator: split_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_COPY /* ExecuTorch op_split_copy */ @@ -2444,7 +2314,7 @@ - + ExecuTorch Portable Operator: split_with_sizes_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_WITH_SIZES_COPY /* ExecuTorch op_split_with_sizes_copy */ @@ -2454,7 +2324,7 @@ - + ExecuTorch Portable Operator: sqrt #define RTE_ML_EXECUTORCH_OP_PORTABLE_SQRT /* ExecuTorch op_sqrt */ @@ -2464,7 +2334,7 @@ - + ExecuTorch Portable Operator: squeeze_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_SQUEEZE_COPY /* ExecuTorch op_squeeze_copy */ @@ -2474,7 +2344,7 @@ - + ExecuTorch Portable Operator: stack #define RTE_ML_EXECUTORCH_OP_PORTABLE_STACK /* ExecuTorch op_stack */ @@ -2484,7 +2354,7 @@ - + ExecuTorch Portable Operator: sub #define RTE_ML_EXECUTORCH_OP_PORTABLE_SUB /* ExecuTorch op_sub */ @@ -2494,7 +2364,7 @@ - + ExecuTorch Portable Operator: sum #define RTE_ML_EXECUTORCH_OP_PORTABLE_SUM /* ExecuTorch op_sum */ @@ -2504,7 +2374,7 @@ - + ExecuTorch Portable Operator: t_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_T_COPY /* ExecuTorch op_t_copy */ @@ -2514,7 +2384,7 @@ - + ExecuTorch Portable Operator: tan #define RTE_ML_EXECUTORCH_OP_PORTABLE_TAN /* ExecuTorch op_tan */ @@ -2524,7 +2394,7 @@ - + ExecuTorch Portable Operator: tanh #define RTE_ML_EXECUTORCH_OP_PORTABLE_TANH /* ExecuTorch op_tanh */ @@ -2534,7 +2404,7 @@ - + ExecuTorch Portable Operator: to_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_TO_COPY /* ExecuTorch op_to_copy */ @@ -2544,7 +2414,7 @@ - + ExecuTorch Portable Operator: topk #define RTE_ML_EXECUTORCH_OP_PORTABLE_TOPK /* ExecuTorch op_topk */ @@ -2554,7 +2424,7 @@ - + ExecuTorch Portable Operator: transpose_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_TRANSPOSE_COPY /* ExecuTorch op_transpose_copy */ @@ -2564,7 +2434,7 @@ - + ExecuTorch Portable Operator: tril #define RTE_ML_EXECUTORCH_OP_PORTABLE_TRIL /* ExecuTorch op_tril */ @@ -2574,7 +2444,7 @@ - + ExecuTorch Portable Operator: trunc #define RTE_ML_EXECUTORCH_OP_PORTABLE_TRUNC /* ExecuTorch op_trunc */ @@ -2584,7 +2454,7 @@ - + ExecuTorch Portable Operator: unbind_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_UNBIND_COPY /* ExecuTorch op_unbind_copy */ @@ -2594,7 +2464,7 @@ - + ExecuTorch Portable Operator: unfold_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_UNFOLD_COPY /* ExecuTorch op_unfold_copy */ @@ -2604,7 +2474,7 @@ - + ExecuTorch Portable Operator: unsqueeze_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_UNSQUEEZE_COPY /* ExecuTorch op_unsqueeze_copy */ @@ -2614,7 +2484,7 @@ - + ExecuTorch Portable Operator: upsample_bilinear2d #define RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D /* ExecuTorch op_upsample_bilinear2d */ @@ -2624,7 +2494,7 @@ - + ExecuTorch Portable Operator: upsample_bilinear2d_aa #define RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D_AA /* ExecuTorch op_upsample_bilinear2d_aa */ @@ -2634,7 +2504,7 @@ - + ExecuTorch Portable Operator: upsample_nearest2d #define RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_NEAREST2D /* ExecuTorch op_upsample_nearest2d */ @@ -2644,7 +2514,7 @@ - + ExecuTorch Portable Operator: var #define RTE_ML_EXECUTORCH_OP_PORTABLE_VAR /* ExecuTorch op_var */ @@ -2654,17 +2524,7 @@ - - ExecuTorch Portable Operator: var_mean - - #define RTE_ML_EXECUTORCH_OP_PORTABLE_VAR_MEAN /* ExecuTorch op_var_mean */ - - - - - - - + ExecuTorch Portable Operator: view_as_real_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_AS_REAL_COPY /* ExecuTorch op_view_as_real_copy */ @@ -2674,7 +2534,7 @@ - + ExecuTorch Portable Operator: view_copy #define RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_COPY /* ExecuTorch op_view_copy */ @@ -2684,7 +2544,7 @@ - + ExecuTorch Portable Operator: where #define RTE_ML_EXECUTORCH_OP_PORTABLE_WHERE /* ExecuTorch op_where */ @@ -2694,7 +2554,7 @@ - + ExecuTorch Portable Operator: zeros #define RTE_ML_EXECUTORCH_OP_PORTABLE_ZEROS /* ExecuTorch op_zeros */ @@ -2705,7 +2565,7 @@ - + ExecuTorch Quantized Operator: add #define RTE_ML_EXECUTORCH_OP_QUANTIZED_ADD /* ExecuTorch op_add */ @@ -2715,7 +2575,7 @@ - + ExecuTorch Quantized Operator: choose_qparams #define RTE_ML_EXECUTORCH_OP_QUANTIZED_CHOOSE_QPARAMS /* ExecuTorch op_choose_qparams */ @@ -2725,7 +2585,7 @@ - + ExecuTorch Quantized Operator: dequantize #define RTE_ML_EXECUTORCH_OP_QUANTIZED_DEQUANTIZE /* ExecuTorch op_dequantize */ @@ -2735,7 +2595,7 @@ - + ExecuTorch Quantized Operator: embedding #define RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING /* ExecuTorch op_embedding */ @@ -2745,7 +2605,7 @@ - + ExecuTorch Quantized Operator: embedding2b #define RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING2B /* ExecuTorch op_embedding2b */ @@ -2755,7 +2615,7 @@ - + ExecuTorch Quantized Operator: embedding4b #define RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING4B /* ExecuTorch op_embedding4b */ @@ -2765,7 +2625,7 @@ - + ExecuTorch Quantized Operator: mixed_linear #define RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_LINEAR /* ExecuTorch op_mixed_linear */ @@ -2775,7 +2635,7 @@ - + ExecuTorch Quantized Operator: mixed_mm #define RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_MM /* ExecuTorch op_mixed_mm */ @@ -2785,7 +2645,7 @@ - + ExecuTorch Quantized Operator: quantize #define RTE_ML_EXECUTORCH_OP_QUANTIZED_QUANTIZE /* ExecuTorch op_quantize */ @@ -2795,195 +2655,84 @@ - - - - ExecuTorch Cortex-M Operator: dequantize_per_tensor + + + + + ExecuTorch Ethos-U NPU Backend - Hardware acceleration for Ethos-U55/U65 - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_DEQUANTIZE_PER_TENSOR /* ExecuTorch op_dequantize_per_tensor */ + #define RTE_ML_EXECUTORCH_BACKEND_ETHOS_U /* ExecuTorch Ethos-U Backend */ + + #define EXECUTORCH_BUILD_ARM_BAREMETAL 1 + #define ET_USE_ETHOS_U_BACKEND 1 + - + + - - - ExecuTorch Cortex-M Operator: maximum + + + + ExecuTorch Cortex-M Backend - CMSIS-NN optimized operators - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_MAXIMUM /* ExecuTorch op_maximum */ + #define RTE_ML_EXECUTORCH_BACKEND_CORTEX_M /* ExecuTorch Cortex-M Backend */ + + #define EXECUTORCH_BUILD_CORTEX_M 1 + + - - - - - ExecuTorch Cortex-M Operator: minimum - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_MINIMUM /* ExecuTorch op_minimum */ - - - - - - - ExecuTorch Cortex-M Operator: pad - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_PAD /* ExecuTorch op_pad */ - - - - - - - - ExecuTorch Cortex-M Operator: quantize_per_tensor - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZE_PER_TENSOR /* ExecuTorch op_quantize_per_tensor */ - - - - - - - ExecuTorch Cortex-M Operator: quantized_add - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_ADD /* ExecuTorch op_quantized_add */ - - - - - - - ExecuTorch Cortex-M Operator: quantized_avg_pool2d - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_AVG_POOL2D /* ExecuTorch op_quantized_avg_pool2d */ - - - - - - - ExecuTorch Cortex-M Operator: quantized_batch_matmul - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_BATCH_MATMUL /* ExecuTorch op_quantized_batch_matmul */ - - - - - - - - ExecuTorch Cortex-M Operator: quantized_conv2d - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_CONV2D /* ExecuTorch op_quantized_conv2d */ - - - - - - - ExecuTorch Cortex-M Operator: quantized_depthwise_conv2d - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_DEPTHWISE_CONV2D /* ExecuTorch op_quantized_depthwise_conv2d */ - - - - - - - ExecuTorch Cortex-M Operator: quantized_linear - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_LINEAR /* ExecuTorch op_quantized_linear */ - - - - - - - ExecuTorch Cortex-M Operator: quantized_max_pool2d - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MAX_POOL2D /* ExecuTorch op_quantized_max_pool2d */ - - - - - - - - ExecuTorch Cortex-M Operator: quantized_mul - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MUL /* ExecuTorch op_quantized_mul */ - - - - - - - ExecuTorch Cortex-M Operator: quantized_transpose_conv2d - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_TRANSPOSE_CONV2D /* ExecuTorch op_quantized_transpose_conv2d */ - - - - - - - - ExecuTorch Cortex-M Operator: softmax - - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_SOFTMAX /* ExecuTorch op_softmax */ - - + + + - - ExecuTorch Cortex-M Operator: transpose + + + + + ExecuTorch Bare-Metal PAL - Platform stubs for ARM Cortex-M bare-metal targets - #define RTE_ML_EXECUTORCH_OP_CORTEX_M_TRANSPOSE /* ExecuTorch op_transpose */ + #define RTE_ML_EXECUTORCH_PLATFORM_BARE_METAL /* ExecuTorch Bare-Metal PAL */ - + - - - - - - ExecuTorch Ethos-U NPU Backend - Cortex-M host (bare-metal). Hardware acceleration for Ethos-U55/U65 + + + ExecuTorch Random Op Stubs - Stubs for rand/randn on platforms without std::random_device - #define RTE_ML_EXECUTORCH_BACKEND_ETHOS_U /* ExecuTorch Ethos-U Backend (Cortex-M host) */ + #define RTE_ML_EXECUTORCH_STUBS_RANDOM_OPS /* ExecuTorch Random Op Stubs */ - - #define EXECUTORCH_BUILD_ARM_BAREMETAL 1 - #define ET_USE_ETHOS_U_BACKEND 1 - - - - - + + + + Basic ExecuTorch inference example + + + + + + diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/Functions.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/Functions.h new file mode 100644 index 0000000..1a6e6c7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/Functions.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +// clang-format off +#pragma once + +#include + +#include // at::Tensor etc. +#include // TORCH_API +#include + +// @generated by gen.py from Functions.h + +#include "NativeFunctions.h" + +namespace torch { +namespace executor { + + + +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/NativeFunctions.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/NativeFunctions.h new file mode 100644 index 0000000..af7ceeb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/NativeFunctions.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +// clang-format off +#pragma once + +#include + +#include // at::Tensor etc. +#include +#include + +// @generated by gen.py from NativeFunctions.h + + diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernelsEverything.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernelsEverything.cpp new file mode 100644 index 0000000..12cf90c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernelsEverything.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include "" // Generated Function import headers +// @generated by gen.py from RegisterCodegenUnboxedKernels.cpp + +// NOTE [Sharded File]: This file is generated in a sharded fashion to speed up +// incremental rebuilds. See the comment at the top of +// templates/VariableType.cpp for an analogous, in-depth discussion. +// +// Generated by tools/jit/gen_unboxing.py. This file registers all ATen ops into +// JIT op registry instead of c10 dispatcher. JIT op registry only takes boxed +// kernels, so we are calling unboxing functions in UnboxingFunctions.h to cast +// arguments into C++ types (instead of IValue) and delegate to unboxed kernels. +using KernelSpan = ::executorch::runtime::Span< + const ::executorch::ET_RUNTIME_NAMESPACE::Kernel>; +namespace torch { +namespace executor { +namespace function { +namespace { + +static Kernel kernels_to_register[] = { + // Generated kernels +}; + +// Explicitly convert to Span, so that the API can take an empty C array of +// Kernels. +static KernelSpan kernel_span( + kernels_to_register, + kernels_to_register + sizeof(kernels_to_register) / sizeof(Kernel)); + +// Return value not used. Keep the static variable assignment to register +// kernels in static initialization time. +static auto success_with_kernel_reg = register_kernels(kernel_span); +} // namespace +} // namespace function +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernels_0.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernels_0.cpp new file mode 100644 index 0000000..12cf90c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterCodegenUnboxedKernels_0.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include "" // Generated Function import headers +// @generated by gen.py from RegisterCodegenUnboxedKernels.cpp + +// NOTE [Sharded File]: This file is generated in a sharded fashion to speed up +// incremental rebuilds. See the comment at the top of +// templates/VariableType.cpp for an analogous, in-depth discussion. +// +// Generated by tools/jit/gen_unboxing.py. This file registers all ATen ops into +// JIT op registry instead of c10 dispatcher. JIT op registry only takes boxed +// kernels, so we are calling unboxing functions in UnboxingFunctions.h to cast +// arguments into C++ types (instead of IValue) and delegate to unboxed kernels. +using KernelSpan = ::executorch::runtime::Span< + const ::executorch::ET_RUNTIME_NAMESPACE::Kernel>; +namespace torch { +namespace executor { +namespace function { +namespace { + +static Kernel kernels_to_register[] = { + // Generated kernels +}; + +// Explicitly convert to Span, so that the API can take an empty C array of +// Kernels. +static KernelSpan kernel_span( + kernels_to_register, + kernels_to_register + sizeof(kernels_to_register) / sizeof(Kernel)); + +// Return value not used. Keep the static variable assignment to register +// kernels in static initialization time. +static auto success_with_kernel_reg = register_kernels(kernel_span); +} // namespace +} // namespace function +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterKernels.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterKernels.h new file mode 100644 index 0000000..cba37da --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/RegisterKernels.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +// @generated by torchgen/gen_executorch.py +// Exposing an API for registering all kernels at once. +#include +#include +#include +#include + +namespace torch { +namespace executor { + +Error register_all_kernels(); + +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/selected_operators.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/selected_operators.yaml new file mode 100644 index 0000000..8c194d7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/generated_test/executorch_selected_kernels/selected_operators.yaml @@ -0,0 +1,23 @@ +build_features: [] +custom_classes: [] +et_kernel_metadata: + quantized_decomposed::dequantize_per_tensor.out: + - v1/1;0,1,2,3|6;0,1,2,3|6;0,1,2,3 + quantized_decomposed::quantize_per_tensor.out: + - v1/6;0,1,2,3|1;0,1,2,3|1;0,1,2,3 +include_all_non_op_selectives: false +include_all_operators: false +kernel_metadata: {} +operators: + quantized_decomposed::dequantize_per_tensor.out: + debug_info: + - /workspace2/model/ethos_u_minimal_example.pte + include_all_overloads: false + is_root_operator: true + is_used_for_training: true + quantized_decomposed::quantize_per_tensor.out: + debug_info: + - /workspace2/model/ethos_u_minimal_example.pte + include_all_overloads: false + is_root_operator: true + is_used_for_training: true diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/macros/Export.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/macros/Export.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/macros/Export.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/macros/Export.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/macros/Macros.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/macros/Macros.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/macros/Macros.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/macros/Macros.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/targets.bzl new file mode 100644 index 0000000..33a5580 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/targets.bzl @@ -0,0 +1,139 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def get_preprocessor_flags(is_fbcode): + flags = ["-DSTANDALONE_TORCH_HEADER"] + if runtime.is_oss: + return flags + # AT_BUILD_ARM_VEC256_WITH_SLEEF is off on Windows because Sleef + # is off on Windows per get_sleef_deps below. + arm64_flags = select({ + "DEFAULT": [ + "-DCPU_CAPABILITY_DEFAULT", + "-DAT_BUILD_ARM_VEC256_WITH_SLEEF", + ], + "ovr_config//os:windows": ["-DCPU_CAPABILITY_DEFAULT"], + }) + + x86_avx2_flags = [ + "-DCPU_CAPABILITY_AVX2", + "-DHAVE_AVX2_CPU_DEFINITION", + ] + default_flags = [ + "-DCPU_CAPABILITY_DEFAULT", + ] + fbcode_flags = select({ + "ovr_config//cpu:x86_64": x86_avx2_flags, + "ovr_config//cpu:arm64": arm64_flags, + "DEFAULT": default_flags, + }) + non_fbcode_flags = select({ + "ovr_config//cpu/x86:avx2": x86_avx2_flags, + "ovr_config//cpu:arm64": arm64_flags, + "DEFAULT": default_flags, + }) + return flags + ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"] + (fbcode_flags if is_fbcode else non_fbcode_flags) + +def get_sleef_deps(): + if runtime.is_oss: + return [] + return select({ + "DEFAULT": select({ + "DEFAULT": [], + "ovr_config//cpu:x86_64": [ + "fbsource//third-party/sleef:sleef", + ], + "ovr_config//cpu:arm64": [ + "fbsource//third-party/sleef:sleef", + ], + }), + "ovr_config//os:windows": [ + "fbsource//third-party/sleef:sleef", + ], + }) + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "aten_headers_for_executorch", + srcs = [], + visibility = ["PUBLIC"], + # select() on ovr_config//runtime:fbcode does not work + # properly in all cases. I have seen + # //xplat/executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch + # pass such a select in (at least) arvr mode. Going back to + # fbcode_exported_deps accordingly. + exported_deps = select({ + "DEFAULT": [], + "ovr_config//cpu:arm64": [ + "fbsource//third-party/sleef:sleef", + ] if not runtime.is_oss else [], + }), + xplat_exported_deps = [ + "fbsource//xplat/caffe2:aten_header", + "fbsource//xplat/caffe2/c10:c10_headers", + ] + select({ + "DEFAULT": ["fbsource//xplat/caffe2:generated_aten_config_header"], + "ovr_config//build_mode:arvr_mode": ["fbsource//xplat/caffe2:ovrsource_aten_Config.h"], + }) + get_sleef_deps(), + fbcode_exported_deps = ([ + "//caffe2:aten-headers-cpu", + "//caffe2:generated-config-header", + "//caffe2/c10:c10_headers", + ] + get_sleef_deps()) if not runtime.is_oss else [], + exported_preprocessor_flags = get_preprocessor_flags(is_fbcode=False) + + ([] if runtime.is_oss else ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"]), + fbcode_exported_preprocessor_flags = get_preprocessor_flags(is_fbcode=True) + + ([] if runtime.is_oss else ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"]), + ) + + if runtime.is_oss: + runtime.cxx_library( + name = "c10", + header_namespace = "c10", + exported_headers = [ + "macros/Export.h", + "macros/Macros.h", + "util/BFloat16.h", + "util/BFloat16-inl.h", + "util/BFloat16-math.h", + "util/Half.h", + "util/Half-inl.h", + "util/TypeSafeSignMath.h", + "util/bit_cast.h", + "util/complex.h", + "util/complex_math.h", + "util/complex_utils.h", + "util/floating_point_utils.h", + "util/irange.h", + "util/llvmMathExtras.h", + "util/overflows.h", + "util/safe_numerics.h", + ], + exported_preprocessor_flags = [ + "-DC10_USING_CUSTOM_GENERATED_MACROS", + ] + ([] if runtime.is_oss else [ + "-DC10_USE_GLOG", + "-DC10_USE_MINIMAL_GLOG", + ]), + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/torch/headeronly:torch_headeronly", + ] + select({ + "DEFAULT": [], + # Half-inl.h depends on vec_half.h from ATen, but only when building for x86. + "ovr_config//cpu:x86_64": [ + ":aten_headers_for_executorch", + ], + }), + ) + else: + runtime.cxx_library( + name = "c10", + exported_deps = [":aten_headers_for_executorch"], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/BFloat16-inl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/BFloat16-inl.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/BFloat16-inl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/BFloat16-inl.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/BFloat16-math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/BFloat16-math.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/BFloat16-math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/BFloat16-math.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/BFloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/BFloat16.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/BFloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/BFloat16.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/Half-inl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/Half-inl.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/Half-inl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/Half-inl.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/Half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/Half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/Half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/Half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/TypeSafeSignMath.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/TypeSafeSignMath.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/TypeSafeSignMath.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/TypeSafeSignMath.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/bit_cast.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/bit_cast.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/bit_cast.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/bit_cast.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/complex_math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/complex_math.h similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/complex_math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/complex_math.h index d369df5..2b59102 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/complex_math.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/complex_math.h @@ -86,41 +86,6 @@ C10_HOST_DEVICE inline c10::complex pow( #endif } -// Regression in ROCm 7.2. See https://github.com/ROCm/rocm-libraries/pull/3836. -// Specialized version for complex on AMD GPUs to use FMA-based -// multiplication -#if defined(__HIPCC__) -namespace detail { -// FMA-aware complex multiplication for float precision on AMD GPUs. -// This prevents SLP vectorizer from breaking FMA formation, which causes -// numerical precision loss in complex arithmetic. -// The issue occurs when vectorizer packs scalar multiplies before backend -// can form FMA instructions, resulting in double rounding instead of single. -C10_HOST_DEVICE inline thrust::complex complex_mul_fma( - thrust::complex a, - thrust::complex b) { - // Complex multiplication: (a.r + a.i*i) * (b.r + b.i*i) - // = (a.r*b.r - a.i*b.i) + (a.r*b.i + a.i*b.r)*i - // Using __builtin_fmaf ensures FMA at source level: - // real: a.r*b.r + (-(a.i*b.i)) = FMA(a.r, b.r, -(a.i*b.i)) - // imag: a.i*b.r + a.r*b.i = FMA(a.r, b.i, a.i*b.r) - float real_part = __builtin_fmaf(a.real(), b.real(), -(a.imag() * b.imag())); - float imag_part = __builtin_fmaf(a.real(), b.imag(), a.imag() * b.real()); - return thrust::complex(real_part, imag_part); -} -} // namespace detail - -template <> -C10_HOST_DEVICE inline c10::complex pow( - const c10::complex& x, - const c10::complex& y) { - auto log_x = thrust::log(static_cast>(x)); - auto y_log_x = - detail::complex_mul_fma(static_cast>(y), log_x); - return static_cast>(thrust::exp(y_log_x)); -} -#endif - template C10_HOST_DEVICE inline c10::complex pow( const c10::complex& x, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/complex_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/complex_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/complex_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/complex_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/floating_point_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/floating_point_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/floating_point_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/floating_point_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/irange.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/irange.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/irange.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/irange.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/llvmMathExtras.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/llvmMathExtras.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/llvmMathExtras.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/llvmMathExtras.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/overflows.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/overflows.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/overflows.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/overflows.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/safe_numerics.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/safe_numerics.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/c10/util/safe_numerics.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/c10/util/safe_numerics.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/CMakeLists.txt new file mode 100644 index 0000000..0ffa6f1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/CMakeLists.txt @@ -0,0 +1,115 @@ +# Copyright 2023, 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +cmake_minimum_required(VERSION 3.19) +project(arm_backend) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) + +set(_common_include_directories + ${EXECUTORCH_ROOT}/.. ${EXECUTORCH_ROOT}/runtime/core/portable_type/c10 +) +add_compile_definitions(C10_USING_CUSTOM_GENERATED_MACROS) + +# bare metal backend builds +if(EXECUTORCH_BUILD_ARM_BAREMETAL) + + add_compile_options("-Wall" "-Werror") + + # Third-party folder and Ethos-U driver inclued + set(THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/third-party") + set(DRIVER_ETHOSU_INCLUDE_DIR + "${THIRD_PARTY_ROOT}/ethos-u-core-driver/include" + ) + include_directories(${DRIVER_ETHOSU_INCLUDE_DIR}) + + set(_arm_baremetal_sources backends/arm/runtime/EthosUBackend.cpp + backends/arm/runtime/VelaBinStream.cpp + ) + list(TRANSFORM _arm_baremetal_sources PREPEND "${EXECUTORCH_ROOT}/") + + add_library(executorch_delegate_ethos_u STATIC ${_arm_baremetal_sources}) + target_link_libraries( + executorch_delegate_ethos_u PUBLIC executorch_core ethosu_core_driver + ) + + install(TARGETS executorch_delegate_ethos_u EXPORT ExecuTorchTargets) + + # end config for bare metal builds +endif() + +# VGF backend builds +if(EXECUTORCH_BUILD_VGF) + set(VULKAN_THIRD_PARTY_PATH ${EXECUTORCH_ROOT}/backends/vulkan/third-party) + set(VULKAN_HEADERS_PATH ${VULKAN_THIRD_PARTY_PATH}/Vulkan-Headers/include) + set(VOLK_HEADERS_PATH ${VULKAN_THIRD_PARTY_PATH}/volk) + + if(EXISTS + "${EXECUTORCH_ROOT}/examples/arm/arm-scratch/ml-sdk-for-vulkan-manifest/" + ) + message(STATUS "libvgf sourced from local scratch tree") + + # Legacy layout: libvgf sourced from local scratch tree + set(LIBVGF_PATH + "${EXECUTORCH_ROOT}/examples/arm/arm-scratch/ml-sdk-for-vulkan-manifest/sw/vgf-lib/" + ) + set(LIBVGF_STATIC "${LIBVGF_PATH}/build/src/libvgf.a") + else() + message(STATUS "libvgf installed from pip package") + + set(Python3_FIND_VIRTUALENV FIRST) + if(EXECUTORCH_ROOT AND EXISTS "${EXECUTORCH_ROOT}/env") + set(Python3_EXECUTABLE "${EXECUTORCH_ROOT}/env/bin/python3") + endif() + + find_package(Python3 REQUIRED COMPONENTS Interpreter) + + # Prefer arch-specific site-packages if present, else pure + set(_vgf_site_arch "${Python3_SITEARCH}/vgf_lib/binaries") + set(_vgf_site_pure "${Python3_SITELIB}/vgf_lib/binaries") + if(EXISTS "${_vgf_site_arch}") + set(LIBVGF_PATH "${_vgf_site_arch}") + else() + set(LIBVGF_PATH "${_vgf_site_pure}") + endif() + + set(LIBVGF_STATIC "${LIBVGF_PATH}/lib/libvgf.a") + endif() + + set(LIBVGF_INCLUDE "${LIBVGF_PATH}/include/") + + add_library(vgf STATIC IMPORTED) + set_property(TARGET vgf PROPERTY IMPORTED_LOCATION "${LIBVGF_STATIC}") + target_include_directories(vgf INTERFACE "${LIBVGF_INCLUDE}") + + # Add backend delegate for VGF + set(_vgf_backend_sources backends/arm/runtime/VGFBackend.cpp + backends/arm/runtime/VGFSetup.cpp + ) + + # vgf backend + list(TRANSFORM _vgf_backend_sources PREPEND "${EXECUTORCH_ROOT}/") + add_library(vgf_backend ${_vgf_backend_sources}) + install(TARGETS vgf_backend EXPORT ExecuTorchTargets) + target_include_directories( + vgf_backend PRIVATE ${_common_include_directories} ${VULKAN_HEADERS_PATH} + ${VOLK_HEADERS_PATH} + ) + target_compile_options( + vgf_backend PRIVATE -DUSE_VULKAN_WRAPPER -DUSE_VULKAN_VOLK + ) + + target_link_libraries(vgf_backend PRIVATE executorch_core) + target_link_libraries(vgf_backend PRIVATE vgf) + executorch_target_link_options_shared_lib(vgf_backend) + + # end config for VGF builds +endif() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/MODELS.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/MODELS.md new file mode 100644 index 0000000..aab801d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/MODELS.md @@ -0,0 +1,20 @@ +# The following file contains all models that have been confirmed to be functional and tested for the Arm backend: +- Conformer +- Deit Tiny +- DeepLab v3 (DL3) +- Inception v3 (IC3) +- Llama +- Long Short-Term Memory (LSTM) +- MobileNet v2 (MV2) +- MobileNet v3 (MV3) +- Some popular torch.nn.functional models (NN functional) +- Some popular torch.nn.modules models (NN modules) +- Some popular torch ops (Torch Functions) +- Neural Super Sampler (NSS) +- ResNet 18 +- Wav2Letter (W2L) +- Stable Diffusion: + * CLIP Text Encoder (CLIP Text with Projection) + * Stable Diffusion 3 Transformer (SD3 Transformer) + * T5 Encoder + * VAE Encoder/Decoder (VAE) \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/README.md new file mode 100644 index 0000000..2e314ca --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/README.md @@ -0,0 +1,237 @@ +# ExecuTorch Arm® Backend + +This subtree contains the Arm® Backend implementation for ExecuTorch. +It supports multiple targets using a common infrastructure, that lowers +PyTorch models to a TOSA representation. This representation is used to +deploy to the following targets: + +- **Arm® Ethos™-U55/65/85** - Compiled using the Ethos-U Vela compiler. +- **VGF Format, for ML extensions for Vulkan®** – a format containing SPIR-V™ ML operators for Vulkan-capable devices. + +The backend provides an ahead-of-time (AOT) flow, that produces a PTE file for your +chosen target. The AOT flow supports the following development operating systems: + +- Linux aarch64 +- Linux x86_64 +- macOS™ with Apple® Silicon + +In addition, the following deployment paths are supported by this backend: + +- Bare metal build of a reference runtime for Arm® Cortex®-M with Ethos-U acceleration: + - Full testing is available in tree using Corstone™ Fixed Virtual Platforms (FVP). +- Linux target support for VGF capable targets, using the executor_runner. + +More information on TOSA can be found here: https://www.mlplatform.org/tosa/tosa_spec.html. + +## Directory Layout + +Below is an overview of the key folder and files in this directory: + +``` +backends/arm/ +│ +├── _passes/ # Graph transformation passes +│ ├── arm_pass_manager.py # Defines ordering of graph transformations +│ └── *_pass.py # Graph transformation implementation +│ +├── common/ # Common functionality used across the backend +│ +├── debug/ # Debugging schema and functionality +│ +├── ethosu/ # Implementations of EthosUPartitioner and EthosUBackend +│ +├── operator_support/ # Checks if operators can be partitioned +│ +├── operators/ # ATen → TOSA serialization +│ ├── node_visitor.py # Defines base class for ATen → TOSA node visitors +│ └── op_*.py # Lowering implementations for individual operators +│ +├── quantizer/ # Quantization-related logic +│ ├── arm_quantizer.py # EthosUQuantizer and VGFQuantizer definitions +│ └── quantization_annotator.py # Defines how operators are annotated for quantization +│ +├── runtime/ # Backends for running inference on target devices +│ ├── ArmEthosUBackend.cpp +│ └── VGFBackend.cpp +│ +├── scripts/ # Auxiliary build, dependency installation and utility scripts +│ +├── test/ # Unit tests for the backend +│ ├── ops/ # Operator level unit tests +│ ├── models/ # Model level unit tests +│ └── tester/ # Testing harnesses and utilities +│ +├── third-party/ # External dependencies +│ +├── tosa/ # Shared TOSA backend implementation and dialect +│ +└── vgf/ # Implementations of VgfPartitioner and VgfBackend +``` + +## Building + +The Arm backend can be built using the following command: + +``` +./install_executorch.sh +``` + +One of the following commands should also be run once to gather the necessary dependencies for your chosen target(s): + +For the Ethos-U target: + +``` +./examples/arm/setup.sh --i-agree-to-the-contained-eula +``` + +For the VGF target: + +``` +./examples/arm/setup.sh --disable-ethos-u-deps --enable-mlsdk-deps +``` + +For both Ethos-U & VGF targets: + +``` +./examples/arm/setup.sh --i-agree-to-the-contained-eula --enable-mlsdk-deps +``` + +**NOTE:** While developing, it can be convenient to use`./install_executorch.sh --editable`, which creates an editable installation of ExecuTorch. + +## Testing + +There are two approaches for running the tests for the Arm backend. This section will explain these two approaches: + +### Using test_arm_baremetal.sh + +The backend provides a script `backends/arm/test/test_arm_baremetal.sh`, which is used in the `trunk` CI workflow. +This approach is useful for checking your change against this workflow on your own machine. +These scripts also install the necessary dependencies to run the tests. +Below is an overview of some of the testing options this script provides: + +| Command | Description | +| ---------------------------------------------------- | ------------------------------------------------------------ | +| `test_arm_baremetal.sh test_pytest_ops_no_target` | Runs operator unit tests for non-target specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_no_target` | Runs model unit tests for non-target specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_tosa` | Runs operator unit tests for TOSA specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_tosa` | Runs model unit tests for TOSA specific use-cases. | +| `test_arm_baremetal.sh test_run_tosa` | Runs end-to-end unit tests for TOSA specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_ethos_u55` | Runs operator unit tests for Ethos-U55 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_ethos_u55` | Runs model unit tests for Ethos-U55 specific use-cases. | +| `test_arm_baremetal.sh test_run_ethos_u55` | Runs end-to-end unit tests for Ethos-U55 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_ethos_u85` | Runs operator unit tests for Ethos-U85 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_ethos_u85` | Runs model unit tests for Ethos-U85 specific use-cases. | +| `test_arm_baremetal.sh test_run_ethos_u85` | Runs end-to-end unit tests for Ethos-U85 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_vkml` | Runs operator unit tests for VGF specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_vkml` | Runs model unit tests for VGF specific use-cases. | +| `test_arm_baremetal.sh test_run_vkml` | Runs end-to-end unit tests for VGF specific use-cases. | +| `test_arm_baremetal.sh test_model_smollm2-135M` | Runs some models with Corstone FVP. | +| `test_arm_baremetal.sh test_smaller_stories_llama` | Runs E2E model tests on Corstone FVP. | +| `test_arm_baremetal.sh test_memory_allocation` | Runs memory allocation tests for Ethos-U specific targets | + +For more information, please refer to the `backends/arm/test/test_arm_baremetal.sh` script. + +### Using pytest + +The Arm backend uses `pytest` to run the unit test suite in `backends/arm/test`. +This option offers flexibility, allowing a specific test or a particular subset of the testsuite to be run. +Below provides some examples of how to use it: + +- To run all the unit tests run the following command: + + ``` + pytest -v -n auto backends/arm/test/ + ``` + +- To run a specific test in a file: + + ``` + pytest -v backends/arm/test/ops/test_add.py -k test_add_tensor_tosa_INT_3 + ``` + +#### Testing Dependencies + +Some tests, with `u55`, `u85` and `vgf` in the name require external dependencies to run if you use `pytest`: + +- When a test contains `u55` or `u85`, you must run the following to setup the executor_runner: + ``` + ./backends/arm/scripts/build_executorch.sh + ./backends/arm/test/setup_testing.sh + ``` +- When a test contains `vgf`, you must run the following to install the ML SDK: + ``` + ./backends/arm/scripts/build_executorch.sh + ./backends/arm/test/setup_testing_vkml.sh + ``` + +In addition, some model tests in the Arm backend require third-party libraries or packages. +To run these tests, you need to install the required dependencies by running the script `examples/arm/setup.sh` with the flag `--setup-test-dependency`. + +Please note that installing model test dependencies is a standalone process. When using the `--setup-test-dependency` flag, +the script will install only the necessary dependencies for model tests, skipping all other setup procedures. + +## Using pre-commit + +A pre-commit script is available in the backend to help developers. Follow the steps below to enable it: + +``` +cp backends/arm/scripts/pre-commit .git/hooks/ +``` + +## Notes on model specific and optional passes + +The current TOSA version does not support int64. However, int64 is commonly used in many models. In order to lower the operators with int64 inputs and/or outputs to TOSA, a few passes have been developed to handle the int64-related issues. The main idea behind these passes is to replace the uses of int64 with int32 where feasible. + +- For floating-point models, these passes need to run very early in the lowering process and can be passed in to the to_edge_transform_and_lower() function call as an optional parameter. +- For quantized models, these transformations will be automatically handled during annotation before the export stage. + +List of model specific and optional passes: + +- ConvertInt64ConstOpsToInt32Pass + - Functionalities: + - Rewrites constant-producing ops that output int64 to instead output int32, when values are within int32 bounds. + - Supported Ops: + - `torch.full`, `torch.arange`, `torch.eye`, `torch.linspace`, `torch.tensor` + - Example usage: + - backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py + - backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py + +- ConvertInt64OutputOpsToInt32Pass + - Overview: + - Rewrites or removes operations that produce int64 outputs, converting them to int32 where possible. + - Overflow checks are applied selectively; for ops without such checks, users need to ensure values fit within the int32 range. + - Functionalities: + 1. Handling casting to int64: + - (1) int32 -> int64: + - Removes the cast and redirect uses of int64 to int32 + - (2) other types -> int64: + - Rewrites the cast to other types -> int32 + - Supported Ops: + - torch.ops.aten.to.\[dtype|dtype_layout\] + - exir_ops.edge.dim_order_ops.\_to_dim_order_copy.default + 2. Post-process argmax outputs: + - Inserts an int64->int32 cast after the argmax operations that produce int64 outputs: + - Supported Ops: + - torch.ops.aten.argmax.default + - exir_ops.edge.aten.argmax.default + - Example usage: + - (Functionality 1) backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py + - (Functionality 2) backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py + +- InsertInt32CastsAfterInt64PlaceholdersPass + - Functionalities: + - Inserts an int64 -> int32 cast immediately after each int64 placeholder (graph input). + - Redirects all uses of each int64 placeholder to its int32 cast output. + - Inserts local int32 -> int64 casts at call sites where an operator requires int64 inputs, e.g. `torch.nn.functional.one_hot` + - Pass ordering: + - When used with `ConvertInt64ConstOpsToInt32Pass` and `ConvertInt64OutputOpsToInt32Pass`, run this pass last. + - Rationale: Those passes may cause retracing to re-infer some int64 placeholders as int32. Running this pass last casts only inputs that remain int64, minimizing inserted casts. + - Example usage: + - backends/arm/test/models/test_llama.py + - backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py + - backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py + +## Help & Improvements + +If you have problems or questions, or have suggestions for ways to improve the Arm backend, please reach out +to the Arm team developing this backend, or create an issue on [here](https://www.github.com/pytorch/executorch/issues) and add the "partner: arm" label. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/TARGETS new file mode 100644 index 0000000..6e81adf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/TARGETS @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @noautodeps +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "constants", + srcs = [ + "constants.py", + ], + deps = [ + "//executorch/exir/dialects:lib", + ], +) +runtime.python_library( + name = "common", + srcs = glob(["common/*.py"]), + deps = [ + "fbsource//third-party/tosa_tools:serializer", + "//caffe2:torch", + "//executorch/exir:lib", + ], +) + +runtime.python_library( + name = "arm_compile_spec", + srcs = [ + "common/arm_compile_spec.py", + ], + deps = [ + "fbsource//third-party/pypi/flatbuffers:flatbuffers", + "fbsource//third-party/pypi/ml-dtypes:ml-dtypes", + "fbsource//third-party/tosa_tools:serializer", + "fbsource//third-party/tosa_tools:tosa", + ":process_node", + "//executorch/exir/backend:compile_spec_schema", + "//executorch/backends/arm/operators:lib", + "//executorch/backends/arm/operators:node_visitor", + "//executorch/backends/arm/_passes:passes", + ], +) +runtime.python_library( + name = "ethosu", + srcs = [ + "ethosu/__init__.py", + "ethosu/backend.py", + "ethosu/compile_spec.py", + "ethosu/partitioner.py", + ], + deps = [ + ":arm_compile_spec", + ":arm_vela", + "//executorch/backends/arm/tosa:specification", + "//executorch/backends/arm/tosa:partitioner", + ], +) + +runtime.python_library( + name = "vgf", + srcs = [ + "vgf/__init__.py", + "vgf/backend.py", + "vgf/compile_spec.py", + "vgf/model_converter.py", + "vgf/partitioner.py", + ], + deps = [ + ":arm_compile_spec", + "//executorch/backends/arm/tosa:specification", + "//executorch/backends/arm/tosa:partitioner", + ], +) + +runtime.python_library( + name = "process_node", + srcs = ["process_node.py"], + deps = [ + "fbsource//third-party/tosa_tools:tosa", + "//executorch/backends/arm/operators:node_visitor", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm/tosa:utils", + "//executorch/exir:lib", + ], +) +runtime.python_library( + name = "arm_vela", + srcs = [ + "arm_vela.py", + ], + deps = [ + "fbsource//third-party/pypi/ethos-u-vela:ethos-u-vela", + ], +) +runtime.python_library( + name = "arm_model_evaluator", + srcs = [ + "util/arm_model_evaluator.py", + ], + deps = [ + "//caffe2:torch", + ] +) +runtime.python_library( + name = "_factory", + srcs = [ + "util/_factory.py" + ], + deps = [ + ":ethosu", + ":vgf", + ":arm_compile_spec", + "//executorch/backends/arm/quantizer:lib", + "//executorch/exir/backend:operator_support", + "//executorch/exir/backend:compile_spec_schema", + ] +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/TARGETS new file mode 100644 index 0000000..a75c63f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/TARGETS @@ -0,0 +1,19 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "passes", + srcs = glob(["*.py"]), + deps = [ + "//executorch/backends/arm:common", + "//executorch/backends/arm:constants", + "//executorch/backends/arm/tosa:utils", + "//executorch/backends/arm/tosa/dialect:lib", + "//executorch/backends/transforms:fuse_view_copy", + "//executorch/backends/transforms:remove_getitem_op", + "//executorch/backends/transforms:replace_scalar_with_tensor", + "//executorch/backends/xnnpack/_passes:xnnpack_passes", + "//executorch/exir:lib", + "//executorch/backends/transforms:utils", + "//executorch/backends/transforms:decompose_sdpa", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/__init__.py new file mode 100644 index 0000000..76e00bc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/__init__.py @@ -0,0 +1,134 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from . import arm_pass_utils # noqa +from .arm_pass import ArmPass # noqa # usort: skip +from .annotate_decomposed_matmul import AnnotateDecomposedMatmulPass # noqa +from .annotate_output_dim_order_pass import AnnotateOutputDimOrderPass # noqa +from .broadcast_args_pass import BroadcastArgsPass # noqa +from .cast_int64_pass import CastInt64BuffersToInt32Pass # noqa +from .cast_to_int32_pass import CastToInt32Pass # noqa +from .conv1d_unsqueeze_pass import Conv1dUnsqueezePass # noqa +from .convert_elu_params import ConvertELUParamsPass # noqa +from .convert_expand_copy_to_repeat import ConvertExpandCopyToRepeatPass # noqa +from .convert_full_like_to_full_pass import ConvertFullLikeToFullPass # noqa +from .convert_int64_const_ops_to_int32 import ConvertInt64ConstOpsToInt32Pass # noqa +from .convert_int64_output_ops_to_int32 import ConvertInt64OutputOpsToInt32Pass # noqa +from .convert_minmax_pass import ConvertMinMaxPass # noqa +from .convert_permute_singleton_to_view_pass import ( # noqa + ConvertPermuteSingletonToViewPass, +) +from .convert_split_to_slice import ConvertSplitToSlicePass # noqa +from .convert_squeezes_to_view import ConvertSqueezesToViewPass # noqa +from .convert_to_clamp_pass import ConvertToClampPass # noqa +from .decompose_acosh_pass import DecomposeAcoshPass # noqa +from .decompose_adaptive_avg_pool2d_pass import DecomposeAdaptiveAvgPool2dPass # noqa +from .decompose_add_sub_alpha_pass import DecomposeAddSubAlphaPass # noqa +from .decompose_addmm_pass import DecomposeAddmmPass # noqa +from .decompose_any_pass import DecomposeAnyPass # noqa +from .decompose_asin_and_acos_pass import DecomposeAsinAndAcosPass # noqa +from .decompose_asinh_pass import DecomposeAsinhPass # noqa +from .decompose_atan_pass import DecomposeAtanPass # noqa +from .decompose_atanh_pass import DecomposeAtanhPass # noqa +from .decompose_avg_pool2d_pass import DecomposeAvgPool2dPass # noqa +from .decompose_batch_norm_no_stats import DecomposeBatchNormNoStatsPass # noqa +from .decompose_cosh_pass import DecomposeCoshPass # noqa +from .decompose_cosine_similarity_pass import DecomposeCosineSimilarityPass # noqa +from .decompose_cumsum_pass import DecomposeCumsumPass # noqa +from .decompose_div_pass import DecomposeDivPass # noqa +from .decompose_div_tensor_mode import DecomposeDivTensorModePass # noqa +from .decompose_elu_pass import DecomposeEluPass # noqa +from .decompose_embedding_pass import DecomposeEmbeddingPass # noqa # noqa +from .decompose_expm1_pass import DecomposeExpm1Pass # noqa +from .decompose_floor_divide_pass import DecomposeFloorDividePass # noqa +from .decompose_gelu_pass import DecomposeGeluPass # noqa +from .decompose_glu_pass import DecomposeGluPass # noqa +from .decompose_grouped_conv_pass import DecomposeGroupedConvPass # noqa +from .decompose_groupnorm_pass import DecomposeGroupNormPass # noqa +from .decompose_int16_activation_conv_pass import ( # noqa + DecomposeConvWithInt16ActivationPass, +) +from .decompose_int_pow_pass import DecomposeIntPowPass # noqa +from .decompose_layernorm_pass import DecomposeLayerNormPass # noqa +from .decompose_leaky_relu_pass import DecomposeLeakyReLUPass # noqa +from .decompose_linalg_vector_norm_pass import DecomposeLinalgVectorNormPass # noqa +from .decompose_linear_pass import DecomposeLinearPass # noqa +from .decompose_log1p_pass import DecomposeLog1pPass # noqa +from .decompose_logit_pass import DecomposeLogitPass # noqa +from .decompose_masked_fill_pass import DecomposeMaskedFillPass # noqa +from .decompose_maxpool2d_with_dilation_pass import DecomposeMaxPool2dPass # noqa +from .decompose_meandim_pass import DecomposeMeanDimPass # noqa +from .decompose_ne_pass import DecomposeNotEqualPass # noqa +from .decompose_quant_nodes import DecomposeQuantNodesPass # noqa +from .decompose_remainder_pass import DecomposeRemainderPass # noqa +from .decompose_round_pass import DecomposeRoundPass # noqa +from .decompose_sdpa_pass import DecomposeScaledDotProductAttentionPass # noqa +from .decompose_select import DecomposeSelectPass # noqa +from .decompose_select_scatter_pass import DecomposeSelectScatterPass # noqa +from .decompose_sign_pass import DecomposeSignPass # noqa +from .decompose_silu_pass import DecomposeSiluPass # noqa +from .decompose_sinh_pass import DecomposeSinhPass # noqa +from .decompose_softmax_pass import DecomposeSoftmaxPass # noqa +from .decompose_softmax_unstable_pass import DecomposeSoftmaxUnstablePass # noqa +from .decompose_sqrt_pass import DecomposeSqrtPass # noqa +from .decompose_sum_pass import DecomposeSumPass # noqa +from .decompose_tan_pass import DecomposeTanPass # noqa +from .decompose_tosa_unsupported_clamp_pass import ( # noqa + DecomposeTOSAUnsupportedClampPass, +) +from .decompose_var_pass import DecomposeVarPass # noqa +from .decorate_fp32_to_int32_casting_pass import DecorateFp32toInt32CastingPass # noqa +from .fold_qdq_with_annotated_qparams_pass import ( # noqa + FoldAndAnnotateQParamsPass, + QuantizeClampArgumentsPass, +) +from .fuse_batch_norm2d_pass import FuseBatchNorm2dPass # noqa +from .fuse_constant_ops_pass import ( # noqa + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, +) +from .fuse_duplicate_users_pass import FuseDuplicateUsersPass # noqa +from .fuse_equal_placeholders_pass import FuseEqualPlaceholdersPass # noqa +from .fuse_quantized_activation_pass import FuseQuantizedActivationPass # noqa +from .fuse_view_copy_transform_pass import FuseViewCopyTransformPass # noqa +from .insert_int32_casts_after_int64_placeholders import ( # noqa + InsertInt32CastsAfterInt64PlaceholdersPass, +) +from .insert_rescales_pass import ( # noqa + InsertControlFlowRescalesPass, + InsertRescaleInt32Pass, + InsertRescalePass, +) +from .insert_table_ops import InsertTableOpsPass # noqa +from .match_arg_dtype_pass import MatchArgDtypePass # noqa +from .match_arg_ranks_pass import MatchArgRanksPass # noqa +from .mm_to_bmm_pass import ConvertMmToBmmPass # noqa +from .normalize_while_initial_args_pass import NormalizeWhileInitialArgsPass # noqa +from .promote_bool_operands_pass import PromoteBoolOperandsPass # noqa +from .remove_getitem_pass import RemoveGetItemPass # noqa +from .remove_graph_asserts_pass import RemoveGraphAssertsPass # noqa +from .remove_noop_pass import RemoveNoopPass # noqa +from .replace_scalar_with_tensor_pass import ( # noqa + ReplaceScalarWithTensorByProfilePass, +) +from .rewrite_bool_bitwise_not_to_logical_not_pass import ( # noqa + RewriteBoolBitwiseNotToLogicalNotPass, +) +from .rewrite_bool_to_fp32_cast_via_int8_pass import ( # noqa + RewriteBoolToFp32CastViaInt8Pass, +) +from .rewrite_conv_pass import RewriteConvPass # noqa +from .rewrite_matmul import RewriteMatmulPass # noqa +from .rewrite_upsample import RewriteUpsamplePass # noqa +from .scalars_to_attribute_pass import ScalarsToAttributePass # noqa +from .size_adjust_input_pass import SizeAdjustInputPass # noqa +from .to_tosa_memory_format_pass import ToTosaMemoryFormatPass # noqa +from .unsqueeze_before_repeat_pass import UnsqueezeBeforeRepeatPass # noqa +from .unsqueeze_scalar_placeholders_pass import UnsqueezeScalarPlaceholdersPass # noqa +from .replace_inf_and_limit_values_pass import ( # noqa # usort: skip + ReplaceInfAndLimitValuesPass, +) +from .arm_pass_manager import ArmPassManager # noqa # usort: skip diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/_debug_passes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/_debug_passes.py new file mode 100644 index 0000000..caaaec8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/_debug_passes.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import inspect +import os +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.devtools.visualization.visualization_utils import visualize_graph +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule + + +class VisualizePass(ArmPass): + """ + This pass visualizes the graph at the point of insertion in the pass manager + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram) -> None: + super().__init__() + self.exported_program = exported_program + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + visualize_graph(graph_module, self.exported_program) + return PassResult(graph_module, False) + + +class PrintGraphModuleCodePass(ArmPass): + """ + This pass prints the graph module's code to stdout for debugging purposes. + + Example output: + + [arm_pass_manager.py:305] + def forward(self, x, y): + x, y, = fx_pytree.tree_flatten_spec(([x, y], {}), self._in_spec) + remainder = torch.ops.aten.remainder.Scalar(x, 0.25); x = None + return pytree.tree_unflatten((remainder,), self._out_spec) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, label: str | None = None): + super().__init__() + caller_frame = inspect.stack()[1] + origin = f"{os.path.basename(caller_frame.filename)}:{caller_frame.lineno}" + self.label = f"[{label}]" if label is not None else f"[{origin}]" + + def call(self, graph_module: GraphModule) -> PassResult: + gm_code = graph_module.code.strip() + print(f"\n{self.label}\n{gm_code}") + return PassResult(graph_module, False) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_decomposed_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_decomposed_matmul.py new file mode 100644 index 0000000..c8be7c7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_decomposed_matmul.py @@ -0,0 +1,127 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import itertools +import operator +from typing import cast, List, Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + FoldAndAnnotateQParamsPass, +) + +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule +from torch.fx.passes.utils.source_matcher_utils import get_source_partitions + + +class AnnotateDecomposedMatmulPass(ArmPass): + """ + torch.matmul and it's equivalent operator @ can be decomposed in many ways, for instance: + dq -> matmul -> q can become + dq -> repeat -> view -> bmm -> view -> dq which makes quantization folding + difficult. This helper function find all matmul partitions and annotate its + matmul-op (can be mm or bmm). + """ + + _passes_required_after: Set[Type[ExportPass]] = {FoldAndAnnotateQParamsPass} + + def _match_partition_to_node( + self, node: torch.fx.Node, partitioned_inputs: List[torch.fx.Node] + ) -> torch.fx.Node: + """ + The partition.input_nodes order is not guaranteed. Compare these + with the matmul node inputs coming in and return the nodes + in the correct order. + """ + if not node or node in partitioned_inputs or node.op == "placeholder": + return node + else: + return self._match_partition_to_node( + node.all_input_nodes[0], partitioned_inputs + ) + raise RuntimeError(f"Cannot find an input node which matches, {node}.") + + def call(self, graph_module: GraphModule) -> PassResult: + matmul_partitions_map = get_source_partitions( + graph_module.graph, + [ + torch.matmul, + operator.matmul, + ], + None, + ) + matmul_partitions = list( + itertools.chain.from_iterable(matmul_partitions_map.values()) + ) + matmul_targets = { + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.mm.default, + } + for partition in matmul_partitions: + quantized_input = all( + input_node.target in DQ_OPS for input_node in partition.input_nodes + ) + matmul_node = [ + node for node in partition.nodes if node.target in matmul_targets + ][0] + + if quantized_input and not all( + input_node.target in DQ_OPS + for input_node in matmul_node.all_input_nodes + ): + matmul_args = matmul_node.all_input_nodes + for node in matmul_args: + # Find the dq-node connected to this mm/bmm arg + input_node = self._match_partition_to_node( + node, partition.input_nodes + ) + # Insert new dq-node just before the mm/bmm with input_node's qparams + with graph_module.graph.inserting_before(matmul_node): + # Create new dq-node before matmul + dq_node = create_node( + graph=graph_module.graph, + op_target=cast(EdgeOpOverload, input_node.target), + ) + dq_node.args = (node, *input_node.args[1:]) + matmul_node.replace_input_with(node, dq_node) + + for partition_input in partition.input_nodes: + # Remove partition input dq-node + partition_input.replace_all_uses_with( + partition_input.all_input_nodes[0] + ) + graph_module.graph.erase_node(partition_input) + + partition_output = list(partition.output_nodes[0].users)[0] + quantized_output = partition_output.target in Q_OPS + if quantized_output and not all( + user.target in Q_OPS for user in matmul_node.users + ): + with graph_module.graph.inserting_after(matmul_node): + # Create q-node after matmul + q_node = create_node( + graph=graph_module.graph, + op_target=cast(EdgeOpOverload, partition_output.target), + ) + matmul_node.replace_all_uses_with(q_node) + q_node.args = (matmul_node, *partition_output.args[1:]) + # Remove partition output q-node + partition_output.replace_all_uses_with( + partition_output.all_input_nodes[0] + ) + graph_module.graph.erase_node(partition_output) + + # retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + + graph_module.recompile() + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_output_dim_order_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_output_dim_order_pass.py new file mode 100644 index 0000000..8dc1332 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/annotate_output_dim_order_pass.py @@ -0,0 +1,26 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_output_dim_orders +from executorch.exir.pass_base import ExportPass, PassResult + + +class AnnotateOutputDimOrderPass(ArmPass): + """ + Stores the current output dim_orders in the meta dict of the output node. This is used + for verifying that the dim order does not change unexpectedly in later passes. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module): + output_node = graph_module.graph.output_node() + output_node.meta["original_dim_orders"] = get_output_dim_orders(graph_module) + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass.py new file mode 100644 index 0000000..8148204 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass.py @@ -0,0 +1,95 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import traceback +from abc import abstractmethod +from typing import Any, List, Optional, Set, Type + +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from executorch.exir.pass_base import ExportPass, NodeMetadata +from torch.fx import GraphModule +from torch.fx.passes.infra.pass_base import PassResult + + +class ArmPass(ExportPass): + """Base class for Arm passes""" + + def __init__(self, tfa_pass: bool = False, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.submodule_depth = 0 + self.is_tfa_pass = tfa_pass + + def allowed_to_transform(self, meta: NodeMetadata | dict[str, Any]) -> bool: + if not self.is_tfa_pass: + return True + + if isinstance(meta, NodeMetadata): + meta_dict = meta.data + else: + meta_dict = meta + + disallow_tfa = meta_dict.get(DISALLOW_TFA_META_KEY, False) + + return not disallow_tfa + + @property + @abstractmethod + def _passes_required_after(self) -> Set[Type[ExportPass]]: + """The subclass defines passes that must run after it""" + pass + + @staticmethod + def get_required_passes(pass_) -> List[str]: + """ + Returns the list of passes that must be run after this pass, sorted by name. + """ + if hasattr(pass_, "_passes_required_after"): + return sorted([ArmPass.get_name(p) for p in pass_._passes_required_after]) + else: + return [] + + @staticmethod + def get_name(pass_) -> str: + """ + Returns the name of the pass. + """ + if isinstance(pass_, ExportPass): + return pass_.__class__.__name__ + elif hasattr(pass_, "__name__"): + return pass_.__name__ + else: + raise ValueError( + f"Cannot get name for pass: {pass_}. It must be an instance of ExportPass or have a __name__ attribute." + ) + + def call_operator(self, op, args, kwargs, meta, updated: Optional[bool] = False): + if not updated: + return super().call_operator(op, args, kwargs, meta) + + # if updated we should update metadata + new_meta = {} + keys = meta.data.keys() + for key in keys: + new_meta[key] = meta[key] + old_stack_trace = new_meta.get("stack_trace", "") + new_meta["stack_trace"] = f"{old_stack_trace}\n{traceback.format_stack()[-2]}" + return super().call_operator(op, args, kwargs, NodeMetadata(new_meta)) + + def call_submodule( + self, graph_module: GraphModule, inputs: tuple[Any, ...] + ) -> PassResult: + self.submodule_depth += 1 + if self.submodule_depth == 1: + result = super().call_submodule(graph_module, inputs) + else: + # When we trace a submodule, we don't want to apply the calling pass. + # Temporarily replace call_operator to avoid this. + _call_operator_fn = self.call_operator + self.call_operator = super().call_operator # type: ignore + result = super().call_submodule(graph_module, inputs) + self.call_operator = _call_operator_fn # type: ignore + self.submodule_depth -= 1 + return result diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_manager.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_manager.py new file mode 100644 index 0000000..ba67f60 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_manager.py @@ -0,0 +1,462 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from collections import defaultdict +from collections.abc import Sequence + +import executorch.backends.arm.tosa.dialect # noqa: unused +from executorch.backends.arm._passes import ( + AnnotateDecomposedMatmulPass, + AnnotateOutputDimOrderPass, + BroadcastArgsPass, + CastInt64BuffersToInt32Pass, + CastToInt32Pass, + ComputeConstantOpsAOTPass, + Conv1dUnsqueezePass, + ConvertELUParamsPass, + ConvertExpandCopyToRepeatPass, + ConvertFullLikeToFullPass, + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, + ConvertMinMaxPass, + ConvertMmToBmmPass, + ConvertPermuteSingletonToViewPass, + ConvertSplitToSlicePass, + ConvertSqueezesToViewPass, + ConvertToClampPass, + DecomposeAcoshPass, + DecomposeAdaptiveAvgPool2dPass, + DecomposeAddmmPass, + DecomposeAddSubAlphaPass, + DecomposeAnyPass, + DecomposeAsinAndAcosPass, + DecomposeAsinhPass, + DecomposeAtanhPass, + DecomposeAtanPass, + DecomposeAvgPool2dPass, + DecomposeBatchNormNoStatsPass, + DecomposeConvWithInt16ActivationPass, + DecomposeCoshPass, + DecomposeCosineSimilarityPass, + DecomposeCumsumPass, + DecomposeDivPass, + DecomposeDivTensorModePass, + DecomposeEluPass, + DecomposeEmbeddingPass, + DecomposeExpm1Pass, + DecomposeFloorDividePass, + DecomposeGeluPass, + DecomposeGluPass, + DecomposeGroupedConvPass, + DecomposeGroupNormPass, + DecomposeIntPowPass, + DecomposeLayerNormPass, + DecomposeLeakyReLUPass, + DecomposeLinalgVectorNormPass, + DecomposeLinearPass, + DecomposeLog1pPass, + DecomposeLogitPass, + DecomposeMaskedFillPass, + DecomposeMaxPool2dPass, + DecomposeMeanDimPass, + DecomposeNotEqualPass, + DecomposeQuantNodesPass, + DecomposeRemainderPass, + DecomposeRoundPass, + DecomposeScaledDotProductAttentionPass, + DecomposeSelectPass, + DecomposeSelectScatterPass, + DecomposeSignPass, + DecomposeSiluPass, + DecomposeSinhPass, + DecomposeSoftmaxPass, + DecomposeSoftmaxUnstablePass, + DecomposeSqrtPass, + DecomposeSumPass, + DecomposeTanPass, + DecomposeTOSAUnsupportedClampPass, + DecomposeVarPass, + DecorateFp32toInt32CastingPass, + FoldAndAnnotateQParamsPass, + FuseBatchNorm2dPass, + FuseConstantArgsPass, + FuseDuplicateUsersPass, + FuseEqualPlaceholdersPass, + FuseQuantizedActivationPass, + FuseViewCopyTransformPass, + InsertControlFlowRescalesPass, + InsertInt32CastsAfterInt64PlaceholdersPass, + InsertRescaleInt32Pass, + InsertRescalePass, + InsertTableOpsPass, + MatchArgDtypePass, + MatchArgRanksPass, + NormalizeWhileInitialArgsPass, + PromoteBoolOperandsPass, + QuantizeClampArgumentsPass, + RemoveGetItemPass, + RemoveGraphAssertsPass, + RemoveNoopPass, + ReplaceInfAndLimitValuesPass, + ReplaceScalarWithTensorByProfilePass, + RewriteBoolBitwiseNotToLogicalNotPass, + RewriteBoolToFp32CastViaInt8Pass, + RewriteConvPass, + RewriteMatmulPass, + RewriteUpsamplePass, + ScalarsToAttributePass, + SizeAdjustInputPass, + ToTosaMemoryFormatPass, + UnsqueezeBeforeRepeatPass, + UnsqueezeScalarPlaceholdersPass, +) +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( + ArmPassPipelineConfig, + FuseDuplicateUsersConfig, + SoftmaxDecompositionConfig, +) +from executorch.backends.arm.tosa.specification import ( + tosa_spec_in_set, + TosaLoweringContext, + TosaSpecification, +) +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass +from executorch.exir.pass_manager import PassManager +from torch.fx import GraphModule +from torch.fx.passes.infra.pass_base import PassResult +from torch.nn.modules import Module + +logger = logging.getLogger(__name__) + + +class ArmPassManager(PassManager): + def __init__(self, compile_spec: ArmCompileSpec) -> None: + self.compile_spec = compile_spec + self.tosa_spec = compile_spec.tosa_spec + self._skip_pass_types: tuple[type, ...] = () + super().__init__() + self.configure_skip_passes() + + def configure_skip_passes( + self, + override_config: ArmPassPipelineConfig | None = None, + ) -> tuple[type, ...]: + """ + Configures the pass manager to skip certain passes based on the ArmPassPipelineConfig class + found in the compile spec. + """ + skip_set: set[type] = set() + + config = override_config or self.compile_spec.get_pass_pipeline_config() + logger.debug(f"Skip Config: {config}") + + match config.softmax: + case SoftmaxDecompositionConfig.MASKED: + skip_set.add(DecomposeSoftmaxUnstablePass) + case SoftmaxDecompositionConfig.UNSTABLE: + skip_set.add(DecomposeSoftmaxPass) + skip_set.add(DecomposeMaskedFillPass) + + if config.fuse_duplicate_users is FuseDuplicateUsersConfig.DISABLED: + skip_set.add(FuseDuplicateUsersPass) + + self._skip_pass_types = tuple(skip_set) + skip_names = [skipped_pass.__name__ for skipped_pass in self._skip_pass_types] + logger.debug(f"Passes in skip list: {skip_names}") + + return self._skip_pass_types + + def validate_constraints_mandatory(self): + """ + Validates that necessary passes have run before transforming to backend. + + Note that this differs from the original validate_constraints function, which + only checks the order of passes. + """ + passes_to_run = defaultdict(list) + + for current_pass in self.passes: + current_pass_name = ArmPass.get_name(current_pass) + for required_pass_name in ArmPass.get_required_passes(current_pass): + passes_to_run[required_pass_name].append(current_pass_name) + + passes_to_run.pop(current_pass_name, None) + + if len(passes_to_run) > 0: + error_msg = "The following constraints for passes are not met:\n" + for required_pass, requiring_passes in passes_to_run.items(): + for requiring_pass in requiring_passes: + error_msg += ( + f" - {required_pass} must run after {requiring_pass}\n" + ) + + raise RuntimeError(error_msg) + + def add_passes(self, passes: Sequence[ExportPass | None]): + for p in passes: + if p is not None: + self.add_pass(p) + + def _transform(self, graph_module: GraphModule): + with TosaLoweringContext(self.tosa_spec): + return self(graph_module).graph_module + + def add_pass(self, pipeline_pass): + if type(pipeline_pass) in self._skip_pass_types: + return + super().add_pass(pipeline_pass) + + def _tosa_pipeline( + self, exported_program: ExportedProgram, graph_module: GraphModule + ) -> GraphModule: + # Preprocessing passes + self.add_pass(AnnotateOutputDimOrderPass()) + + # Node transformation passes (pre q/dq folding) + self.add_passes( + [ + FuseQuantizedActivationPass(), + RewriteBoolBitwiseNotToLogicalNotPass(), + RewriteBoolToFp32CastViaInt8Pass(), + ConvertToClampPass(), + DecomposeTOSAUnsupportedClampPass(), + DecomposeGroupNormPass(), + DecomposeLayerNormPass(), + DecomposeVarPass(), + DecomposeMeanDimPass(exported_program.graph_module, self.tosa_spec), + AnnotateDecomposedMatmulPass(), + ConvertELUParamsPass(), + NormalizeWhileInitialArgsPass(use_exir_clone=True), + ] + ) + + # Fold Q/DQ nodes, insert INT8/INT32 rescales, decompose quantization nodes. + self.add_passes( + [ + FoldAndAnnotateQParamsPass(exported_program), + FuseDuplicateUsersPass(), + # TODO: DecomposeLinearPass should run after InsertRescaleInt32Pass or + # before FoldAndAnnotateQParamsPass but is unable to at the moment. + # Ticket: MLETORCH-1539 + DecomposeLinearPass(), + InsertRescaleInt32Pass(), + InsertControlFlowRescalesPass(), + DecomposeQuantNodesPass(), + ] + ) + + # Node transformation passes (post q/dq folding) + self.add_passes( + [ + ConvertSplitToSlicePass(), + QuantizeClampArgumentsPass(), + RemoveGetItemPass(), + DecomposeBatchNormNoStatsPass(), + DecomposeLogitPass(), + DecomposeMaskedFillPass(), + DecomposeRoundPass(), + DecomposeAcoshPass(), + DecomposeAsinhPass(), + DecomposeCoshPass(), + DecomposeAsinAndAcosPass(), + DecomposeSqrtPass(), + DecomposeAtanPass(), + DecomposeAtanhPass(), + DecomposeTanPass(), + DecomposeAddmmPass(), + DecomposeEluPass(), + DecomposeExpm1Pass(), + DecomposeIntPowPass(), + DecomposeLog1pPass(), + PromoteBoolOperandsPass(), + DecomposeSinhPass(), + DecomposeSignPass(), + DecomposeFloorDividePass(), + DecomposeGeluPass(), + DecomposeAddSubAlphaPass(), + DecomposeGroupedConvPass(), + Conv1dUnsqueezePass(), + ] + ) + + # Scalars -> tensors, match tensor dtypes and ranks. + self.add_passes( + [ + ReplaceScalarWithTensorByProfilePass(), + ConvertFullLikeToFullPass(), + MatchArgDtypePass(), + UnsqueezeScalarPlaceholdersPass(exported_program), + # TODO: Move DecomposeNotEqualPass to before or after this block of + # passes. Ticket: MLETORCH-1540 + DecomposeNotEqualPass(), + MatchArgRanksPass(exported_program), + ] + ) + + # Node transformation passes (post scalar-removal) + self.add_passes( + [ + DecomposeRemainderPass(), + DecomposeDivTensorModePass(), + DecomposeEmbeddingPass(), + FuseBatchNorm2dPass(exported_program), + ConvertMmToBmmPass(), + DecomposeGluPass(), + DecomposeLeakyReLUPass(), + DecomposeDivPass(), + DecomposeSoftmaxPass(), + ConvertMinMaxPass(), + DecomposeAnyPass(), + DecomposeAdaptiveAvgPool2dPass(), + DecomposeAvgPool2dPass(), + DecorateFp32toInt32CastingPass(), + ComputeConstantOpsAOTPass(exported_program), + FuseConstantArgsPass(exported_program), + ConvertExpandCopyToRepeatPass(), + UnsqueezeBeforeRepeatPass(), + DecomposeCumsumPass(exported_program), + DecomposeMaxPool2dPass(), + SizeAdjustInputPass(), + DecomposeSelectPass(), + ConvertSqueezesToViewPass(), + CastToInt32Pass(), + BroadcastArgsPass(), + ConvertPermuteSingletonToViewPass(), + FuseViewCopyTransformPass(), + DecomposeConvWithInt16ActivationPass(), + DecomposeSumPass(), + InsertTableOpsPass(exported_program), + ] + ) + + # Aten -> TOSA transformation passes + self.add_passes( + [ + RewriteUpsamplePass(), + RewriteConvPass(exported_program), + RewriteMatmulPass(), + ] + ) + + # Postprocessing/cleanup passes + self.add_passes( + [ + CastInt64BuffersToInt32Pass(exported_program), + FuseEqualPlaceholdersPass(exported_program), + ToTosaMemoryFormatPass(exported_program), + RemoveNoopPass(), + InsertRescalePass(), + ] + ) + + self.validate_constraints_mandatory() + return self._transform(graph_module) + + def transform_to_backend_pipeline( + self, exported_program: ExportedProgram, graph_module: GraphModule + ): + """Apply passes before transforming program to backend""" + + if not tosa_spec_in_set( + self.tosa_spec, + { + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + }, + ): + raise RuntimeError( + f"No pass pipeline found for TOSA specification: {self.tosa_spec}" + ) + + return self._tosa_pipeline(exported_program, graph_module) + + def transform_for_annotation_pipeline(self, graph_module: GraphModule): + # Preprocessing passes + self.add_pass(RemoveGraphAssertsPass(tfa_pass=True)) + + # Transformation passes (pre scalar -> tensor) + self.add_passes( + [ + DecomposeSelectScatterPass(tfa_pass=True), + ConvertInt64ConstOpsToInt32Pass(tfa_pass=True), + ConvertInt64OutputOpsToInt32Pass(tfa_pass=True), + InsertInt32CastsAfterInt64PlaceholdersPass(tfa_pass=True), + DecomposeEmbeddingPass(tfa_pass=True), + DecomposeScaledDotProductAttentionPass(tfa_pass=True), + DecomposeRoundPass(tfa_pass=True), + DecomposeLogitPass(tfa_pass=True), + PromoteBoolOperandsPass(tfa_pass=True), + DecomposeSignPass(tfa_pass=True), + DecomposeAddmmPass(tfa_pass=True), + DecomposeRemainderPass(tfa_pass=True), + DecomposeFloorDividePass(tfa_pass=True), + DecomposeDivTensorModePass(tfa_pass=True), + ] + ) + + # Scalars -> tensors + self.add_passes( + [ + ReplaceScalarWithTensorByProfilePass(tfa_pass=True), + ScalarsToAttributePass(tfa_pass=True), + ] + ) + + # Transformation passes (post scalar removal) + self.add_passes( + [ + NormalizeWhileInitialArgsPass(use_exir_clone=False, tfa_pass=True), + DecomposeAddSubAlphaPass(tfa_pass=True), + DecomposeGroupNormPass(tfa_pass=True), + DecomposeLayerNormPass(tfa_pass=True), + DecomposeVarPass(tfa_pass=True), + DecomposeMeanDimPass(graph_module, self.tosa_spec, tfa_pass=True), + DecomposeNotEqualPass(tfa_pass=True), + DecomposeCosineSimilarityPass(tfa_pass=True), + DecomposeGluPass(tfa_pass=True), + DecomposeDivPass(tfa_pass=True), + DecomposeLeakyReLUPass(tfa_pass=True), + DecomposeLinalgVectorNormPass(tfa_pass=True), + DecomposeSqrtPass(tfa_pass=True), + DecomposeSiluPass(tfa_pass=True), + DecomposeAvgPool2dPass(tfa_pass=True), + DecomposeSoftmaxUnstablePass(tfa_pass=True), + DecomposeSoftmaxPass(tfa_pass=True), + ConvertMinMaxPass(tfa_pass=True), + ] + ) + + # Postprocessing passes + self.add_passes( + [ + ReplaceInfAndLimitValuesPass(tfa_pass=True), + DecomposeMaskedFillPass(tfa_pass=True), + ] + ) + + return self._transform(graph_module) + + def __call__(self, module: Module) -> PassResult: + try: + return super().__call__(module) + except Exception as e: + first_exception = e.__cause__ or e.__context__ or e + import re + + message = e.args[0] + m = re.search(r"An error occurred when running the '([^']+)' pass", message) + if m: + pass_name = m.group(1) + first_exception.args = ( + f"{pass_name}: {first_exception.args[0]}", + *first_exception.args[1:], + ) + raise first_exception diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_utils.py new file mode 100644 index 0000000..006d4ff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/arm_pass_utils.py @@ -0,0 +1,281 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import traceback +from inspect import isclass +from typing import Optional, Sequence + +import torch +import torch.fx +from executorch.backends.arm.common.debug import get_node_debug_info +from executorch.backends.arm.common.type import ensure_type +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload + +from torch._export.utils import ( + get_buffer, + get_lifted_tensor_constant, + get_param, + is_buffer, + is_lifted_tensor_constant, + is_param, +) +from torch._ops import OpOverload +from torch._subclasses.fake_tensor import FakeTensor +from torch.export.graph_signature import InputKind + + +def is_submodule_node(node: torch.fx.Node): + if node.op not in ("get_attr", "placeholder"): + return False + try: + node.graph.owning_module.get_submodule(node.target) + except AttributeError: + return False + return True + + +def is_get_attr_node(node: torch.fx.Node) -> bool: + """ + Returns true if the given node is a get attr node for a tensor of the model. + """ + return ( + isinstance(node, torch.fx.Node) + and node.op == "get_attr" + and not is_submodule_node(node) + ) + + +def is_param_node(exp_prog: ExportedProgram, node: torch.fx.Node) -> bool: + return ( + is_get_attr_node(node) + or is_param(exp_prog, node) + or is_buffer(exp_prog, node) + or is_lifted_tensor_constant(exp_prog, node) + ) + + +def get_constant_placeholder_kind( + exp_prog: ExportedProgram, node: torch.fx.Node +) -> InputKind: + if is_param(exp_prog, node): + return InputKind.PARAMETER + if is_buffer(exp_prog, node): + return InputKind.BUFFER + if is_lifted_tensor_constant(exp_prog, node): + return InputKind.CONSTANT_TENSOR + + raise RuntimeError("Node is neither PARAMETER, BUFFER nor CONSTANT_TENSOR") + + +def is_persistent_buffer(exp_prog: ExportedProgram, node: torch.fx.Node) -> bool | None: + if is_buffer(exp_prog, node): + buffer_name = exp_prog.graph_signature.inputs_to_buffers[node.name] + if buffer_name in exp_prog.graph_signature.non_persistent_buffers: + return False + else: + return True + + return None + + +def get_param_tensor( + exp_prog: ExportedProgram, node: torch.fx.Node +) -> Optional[torch.Tensor]: + if node is None: + return None + elif is_param(exp_prog, node): + return get_param(exp_prog, node) + elif is_buffer(exp_prog, node): + return get_buffer(exp_prog, node) + elif is_lifted_tensor_constant(exp_prog, node): + return get_lifted_tensor_constant(exp_prog, node) + elif is_get_attr_node(node): + target_node = ensure_type(str, node.target) + # This is a hack to support both lifted and unlifted graph + try: + return getattr(node.graph.owning_module, target_node) + except AttributeError: + return getattr(exp_prog.graph_module, target_node) + raise RuntimeError(f"unsupported param type, {node.op}.") + + +def expand_around_channel(param: Sequence[int] | int, spatial_rank: int) -> list[int]: + """ + Expand a scalar or 1-D parameter around the channel dimension into a broadcastable + shape while preserving the channel location. + """ + if isinstance(param, int): + return [param] * spatial_rank + + param_list = list(param) + if len(param_list) == 1 and spatial_rank > 1: + param_list = param_list * spatial_rank + return param_list + + +def create_node( + graph: torch.fx.Graph, + op_target: OpOverload | EdgeOpOverload, + args: tuple = (), + kwargs: Optional[dict] = None, + quantize: bool = False, + q_params: Optional[tuple] = None, + from_node: Optional[torch.fx.Node] = None, + inherit_qparams: bool = False, +): + """ + Adds a node to 'graph'. graph.inserting_before/after() should be used before the call to decide where to insert the node. + If quantize is true and q_params is not None, a q dq pair is inserted after the newly created node. + """ + + node = graph.create_node( + "call_function", + op_target, + args=args, + kwargs=kwargs or {}, + ) + + new_meta = {} + if from_node: + keys = from_node.meta.keys() + for key in keys: + new_meta[key] = from_node.meta[key] + if not inherit_qparams: + if "input_qparams" in new_meta: + new_meta["input_qparams"] = {} + if "output_qparams" in new_meta: + new_meta["output_qparams"] = {} + elif inherit_qparams: + raise ValueError("inherit_qparams is only valid when from_node is given") + + old_stack_trace = new_meta.get("stack_trace", "") + new_meta["stack_trace"] = f"{old_stack_trace}\n{traceback.format_stack()[-2]}" + node.meta = new_meta + + if quantize and q_params: + return insert_q_dq_pair(graph, node, q_params, from_node) + return node + + +def insert_q_dq_pair( + graph: torch.fx.Graph, + anchor: torch.fx.Node, + q_params: tuple, + from_node: Optional[torch.fx.Node] = None, +): + """ + Inserts a q dq node pair after the node 'anchor'. + """ + + with graph.inserting_after(anchor): + q = create_node( + graph=graph, + op_target=exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + args=(), # We add the argument last + from_node=from_node if from_node else anchor, + ) + q.meta = anchor.meta + with graph.inserting_after(q): + dq = create_node( + graph=graph, + op_target=exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + args=(q,) + q_params, + from_node=from_node if from_node else anchor, + ) + dq.meta = q.meta + anchor.replace_all_uses_with(dq) + # We add this last so the replace all uses above does not replace the quantized + # node's first use + q.args = (anchor,) + q_params + return dq + + +def get_first_fake_tensor(node: torch.fx.Node) -> FakeTensor: + """ + Returns a FakeTensor from the meta field of 'node'. + If the node contains many fake tensors, return the first one. + """ + if isinstance( + node.meta["val"], (Sequence, torch.fx.immutable_collections.immutable_list) + ): + fake_tensor = node.meta["val"][0] + else: + fake_tensor = node.meta["val"] + + if not isinstance(fake_tensor, FakeTensor): + raise TypeError( + f'Expected a FakeTensor in meta["val"] of node {node}, but got ' + f"{type(fake_tensor).__name__}\n" + f"{get_node_debug_info(node)}" + ) + + return fake_tensor + + +def get_node_arg(args: list | dict, key: int | str | type, default_value=None): + """ + Help-function for getting a value from node.args/ kwargs, three cases: + 1. By position in node.args - Returns arg at given position or default_value if index is one out of bounds + 2. By key in node.kwargs - Returns kwarg with given key or default_value if it deos not exist + 3. By type in node.args - Returns first arg of args of given type. Useful for cases where arg postions may differ but types are unique. + """ + if isinstance(key, int): + if 0 <= key < len(args): + return args[key] + elif key == len(args): + if default_value is not None: + return default_value + else: + raise RuntimeError(f"No defult value given for index {key}") + else: + raise RuntimeError( + f"Out of bounds index {key} for getting value in args (of size {len(args)})" + ) + elif isinstance(key, str): + return args.get(key, default_value) # type: ignore[union-attr] + elif isclass(key): + for arg in args: + if isinstance(arg, key): + return arg + if default_value is not None: + return default_value + else: + raise RuntimeError(f"No arg of type {key}") + else: + raise RuntimeError("Invalid type") + + +def set_node_arg(node: torch.fx.Node, i: int | str, value): + """ + Help-function for setting a value in node.args/ kwargs. If the index is one larger than the list size, the value is instead appended to the list. + """ + if isinstance(i, int): + if 0 <= i < len(node.args): + args = list(node.args) + args[i] = value + node.args = tuple(args) + return + elif i == len(node.args): + node.args = node.args + (value,) + else: + raise RuntimeError( + f"Out of bounds index {i} for setting value in {node} args (of size {len(node.args)})" + ) + elif isinstance(i, str): + kwargs = dict(node.kwargs) + kwargs[i] = value + node.kwargs = kwargs + else: + raise RuntimeError("Invalid type") + + +def get_output_dim_orders(graph_module): + output_node = graph_module.graph.output_node() + return [get_first_fake_tensor(node).dim_order() for node in output_node.args[0]] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/broadcast_args_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/broadcast_args_pass.py new file mode 100644 index 0000000..d11fb77 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/broadcast_args_pass.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm.tosa.specification import get_context_spec + +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +class BroadcastArgsPass(ArmPass): + """ + Pass to manually broadcast arguments by inserting repeats. + This is done when more than one arg needs broadcasting. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = { + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + # mul is indirectly targeting div as div is decompsed to reciprocal + mul + exir_ops.edge.aten.mul.Tensor, + } + + def call(self, graph_module: GraphModule) -> PassResult: + tosa_spec = get_context_spec() + if not tosa_spec.is_U55_subset: + return PassResult(graph_module, False) + for node in graph_module.graph.nodes: + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + output_shape = get_first_fake_tensor(node).shape + nbr_of_broacasts = 0 + for arg in node.args: + if not isinstance(arg, Node): + continue + + shape = get_first_fake_tensor(arg).shape + if shape != output_shape: + nbr_of_broacasts += 1 + if nbr_of_broacasts > 1: + multiples = [ + int(output_shape[d] / shape[d]) + for d in range(len(output_shape)) + ] + with graph_module.graph.inserting_before(node): + repeat = create_node( + graph_module.graph, + exir_ops.edge.aten.repeat.default, + args=(arg, multiples), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + node.replace_input_with(arg, repeat) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_int64_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_int64_pass.py new file mode 100644 index 0000000..535da39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_int64_pass.py @@ -0,0 +1,70 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.pass_base import ExportPass, PassResult +from torch._export.utils import is_buffer +from torch.export import ExportedProgram + +logger = logging.getLogger(__name__) + + +class CastInt64BuffersToInt32Pass(ArmPass): + """ + Cast int64 buffers to int32 if the int64 data is in int32 range. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def _assert_within_int32(self, tensor: torch.Tensor, node: torch.fx.Node): + if torch.min(tensor) < torch.iinfo(torch.int32).min: + raise RuntimeError( + f"Node {node.name} has value < {torch.iinfo(torch.int32).min}" + ) + if torch.max(tensor) > torch.iinfo(torch.int32).max: + raise RuntimeError( + f"Node {node.name} has value > {torch.iinfo(torch.int32).max}" + ) + + def _to_int32(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if len(node.users) == 0: + continue + if "val" not in node.meta: + continue + fake_tensor = node.meta["val"] + if not isinstance(fake_tensor, torch._subclasses.fake_tensor.FakeTensor): + continue + if fake_tensor.dtype != torch.int64: + continue + if is_buffer(self.exported_program, node): + node.meta["val"] = fake_tensor.to(torch.int32) + buffer_name = self.exported_program.graph_signature.inputs_to_buffers[ + node.name + ] + buffer = self.exported_program.state_dict[buffer_name] + self._assert_within_int32(buffer, node) + logger.warning( + f"Casting buffer {node.name} from torch.int64 to torch.int32" + f" defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + buffer_int32 = buffer.to(torch.int32) + self.exported_program.state_dict[buffer_name] = buffer_int32 + continue + + def call(self, graph_module: torch.fx.GraphModule): + self._to_int32(graph_module) + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_to_int32_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_to_int32_pass.py new file mode 100644 index 0000000..40f7e34 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/cast_to_int32_pass.py @@ -0,0 +1,67 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass + +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class CastToInt32Pass(ArmPass): + """Casts the input to int32 if it is not already and casts back the output to the original input dtype.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = { + exir_ops.edge.aten.bitwise_left_shift.Tensor, + exir_ops.edge.aten.bitwise_right_shift.Tensor, + } + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + tosa_spec = get_context_spec() + if not tosa_spec.is_U55_subset: + return PassResult(graph_module, False) + return super().call(graph_module) + + def call_operator(self, op, args, kwargs, meta): + if op not in self.targeted_ops: + return super().call_operator(op, args, kwargs, meta) + + new_args: list = [] + did_cast = False + for arg in args: + if arg.data.dtype != torch.int32: + new_args.append( + super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (arg,), + {"dtype": torch.int32}, + meta, + ) + ) + did_cast = True + else: + new_args.append(arg) + + output = super().call_operator( + op, + tuple(new_args), + {}, + meta, + ) + + if did_cast: + output = super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (output,), + {"dtype": args[0].data.dtype}, + meta, + ) + return output diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/conv1d_unsqueeze_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/conv1d_unsqueeze_pass.py new file mode 100644 index 0000000..f0b1026 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/conv1d_unsqueeze_pass.py @@ -0,0 +1,98 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class Conv1dUnsqueezePass(ArmPass): + """ + This pass is used to change conv1d ops into conv2d since TOSA only + supports 2d and 3d convolution. This is done by modifying the graph to do the + following: + 1a) unsqueeze the convolution's input from 3d to 4d + 1b) unsqueeze the convolution's weight from 3d to 4d + 2) perform a conv2d (with a modified version of the original conv1d args) + 3) squeeze the output back down to 3d. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + RewriteConvPass, + SizeAdjustInputPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op != exir_ops.edge.aten.convolution.default: + return super().call_operator(op, args, kwargs, meta) + stride = list(args[3]) + if len(stride) != 1: + return super().call_operator(op, args, kwargs, meta) + + x_meta = meta.copy() + x_meta.data["input_qparams"] = {} + x_meta.data["output_qparams"] = {} + + x = args[0] + x_unsqueezed_shape = list(x.data.shape) + [1] + x = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x, x_unsqueezed_shape), + {}, + x_meta, + updated=True, + ) + + w_meta = meta.copy() + w_meta.data["input_qparams"] = {} + w_meta.data["output_qparams"] = {} + + w = args[1] + w_unsqueezed_shape = list(w.data.shape) + [1] + w = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (w, w_unsqueezed_shape), + {}, + w_meta, + updated=True, + ) + + new_args = ( + x, + w, + args[2], + args[3] + [1], # stride + args[4] + [0], # padding + args[5] + [1], # dilation + args[6], + args[7] + [0], + args[8], + ) + x = super().call_operator( + exir_ops.edge.aten.convolution.default, new_args, kwargs, meta, updated=True + ) + + x_squeezed_meta = meta.copy() + x_squeezed_meta.data["input_qparams"] = {} + x_squeezed_meta.data["output_qparams"] = {} + x_squeezed_shape = list(x.data.shape)[:-1] + x = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x, x_squeezed_shape), + {}, + x_squeezed_meta, + updated=True, + ) + + return x diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_elu_params.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_elu_params.py new file mode 100644 index 0000000..10c6a28 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_elu_params.py @@ -0,0 +1,67 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm.constants import DQ_OPS +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class ConvertELUParamsPass(ArmPass): + """ + Pass to convert the input_scale kwarg of ELU operator from float to + int. + + It has been set to 2 as the outputs seem to stay the same regardless of what + the value of input_scale is, as long as that value is not 1. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + graph = graph_module.graph + node_list = graph.find_nodes( + op="call_function", target=exir_ops.edge.aten.elu.default + ) + for node in node_list: + input_node = node.all_input_nodes[0] + is_quantized = ( + input_node.op == "call_function" and input_node.target in DQ_OPS + ) + if not is_quantized or not self.allowed_to_transform(node.meta): + continue + with graph.inserting_after(node): + replace_node = create_node( + graph, exir_ops.edge.aten.elu.default, from_node=node + ) + old_args = list(node.args) + + alpha = old_args[1] if len(old_args) > 1 else 1.0 + scale = 1.0 + input_scale = 2.0 + + replace_node.args = (old_args[0],) + + updated_kwargs = dict(node.kwargs) + updated_kwargs["alpha"] = int(alpha) + updated_kwargs["scale"] = int(scale) + updated_kwargs["input_scale"] = int(input_scale) + + replace_node.kwargs = updated_kwargs + + node.replace_all_uses_with(replace_node) + graph.erase_node(node) + + modified_graph = True + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_expand_copy_to_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_expand_copy_to_repeat.py new file mode 100644 index 0000000..0cd3060 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_expand_copy_to_repeat.py @@ -0,0 +1,77 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import cast, Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.unsqueeze_before_repeat_pass import ( + UnsqueezeBeforeRepeatPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +logger = logging.getLogger(__name__) + + +def calculate_multiples(args): + """Returns expand args converted to repeat args, and whether the expand changes the rank""" + input_node_or_tensor = args[0] + + if isinstance(input_node_or_tensor, torch.fx.node.Node): + input_data = input_node_or_tensor.meta["val"] + else: + input_data = input_node_or_tensor.data + + input_shape = input_data.shape + + multiples = cast(list[int], args[1]) + expanded_rank = len(multiples) + + # Expanded shape is 'input_shape' front-padded with ones. + padding = expanded_rank - len(input_shape) + extended_shape = [ + input_shape[i] if i >= 0 else 1 for i in range(-padding, len(input_shape)) + ] + + # To convert expand arg to repeat arg, non-repeated dims should have + # multiples[dim] = 1. Passing -1 to expand arg means + # not changing the size of that dimension. + multiples = [ + multiples[i] if multiples[i] != -1 and extended_shape[i] == 1 else 1 + for i in range(expanded_rank) + ] + return multiples, expanded_rank != len(input_shape) + + +class ConvertExpandCopyToRepeatPass(ArmPass): + """ + Replace expand copy with repeat since it is a repeat that can only repeat singleton dimensions. + """ + + _passes_required_after: Set[Type[ExportPass]] = {UnsqueezeBeforeRepeatPass} + + expand_copy = exir_ops.edge.aten.expand_copy.default + repeat = exir_ops.edge.aten.repeat.default + + def call_operator(self, op, args, kwargs, meta): + if op != self.expand_copy: + return super().call_operator(op, args, kwargs, meta) + + multiples, changes_rank = calculate_multiples(args) + + if all((x == 1 for x in multiples)) and not changes_rank: + # All dimensions/repetitions occur only once. Remove node + # altogether since it's in practice just a copy. + logger.warning("Found redundant expand node (no-op). Removing it.") + + return args[0] + + return super().call_operator( + op=self.repeat, args=(args[0], multiples), kwargs=kwargs, meta=meta + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_full_like_to_full_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_full_like_to_full_pass.py new file mode 100644 index 0000000..becb0b7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_full_like_to_full_pass.py @@ -0,0 +1,42 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class ConvertFullLikeToFullPass(ArmPass): + """As per the full_like pytorch documentation, + `torch.full_like(input, fill_value)` is equivalent to + `torch.full(input.size(), + fill_value, + dtype=input.dtype, + layout=input.layout, + device=input.device + )` + Skip layout and device since it's not relevant for our backend. + """ + + _passes_required_after: Set[Type[ExportPass]] = {ComputeConstantOpsAOTPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in [ + exir_ops.edge.aten.full_like.default, + ]: + return super().call_operator(op, args, kwargs, meta) + + tensor = args[0].data + full_args = (list(tensor.shape), args[1]) + full_kwargs = {"dtype": tensor.dtype} + return super().call_operator( + exir_ops.edge.aten.full.default, full_args, full_kwargs, meta + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_const_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_const_ops_to_int32.py new file mode 100644 index 0000000..85fcf71 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_const_ops_to_int32.py @@ -0,0 +1,81 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.exir.pass_base import ExportPass, PassResult + + +logger = logging.getLogger(__name__) +INT32_MIN = torch.iinfo(torch.int32).min +INT32_MAX = torch.iinfo(torch.int32).max + + +class ConvertInt64ConstOpsToInt32Pass(ArmPass): + """ + Rewrite constant ops that produce int64 to int32 where safe. + + List of supported operatos: + 1. `torch.full` + 2. `torch.arange` + 3. `torch.eye` + 4. `torch.linspace` + 5. `torch.tensor` + """ + + _passes_required_after: Set[Type[ExportPass]] = {ComputeConstantOpsAOTPass} + + torch_ops = [ + torch.ops.aten.full.default, + torch.ops.aten.arange.default, + torch.ops.aten.arange.start, + torch.ops.aten.arange.start_step, + torch.ops.aten.eye.default, + torch.ops.aten.linspace.default, + ] + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + + if ( + node.target + not in ComputeConstantOpsAOTPass.targeted_ops + self.torch_ops + ): + continue + + data = node.target(*node.args, **node.kwargs) + if data.dtype is not torch.int64: + continue + + min_val, max_val = torch.min(data), torch.max(data) + if INT32_MIN <= min_val and max_val <= INT32_MAX: + logger.warning( + f"Casting {node.name} from torch.int64 to torch.int32" + f" defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + node.update_kwarg("dtype", torch.int32) + modified = True + else: + logger.warning( + f"[{node.name}] has values: min={min_val}, max={max_val}, which exceeds int32 range " + f"([{INT32_MIN}, {INT32_MAX}]); not converting dtype to int32." + ) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_output_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_output_ops_to_int32.py new file mode 100644 index 0000000..0482191 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_int64_output_ops_to_int32.py @@ -0,0 +1,155 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, + set_node_arg, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +logger = logging.getLogger(__name__) + + +class ConvertInt64OutputOpsToInt32Pass(ArmPass): + """ + Rewrites or removes operations that produce int64 outputs, converting them + to int32 where possible. + + + Currently, this pass handles casting and argmax operators: + 1. int32 -> int64: + removes the cast and redirects all uses to the original int32 value. + 2. other types -> int64: + rewrites the cast to produce int32 instead of int64. + 3. torch.argmax() + insert an int64->int32 cast after the argmax node + + Future extensions may include operators that return int64 outputs by default + (e.g., `argmin`), rewriting them or inserting an int64 -> int32 cast to yield + int32 results. + + Note: Overflow checks are applied selectively in this pass. For operators without + such checks, it is the user's responsibility to ensure that values fit within + the int32 range. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + aten_cast_ops = ( + torch.ops.aten.to.dtype, + torch.ops.aten.to.dtype_layout, + ) + edge_cast_ops = (exir_ops.edge.dim_order_ops._to_dim_order_copy.default,) + + aten_argmax_ops = (torch.ops.aten.argmax.default,) + edge_argmax_ops = (exir_ops.edge.aten.argmax.default,) + + aten_ops = aten_cast_ops + aten_argmax_ops + edge_ops = edge_cast_ops + edge_argmax_ops + + # dtype is specified in args + cast_ops_args = ( + torch.ops.aten.to.dtype, # to_2: node.args: (gt, torch.int64) node.kwargs: {} + ) + # dtype is specified in kwargs + cast_ops_kwargs = ( + torch.ops.aten.to.dtype_layout, # to_1: node.args: (unsqueeze,) node.kwargs: {'dtype': torch.int64, 'layout': torch.strided, 'device': device(type='cpu')} + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, # node.args: (aten_gt_scalar,) node.kwargs: {'dtype': torch.int64, 'dim_order': [0, 1]} + ) + + def _get_decomposition(self, op): + if op in self.edge_ops: + return exir_ops.edge.dim_order_ops._to_dim_order_copy.default + + if op in self.aten_ops: + return torch.ops.dim_order_ops._to_dim_order_copy.default + + raise RuntimeError( + f"[{self.__class__.__name__}] Can't get decomposition for op {op}" + ) + + def _convert_casting_operators(self, node: torch.fx.Node): + input_node = node.all_input_nodes[0] + input_dtype = get_first_fake_tensor(input_node).dtype + # Case 1: int32 -> int64 - removes the ops + if input_dtype == torch.int32: + users = [user for user in node.users if node != user] + for user in users: + logger.warning( + f"Removing int32->int64 casting node {node.name} defined in" + f" {node.meta.get('stack_trace','[no stack trace found]')}" + ) + user.replace_input_with(node, input_node) + # Case 2: other types -> int64 - rewrites to cast to int32 + else: + if node.target in self.cast_ops_kwargs: + set_node_arg(node, "dtype", torch.int32) + elif node.target in self.cast_ops_args: + set_node_arg(node, 1, torch.int32) + else: + raise RuntimeError(f"Unexpected target {node.target} in {node.name}") + output_dtype = get_first_fake_tensor(node).dtype + logger.warning( + f"Converting casting node {node.name} from {input_dtype}->{output_dtype} to" + f" {input_dtype}->torch.int32 defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + + def _convert_argmax_operators(self, node: torch.fx.Node, graph: torch.fx.Graph): + output_tensor = node + to_copy_op = self._get_decomposition(node.target) + with graph.inserting_after(node): + cast_after = create_node( + graph, + to_copy_op, + args=(output_tensor,), + kwargs={ + "dtype": torch.int32, + }, + ) + users = [user for user in node.users if user != cast_after] + for user in users: + user.replace_input_with(output_tensor, cast_after) + logger.warning( + f"Inserting a casting node {cast_after.name} after {node.name} to cast int64 output" + f" to int32 for {node.name} defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + graph = graph_module.graph + for node in list(graph.nodes): + if node.op != "call_function": + continue + if node.target not in self.aten_ops + self.edge_ops: + continue + output_dtype = get_first_fake_tensor(node).dtype + if output_dtype != torch.int64: + continue + + if node.target in self.aten_cast_ops + self.edge_cast_ops: + self._convert_casting_operators(node) + elif node.target in self.aten_argmax_ops + self.edge_argmax_ops: + # TODO: Add range check based on the input tensor shape before casting the output + self._convert_argmax_operators(node, graph) + else: + raise RuntimeError(f"Unexpected target {node.target} in {node.name}") + + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_minmax_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_minmax_pass.py new file mode 100644 index 0000000..caedbbf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_minmax_pass.py @@ -0,0 +1,166 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.convert_squeezes_to_view import ( + ConvertSqueezesToViewPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class ConvertMinMaxPass(ArmPass): + """ + Converts min/max to amin/amax and unrolls multi-dimensional reduction and keep-dims arg to be + TOSA compliant. + + The difference between max/min and amax/amin is (from pytorch docs): + - amax/amin supports reducing on multiple dimensions, + - amax/amin does not return indices, + - amax/amin evenly distributes gradient between equal values, while max(dim)/min(dim) + propagates gradient only to a single index in the source tensor. + Since we do not care about gradients post training, convert min/max ops to amin/amax as long as + the indices are not used. + + Original: + amax([dim1, dim2], keepdim = False) + After pass: + amax(dim1, keepdim = True) + amax(dim2, keepdim = True) + squeeze(dim = [dim1, dim2]) + """ + + _passes_required_after: Set[Type[ExportPass]] = {ConvertSqueezesToViewPass} + + _TARGET_OPS = { + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + exir_ops.edge.aten.max.dim, + exir_ops.edge.aten.min.dim, + torch.ops.aten.max.dim, + torch.ops.aten.min.dim, + } + + def check_argmax(self, node): + """ + Raises a RuntimeError if the argmax value returned by the min/max op is used in the graph. + """ + if node.target in [torch.ops.aten.max.dim, torch.ops.aten.min.dim]: + no_argmax = len(node.users) == 1 + no_argmax_users = (len(node.users) == 2) and ( + len(list(node.users)[1].users) == 0 + ) + if not (no_argmax or no_argmax_users): + raise RuntimeError("Argmax is not supported by the arm_quantizer") + + def get_variables(self, node): + """Returns variables specific for each op handled by the pass.""" + if node.target in [ + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + ]: + replace_node = node + op = node.target + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + elif node.target == exir_ops.edge.aten.max.dim: + replace_node = list(node.users)[0] + op = exir_ops.edge.aten.amax.default + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + elif node.target == exir_ops.edge.aten.min.dim: + replace_node = list(node.users)[0] + op = exir_ops.edge.aten.amin.default + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + elif node.target == torch.ops.aten.max.dim: + replace_node = list(node.users)[0] + op = torch.ops.aten.amax.default + squeeze_op = torch.ops.aten.squeeze.dims + elif node.target == torch.ops.aten.min.dim: + replace_node = list(node.users)[0] + op = torch.ops.aten.amin.default + squeeze_op = torch.ops.aten.squeeze.dims + else: + raise RuntimeError( + f"{node.name} is not an accepted target for ConvertMinMaxPass()" + ) + + return (replace_node, op, squeeze_op) + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in ConvertMinMaxPass._TARGET_OPS + or not self.allowed_to_transform(node.meta) + ): + continue + + self.check_argmax( + node + ) # TODO: MLETORCH-718 : Quantization of indices in arm_quantizer + replace_node, op, squeeze_op = self.get_variables(node) + + # Unwrap args + if len(node.args) == 1: + # If dims is unspecified, min/max over all dims. + input_node = cast(torch.fx.Node, node.args[0]) + input_shape = get_first_fake_tensor(input_node).shape + dims = range(len(input_shape)) + keepdims = False + elif len(node.args) == 2: + input_node, dims = node.args + keepdims = False + elif len(node.args) == 3: + input_node, dims, keepdims = node.args + else: + raise RuntimeError( + f"Unexpected arg size {len(node.args)} in {node.name}" + ) + + try: + iter(dims) # type:ignore[assignment] + except Exception: + dims = [dims] # type:ignore[assignment] + else: + dims = list(dims) # type:ignore[assignment] + + # Unroll multi-dimensional reduction and keep-dims arg + with graph_module.graph.inserting_before(node): + + for dim in dims: + args = (input_node, dim, True) + input_node = create_node( + graph=graph_module.graph, + op_target=op, + args=args, + kwargs={}, + from_node=node, + ) + + if not keepdims: + input_node = create_node( + graph=graph_module.graph, + op_target=squeeze_op, + args=(input_node, dims), + kwargs={}, + from_node=node, + ) + + replace_node.replace_all_uses_with(input_node) + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_permute_singleton_to_view_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_permute_singleton_to_view_pass.py new file mode 100644 index 0000000..fe4697b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_permute_singleton_to_view_pass.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Sequence, Set, Tuple, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +from torch._ops import OpOverload + + +_PERMUTE_TARGETS: Tuple[OpOverload, ...] = ( + exir_ops.edge.aten.permute.default, + exir_ops.edge.aten.permute_copy.default, +) + + +class ConvertPermuteSingletonToViewPass(ArmPass): + """Replace permutations that only move singleton axes with a reshape. + + Examples: + x = rand(1,1,1,4) + y = permute(x, (0,3,1,2)) + + becomes: + x = rand(1,1,1,4) + y = view_copy(x, (1,4,1,1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in _PERMUTE_TARGETS: + return super().call_operator(op, args, kwargs, meta) + + input_tensor = args[0].data + permutation = args[1] + if not is_singleton_permutation(input_tensor.shape, permutation): + return super().call_operator(op, args, kwargs, meta) + + output_shape = meta["val"].shape + view_args = (args[0], output_shape) + return super().call_operator( + exir_ops.edge.aten.view_copy.default, view_args, kwargs, meta + ) + + +def is_singleton_permutation(shape: Sequence[int], permutation: Sequence[int]) -> bool: + """ + Treat as a view only when non-singleton axes keep their order; singleton + axes may move freely since they carry no data volume. + """ + rank = len(shape) + normalized_perm = [d % rank for d in permutation] + + non_singleton_axes = [i for i, size in enumerate(shape) if size != 1] + permuted_non_singleton_axes = [axis for axis in normalized_perm if shape[axis] != 1] + + return permuted_non_singleton_axes == non_singleton_axes diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_split_to_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_split_to_slice.py new file mode 100644 index 0000000..5006c30 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_split_to_slice.py @@ -0,0 +1,132 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch.fx +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class ConvertSplitToSlicePass(ArmPass): + """ + Replace a split operation with many slice operations. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + split_ops = ( + exir_ops.edge.aten.split_with_sizes_copy.default, + exir_ops.edge.aten.split_copy.Tensor, + ) + slice = exir_ops.edge.aten.slice_copy.Tensor + + def call(self, graph_module: torch.fx.GraphModule): + graph = graph_module.graph + for node in graph.nodes: + if node.target not in self.split_ops: + continue + + # Get useful variables + split_node = node + input_node = split_node.all_input_nodes[0] + output_nodes = split_node.users.copy() + shape = get_first_fake_tensor(input_node).shape + rank = len(shape) + split_lengths = split_node.args[1] + dim = split_node.args[2] if len(split_node.args) > 2 else 0 + dim = (dim + rank) % rank + + # Validate that split lengths cover the entire dimension + + dim_size = shape[dim] + if isinstance(split_lengths, int): + if split_lengths <= 0: + raise ValueError( + f"Split size must be positive, got {split_lengths}" + ) + full_chunks, remainder = divmod(dim_size, split_lengths) + split_lengths = [split_lengths] * full_chunks + if remainder: + split_lengths.append(remainder) + else: + length_sum = sum(split_lengths) + if length_sum != dim_size: + raise ValueError( + f"Split sizes {split_lengths} sum to {length_sum}, " + f"but dimension {dim} has size {dim_size}" + ) + + # Convert split argument 'split_lengths' to slice arguments start and end. + starts = [0] * len(split_lengths) + ends = [0] * len(split_lengths) + start = 0 + end = 0 + for i, split_length in enumerate(split_lengths): + end = start + split_length + starts[i] = start + ends[i] = end + start = end + + # Output nodes are of type getitem + # Replace them with one slice node for each output node. + with graph_module.graph.inserting_before(split_node): + for output_node in output_nodes: + index = output_node.args[1] + slice_node = create_node( + graph, + self.slice, + (input_node, dim, starts[index], ends[index]), + from_node=node, + ) + slice_node.meta = _copy_user_node_qparams( + split_node, output_node, index + ) + output_node.replace_all_uses_with(slice_node) + graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) + + +def _copy_user_node_qparams( + split_node: torch.fx.Node, output_node: torch.fx.Node, index: int +) -> dict: + """ + Construct metadata for the slice node that will replace the split output. + + Note that output quantization parameters are copied from the user nodes + of the split node. The split node itself does not have output quantization + parameters. + + Args: + split_node: The split node being replaced. + output_node: The getitem node that is user of the split node. + index: The index of the output being processed. + Returns: + Updated metadata dictionary for the slice node. + """ + + def _select_index(value): + if isinstance(value, (list, tuple)): + return value[index] + return value + + meta = split_node.meta.copy() + if "val" in meta: + meta["val"] = _select_index(meta["val"]) + if "tensor_meta" in meta: + meta["tensor_meta"] = _select_index(meta["tensor_meta"]) + if "input_qparams" in meta: + meta["input_qparams"] = dict(meta["input_qparams"]) + if "output_qparams" in meta: + meta["output_qparams"] = dict(output_node.meta["output_qparams"]) + return meta diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_squeezes_to_view.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_squeezes_to_view.py new file mode 100644 index 0000000..9d185a8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_squeezes_to_view.py @@ -0,0 +1,36 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.fuse_view_copy_transform_pass import ( + FuseViewCopyTransformPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class ConvertSqueezesToViewPass(ArmPass): + """ + Replaces squeeze/unsqueeze operators with view. These are simply special cases of the view op, so removing them gives us less cases to handle in the node visitiors. + """ + + _passes_required_after: Set[Type[ExportPass]] = {FuseViewCopyTransformPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in [ + exir_ops.edge.aten.squeeze_copy.dims, + exir_ops.edge.aten.unsqueeze_copy.default, + ]: + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + shape = meta["val"].size() + view_args = (x, list(shape)) + return super().call_operator( + exir_ops.edge.aten.view_copy.default, view_args, kwargs, meta + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_to_clamp_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_to_clamp_pass.py new file mode 100644 index 0000000..effb46f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/convert_to_clamp_pass.py @@ -0,0 +1,45 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Tuple, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + QuantizeClampArgumentsPass, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_operators = { + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.relu.default, +} + + +def get_clamp_params(op, args) -> Tuple[float | None, float | None]: + if op == exir_ops.edge.aten.hardtanh.default: + return args[1], args[2] + elif op == exir_ops.edge.aten.relu.default: + return 0.0, None + else: + raise ValueError(f"Getting clamp parameters for op {op} is not implemented.") + + +class ConvertToClampPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {QuantizeClampArgumentsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_operators or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + return super().call_operator( + exir_ops.edge.aten.clamp.default, + (args[0], *get_clamp_params(op, args)), + {}, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_acosh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_acosh_pass.py new file mode 100644 index 0000000..1d29986 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_acosh_pass.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass # noqa +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_acosh_op = exir_ops.edge.aten.acosh.default + + +class DecomposeAcoshPass(ArmPass): + """ + Decomposes acosh to supported TOSA-operations. + This decomposition is based on the mathematical identity: + acosh(x) = log(x + sqrt((x-1)(x+1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta, updated=False): + + if op is not edge_acosh_op: + return super().call_operator(op, args, kwargs, meta, updated) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta, updated) + + log_op, sqrt_op, mul_op, sub_op, add_op, add_op_scalar = ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.add.Scalar, + ) + + x = args[0] + + # (x-1)(x+1) + sub = super().call_operator(sub_op, (x, 1.0), {}, meta, True) + add = super().call_operator(add_op_scalar, (x, 1.0), {}, meta, True) + mul = super().call_operator(mul_op, (sub, add), {}, meta, True) + + # sqrt((x-1)(x+1)) + sqrt = super().call_operator(sqrt_op, (mul,), {}, meta, True) + + # x + sqrt((x-1)(x+1)) + add = super().call_operator(add_op, (x, sqrt), {}, meta, True) + + # out = ln(x + sqrt((x-1)(x+1)) + out = super().call_operator(log_op, (add,), {}, meta, True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py new file mode 100644 index 0000000..5905e8f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from math import ceil, floor +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_avg_pool2d_pass import ( + DecomposeAvgPool2dPass, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, NodeMetadata + +edge_ops = (exir_ops.edge.aten._adaptive_avg_pool2d.default,) +aten_ops = (torch.ops.aten.adaptive_avg_pool2d.default,) + + +def _get_decomposition(op) -> tuple: + if op in edge_ops: + return ( + exir_ops.edge.aten.avg_pool2d.default, + exir_ops.edge.aten.slice_copy.Tensor, + exir_ops.edge.aten.cat.default, + ) + if op in aten_ops: + return ( + torch.ops.aten.avg_pool2d.default, + torch.ops.aten.slice_copy.Tensor, + torch.ops.aten.cat.default, + ) + raise RuntimeError(f"Unable to get decomposition for op {op}") + + +class DecomposeAdaptiveAvgPool2dPass(ArmPass): + """ + Decomposes AdaptiveAvgPool2d into AvgPool2d operations. + + An input tensor of shape (N, C, H, W) is transformed into an output tensor + of shape (N, C, output_size_h, output_size_w). + + The output is of size output_size_h x output_size_w for any input. + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeAvgPool2dPass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op not in (edge_ops + aten_ops): + return super().call_operator(op, args, kwargs, meta, updated) + + avg_pool2d_op, slice_op, cat_op = _get_decomposition(op) + + x = args[0] + _, _, input_size_h, input_size_w = x.data.shape + + (output_size_h, output_size_w) = args[1] + + # Vela currently only allows a stride in the interval of [1,3] for AvgPool2d. + # To accommodate this, the AvgPool2d op is applied to pooling regions and the results are concatenated. + + # Slices and concats does not require quantization parameters + metadata_dict = dict(meta.data) + metadata_dict["input_qparams"] = {} + metadata_dict["output_qparams"] = {} + meta_with_no_qparams = NodeMetadata(metadata_dict) + res = [] + for out_i in range(output_size_h): + row = [] + for out_j in range(output_size_w): + # Calculate pooling regions + start_h = floor(out_i * input_size_h / output_size_h) + end_h = ceil((out_i + 1) * input_size_h / output_size_h) + start_w = floor(out_j * input_size_w / output_size_w) + end_w = ceil((out_j + 1) * input_size_w / output_size_w) + + # Slice along H + x_h = super().call_operator( + slice_op, (x, 2, start_h, end_h), kwargs, meta_with_no_qparams, True + ) + # Slice along W + x_hw = super().call_operator( + slice_op, + (x_h, 3, start_w, end_w), + kwargs, + meta_with_no_qparams, + True, + ) + + # Apply avg pooling with kernel size equal to the pooling region + kernel_h = end_h - start_h + kernel_w = end_w - start_w + pool_args = (x_hw, (kernel_h, kernel_w), (1, 1), (0, 0)) + pooled = super().call_operator( + avg_pool2d_op, pool_args, kwargs, meta, True + ) + row.append(pooled) + + # Concatenate row results along width (dim=3) + row_tensor = super().call_operator( + cat_op, (row, 3), kwargs, meta_with_no_qparams, True + ) + res.append(row_tensor) + + # Concatenate all rows along height (dim=2) + out = super().call_operator( + cat_op, (res, 2), kwargs, meta_with_no_qparams, True + ) + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_add_sub_alpha_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_add_sub_alpha_pass.py new file mode 100644 index 0000000..e59fb54 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_add_sub_alpha_pass.py @@ -0,0 +1,98 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +import numbers +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +_ADD_OPS = ( + exir_ops.edge.aten.add.Tensor, + torch.ops.aten.add.Tensor, +) + +_SUB_OPS = ( + exir_ops.edge.aten.sub.Tensor, + torch.ops.aten.sub.Tensor, +) + + +def _get_ops(op): + if op in _ADD_OPS: + if op is exir_ops.edge.aten.add.Tensor: + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + ) + return ( + torch.ops.aten.mul.Tensor, + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + ) + if op in _SUB_OPS: + if op is exir_ops.edge.aten.sub.Tensor: + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.sub.Tensor, + ) + return ( + torch.ops.aten.mul.Tensor, + torch.ops.aten.full.default, + torch.ops.aten.sub.Tensor, + ) + raise RuntimeError(f"Unsupported operator {op}") + + +def _should_decompose(alpha) -> bool: + if isinstance(alpha, numbers.Number): + return alpha != 1 + return False + + +class DecomposeAddSubAlphaPass(ArmPass): + """Rewrite add/sub with alpha into a mul followed by add/sub.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta, updated: bool | None = False): + if op not in _ADD_OPS + _SUB_OPS: + return super().call_operator(op, args, kwargs, meta, updated) + + alpha = kwargs.get("alpha", 1) + if not _should_decompose(alpha): + return super().call_operator(op, args, kwargs, meta, updated) + + mul_op, full_op, binary_op = _get_ops(op) + lhs, rhs = args + + alpha_full = super().call_operator( + full_op, + ((1,), float(alpha)), + {"device": meta["val"].device}, + meta, + updated=True, + ) + scaled_rhs = super().call_operator( + mul_op, + (rhs, alpha_full), + {}, + meta, + updated=True, + ) + return super().call_operator( + binary_op, + (lhs, scaled_rhs), + {}, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_addmm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_addmm_pass.py new file mode 100644 index 0000000..f709aca --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_addmm_pass.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.mm_to_bmm_pass import ConvertMmToBmmPass # noqa +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For MI case +edge_addmm = exir_ops.edge.aten.addmm.default +# For BI case +aten_addmm = torch.ops.aten.addmm.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_addmm: + return ( + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Tensor, + ) + elif op == aten_addmm: + return ( + torch.ops.aten.mm.default, + torch.ops.aten.mul.Scalar, + torch.ops.aten.add.Tensor, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeAddmmPass(ArmPass): + """Decomposes the addmm operator into tensor multiplication and addition.""" + + _passes_required_after: Set[Type[ExportPass]] = { + ConvertMmToBmmPass, + MatchArgRanksPass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in [edge_addmm, aten_addmm] or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + input, mat1, mat2 = args + beta = kwargs.get("beta", 1.0) + alpha = kwargs.get("alpha", 1.0) + + mul_op, mul_scalar_op, add_op = get_ops(op) + + mul = super().call_operator(mul_op, (mat1, mat2), {}, meta, updated=True) + mul_alpha = super().call_operator( + mul_scalar_op, (mul, alpha), {}, meta, updated=True + ) + + input_beta = super().call_operator( + mul_scalar_op, (input, beta), {}, meta, updated=True + ) + + return super().call_operator( + add_op, (mul_alpha, input_beta), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_any_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_any_pass.py new file mode 100644 index 0000000..a0487e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_any_pass.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.exir.dialects._ops import ( # type: ignore[import-not-found] + ops as exir_ops, +) +from executorch.exir.pass_base import ( # type: ignore[import-not-found] + ExportPass, + PassResult, +) + + +class DecomposeAnyPass(ArmPass): + """ + Converts any.default, any.dim and any.dims to a sequence of any.dim by + unrolling multi-dimensional reductions with keepdim=True. If keepdim=False + was requested, the final shape adjustment is implemented with a + view_copy.default to the reduced shape. + + Example 1 + Original: + any.dim() # x.shape: [dim1, dim2, ..., dimn] + After pass: + any.dim(dim1, keepdim = True) + any.dim(dim2, keepdim = True) + ... + any.dim(dimn, keepdim = True) + view_copy(shape = squeezed_shape) + + Example 2 + Original: + any.dim(dim1, keepdim = False) + After pass: + any.dim(dim1, keepdim = True) + view_copy(shape = squeezed_shape) + + Example 3 + Original: + any.dims([dim1, dim2], keepdim = False) + After pass: + any.dim(dim1, keepdim = True) + any.dim(dim2, keepdim = True) + view_copy(shape = squeezed_shape) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target not in [ + exir_ops.edge.aten.any.default, + exir_ops.edge.aten.any.dim, + exir_ops.edge.aten.any.dims, + ]: + continue + + if len(node.args) == 1: + # any.default(input) + input_node = (node.args)[0] + dims_to_reduce = range(len(input_node.meta["val"].shape)) + keepdim = False + elif len(node.args) == 2: + # any.dim/dims(input, dims=dims) + input_node, dims_to_reduce = node.args + keepdim = False + elif len(node.args) == 3: + # any.dim/dims(input, dims=dims, keepdim=keepdim) + input_node, dims_to_reduce, keepdim = node.args + else: + raise RuntimeError( + f"Unexpected arg size {len(node.args)} in {node.name}" + ) + try: + iter(dims_to_reduce) + except: + dims_to_reduce = [dims_to_reduce] # type: ignore[assignment] + else: + dims_to_reduce = list(dims_to_reduce) # type: ignore[assignment] + + # Unroll multi-dimensional reduction and keep-dims arg + with graph_module.graph.inserting_before(node): + for dim in dims_to_reduce: + args = (input_node, dim, True) + input_node = graph_module.graph.create_node( + "call_function", exir_ops.edge.aten.any.dim, args, node.kwargs + ) + + if not keepdim: + output_shape = list(get_first_fake_tensor(node).shape) + input_node = graph_module.graph.create_node( + "call_function", + exir_ops.edge.aten.view_copy.default, + (input_node, output_shape), + ) + + node.replace_all_uses_with(input_node) + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asin_and_acos_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asin_and_acos_pass.py new file mode 100644 index 0000000..e0da9eb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asin_and_acos_pass.py @@ -0,0 +1,236 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from math import pi +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_full_like_to_full_pass import ( + ConvertFullLikeToFullPass, +) +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_asin_op = (exir_ops.edge.aten.asin.default,) +edge_acos_op = (exir_ops.edge.aten.acos.default,) + + +def get_decomposition(op) -> tuple: + if op in (edge_asin_op + edge_acos_op): + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.div.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.neg.default, + ) + + raise RuntimeError(f"Can't get decomposition for op {op}") + + +class DecomposeAsinAndAcosPass(ArmPass): + """ + This pass decomposes asin and acos into a rational approximation for small values + and a transformed rational approximation for large values. + + The decomposition is based on the following mathematical identities: + if abs(x) < 0.5: + asin(x) = x + P(x^2) / Q(x^2) + acos(x) = π/2 - asin(x) + else: + asin(x) = π/2 - 2 * (s + s^3 * Q(z) / P(z)) + acos(x) = 2 * (s + s^3 * Q(z) / P(z)) + where P and Q are polynomials defined in the function and s is the square root of z. + + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + DecomposeDivPass, + ConvertFullLikeToFullPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + def _build_polynomial( + self, coefficients: list[float], variable: torch.Tensor, meta: dict[str, str] + ) -> torch.Tensor: + """ + Helper function to build polynomial from coefficients and variable. + """ + full_like_op, add_op, mul_op_scalar, mul_op = ( + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.mul.Tensor, + ) + result = super().call_operator( + full_like_op, (variable, coefficients[0]), {}, meta, True + ) + for coeff in coefficients[1:]: + result = super().call_operator( + add_op, + ( + result, + super().call_operator( + mul_op_scalar, (variable, coeff), {}, meta, True + ), + ), + {}, + meta, + ) + variable = super().call_operator( + mul_op, (variable, variable), {}, meta, True + ) + return result + + def _combine_branches( + self, + bool_op, + bool_args: tuple[torch.Tensor, float], + branches: tuple[torch.Tensor, torch.Tensor], + meta: dict[str, str], + ) -> torch.Tensor: + where_op = exir_ops.edge.aten.where.self + mask = super().call_operator(bool_op, bool_args, {}, meta, True) + branch_true, branch_false = branches + return super().call_operator( + where_op, (mask, branch_true, branch_false), {}, meta, True + ) + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_asin_op + edge_acos_op): + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + logging.info( + f"Approximating {op}. This may introduce small numerical errors. For details, see {__file__}." + ) + x = args[0] + half = 0.5 + one = 1.0 + neg_half = -0.5 + two = 2.0 + pi_over_2 = pi / 2.0 + zero = 0.0 + neg_one = -1.0 + + ( + mul_op, + add_op, + mul_op_scalar, + sqrt_op, + abs_op, + sub_op_scalar, + div_op, + gt_op, + lt_op, + sub_op, + full_like_op, + neg_op, + ) = get_decomposition(op) + + # Coefficients for the rational approximation, calculated with the Minimax (Remez) method + p_coefficients = [ + 1.6666667163e-01, + -3.2556581497e-01, + 2.0121252537e-01, + -4.0055535734e-02, + 7.9153501429e-04, + ] + + q_coefficients = [1.0, -2.4033949375e00, 2.0209457874e00, -6.8828397989e-01] + + x_abs = super().call_operator(abs_op, (x,), {}, meta, True) + + # Step 1: compute asin_small - rational approximation for [0,0.5] + y = super().call_operator(mul_op, (x_abs, x_abs), {}, meta, True) + x3 = super().call_operator(mul_op, (x_abs, y), {}, meta, True) + + P = self._build_polynomial(p_coefficients, x_abs, meta) + Q = self._build_polynomial(q_coefficients, x_abs, meta) + numer = super().call_operator(mul_op, (x3, P), {}, meta, True) + r_small = super().call_operator(div_op, (numer, Q), {}, meta, True) + asin_small = super().call_operator(add_op, (x_abs, r_small), {}, meta, True) + + # Step 2: Compute the transformed approximation for large values + # Calculate z = -0.5 * (|x| - 1) + tmp_ones = super().call_operator(full_like_op, (x_abs, one), {}, meta, True) + tmp = super().call_operator(sub_op, (x_abs, tmp_ones), {}, meta, True) + z = super().call_operator(mul_op_scalar, (tmp, neg_half), {}, meta, True) + + # Calculate s-terms + s = super().call_operator(sqrt_op, (z,), {}, meta, True) + s2 = super().call_operator(mul_op, (s, s), {}, meta, True) + s3 = super().call_operator(mul_op, (s2, s), {}, meta, True) + + Pz = self._build_polynomial(p_coefficients, z, meta) + Qz = self._build_polynomial(q_coefficients, z, meta) + + numer = super().call_operator(mul_op, (s3, Pz), {}, meta, True) + + # Calculate r_large = P(z) / Q(z) + r_large = super().call_operator(div_op, (numer, Qz), {}, meta, True) + + # Calculate asin_large = pi/2 - 2 * (s + s^3 * Q(z) / P(z)) + t1 = super().call_operator(add_op, (s, r_large), {}, meta, True) + t2 = super().call_operator(mul_op_scalar, (t1, two), {}, meta, True) + + diff = super().call_operator(sub_op_scalar, (t2, pi_over_2), {}, meta, True) + tmp_neg_ones = super().call_operator( + full_like_op, (diff, neg_one), {}, meta, True + ) + asin_large = super().call_operator(mul_op, (diff, tmp_neg_ones), {}, meta, True) + + asin_unsigned = self._combine_branches( + gt_op, (x_abs, half), (asin_large, asin_small), meta + ) + + # Handle x < 0 + negated_asin = super().call_operator(neg_op, (asin_unsigned,), {}, meta, True) + asin = self._combine_branches( + lt_op, (x, zero), (negated_asin, asin_unsigned), meta + ) + + if op in edge_acos_op: + # If x <= 0.5: acos(x) = pi/2 - asin(x) + const_tensor = super().call_operator( + full_like_op, (x, pi_over_2), {}, meta, True + ) + acos_small = super().call_operator( + sub_op, (const_tensor, asin), {}, meta, True + ) + # If x > 0.5, acos(x) = 2 * (s + s^3 * Q(z) / P(z)) = t2 + acos = self._combine_branches(gt_op, (x, half), (t2, acos_small), meta) + return acos + + return asin diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asinh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asinh_pass.py new file mode 100644 index 0000000..1131fee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_asinh_pass.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_asinh_op = (exir_ops.edge.aten.asinh.default,) + + +class DecomposeAsinhPass(ArmPass): + """ + Decomposes asinh to supported TOSA-operations. + This decomposition is based on the mathematical identity: + asinh(x) = log(x + sqrt(x^2 + 1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_asinh_op: + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + log_op, sqrt_op, mul_op, add_op_scalar, add_op = ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.add.Tensor, + ) + + x = args[0] + + # calculate t1 = x^2 + 1 + x2 = super().call_operator(mul_op, (x, x), {}, meta, True) + t1 = super().call_operator(add_op_scalar, (x2, 1.0), {}, meta, True) + + # t2 = sqrt(t1) + t2 = super().call_operator(sqrt_op, (t1,), {}, meta, True) + + # t3 = x + t2 + t3 = super().call_operator(add_op, (x, t2), {}, meta, True) + + # out = ln(t3) + out = super().call_operator(log_op, (t3,), {}, meta, True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atan_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atan_pass.py new file mode 100644 index 0000000..a3b4081 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atan_pass.py @@ -0,0 +1,142 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from math import pi +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_atan = exir_ops.edge.aten.atan.default # MI case + + +def _get_atan_ops(op): + """Return the primitive ops required..""" + if op is not edge_atan: + raise RuntimeError(f"Can't decompose atan for op {op}") + + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.neg.default, + ) + + +class DecomposeAtanPass(ArmPass): + """Decomposes the atan operator into a rational (Padé) approximation.""" + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + def _rational_approximation(self, z, ops, meta): + """Creates a (2,1) Padé approximation for atan(x) on [-1, 1].""" + + op_mul, op_mul_scalar, op_add, op_add_scalar, _, _, _, op_recip, _, _ = ops + + # Coefficients calculated using minimax on the interval [-1, 1]. + a1 = 0.3529666667 + a2 = -0.0287666667 + b1 = 0.6863 + + z2 = super().call_operator(op_mul, (z, z), {}, meta, updated=True) + z4 = super().call_operator(op_mul, (z2, z2), {}, meta, updated=True) + + num1 = super().call_operator(op_mul_scalar, (z2, a1), {}, meta, updated=True) + num2 = super().call_operator(op_mul_scalar, (z4, a2), {}, meta, updated=True) + num = super().call_operator(op_add_scalar, (num1, 1.0), {}, meta, updated=True) + num = super().call_operator(op_add, (num, num2), {}, meta, updated=True) + + den1 = super().call_operator(op_mul_scalar, (z2, b1), {}, meta, updated=True) + den = super().call_operator(op_add_scalar, (den1, 1.0), {}, meta, updated=True) + + inv_den = super().call_operator(op_recip, (den,), {}, meta, updated=True) + + prod = super().call_operator(op_mul, (num, inv_den), {}, meta, updated=True) + return super().call_operator(op_mul, (z, prod), {}, meta, updated=True) + + def call_operator(self, op, args, kwargs, meta): + if op is not edge_atan: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + logging.info( + f"Approximating atan. This may introduce small numerical errors. For details, see {__file__}." + ) + + ops = _get_atan_ops(op) + ( + _, + op_mul_scalar, + _, + op_add_scalar, + op_sub, + op_abs, + op_gt, + op_recip, + op_where, + op_neg, + ) = ops + + x = args[0] + + # |x| > 1 is reduced to [0, 1] using atan(x) = pi/2 - atan(1/x) and atan(-x) = -atan(x). + + abs_x = super().call_operator(op_abs, (x,), {}, meta, updated=True) + mask_hi = super().call_operator(op_gt, (abs_x, 1.0), {}, meta, updated=True) + + inv_x = super().call_operator(op_recip, (abs_x,), {}, meta, updated=True) + z = super().call_operator( + op_where, (mask_hi, inv_x, abs_x), {}, meta, updated=True + ) + + atan_z = self._rational_approximation(z, ops, meta) + + zero_tensor = super().call_operator( + op_mul_scalar, (x, 0.0), {}, meta, updated=True + ) + half_pi_tensor = super().call_operator( + op_add_scalar, (zero_tensor, pi / 2), {}, meta, updated=True + ) + + diff = super().call_operator( + op_sub, (half_pi_tensor, atan_z), {}, meta, updated=True + ) + atan_abs = super().call_operator( + op_where, (mask_hi, diff, atan_z), {}, meta, updated=True + ) + + mask_pos = super().call_operator(op_gt, (x, 0.0), {}, meta, updated=True) + neg_val = super().call_operator(op_neg, (atan_abs,), {}, meta, updated=True) + + return super().call_operator( + op_where, (mask_pos, atan_abs, neg_val), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atanh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atanh_pass.py new file mode 100644 index 0000000..789dafe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_atanh_pass.py @@ -0,0 +1,86 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_atanh = exir_ops.edge.aten.atanh.default # MI case + + +def _get_atanh_ops(op): + """Return the primitive ops required..""" + if op is not edge_atanh: + raise RuntimeError(f"Can't decompose atanh for op {op}") + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.neg.default, + ) + + +class DecomposeAtanhPass(ArmPass): + """ + Decomposes the atanh operator into primitive ops. + atanh(x) = 0.5 * log((1 + x) / (1 - x)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op is not edge_atanh: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + ops = _get_atanh_ops(op) + ( + op_mul_tensor, + op_mul_scalar, + op_add_scalar, + op_reciprocal, + op_log, + op_neg, + ) = ops + + x = args[0] + + nom = super().call_operator(op_add_scalar, (x, 1.0), {}, meta, updated=True) + + neg_x = super().call_operator(op_neg, (x,), {}, meta, updated=True) + denom = super().call_operator( + op_add_scalar, (neg_x, 1.0), {}, meta, updated=True + ) + recip = super().call_operator(op_reciprocal, (denom,), {}, meta, updated=True) + + log_input = super().call_operator( + op_mul_tensor, (nom, recip), {}, meta, updated=True + ) + log = super().call_operator(op_log, (log_input,), {}, meta, updated=True) + + return super().call_operator(op_mul_scalar, (log, 0.5), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_avg_pool2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_avg_pool2d_pass.py new file mode 100644 index 0000000..c46a54b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_avg_pool2d_pass.py @@ -0,0 +1,154 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_div_ops = (exir_ops.edge.aten.avg_pool2d.default,) +aten_div_ops = (torch.ops.aten.avg_pool2d.default,) + + +def get_decomposition(op) -> tuple: + if op in edge_div_ops: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.avg_pool2d.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in aten_div_ops: + return ( + torch.ops.aten.full.default, + torch.ops.aten.cat.default, + torch.ops.aten.avg_pool2d.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get avg_pool2d decomposition for op {op}") + + +class DecomposeAvgPool2dPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {ComputeConstantOpsAOTPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_div_ops + aten_div_ops) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + full_op, cat_op, avgpool_op, mul_op = get_decomposition(op) + + x = args[0] + full_kwargs = {"device": x.data.device} + kernel_h, kernel_w = args[1] + kernel_size = kernel_h * kernel_w + if len(args) > 2 and args[2] is not None: + stride_h, stride_w = args[2] + else: + stride_h, stride_w = kernel_h, kernel_w + pad_h, pad_w = new_pad_h, new_pad_w = args[3] if len(args) > 3 else (0, 0) + ceil_mode = args[4] if len(args) > 4 else False + count_include_pad = args[5] if len(args) > 5 else True + divisor_override = args[6] if len(args) > 6 else None + + n, c, h, w = x.data.shape + post_pad_w, post_pad_h = (0, 0) + + # Count_include_pad == False means that we use a different divisor for edge elements + # When divisor_override is set, this will be overriden anyways. + # It is easier to replace a constant divisor, so set count_include_pad == True + if divisor_override is not None: + count_include_pad = True + + # Add width padding manually if count_include_pad + if count_include_pad and pad_w > 0: + pre_pad_shape = [n, c, h, pad_w] + pre_pad = super().call_operator( + full_op, (pre_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + + if ceil_mode and divisor_override is None: + post_pad_w = pad_w + else: + post_pad_w = adjust_pooling_pad_if_needed( + w, kernel_w, stride_w, pad_w, ceil_mode + ) + + if post_pad_w > 0: + post_pad_shape = [n, c, h, post_pad_w] + post_pad = super().call_operator( + full_op, (post_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + cat_nodes = [pre_pad, x, post_pad] + else: + cat_nodes = [pre_pad, x] + + x = super().call_operator( + cat_op, (cat_nodes, 3), kwargs, meta, updated=True + ) + new_pad_w = 0 + + # Add height padding manually if count_include_pad + if count_include_pad and pad_h > 0: + pre_pad_shape = [n, c, pad_h, w + pad_w + post_pad_w] + pre_pad = super().call_operator( + full_op, (pre_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + + if ceil_mode and divisor_override is None: + post_pad_h = pad_h + else: + post_pad_h = adjust_pooling_pad_if_needed( + h, kernel_h, stride_h, pad_h, ceil_mode + ) + + if post_pad_h > 0: + post_pad_shape = [n, c, post_pad_h, w + pad_w + post_pad_w] + post_pad = super().call_operator( + full_op, (post_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + cat_nodes = [pre_pad, x, post_pad] + else: + cat_nodes = [pre_pad, x] + + x = super().call_operator( + cat_op, (cat_nodes, 2), kwargs, meta, updated=True + ) + new_pad_h = 0 + + avgpool_args = ( + x, + args[1], + [stride_h, stride_w], + [new_pad_h, new_pad_w], + ceil_mode, + False, + ) + x = super().call_operator(avgpool_op, avgpool_args, kwargs, meta, updated=True) + + # Multiply by factor (kernel_size / divisor_override) if divisor_override + if divisor_override is not None and divisor_override != kernel_size: + override_multiplier = super().call_operator( + full_op, + ([1, 1, 1, 1], kernel_size / divisor_override), + full_kwargs, + meta, + updated=True, + ) + x = super().call_operator( + mul_op, (x, override_multiplier), kwargs, meta, updated=True + ) + + return x diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_batch_norm_no_stats.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_batch_norm_no_stats.py new file mode 100644 index 0000000..36af927 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_batch_norm_no_stats.py @@ -0,0 +1,233 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) + +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeBatchNormNoStatsPass(ArmPass): + """ + Decompose BatchNorm2d(track_running_stats=False) (aten._native_batch_norm_legit_no_training) + into a sequence of elementwise operations: + + # let input = x, rm = running_mean, rv = running_var, eps: float + rm_view = view(rm, weights_shape) + rv_view = view(rv, weights_shape) + centered = sub(x, rm_view) + eps_full = full(eps_shape, eps) + var_eps = add(rv_view, eps_full) + inv_sqrt = rsqrt(var_eps) + normed = mul(centered, inv_sqrt) + weighted = mul(normed, w_view) + biased = add(weighted, b_view) + + Source: https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm2d.html + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + InsertTableOpsPass, + } + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901 + bn_ops = ( + exir_ops.edge.aten._native_batch_norm_legit.no_stats, + exir_ops.edge.aten._native_batch_norm_legit_no_training.default, + torch.ops.aten._native_batch_norm_legit_no_training.default, + torch.ops.aten.batch_norm.default, + torch.ops.aten.native_batch_norm.default, + ) + + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in bn_ops + or not self.allowed_to_transform(node.meta) + ): + continue + + if node.target in ( + torch.ops.aten.batch_norm.default, + torch.ops.aten.native_batch_norm.default, + ): + # signature: (input, weight, bias, mean, var, training, momentum, eps, cudnn_enabled) + # pos‐arg 5 is training + training = node.kwargs.get("training", False) + if len(node.args) > 5: + training = node.args[5] + if training: + # skip training‐mode batchnorm + continue + + # Extract args + args = node.args + meta = node.meta + + # Default eps + eps: float = torch.finfo().eps + # weight and bias may be None + x = args[0] + weight = args[1] if len(args) > 1 else None + bias = args[2] if len(args) > 2 else None + running_mean = args[3] + running_var = args[4] + if len(args) > 6: + eps = args[6] + + # Determine shapes + val = meta.get("val") + ref_tensor = val[0] if isinstance(val, tuple) else val + shape = tuple(ref_tensor.size()) + dtype = ref_tensor.dtype + rank = len(shape) + + # channel dimension is 1 for BatchNorm2d + channel_axis = 1 + weights_shape = [1] * rank + weights_shape[channel_axis] = shape[channel_axis] + num_features = shape[channel_axis] + + # Ops to use + sub_op = exir_ops.edge.aten.sub.Tensor + view_op = exir_ops.edge.aten.view_copy.default + full_op = exir_ops.edge.aten.full.default + add_op = exir_ops.edge.aten.add.Tensor + rsqrt_op = exir_ops.edge.aten.rsqrt.default + mul_op = exir_ops.edge.aten.mul.Tensor + + # Begin decomposition + with graph_module.graph.inserting_before(node): + # reshape running stats + rm_view = create_node( + graph_module.graph, + view_op, + args=(running_mean, weights_shape), + from_node=node, + ) + rv_view = create_node( + graph_module.graph, + view_op, + args=(running_var, weights_shape), + from_node=node, + ) + # center input + centered = create_node( + graph_module.graph, + sub_op, + args=(x, rm_view), + from_node=node, + ) + # epsilon tensor + eps_shape = [1] * rank + eps_full = create_node( + graph_module.graph, + full_op, + args=(eps_shape, eps), + kwargs={"dtype": dtype}, + from_node=node, + ) + # var + eps + var_eps = create_node( + graph_module.graph, + add_op, + args=(rv_view, eps_full), + from_node=node, + ) + # inverse sqrt + inv_sqrt = create_node( + graph_module.graph, + rsqrt_op, + args=(var_eps,), + from_node=node, + ) + # normalized + normed = create_node( + graph_module.graph, + mul_op, + args=(centered, inv_sqrt), + from_node=node, + ) + + # weight + if weight is None: + one = create_node( + graph_module.graph, + full_op, + args=([num_features], 1), + kwargs={"dtype": dtype}, + from_node=node, + ) + w_view = create_node( + graph_module.graph, + view_op, + args=(one, weights_shape), + from_node=node, + ) + else: + w_view = create_node( + graph_module.graph, + view_op, + args=(weight, weights_shape), + from_node=node, + ) + weighted = create_node( + graph_module.graph, + mul_op, + args=(normed, w_view), + from_node=node, + ) + + # bias + if bias is None: + zero = create_node( + graph_module.graph, + full_op, + args=([num_features], 0), + kwargs={"dtype": dtype}, + from_node=node, + ) + b_view = create_node( + graph_module.graph, + view_op, + args=(zero, weights_shape), + from_node=node, + ) + else: + b_view = create_node( + graph_module.graph, + view_op, + args=(bias, weights_shape), + from_node=node, + ) + final_out = create_node( + graph_module.graph, + add_op, + args=(weighted, b_view), + from_node=node, + ) + + users = [u for u in node.users if u is not node] + node.replace_all_uses_with(final_out) + for u in users: + if u.target == operator.getitem: + u.replace_all_uses_with(final_out) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + + graph_module.recompile() + new_gm = super().call(graph_module).graph_module + return PassResult(new_gm, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosh_pass.py new file mode 100644 index 0000000..fe84f2b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosh_pass.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_cosh = exir_ops.edge.aten.cosh.default + + +class DecomposeCoshPass(ArmPass): + """ + This pass replaces the cosh operator with a sequence of TOSA-equivalent operations that + compute the hyperbolic cosine using the formula: + + cosh(x) = 0.5 * (e^x + e^(-x)) + + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op is not edge_cosh: + return super().call_operator(op, args, kwargs, meta, updated) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + x = args + + exp_op, mul_op, neg_op, add_op = ( + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.add.Tensor, + ) + + # exp1 = e^x + exp1 = super().call_operator(exp_op, x, {}, meta, updated=True) + + # exp2 = e^(⁻x) + neg_x = super().call_operator(neg_op, x, {}, meta, updated=True) + exp2 = super().call_operator(exp_op, (neg_x,), {}, meta, updated=True) + + # numer = exp1 + exp2 + numer = super().call_operator(add_op, (exp1, exp2), {}, meta, updated=True) + + # out = 0.5 * numer + out = super().call_operator(mul_op, (numer, 0.5), {}, meta, updated=True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosine_similarity_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosine_similarity_pass.py new file mode 100644 index 0000000..1978a40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cosine_similarity_pass.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_full_like_to_full_pass import ( + ConvertFullLikeToFullPass, +) + +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.pass_base import ExportPass + +torch_cosine_similarity = (torch.ops.aten.cosine_similarity.default,) + + +class DecomposeCosineSimilarityPass(ArmPass): + """ + Decomposition of aten.cosine_similarity: + + dot = sum(mul(x1, x2), dims, keepdim=False) + norm = pow( sum(mul(x, x), dims, keepdim=False), 0.5 ) + eps = full( (), eps_scalar ) + n1c = max(norm1, eps) + n2c = max(norm2, eps) + denom = mul(n1c, n2c) + out = div(dot, denom) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeDivPass, + DecomposeSumPass, + ConvertFullLikeToFullPass, + InsertTableOpsPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in torch_cosine_similarity or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x1, x2 = args[0], args[1] + dim = kwargs.get("dim", 1) + eps = kwargs.get("eps", 1e-8) + dims = [dim] if isinstance(dim, int) else list(dim) + + # 1) dot + prod = super().call_operator(torch.ops.aten.mul.Tensor, (x1, x2), {}, meta) + dot = super().call_operator( + torch.ops.aten.sum.dim_IntList, (prod, dims, False), {}, meta + ) + + # 2a) norm1 = pow(sum(x1*x1), 0.5) + x1_sq = super().call_operator(torch.ops.aten.mul.Tensor, (x1, x1), {}, meta) + s1 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (x1_sq, dims, False), {}, meta + ) + norm1 = super().call_operator( + torch.ops.aten.pow.Tensor_Scalar, (s1, 0.5), {}, meta + ) + + # 2b) norm2 = pow(sum(x2*x2), 0.5) + x2_sq = super().call_operator(torch.ops.aten.mul.Tensor, (x2, x2), {}, meta) + s2 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (x2_sq, dims, False), {}, meta + ) + norm2 = super().call_operator( + torch.ops.aten.pow.Tensor_Scalar, (s2, 0.5), {}, meta + ) + + # 3) eps scalar - we need to broadcast ourselves as TOSA dont do this for scalar + eps_t = super().call_operator( + torch.ops.aten.full_like.default, (norm1, eps), {}, meta + ) + + # 4) clamp to avoid zero division + n1c = super().call_operator( + torch.ops.aten.maximum.default, (norm1, eps_t), {}, meta + ) + n2c = super().call_operator( + torch.ops.aten.maximum.default, (norm2, eps_t), {}, meta + ) + + # 5) denom and divide + denom = super().call_operator(torch.ops.aten.mul.Tensor, (n1c, n2c), {}, meta) + out = super().call_operator(torch.ops.aten.div.Tensor, (dot, denom), {}, meta) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cumsum_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cumsum_pass.py new file mode 100644 index 0000000..143d08d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_cumsum_pass.py @@ -0,0 +1,167 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from math import prod +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass + +from executorch.backends.transforms.utils import create_constant_placeholder +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind + + +class DecomposeCumsumPass(ArmPass): + """ + Decomposes cumsum into a 1D convolution with a kernel of ones. + + For example, the cumsum of an input tensor [1, 1] is [1, 1 + 1] = [1, 2]. + To decompose this, take the input tensor and pre-padded with len(input)-1 zeros and + slided over with a kernel [1,1], of length len(input): + + Input: [0, 1, 1] + Kernel: [1, 1] = [1] + [1, 1] = [2] + + Since pytorch only supports symmetric padding, in reality the result will have + an additional 1 calculated at the end, which leads to an required extra slice op. + + To extend this to higher dimensions, the input is reshaped to [N, C, H, W] with + N = + C = 1 + H = + W = + And the convolution is applied over dimension H. + """ + + _passes_required_after: Set[Type[ExportPass]] = {RewriteConvPass} + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def call(self, graph_module): + graph = graph_module.graph + targets = (exir_ops.edge.aten.cumsum.default, torch.ops.aten.cumsum.default) + modified = False + for node in list(graph.nodes): + if node.op != "call_function" or node.target not in targets: + continue + + if len(node.args) != 2: + raise ValueError( + "Cumsum node should have exactly two arguments: input and dim." + ) + + # Get node data + input_node, dim = node.args + val = node.meta.get("val") + original_shape = list(val.shape) + dtype = input_node.meta.get("val").dtype + dim = dim % len(original_shape) + + # Compute shapes + pre_cumsum_dim = prod(original_shape[:dim]) if dim > 0 else 1 + cumsum_dim = original_shape[dim] + post_cumsum_dim = ( + prod(original_shape[dim + 1 :]) if dim < len(original_shape) - 1 else 1 + ) + conv_shape = [ + pre_cumsum_dim, + 1, + cumsum_dim, + post_cumsum_dim, + ] + pad_shape = [original_shape[dim] - 1, 0] + weight_shape = [1, 1, original_shape[dim], 1] + + # Create convolution weight + with graph.inserting_before(list(graph.nodes)[0]): + weight_data = torch.ones(size=weight_shape, dtype=dtype) + weight_node = create_constant_placeholder( + self.exported_program, + graph, + node.name + "_kernel", + InputKind.PARAMETER, + weight_data, + ) + + # Create decomposed nodes + view_op = exir_ops.edge.aten.view_copy.default + conv_op = exir_ops.edge.aten.convolution.default + slice_op = exir_ops.edge.aten.slice_copy.Tensor + with graph.inserting_before(node): + # Reshape to 4D with + view_args = (input_node, conv_shape) + view_node = create_node( + graph, + view_op, + args=view_args, + from_node=node, + inherit_qparams=False, + ) + + conv_args = ( + view_node, + weight_node, + None, + [1, 1], + pad_shape, + [1, 1], + False, + [0], + 1, + ) + conv_node = create_node( + graph, conv_op, args=conv_args, from_node=node, inherit_qparams=True + ) + + # The convolution is inserted after quantization, so we need to set our + # own quantization parameters for the weights here. However since the + # data is ones directly created as int8, they already have correct scale + # and so no scaling needs to be done, i.e. set scale=1.0, zero_point=0.0 + if ( + "input_qparams" in conv_node.meta + and len(conv_node.meta["input_qparams"]) > 0 + ): + qparams = QuantArgs(1.0, 0.0, -128, 127, torch.int8) + conv_node.meta["input_qparams"][1] = qparams + + slice_args = (conv_node, 2, 0, original_shape[dim]) + slice_node = create_node( + graph, + slice_op, + args=slice_args, + from_node=node, + inherit_qparams=False, + ) + + view_original_args = (slice_node, original_shape) + view_original_node = create_node( + graph, + view_op, + args=view_original_args, + from_node=node, + inherit_qparams=False, + ) + + # Replace and remove original + node.replace_all_uses_with(view_original_node) + graph.erase_node(node) + modified = True + + if modified: + # Cleanup + graph.eliminate_dead_code() + graph_module.recompile() + # Apply any operator-level transforms + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_pass.py new file mode 100644 index 0000000..e883fea --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_pass.py @@ -0,0 +1,61 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_div_ops = (exir_ops.edge.aten.div.Tensor,) +aten_div_ops = (torch.ops.aten.div.Tensor, torch.ops.aten.div_.Tensor) + + +def get_div_decomposition(op) -> tuple: + """ + Returns the the (reciprocal_op, mul_op), where the ops depends on if + the div op is in exir_ops torch.ops.aten. + """ + if op in edge_div_ops: + return (exir_ops.edge.aten.reciprocal.default, exir_ops.edge.aten.mul.Tensor) + if op in aten_div_ops: + return (torch.ops.aten.reciprocal.default, torch.ops.aten.mul.Tensor) + raise RuntimeError(f"Can't get div decomposition for op {op}") + + +class DecomposeDivPass(ArmPass): + """ + This pass decomposes div into a mul and a reciprocal node. + + Example: + y = div(a,b) + Becomes: + x = reciprocal(b) + y = mul(a,x) + """ + + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_div_ops + aten_div_ops) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + reciprocal_op, mul_op = get_div_decomposition(op) + + numerator = args[0] + denominator = args[1] + reciprocal = super().call_operator( + reciprocal_op, (denominator,), {}, meta, updated=True + ) + + return super().call_operator( + mul_op, (numerator, reciprocal), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_tensor_mode.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_tensor_mode.py new file mode 100644 index 0000000..39e22c4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_div_tensor_mode.py @@ -0,0 +1,94 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_div_mode_ops = (exir_ops.edge.aten.div.Tensor_mode,) +aten_div_mode_ops = (torch.ops.aten.div.Tensor_mode,) + +edge_unary = { + "div": exir_ops.edge.aten.div.Tensor, + "floor": exir_ops.edge.aten.floor.default, + "ceil": exir_ops.edge.aten.ceil.default, + "full": exir_ops.edge.aten.full.default, + "lt": exir_ops.edge.aten.lt.Tensor, + "where": exir_ops.edge.aten.where.self, +} + +aten_unary = { + "div": torch.ops.aten.div.Tensor, + "floor": torch.ops.aten.floor.default, + "ceil": torch.ops.aten.ceil.default, + "full": torch.ops.aten.full.default, + "lt": torch.ops.aten.lt.Tensor, + "where": torch.ops.aten.where.self, +} + + +def _get_opset(op): + if op in edge_div_mode_ops: + return edge_unary + if op in aten_div_mode_ops: + return aten_unary + raise RuntimeError(f"div.Tensor_mode not supported for op {op}") + + +class DecomposeDivTensorModePass(ArmPass): + """ + Rewrites aten.div.Tensor_mode into + + rounding_mode=None -> div(a, b) + rounding_mode='floor' -> floor(div(a, b)) + rounding_mode='trunc' -> where(div(a,b) < 0, ceil(div(a,b)), floor(div(a,b))) + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + edge_div_mode_ops + aten_div_mode_ops + ) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + opset = _get_opset(op) + + a, b = args[0], args[1] + rounding_mode = kwargs.get("rounding_mode", None) + if rounding_mode is None and len(args) > 2: + rounding_mode = args[2] + + q = super().call_operator(opset["div"], (a, b), {}, meta, updated=True) + + if rounding_mode is None: + return q + + if rounding_mode == "floor": + return super().call_operator(opset["floor"], (q,), {}, meta, updated=True) + + if rounding_mode == "trunc": + zero = super().call_operator( + opset["full"], + args=((1,) * len(meta["val"].size()), 0.0), + kwargs={"dtype": torch.float32, "device": meta["val"].device}, + meta=meta, + updated=True, + ) + lt0 = super().call_operator(opset["lt"], (q, zero), {}, meta, updated=True) + ceilq = super().call_operator(opset["ceil"], (q,), {}, meta, updated=True) + floorq = super().call_operator(opset["floor"], (q,), {}, meta, updated=True) + return super().call_operator( + opset["where"], (lt0, ceilq, floorq), {}, meta, updated=True + ) + + raise RuntimeError( + f"Unsupported rounding_mode for div.Tensor_mode: {rounding_mode!r}" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_elu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_elu_pass.py new file mode 100644 index 0000000..5428465 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_elu_pass.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_elu_ops = (exir_ops.edge.aten.elu.default,) + + +def get_elu_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.elu operation into + its equivalent TOSA-supported operations + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + elu(x, y) → where(greater_or_eq(x, 0), (exp(x)-1), x) + + Returns: + A tuple (expm1_op, ge_op, where_op, mul_op) corresponding to the appropriate operator + overloads for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported elu variant. + """ + + if op in edge_elu_ops: + return ( + exir_ops.edge.aten.expm1.default, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.mul.Scalar, + ) + + raise RuntimeError(f"Can't get elu decomposition for op {op}") + + +class DecomposeEluPass(ArmPass): + """ + A transformation pass that decomposes unsupported 'aten.elu' operations + into a combination of supported TOSA-equivalent operations. + + Since TOSA does not provide a native ELU operator, this pass rewrites: + elu(x) → where(greater_or_eq(x, 0), (alpha*(exp(x)-1)), x) + + Supported input ops: + - exir_ops.edge.aten.elu.Tensor(x) + + These are replaced with: + - exir_ops.edge.aten.expm1.default + - exir_ops.edge.aten.ge.Scalar + - exir_ops.edge.aten.where.self + - exir_ops.edge.aten.mul.Scalar + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_elu_ops: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + ( + expm1_op, + ge_op, + where_op, + mul_op, + ) = get_elu_decomposition(op) + + input = args[0] + alpha = args[1] if len(args) > 1 else 1.0 + + if alpha == 0: + relu_op = exir_ops.edge.aten.clamp.default + return super().call_operator( + relu_op, + ( + input, + 0, + ), + {}, + meta, + updated=True, + ) + + expm1_node = super().call_operator(expm1_op, (input,), {}, meta, updated=True) + mul_node = super().call_operator( + mul_op, (expm1_node, alpha), {}, meta, updated=True + ) + ge_node = super().call_operator(ge_op, (input, 0.0), {}, meta, updated=True) + where_node = super().call_operator( + where_op, (ge_node, input, mul_node), {}, meta, updated=True + ) + + return where_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_embedding_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_embedding_pass.py new file mode 100644 index 0000000..5b1f41f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_embedding_pass.py @@ -0,0 +1,126 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from math import prod +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.fuse_view_copy_transform_pass import ( + FuseViewCopyTransformPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +from .arm_pass_utils import create_node, get_first_fake_tensor + +logger = logging.getLogger(__name__) + + +class DecomposeEmbeddingPass(ArmPass): + """ + This pass decomposes embedding into index_select. + + Example: + o = embedding(w, i) + Becomes: + i = view_copy(i) # flatten indices + o = index_select(w, i) + o = view_copy(o) # reshape back output + Note: + i = indices is expected to be int32 before this pass + """ + + _passes_required_after: Set[Type[ExportPass]] = {FuseViewCopyTransformPass} + + aten_ops = (torch.ops.aten.embedding.default,) + edge_ops = (exir_ops.edge.aten.embedding.default,) + + def get_decomposition(self, op): + if op in self.aten_ops: + return ( + torch.ops.aten.reshape.default, + torch.ops.aten.index_select.default, + ) + + if op in self.edge_ops: + return ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.index_select.default, + ) + raise RuntimeError( + f"[{self.__class__.__name__}] Can't get decomposition for op {op}" + ) + + def call(self, graph_module): + graph = graph_module.graph + modified_graph = False + + for node in graph.nodes: + if node.op != "call_function": + continue + if node.target not in self.aten_ops + self.edge_ops: + continue + if not self.allowed_to_transform(node.meta): + continue + + args = node.args + + weights = args[0] + indices = args[1] + + weights_shape = get_first_fake_tensor(weights).shape + indices_shape = get_first_fake_tensor(indices).shape + + output_shape = torch.Size(list(indices_shape) + [weights_shape[1]]) + if output_shape != get_first_fake_tensor(node).shape: + raise RuntimeError( + f"[{self.__class__.__name__}] Unexpected output shape mismatch {output_shape} " + "!= {get_first_fake_tensor(node).shape}" + ) + + view_copy_op, index_select_op = self.get_decomposition(node.target) + + with graph.inserting_before(node): + reshaped_indices = [prod(list(indices_shape))] + flattened_indices = create_node( + graph=graph, + op_target=view_copy_op, + args=(indices, reshaped_indices), + ) + node.replace_input_with(indices, flattened_indices) + + index_select = create_node( + graph=graph, + op_target=index_select_op, + args=(weights, 0, flattened_indices), + ) + node.replace_all_uses_with(index_select) + graph.erase_node(node) + + with graph.inserting_after(index_select): + restored_output = create_node( + graph, + view_copy_op, + ) + restored_output.args = ( + index_select, + output_shape, + ) + original_users = [ + user for user in index_select.users if user != restored_output + ] + for user in original_users: + user.replace_input_with(index_select, restored_output) + + modified_graph = True + + if modified_graph: + graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_expm1_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_expm1_pass.py new file mode 100644 index 0000000..d2eb908 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_expm1_pass.py @@ -0,0 +1,163 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.backends.arm._passes.decompose_int_pow_pass import DecomposeIntPowPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_expm1_ops = (exir_ops.edge.aten.expm1.default,) # MI case + + +def _get_expm1_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.expm1 operation into + its equivalent TOSA-supported operations + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + expm1(x) → where(and(ge(x, -0.35), le(x, 0.35)), {taylor_series_expansion}, (exp(x)-1)) + + where {taylor_series_expansion} = x + (x^2/2) + (x^3/6) + (x^4/24) + + Returns: + A tuple (op_pow, op_div, op_add, op_exp, op_sub, op_ge, op_where, op_le, op_and) + corresponding to the appropriate operator overloads for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported elu variant. + """ + if op in edge_expm1_ops: + return ( + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.div.Scalar, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.logical_and.default, + ) + + raise RuntimeError(f"Can't get expm1 decomposition for op {op}") + + +class DecomposeExpm1Pass(ArmPass): + """ + A transformation pass that decomposes unsupported 'aten.expm1' operations + into a combination of supported TOSA-equivalent operations. + + Since TOSA does not provide a native expm1 operator, this pass rewrites: + expm1(x) → where(and(ge(x, -0.35), le(x, 0.35)), {taylor_series_expansion}, (exp(x)-1)) + where {taylor_series_expansion} = x + (x^2/2) + (x^3/6) + (x^4/24) + + Supported input ops: + - exir_ops.edge.aten.expm1.default(x) + + These are replaced with: + - exir_ops.edge.aten.pow.Tensor_Scalar, + - exir_ops.edge.aten.div.Scalar, + - exir_ops.edge.aten.add.Tensor, + - exir_ops.edge.aten.exp.default, + - exir_ops.edge.aten.sub.Scalar, + - exir_ops.edge.aten.ge.Scalar, + - exir_ops.edge.aten.where.self, + - exir_ops.edge.aten.le.Scalar, + - exir_ops.edge.aten.logical_and.default + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeIntPowPass, + InsertTableOpsPass, + DecomposeDivPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + MatchArgRanksPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_expm1_ops: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + ( + op_pow, + op_div, + op_add, + op_exp, + op_sub, + op_ge, + op_where, + op_le, + op_and, + ) = _get_expm1_decomposition(op) + + input = args[0] + + cutlo = -0.35 + cuthi = 0.35 + + taylor_term_2_numerator = super().call_operator( + op_pow, (input, 2), {}, meta, updated=False + ) + taylor_term_3_numerator = super().call_operator( + op_pow, (input, 3), {}, meta, updated=False + ) + taylor_term_4_numerator = super().call_operator( + op_pow, (input, 4), {}, meta, updated=False + ) + + taylor_term_2 = super().call_operator( + op_div, (taylor_term_2_numerator, 2), {}, meta, updated=False + ) + taylor_term_3 = super().call_operator( + op_div, (taylor_term_3_numerator, 6), {}, meta, updated=False + ) + taylor_term_4 = super().call_operator( + op_div, (taylor_term_4_numerator, 24), {}, meta, updated=False + ) + + add_terms_1_2 = super().call_operator( + op_add, (input, taylor_term_2), {}, meta, updated=False + ) + add_term_3 = super().call_operator( + op_add, (add_terms_1_2, taylor_term_3), {}, meta, updated=False + ) + taylor_expansion = super().call_operator( + op_add, (add_term_3, taylor_term_4), {}, meta, updated=False + ) + + decomp_exp = super().call_operator(op_exp, (input,), {}, meta, updated=False) + decomp_sub = super().call_operator( + op_sub, (decomp_exp, 1.0), {}, meta, updated=False + ) + + ge = super().call_operator(op_ge, (input, cutlo), {}, meta, updated=False) + le = super().call_operator(op_le, (input, cuthi), {}, meta, updated=False) + + cond_and = super().call_operator(op_and, (ge, le), {}, meta, updated=False) + where = super().call_operator( + op_where, (cond_and, taylor_expansion, decomp_sub), {}, meta, updated=True + ) + + return where diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_floor_divide_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_floor_divide_pass.py new file mode 100644 index 0000000..c2754f4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_floor_divide_pass.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_div_tensor_mode import ( + DecomposeDivTensorModePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_floor_divide_ops = (exir_ops.edge.aten.floor_divide.default,) +aten_floor_divide_ops = (torch.ops.aten.floor_divide.default,) + + +def get_floor_divide_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.floor_div operation into + its equivalent TOSA-supported operations + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + floor_div(x, y) → div_tensor_mode(x, y, rounding_mode="floor") + + Returns: + A tuple (div_op,) corresponding to the appropriate operator overload for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported floor_divide variant. + """ + + if op in edge_floor_divide_ops: + return ( + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.full_like.default, + ) + if op in aten_floor_divide_ops: + return ( + torch.ops.aten.div.Tensor_mode, + torch.ops.aten.full_like.default, + ) + + raise RuntimeError(f"Can't get floor_div decomposition for op {op}") + + +class DecomposeFloorDividePass(ArmPass): + """ + Decomposes aten.floor_divide into aten.div.Tensor_mode with rounding_mode="floor". + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivTensorModePass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_floor_divide_ops + aten_floor_divide_ops): + return super().call_operator(op, args, kwargs, meta, updated=False) + + (div_op, full_op) = get_floor_divide_decomposition(op) + + input = args[0] + other = args[1] + + if isinstance(other, int): + other = super().call_operator( + full_op, (input, other), {}, meta, updated=False + ) + + div_node = super().call_operator( + div_op, (input, other), {"rounding_mode": "floor"}, meta, updated=True + ) + + return div_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_gelu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_gelu_pass.py new file mode 100644 index 0000000..5bf3937 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_gelu_pass.py @@ -0,0 +1,172 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +torch_gelu = (torch.ops.aten.gelu.default,) + +edge_gelu = (exir_ops.edge.aten.gelu.default,) + + +def _get_gelu_ops(op) -> tuple: + """ + Returns the operators needed to decompose GELU + """ + + if op in edge_gelu: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.tanh.default, + exir_ops.edge.aten.erf.default, + ) + if op in torch_gelu: + return ( + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + torch.ops.aten.mul.Tensor, + torch.ops.aten.tanh.default, + torch.ops.aten.erf.default, + ) + raise RuntimeError(f"Can't get GeLU decomposition ops for op {op}") + + +class DecomposeGeluPass(ArmPass): + """ + This pass decomposes the GELU operator into primitive ops. + Aiming to adhere closely to the reference implementations built into + ExecuTorch. Including using the same pre-calculated constants. + + This operator has two formulae depending on the value of the + approximate argument. Examples below include the added full + operators necessary for the initialization for constants used in + each respective formula. + + aten.gelu(x, approximate="none") becomes: + %FULL_0_5 = full() + %FULL_1 = full() + %FULL_SQRT1_2 = full() + %op1 = mul(x, %FULL_SQRT1_2) + %op2 = erf(%op1) + %op3 = add(%op2, %FULL_1) + %op4 = mul(%op3, %FULL_0_5) + %op5 = mul(%x, %op4) + + aten.gelu(x, approximate="tanh") becomes: + %FULL_0_5 = full() + %FULL_1 = full() + %FULL_SQRT2 = full() + %FULL_2_SQRTPI = full() + %FULL_CUBE_COEFF = full() + %SQRT_MUL = mul(%FULL_SQRT2, %FULL_2_SQRTPI) + %SQRT_2_PI = mul(%SQRT_MUL, %FULL_0_5) + %sqr_x = mul(x, x) + %cube_x = mul(sqr_x, x) + %op1 = mul(%cube_x, %FULL_CUBE_COEFF) + %op2 = add(%x, %op1) + %op3 = mul(%op2, %SQRT_2_PI) + %op4 = tanh(%op3) + %op5 = add(%op4, %FULL_1) + %op6 = mul(%x, %op5) + %op7 = mul(%op6, %FULL_0_5) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + InsertTableOpsPass, + MatchArgDtypePass, + MatchArgRanksPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in torch_gelu + edge_gelu: + return super().call_operator(op, args, kwargs, meta) + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + full_op, add_op, mul_op, tanh_op, erf_op = _get_gelu_ops(op) + + input = get_node_arg(args, 0) + # If approximate is default (none) it does not appear in kwargs + approximate = get_node_arg(kwargs, "approximate", "none") + + shape = meta["val"].size() + dtype = meta["val"].dtype + + FULL_0_5 = super().call_operator( + full_op, ([1] * len(shape), 0.5), {"dtype": dtype}, meta + ) + FULL_1 = super().call_operator( + full_op, ([1] * len(shape), 1), {"dtype": dtype}, meta + ) + + if approximate == "none": + # Constant mirrors ExecuTorch implementation for parity. + FULL_SQRT1_2 = super().call_operator( + full_op, ([1] * len(shape), 0.70710678118654752440), {}, meta + ) + + op1 = super().call_operator(mul_op, (input, FULL_SQRT1_2), {}, meta) + op2 = super().call_operator(erf_op, (op1,), {}, meta) + op3 = super().call_operator(add_op, (op2, FULL_1), {}, meta) + op4 = super().call_operator(mul_op, (op3, FULL_0_5), {}, meta) + return super().call_operator(mul_op, (input, op4), {}, meta) + + elif approximate == "tanh": + # Constants mirror ExecuTorch implementation for parity. + FULL_SQRT2 = super().call_operator( + full_op, + ([1] * len(shape), 1.41421356237309504880), + {"dtype": dtype}, + meta, + ) + FULL_2_SQRTPI = super().call_operator( + full_op, + ([1] * len(shape), 1.12837916709551257390), + {"dtype": dtype}, + meta, + ) + FULL_CUBE_COEFF = super().call_operator( + full_op, ([1] * len(shape), 0.044715), {"dtype": dtype}, meta + ) + + # Mirrors ExecuTorch implementations for calculating this value + SQRT_MUL = super().call_operator( + mul_op, (FULL_SQRT2, FULL_2_SQRTPI), {}, meta + ) + SQRT_2_PI = super().call_operator(mul_op, (SQRT_MUL, FULL_0_5), {}, meta) + + # Avoiding using POW in order to reduce pass order reliance. + sqr_x = super().call_operator(mul_op, (input, input), {}, meta) + cube_x = super().call_operator(mul_op, (sqr_x, input), {}, meta) + op1 = super().call_operator(mul_op, (cube_x, FULL_CUBE_COEFF), {}, meta) + op2 = super().call_operator(add_op, (input, op1), {}, meta) + op3 = super().call_operator(mul_op, (op2, SQRT_2_PI), {}, meta) + op4 = super().call_operator(tanh_op, (op3,), {}, meta) + op5 = super().call_operator(add_op, (op4, FULL_1), {}, meta) + op6 = super().call_operator(mul_op, (input, op5), {}, meta) + return super().call_operator(mul_op, (op6, FULL_0_5), {}, meta) + else: + raise RuntimeError( + f"approximate argument expected 'none' or 'tanh' but got {approximate}" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_glu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_glu_pass.py new file mode 100644 index 0000000..2143b5d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_glu_pass.py @@ -0,0 +1,81 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For FP case +edge_glu = exir_ops.edge.aten.glu.default + +# For INT case +aten_glu = torch.ops.aten.glu.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_glu: + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sigmoid.default, + exir_ops.edge.aten.slice_copy.Tensor, + ) + elif op == aten_glu: + return ( + torch.ops.aten.mul.Tensor, + torch.ops.aten.sigmoid.default, + torch.ops.aten.slice_copy.Tensor, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeGluPass(ArmPass): + """Decomposes the GLU operator into hadamard product and sigmoid.""" + + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in [edge_glu, aten_glu] or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + hadamard_prod, sigmoid, slice_op = get_ops(op) + X = args[0] + + dim = args[1] if len(args) > 1 else kwargs.get("dim", -1) + + if "val" not in X.node.meta: + raise Exception("Could not get dimension metadata in input.") + + if dim < 0: + dim += X.node.meta["val"].dim() + + n = X.node.meta["val"].size(dim) + + if n % 2: + raise RuntimeError( + f"glu expects an even split along dim={dim}, got size {n}" + ) + + middle = n // 2 + + T1 = super().call_operator( + slice_op, (X, dim, 0, middle), {}, meta, updated=True + ) + + T2 = super().call_operator( + slice_op, (X, dim, middle, n), {}, meta, updated=True + ) + + T2_sigmoid = super().call_operator(sigmoid, (T2,), {}, meta, updated=True) + + return super().call_operator( + hadamard_prod, (T1, T2_sigmoid), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_grouped_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_grouped_conv_pass.py new file mode 100644 index 0000000..a0765b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_grouped_conv_pass.py @@ -0,0 +1,185 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from copy import copy +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.conv1d_unsqueeze_pass import Conv1dUnsqueezePass +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeGroupedConvPass(ArmPass): + """ + Splits a grouped convolution which is not supported by TOSA into multiple + convolutions using slice->conv->cat. + + Before pass: + x = conv(input, weight, bias, groups = 2) + + After pass: + input1 = slice(input) + weight1 = slice(weight) + bias1 = slice(bias) + x1 = conv(input1, weight1, bias1) + + input2 = slice(input) + weight2 = slice(weight) + bias2 = slice(bias) + x2 = conv(input2, weight2, bias2) + + x = cat(x1, x2) + """ + + _passes_required_after: Set[Type[ExportPass]] = {Conv1dUnsqueezePass} + + @staticmethod + def _get_decomposition(op): + match op: + case exir_ops.edge.aten.convolution.default: + return ( + exir_ops.edge.aten.slice_copy.Tensor, + exir_ops.edge.aten.convolution.default, + exir_ops.edge.aten.cat.default, + ) + case torch.ops.aten.conv2d.default: + return ( + torch.ops.aten.slice_copy.Tensor, + torch.ops.aten.conv2d.default, + torch.ops.aten.cat.default, + ) + case _: + raise RuntimeError("Invalid op for grouped conv decomposition") + + @staticmethod + def _split_per_channel_qparams(qarg, index, output_slice_size): + if qarg is not None and qarg.per_channel: + start_index = index * output_slice_size + stop_index = (index + 1) * output_slice_size + return QuantArgs( + scale=qarg.scale[start_index:stop_index], + zp=qarg.zp[start_index:stop_index], + qmin=qarg.qmin, + qmax=qarg.qmax, + dtype=qarg.dtype, + axis=qarg.axis, + per_channel=qarg.per_channel, + ) + return qarg + + @staticmethod + def _get_meta_copy(meta, i, output_slice_size): + meta_copy = meta.copy() + if "input_qparams" in meta.data and len(meta.data["input_qparams"]) > 0: + # Handle per-channel quantization by splitting quantization params + # similarly to how activations/weights/biases are split. + new_qparams = meta.data.get("input_qparams").copy() + # Get quantization params of the weights and slice them. + qarg = new_qparams[1] + new_qparams[1] = DecomposeGroupedConvPass._split_per_channel_qparams( + qarg, index=i, output_slice_size=output_slice_size + ) + + meta_copy.data["input_qparams"] = new_qparams + + return meta_copy + + def call_operator(self, op, args, kwargs, meta): + if op == exir_ops.edge.aten.convolution.default: + groups = args[8] + transposed = args[6] + elif op == torch.ops.aten.conv2d.default: + groups = args[6] + transposed = False + else: + return super().call_operator(op, args, kwargs, meta) + + if groups == 1 or transposed: + return super().call_operator(op, args, kwargs, meta) + + input_node = args[0] + if input_node.data.shape[1] == groups: + # This is a depthwise convolution which is handled elsewhere + return super().call_operator(op, args, kwargs, meta) + + weight_node = args[1] + bias_node = args[2] + + input_slice_size = weight_node.data.shape[1] + output_slice_size = weight_node.data.shape[0] // groups + + no_q_dq_meta = copy(meta) + no_q_dq_meta.data = {} + no_q_dq_meta.data = {} + + slice_op, conv_op, cat_op = DecomposeGroupedConvPass._get_decomposition(op) + + input_slices = [] + for i in range(groups): + start_index = i * input_slice_size + stop_index = (i + 1) * input_slice_size + slice_args = (input_node, 1, start_index, stop_index) + + input_slices.append( + super().call_operator( + slice_op, slice_args, kwargs, no_q_dq_meta, updated=True + ) + ) + + filter_slices = [] + for i in range(groups): + start_index = i * output_slice_size + stop_index = (i + 1) * output_slice_size + slice_args = (weight_node, 0, start_index, stop_index) + + filter_slices.append( + super().call_operator( + slice_op, slice_args, kwargs, no_q_dq_meta, updated=True + ) + ) + + bias_slices = [] + for i in range(groups): + if bias_node is None: + bias_slices.append(None) + else: + start_index = i * output_slice_size + stop_index = (i + 1) * output_slice_size + slice_args = (bias_node, 0, start_index, stop_index) + + bias_slices.append( + super().call_operator( + slice_op, slice_args, kwargs, no_q_dq_meta, updated=True + ) + ) + + output_slices = [] + for i, (input_slice, filter_slice, bias_slice) in enumerate( + zip(input_slices, filter_slices, bias_slices) + ): + + meta_copy = DecomposeGroupedConvPass._get_meta_copy( + meta, i, output_slice_size + ) + + if op == exir_ops.edge.aten.convolution.default: + conv_args = (input_slice, filter_slice, bias_slice, *args[3:8], 1) + elif op == torch.ops.aten.conv2d.default: + conv_args = (input_slice, filter_slice, bias_slice, *args[3:6], 1) + else: + raise RuntimeError("Invalid op for grouped conv decomposition") + + output_slices.append( + super().call_operator( + conv_op, conv_args, kwargs, meta_copy, updated=True + ) + ) + + cat_args = (output_slices, 1) + # propagate original metadata (including quantization params) to the concatenated output + return super().call_operator(cat_op, cat_args, kwargs, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_groupnorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_groupnorm_pass.py new file mode 100644 index 0000000..322f694 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_groupnorm_pass.py @@ -0,0 +1,227 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_meandim_pass import DecomposeMeanDimPass +from executorch.backends.arm._passes.decompose_var_pass import DecomposeVarPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +def get_group_norm_decomposition(op) -> tuple: + if op == exir_ops.edge.aten.native_group_norm.default: + return ( + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.var.correction, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.view_copy.default, + ) + if op == torch.ops.aten.group_norm.default: + return ( + torch.ops.aten.mean.dim, + torch.ops.aten.sub.Tensor, + torch.ops.aten.var.correction, + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + torch.ops.aten.rsqrt.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.reshape.default, + ) + raise RuntimeError(f"Can't get group_norm composition for op {op}") + + +class DecomposeGroupNormPass(ArmPass): + """ + groupnorm is defined as: ((x - E[x]) / sqrt(Var[x] + eps)) * weights + bias + Decompose groupnorm(x, weight, bias, N, C, HxW, group, eps) to a sequence of: + mean = op_mean(x, dims) # E[x] + var = op_var(x, dims) # Var[x] + numerator = op_sub(x, mean) # (x - E[x]) + add = op_add(var, eps) # Var[x] + eps + rsqrt = op_rsqrt(add) # 1 / sqrt(Var[x] + eps) + mul = op_mul(numerator, rsqrt) # ((x - E[x]) / sqrt(Var[x] + eps)) + weigths = op_mul(mul, weigths) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias = op_add(weigths, bias) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias + where x can viewed with shape [N, group, C//group, HxW] dims=[C//group, HxW] + + Source: https://pytorch.org/docs/stable/generated/torch.nn.GroupNorm.html + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + DecomposeMeanDimPass, + DecomposeVarPass, + SizeAdjustInputPass, + } + + _TARGET_OPS = { + exir_ops.edge.aten.native_group_norm.default, + torch.ops.aten.group_norm.default, + } + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in DecomposeGroupNormPass._TARGET_OPS + or not self.allowed_to_transform(node.meta) + ): + continue + + # epsilon default value + eps = torch.finfo().eps + weights = None + bias = None + args = node.args + meta = node.meta + if isinstance(meta["val"], tuple): + shape = meta["val"][0].size() + dtype = meta["val"][0].dtype + device = meta["val"][0].device + else: + shape = meta["val"].size() + dtype = meta["val"].dtype + device = meta["val"].device + match len(args): + # MI profile always provides all the args: x, weight, bias, N, C, HxW, group, eps + case 8: + x, weights, bias, N, C, HxW, group, eps = args + # BI profile: affine=[True|False], eps!=1e-5 + case 5: + x, group, weights, bias, eps = args + # BI profile: affine=True, eps=1e-5 + case 4: + x, group, weights, bias = args + # BI profile: affine=False, eps=1e=5 + case 2: + x, group = args + # Unsupported args + case _: + raise ValueError( + f"Unsupported group_norm argument pattern with {len(args)} args" + ) + N = shape[0] + C = shape[1] + HxW = 1 + for dim in shape[2:]: + HxW *= dim + channels_per_group = C // group + grouped_shape = torch.Size([N, group, channels_per_group, HxW]) + dims = [2, 3] + epsilon_reshaped_shape = torch.Size([1] * len(grouped_shape)) + weights_reshaped_shape = torch.Size([1, group, channels_per_group, 1]) + ( + mean_op, + sub_op, + var_op, + full_op, + add_op, + rsqrt_op, + mul_op, + view_op, + ) = get_group_norm_decomposition(node.target) + with graph_module.graph.inserting_before(node): + keepdim = True + x_reshaped = create_node( + graph_module.graph, + view_op, + args=(x, grouped_shape), + from_node=node, + ) + mean = create_node( + graph_module.graph, mean_op, args=(x_reshaped, dims, keepdim) + ) + sub = create_node(graph_module.graph, sub_op, args=(x_reshaped, mean)) + var = create_node( + graph_module.graph, + var_op, + args=(x_reshaped, dims), + kwargs={"correction": 0, "keepdim": keepdim}, + from_node=node, + ) + full = create_node( + graph_module.graph, + full_op, + args=(epsilon_reshaped_shape, eps), + kwargs={"dtype": dtype, "device": device}, + from_node=node, + ) + add0 = create_node( + graph_module.graph, add_op, args=(var, full), from_node=node + ) + rsqrt = create_node( + graph_module.graph, rsqrt_op, args=(add0,), from_node=node + ) + mul0 = create_node( + graph_module.graph, mul_op, args=(sub, rsqrt), from_node=node + ) + if weights is not None: + weights_reshaped = create_node( + graph_module.graph, + view_op, + args=(weights, weights_reshaped_shape), + from_node=node, + ) + mul1 = create_node( + graph_module.graph, + mul_op, + args=( + mul0, + weights_reshaped, + ), + from_node=node, + ) + else: + mul1 = mul0 + if bias is not None: + bias_reshaped_shape = weights_reshaped_shape + bias_reshaped = create_node( + graph_module.graph, + view_op, + args=(bias, bias_reshaped_shape), + from_node=node, + ) + output = create_node( + graph_module.graph, + add_op, + args=(mul1, bias_reshaped), + from_node=node, + ) + else: + output = mul1 + + output_reshaped = create_node( + graph_module.graph, + view_op, + args=(output, shape), + from_node=node, + ) + + users = [user for user in node.users if node != user] + node.replace_all_uses_with(output_reshaped) + for user in users: + if user.target == operator.getitem: + user.replace_all_uses_with(output_reshaped) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + modified = True + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int16_activation_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int16_activation_conv_pass.py new file mode 100644 index 0000000..0a8c5ee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int16_activation_conv_pass.py @@ -0,0 +1,137 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Sequence, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.quant_args import QuantArgs + +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeConvWithInt16ActivationPass(ArmPass): + """ + This pass decomposes a convolution with input dtype int16 and bias + into a convolution without bias followed by an addition of the bias. + We also reshape the 1D bias to [1, C, 1, …] so it broadcasts along the channel + dimension. Since the TOSA op requires the bias to be int48 which is hard to represent + in torch. Instead rescale the int48 output to int16 and add the bias in int16. + """ + + def __init__(self) -> None: + super().__init__() + + _passes_required_after: Set[Type[ExportPass]] = set() + + def bias_view_shape( + self, bias: torch.Tensor, activation_rank: int + ) -> Sequence[int]: + # reshape bias to match convolution output rank so addition broadcasts over channels + return [1, bias.shape[0], *([1] * (activation_rank - 2))] + + def call_operator(self, op, args, kwargs, meta): + if op != exir_ops.edge.aten.convolution.default: + return super().call_operator(op, args, kwargs, meta) + + tosa_spec = get_context_spec() + if not tosa_spec.support_integer(): + return super().call_operator(op, args, kwargs, meta) + + # return if no bias + if args[2] is None: + return super().call_operator(op, args, kwargs, meta) + + activation_tensor = args[0].data + activation_rank = activation_tensor.dim() + + if activation_rank not in (4, 5) or activation_tensor.dtype != torch.int16: + return super().call_operator(op, args, kwargs, meta) + + if not tosa_spec.support_extension("int16"): + raise ValueError( + "int16 activation for convolution requires TOSA int16 extension" + ) + + # convolution with bias and activation is int16 (expected activation rank enforced above) + # The bias is assumed to be quantized with the same quantization parameters as + # the output of the convolution + bias_arg = args[2] + bias_data = bias_arg.data + + no_bias_args = list(args) + no_bias_args[2] = None + # split up to convolution + bias + convolution = super().call_operator(op, tuple(no_bias_args), kwargs, meta) + + # create a copy of the meta without the qparams, to be used with the new nodes + new_meta = meta.copy() + new_meta.data.pop("output_qparams", None) + new_meta.data.pop("input_qparams", None) + + # reshape the tensor to the same rank as the convolution output to add the bias to the channels + channel_bias = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (bias_arg, self.bias_view_shape(bias_data, activation_rank)), + {}, + new_meta, + ) + + output_dtype = meta.data["output_qparams"][0].dtype + + if output_dtype == torch.int16: + # The conv will get the output int48 scaled to int32 in serialization step. + # To be able to add the bias we need to first scale (cast?) the output to int32. + # The resulting i32 sum will then need to be scaled back to the output dtype. + output_qparams = cast(QuantArgs, meta.data["output_qparams"][0]) + conv_output_scale = output_qparams.scale + + bias_qparams = cast(QuantArgs, meta.data["input_qparams"][2]) + per_channel_quant = bias_qparams.per_channel + + if per_channel_quant: + bias_scale = bias_qparams.get_scale_per_channel() + else: + bias_scale = [bias_qparams.get_scale_per_tensor()] + + conv_rescale_factors = [1.0] * len(bias_scale) + final_output_scale = [b / conv_output_scale for b in bias_scale] + + conv_output = super().call_operator( + exir_ops.backend.tosa.RESCALE.default, + (convolution, torch.int32, conv_rescale_factors, 0, 0), + {}, + new_meta, + ) + + add = super().call_operator( + exir_ops.edge.aten.add.Tensor, + (conv_output, channel_bias), + {}, + new_meta, + ) + + res_rescale = super().call_operator( + exir_ops.backend.tosa.RESCALE.default, + ( + add, + output_dtype, + final_output_scale, + 0, + 0, + ), + {}, + new_meta, + ) + + else: + raise NotImplementedError( + f"Decomposition to conv+add only implemented for activation of int16 type, not for {output_dtype}" + ) + + return res_rescale diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int_pow_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int_pow_pass.py new file mode 100644 index 0000000..4db5e45 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_int_pow_pass.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeIntPowPass(ArmPass): + """ + Replaces pow with integer exponent with a series of multiplications. + Only handles pow.Tensor_Scalar and not pow.Tensor_Tensor. + Needs to be run before doing scalar to tensor conversion. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op != exir_ops.edge.aten.pow.Tensor_Scalar: + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + exp = args[1] + + # Handle zero first and return early + if exp == 0: + # return a tensor of ones with the same shape as x + return super().call_operator( + exir_ops.edge.aten.full_like.default, (x, 1), {}, meta, True + ) + + if not isinstance(exp, int): + return super().call_operator(op, args, kwargs, meta) + + # Handle negative exponent + if exp < 0: + x = super().call_operator( + exir_ops.edge.aten.reciprocal.default, (x,), {}, meta, True + ) + exp = -exp + + res = x + + # Consider exponentiation by squaring, if exp turns out to be large. + # Now we just roll out the multiplications. + for _ in range(exp - 1): + res = super().call_operator( + exir_ops.edge.aten.mul.Tensor, (res, x), {}, meta, True + ) + + return res diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_layernorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_layernorm_pass.py new file mode 100644 index 0000000..992b21f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_layernorm_pass.py @@ -0,0 +1,203 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_meandim_pass import DecomposeMeanDimPass +from executorch.backends.arm._passes.decompose_var_pass import DecomposeVarPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +def get_layer_norm_decomposition(op) -> tuple: + if op == exir_ops.edge.aten.native_layer_norm.default: + return ( + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.var.correction, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.view_copy.default, + ) + if op == torch.ops.aten.layer_norm.default: + return ( + torch.ops.aten.mean.dim, + torch.ops.aten.sub.Tensor, + torch.ops.aten.var.correction, + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + torch.ops.aten.rsqrt.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.reshape.default, + ) + raise RuntimeError(f"Can't get layer_norm composition for op {op}") + + +class DecomposeLayerNormPass(ArmPass): + """ + layernorm is defined as: ((x - E[x]) / sqrt(Var[x] + eps)) * weights + bias + Decompose layernorm(x, normalized_shape, weights, bias, eps) to a sequence of: + mean = op_mean(x, dims) # E[x] + var = op_var(x, dims) # Var[x] + numerator = op_sub(x, mean) # (x - E[x]) + add = op_add(var, eps) # Var[x] + eps + rsqrt = op_rsqrt(add) # 1 / sqrt(Var[x] + eps) + mul = op_mul(numerator, rsqrt) # ((x - E[x]) / sqrt(Var[x] + eps)) + weigths = op_mul(mul, weigths) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias = op_add(weigths, bias) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias + + Source: https://pytorch.org/docs/stable/generated/torch.nn.LayerNorm.html + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + DecomposeMeanDimPass, + DecomposeVarPass, + InsertTableOpsPass, + } + + _TARGET_OPS = { + exir_ops.edge.aten.native_layer_norm.default, + torch.ops.aten.layer_norm.default, + } + + def call(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in DecomposeLayerNormPass._TARGET_OPS + or not self.allowed_to_transform(node.meta) + ): + continue + + # epsilon default value + epsilon = torch.finfo().eps + weights = None + bias = None + args = node.args + meta = node.meta + match len(args): + case 6: + # torch.ops.aten.layer_norm.default has 6 args: + # (input, normalized_shape, weight, bias, eps, cudnn_enable) + # cudnn_enable is not used in the decomposition + x, normalized_shape, weights, bias, epsilon, _cudnn_enable = args + case 5: + x, normalized_shape, weights, bias, epsilon = args + case 4: + x, normalized_shape, weights, bias = args + case 3: + x, normalized_shape, weights = args + case _: + x, normalized_shape = args + + n_dims = len(normalized_shape) + if isinstance(meta["val"], tuple): + shape = meta["val"][0].size() + dtype = meta["val"][0].dtype + device = meta["val"][0].device + else: + shape = meta["val"].size() + dtype = meta["val"].dtype + device = meta["val"].device + rank = len(shape) + dims = list(range(-1, -1 * (n_dims + 1), -1)) + dims = [dim % rank for dim in dims] + weights_reshaped_shape = [shape[i] if i in dims else 1 for i in range(rank)] + epsilon_reshaped_shape = [1] * rank + + ( + mean_op, + sub_op, + var_op, + full_op, + add_op, + rsqrt_op, + mul_op, + view_op, + ) = get_layer_norm_decomposition(node.target) + with graph_module.graph.inserting_before(node): + keepdim = True + mean = create_node(graph_module.graph, mean_op, args=(x, dims, keepdim)) + sub = create_node(graph_module.graph, sub_op, args=(x, mean)) + var = create_node( + graph_module.graph, + var_op, + args=(x, dims), + kwargs={"correction": 0, "keepdim": keepdim}, + from_node=node, + ) + full = create_node( + graph_module.graph, + full_op, + args=(epsilon_reshaped_shape, epsilon), + kwargs={"dtype": dtype, "device": device}, + from_node=node, + ) + add0 = create_node( + graph_module.graph, add_op, args=(var, full), from_node=node + ) + rsqrt = create_node( + graph_module.graph, rsqrt_op, args=(add0,), from_node=node + ) + mul0 = create_node( + graph_module.graph, mul_op, args=(sub, rsqrt), from_node=node + ) + if weights is not None: + weights_reshaped = create_node( + graph_module.graph, + view_op, + args=(weights, weights_reshaped_shape), + from_node=node, + ) + mul1 = create_node( + graph_module.graph, + mul_op, + args=( + mul0, + weights_reshaped, + ), + from_node=node, + ) + else: + mul1 = mul0 + output = mul1 + if bias is not None: + bias_reshaped_shape = weights_reshaped_shape + bias_reshaped = create_node( + graph_module.graph, + view_op, + args=(bias, bias_reshaped_shape), + from_node=node, + ) + output = create_node( + graph_module.graph, + add_op, + args=(mul1, bias_reshaped), + from_node=node, + ) + + users = [user for user in node.users if node != user] + node.replace_all_uses_with(output) + for user in users: + if user.target == operator.getitem: + user.replace_all_uses_with(output) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_leaky_relu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_leaky_relu_pass.py new file mode 100644 index 0000000..3e52efe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_leaky_relu_pass.py @@ -0,0 +1,76 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_ops = (exir_ops.edge.aten.leaky_relu.default,) +torch_ops = (torch.ops.aten.leaky_relu.default,) + + +def _get_leaky_relu_ops(op) -> tuple: + if op in edge_ops: + return ( + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.add.Tensor, + ) + elif op in torch_ops: + return ( + torch.ops.aten.clamp.default, + torch.ops.aten.full.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.add.Tensor, + ) + else: + raise RuntimeError(f"Can't get decomposition ops for op {op}") + + +class DecomposeLeakyReLUPass(ArmPass): + """ + This pass decomposes Leaky ReLU into primitive operations. + LeakyReLU(x,slope) = max(0,x) + slope * min(0,x) + + Example: + %op1 = clamp(x,0,None) (equivalent to max(0,x)) + %op2 = clamp(x,None,0) (equivalent to min(0,x)) + %op3 = full(x.shape,slope) + %op4 = mul(%op3,%op2) + %op5 = add(%op1,%op4) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_ops + torch_ops) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + slope = args[1] if len(args) > 1 else 0.01 + dtype = x.node.meta["val"].dtype + device = x.node.meta["val"].device + clamp, full, mul, add = _get_leaky_relu_ops(op) + op1 = super().call_operator( + op=clamp, args=(x, 0, None), kwargs=kwargs, meta=meta + ) + op2 = super().call_operator( + op=clamp, args=(x, None, 0), kwargs=kwargs, meta=meta + ) + op3 = super().call_operator( + op=full, + args=(x.node.meta["val"].shape, slope), + kwargs={"dtype": dtype, "device": device}, + meta=meta, + ) + op4 = super().call_operator(op=mul, args=(op3, op2), kwargs=kwargs, meta=meta) + op5 = super().call_operator(op=add, args=(op1, op4), kwargs=kwargs, meta=meta) + return op5 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linalg_vector_norm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linalg_vector_norm_pass.py new file mode 100644 index 0000000..d766866 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linalg_vector_norm_pass.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.exir.pass_base import ExportPass + + +class DecomposeLinalgVectorNormPass(ArmPass): + """ + This pass decomposes aten.linalg_vector_norm.default into more primitive ops. + We need to add this pass before quantization for graph annotation. + By default, aten.linalg_vector_norm op is decomposed during legalization to Edge IR. + + The decomposition is as follows: + + For p == 1: + out = REDUCE_SUM(ABS(x), dims, keepdim) + + For p == 2: + out = SQRT(REDUCE_SUM(MUL(x, x), dims, keepdim)) + + For arbitrary p: + We dont support arbitrary p, because our decomposition looks like + out = POW(REDUCE_SUM(POW(ABS(x), p), dims, keepdim), 1/p) + In this case we need to wrap p into Tensor and we need to know + dtype prior, but we dont know this from FX graph. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + DecomposeSumPass, + } + + torch_linalg_vector_norm = (torch.ops.aten.linalg_vector_norm.default,) + + def call_operator(self, op, args, kwargs, meta): + if op not in self.torch_linalg_vector_norm or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + # Extract inputs and optional arguments. + # Expected args: + # args[0]: input tensor + # args[1]: norm order 'p' (optional, default: 2.0) + # args[2]: dimensions to reduce (should be provided) + # args[3]: keepdim flag (optional, default: False) + input_tensor = args[0] + norm_order = args[1] if len(args) > 1 else 2.0 + norm_dim = args[2] if len(args) > 2 else None + keepdim = args[3] if len(args) > 3 else False + + if norm_order not in (1, 2): + raise ValueError( + f"The order of {norm_order}\n" + f"is not supported for linalg_vector_norm operator" + ) + + # Sum over all dimensions if dim is None + if norm_dim is None: + rank = input_tensor.data.dim() + dims = list(range(rank)) + else: + dims = [norm_dim] if isinstance(norm_dim, int) else list(norm_dim) + + # Decomposition based on norm order. + if norm_order == 1: + op1 = super().call_operator( + torch.ops.aten.abs.default, (input_tensor,), {}, meta + ) + op2 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (op1, dims, keepdim), {}, meta + ) + return op2 + + elif norm_order == 2: + # For p == 2, decomposition is sqrt(sum(x * x, dims, keepdim)) + op1 = super().call_operator( + torch.ops.aten.mul.Tensor, (input_tensor, input_tensor), {}, meta + ) + op2 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (op1, dims, keepdim), {}, meta + ) + op3 = super().call_operator(torch.ops.aten.sqrt.default, (op2,), {}, meta) + return op3 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linear_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linear_pass.py new file mode 100644 index 0000000..e1a9cfd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_linear_pass.py @@ -0,0 +1,109 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import numpy as np +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.insert_rescales_pass import InsertRescaleInt32Pass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeLinearPass(ArmPass): + """ + This pass decomposes linear into a Conv2D with the required view operations. + linear(x, weights, bias) becomes: + x_reshaped = view(x) + weights_reshaped = view(weights) + conv2d = conv2d(x_reshaped, weights_reshaped, bias) + output = view(conv2d) + """ + + _passes_required_after: Set[Type[ExportPass]] = {InsertRescaleInt32Pass} + + def call(self, graph_module): + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target != exir_ops.edge.aten.linear.default: + continue + args = node.args + input = args[0] + weights = args[1] + bias = args[2] if len(args) > 2 else None + output_shape = get_first_fake_tensor(node).shape + input_shape = get_first_fake_tensor(input).shape + weights_shape = get_first_fake_tensor(weights).shape + batches = int(np.prod(input_shape[:-1])) if len(input_shape) > 1 else 1 + # input has shape (..., Ci) + input_reshaped_shape = [batches, input_shape[-1], 1, 1] + # weights have shape (Co, Ci) + weights_reshaped_shape = [weights_shape[0], weights_shape[1], 1, 1] + + with graph_module.graph.inserting_before(node): + # Reshape input to 4D with shape (N, Ci, 1, 1) + input_reshaped = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.view_copy.default, + args=(input, input_reshaped_shape), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + + # Reshape weights to 4D with shape (Co, Ci, 1, 1) + weights_reshaped = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.view_copy.default, + args=(weights, weights_reshaped_shape), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + + conv = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.convolution.default, + args=( + input_reshaped, + weights_reshaped, + bias, + [1, 1], # strides + [0, 0], # padding + [1, 1], # dilation + False, # transposed + [0, 0], # output padding + 1, # groups + ), + kwargs={}, + from_node=node, + inherit_qparams=True, + ) + + with graph_module.graph.inserting_after(conv): + # Reshape output to same rank as original input with shape (..., Co) + # No need to insert q/dq pair as Conv2D node above has inserted them if + # required. + output = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.view_copy.default, + args=(conv, list(output_shape)), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + + node.replace_all_uses_with(output) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_log1p_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_log1p_pass.py new file mode 100644 index 0000000..4531d66 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_log1p_pass.py @@ -0,0 +1,97 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeLog1pPass(ArmPass): + """Decompose log1p into a small polynomial with a log fallback for larger inputs.""" + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + _supported_ops = { + exir_ops.edge.aten.log1p.default, + } + + def _poly(self, x, meta): + # 6-term Taylor: x - x^2/2 + x^3/3 - x^4/4 + x^5/5 - x^6/6 + op_mul = exir_ops.edge.aten.mul.Tensor + op_mul_scalar = exir_ops.edge.aten.mul.Scalar + op_add = exir_ops.edge.aten.add.Tensor + + x2 = super().call_operator(op_mul, (x, x), {}, meta, updated=True) + x3 = super().call_operator(op_mul, (x2, x), {}, meta, updated=True) + x4 = super().call_operator(op_mul, (x3, x), {}, meta, updated=True) + x5 = super().call_operator(op_mul, (x4, x), {}, meta, updated=True) + x6 = super().call_operator(op_mul, (x5, x), {}, meta, updated=True) + + t2 = super().call_operator(op_mul_scalar, (x2, -0.5), {}, meta, updated=True) + t3 = super().call_operator( + op_mul_scalar, (x3, 1.0 / 3.0), {}, meta, updated=True + ) + t4 = super().call_operator(op_mul_scalar, (x4, -0.25), {}, meta, updated=True) + t5 = super().call_operator(op_mul_scalar, (x5, 0.2), {}, meta, updated=True) + t6 = super().call_operator( + op_mul_scalar, (x6, -1.0 / 6.0), {}, meta, updated=True + ) + + acc = super().call_operator(op_add, (x, t2), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t3), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t4), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t5), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t6), {}, meta, updated=True) + return acc + + def call_operator(self, op, args, kwargs, meta): + if op not in self._supported_ops: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # Quantized log1p should be handled by LUT/table instead of decomposition. + return super().call_operator(op, args, kwargs, meta) + + logging.info("Decomposing log1p via polynomial + log branch for FP profile.") + + x = args[0] + approx = self._poly(x, meta) + + # For x > 1e-3, use log(1+x) directly. + op_add_scalar = exir_ops.edge.aten.add.Scalar + op_gt = exir_ops.edge.aten.gt.Scalar + op_where = exir_ops.edge.aten.where.self + op_log = exir_ops.edge.aten.log.default + + one_plus_x = super().call_operator( + op_add_scalar, (x, 1.0), {}, meta, updated=True + ) + log_branch = super().call_operator( + op_log, (one_plus_x,), {}, meta, updated=True + ) + + mask = super().call_operator(op_gt, (x, 1e-3), {}, meta, updated=True) + result = super().call_operator( + op_where, (mask, log_branch, approx), {}, meta, updated=True + ) + return result diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_logit_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_logit_pass.py new file mode 100644 index 0000000..f469b84 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_logit_pass.py @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For FP case +edge_logit = exir_ops.edge.aten.logit.default +# For INT case +aten_logit = torch.ops.aten.logit.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_logit: + return ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.clamp.default, + ) + elif op == aten_logit: + return ( + torch.ops.aten.log.default, + torch.ops.aten.add.Scalar, + torch.ops.aten.reciprocal.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.mul.Scalar, + torch.ops.aten.clamp.default, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeLogitPass(ArmPass): + """ + Decomposes the `logit` operator into a sequence of primitive operations. + + If `eps` is provided, the input tensor `x` is first clamped to the range + [eps, 1 - eps]. + + The decomposition follows the identity: + + logit(x) = log(x / (1 - x)) + + Examples: + + logit(x) becomes: + log(x * reciprocal((-1) * x + 1)) + + logit(x, eps) becomes: + y = clamp(x, eps, 1 - eps) + log(y * reciprocal((-1) * y + 1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + _TARGET_OPS = { + edge_logit, + aten_logit, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in DecomposeLogitPass._TARGET_OPS or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + X = args[0] + eps = args[1] if len(args) > 1 else kwargs.get("eps", None) + + ( + log_op, + add_scalar_op, + recip_op, + mul_tensor_op, + mul_scalar_op, + clamp_op, + ) = get_ops(op) + + if eps is not None: + X = super().call_operator( + clamp_op, (X, eps, 1.0 - eps), {}, meta, updated=True + ) + + neg_X = super().call_operator(mul_scalar_op, (X, -1.0), {}, meta, updated=True) + + denom = super().call_operator( + add_scalar_op, (neg_X, 1.0), {}, meta, updated=True + ) + + frac = super().call_operator(recip_op, (denom,), {}, meta, updated=True) + + log_input = super().call_operator( + mul_tensor_op, (X, frac), {}, meta, updated=True + ) + + return super().call_operator(log_op, (log_input,), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_masked_fill_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_masked_fill_pass.py new file mode 100644 index 0000000..49a4bbb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_masked_fill_pass.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_full_like_to_full_pass import ( + ConvertFullLikeToFullPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_ops = (exir_ops.edge.aten.masked_fill.Scalar,) +aten_ops = (torch.ops.aten.masked_fill.Scalar, torch.ops.aten.masked_fill_.Scalar) + + +def _get_decomposition(op) -> tuple: + if op in edge_ops: + return ( + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.full_like.default, + ) + elif op in aten_ops: + return ( + torch.ops.aten.where.self, + torch.ops.aten.full_like.default, + ) + raise RuntimeError(f"Unable to get decomposition for op {op}") + + +class DecomposeMaskedFillPass(ArmPass): + """ + Masked fill takes in a boolean mask, a tensor and a scalar value. + Fills the tensor with the scalar value according to the boolean mask. + Decomposed to a where and a full_like operator. + """ + + _passes_required_after: Set[Type[ExportPass]] = {ConvertFullLikeToFullPass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op not in (*aten_ops, *edge_ops): + return super().call_operator(op, args, kwargs, meta, updated) + + x, mask, scalar = args + + where_op, full_like_op = _get_decomposition(op) + + scalar_tensor = super().call_operator(full_like_op, (x, scalar), {}, meta, True) + + return super().call_operator( + where_op, (mask, scalar_tensor, x), kwargs, meta, True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py new file mode 100644 index 0000000..bf3f6af --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py @@ -0,0 +1,218 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# We'll decompose only the EXIR edge max_pool2d ops when dilation > 1 +EDGE_MAXPOOL2D = ( + exir_ops.edge.aten.max_pool2d.default, + exir_ops.edge.aten.max_pool2d_with_indices.default, +) + + +class DecomposeMaxPool2dPass(ArmPass): + """ + Decompose dilated max_pool2d (EXIR edge ops) into space-to-batch -> maxpool -> batch-to-space. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + SizeAdjustInputPass, + } + + def call_operator(self, op, args, kwargs, meta): + # Only intercept EXIR edge max_pool2d ops + if op not in EDGE_MAXPOOL2D: + return super().call_operator(op, args, kwargs, meta) + + # detect whether indices variant + is_with_indices = op is exir_ops.edge.aten.max_pool2d_with_indices.default + + # Normalize missing trailing args to their defaults + x = args[0] + kernel_size = args[1] + stride = args[2] + padding = args[3] if len(args) >= 4 else 0 + dilation = args[4] if len(args) >= 5 else 1 + ceil_mode = args[5] if len(args) == 6 else False + + # Normalize attributes + pad_h, pad_w = (padding, padding) if isinstance(padding, int) else padding + d_h, d_w = (dilation, dilation) if isinstance(dilation, int) else dilation + k_h, k_w = ( + (kernel_size, kernel_size) if isinstance(kernel_size, int) else kernel_size + ) + s_h, s_w = (stride, stride) if isinstance(stride, int) else stride + + # If no dilation: call EXIR edge op + if d_h == 1 and d_w == 1: + minimal_args = [x, kernel_size, stride, padding, dilation, ceil_mode] + return super().call_operator(op, tuple(minimal_args), {}, meta) + + # Compute padded and packed dimensions for dilation > 1 + N, C, H, W = x.data.size() + ph, pw = pad_h, pad_w + ph2, pw2 = pad_h, pad_w + H_pad = H + ph + ph2 + W_pad = W + pw + pw2 + H_pack = (H_pad + d_h - 1) // d_h + W_pack = (W_pad + d_w - 1) // d_w + extra_h = 0 if H_pack < k_h else (s_h - ((H_pack - k_h) % s_h)) % s_h + extra_w = 0 if W_pack < k_w else (s_w - ((W_pack - k_w) % s_w)) % s_w + ph2 += extra_h * d_h + pw2 += extra_w * d_w + + meta_with_no_qparams = meta.copy() + meta_with_no_qparams.data["output_qparams"] = {} + meta_with_no_qparams.data["input_qparams"] = {} + meta_with_no_output_qparams = meta.copy() + meta_with_no_output_qparams.data["output_qparams"] = {} + + # 1) Pad via EXIR edge pad (preserves dtype) + pad_edge = exir_ops.edge.aten.constant_pad_nd.default + pads = [pw, pw2, ph, ph2, 0, 0, 0, 0] + x_pad = super().call_operator( + pad_edge, + (x, pads, 0), + {}, + meta_with_no_output_qparams, + ) + + # 2) Space-to-batch: reshape and permute + x2 = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x_pad, [N, C, H_pack, d_h, W_pack, d_w]), + {}, + meta_with_no_qparams, + ) + x2 = super().call_operator( + exir_ops.edge.aten.permute_copy.default, + (x2, [3, 5, 0, 1, 2, 4]), + {}, + meta_with_no_qparams, + ) + x2 = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x2, [N * d_h * d_w, C, H_pack, W_pack]), + {}, + meta_with_no_qparams, + ) + + # 3) Core pooling on packed tensor + pool_edge_op = ( + exir_ops.edge.aten.max_pool2d_with_indices.default + if is_with_indices + else exir_ops.edge.aten.max_pool2d.default + ) + pool_args = (x2, (k_h, k_w), (s_h, s_w), (0, 0), 1, ceil_mode) + pool_out = super().call_operator( + pool_edge_op, + pool_args, + {}, + meta, + ) + + # Unpack pooled result + if is_with_indices: + pooled_proxy = super().call_operator( + operator.getitem, + (pool_out, 0), + {}, + meta_with_no_qparams, + ) + indices_proxy = super().call_operator( + operator.getitem, + (pool_out, 1), + {}, + meta_with_no_qparams, + ) + pooled_fake, _ = pool_out.data + else: + pooled_proxy = pool_out + pooled_fake = pool_out.data + indices_proxy = None + + _, C_out, H_out, W_out = pooled_fake.shape + + # 4) Batch-to-space: reshape and permute back + out = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (pooled_proxy, [d_h, d_w, N, C_out, H_out, W_out]), + {}, + meta_with_no_qparams, + ) + out = super().call_operator( + exir_ops.edge.aten.permute_copy.default, + (out, [2, 3, 4, 0, 5, 1]), + {}, + meta_with_no_qparams, + ) + # now flatten back into (N, C, H_out*d_h, W_out*d_w) + out = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (out, [N, C_out, H_out * d_h, W_out * d_w]), + {}, + meta_with_no_qparams, + ) + + # 5) Final crop + S_top = ph // d_h + (1 if ph % d_h else 0) + S_left = pw // d_w + (1 if pw % d_w else 0) + S_top = max(0, min(S_top, H_out * d_h - H)) + S_left = max(0, min(S_left, W_out * d_w - W)) + out = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (out, 2, S_top, S_top + H), + {}, + meta_with_no_qparams, + ) + out = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (out, 3, S_left, S_left + W), + {}, + meta_with_no_qparams, + ) + + if is_with_indices: + # Reconstruct indices + idx = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (indices_proxy, [d_h, d_w, N, C_out, H_out, W_out]), + {}, + meta_with_no_qparams, + ) + idx = super().call_operator( + exir_ops.edge.aten.permute_copy.default, + (idx, [2, 3, 4, 0, 5, 1]), + {}, + meta, + ) + idx = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (idx, [N, C_out, H_out * d_h, W_out * d_w]), + {}, + meta_with_no_qparams, + ) + idx = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (idx, 2, S_top, S_top + H), + {}, + meta_with_no_qparams, + ) + idx = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (idx, 3, S_left, S_left + W), + {}, + meta_with_no_qparams, + ) + return out, idx + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_meandim_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_meandim_pass.py new file mode 100644 index 0000000..a8cac5a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_meandim_pass.py @@ -0,0 +1,283 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from copy import copy +from math import prod +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.exir.backend.utils import WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def get_meandim_decomposition(op) -> tuple: + if op in (exir_ops.edge.aten.mean.dim, exir_ops.edge.aten.mean.default): + return ( + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in (torch.ops.aten.mean.dim, torch.ops.aten.mean.default): + return ( + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.full.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get meandim decomposition for op {op}") + + +def get_avgpool(op): + if op in (exir_ops.edge.aten.mean.dim, exir_ops.edge.aten.mean.default): + return exir_ops.edge.aten.avg_pool2d.default + if op in (torch.ops.aten.mean.dim, torch.ops.aten.mean.default): + return torch.ops.aten.avg_pool2d.default + raise RuntimeError(f"Can't get meandim decomposition for op {op}") + + +def get_view(op): + if op in (exir_ops.edge.aten.mean.dim, exir_ops.edge.aten.mean.default): + return exir_ops.edge.aten.view_copy.default + if op in (torch.ops.aten.mean.dim, torch.ops.aten.mean.default): + return torch.ops.aten.reshape.default + raise RuntimeError(f"Can't get meandim decomposition for op {op}") + + +def get_quantization(op): + """Returns quant and dequant op of same type (per_channel/ tensor) as op if op is a dequant node, None otherwise.""" + if op in DQ_OPS: + # Input of op can be placeholder, can't use that to get quant node directly. + quant_type_index = DQ_OPS.index(op) + return Q_OPS[quant_type_index], op + return None + + +class DecomposeMeanDimPass(ArmPass): + """ + Decomposes a meandim into avg_pool and/or sum + mul (1/N) depending on which dims the mean is taken for: + h,w -> avg_pool + n,c -> sum + mul(1/N) + For rank < 4, the input is first reshaped to 4D by padding with dim=1 from the left. + + Example: + x = mean_dim(x, (0,2), keepdim=False) # x = (c,h,w) + Becomes: + x = view_copy.default(x, new_shape=(1,c,h,w)) # Reshape to work with avg_pool + x = avg_pool2d.default(x, kernel=(1,w), stride=(1,1)) # Reduce w with avg_pool + x = sum.dim_IntList(x, dim=1, keepdims=True) # Reduce c with sum + x = mul.Tensor(x, 1/c) # Divide by number of channels to get mean + x = view_copy.default(x, new_shape=(h)) # Squeeze dims since keepdims = False + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + DecomposeSumPass, + SizeAdjustInputPass, + } + + def __init__(self, graph_module, tosa_spec, *args, **kwargs): + super().__init__(*args, **kwargs) + self._graph_module = graph_module + self._tosa_spec = tosa_spec + # Lazy import to avoid circular dependency with operator_support + from executorch.backends.arm.operator_support.pool_2d_support import ( + AvgPool2dSupported, + ) + + self._avg_pool_checker = AvgPool2dSupported( + self._tosa_spec, WhyNoPartitionReporter() + ) + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + exir_ops.edge.aten.mean.dim, + torch.ops.aten.mean.dim, + exir_ops.edge.aten.mean.default, + torch.ops.aten.mean.default, + ) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x = get_node_arg(args, 0) + input_shape = list(x.data.shape) + output_shape = list(meta["val"].shape) + dims_to_reduce = get_node_arg(args, 1, range(len(input_shape))) + if dims_to_reduce is None: + dims_to_reduce = range(len(input_shape)) + dims_to_reduce = [dim % len(input_shape) for dim in dims_to_reduce] + dims_to_reduce = [dim for dim in dims_to_reduce if input_shape[dim] != 1] + + dtype = meta["val"].dtype + view_op = get_view(op) + + # Reshape to 4D + if len(input_shape) != 4: + new_shape = copy(input_shape) + + while len(new_shape) < 4: + new_shape.insert(0, 1) + dims_to_reduce = [dim + 1 for dim in dims_to_reduce] + + while len(new_shape) > 4: + i = new_shape.pop(0) + new_shape[0] = new_shape[0] * i + dims_to_reduce = [dim - 1 for dim in dims_to_reduce] + + x = super().call_operator(view_op, (x, new_shape), {}, meta, True) + x = self._maybe_insert_q_dq_after(x, meta) + + # Reduce (h,w) dims by avg pool if possible + x, dims_to_reduce = self._reduce_by_average_pool(op, x, dims_to_reduce, meta) + + # Reshape back to 5D if necessary + if len(input_shape) > 4: + original_dims = input_shape[0:-3] + temp_shape = list(x.data.shape)[1:] + temp_shape = original_dims + temp_shape + dims_to_reduce = [dim + len(original_dims) - 1 for dim in dims_to_reduce] + + x = super().call_operator(view_op, (x, temp_shape), {}, meta, True) + x = self._maybe_insert_q_dq_after(x, meta) + # Reduce remaining dims by sum + x = self._reduce_by_sum(op, x, dims_to_reduce, meta, dtype) + + # Reshape to correct output shape if necessary + if list(x.data.shape) != output_shape: + x = super().call_operator(view_op, (x, output_shape), {}, meta, True) + + return x + + def _reduce_by_sum(self, op, input_node, dims, meta, dtype): + if len(dims) == 0: + return input_node + + input_shape = input_node.data.size() + output_shape = meta["val"].size() + N = prod((n for i, n in enumerate(input_shape) if i in dims)) + sum_op, full_op, mul_op = get_meandim_decomposition(op) + + sum = super().call_operator(sum_op, (input_node, dims, True), {}, meta, True) + full = super().call_operator( + full_op, + ([1] * len(output_shape), 1 / N), + {"dtype": dtype, "device": input_node.data.device}, + meta, + True, + ) + if (quant_ops := get_quantization(input_node.node.target)) is not None: + # Insert Q and DQ nodes after full op. + # Since the value of full is known, we can compute quant params such that dq(q_max_value) + q_op, dq_op = quant_ops + qmax = input_node.node.args[4] + full_quant_args = ( + 1 / (N * qmax), # Scale to map qmax to 1/N + 0, # Zero point + *input_node.node.args[3:], + ) + q_args = (full, *full_quant_args) + full = super().call_operator( + q_op, + q_args, + kwargs={}, + meta=meta, + updated=True, + ) + dq_args = (full, *full_quant_args) + full = super().call_operator( + dq_op, dq_args, kwargs={}, meta=meta, updated=True + ) + + # Insert Q and DQ nodes after sum op. + # Scale needs to be adjusted with N, since it was computed on data after the division with N. + sum_quant_args = (input_node.node.args[1] * N, *input_node.node.args[2:]) + q_args = (sum, *sum_quant_args) + sum = super().call_operator( + q_op, + q_args, + kwargs={}, + meta=meta, + updated=True, + ) + dq_args = (sum, *sum_quant_args) + sum = super().call_operator( + dq_op, dq_args, kwargs={}, meta=meta, updated=True + ) + + return super().call_operator(mul_op, (sum, full), {}, meta, True) + + def _reduce_by_average_pool(self, op, input_node, dims, meta): + dims_to_reduce_by_avgpool = [dim for dim in dims if dim >= 2] + if len(dims_to_reduce_by_avgpool) == 0: + return input_node, dims + + dims_to_reduce_by_sum = [dim for dim in dims if dim < 2] + + avgpool_op = get_avgpool(op) + input_shape = input_node.data.size() + + stride = [1, 1] + if dims_to_reduce_by_avgpool in ([2, 3], [3, 2]): + kernel_size = [input_shape[2], input_shape[3]] + elif dims_to_reduce_by_avgpool == [3]: + kernel_size = [1, input_shape[3]] + elif dims_to_reduce_by_avgpool == [2]: + kernel_size = [input_shape[2], 1] + else: + raise RuntimeError( + f"Bad dims {dims_to_reduce_by_avgpool} for {op} decomposition of mean_dim." + ) + + args = (input_node, kernel_size, stride) + + avg_pool_node = self._graph_module.graph.create_node( + "call_function", avgpool_op, args + ) + is_supported = self._avg_pool_checker.is_node_tosa_supported( + avg_pool_node, self._tosa_spec + ) + + if is_supported: + out = super().call_operator(avgpool_op, args, {}, meta, True) + out = self._maybe_insert_q_dq_after(out, meta) + return ( + out, + dims_to_reduce_by_sum, + ) + + else: + return input_node, dims + + def _maybe_insert_q_dq_after(self, op, meta): + """If the input node of op is a dequant node, insert a q-dq pair after op with identical quantization parameters.""" + + if len(op.node.all_input_nodes) > 1: + raise ValueError( + f"Expected one input to {op.node}, got inputs {op.node.all_input_nodes}" + ) + input_node = op.node.all_input_nodes[0] + if (quant_ops := get_quantization(input_node.target)) is not None: + q_op, dq_op = quant_ops + quant_args = list(input_node.args[1:]) + q_args = (op, *quant_args) + out = super().call_operator( + q_op, + q_args, + kwargs={}, + meta=meta, + updated=True, + ) + dq_args = (out, *quant_args) + return super().call_operator( + dq_op, dq_args, kwargs={}, meta=meta, updated=True + ) + else: + return op diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_ne_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_ne_pass.py new file mode 100644 index 0000000..eff2255 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_ne_pass.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_ne_ops = (exir_ops.edge.aten.ne.Tensor,) +aten_ne_ops = (torch.ops.aten.ne.Tensor, torch.ops.aten.ne_.Tensor) + + +def get_ne_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.ne operation into its equivalent + TOSA-supported operations. + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + ne(x, y) -> logical_not(eq(x, y)) + + Returns: + A tuple (eq_op, logical_not_op) corresponding to the appropriate operator + overloads for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported ne variant. + """ + if op in edge_ne_ops: + return (exir_ops.edge.aten.eq.Tensor, exir_ops.edge.aten.logical_not.default) + if op in aten_ne_ops: + return (torch.ops.aten.eq.Tensor, torch.ops.aten.logical_not.default) + + raise RuntimeError(f"Can't get ne decomposition for op {op}") + + +class DecomposeNotEqualPass(ArmPass): + """ + A transformation pass that decomposes unsupported `aten.ne` operations into a + combination of supported TOSA-equivalent operations. + + Since TOSA does not provide a native NOT_EQUAL operator, this pass rewrites: + ne(x, y) → logical_not(eq(x, y)) + + Supported input ops: + - aten.ne.Tensor(x, y) + - aten.ne_.Tensor(x, y) + - exir_ops.edge.aten.ne.Tensor(x, y) + + These are replaced with: + - aten.eq.Tensor or exir_ops.edge.aten.eq.Tensor + - followed by aten.logical_not.default or its edge equivalent + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_ne_ops + aten_ne_ops) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + lhs, rhs = args + + eq_op, logical_not_op = get_ne_decomposition(op) + + eq_node = super().call_operator(eq_op, (lhs, rhs), {}, meta, updated=True) + not_node = super().call_operator( + logical_not_op, (eq_node,), {}, meta, updated=True + ) + + return not_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_quant_nodes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_quant_nodes.py new file mode 100644 index 0000000..3cc99e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_quant_nodes.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_round_pass import DecomposeRoundPass +from executorch.backends.arm.constants import DEQUANT_PER_TENSOR_OP, QUANT_PER_TENSOR_OP +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeQuantNodesPass(ArmPass): + """Decomposes quantization nodes into more primitive operations by rewriting the graph + using the two formulas: + + quantized value = clamp(round(fp32_value / scale) + zero point, qmin, qmax) + + fp32_value = (quantized value - zp) * scale + + For quantization nodes, the pass replaces them with: + + 1. Multiplying the input by the inverse of the scale factor. + 2. Rounding the result. + 3. Adding the zero point. + 4. Clamping the result to [qmin, qmax]. + 5. Casting to the target data type. + + For dequantization nodes, the pass replaces them with: + + 1. Casting the input to int32. + 2. Subtracting the zero point. + 3. Casting to float32. + 4. Multiplying by the scale factor. + + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeRoundPass} + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in list(graph_module.graph.nodes): + if node.op != "call_function" or node.target not in ( + QUANT_PER_TENSOR_OP, + DEQUANT_PER_TENSOR_OP, + ): + continue + if node.target == DEQUANT_PER_TENSOR_OP and all( + user.target == QUANT_PER_TENSOR_OP for user in node.users + ): + continue + elif ( + node.target == QUANT_PER_TENSOR_OP + and node.all_input_nodes[0].target == DEQUANT_PER_TENSOR_OP + ): + continue + modified = True + args = node.args + input_rank = args[0].meta["val"].ndim + x, scale, zero_point, qmin, qmax, dtype = args + # Instead of dividing by scale in quantization, we multiply by 1/scale + # when quantizing. + scale = cast(float, scale) + scale = scale if node.target == DEQUANT_PER_TENSOR_OP else 1.0 / scale + with graph_module.graph.inserting_before(node): + scale_const = create_node( + graph_module.graph, + exir_ops.edge.aten.full.default, + args=((1,) * input_rank, scale), + kwargs={"dtype": torch.float32}, + ) + zp_const = create_node( + graph_module.graph, + exir_ops.edge.aten.full.default, + args=((1,) * input_rank, zero_point), + kwargs={ + "dtype": ( + torch.float32 + if node.target == QUANT_PER_TENSOR_OP + else torch.int32 + ) + }, + ) + if node.target == QUANT_PER_TENSOR_OP: + # TODO MLETORCH-1587: Decompose quantization nodes using more integer arithmetic + scaled = create_node( + graph_module.graph, + exir_ops.edge.aten.mul.Tensor, + args=(x, scale_const), + from_node=node, + ) + rounded = create_node( + graph_module.graph, + exir_ops.edge.aten.round.default, + args=(scaled,), + from_node=node, + ) + shifted = create_node( + graph_module.graph, + exir_ops.edge.aten.add.Tensor, + args=(rounded, zp_const), + from_node=node, + ) + clamped = create_node( + graph_module.graph, + exir_ops.edge.aten.clamp.default, + args=(shifted, float(qmin), float(qmax)), + from_node=node, + ) + quantized = create_node( + graph_module.graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + args=(clamped,), + kwargs={"dtype": dtype}, + from_node=node, + ) + output = quantized + else: + input_casted_to_zp_dtype = create_node( + graph_module.graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + args=(x,), + kwargs={"dtype": torch.int32}, + from_node=node, + ) + shifted = create_node( + graph_module.graph, + exir_ops.edge.aten.sub.Tensor, + args=(input_casted_to_zp_dtype, zp_const), + from_node=node, + ) + casted_to_float = create_node( + graph_module.graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + args=(shifted,), + kwargs={"dtype": torch.float32}, + from_node=node, + ) + dequantized = create_node( + graph_module.graph, + exir_ops.edge.aten.mul.Tensor, + args=(casted_to_float, scale_const), + from_node=node, + ) + output = dequantized + node.replace_all_uses_with(output) + graph_module.graph.erase_node(node) + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified=modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_remainder_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_remainder_pass.py new file mode 100644 index 0000000..6c11a7b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_remainder_pass.py @@ -0,0 +1,70 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_div_tensor_mode import ( + DecomposeDivTensorModePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass +from torch._ops import OpOverload + +Op = OpOverload | EdgeOpOverload + +_decomposition_ops: Dict[Op, tuple[Op, Op, Op]] = { + exir_ops.edge.aten.remainder.Scalar: ( + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.sub.Tensor, + ), + torch.ops.aten.remainder.Tensor: ( + torch.ops.aten.div.Tensor_mode, + torch.ops.aten.mul.Tensor, + torch.ops.aten.sub.Tensor, + ), + torch.ops.aten.remainder.Scalar: ( + torch.ops.aten.div.Tensor_mode, + torch.ops.aten.mul.Scalar, + torch.ops.aten.sub.Tensor, + ), + exir_ops.edge.aten.remainder.Tensor: ( + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sub.Tensor, + ), +} + + +class DecomposeRemainderPass(ArmPass): + """ + Decompose the remainder operation into primitive arithmetic: + remainder(x, y) -> x - floor_div(x, y) * y + where floor_div(x, y) == div(x, y, rounding_mode="floor"). + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivTensorModePass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + supported_ops = ( + exir_ops.edge.aten.remainder.Scalar, + exir_ops.edge.aten.remainder.Tensor, + torch.ops.aten.remainder.Scalar, + torch.ops.aten.remainder.Tensor, + ) + if op not in supported_ops: + return super().call_operator(op, args, kwargs, meta, updated) + + div_op, mul_op, sub_op = _decomposition_ops[op] + x, y = args[0], args[1] + + floor_div = super().call_operator( + div_op, (x, y), {"rounding_mode": "floor"}, meta, updated=True + ) + product = super().call_operator(mul_op, (floor_div, y), {}, meta, updated=True) + return super().call_operator(sub_op, (x, product), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_round_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_round_pass.py new file mode 100644 index 0000000..c672e1f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_round_pass.py @@ -0,0 +1,96 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass +from torch._ops import OpOverload + + +Op = OpOverload | EdgeOpOverload + + +def _get_round_decomposition_ops(op) -> tuple[Op, Op, Op, Op, Op, Op, Op]: + """ + Returns the (full_op, ge_op, add_op, sub_op, floor_op, ceil_op, where_op) for the + given round operation. The ops depend on whether the round op is an aten or edge op. + """ + if op == exir_ops.edge.aten.round.default: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.where.self, + ) + elif op == torch.ops.aten.round.default: + return ( + torch.ops.aten.full.default, + torch.ops.aten.ge.Tensor, + torch.ops.aten.add.Scalar, + torch.ops.aten.sub.Scalar, + torch.ops.aten.floor.default, + torch.ops.aten.ceil.default, + torch.ops.aten.where.self, + ) + raise RuntimeError(f"Can't get round decomposition ops for op {op}") + + +class DecomposeRoundPass(ArmPass): + """ + For inputs >= 0, round(x) is equivalent to floor(x + 0.5), and for inputs < 0, + round(x) is equivalent to ceil(x - 0.5). This pass decomposes the round operation into + a sequence of more primitive operations. + Example: + %zero = full((1,), 0.0, dtype=torch.float32) + %is_non_negative = ge(x, %zero) + %plus_half = add(x, 0.5) + %minus_half = sub(x, 0.5) + %floor = floor(%plus_half) + %ceil = ceil(%minus_half) + %result = where(%is_non_negative, %floor, %ceil) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + _TARGET_OPS = { + exir_ops.edge.aten.round.default, + torch.ops.aten.round.default, + } + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op not in DecomposeRoundPass._TARGET_OPS or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta, updated) + x = args[0] + full, ge, add, sub, floor, ceil, where = _get_round_decomposition_ops(op) + zero = super().call_operator( + full, + args=((1,), 0.0), + kwargs={"dtype": torch.float32}, + meta=meta, + updated=True, + ) + is_non_negative = super().call_operator( + ge, (x, zero), kwargs, meta, updated=True + ) + plus_half = super().call_operator(add, (x, 0.5), kwargs, meta, updated=True) + minus_half = super().call_operator(sub, (x, 0.5), kwargs, meta, updated=True) + floor = super().call_operator(floor, (plus_half,), kwargs, meta, updated=True) + ceil = super().call_operator(ceil, (minus_half,), kwargs, meta, updated=True) + return super().call_operator( + where, + (is_non_negative, floor, ceil), + kwargs, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sdpa_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sdpa_pass.py new file mode 100644 index 0000000..28a3bad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sdpa_pass.py @@ -0,0 +1,36 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.transforms import decompose_sdpa +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeScaledDotProductAttentionPass( + ArmPass, decompose_sdpa.DecomposeScaledDotProductAttention +): + """Pass that expands `aten.scaled_dot_product_attention` into primitive ops.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call( + self, graph_module: torch.fx.GraphModule, allow_non_fake_inputs: bool = True + ) -> PassResult: + graph = graph_module.graph + for node in list(graph.nodes): + if node.target != torch.ops.aten.scaled_dot_product_attention.default: + continue + if not self.allowed_to_transform(node.meta): + continue + + # Decompose with the superclass helper to reuse the shared logic. + super()._decompose_sdpa_node(graph_module, node, allow_non_fake_inputs) + + graph.eliminate_dead_code() + graph_module.recompile() + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select.py new file mode 100644 index 0000000..23b100c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.convert_squeezes_to_view import ( + ConvertSqueezesToViewPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeSelectPass(ArmPass): + """ + This pass decomposes select into slice + squeeze to ensure that Aten and TOSA outputs has the same rank (input rank -1) + """ + + _passes_required_after: Set[Type[ExportPass]] = {ConvertSqueezesToViewPass} + + def call(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + + if node.op != "call_function": + continue + + if node.target in ( + exir_ops.edge.aten.select.int, + exir_ops.edge.aten.select_copy.int, + ): + slice_op = exir_ops.edge.aten.slice_copy.Tensor + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + else: + continue + + input_node, dim, index = node.args + + input_tensor = get_first_fake_tensor(input_node) + rank = len(input_tensor.size()) + shape = input_tensor.shape + dim = dim % rank if dim < 0 else dim + index = index % shape[dim] if index < 0 else index + + with graph_module.graph.inserting_before(node): + slice_node = create_node( + graph_module.graph, + slice_op, + (input_node, dim, index, index + 1), + from_node=node, + inherit_qparams=False, + ) + squeeze_node = create_node( + graph_module.graph, + squeeze_op, + (slice_node, [dim]), + from_node=node, + inherit_qparams=True, + ) + + node.replace_all_uses_with(squeeze_node) + graph_module.graph.erase_node(node) + + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select_scatter_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select_scatter_pass.py new file mode 100644 index 0000000..f3c7ae5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_select_scatter_pass.py @@ -0,0 +1,143 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_int64_const_ops_to_int32 import ( + ConvertInt64ConstOpsToInt32Pass, +) +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_scatter_ops = (exir_ops.edge.aten.select_scatter.default,) +aten_scatter_ops = (torch.ops.aten.select_scatter.default,) + + +def get_select_scatter_decomposition(op) -> tuple: + if op in edge_scatter_ops: + return ( + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.unsqueeze_copy.default, + exir_ops.edge.aten.view_copy.default, + ) + if op in aten_scatter_ops: + return ( + torch.ops.aten.arange.start_step, + torch.ops.aten.eq.Scalar, + torch.ops.aten.where.self, + torch.ops.aten.expand_copy.default, + torch.ops.aten.unsqueeze_copy.default, + torch.ops.aten.view_copy.default, + ) + + raise RuntimeError(f"Can't get select_scatter decomposition for op {op}") + + +class DecomposeSelectScatterPass(ArmPass): + """select_scatter is decomposed into other ops during export, however this is only + suppported for the fp profile and for the int profile we need to decompose it here. + + The decomposition is as follows: + - Build a boolean mask the size of x + eq(view(arange(0, dim_size), mask_shape), index) + - Broadcast source to x + expand(unsqueeze(source, dim), shape) + - Route the updated slice while keeping the untouched lanes + where(mask, expanded_source, x) + + This reflects the decomposition for the fp profile implemented in torch._refs + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ReplaceScalarWithTensorByProfilePass, + ConvertInt64ConstOpsToInt32Pass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_scatter_ops + aten_scatter_ops): + return super().call_operator(op, args, kwargs, meta, updated=False) + + ( + arange_op, + eq_op, + where_op, + expand_op, + unsqueeze_op, + view_op, + ) = get_select_scatter_decomposition(op) + + input_tensor = args[0] + src_tensor = args[1] + dim = int(args[2]) + index = int(args[3]) + + shape = input_tensor.data.size() + rank = len(shape) + dim = dim % rank if dim < 0 else dim + dim_size = shape[dim] + if index < 0: + index = index + dim_size + + mask_shape = [1] * rank + mask_shape[dim] = -1 + + arange_node = super().call_operator( + arange_op, + (0, dim_size, 1), + {}, + meta, + updated=False, + ) + + view_node = super().call_operator( + view_op, + (arange_node, mask_shape), + {}, + meta, + updated=False, + ) + + mask_node = super().call_operator( + eq_op, + (view_node, index), + {}, + meta, + updated=False, + ) + + unsqueeze_node = super().call_operator( + unsqueeze_op, + (src_tensor, dim), + {}, + meta, + updated=False, + ) + + expand_node = super().call_operator( + expand_op, + (unsqueeze_node, shape), + {}, + meta, + updated=False, + ) + + where_node = super().call_operator( + where_op, + (mask_node, expand_node, input_tensor), + {}, + meta, + updated=True, + ) + + return where_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sign_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sign_pass.py new file mode 100644 index 0000000..b0cf243 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sign_pass.py @@ -0,0 +1,78 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For MI case +edge_sign = exir_ops.edge.aten.sign.default +# For BI case +aten_sign = torch.ops.aten.sign.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_sign: + return ( + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Scalar, + ) + elif op == aten_sign: + return ( + torch.ops.aten.gt.Scalar, + torch.ops.aten.lt.Scalar, + torch.ops.aten.where.self, + torch.ops.aten.neg.default, + torch.ops.aten.mul.Scalar, + torch.ops.aten.add.Scalar, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeSignPass(ArmPass): + """Decomposes the sign operator into a sequence of operations that are supported by the Arm backend.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_sign, aten_sign) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + gt_op, lt_op, where_op, neg_op, mul_op, add_op = get_ops(op) + + x = args[0] + + gt_mask = super().call_operator(gt_op, (x, 0.0), {}, meta, updated=True) + lt_mask = super().call_operator(lt_op, (x, 0.0), {}, meta, updated=True) + + zeros = super().call_operator(mul_op, (x, 0.0), {}, meta, updated=True) + ones = super().call_operator(add_op, (zeros, 1.0), {}, meta, updated=True) + neg_ones = super().call_operator(neg_op, (ones,), {}, meta, updated=True) + + negative_tensor = super().call_operator( + where_op, (lt_mask, neg_ones, zeros), {}, meta, updated=True + ) + positive_tensor = super().call_operator( + where_op, (gt_mask, ones, zeros), {}, meta, updated=True + ) + + return super().call_operator( + where_op, + (lt_mask, negative_tensor, positive_tensor), + {}, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_silu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_silu_pass.py new file mode 100644 index 0000000..bf30271 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_silu_pass.py @@ -0,0 +1,41 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.pass_base import ExportPass + +aten_silu_ops = (torch.ops.aten.silu.default, torch.ops.aten.silu_.default) + + +class DecomposeSiluPass(ArmPass): + """ + This pass decomposes silu into a mul and a sigmoid node. + + Example: + y = silu(a) + Becomes: + x = sigmoid(a) + y = mul(a,x) + """ + + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (aten_silu_ops) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + sigmoid_op = torch.ops.aten.sigmoid.default + mul_op = torch.ops.aten.mul.Tensor + + original = args[0] + sigmoid = super().call_operator(sigmoid_op, (original,), {}, meta, updated=True) + + return super().call_operator( + mul_op, (original, sigmoid), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sinh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sinh_pass.py new file mode 100644 index 0000000..731f9a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sinh_pass.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For MI case +edge_sinh = exir_ops.edge.aten.sinh.default + + +class DecomposeSinhPass(ArmPass): + """ + A decomposition pass that decomposes Sinh operations into a + combination of supported TOSA-equivalent operations (MI). + + Supported input ops: + - exir_ops.edge.aten.sinh.default + + These are decomposed into exponentials, negation, subtraction, + and scalar multiplication. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op is not edge_sinh: + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + x = args + + sub_op, exp_op, neg_op, mul_op = ( + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.mul.Scalar, + ) + + # Exponential 1 + exp1 = super().call_operator(exp_op, x, {}, meta, updated=True) + + # Exponential 2 + neg_x = super().call_operator(neg_op, x, {}, meta, updated=True) + exp2 = super().call_operator(exp_op, (neg_x,), {}, meta, updated=True) + + # Subtraction + sub = super().call_operator(sub_op, (exp1, exp2), {}, meta, updated=True) + + # Multiplication + out = super().call_operator(mul_op, (sub, 0.5), {}, meta, updated=True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_pass.py new file mode 100644 index 0000000..88408ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_pass.py @@ -0,0 +1,93 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For BI case +torch_softmax = ( + torch.ops.aten.softmax.int, + torch.ops.aten._safe_softmax.default, + torch.ops.aten.log_softmax.int, +) +# For MI case +edge_softmax = ( + exir_ops.edge.aten._softmax.default, + exir_ops.edge.aten._log_softmax.default, +) +log_softmax = (torch.ops.aten.log_softmax.int, exir_ops.edge.aten._log_softmax.default) + + +def _get_logsoftmax_ops(op) -> tuple: + """ + Returns the (log_op, sub_op, amax_op, expo_op, sum_op, reciprocal_op), where the ops depends on if + the softmax op is an aten or edge op. + """ + if op in edge_softmax: + return ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in torch_softmax: + return ( + torch.ops.aten.log.default, + torch.ops.aten.sub.Tensor, + torch.ops.aten.amax.default, + torch.ops.aten.exp.default, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.reciprocal.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get logsoftmax decomposition ops for op {op}") + + +class DecomposeSoftmaxPass(ArmPass): + """ + This pass decomposes log_softmax or softmax into more primitive ops. + Example: + %op1 = amax(x) + %op2 = sub(x, %op1) + %op3 = exp(%op2) + %op4 = sum(%op3, dim) + %op5 = reciprocal(%op4) + %op6 = mul(%op3, %op5) + (in logsoftmax case: %op7 = log(%op6)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSumPass, + InsertTableOpsPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in torch_softmax + edge_softmax or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + log_op, sub_op, max_op, exp_op, sum_op, reciprocal_op, mul_op = ( + _get_logsoftmax_ops(op) + ) + _input = args[0] + dim = [args[1]] + op1 = super().call_operator(max_op, (_input, dim, True), {}, meta, updated=True) + op2 = super().call_operator(sub_op, (_input, op1), {}, meta, updated=True) + op3 = super().call_operator(exp_op, (op2,), {}, meta, updated=True) + op4 = super().call_operator(sum_op, (op3, dim, True), {}, meta, updated=True) + op5 = super().call_operator(reciprocal_op, (op4,), {}, meta, updated=True) + op6 = super().call_operator(mul_op, (op3, op5), {}, meta, updated=True) + if op in log_softmax: + op6 = super().call_operator(log_op, (op6,), {}, meta, updated=True) + return op6 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_unstable_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_unstable_pass.py new file mode 100644 index 0000000..7759c7f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_softmax_unstable_pass.py @@ -0,0 +1,86 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For BI case +torch_softmax = (torch.ops.aten.softmax.int, torch.ops.aten.log_softmax.int) + +# For MI case +edge_softmax = ( + exir_ops.edge.aten._softmax.default, + exir_ops.edge.aten._log_softmax.default, +) + +log_softmax = (torch.ops.aten.log_softmax.int, exir_ops.edge.aten._log_softmax.default) + + +def get_logsoftmax_ops(op) -> tuple: + """ + Returns the the (log_op, expo_op, sum_op, reciprocal_op), where the ops depends on if + the logsoftmax op is in exir_ops torch.ops.aten. + """ + if op in edge_softmax: + return ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in torch_softmax: + return ( + torch.ops.aten.log.default, + torch.ops.aten.exp.default, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.reciprocal.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get softmax decomposition ops for op {op}") + + +class DecomposeSoftmaxUnstablePass(ArmPass): + """ + This pass decomposes log softmax or softmax into more primitive ops. + + Example: + %op1 = exp(x) + %op2 = sum(%op1, dim) + %op3 = reciprocal(%op2) + %op4 = mul(%op1, %op3) + (in logsoftmax case: %op5 = log(%op4)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSumPass, + InsertTableOpsPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in (torch_softmax + edge_softmax) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + log_op, exp_op, sum_op, reciprocal_op, mul_op = get_logsoftmax_ops(op) + + _input = args[0] + dim = [args[1]] + + op1 = super().call_operator(exp_op, (_input,), {}, meta, True) + op2 = super().call_operator(sum_op, (op1, dim, True), {}, meta, True) + op3 = super().call_operator(reciprocal_op, (op2,), {}, meta, True) + op4 = super().call_operator(mul_op, (op1, op3), {}, meta, True) + if op in log_softmax: + op4 = super().call_operator(log_op, (op4,), {}, meta, True) + return op4 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sqrt_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sqrt_pass.py new file mode 100644 index 0000000..6bde3f5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sqrt_pass.py @@ -0,0 +1,53 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Tuple, Type, Union + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_sqrt_ops = (exir_ops.edge.aten.sqrt.default,) +aten_sqrt_ops = ( + torch.ops.aten.sqrt.default, + torch.ops.aten.sqrt_.default, +) + + +def get_sqrt_decomposition(op) -> Union[Tuple, torch._ops.OpOverload]: + # TODO : "MLETORCH-863 : Replace current sqrt -> pow.Tensor_Scalar workaround with pow.Tensor_Tensor" + if op in edge_sqrt_ops: + return exir_ops.edge.aten.pow.Tensor_Scalar + if op in aten_sqrt_ops: + return torch.ops.aten.pow.Tensor_Scalar + raise RuntimeError(f"Can't get sqrt decomposition for op {op}") + + +class DecomposeSqrtPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + """ + Decomposes `sqrt(x)` into `pow(x, 0.5)` for backend support. + """ + + if op not in (edge_sqrt_ops + aten_sqrt_ops) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + pow_op = get_sqrt_decomposition(op) + + return super().call_operator(pow_op, (args[0], 0.5), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sum_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sum_pass.py new file mode 100644 index 0000000..0e63ef3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_sum_pass.py @@ -0,0 +1,93 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def _get_sum_decomp(op): + match op: + case exir_ops.edge.aten.sum.dim_IntList: + return ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.sum.dim_IntList, + ) + case torch.ops.aten.sum.dim_IntList: + return (torch.ops.aten.reshape.default, torch.ops.aten.sum.dim_IntList) + case _: + raise RuntimeError("Unvalid op in DecomposeSumPass") + + +class DecomposeSumPass(ArmPass): + """ + In Pytorch, the default behaviour of for example Tensor.sum is to squeeze the + dimension that is summed (keep_dim = False). However, in TOSA, REDUCE_SUM always + preserves the rank of the input (keep_dim = True). To get a 1-1 mapping in the sum + lowering, normalize the keep_dim = False case to keep_dim = True and lower the rank + with a view op. + + Since TOSA can only reduce one dimension at a time, multiple dims are additionally + unrolled into multiple ops. + + Original: + sum((dim_1, dim_2), keep_dim = False) -> squeezed_shape + After pass: + sum(dim_1, keep_dim = True) -> unsqueezed_shape + sum(dim_2, keep_dim = True) -> unsqueezed_shape + view(shape = squeezed_shape) -> squeezed_shape + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in [ + exir_ops.edge.aten.sum.dim_IntList, + torch.ops.aten.sum.dim_IntList, + ]: + return super().call_operator(op, args, kwargs, meta) + + match len(args): + case 3: + ( + input_node, + dims, + keepdims, + ) = args + case 2: + ( + input_node, + dims, + ) = args + keepdims = False + case _: + raise ValueError(f"Invalid number of arguments ({len(args)}) provided.") + + # If dims evaluates to False (None or []), sum over all dimensions + if not dims: + shape = input_node.data.size() + dims = list(range(len(shape))) + + view_op, sum_op = _get_sum_decomp(op) + + for dim in dims: + input_node = super().call_operator( + sum_op, + (input_node, dim, True), + kwargs, + meta, + updated=True, + ) + + if not keepdims: + shape = list(meta["val"].size()) + input_node = super().call_operator( + view_op, (input_node, shape), {}, meta, updated=True + ) + + return input_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tan_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tan_pass.py new file mode 100644 index 0000000..3a196b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tan_pass.py @@ -0,0 +1,51 @@ +# Copyright 2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass, DecomposeDivPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_tan_op = exir_ops.edge.aten.tan.default + + +class DecomposeTanPass(ArmPass): + """ + Decomposes tan to sin/cos + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivPass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op != edge_tan_op: + return super().call_operator(op, args, kwargs, meta, updated) + # Skip quantized tan - it is decomposed as one single table op + if ( + len(meta.data.get("input_qparams", [])) > 0 + and len(meta.data.get("output_qparams", [])) > 0 + ): + return super().call_operator(op, args, kwargs, meta, updated) + if ( + len(meta.data.get("input_qparams", [])) > 0 + or len(meta.data.get("output_qparams", [])) > 0 + ): + raise RuntimeError( + "Mixed quantized and non-quantized inputs/outputs not supported." + ) + + x = args[0] + + sin_op = exir_ops.edge.aten.sin.default + cos_op = exir_ops.edge.aten.cos.default + div_op = exir_ops.edge.aten.div.Tensor + + sin = super().call_operator(sin_op, (x,), {}, meta, True) + cos = super().call_operator(cos_op, (x,), {}, meta, True) + + out = super().call_operator(div_op, (sin, cos), {}, meta, True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py new file mode 100644 index 0000000..b467f67 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py @@ -0,0 +1,97 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeTOSAUnsupportedClampPass(ArmPass): + """Rewrite TOSA unsupported clamp into min/max chain since TOSA lacks int32 clamp support + and only supports scalar min/max values.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + _supported_ops = { + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.clamp.Tensor, + torch.ops.aten.clamp.default, + torch.ops.aten.clamp.Tensor, + } + + def _ensure_tensor( + self, + value, + ref_tensor, + dtype, + rank, + meta, + ): + if value is None: + return None + return super().call_operator( + exir_ops.edge.aten.full.default, + ((1,) * rank, value), + {"dtype": dtype}, + meta, + updated=True, + ) + + def call_operator(self, op, args, kwargs, meta): + val = meta["val"] + + is_scalar_clamp = op in { + exir_ops.edge.aten.clamp.default, + torch.ops.aten.clamp.default, + } + is_tensor_clamp = op in { + exir_ops.edge.aten.clamp.Tensor, + torch.ops.aten.clamp.Tensor, + } + + if op not in self._supported_ops: + return super().call_operator(op, args, kwargs, meta) + + # Only rewrite scalar clamp for int32 + if is_scalar_clamp and val.dtype != torch.int32: + return super().call_operator(op, args, kwargs, meta) + + input_tensor = args[0] + dtype = val.dtype + rank = len(val.shape) + min_arg = args[1] if len(args) > 1 else None + max_arg = args[2] if len(args) > 2 else None + + if is_scalar_clamp: + # Scalar min/max -> make them tensors for min/max ops + min_arg = self._ensure_tensor(min_arg, input_tensor, dtype, rank, meta) + max_arg = self._ensure_tensor(max_arg, input_tensor, dtype, rank, meta) + else: + # Tensor variant: arguments are already tensors; nothing extra to do + if not is_tensor_clamp: + raise RuntimeError( + f"DecomposeTOSAUnsupportedClampPass: unexpected op {op} in tensor clamp branch" + ) + + current = input_tensor + if min_arg is not None: + current = super().call_operator( + exir_ops.edge.aten.maximum.default, + (current, min_arg), + {}, + meta, + updated=True, + ) + if max_arg is not None: + current = super().call_operator( + exir_ops.edge.aten.minimum.default, + (current, max_arg), + {}, + meta, + updated=True, + ) + return current diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_var_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_var_pass.py new file mode 100644 index 0000000..72da356 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decompose_var_pass.py @@ -0,0 +1,109 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.backends.arm._passes.decompose_meandim_pass import DecomposeMeanDimPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def get_var_decomposition(op) -> tuple: + if op == exir_ops.edge.aten.var.correction: + return ( + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.full.default, + ) + if op in (torch.ops.aten.var.correction, torch.ops.aten.var.dim): + return ( + torch.ops.aten.mean.dim, + torch.ops.aten.sub.Tensor, + torch.ops.aten.mul.Tensor, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.full, + ) + raise RuntimeError(f"Can't get var decomposition for op {op}") + + +class DecomposeVarPass(ArmPass): + """ + This pass decomposes var.correction and var.dim into smaller ops (see https://pytorch.org/docs/stable/generated/torch.var.html) + + Example: + y = var_correction(x, dim, keepdim, correction) + Becomes: + mean = mean(x, dim) + diff = sub(x, mean) + squared_diff = mul(diff, diff) + sum = sum(squared_diff, dim) + y = div(sum, max(0, N-correction)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + DecomposeMeanDimPass, + DecomposeSumPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + exir_ops.edge.aten.var.correction, + torch.ops.aten.var.correction, + torch.ops.aten.var.dim, + ) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + input_shape = x.data.size() + shape = list(meta["val"].size()) + if shape == []: + shape = [1 for _ in input_shape] + + dtype = meta["val"].dtype + # Get dim from args based on argument type + dim = get_node_arg(args, key=list, default_value=list(range(len(shape)))) + + if op == torch.ops.aten.var.dim: + keepdim = False + correction = 1 + if len(args) > 2: + correction = int(get_node_arg(args, 2, True)) + if len(args) > 3: + keepdim = get_node_arg(args, 3, False) + else: + correction = get_node_arg(kwargs, "correction", 1) + keepdim = get_node_arg(kwargs, "keepdim", False) + + N = 1 + for d in dim: + N *= input_shape[d] + + mean_op, diff_op, mul_op, sum_op, full_op = get_var_decomposition(op) + mean = super().call_operator(mean_op, (x, dim, True), {}, meta, True) + diff = super().call_operator(diff_op, (x, mean), {}, meta, True) + squared_diff = super().call_operator(mul_op, (diff, diff), {}, meta, True) + sum = super().call_operator( + sum_op, (squared_diff, dim, keepdim), {}, meta, True + ) + full = super().call_operator( + full_op, + ([], 1 / max(0, N - correction)), + {"dtype": dtype, "device": x.data.device}, + meta, + True, + ) + return super().call_operator(mul_op, (sum, full), {}, meta, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py new file mode 100644 index 0000000..0b9c593 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py @@ -0,0 +1,88 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def _get_decorated_ops(op): + if op in DecorateFp32toInt32CastingPass.targets: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.where.self, + ) + else: + raise RuntimeError(f"Can't get decorated ops for op {op}") + + +class DecorateFp32toInt32CastingPass(ArmPass): + """ + To lower pytorch fp32 -> int32 casting to TOSA, + we need to transform the value with Ceil, Floor, and Where. + Before: + output = to_dim_order_copy(x, dtype=torch.int32) + After: + %zero = full((1,), 0.0, dtype=torch.float32) + is_non_negative = x >= %zero + floor_x = floor(x) + ceil_x = ceil(x) + decorated_x = where(is_non_negative, floor_x, ceil_x) + output = to_dim_order_copy(decorated_x, dtype=torch.int32) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targets = [ + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ] + + def call_operator(self, op, args, kwargs, meta): + if op not in self.targets: + return super().call_operator(op, args, kwargs, meta) + + input = get_node_arg(args, 0) + input_dtype = input.node.meta["val"].dtype + output_dtype = meta["val"].dtype + + if not (input_dtype == torch.float32 and output_dtype == torch.int32): + return super().call_operator(op, args, kwargs, meta) + + # For some ops, qparams dtype is inconsistent with fake tensor's dtype. + # Skip decorating if the input is quantized and thus not floating point. + if ( + "output_qparams" in input.node.meta + and len(input.node.meta["output_qparams"]) > 0 + ): + return super().call_operator(op, args, kwargs, meta) + + op_full, op_ge, op_floor, op_ceil, op_where = _get_decorated_ops(op) + + zero = super().call_operator( + op_full, + args=((1,) * len(meta["val"].size()), 0.0), + kwargs={"dtype": torch.float32}, + meta=meta, + updated=True, + ) + + is_non_negative = super().call_operator( + op_ge, (input, zero), {}, meta, updated=True + ) + floor_x = super().call_operator(op_floor, (input,), {}, meta, updated=True) + ceil_x = super().call_operator(op_ceil, (input,), {}, meta, updated=True) + decorated_x = super().call_operator( + op_where, (is_non_negative, floor_x, ceil_x), {}, meta, updated=True + ) + + return super().call_operator(op, (decorated_x,), kwargs, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py new file mode 100644 index 0000000..0ecb7ff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py @@ -0,0 +1,394 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import copy + +from typing import cast, Optional, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + get_param_tensor, + is_param_node, + set_node_arg, +) +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass + +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm._passes.remove_noop_pass import RemoveNoopPass +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.exir import ExportedProgram + +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +def _get_special_dtype(qspec: QuantArgs) -> TosaSpecialDtype | None: + if qspec.dtype == torch.int8: + if qspec.qmax == 7 and qspec.qmin == -7: + return TosaSpecialDtype.INT4 + return None + + +def get_input_qparams(node: Node) -> dict[int, QuantArgs]: + """ + Get the input quantization parameters from a node, set by the 'FoldAndAnnotateQParamsPass'. + Raises a ValueError if the node doesn't have any parameters set. + """ + if "input_qparams" not in node.meta.keys(): + raise ValueError( + f"No input quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + input_qparams = cast(dict[int, QuantArgs], node.meta["input_qparams"]) + if len(input_qparams) == 0: + raise ValueError( + f"No input quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + return input_qparams + + +def get_output_qparams(node: Node) -> dict[int, QuantArgs]: + """ + Get the output quantization parameters from a node, set by the 'FoldAndAnnotateQParamsPass'. + Raises a ValueError if the node doesn't have any parameters set. + """ + if "output_qparams" not in node.meta.keys(): + raise ValueError( + f"No output quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + output_qparams = cast(dict[int, QuantArgs], node.meta["output_qparams"]) + if len(output_qparams) == 0: + raise ValueError( + f"No output quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + return output_qparams + + +class FoldAndAnnotateQParamsPass(ArmPass): + """ + A pass that walks the graph and removes any DQ and Q nodes before and after the target + node. + The quantization parameters from the DQ/Q nodes are stored as meta values to be + accessible for later lowering and serialization passes. + The assumption is that the quantization annotation adds DQ nodes for all tensor + inputs to the target one Q node to the output. + + Example ('executorch_exir_dialects_edge__ops_' prefix removed from operators for readability): + + x_q: "i8[5]" = quantized_decomposed_quantize_per_tensor_default(x, 0.05487706884741783, -128, -128, 127, torch.int8) + + x_dq: "f32[5]" = quantized_decomposed_dequantize_per_tensor_default(x_q, 0.05487706884741783, -128, -128, 127, torch.int8) + aten_add_tensor: "f32[5]" = ops_aten_add_Tensor(x_dq, x_dq) + aten_add_tensor_q: "i8[5]" = quantized_decomposed_quantize_per_tensor_default(aten_add_tensor, 0.05487706884741783, -128, -128, 127, torch.int8) + + output_dq: "f32[5]" = quantized_decomposed_dequantize_per_tensor_default(aten_add_tensor_q, 0.05487706884741783, -128, -128, 127, torch.int8) + + Becomes: + x_q: "i8[5]" = quantized_decomposed_quantize_per_tensor_default(x, 0.05487706884741783, -128, -128, 127, torch.int8) + + aten_add_tensor: "i8[5]" = aten_add_Tensor(x_q, x_q) + + output_dq: "f32[5]" = quantized_decomposed_dequantize_per_tensor_default(aten_add_tensor_q, 0.05487706884741783, -128, -128, 127, torch.int8) + + The quantization parameters for x_dq and aten_add_tensor_q are stored in meta for the aten_add_tensor node. + + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + RemoveNoopPass, + } + + def __init__( + self, exported_program: Optional[ExportedProgram] = None, *args, **kwargs + ) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def fold_and_annotate_arg( + self, graph_module: GraphModule, node: Node, arg_list: list[Node], i: int + ) -> None: + input_qparams = None + nodes_to_remove = set() + for arg in arg_list: + if not isinstance(arg, Node): + return + + arg_quant_params = None + if arg.target in DQ_OPS: + args = arg.args + scales = args[1] + if ( + isinstance(args[1], Node) + and self.exported_program is not None + and is_param_node(self.exported_program, args[1]) + ): + scales = get_param_tensor(self.exported_program, args[1]) + zps = args[2] + if ( + isinstance(args[2], Node) + and self.exported_program is not None + and is_param_node(self.exported_program, args[2]) + ): + zps = get_param_tensor(self.exported_program, args[2]) + arg_quant_params = QuantArgs.from_operator( + arg.target, (args[0], scales, zps, *args[3:]) + ) + # add arg to nodes_to_remove to fold the dq-node + nodes_to_remove.add(arg) + if input_qparams is not None and input_qparams != arg_quant_params: + # Two args are quantized differently + raise RuntimeError("Input qparams do not match") + input_qparams = arg_quant_params + if input_qparams is not None: + node.meta["input_qparams"][i] = input_qparams + for n in nodes_to_remove: + if n.target not in DQ_OPS: + raise RuntimeError( + f"Expected one of {DQ_OPS} dq_op, got {n.target}" + ) + + node.replace_input_with(n, cast(Node, n.args[0])) + if len(n.users) == 0: + graph_module.graph.erase_node(n) + special_dtype = _get_special_dtype(input_qparams) + if special_dtype: + node.all_input_nodes[i].meta[ + TosaSpecialDtype.meta_key() + ] = special_dtype + + def _handle_control_flow_node(self, node: Node, graph_module: GraphModule): + """Fold outmost quant nodes inside submodule. + placeholders => qs => dqs => ... => qs => dqs => output + becomes + placeholders => dqs => ... => qs => output, + With output_qparams meta in the placeholders, and input_qparams meta in the output node. + """ + match node.target: + case torch.ops.higher_order.cond: + submodule_nodes = cast(list[Node], node.args[1:3]) + args = cast(list[Node], node.args[-1]) + case torch.ops.higher_order.while_loop: + submodule_nodes = cast(list[Node], node.args[0:2]) + args = cast(list[Node], node.args[-2]) + case _: + raise ValueError(f"Unhandled target {node.target}") + submodules = ( + graph_module.get_submodule(str(submodule_node.target)) + for submodule_node in submodule_nodes + ) + for submodule in submodules: + submodule = cast(GraphModule, submodule) + output_node = submodule.graph.output_node() + output_node.meta["input_qparams"] = {} + nodes_to_remove = [] + arg_id = 0 + for submodule_node in submodule.graph.nodes: + # Remove initial q nodes and ending dq nodes in the module. + submodule_node = cast(Node, submodule_node) + if ( + submodule_node.target in Q_OPS + and list(submodule_node.all_input_nodes)[0].op == "placeholder" + ): + input_node = cast(Node, submodule_node.args[0]) + input_node.meta["val"] = submodule_node.meta["val"] + quant_args = QuantArgs.from_operator( + submodule_node.target, submodule_node.args + ) + input_node.meta["output_qparams"] = {0: quant_args} + + submodule_node.replace_all_uses_with(input_node) + nodes_to_remove.append(submodule_node) + if submodule_node.target in DQ_OPS: + has_non_output_user = False + for user in copy.copy(submodule_node.users): + if user.op != "output": + has_non_output_user = True + else: + input_node = cast(Node, submodule_node.args[0]) + submodule_node.replace_all_uses_with(input_node) + arg_index = cast(list[Node], output_node.args[0]).index( + input_node + ) + quant_args = QuantArgs.from_operator( + submodule_node.target, submodule_node.args + ) + output_node.meta["input_qparams"][arg_index] = quant_args + + # Remove dq node if it only has the output node as its user. + if not has_non_output_user: + nodes_to_remove.append(submodule_node) + # Placeholders without users won't be retraced with correct dtype, do it manually. + # Control flow node input is matched to placeholder nodes in the submodule by index. + # This means it will break if another pass inserts a placeholder before this pass. + if submodule_node.op == "placeholder": + if len(submodule_node.users) == 0: + submodule_node.meta["val"] = args[arg_id].meta["val"] + arg_id += 1 + if arg_id > len(args): + raise RuntimeError( + "Submodule had more placeholders than calling node had inputs." + " This is probably due to a placeholder being inserted in a pass." + ) + for node_to_remove in nodes_to_remove: + submodule.graph.erase_node(node_to_remove) + return + + @staticmethod + def is_foldable(node: Node) -> bool: + if node.op != "call_function": + return False + # Don't fold chains of quant-ops into each other. + if node.target in (*Q_OPS, *DQ_OPS): + return False + + # Always fold q-dq into constant ops. + if node.target in ( + exir_ops.edge.aten.full_like.default, + *ComputeConstantOpsAOTPass.targeted_ops, + ): + return True + + # We should not fold q-dq nodes into non-quantized nodes. + if not ( + ArmAnnotationInfo.CUSTOM_META_KEY in node.meta.get("custom", {}) + and ArmAnnotationInfo( + node.meta["custom"][ArmAnnotationInfo.CUSTOM_META_KEY] + ).quantized + ): + return False + return True + + def call(self, graph_module: GraphModule) -> PassResult: # noqa: C901 + + # Loop over the graph nodes and find any node in the 'targeted_ops' list. + for n in graph_module.graph.nodes: + n = cast(Node, n) + if not FoldAndAnnotateQParamsPass.is_foldable(n): + continue + + # Make sure we haven't already set qparams meta information on the node + if "input_qparams" in n.meta: + raise RuntimeError( + f'Unexpected key "input_qparams" found in meta for node {n}. ' + "input_qparams should not have been set at this point" + ) + if "output_qparams" in n.meta: + raise RuntimeError( + f'Unexpected key "output_qparams" found in meta for node {n}. ' + "output_qparams should not have been set at this point" + ) + + # for the inputs and outputs search the graph for quantization info and + # store the information in a dict with order of the _tensor_ inputs as key, + # ignoring any other arguments to the target node. + n.meta["input_qparams"] = {} + n.meta["output_qparams"] = {} + for i, arg in enumerate(n.args): + if isinstance(arg, (list, tuple)): + self.fold_and_annotate_arg(graph_module, n, arg, i) # type: ignore + + elif isinstance(arg, Node): + self.fold_and_annotate_arg(graph_module, n, [arg], i) + + # Copy the users, since we are modifying it. + users_copy = copy.copy(n.users) + for i, user in enumerate(users_copy): + if user.target not in Q_OPS: + continue + + # quantization node found here, store the quantization parameters in meta value + n.meta["output_qparams"][i] = QuantArgs.from_operator( + user.target, user.args + ) + + user.replace_all_uses_with(n) + graph_module.graph.erase_node(user) + + # Some op(s) contain a "dtype" key in their node kwargs. Set this + # to the type of output qparams. + output_qparams = n.meta["output_qparams"] + if ( + n.target in {exir_ops.edge.aten.sum.dim_IntList} + and len(output_qparams) > 0 + ): + output_dtype = output_qparams[0].dtype + set_node_arg(n, "dtype", output_dtype) + + if n.target in ( + torch.ops.higher_order.cond, + torch.ops.higher_order.while_loop, + ): + self._handle_control_flow_node(n, graph_module) + + # retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + + graph_module.recompile() + return PassResult(graph_module, True) + + +class QuantizeClampArgumentsPass(ArmPass): + """ + This pass makes sure that the arguments to clamp.default are quantized correctly. + More specifically, this pass: + - Makes sure the min and max values to clamp.default are quantized, if it's a quantized operator. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + # Loop over the graph nodes and find full.default nodes. + for n in graph_module.graph.nodes: + n = cast(Node, n) + if n.target not in { + exir_ops.edge.aten.clamp.default, + }: + continue + + try: + output_qparams = get_output_qparams(n) + except ValueError: + continue + if len(output_qparams) == 0: + continue + + # Qparams are stored per user index; use the first entry. + qargs = next(iter(output_qparams.values())) + + if n.target == exir_ops.edge.aten.clamp.default: + # Quantize the min and max arguments of clamp, if they are not None + min_val = n.args[1] + max_val = None if len(n.args) <= 2 else n.args[2] + + if min_val is not None: + quantized_min_val = qargs.quantize_value(min_val).item() + n.update_arg(1, quantized_min_val) + + if max_val is not None: + quantized_max_val = qargs.quantize_value(max_val).item() + n.update_arg(2, quantized_max_val) + + modified = True + + if modified: + # Retrace to refresh fake tensor metadata after updating clamp min/max. + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_batch_norm2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_batch_norm2d_pass.py new file mode 100644 index 0000000..d1b2aa4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_batch_norm2d_pass.py @@ -0,0 +1,241 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm.common.debug import get_node_debug_info +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + delete_constant_placeholder, +) +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch._export.utils import get_buffer, get_param +from torch.export.graph_signature import InputKind +from torch.fx import Node +from torch.nn.utils.fusion import fuse_conv_bn_weights + + +class FuseBatchNorm2dPass(ArmPass): + """Fuses the pattern convolution -> batchnorm by updating + the weights and bias of the convolution and removing the batchnorm. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def get_bias_name(self, weight_node: Node, bias_node: Node | None) -> str: + if bias_node: + return bias_node.name + "_fused_bn" + elif "weight" in weight_node.name: + return weight_node.name.replace("weight", "bias") + "_fused_bn" + else: + return weight_node.name + "_bias_fused_bn" + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901 + modified = False + constant_placeholders_to_delete = set() + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if ( + node.target + != exir_ops.edge.aten._native_batch_norm_legit_no_training.default + ): + continue + + # Get data from batchnorm + input_node = node.all_input_nodes[0] + is_single_user = len(input_node.users) == 1 + bn_weight_node, bn_bias_node, bn_mean_node, bn_var_node = node.args[1:5] + if bn_mean_node is None: + raise RuntimeError( + "BatchNorm mean buffer missing for node: " + f"{get_node_debug_info(node, graph_module)}" + ) + if bn_var_node is None: + raise RuntimeError( + "BatchNorm variance buffer missing for node: " + f"{get_node_debug_info(node, graph_module)}" + ) + + epsilon = node.args[-1] + + bn_weight_tensor = ( + get_param(self.exported_program, bn_weight_node) + if bn_weight_node is not None + else None + ) + bn_bias_tensor = ( + get_param(self.exported_program, bn_bias_node) + if bn_bias_node is not None + else None + ) + + bn_mean_tensor = torch.Tensor( + get_buffer(self.exported_program, bn_mean_node) + ) + bn_var_tensor = torch.Tensor(get_buffer(self.exported_program, bn_var_node)) + + if ( + input_node.target != exir_ops.edge.aten.convolution.default + or not is_single_user + ): + # Insert a transparent conv2d before bn to fuse with if none is present. + shape = get_first_fake_tensor(node) + if len(shape.size()) == 3: + input_weight_tensor = torch.ones((1, 1, 1)) + stride = [1] + padding = [0] + dilation = [1] + output_padding = [0] + else: + input_weight_tensor = torch.ones((1, 1, 1, 1)) + stride = [1, 1] + padding = [0, 0] + dilation = [1, 1] + output_padding = [0, 0] + + with graph_module.graph.inserting_before(bn_weight_node): + input_weight_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + name=node.name + "_conv_weight", + data=input_weight_tensor, + ) + + input_bias_tensor = input_bias_node = None + + with graph_module.graph.inserting_before(node): + channels = bn_mean_tensor.size(0) + conv_args = ( + input_node, + input_weight_node, + input_bias_node, + stride, + padding, + dilation, + False, # Transposed + output_padding, + channels, + ) + new_input_node = create_node( + graph_module.graph, + exir_ops.edge.aten.convolution.default, + conv_args, + ) + node.replace_input_with(input_node, new_input_node) + input_node = new_input_node + else: + input_weight_node, input_bias_node = input_node.args[1:3] + if not ( + isinstance(input_weight_node, Node) + and input_weight_node.op == "placeholder" + ): + raise RuntimeError( + "Parameter weight of convolution must be a placeholder" + ) + if not ( + (input_bias_node is None) + or ( + isinstance(input_weight_node, Node) + and input_weight_node.op == "placeholder" + ) + ): + raise RuntimeError( + "Parameter bias of convolution must be a placeholder or None" + ) + + input_weight_tensor = torch.Tensor( + get_param(self.exported_program, input_weight_node) + ) + + input_bias_tensor = ( + get_param(self.exported_program, input_bias_node) + if input_bias_node is not None + else None + ) + + # Fuse bn weights/bias with input weights/bias + fused_weight, fused_bias = fuse_conv_bn_weights( + input_weight_tensor, + input_bias_tensor, + bn_mean_tensor, + bn_var_tensor, + epsilon, + bn_weight_tensor, + bn_bias_tensor, + ) + + # Create fused weights and bias to conv and replace conv args + with graph_module.graph.inserting_before(input_weight_node): + fused_conv_weight_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + name=input_weight_node.name + "_fused_bn", + data=fused_weight, + ) + + if fused_bias is not None: + fused_input_bias_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + name=self.get_bias_name(input_weight_node, input_bias_node), + data=fused_bias, + ) + else: + fused_input_bias_node = None + + input_node.args = ( + input_node.args[0], + fused_conv_weight_node, + fused_input_bias_node, + *input_node.args[3:], + ) + + # Erasing batch-norm nodes is handled by dead-code elimination. After that we may remove their constant placeholder inputs + for user in node.users: + user.replace_all_uses_with(input_node) + + constant_placeholders_to_delete.update( + [ + bn_weight_node, + bn_bias_node, + bn_mean_node, + bn_var_node, + input_weight_node, + input_bias_node, + ] + ) + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + for constant_placeholder in constant_placeholders_to_delete: + if (constant_placeholder is not None) and ( + len(constant_placeholder.users) == 0 + ): + delete_constant_placeholder( + self.exported_program, constant_placeholder + ) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module=graph_module, modified=modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_constant_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_constant_ops_pass.py new file mode 100644 index 0000000..c29603d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_constant_ops_pass.py @@ -0,0 +1,272 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Set, Type + +import torch._export.utils +import torch.fx +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + get_constant_placeholder_kind, + get_first_fake_tensor, + get_param_tensor, + is_persistent_buffer, +) +from executorch.backends.arm._passes.fuse_equal_placeholders_pass import ( + FuseEqualPlaceholdersPass, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + delete_constant_placeholder, +) +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind + +logger = logging.getLogger(__name__) + + +class FuseConstantArgsPass(ArmPass): + """ + Fuses ops with only placeholder parameters into one placeholder parameter node with the op + pre-calulcated on its data. + + Original: + state_dict = {x_tensor_name : data} + def f(): + return x.view(...) + + After pass: + state_dict = {x_tensor_name_fused_const : data.view(...)} + def f(): + return x + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def _propagate_special_dtype(self, from_nodes, to_node, data): + """Propagate special dtype meta if it exists.""" + special_dtypes = set() + for input_node in from_nodes: + special_type = input_node.meta.get(TosaSpecialDtype.meta_key(), None) + if special_type: + special_dtypes.add(special_type) + if len(special_dtypes) > 1: + logger.warning( + "Propagating mixed special dtypes is not implemented, skipping." + ) + elif len(special_dtypes) == 1: + special_dtype = list(special_dtypes)[0] + # Make sure data is still within special dtype range. + if data.abs().max() <= special_dtype.max(): + to_node.meta[TosaSpecialDtype.meta_key()] = special_dtype + + def _fuse_nodes(self, node) -> bool: + """ + Takes a node with only parameter inputs and replaces it with one constant tensor node with + the operations already carried out on the data. + """ + + input_nodes = list(node.all_input_nodes) + qparams = node.meta.get("input_qparams", None) + + def resolve_arg(arg): + if isinstance(arg, torch.fx.Node) and arg in input_nodes: + idx = input_nodes.index(arg) + t = get_param_tensor(self.exported_program, arg) + # Check if qparams exist for this arg + if qparams and idx in qparams.keys(): + t = qparams[idx].dequantize_value(t) + return t + if isinstance(arg, tuple): + return tuple(resolve_arg(x) for x in arg) + if isinstance(arg, list): + return [resolve_arg(x) for x in arg] + return arg + + new_args = tuple(resolve_arg(a) for a in node.args) + new_kwargs = {k: resolve_arg(v) for k, v in node.kwargs.items()} + + data = node.target(*new_args, **new_kwargs) + + # Only fuse if the tensor does not get bigger. + if data.numel() > get_first_fake_tensor(node).numel(): + return False + + if "output_qparams" in node.meta and len(node.meta["output_qparams"]) > 0: + q_params = node.meta["output_qparams"][0] + data = q_params.quantize_value(data) + + insert_pos = list(node.all_input_nodes)[0] + + # Make new node the same kind as the first constant input + input_kind = get_constant_placeholder_kind(self.exported_program, insert_pos) + persistent_buffer = is_persistent_buffer(self.exported_program, insert_pos) + + # Create new node + with node.graph.inserting_before(insert_pos): + const_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=node.graph, + kind=input_kind, + name=node.name + "_fused_const", + data=data, + persistent_buffer=persistent_buffer, + ) + + self._propagate_special_dtype(input_nodes, const_node, data) + + node.replace_all_uses_with(const_node) + + return True + + def call(self, graph_module): + modified = False + input_nodes_to_maybe_delete = set() + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target in [ + exir_ops.backend.tosa.MATMUL.default, + exir_ops.backend.tosa.RESCALE.default, + exir_ops.backend.tosa.RESIZE.default, + exir_ops.backend.tosa.TABLE.default, + exir_ops.backend.tosa.TRANSPOSE.default, + ]: + continue + + input_nodes = node.all_input_nodes + if len(input_nodes) == 0: + continue + input_nodes_constant = ( + torch._export.utils.is_param(self.exported_program, input_node) + or torch._export.utils.is_lifted_tensor_constant( + self.exported_program, input_node + ) + or torch._export.utils.is_buffer(self.exported_program, input_node) + for input_node in input_nodes + ) + if not all(input_nodes_constant): + continue + + try: + did_fuse = self._fuse_nodes(node) + if did_fuse: + logger.debug( + f"Fused constant op: {node.name} with placeholder inputs:" + f"{[input_node.name for input_node in input_nodes]}" + ) + modified |= did_fuse + graph_module.recompile() # Recompile needed to catch chains of constant ops + input_nodes_to_maybe_delete.update(input_nodes) + except Exception as e: + logger.warning( + f"\nFailed to fuse constant op {node.name} due to exception:\n{str(e)}" + ) + + if modified: + graph_module.graph.eliminate_dead_code() + for input_node in input_nodes_to_maybe_delete: + if len(input_node.users) == 0: + delete_constant_placeholder(self.exported_program, input_node) + + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) + + +class ComputeConstantOpsAOTPass(ArmPass): + """ + Evaluates call_functions that produce constant tensor outputs and replaces them with placeholders. + + Original: + state_dict = {} + def f(): + return torch.arange(0,10) + After pass: + state_dict = {node_name_pre_computed : torch.arange(0,10)} + def f(node_name_pre_computed): + return node_name_pre_computed + """ + + _passes_required_after: Set[Type[ExportPass]] = { + FuseEqualPlaceholdersPass, + FuseConstantArgsPass, + } + + targeted_ops = [ + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.eye.default, + exir_ops.edge.aten.linspace.default, + torch.ops.aten.scalar_tensor.default, + ] + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def compute_node_aot(self, node: torch.fx.Node) -> bool: + """ + Takes a node with only parameter inputs and replaces it with one constant tensor node with + the operations already carried out on the data. + """ + + # Create data from args + output_qparams = node.meta.get("output_qparams", None) + if output_qparams: + # If we have output_qparams, compute data in fp and quantize + data = node.target(*node.args) # type: ignore + output_qparams = output_qparams[0] + data = output_qparams.quantize_value(data) + else: + # If we don't have output_qparams, compute data using kwarg-specified dtype + data = node.target(*node.args, **node.kwargs) # type: ignore + + # Create new node + insert_pos = list(node.graph.nodes)[0] + input_kind = InputKind.BUFFER + persistent_buffer = True + + with node.graph.inserting_before(insert_pos): + const_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=node.graph, + kind=input_kind, + name=node.name + "_pre_computed", + data=data, + persistent_buffer=persistent_buffer, + ) + node.replace_all_uses_with(const_node) + + return True + + def call(self, graph_module): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target not in self.targeted_ops: + continue + try: + modified |= self.compute_node_aot(node) + except Exception as e: + logger.warning( + f"\nFailed to pre-compute op {node.name} due to exception:\n{str(e)}" + ) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_duplicate_users_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_duplicate_users_pass.py new file mode 100644 index 0000000..217d933 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_duplicate_users_pass.py @@ -0,0 +1,165 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from collections import deque +from typing import Any, Deque, Dict, Hashable, List, Set, Tuple, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, PassResult +from torch._ops import OpOverload +from torch.fx import GraphModule, Node +from torch.fx.node import Argument, map_arg + + +class FuseDuplicateUsersPass(ArmPass): + """Fuse identical users of a producer node into a single operation. + + Example: + + y = producer(x) + z0 = torch.add(y, bias) + z1 = torch.add(y, bias) + + becomes a single ``torch.add`` that feeds both consumers. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: GraphModule) -> PassResult: + graph = graph_module.graph + modified = False + + producers: Deque[Node] = deque(node for node in graph.nodes) + + while producers: + producer = producers.popleft() + + if producer.graph is None: + # Node was deleted by a previous rewrite while still queued. + continue + + # Only meaningful if a value is consumed by multiple users. + user_nodes = list(producer.users) + if len(user_nodes) < 2: + continue + + candidate_groups = self._get_candidate_groups(user_nodes) + + signature_to_user: Dict[Tuple[Hashable, ...], Node] = {} + for group in candidate_groups: + for user in group: + signature = self._build_user_signature(user) + if signature is None: + continue + + representative = signature_to_user.get(signature) + if representative is None: + # Check if we already encountered identical node that we can fuse with. + signature_to_user[signature] = user + continue + + if user is representative: + # The queue can enqueue the surviving node again after rewrites. + continue + + user.replace_all_uses_with(representative) + graph.erase_node(user) + modified = True + + # Revisit the current producer and the surviving user so that + # newly formed duplicate chains can be fused in later + # iterations. + producers.append(producer) + producers.append(representative) + + if modified: + graph_module.recompile() + graph_module.graph.lint() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) + + def _get_candidate_groups(self, user_nodes): + users_by_target: Dict[Tuple[str, Hashable], List[Node]] = {} + for user in user_nodes: + if user.graph is None: + # User might already have been removed by a prior rewrite. + continue + + if user.op != "call_function": + continue + + target_key = self._get_target_key(user.target) + target_signature = (user.op, target_key) + users_by_target.setdefault(target_signature, []).append(user) + + candidate_groups = [ + group for group in users_by_target.values() if len(group) > 1 + ] + + return candidate_groups + + def _build_user_signature(self, node: Node) -> Tuple[Hashable, ...] | None: + try: + normalized_args = self._to_hashable( + map_arg(node.args, self._map_leaf_to_key) + ) + normalized_kwargs = self._to_hashable( + {k: map_arg(v, self._map_leaf_to_key) for k, v in node.kwargs.items()} + ) + except TypeError: + return None + + target_key = self._get_target_key(node.target) + + return (node.op, target_key, normalized_args, normalized_kwargs) + + def _map_leaf_to_key(self, node: Node) -> Argument: + return node.name + + def _to_hashable(self, value: Any) -> Hashable: + """Convert arbitrarily nested structures into hashable tuples.""" + + if isinstance(value, (list, tuple)): + return tuple(self._to_hashable(v) for v in value) + if isinstance(value, dict): + normalized_items = [(k, self._to_hashable(v)) for k, v in value.items()] + return tuple(sorted(normalized_items, key=lambda item: repr(item[0]))) + if isinstance(value, set): + hashable_values: List[Hashable] = [self._to_hashable(v) for v in value] + return tuple(sorted(hashable_values, key=repr)) + if isinstance(value, slice): + return ( + "slice", + self._to_hashable(value.start), + self._to_hashable(value.stop), + self._to_hashable(value.step), + ) + if isinstance(value, range): + return ("range", value.start, value.stop, value.step) + if isinstance(value, torch.Size): + return ("size", tuple(value)) + if isinstance(value, torch.dtype): + return ("dtype", str(value)) + if isinstance(value, torch.device): + return ("device", str(value)) + if isinstance(value, torch.memory_format): + return ("memory_format", str(value)) + if isinstance(value, torch.Tensor): + return ( + "tensor", + str(value.dtype), + tuple(value.size()), + value.device.type, + value.requires_grad, + ) + return value + + def _get_target_key(self, target: Any) -> Hashable: + if isinstance(target, (EdgeOpOverload, OpOverload)): + return str(target) + return target diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_equal_placeholders_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_equal_placeholders_pass.py new file mode 100644 index 0000000..37cac8a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_equal_placeholders_pass.py @@ -0,0 +1,104 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import hashlib +from collections import defaultdict +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + get_constant_placeholder_kind, + get_param_tensor, + is_param_node, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + delete_constant_placeholder, +) +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass, PassResult + + +class FuseEqualPlaceholdersPass(ArmPass): + """ + This pass optimizes memory usage by finding constant placeholders + pointing to identical tensors and fusing them to one single placeholder + with multiple users, using a cache for faster comparison. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + modified = False + + # Build a cache of params: mapping hash_key -> list of (node, tensor) + hash_buckets = defaultdict(list) + for node in graph_module.graph.nodes: + if not is_param_node(self.exported_program, node): + continue + tensor = get_param_tensor(self.exported_program, node) + if tensor is None: + continue + # Create a lightweight fingerprint: dtype + shape + SHA1 of raw bytes + # Ensure tensor is on CPU and contiguous + + # ensure we don't merge any special case int48_t tensors with int32_t tensors + # since int48_t tensors needs to be instantiated separately. + is_special_dtype = node.meta.get(TosaSpecialDtype.meta_key(), None) + t_cpu = tensor.detach().cpu().contiguous() + data_bytes = t_cpu.numpy().tobytes() + key = ( + is_special_dtype, + str(t_cpu.dtype), + tuple(t_cpu.shape), + hashlib.sha1(data_bytes, usedforsecurity=False).hexdigest(), + ) + hash_buckets[key].append((node, t_cpu)) + + # For each bucket with more than one entry, fuse: + for nodes_tensors in hash_buckets.values(): + if len(nodes_tensors) < 2: + continue + + # Create a new placeholder from first in list of equal placeholders. + rep_node, rep_tensor = nodes_tensors[0] + common_name = rep_node.name + "_common" + common_kind = get_constant_placeholder_kind(self.exported_program, rep_node) + common_persistent = True + with graph_module.graph.inserting_before(rep_node): + common_node = create_constant_placeholder( + self.exported_program, + graph_module.graph, + common_name, + common_kind, + rep_tensor, + common_persistent, + ) + + # TBD: Find a principled way to merge node.meta across all fused node + # For now, i specifically transfer over the TosaSpecialDtype.meta_key() of the rep_node + if TosaSpecialDtype.meta_key() in rep_node.meta: + common_node.meta[TosaSpecialDtype.meta_key()] = rep_node.meta[ + TosaSpecialDtype.meta_key() + ] + + # Replace uses and delete duplicates + for node, _ in nodes_tensors: + node.replace_all_uses_with(common_node) + delete_constant_placeholder(self.exported_program, node) + modified = True + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module=graph_module, modified=modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_quantized_activation_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_quantized_activation_pass.py new file mode 100644 index 0000000..09e989c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_quantized_activation_pass.py @@ -0,0 +1,80 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_to_clamp_pass import ConvertToClampPass +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + FoldAndAnnotateQParamsPass, +) +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm.constants import Q_OPS +from executorch.backends.transforms.remove_getitem_op import RemoveGetItemPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import Node + + +class FuseQuantizedActivationPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = { + ConvertToClampPass, + FoldAndAnnotateQParamsPass, + RemoveGetItemPass, + } + + @staticmethod + def _is_fuseable_quantized_activation(node: Node): + """Fuse activations that have a 0 lower bound and quantized with a qmin zero-point""" + is_fuseable = node.target == exir_ops.edge.aten.relu.default + if node.target == exir_ops.edge.aten.hardtanh.default: + min_val = node.args[1] + is_fuseable = min_val == 0 + + is_quantized = len(node.users) == 1 and next(iter(node.users)).target in Q_OPS + if is_fuseable and is_quantized: + quant_node = next(iter(node.users)) + quant_args = QuantArgs.from_operator(quant_node.target, quant_node.args) + zp = quant_args.zp + qmin = quant_args.qmin + return zp == qmin + else: + return False + + @staticmethod + def _is_fuseable_input(node: Node): + return ( + node.target + in ( + exir_ops.edge.aten.convolution.default, + exir_ops.edge.aten.linear.default, + ) + and len(node.users) == 1 + ) + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + + if not FuseQuantizedActivationPass._is_fuseable_quantized_activation(node): + continue + + input_node = node.args[0] + if not FuseQuantizedActivationPass._is_fuseable_input(input_node): + continue + + node.replace_all_uses_with(input_node) + graph_module.graph.erase_node(node) + modified = True + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_view_copy_transform_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_view_copy_transform_pass.py new file mode 100644 index 0000000..cef3b40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/fuse_view_copy_transform_pass.py @@ -0,0 +1,14 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.transforms.fuse_view_copy import FuseViewCopyTransform +from executorch.exir.pass_base import ExportPass + + +class FuseViewCopyTransformPass(ArmPass, FuseViewCopyTransform): + _passes_required_after: Set[Type[ExportPass]] = set() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py new file mode 100644 index 0000000..de80d61 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py @@ -0,0 +1,130 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_embedding_pass import ( + DecomposeEmbeddingPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import EdgeOpOverload, ExportPass, PassResult +from torch._subclasses.fake_tensor import FakeTensor + + +logger = logging.getLogger(__name__) + + +class InsertInt32CastsAfterInt64PlaceholdersPass(ArmPass): + """ + Insert an int64->int32 cast after each int64 placeholder. + + Note: Overflow checks are not applied in this pass. It is the user's responsibility to ensure that values fit within + the int32 range. + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeEmbeddingPass} + + # Ops that require i64 inputs → positions of args to upcast. + # Key: op overload; Value: zero-based indices of positional args that must be i64. + I64_INPUT_ARG_POSITIONS = { + torch.ops.aten.one_hot.default: (0,), + torch.ops.aten.index_copy_.default: (2,), + torch.ops.aten.index_copy.default: (2,), + } + + def _insert_callsite_i32_to_i64_casts(self, graph_module: torch.fx.GraphModule): + """ + If an operator requires int64 inputs but dtype propagation (via call_operator) + produced int32, insert a local int32→int64 cast at the call site to satisfy + PyTorch's operator input validation. + """ + modified = False + graph = graph_module.graph + for node in graph.nodes: + if node.op != "call_function": + continue + if node.target not in self.I64_INPUT_ARG_POSITIONS: + continue + + with graph.inserting_before(node): + arg_positions = self.I64_INPUT_ARG_POSITIONS.get(node.target) + args_list = list(node.args) + for pos in arg_positions: # type: ignore[union-attr] + input_arg = args_list[pos] + to_copy_op = self._get_decomposition(graph) + cast_node = graph_module.graph.create_node( + "call_function", + to_copy_op, + (input_arg,), + {"dtype": torch.int64}, + ) + cast_node.meta["val"] = node.meta["val"].to(torch.int64) + args_list[pos] = cast_node + node.args = tuple(args_list) + modified = True + return modified + + def _graph_uses_edge_ops(self, graph: torch.fx.Graph) -> bool: + for n in graph.nodes: + if n.op == "call_function": + if isinstance(n.target, EdgeOpOverload): + return True + return False + + def _get_decomposition(self, graph: torch.fx.Graph): + if self._graph_uses_edge_ops(graph): + return exir_ops.edge.dim_order_ops._to_dim_order_copy.default + else: + return torch.ops.dim_order_ops._to_dim_order_copy.default + + def _is_tensor_of_dtype(self, node_val, dtype: torch.dtype) -> bool: + return isinstance(node_val, FakeTensor) and node_val.dtype == dtype + + def _insert_placeholder_i64_to_i32_casts(self, graph_module: torch.fx.GraphModule): + modified = False + graph = graph_module.graph + for node in graph.nodes: + if node.op != "placeholder": + continue + node_val = node.meta["val"] + if not self._is_tensor_of_dtype(node_val, torch.int64): + continue + + to_copy_op = self._get_decomposition(graph) + with graph.inserting_after(node): + cast_after = create_node( + graph, + to_copy_op, + args=(node,), + kwargs={ + "dtype": torch.int32, + }, + ) + users = [user for user in node.users if user != cast_after] + for user in users: + user.replace_input_with(node, cast_after) + logger.warning( + f"Inserting a casting node {cast_after.name} after {node.name} to cast int64 placeholder" + f" to int32 for {node.name} defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + modified = True + return modified + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + modified |= self._insert_placeholder_i64_to_i32_casts(graph_module) + modified |= self._insert_callsite_i32_to_i64_casts(graph_module) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_rescales_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_rescales_pass.py new file mode 100644 index 0000000..9e69a1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_rescales_pass.py @@ -0,0 +1,584 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from copy import copy +from typing import cast, Dict, Optional, Set, Tuple, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node, set_node_arg +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_output_qparams, +) + +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +class InsertRescalePass(ArmPass): + """Finds patterns of dq -> q, and replaces them + with backend dialect tosa::RESCALE op. + + Does not guarantee that the dtypes and zero points are valid + in TOSA, that is the job of the quantization annotator that + produced the dq and q nodes. The TOSA constraints are validated + in the fake implementation of. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def fold_dq_q_to_rescale(self, node: Node, user: Node, graph_module: GraphModule): + dq_args = QuantArgs.from_operator(node.target, node.args) + q_args = QuantArgs.from_operator(user.target, user.args) + new_scale = dq_args.scale / q_args.scale + + with graph_module.graph.inserting_before(node): + rescale_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.RESCALE.default, + ( + node.all_input_nodes[0], + q_args.dtype, + [new_scale], + dq_args.zp, + q_args.zp, + ), + ) + rescale_node.meta = copy(user.meta) + user.replace_all_uses_with(rescale_node) + graph_module.graph.erase_node(user) + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + node = cast(Node, node) + + if node.target not in DQ_OPS: + continue + # Copy users since we remove them while iterating, modyfing the node.users list. + for user in copy(node.users): + if user.target in Q_OPS: + self.fold_dq_q_to_rescale(node, user, graph_module) + modified = True + if len(node.users) == 0: + graph_module.graph.erase_node(node) + + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + return PassResult(graph_module, modified) + + +class InsertRescaleInt32Pass(ArmPass): + """Numerous TOSA ops require inputs and outputs to be 32-bit integers in their + quantized implementations. This pass treats such operator nodes by + inserting rescale ops before and after them if needed. Note that extra + logic that handles the scales and zero points are in place here because the + affected TOSA ops have naive implementations that do not account for the + quantization parameters. + """ + + # SUM must be decomposed after this pass to prevent insertion of RESCALE + # nodes between each subsequent SUM node after decomposition. RESCALE nodes + # should only be inserted before and after the SUM node prior to its + # decomposition. + _passes_required_after: Set[Type[ExportPass]] = {DecomposeSumPass} + + included_targets = [ + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.sum.dim_IntList, + ] + + def _int32_qargs(self, s): + """Helper creator function for INT32-based QuantArgs""" + + return QuantArgs( + scale=s, + zp=0, + qmin=torch.iinfo(torch.int32).min, + qmax=torch.iinfo(torch.int32).max, + dtype=torch.int32, + ) + + def _get_inputs_rescaled_qparams( + self, target, input_qparams: Dict[int, QuantArgs] + ) -> Dict[int, QuantArgs]: + """Get the qparams for the INT32 operands to the op ``target`` + + Inputs to the INT32-based operator must be rescaled from INT8 to INT32. + This function computes the ``QuantArgs`` for each of the operands and returns + it as a dict, mapping tensor index to ``QuantArgs``. + """ + + if target in [ + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.maximum.default, + ]: + # For these ops, use the smallest scale among the INT8 operands. + min_scale = min( + [qp.get_scale_per_tensor() for qp in input_qparams.values()] + ) + qparams = {i: self._int32_qargs(min_scale) for i in input_qparams.keys()} + elif target in [ + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + ]: + keys = list(input_qparams) + if len(keys) < 2: + raise ValueError(f"Expected two input qparams, got: {input_qparams}.") + if input_qparams[keys[0]].dtype != input_qparams[keys[1]].dtype: + raise ValueError( + f"Mismatch in dtype args: {input_qparams[keys[0]].dtype} != {input_qparams[keys[1]].dtype}" + ) + + # We are handling two INT8 or two INT16 numbers. For INT8, if the + # zero point is non-null, the result will be in the range [-255; + # 255], therefore we need 9 bits for the result. We have a 32-bit + # accumulator, so we can divide the scale by (1 << 20) which is + # equivalent to shifting the INT8 operands 20 bits to the left + # before rescaling them both to 2 * max(lhs, rhs). + # + # For INT16, similary logic can be applied, but we instead end up + # with a left shift of 12. + lhs_scale, rhs_scale = ( + qp.get_scale_per_tensor() for qp in input_qparams.values() + ) + max_scale_2x = 2 * max(lhs_scale, rhs_scale) + + # Select shift based on input dtype. + shift_bits = 12 if input_qparams[keys[0]].dtype == torch.int16 else 20 + + scale = max_scale_2x / (1 << shift_bits) + qparams = {i: self._int32_qargs(scale) for i in input_qparams.keys()} + elif target in [ + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sum.dim_IntList, + ]: + # The input scales do not need to be adjusted for these ops; they + # can remain the same. + qparams = { + i: self._int32_qargs(qp.get_scale_per_tensor()) + for i, qp in input_qparams.items() + } + else: + raise ValueError(f"Not a valid target: {target}") + + return qparams + + def _get_output_qparams( + self, target, inputs_qparams: Dict[int, QuantArgs] + ) -> Optional[QuantArgs]: + """Given an op ``target`` and the ``QuantArgs`` for each of its inputs, compute + the scale of the output based on how the operator itself affects it.""" + + if target in [ + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + ]: + # The op has not altered the scale; the output scale is equal to + # the operands' scales. + return self._int32_qargs(inputs_qparams[0].get_scale_per_tensor()) + elif target in [ + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.lt.Tensor, + ]: + # Output is bool for these ops and thus no qparams are present + return None + elif target in [exir_ops.edge.aten.mul.Tensor]: + # Mul will cause the scales to also multiply; refer to the formula + # where we compute the output scale S_2: + # + # (Q_2 - ZP_2) * S_2 == ((Q_0 - ZP_0) * S_0) * ((Q_1 - ZP_1) * S_1) + # + # yields: + # + # (Q_2 - ZP_2) == (Q_0 - ZP_0) * (Q_1 - ZP_1) + # S_2 = S_0 * S_1 + output_scale = math.prod( + (qp.get_scale_per_tensor() for qp in inputs_qparams.values()) + ) + return self._int32_qargs(output_scale) + else: + raise ValueError(f"Not a valid target: {target}") + + def _get_rescale_qparams( + self, target, input_qparams: Dict[int, QuantArgs] + ) -> Tuple[Dict[int, QuantArgs], Optional[QuantArgs]]: + """ + Get the quantization parameters of the INT32 inputs/outputs that will + surround the node after the new RESCALE ops have been inserted. + """ + + inputs_rescaled_qparams = self._get_inputs_rescaled_qparams( + target, input_qparams + ) + output_qparams = self._get_output_qparams(target, inputs_rescaled_qparams) + + return (inputs_rescaled_qparams, output_qparams) + + def _rescale_inputs(self, graph, node, rescale_qargs: Dict[int, QuantArgs]) -> bool: + qargs = node.meta["input_qparams"] + + args_copy = list(node.args) + seen_args = set() + modified = False + for i in qargs: + qp = qargs[i] + if qp.dtype not in (torch.int8, torch.int16): + continue + + arg_node = args_copy[i] + if arg_node in seen_args: + continue + seen_args.add(arg_node) + + with graph.inserting_after(arg_node): + rescale_node = create_node( + graph, + exir_ops.backend.tosa.RESCALE.default, + ( + arg_node, + torch.int32, + [ + qp.get_scale_per_tensor() + / rescale_qargs[i].get_scale_per_tensor() + ], # [Old scale / new scale] + qp.get_zp_per_tensor(), # Old zero point + rescale_qargs[i].get_zp_per_tensor(), # New zero point + ), + from_node=node, + ) + + node.replace_input_with(arg_node, rescale_node) + modified = True + + return modified + + def _rescale_outputs(self, graph, node, rescale_qargs: Optional[QuantArgs]) -> bool: + if "output_qparams" not in node.meta or len(node.meta["output_qparams"]) == 0: + return False + + qargs = get_output_qparams(node) + assert len(qargs) == 1 + assert rescale_qargs is not None + + qarg = qargs[0] + if qarg.dtype not in (torch.int8, torch.int16): + return False + + users_copy = list(node.users) + + with graph.inserting_after(node): + rescale_node = create_node( + graph, + exir_ops.backend.tosa.RESCALE.default, + ( + node, + qarg.dtype, + [ + rescale_qargs.get_scale_per_tensor() + / qarg.get_scale_per_tensor() + ], # [Old scale / new scale] + rescale_qargs.get_zp_per_tensor(), # Old zero point + qarg.get_zp_per_tensor(), # New zero point + ), + from_node=node, + ) + + for user in users_copy: + user.replace_input_with(node, rescale_node) + + return True + + def call(self, graph_module: GraphModule) -> PassResult: + graph = graph_module.graph + + modified = False + for node in list(graph.nodes): + node = cast(Node, node) + + if node.op != "call_function" or node.target not in self.included_targets: + continue + + if "input_qparams" not in node.meta or len(node.meta["input_qparams"]) == 0: + continue + input_qparams = node.meta["input_qparams"] + + inputs_rescale_qargs, output_rescale_qargs = self._get_rescale_qparams( + node.target, input_qparams + ) + + inputs_was_rescaled = self._rescale_inputs( + graph, node, inputs_rescale_qargs + ) + outputs_was_rescaled = False + if inputs_was_rescaled: + outputs_was_rescaled = self._rescale_outputs( + graph, node, output_rescale_qargs + ) + modified = True + + # Update node metadata + + if inputs_was_rescaled: + assert len(inputs_rescale_qargs) == len(node.meta["input_qparams"]) + node.meta["input_qparams"] = inputs_rescale_qargs + + if outputs_was_rescaled: + assert len(node.meta["output_qparams"]) == 1 + node.meta["output_qparams"] = {0: output_rescale_qargs} + + # If the output type is specified in the node, change it such + # that it matches the subsequent rescale node(s) that this node + # now has output edges to. + if "dtype" in node.kwargs: + set_node_arg(node, "dtype", torch.int32) + + if modified: + # Retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + + return PassResult(graph_module, modified) + + +class InsertControlFlowRescalesPass(ArmPass): + """The quantization parameters for tensors going into and coming out of a submodule are not guaranteed to + match the quantization parameters for the corresponding tensors inside the submodule. For example, cond has + different annotation on input and output, while the entire graph inside the submodule could be using shared + annotation. This pass solves this by inserting rescales in the beginning and end of the submodule + that transform the tensor from one set of quantization parameters to another. + + The pass is run by the graph_module containing the control flow operator, but requires that the affected nodes + inside the submodule have been q-dq folded and have input/output_qparams meta. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _get_input_nodes(self, graph_module: GraphModule): + return [node for node in graph_module.graph.nodes if node.op == "placeholder"] + + def _insert_rescale( + self, + in_qparams: QuantArgs, + out_qparams: QuantArgs, + from_node: Node, + graph_module: GraphModule, + ): + """Insert a rescale into the graph, inheriting meta from `from_node`. + The node is not connected to anything, that is up to the user.""" + + new_scales = [ + in_qparams.get_scale_per_tensor() / out_qparams.get_scale_per_tensor() + ] + + rescale_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.RESCALE.default, + ( + None, + out_qparams.dtype, + new_scales, + in_qparams.get_zp_per_tensor(), # Old zero point + out_qparams.get_zp_per_tensor(), # New zero point + ), + from_node=from_node, + ) + return rescale_node + + def _rescale_submodule_inputs( + self, submodule: GraphModule, input_qparams_map: Dict[int, QuantArgs] + ) -> bool: + """Insert rescales at the inputs of `submodule` to match the qparams outside the submodule. + Matching the correct qparams gets a bit tricky: + Containing module: | submodule: + ops => cond | => placeholders => ... + + The dq->q qparam pair we want to convert to a rescale is: + (input qparams of op, output qparams of placeholder) + And the rescale is inserted after the placeholder. + + Args: + submodule: GraphModule: the GraphModule in which to rescale the inputs. + input_qparams_map: A map of input indexes mapping to QuantArgs. Not guaranteed to contain a mapping + for every submodule input. + Returns: + True if at least one rescale was inserted, False otherwise. + """ + + modified = False + input_nodes = self._get_input_nodes(submodule) + for qargs_index in input_qparams_map: + input_node = input_nodes[qargs_index] + if len(input_node.users) == 0: + continue + if len(out_qparams_map := input_node.meta.get("output_qparams", {})) != 1: + raise ValueError( + f"Expected submodule input {input_node} to have exactly one output qparam, got {out_qparams_map}" + ) + in_qparams = input_qparams_map[qargs_index] + out_qparams = cast(QuantArgs, out_qparams_map[0]) + + # Remove qparam meta to not confuse folding pass. + del input_node.meta["output_qparams"] + if in_qparams == out_qparams: + continue + with submodule.graph.inserting_after(input_node): + modified = True + rescale_node = self._insert_rescale( + in_qparams, out_qparams, input_node, submodule + ) + input_node.replace_all_uses_with(replace_with=rescale_node) + rescale_node.update_arg(0, input_node) + return modified + + def _rescale_submodule_outputs( + self, submodule: GraphModule, output_qparams_map: Dict[int, QuantArgs] + ) -> bool: + """Insert rescales at the outputs of `submodule` to match the qparams outside the submodule. + Matching the correct qparams gets a bit tricky: + Submodule: | Containing module: + output_nodes => output |=> getitems => ... + + The dq->q qparam pair we want to convert to a rescale is: + (input qparam of output_node, output qparam of getitem) + And the rescale is inserted between op and output. Note that the output qparam of op is called input_qargs, + since the it is the input to the dq-q pair. + + Args: + submodule: GraphModule: the GraphModule in which to rescale the outputs. + output_qparams_map: A map of output indexes mapping to QuantArgs. Not guaranteed to contain a mapping + for every submodule output. + Returns: + True if at least one rescale was inserted, False otherwise. + """ + + modified = False + output_node = submodule.graph.output_node() + output_args = list(cast(tuple[Node], output_node.args[0])) + input_qparams_map = cast( + dict[int, QuantArgs], output_node.meta["input_qparams"] + ) + for qargs_index in output_qparams_map: + output_arg_node = output_args[qargs_index] + in_qparams = input_qparams_map[qargs_index] + out_qparams = output_qparams_map[qargs_index] + if in_qparams == out_qparams: + continue + with submodule.graph.inserting_before(output_node): + modified = True + rescale_node = self._insert_rescale( + in_qparams, out_qparams, output_arg_node, submodule + ) + output_args[qargs_index] = rescale_node + rescale_node.update_arg(0, output_arg_node) + output_node.update_arg(0, tuple(output_args)) + # Remove qparam meta to not confuse folding pass. + del output_node.meta["input_qparams"] + return modified + + def _get_input_qparams_map(self, node: Node, idx: int): + input_qparams_meta = cast( + dict[int, QuantArgs], node.meta.get("input_qparams", None) + ) + if input_qparams_meta: + input_qparams = cast(QuantArgs, input_qparams_meta.get(idx, None)) + if not input_qparams: + raise ValueError( + f"Expected entry with key {idx} in input_qparams meta, got {input_qparams_meta}" + ) + num_inputs = len(cast(list, node.args[idx])) + + # Currently, infra only supports one set of qparams for a list of inputs + # Map all inputs to the same qparams. + input_qparams_map = {i: input_qparams for i in range(num_inputs)} + return input_qparams_map + return None + + def _get_output_qparams_map(self, node: Node): + output_qparams_map: dict[int, QuantArgs] = {} + for getitem_node in node.users: + idx = cast(int, getitem_node.args[1]) + qparam = getitem_node.meta.get("output_qparams", None) + if qparam: + output_qparams_map[idx] = cast(QuantArgs, qparam[0]) + return output_qparams_map + + def _rescale_cond_submodules(self, node: Node, graph_module: GraphModule) -> bool: + modified = False + if_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[1].target)) # type: ignore + else_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[2].target)) # type: ignore + input_qparams_map = self._get_input_qparams_map(node, 3) + if input_qparams_map: + modified |= self._rescale_submodule_inputs(if_graph, input_qparams_map) + modified |= self._rescale_submodule_inputs(else_graph, input_qparams_map) + + output_qparams_map = self._get_output_qparams_map(node) + if output_qparams_map: + modified |= self._rescale_submodule_outputs(if_graph, output_qparams_map) + modified |= self._rescale_submodule_outputs(else_graph, output_qparams_map) + return modified + + def _rescale_while_submodules(self, node: Node, graph_module: GraphModule): + modified = False + cond_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[0].target)) # type: ignore + body_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[1].target)) # type: ignore + + input_qparams_map = self._get_input_qparams_map(node, 2) + if input_qparams_map: + modified |= self._rescale_submodule_inputs(cond_graph, input_qparams_map) + modified |= self._rescale_submodule_inputs(body_graph, input_qparams_map) + + output_qparams_map = self._get_output_qparams_map(node) + if output_qparams_map: + modified |= self._rescale_submodule_outputs(body_graph, output_qparams_map) + return modified + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + + for node in list(graph_module.graph.nodes): + node = cast(Node, node) + if node.op != "call_function": + continue + + if node.target == torch.ops.higher_order.cond: + modified = self._rescale_cond_submodules(node, graph_module) + if node.target == torch.ops.higher_order.while_loop: + modified = self._rescale_while_submodules(node, graph_module) + + if modified: + # Retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_table_ops.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_table_ops.py new file mode 100644 index 0000000..3daa4b9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/insert_table_ops.py @@ -0,0 +1,305 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from itertools import chain +from typing import Callable, cast, Dict, Iterator, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.transforms.utils import create_constant_placeholder + +from executorch.exir import ExportedProgram + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind +from torch.fx import GraphModule +from torch.fx.node import Node + + +class TableOps: + """ + Helper class for finding the corresponding table operator for a given Node. + """ + + # Targets that follow a straigtforward one-to-one mapping to their table op + unary_table_ops: Dict[EdgeOpOverload, Callable[[torch.Tensor], torch.Tensor]] = { + exir_ops.edge.aten.ceil.default: torch.ceil, + exir_ops.edge.aten.erf.default: torch.erf, + exir_ops.edge.aten.exp.default: torch.exp, + exir_ops.edge.aten.expm1.default: torch.expm1, + exir_ops.edge.aten.floor.default: torch.floor, + exir_ops.edge.aten.log.default: torch.log, + exir_ops.edge.aten.log1p.default: torch.log1p, + exir_ops.edge.aten.reciprocal.default: torch.reciprocal, + exir_ops.edge.aten.rsqrt.default: torch.rsqrt, + exir_ops.edge.aten.sigmoid.default: torch.sigmoid, + exir_ops.edge.aten.cos.default: torch.cos, + exir_ops.edge.aten.sin.default: torch.sin, + exir_ops.edge.aten.tanh.default: torch.tanh, + exir_ops.edge.aten.atan.default: torch.atan, + exir_ops.edge.aten.atanh.default: torch.atanh, + exir_ops.edge.aten.hardsigmoid.default: torch.nn.functional.hardsigmoid, + exir_ops.edge.aten.hardswish.default: torch.nn.functional.hardswish, + exir_ops.edge.aten.sinh.default: torch.sinh, + exir_ops.edge.aten.acosh.default: torch.acosh, + exir_ops.edge.aten.asin.default: torch.asin, + exir_ops.edge.aten.asinh.default: torch.asinh, + exir_ops.edge.aten.cosh.default: torch.cosh, + exir_ops.edge.aten.acos.default: torch.acos, + exir_ops.edge.aten.tan.default: torch.tan, + } + + # Targets that must be treated explicitly + special_table_ops: Set[EdgeOpOverload] = { + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.gelu.default, + exir_ops.edge.aten.elu.default, + } + + def __init__(self, exported_program: ExportedProgram): + self.exported_program = exported_program + + def __contains__(self, node: Node) -> bool: + return ( + node.target in self.unary_table_ops or node.target in self.special_table_ops + ) + + def __getitem__(self, node: Node): + target = cast(EdgeOpOverload, node.target) + if target in self.unary_table_ops: + return self.unary_table_ops[target] + elif target in self.special_table_ops: + match target: + case exir_ops.edge.aten.pow.Tensor_Scalar: + # Exponent is a constant. Embed it into a lambda. + exp = cast(int, node.args[1]) + return lambda x: torch.pow(x, exp).flatten() + case exir_ops.edge.aten.gelu.default: + # If kwargs not present it is default "none" + approximate = cast( + str, + ( + node.kwargs["approximate"] + if "approximate" in node.kwargs + else "none" + ), + ) + return lambda x: torch.nn.functional.gelu( + x, approximate=approximate + ).flatten() + case exir_ops.edge.aten.elu.default: + input_alpha = cast(int, node.kwargs["alpha"]) + return lambda x: torch.nn.functional.elu( + x, alpha=input_alpha + ).flatten() + case _: + # Op must be handled if it's inside self.special_ops + raise AssertionError("Unhandled table operation") + else: + raise KeyError("Table op for {target} does not exist") + + @staticmethod + def included_ops() -> Iterator[EdgeOpOverload]: + return chain(TableOps.unary_table_ops, TableOps.special_table_ops) + + +class InsertTableOpsPass(ArmPass): + """ + For ops in self.table_ops they need to be serialized as a TOSA TABLE. This pass replaces these + edge ops with a tosa._table(input: Tensor, target_str: str) where target_str == str(node.target). + When lowering the _table node target_str will be used to find the corresponding torch operator + which will be used to produce the table values in operators/op_table.py. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram) -> None: + super().__init__() + self.exported_program = exported_program + self.table_ops = TableOps(exported_program) + + def register_buffer(self, buffer_name: str, buffer: torch.Tensor) -> None: + """ + Add buffer to self.exported_program.state_dict + """ + self.exported_program.state_dict[buffer_name] = buffer + + def generate_8bit_table_values( + self, + torch_op: Callable[[torch.Tensor], torch.Tensor], + in_quantargs: QuantArgs, + out_quantargs: QuantArgs, + ) -> tuple[torch.Tensor, int]: + """Compute LUT values for a INT8 TOSA.TABLE. Also returns 0 since no shifting is required after 8bit table. + The INT8 table is a simple 256 value 1-1 LUT. + """ + + def f(x: torch.Tensor) -> torch.Tensor: + x = in_quantargs.dequantize_value(x) + x = torch_op(x) + return out_quantargs.quantize_value(x) + + return ( + f( + torch.linspace( + start=in_quantargs.qmin, + end=in_quantargs.qmax, + steps=256, + dtype=torch.int8, + ) + ).to(dtype=torch.int8), + 0, + ) + + def generate_16_bit_table_values( + self, + torch_op: Callable[[torch.Tensor], torch.Tensor], + in_quantargs: QuantArgs, + out_quantargs: QuantArgs, + ) -> tuple[torch.Tensor, int]: + """Compute LUT values for a INT16 TOSA.TABLE with 32 bit output. + In practice the output is 23 bits that should be interpreted as 16 'whole' bits and 7 fractional bits, see + the specification: https://www.mlplatform.org/tosa/tosa_spec.html#_table. This means that the output + will interpreted as 2**7=128 times too large unless accounted for by rescaling down the table output. + + Quantization can be either int16 or int32 which means that the op output could be larger than the 23 bits from + the TOSA.TABLE output. In that case, we need to rescale up the output. + + To handle this we need to: + 1) Make sure that our table values fit within 16 bits. + 2) Insert a rescale after the table to handle the x128 from the fractional bits and match the quantization. + + The function returns rescale_lshift which says how much to rescale after the table. This value can negative. + """ + + def f(x: torch.Tensor) -> torch.Tensor: + x = x.clamp(in_quantargs.qmin, in_quantargs.qmax).to( + dtype=in_quantargs.dtype + ) + # Dont use the 7 LSBs. + x = in_quantargs.dequantize_value((x & ~0x7F)) + x = torch_op(x) + return out_quantargs.quantize_value(x) + + lut_values = f( + torch.linspace( + start=in_quantargs.qmin, + end=in_quantargs.qmax + 1, + steps=513, + # use torch.int32 to avoid overflow for end=in_quantargs.qmax + 1. + dtype=torch.int32, + ) + ) + # Calculate how much we need to shift table values to fit in 16 signed bits + # ceil(log2(max absolute table value)) + 1 bit for signedness - 16 + # Example: + # Max value in the table is 70 000. We want to fit it in 16 signed bits. + # 70 000=0b10001000101110000 (17 digits) has ceil(log2(70 000)) = ceil(16.095) = 17 bits. + # If we shift it 17-16=1 bit, we do get 16 bits (0b1000100010111000), + # but due to signedness this is a negative number! So we need to shift it one more bit. + # Note: for out_quantargs.dtype=torch.int16, rshift == 0 and rescale_lshift = -7. + rshift = int(torch.ceil(torch.log2(lut_values.abs().max()))) + 1 - 16 + # The 7 fractional bits are equivalent to a lshift of 7, so subtract 7 from the lshift we do. + rescale_lshift = rshift - 7 + lut_values = lut_values >> rshift + return lut_values.to(dtype=torch.int16), rescale_lshift + + def generate_table_values( + self, + torch_op: Callable[[torch.Tensor], torch.Tensor], + in_quantargs: QuantArgs, + out_quantargs: QuantArgs, + ) -> tuple[torch.Tensor, int]: + match out_quantargs.dtype: + case torch.int8: + return self.generate_8bit_table_values( + torch_op, in_quantargs, out_quantargs + ) + case torch.int16 | torch.int32: + return self.generate_16_bit_table_values( + torch_op, in_quantargs, out_quantargs + ) + case _: + raise ValueError( + f"Unsupported output dtype for table: {out_quantargs.dtype}" + ) + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function" or node not in self.table_ops: + continue + input_qparams = node.meta.get("input_qparams", {}) + output_qparams = node.meta.get("output_qparams", {}) + if len(input_qparams) == 0 or len(output_qparams) == 0: + # We only want to replace the node if it's quantized + continue + # Create table node + insert_pos = list(node.graph.nodes)[0] + with graph_module.graph.inserting_before(insert_pos): + # Expect exactly one quantization parameter for input and output + if len(input_qparams) != 1: + raise ValueError( + f"InsertTableOpsPass expected exactly one input quantization parameter, " + f"got {len(input_qparams)} for node {node.name}" + ) + if len(output_qparams) != 1: + raise ValueError( + f"InsertTableOpsPass expected exactly one output quantization parameter, " + f"got {len(output_qparams)} for node {node.name}" + ) + + # Generate table buffer and how much to lshift the table output. + buffer, lshift = self.generate_table_values( + torch_op=self.table_ops[node], + in_quantargs=input_qparams[0], + out_quantargs=output_qparams[0], + ) + # Register buffer in self.exported_program.state_dict + const_table_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=node.graph, + kind=InputKind.BUFFER, + name=node.name + "_table_constant", + data=buffer, + persistent_buffer=True, + ) + + # Create table node + with graph_module.graph.inserting_before(node): + table_op_node = create_node( + graph=graph_module.graph, + op_target=exir_ops.backend.tosa.TABLE.default, + args=(node.args[0], const_table_node), + ) + output_node = table_op_node + + if lshift != 0: + scale = 2.0**lshift + rescale_node = create_node( + graph=graph_module.graph, + op_target=exir_ops.backend.tosa.RESCALE.default, + args=(table_op_node, output_qparams[0].dtype, [scale], 0, 0), + ) + output_node = rescale_node + + node.replace_all_uses_with(output_node) + graph_module.graph.erase_node(node) + table_op_node.meta["input_qparams"] = input_qparams + table_op_node.meta["output_qparams"] = output_qparams + modified = True + + if modified: + # retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + + graph_module.recompile() + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_dtype_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_dtype_pass.py new file mode 100644 index 0000000..f0aaa0c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_dtype_pass.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node, get_node_arg +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +DTYPE_RANK = { + torch.bool: 0, + torch.uint8: 1, + torch.int8: 2, + torch.int16: 3, + torch.int32: 4, + torch.int64: 5, + torch.float16: 6, + torch.float32: 7, + torch.float64: 8, +} + + +def get_largest_dtype(dtype_1, dtype_2): + """Find the largest dtype.""" + return dtype_1 if DTYPE_RANK[dtype_1] > DTYPE_RANK[dtype_2] else dtype_2 + + +class MatchArgDtypePass(ArmPass): + """Pass to match data types of non-condition input tensors. + + Edge dialect allows different data types for non-condition tensors, while TOSA + does not. In cases where they differ a TOSA CAST operator is inserted. + + There is an edge case where one input is `boolean`, which cannot be directly cast + to, for example, float32. When this occurs two CAST operators are added to first + cast to int8 and then to the correct target data type. + + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = {exir_ops.edge.aten.sub.Tensor, exir_ops.edge.aten.where.self} + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + graph = graph_module.graph + + for node in list(graph.nodes): + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + input_ = get_node_arg(node.args, 0) + other_ = get_node_arg(node.args, 1) + + input_dtype = input_.meta["val"].dtype + other_dtype = other_.meta["val"].dtype + target_dtype = input_dtype + if input_dtype != other_dtype: + target_dtype = get_largest_dtype(input_dtype, other_dtype) + + for arg in node.args[1:]: + arg_dtype = arg.meta["val"].dtype + + if arg_dtype != target_dtype: + if arg_dtype == torch.bool: + # Bool is an edge case which cannot necessarily be directly + # converted to the target data type. + with graph.inserting_after(arg): + replace_node_int8 = create_node( + graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ) + replace_node_int8.args = (arg,) + replace_node_int8.kwargs = {"dtype": torch.int8} + + with graph.inserting_after(replace_node_int8): + replace_node_fp32 = create_node( + graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ) + replace_node_fp32.args = (replace_node_int8,) + replace_node_fp32.kwargs = {"dtype": target_dtype} + node.replace_input_with(arg, replace_node_fp32) + else: + with graph.inserting_after(arg): + replace_node = create_node( + graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ) + replace_node.args = (arg,) + replace_node.kwargs = {"dtype": target_dtype} + node.replace_input_with(arg, replace_node) + + modified_graph = True + + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_ranks_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_ranks_pass.py new file mode 100644 index 0000000..61dd4ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/match_arg_ranks_pass.py @@ -0,0 +1,114 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.exir import ExportedProgram + +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +class MatchArgRanksPass(ArmPass): + """ + For ops in 'targeted_ops', make sure that the inputs share the same rank. + New dimensions are inserted from the beginning of the inputs that have a + lower rank to match the input with the highest rank. + + Example: + input0 = shape(4, 3, 2) + input1 = shape(2) + input2 = shape(3, 1) + Becomes: + input0 = shape(4, 3, 2) + input1 = shape(1, 1, 2) + input2 = shape(1, 3, 1) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + targeted_ops = [ + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.div.Tensor, + exir_ops.edge.aten.div.Tensor_mode, + 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.ge.Tensor, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.pow.Tensor_Tensor, + exir_ops.edge.aten.remainder.Tensor, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.minimum.default, + ] + + def _match_op_rank(self, graph_module, node, arg, max_rank): + """ + In graph_module, insert a view between arg and node to make the + rank of arg match the other args to node. + """ + shape = get_first_fake_tensor(arg).shape + rank = len(shape) + new_shape = list([1] * (max_rank - rank) + list(shape)) + with graph_module.graph.inserting_before(node): + view = create_node( + graph_module.graph, + exir_ops.edge.aten.view_copy.default, + args=(arg, new_shape), + kwargs={}, + ) + node.replace_input_with(arg, view) + + def call(self, graph_module: GraphModule) -> PassResult: + for node in graph_module.graph.nodes: + node = cast(Node, node) + + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + # Calculate max rank of all inputs to node + max_rank = 0 + for arg in node.args: + if isinstance(arg, Node): + shape = get_first_fake_tensor(arg).shape + max_rank = max(max_rank, len(shape)) + + # Adjust output shape of args if needed. + for arg in node.args: + if not isinstance(arg, Node): + continue + shape = get_first_fake_tensor(arg).shape + rank = len(shape) + if rank == max_rank: + continue + + self._match_op_rank(graph_module, node, arg, max_rank) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/mm_to_bmm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/mm_to_bmm_pass.py new file mode 100644 index 0000000..34634b9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/mm_to_bmm_pass.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.convert_squeezes_to_view import ( + ConvertSqueezesToViewPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import Node + + +class ConvertMmToBmmPass(ArmPass): + """ + This pass converts a MM node to a BMM one and turns input and output tensors + from rank 2 to rank 3. The TOSA specification requires rank 3. The graph is + modified to do the following: + 1) Unsqueeze input tensors to rank 3. + 2) Convert MM node to BMM. + 3) Squeeze output tensor to rank 2. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ConvertSqueezesToViewPass, + } + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + graph = graph_module.graph + node_list = graph.find_nodes( + op="call_function", target=exir_ops.edge.aten.mm.default + ) + for node in node_list: + # Unsqueeze input tensors to rank 3 + for input_node in node.args: + if not isinstance(input_node, Node): + continue + + shape = get_first_fake_tensor(input_node).shape + rank = len(shape) + if rank != 2: + raise RuntimeError(f"Input tensor has rank {rank}, must be 2") + + with graph.inserting_before(node): + unsqueeze_before = create_node( + graph, + exir_ops.edge.aten.unsqueeze_copy.default, + from_node=node, + inherit_qparams=False, + ) + unsqueeze_before.args = ( + input_node, # Input is node's original input + 0, + ) + node.replace_input_with(input_node, unsqueeze_before) + + # Replace mm node with bmm + with graph.inserting_before(node): + bmm_node = create_node( + graph, + exir_ops.edge.aten.bmm.default, + from_node=node, + inherit_qparams=True, + ) + bmm_node.args = node.args + node.replace_all_uses_with(bmm_node) + graph.erase_node(node) + + # Unsqueeze output tensor to rank 3 + with graph.inserting_after(bmm_node): + squeeze_after = create_node( + graph, + exir_ops.edge.aten.squeeze_copy.dims, + from_node=node, + inherit_qparams=False, + ) + squeeze_after.args = ( + bmm_node, + [0], + ) + original_users = [ + user for user in bmm_node.users if user != squeeze_after + ] + for user in original_users: + user.replace_input_with(bmm_node, squeeze_after) + + modified_graph = True + + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/normalize_while_initial_args_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/normalize_while_initial_args_pass.py new file mode 100644 index 0000000..00ccf78 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/normalize_while_initial_args_pass.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +from typing import cast, Sequence, Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass +from torch.fx import GraphModule, Node +from torch.fx.passes.infra.pass_base import PassResult + + +class NormalizeWhileInitialArgsPass(ArmPass): + """ + Normalize ``torch.ops.higher_order.while_loop`` by moving additional_args to carried_args, + making the number of outputs equal to the number of inputs which is required by the TOSA specification. + Example: + def cond(val): + return val.sum() < 10 + + def body(val): + return (val * 2,) + while_loop(cond, body, (val,), additional_args= (buffer,)) + becomes: + def cond(val, buffer): + return val.sum() < 10 + + def body(val, buffer): + return (val * 2, buffer.clone()) + while_loop(cond, body, (val, buffer), ()) + + The clone is neccessary to avoid issues with aliasing. + """ + + def __init__(self, use_exir_clone: bool, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + if use_exir_clone: + self.clone_op = exir_ops.edge.aten.alias_copy.default + else: + self.clone_op = torch.ops.aten.clone.default + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _connect_to_output( + self, body_module: GraphModule, placeholders: Sequence[Node] + ) -> list[Node]: + if not placeholders: + return [] + + cloned_placeholders = [] + with body_module.graph.inserting_after(placeholders[-1]): + for placeholder in placeholders: + clone = body_module.graph.create_node( + "call_function", + self.clone_op, + (placeholder,), + ) + cloned_placeholders.append(clone) + clone.meta = placeholder.meta + output_node = body_module.graph.output_node() + output_values = output_node.args[0] + if not isinstance(output_values, tuple): + raise RuntimeError("Output of a while should be a tuple.") + + output_node.update_arg(0, output_values + tuple(cloned_placeholders)) + body_module.recompile() + return list(cloned_placeholders) + + def _normalize_node(self, graph_module: GraphModule, node: Node) -> bool: + additional_inputs = list(cast(Sequence[Node], node.args[3])) + + if not additional_inputs: + return False + + carried_inputs = list(cast(Sequence[Node], node.args[2])) + new_carried = tuple(carried_inputs + additional_inputs) + node.update_arg(2, new_carried) + node.update_arg(3, ()) + + body_module_name = str(cast(Node, node.args[1]).target) + body_module = cast(GraphModule, graph_module.get_submodule(body_module_name)) # type: ignore + placeholders = [n for n in body_module.graph.nodes if n.op == "placeholder"] + num_inputs = len(placeholders) + old_num_inputs = len(carried_inputs) + if num_inputs != len(new_carried): + raise RuntimeError( + f"Length of loop placeholders {placeholders} is not equal length of carried inputs {new_carried}" + ) + + missing_placeholders = placeholders[old_num_inputs:] + self._connect_to_output(body_module, missing_placeholders) + + return True + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target != torch.ops.higher_order.while_loop: + continue + modified |= self._normalize_node(graph_module, node) + + if modified: + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/promote_bool_operands_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/promote_bool_operands_pass.py new file mode 100644 index 0000000..8c45a80 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/promote_bool_operands_pass.py @@ -0,0 +1,88 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# The TOSA BITWISE_AND, BITWISE_OR, and BITWISE_XOR don't handle bool inputs. +# When a targeted op receives boolean tensors, we promote them to an integer type before +# invocation and cast the result back to the expected dtype afterwards. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class PromoteBoolOperandsPass(ArmPass): + """Promote boolean operands to the appropriate integer dtype for unsupported ops.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = { + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.mul.Tensor, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in self.targeted_ops: + return super().call_operator(op, args, kwargs, meta) + + original_dtypes = [arg.data.dtype for arg in args] + if torch.bool not in original_dtypes: + return super().call_operator(op, args, kwargs, meta) + + # select the first non-bool dtype, or None if all bool + promoted_dtype = next((dt for dt in original_dtypes if dt != torch.bool), None) + + # if we don't have a dtype specified by the op, promote to default choice for the op + if promoted_dtype is None: + if op == exir_ops.edge.aten.mul.Tensor: + # mul as int32 + promoted_dtype = torch.int32 + else: + # bitwise ops can be int8 + promoted_dtype = torch.int8 + + target_dtypes = [] + for dt in original_dtypes: + if dt == torch.bool: + target_dtypes.append(promoted_dtype) + else: + target_dtypes.append(dt) + + new_args = [] + for arg, original_dtype, target_dtype in zip( + args, original_dtypes, target_dtypes + ): + if original_dtype == target_dtype: + new_args.append(arg) + else: + new_args.append( + super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (arg,), + {"dtype": target_dtype}, + meta, + ) + ) + + output = super().call_operator( + op, + tuple(new_args), + kwargs, + meta, + ) + + if all(dtype == torch.bool for dtype in original_dtypes): + output = super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (output,), + {"dtype": torch.bool}, + meta, + ) + return output diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/quant_args.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/quant_args.py new file mode 100644 index 0000000..974d6df --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/quant_args.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, cast, NamedTuple + +import torch +from executorch.exir.dialects._ops import ops as exir_ops + +exir_ops = cast(Any, exir_ops) +from executorch.backends.arm.constants import PER_CHANNEL_QDQ_OPS, PER_TENSOR_QDQ_OPS +from torch import Tensor + + +class QuantArgs(NamedTuple): + scale: list[float] | float + zp: list[int] | int + qmin: int + qmax: int + dtype: torch.dtype + axis: int = 0 + per_channel: bool = False + + def quantize_value(self, x: torch.Tensor | float) -> Tensor: + """Quantizes the input tensor or value to a quantized tensor. If the input is + not a tensor, it is converted to a tensor first. If self.per_channel is True, + the quantization is done per channel, otherwise it is done per tensor. + """ + if not isinstance(x, torch.Tensor): + x = torch.Tensor([x]) + x = x.to(torch.float32) + if self.per_channel: + q_op = exir_ops.edge.quantized_decomposed.quantize_per_channel.default + args = ( + x, + torch.tensor(self.scale), + torch.tensor(self.zp), + self.axis, + self.qmin, + self.qmax, + self.dtype, + ) + else: + q_op = exir_ops.edge.quantized_decomposed.quantize_per_tensor.default + args = (x, self.scale, self.zp, self.qmin, self.qmax, self.dtype) # type: ignore[assignment] + return q_op(*args) + + def dequantize_value(self, qx: torch.Tensor) -> torch.Tensor: + """Dequantizes the input tensor or value to a dequantized tensor If the input + is not a tensor, it is converted to a tensor first. If self.per_channel is True, + the dequantization is done per channel, otherwise it is done per tensor. + """ + if self.per_channel: + dq_op = exir_ops.edge.quantized_decomposed.dequantize_per_channel.default + args = ( + qx, + torch.tensor(self.scale), + torch.tensor(self.zp), + self.axis, + self.qmin, + self.qmax, + self.dtype, + ) + else: + dq_op = exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default + args = (qx, self.scale, self.zp, self.qmin, self.qmax, self.dtype) # type: ignore[assignment] + return dq_op(*args) + + @classmethod + def from_operator(cls, op, args): + if op in PER_TENSOR_QDQ_OPS: + return cls( + scale=cast(float, args[1]), + zp=cast(int, args[2]), + qmin=cast(int, args[3]), + qmax=cast(int, args[4]), + dtype=cast(torch.dtype, args[5]), + axis=0, + per_channel=False, + ) + elif op in PER_CHANNEL_QDQ_OPS: + return cls( + scale=cast(list[float], args[1].tolist()), + zp=cast(list[int], args[2].tolist()), + axis=cast(int, args[3]), + qmin=cast(int, args[4]), + qmax=cast(int, args[5]), + dtype=cast(torch.dtype, args[6]), + per_channel=True, + ) + else: + # We're only handling per tensor and per channel quantization + raise NotImplementedError(f"Unsupported quantization operation: {op}") + + def get_scale_per_tensor(self) -> float: + if not isinstance(self.scale, float): + raise TypeError( + f"Expected scale {self.scale} to be a float but found scale of " + f"type {type(self.scale)}" + ) + return self.scale + + def get_zp_per_tensor(self) -> int: + if not isinstance(self.zp, int): + raise TypeError( + f"Expected zero point {self.zp} to be an int but found zp of " + f"type {type(self.zp)}" + ) + return self.zp + + def get_scale_per_channel(self) -> list[float]: + if not isinstance(self.scale, list): + raise TypeError( + f"Expected scale {self.scale} to be a list but found scale of " + f"type {type(self.scale)}" + ) + return self.scale + + def get_zp_per_channel(self) -> list[int]: + if not isinstance(self.zp, list): + raise TypeError( + f"Expected zero point {self.zp} to be a list but found zp of " + f"type {type(self.zp)}" + ) + return self.zp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_getitem_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_getitem_pass.py new file mode 100644 index 0000000..3ce157d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_getitem_pass.py @@ -0,0 +1,14 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.transforms import remove_getitem_op +from executorch.exir.pass_base import ExportPass + + +class RemoveGetItemPass(ArmPass, remove_getitem_op.RemoveGetItemPass): + _passes_required_after: Set[Type[ExportPass]] = set() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_graph_asserts_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_graph_asserts_pass.py new file mode 100644 index 0000000..a462c11 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_graph_asserts_pass.py @@ -0,0 +1,18 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass + +from executorch.backends.arm._passes.convert_int64_const_ops_to_int32 import ( + ConvertInt64ConstOpsToInt32Pass, +) +from executorch.exir.pass_base import ExportPass +from executorch.exir.passes import remove_graph_asserts_pass + + +class RemoveGraphAssertsPass(remove_graph_asserts_pass.RemoveGraphAssertsPass, ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {ConvertInt64ConstOpsToInt32Pass} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_noop_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_noop_pass.py new file mode 100644 index 0000000..8ac8088 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/remove_noop_pass.py @@ -0,0 +1,40 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +logger = logging.getLogger(__name__) + + +class RemoveNoopPass(ArmPass): + """Remove no-ops from graph_module""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + exir_ops.edge.dim_order_ops._clone_dim_order.default, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + exir_ops.edge.aten.copy.default, + ): + return super().call_operator(op, args, kwargs, meta) + + input_dtype = args[0].data.dtype + output_dtype = kwargs.get("dtype", input_dtype) + + if input_dtype != output_dtype: + return super().call_operator(op, args, kwargs, meta) + + if op == exir_ops.edge.aten.copy.default: + return args[1] + return args[0] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_inf_and_limit_values_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_inf_and_limit_values_pass.py new file mode 100644 index 0000000..0f1fad5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_inf_and_limit_values_pass.py @@ -0,0 +1,73 @@ +# Copyright (c) Qualcomm Innovation Center, Inc. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This pass is based on backends/qualcomm/_passes/replace_inf_values.py +# with some modification to replaced inf values. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.pass_base import ExportPass, NodeMetadata, PassResult + + +class ReplaceInfAndLimitValuesPass(ArmPass): + """ + Rewrites +inf/-inf and floating-point limit values (e.g., torch.finfo(...).min/max) + to quantization-friendly values (±255 by default), improving quantizer stability + (notably for attention mask paths). + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _allowed_to_transform_named_buffer(self, buf_name, graph_module) -> bool: + attr_nodes = [ + node + for node in graph_module.graph.nodes + if node.op == "get_attr" and node.target == buf_name + ] + + can_transform_buffer = True + for attr_node in attr_nodes: + for user in list(attr_node.users): + if user.op != "call_function": + continue + if not self.allowed_to_transform(NodeMetadata(user.meta)): + can_transform_buffer = False + break + if not can_transform_buffer: + break + + return can_transform_buffer + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for buf_name, tensor in graph_module.named_buffers(): + if not tensor.is_floating_point(): + continue + if not self._allowed_to_transform_named_buffer(buf_name, graph_module): + continue + + modified = True + # 255 here is mainly for attention_mask in Llama for reasonable quant scale + tensor[tensor == float("inf")] = 255 + tensor[tensor == float("-inf")] = -255 + setattr(graph_module, buf_name, tensor) + + for node in graph_module.graph.nodes: + arg_list = list(node.args) + for index, arg in enumerate(arg_list): + if arg == float("-inf") or arg == torch.finfo(torch.float32).min: + modified = True + arg_list[index] = -255.0 + elif arg == float("inf") or arg == torch.finfo(torch.float32).max: + modified = True + arg_list[index] = +255.0 + node.args = tuple(arg_list) + + if modified: + graph_module.recompile() + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_scalar_with_tensor_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_scalar_with_tensor_pass.py new file mode 100644 index 0000000..df48434 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/replace_scalar_with_tensor_pass.py @@ -0,0 +1,121 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Set, Type, Union + +import torch +from executorch.backends.arm._passes.insert_table_ops import TableOps + +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.backends.transforms.replace_scalar_with_tensor import ( + ReplaceScalarWithTensorArgPass, +) +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass + +from .arm_pass import ArmPass + + +# Operators that are included for both TOSA profiles +_common_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = { + exir_ops.edge.aten.add.Scalar: exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Scalar: exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.mul.Scalar: exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.div.Scalar: exir_ops.edge.aten.div.Tensor, + 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.ge.Scalar: exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.lt.Scalar: exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.le.Scalar: exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.ne.Scalar: exir_ops.edge.aten.ne.Tensor, + exir_ops.edge.aten.bitwise_and.Scalar: exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Scalar: exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Scalar: exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.remainder.Scalar: exir_ops.edge.aten.remainder.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, + torch.ops.aten.div.Scalar: torch.ops.aten.div.Tensor, + 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.ge.Scalar: torch.ops.aten.ge.Tensor, + torch.ops.aten.lt.Scalar: torch.ops.aten.lt.Tensor, + torch.ops.aten.le.Scalar: torch.ops.aten.le.Tensor, + torch.ops.aten.ne.Scalar: torch.ops.aten.ne.Tensor, + torch.ops.aten.bitwise_and.Scalar: torch.ops.aten.bitwise_and.Tensor, + torch.ops.aten.bitwise_or.Scalar: torch.ops.aten.bitwise_or.Tensor, + torch.ops.aten.bitwise_xor.Scalar: torch.ops.aten.bitwise_xor.Tensor, + torch.ops.aten.remainder.Scalar: torch.ops.aten.remainder.Tensor, +} + +_fp_profile_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = _common_ops | { + exir_ops.edge.aten.pow.Tensor_Scalar: exir_ops.edge.aten.pow.Tensor_Tensor, +} + +_int_profile_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = _common_ops + +_all_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = ( + _fp_profile_ops | _int_profile_ops +) + + +class ReplaceScalarWithTensorByProfilePass(ArmPass, ReplaceScalarWithTensorArgPass): + """Profile-aware scalar-to-tensor replacement pass for binary ops.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, tfa_pass=False, *args, **kwargs): + # NOTE diamond heritance for this class, thus MRO is important. + + # Initialize base (ReplaceScalarWithTensorArgPass) with the full + # superset which will make the superclass handle ops in _all_ops. + # Actual selection is done per-call in call_operator. + super().__init__(tfa_pass, _all_ops, *args, **kwargs) + + def call_operator(self, op, args, kwargs, meta): + tosa_spec = get_context_spec() + + included_ops = {} + if tosa_spec.support_integer(): + included_ops |= _int_profile_ops + if tosa_spec.support_float(): + included_ops |= _fp_profile_ops + + if included_ops == {}: + raise ValueError("Profile must support at least INT or FP") + + if op in TableOps.included_ops(): + # Do not handle quantized table ops; forward unchanged. + input_qparams = meta.data.get("input_qparams", {}) + output_qparams = meta.data.get("input_qparams", {}) + if len(input_qparams) > 0 and len(output_qparams) > 0: + # Do not handle; forward unchanged. + return ExportPass.call_operator(self, op, args, kwargs, meta) + + if op in included_ops: + # Include this op based on the current profile. + return super().call_operator(op, args, kwargs, meta) + else: + # Do not handle; forward unchanged. + return ExportPass.call_operator(self, op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py new file mode 100644 index 0000000..734583c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py @@ -0,0 +1,43 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class RewriteBoolBitwiseNotToLogicalNotPass(ArmPass): + """ + Rewrites ``aten.bitwise_not`` on boolean tensors to ``aten.logical_not``. + + TOSA ``bitwise_not`` does not support boolean inputs. On boolean tensors, + ``bitwise_not`` is equivalent to ``logical_not``, so this rewrite preserves + semantics while enabling lowering. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + _TARGET_OPS = { + exir_ops.edge.aten.bitwise_not.default, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in self._TARGET_OPS: + return super().call_operator(op, args, kwargs, meta) + + if meta["val"].dtype == torch.bool: + x = args[0] + return super().call_operator( + exir_ops.edge.aten.logical_not.default, + (x,), + {}, + meta, + ) + + return super().call_operator(op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py new file mode 100644 index 0000000..4f8eeb8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, + set_node_arg, +) +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class RewriteBoolToFp32CastViaInt8Pass(ArmPass): + """ + Legalizes unsupported bool->fp32 to_dim_order_copy casts for the Arm TOSA + backend when both integer and float TOSA profiles are enabled. + + For the combined INT+FP profile, this pass rewrites a single bool->fp32 cast + into a bool->int8 cast followed by an int8->fp32 cast, so that each cast + is individually supported by the TOSA INT and FP profiles. For other + profiles (INT-only or FP-only) the pass is a no-op. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = {exir_ops.edge.dim_order_ops._to_dim_order_copy.default} + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + + tosa_spec = get_context_spec() + if not (tosa_spec.support_integer() and tosa_spec.support_float()): + return PassResult(graph_module, modified) + + graph = graph_module.graph + for node in graph.nodes: + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + input_node = node.all_input_nodes[0] + input_dtype = get_first_fake_tensor(input_node).dtype + if input_dtype != torch.bool: + continue + + output_dtype = get_first_fake_tensor(node).dtype + if output_dtype != torch.float32: + continue + + set_node_arg(node, "dtype", torch.int8) + + users = list(node.users) + with graph.inserting_after(node): + cast_after = create_node( + graph, + node.target, + args=(node,), + kwargs={ + "dtype": torch.float32, + }, + ) + for user in users: + user.replace_input_with(node, cast_after) + modified = True + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_conv_pass.py new file mode 100644 index 0000000..b20aa22 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_conv_pass.py @@ -0,0 +1,336 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import itertools +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + expand_around_channel, + get_first_fake_tensor, + get_param_tensor, + is_buffer, + is_param, +) +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.constants import HWCM_ORDER, NHWC_INVERSE_ORDER +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.transforms.utils import create_constant_placeholder +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind + + +class RewriteConvPass(ArmPass): + """Rewrites aten.convolution to tosa.CONV2D or tosa.DEPTHWISE_CONV2D.""" + + def __init__(self, exported_program: torch.export.ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + _passes_required_after: Set[Type[ExportPass]] = set() + + # torch.nn.Conv2d does not require the result of + # `(input + 2 * pad - dilation * (weight - 1) - 1) / stride` + # to be an integer, but tosa currently strictly require this property. + # This function adjusts the pad value to meet the requirement. + def _adjust_pad_if_needed( + self, input_len: int, input_weight: int, stride: int, pad: int, dilation: int + ) -> int: + """Adjust padding to satisfy TOSA's integer output-size requirement. + + Torch ``Conv2d`` does not require the result of + ``(input + 2 * pad - dilation * (weight - 1) - 1) / stride`` to be an + integer, but TOSA does. This helper reduces the provided padding so + that the expression becomes divisible by ``stride``. + + Args: + input_size (int): Spatial input size along the dimension (H or W). + input_weight (int): Kernel size along the same dimension. + stride (int): Stride along the same dimension. + pad (int): Padding value to adjust (bottom or right after duplication). + dilation (int): Dilation along the same dimension. + + Returns: + int: Adjusted padding value that yields an integer output size. + + Raises: + RuntimeError: If the required adjustment exceeds the provided + padding, which should be handled by the ``SizeAdjustInputPass`` + pass instead. + + """ + mod_remainder = ( + input_len + 2 * pad - dilation * (input_weight - 1) - 1 + ) % stride + + # No need to adjust + if mod_remainder == 0: + return pad + + if mod_remainder > pad: + raise RuntimeError( + "This case should be handled by the SizeAdjustInputPass, is it enabled?" + ) + return pad - mod_remainder + + def _is_depthwise_conv2d(self, node: torch.fx.Node) -> bool: + if ( + node.op != "call_function" + or node.target != exir_ops.edge.aten.convolution.default + ): + return False + input_tensor = get_first_fake_tensor(node.all_input_nodes[0]) + if len(input_tensor.shape) != 4: + return False + groups = node.args[-1] + in_channels = input_tensor.shape[1] + out_channels = get_first_fake_tensor(node).shape[1] + return (in_channels == groups) and (out_channels % in_channels) == 0 + + def _is_conv3d(self, rank, groups) -> bool: + if rank == 5: + # A Conv3D is considered depthwise if Group == InChannels and + # Group * N == OutChannels, where N is a possitive integer. + # Currently we do not support depthwise or grouped conv3d. + # @TODO Add grouped/depthwise conv3d support or reject in partitioner. + if groups != 1: + raise RuntimeError( + "CONV3D with groups != 1 is not supported in the Arm backend." + ) + return True + return False + + def _reshape_weights(self, weight_node: torch.fx.Node, in_channels: int) -> None: + """Reshape the weights for depthwise convolution such that when serialized to TOSA, + the weights are in the format [H, W, in_channels, m_length] where + m_length is the number of output channels per input channel. + """ + weight_tensor = get_param_tensor(self.exported_program, weight_node) # type: ignore[arg-type] + if weight_tensor is None: + raise RuntimeError( + f"Weight node {weight_node.name} is not a parameter or buffer" + ) + + reshaped_weight_tensor = ( + weight_tensor.permute(HWCM_ORDER) + .reshape( + weight_tensor.shape[2], + weight_tensor.shape[3], + in_channels, + weight_tensor.shape[0] // in_channels, + ) + .permute(NHWC_INVERSE_ORDER) + ) + + if is_buffer(self.exported_program, weight_node): + param_name = self.exported_program.graph_signature.inputs_to_buffers[ + weight_node.name + ] + reshaped_weight_tensor = torch.nn.Buffer(reshaped_weight_tensor) + elif is_param(self.exported_program, weight_node): + param_name = self.exported_program.graph_signature.inputs_to_parameters[ + weight_node.name + ] + reshaped_weight_tensor = torch.nn.Parameter( + reshaped_weight_tensor, requires_grad=False + ) + else: + raise RuntimeError( + f"Weight node {weight_node.name} is neither a parameter nor a buffer" + ) + + self.exported_program.state_dict[param_name] = reshaped_weight_tensor + weight_node.meta["val"] = weight_node.meta["val"].reshape( + weight_tensor.shape[2], + weight_tensor.shape[0] // in_channels, + weight_tensor.shape[3], + in_channels, + ) + + def _add_bias( + self, + graph_module: torch.fx.GraphModule, + node: torch.fx.Node, + weight_node: torch.fx.Node, + ) -> torch.fx.Node: + output_channels = get_first_fake_tensor(node).shape[1] + # add a node containging zeros if quantized, use int32, otherwise use float32 + if "output_qparams" in node.meta and len(node.meta["output_qparams"]) > 0: + bias_data = torch.zeros(size=(output_channels,), dtype=torch.int32) + else: + bias_data = torch.zeros(size=(output_channels,), dtype=torch.float32) + + with graph_module.graph.inserting_after(weight_node): + bias_node = create_constant_placeholder( + self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + data=bias_data, + persistent_buffer=True, + name=f"{node.name}_bias", + ) + if node.all_input_nodes[0].meta["val"].dtype == torch.int16: + bias_node.meta[TosaSpecialDtype.meta_key()] = TosaSpecialDtype.INT48 + node.update_arg(2, bias_node) + return bias_node + + def insert_output_rescale(self, graph_module, node): + input_qparams = get_input_qparams(node) + output_qparams = get_output_qparams(node)[0] + weight_qparams = input_qparams[1] + input_qparams = input_qparams[0] + is_per_channel = weight_qparams.per_channel + if is_per_channel: + weight_scale = weight_qparams.get_scale_per_channel() + else: + weight_scale = [weight_qparams.get_scale_per_tensor()] + input_scale = input_qparams.get_scale_per_tensor() + post_conv2d_scale = [ + (inp * w) / out + for inp, w, out in zip( + itertools.cycle([input_scale]), + weight_scale, + itertools.cycle([output_qparams.get_scale_per_tensor()]), + ) + ] + with graph_module.graph.inserting_after(node): + rescale_node = create_node( + graph=graph_module.graph, + op_target=exir_ops.backend.tosa.RESCALE.default, + args=( + node, + output_qparams.dtype, + post_conv2d_scale, + 0, + output_qparams.get_zp_per_tensor(), + ), + from_node=node, + ) + return rescale_node + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901 + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target != exir_ops.edge.aten.convolution.default + ): + continue + + modified = True + + ( + x, + weight, + bias, + stride, + pad, + dilation, + _, + _, + group, + ) = node.args + + input_fake_tensor = get_first_fake_tensor(x) + weight_fake_tensor = get_first_fake_tensor(weight) + input_shape = input_fake_tensor.shape + weight_shape = weight_fake_tensor.shape + spatial_rank = len(input_shape) - 2 + stride_list = expand_around_channel(stride, spatial_rank) + dilation_list = expand_around_channel(dilation, spatial_rank) + pad_list = expand_around_channel(pad, spatial_rank) + + pad_attr: list[int] = [] + for value in pad_list: + pad_attr.extend([value, value]) # duplicate pad before/after per axis + + for axis_index in range(spatial_rank): + pad_index = axis_index * 2 + 1 # adjust trailing pad entry + pad_attr[pad_index] = self._adjust_pad_if_needed( + input_shape[axis_index + 2], + weight_shape[axis_index + 2], + stride_list[axis_index], + pad_attr[pad_index], + dilation_list[axis_index], + ) + + stride = tuple(stride_list) + dilation = tuple(dilation_list) + pad = pad_attr + + has_bias = bias is not None + if not has_bias: + bias = self._add_bias(graph_module, node, weight) + + if self._is_conv3d(len(input_shape), group): + target_op = exir_ops.backend.tosa.CONV3D.default + elif self._is_depthwise_conv2d(node): + target_op = exir_ops.backend.tosa.DEPTHWISE_CONV2D.default + # If there are any TOSA.DEPTHWISE_CONV2D nodes using the weights, we've already reshaped them. + if all(user.target != target_op for user in weight.users): + self._reshape_weights(weight, input_fake_tensor.shape[1]) + weight_fake_tensor = get_first_fake_tensor(weight) + else: + target_op = exir_ops.backend.tosa.CONV2D.default + + conv_args = ( + x, + weight, + bias, + stride, + pad, + dilation, + ) + + with graph_module.graph.inserting_after(node): + tosa_op = create_node( + graph=graph_module.graph, + op_target=target_op, + args=conv_args, + from_node=node, + inherit_qparams=True, + ) + bias_fake_tensor = get_first_fake_tensor(bias) if bias else None + tosa_node_fake_tensor = target_op( + input_fake_tensor, + weight_fake_tensor, + bias_fake_tensor, + *conv_args[3:], + ) + + if ( + tosa_node_fake_tensor.dtype == torch.int32 + and input_fake_tensor.dtype == torch.int8 + ): + output_rescale = self.insert_output_rescale(graph_module, tosa_op) + node.replace_all_uses_with(output_rescale) + elif ( + tosa_node_fake_tensor.dtype == torch.int32 + and input_fake_tensor.dtype == torch.int16 + ): + has_bias = len(node.meta["input_qparams"]) > 2 + if not has_bias: + output_rescale = self.insert_output_rescale(graph_module, tosa_op) + node.replace_all_uses_with(output_rescale) + else: + node.replace_all_uses_with(tosa_op) + tosa_op.meta[TosaSpecialDtype.meta_key()] = TosaSpecialDtype.INT48 + else: + node.replace_all_uses_with(tosa_op) + + graph_module.graph.erase_node(node) + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_matmul.py new file mode 100644 index 0000000..298cfd1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_matmul.py @@ -0,0 +1,98 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class RewriteMatmulPass(ArmPass): + """Rewrites aten.bmm to tosa.MATMUL and inserts a tosa.RESCALE op if needed.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _insert_output_rescale(self, graph_module, node, tosa_matmul_node, dtype): + input_qparams = get_input_qparams(node) + output_qparams = get_output_qparams(node)[0] + scale = ( + input_qparams[0].get_scale_per_tensor() + * input_qparams[1].get_scale_per_tensor() + ) / output_qparams.get_scale_per_tensor() + + with graph_module.graph.inserting_after(tosa_matmul_node): + # If the input is int8, we need to cast the output to int32 + rescale_node = create_node( + graph_module.graph, + op_target=exir_ops.backend.tosa.RESCALE.default, + from_node=tosa_matmul_node, + ) + tosa_matmul_node.replace_all_uses_with(rescale_node) + rescale_node.args = ( + tosa_matmul_node, + dtype, + [scale], + 0, + output_qparams.get_zp_per_tensor(), + ) + + def call(self, graph_module): + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target != exir_ops.edge.aten.bmm.default + ): + continue + modified = True + + x1, x2 = node.args + tosa_matmul_target = exir_ops.backend.tosa.MATMUL.default + with graph_module.graph.inserting_before(node): + tosa_matmul_node = create_node( + graph_module.graph, + op_target=tosa_matmul_target, + args=(x1, x2), + kwargs={}, + from_node=node, + inherit_qparams=True, + ) + node.replace_all_uses_with(tosa_matmul_node) + graph_module.graph.erase_node(node) + + x1_fake_tensor = get_first_fake_tensor(x1) + x2_fake_tensor = get_first_fake_tensor(x2) + output_fake_tensor = tosa_matmul_target(x1_fake_tensor, x2_fake_tensor) + node_output_fake_tensor = get_first_fake_tensor(node) + if ( + output_fake_tensor.dtype == torch.int32 + and node_output_fake_tensor.dtype in (torch.int8, torch.int16) + ): + self._insert_output_rescale( + graph_module, + node, + tosa_matmul_node, + dtype=node_output_fake_tensor.dtype, + ) + if x1_fake_tensor.dtype == torch.int16: + tosa_matmul_node.meta[TosaSpecialDtype.meta_key()] = ( + TosaSpecialDtype.INT48 + ) + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_upsample.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_upsample.py new file mode 100644 index 0000000..cff241d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/rewrite_upsample.py @@ -0,0 +1,93 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.arm.tosa.utils import get_resize_parameters +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class RewriteUpsamplePass(ArmPass): + """Rewrite upsample2d nodes to TOSA.RESIZE nodes.""" + + targeted_ops = ( + exir_ops.edge.aten.upsample_nearest2d.vec, + exir_ops.edge.aten.upsample_bilinear2d.vec, + ) + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + modified = True + + if node.target == exir_ops.edge.aten.upsample_bilinear2d.vec: + x, output_size, align_corners, scale_factors = node.args + resize_mode = "bilinear" + else: + x, output_size, scale_factors = node.args + align_corners = False + resize_mode = "nearest" + + with graph_module.graph.inserting_before(node): + tosa_resize_node = create_node( + graph_module.graph, + op_target=exir_ops.backend.tosa.RESIZE.default, + args=(x, output_size, align_corners, scale_factors), + kwargs={"resize_mode": resize_mode}, + from_node=node, + inherit_qparams=True, + ) + node.replace_all_uses_with(tosa_resize_node) + graph_module.graph.erase_node(node) + input_dtype = get_first_fake_tensor(x).dtype + if ( + input_dtype == torch.int8 or input_dtype == torch.int16 + ) and resize_mode == "bilinear": + input_size = get_first_fake_tensor(x).shape + input_size_xy = input_size[2:] + output_size = get_first_fake_tensor(node).shape + output_size_xy = output_size[2:] + scale_n_yx, _, _, _ = get_resize_parameters( + input_size_xy=input_size_xy, + output_size_xy=output_size_xy, + resize_mode=1, + align_corners=align_corners, + ) + output_dtype = get_first_fake_tensor(node).dtype + output_scale = float(1 / (scale_n_yx[0] * scale_n_yx[1])) + with graph_module.graph.inserting_after(tosa_resize_node): + rescale_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.RESCALE.default, + ) + tosa_resize_node.replace_all_uses_with(rescale_node) + if input_dtype == torch.int16: + tosa_resize_node.meta[TosaSpecialDtype.meta_key()] = ( + TosaSpecialDtype.INT48 + ) + + rescale_node.args = ( + tosa_resize_node, + output_dtype, + [output_scale], + 0, # zero point + 0, # zero point + ) + + if modified: + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/scalars_to_attribute_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/scalars_to_attribute_pass.py new file mode 100644 index 0000000..87f5825 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/scalars_to_attribute_pass.py @@ -0,0 +1,97 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Set, Type, Union + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node +from torchao.quantization.pt2e.utils import get_new_attr_name_with_prefix + + +class ScalarsToAttributePass(ArmPass): + """ + For ops in 'targeted_ops', convert inputs that are scalar values + to attribute Nodes that output the same value. + """ + + _passes_required_after: Set[Type[ExportPass]] = {MatchArgRanksPass} + + targeted_ops = [ + torch.ops.aten.add.Tensor, + torch.ops.aten.add_.Tensor, + torch.ops.aten.sub.Tensor, + torch.ops.aten.sub_.Tensor, + torch.ops.aten.rsub.Scalar, + torch.ops.aten.mul.Tensor, + torch.ops.aten.mul_.Tensor, + torch.ops.aten.div.Tensor, + torch.ops.aten.div_.Tensor, + ] + + def call(self, graph_module: GraphModule) -> PassResult: + for n in graph_module.graph.nodes: + n = cast(Node, n) + if n.op != "call_function" or n.target not in self.targeted_ops: + continue + + biggest_rank = 1 + for arg in n.args: + if isinstance(arg, Node): + shape = get_first_fake_tensor(arg).shape + biggest_rank = max(biggest_rank, len(shape)) + + output_fake_tensor = get_first_fake_tensor(n) + new_args: list[Node | int] = [] + for arg in n.args: + if isinstance(arg, Node): + new_args.append(arg) + continue + if isinstance(arg, int) and not torch.is_floating_point( + output_fake_tensor + ): + new_args.append(arg) + continue + + prefix = "_tensor_constant_" + get_new_attr_name = get_new_attr_name_with_prefix(prefix) + tensor_constant_name = get_new_attr_name(graph_module) + float_tensor = torch.tensor( + float(cast(Union[int, float], arg)), + device=output_fake_tensor.device, + ).reshape((1,) * biggest_rank) + graph_module.register_buffer(tensor_constant_name, float_tensor) + fake_mode = n.meta["val"].fake_mode + + with graph_module.graph.inserting_before(n): + get_attr_node = graph_module.graph.create_node( + "get_attr", tensor_constant_name, (), {} + ) + get_attr_node.meta["val"] = fake_mode.from_tensor( + float_tensor, static_shapes=True + ) + new_args.append(get_attr_node) + n.args = tuple(new_args) + + # Replace rsub.Scalar with sub.Tensor as retracing will fail otherwise + if n.target == torch.ops.aten.rsub.Scalar: + with graph_module.graph.inserting_after(n): + reversed_args = (n.args[1], n.args[0]) + sub = graph_module.graph.create_node( + "call_function", torch.ops.aten.sub.Tensor, reversed_args, {} + ) + n.replace_all_uses_with(sub) + sub.meta["val"] = n.meta["val"] + graph_module.graph.erase_node(n) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/size_adjust_input_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/size_adjust_input_pass.py new file mode 100644 index 0000000..642a249 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/size_adjust_input_pass.py @@ -0,0 +1,227 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Sequence, Set, Type, TypeAlias + +import torch.fx +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + expand_around_channel, +) +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +Slices: TypeAlias = list[tuple[int, int, int]] + +conv2d_op = exir_ops.edge.aten.convolution.default +max_pooling_op = exir_ops.edge.aten.max_pool2d.default +avg_pooling_op = exir_ops.edge.aten.avg_pool2d.default +slice_op = exir_ops.edge.aten.slice_copy.Tensor + +valid_operators = [conv2d_op, max_pooling_op, avg_pooling_op] + + +def conv_remainder(input_length, pad, dilation, weight, stride) -> int: + """ + Returns the remainder of input_length; given the padding, dilation, stride, + and kernel size. + """ + return (input_length + 2 * pad - dilation * (weight - 1) - 1) % stride + + +def pooling_remainder(input_size, pad, kernel_size, stride) -> int: + """ + Returns the remainder of input_length; given the padding, stride, and + kernel size. + """ + return (input_size + 2 * pad - kernel_size) % stride + + +def get_slices_convolution(conv_node: torch.fx.Node) -> Slices: + slices = [] + + input_node, weight, _, stride_hw, pad_hw, dilation_hw, _, _, _ = conv_node.args + weight_shape = cast(torch.fx.Node, weight).meta["val"].shape + input_shape = cast(torch.fx.Node, input_node).meta["val"].shape + spatial_rank = len(input_shape) - 2 + + strides = expand_around_channel(cast(Sequence[int] | int, stride_hw), spatial_rank) + pads = expand_around_channel(cast(Sequence[int] | int, pad_hw), spatial_rank) + dilations = expand_around_channel( + cast(Sequence[int] | int, dilation_hw), spatial_rank + ) + + for axis_index, (stride, pad, dilation) in enumerate(zip(strides, pads, dilations)): + dim = axis_index + 2 + remainder = conv_remainder( + input_shape[dim], pad, dilation, weight_shape[dim], stride + ) + if remainder > pad: + adjustment = remainder - pad + args = (dim, 0, input_shape[dim] - adjustment) + slices.append(args) + + return slices + + +def get_slices_pooling(pooling_node: torch.fx.Node) -> Slices: + slices = [] + + input_node = pooling_node.args[0] + kernel_size = pooling_node.args[1] + stride = pooling_node.args[2] + padding = pooling_node.args[3] if len(pooling_node.args) >= 4 else 0 + + input_shape = cast(torch.fx.Node, input_node).meta["val"].shape + + kernel_sizes = expand_around_channel(cast(Sequence[int] | int, kernel_size), 2) + strides = expand_around_channel(cast(Sequence[int] | int, stride), 2) + pads = expand_around_channel(cast(Sequence[int] | int, padding), 2) + + for dim, (kernel_length, stride_length, pad_size) in enumerate( + zip(kernel_sizes, strides, pads), start=2 + ): + remainder = pooling_remainder( + input_shape[dim], pad_size, kernel_length, stride_length + ) + if remainder > pad_size: + adjustment = remainder - pad_size + args = (dim, 0, input_shape[dim] - adjustment) + slices.append(args) + + return slices + + +def get_slices(node: torch.fx.Node) -> Slices: + """ + Returns the remainder of input_length; given graph Node. + """ + if node.target == conv2d_op: + return get_slices_convolution(node) + elif node.target == max_pooling_op or node.target == avg_pooling_op: + return get_slices_pooling(node) + else: + raise ValueError(f"Unsupported node target, was expecting {valid_operators}") + + +def is_valid_operator(node: torch.fx.Node) -> bool: + if node.target == conv2d_op: + return True + elif node.target == max_pooling_op: + dilation = node.args[4] if len(node.args) >= 5 else 1 + ceil_mode = node.args[5] if len(node.args) >= 6 else False + + # Dilation should be handled first by DecomposeMaxPool2dPass + if isinstance(dilation, int): + if dilation > 1: + raise ValueError( + "Expected max_pool2d with dilation = 1, has DecomposeMaxPool2dPass been run?" + ) + else: + dilation = cast(list, dilation) + if dilation[0] > 1 or dilation[1] > 1: + raise ValueError( + "Expected max_pool2d with dilation = [1, 1], has DecomposeMaxPool2dPass been run?" + ) + + # If using ceil mode for rounding, the input does not need adjusting + return not ceil_mode + elif node.target == avg_pooling_op: + ceil_mode = node.args[4] if len(node.args) >= 5 else False + count_include_pad = node.args[5] if len(node.args) >= 6 else True + divisor_override = node.args[6] if len(node.args) >= 7 else None + + return not ceil_mode and not count_include_pad and divisor_override is None + + return False + + +class SizeAdjustInputPass(ArmPass): + """ + Adjusts the input size to Conv2D and Pooling operators. PyTorch allows + the input and kernel shape to not "match", in which case the remaining + rows/columns are truncated. However, matching the size is a requirement + in the TOSA specification. In case the input and kernel shape do not + match, the following is performed to meet the specification: + + 1) The padding is truncated (done in the node visitor) + 2) (if neccessary) The input is truncated (done in this pass)." + + A simple example would be a 2x2 kernel (no padding, stride=2) and a 5x5 + input: + + ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ + │ X │ X │ │ │ │ │ │ │ X │ X │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ X │ X │ │ │ │ │ │ │ X │ X │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ -> │ │ │ │ │ │ -> │ X │ X │ │ │ │ -> + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ │ │ │ │ │ │ X │ X │ │ │ │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ + First pass second pass third pass + + ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ + │ │ │ │ │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ X │ X │ │ -> │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ X │ X │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ - │ - │ - │ - │ - │ + └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ + Fourth pass Unvisited cells + + Cells that are never visited are marked with `-` and are never considered + when the kernel traverses over the input, hence they can be removed. + + To match the shape of the kernel (and all parameters) with the input, a + slice op is inserted to remove the remaining edges (rows and columns) of the + input. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + RewriteConvPass, + } + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + graph = graph_module.graph + modified_graph = False + for node in graph.nodes: + if node.op != "call_function": + continue + if not is_valid_operator(node): + continue + + target_node = cast(torch.fx.Node, node) + slice_args = get_slices(target_node) + + if len(slice_args) == 0: + continue + + parent_node = node.args[0] + with graph_module.graph.inserting_before(node): + last_node = cast(torch.fx.Node, parent_node) + for args in slice_args: + slice_node = create_node( + graph, slice_op, (last_node,) + args, from_node=node + ) + last_node = slice_node + node.replace_input_with(cast(torch.fx.Node, parent_node), last_node) + modified_graph = True + + if modified_graph: + graph_module = super().call(graph_module).graph_module + graph.eliminate_dead_code() + graph_module.recompile() + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/to_tosa_memory_format_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/to_tosa_memory_format_pass.py new file mode 100644 index 0000000..059e271 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/to_tosa_memory_format_pass.py @@ -0,0 +1,454 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.annotate_decomposed_matmul import ( + AnnotateDecomposedMatmulPass, +) +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, + is_param_node, +) +from executorch.backends.arm.constants import NCHW_ORDER, NNCHW_ORDER, NNNCHW_ORDER +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +logger = logging.getLogger(__name__) + + +def _is_input(node: torch.fx.Node, exported_program: ExportedProgram) -> bool: + """ + Returns True if the node is an input node, i.e. a placeholder or a parameter. + """ + return node.op == "placeholder" and not is_param_node(exported_program, node) + + +class ToTosaMemoryFormatPass(ArmPass): + """ + Annotates each node with a tosa_dim_order. tosa_dim_order can be seen as a channels-last dim-order + that in most cases will be (0, 2, 3, 1) for nodes with 4D-shapes. The pass also inserts backend.tosa.TRANSPOSE + when a transition between 3D and 4D/5D tensors happen. + The annotated tosa_dim_order is used to permute the node's shape such that it gives a TOSA-compliant shape. + This pass also makes other values aware of spatial dimensions required by future operators by back propogating info as required. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + @staticmethod + def _channels_last_order(rank: int, spatial_rank: int) -> tuple[int, ...]: + """ + Compute the permutation of tensor dimensions corresponding to a + "channels_last"-style memory layout for an arbitrary tensor rank. + + In standard PyTorch convention: + - "channels_first" order is (N, C, H, W) + - "channels_last" order is (N, H, W, C) + This helper generalizes that concept beyond 4D tensors, producing an index + ordering that moves the channel dimension to the end while preserving the + relative order of batch and spatial dimensions. + + Args: + rank (int): Total number of tensor dimensions (e.g. 4 for NCHW). + spatial_rank (int): Number of spatial dimensions (e.g. 2 for HW, 3 for DHW). + Values outside [0, rank - 2] are clamped to that range. + + Returns: + tuple[int, ...]: A permutation of dimension indices that reorders the + tensor into "channels_last" format. For example: + - rank=4, spatial_rank=2 → (0, 2, 3, 1) # NCHW → NHWC + - rank=5, spatial_rank=3 → (0, 2, 3, 4, 1) # NCDHW → NDHWC + - rank=3, spatial_rank=1 → (0, 2, 1) + + Notes: + If `rank <= 2`, the function returns the identity order since there + are no distinct channel/spatial dimensions. + In practice only rank 4+ tensors will reach this function as the dim order should be fixed for those. + """ + if rank <= 2: + return tuple(range(rank)) + spatial_rank = max(0, min(spatial_rank, rank - 2)) + channel_axis = rank - (spatial_rank + 1) + batch_axes = list(range(channel_axis)) + spatial_axes = list(range(channel_axis + 1, rank)) + return tuple(batch_axes + spatial_axes + [channel_axis]) + + @staticmethod + def _channels_last_inverse_order(rank: int, spatial_rank: int) -> tuple[int, ...]: + """ + Return the inverse permutation of `_channels_last_order`. + + This provides the axis order needed to map a tensor from + "channels_last" layout back to its original layout. + """ + order = ToTosaMemoryFormatPass._channels_last_order(rank, spatial_rank) + inverse = [0] * rank + for idx, axis in enumerate(order): + inverse[axis] = idx + return tuple(inverse) + + def _initial_spatial_rank(self, node: torch.fx.Node) -> int: + """ + Infer the initial spatial rank based on the current rank, input node spatial + ranks and node target. A spatial dimension includes Height, Width or Depth + fields. In most operators this will only ever be Height and Width, but for 3D + operators such as conv3d this would contain 3 spatial dims. + + Spatial rank is the max of any input node spatial ranks and the number of + trailing spatial dims we need to preserve (rank - 2, capped at 3). This + decides which axes must stay channels-last when inserting transposes. + """ + tensor = get_first_fake_tensor(node).data + # Start by assuming 2D when dealing with rank4+ to account for the base case + # of an increasing amount of batch dimensions. + rank = tensor.dim() + if rank >= 4: + spatial_rank = 2 + elif rank == 3: + spatial_rank = 1 + else: + spatial_rank = 0 + + # Look for supported 3D ops and update spatial rank if relevent. + # Currently only Conv3d is supported. + if node.target == exir_ops.backend.tosa.CONV3D.default: + spatial_rank = 3 + + # Check input spatial ranks to know what the previous node spatial ranks were. + input_ranks = [ + input_node.meta.get("tosa_spatial_rank", 0) + for input_node in node.all_input_nodes + ] + if input_ranks: + spatial_rank = max([spatial_rank, *input_ranks]) + + # The max that spatial rank can be is 3. If the current rank not capable of holding + # the current spatial rank, we clamp the max to Rank - (Channels and a singular batch dimension). + # This ensures we revert back to lower spatial ranks after we are finished processing higher spatial ops. + return min(spatial_rank, max(rank - 2, 0)) + + @staticmethod + def memory_format_differs(shape, spatial_rank): + """ + Determine whether a tensor shape would be laid out differently in + channels-first ((N)NCHW) versus channels-last ((N)NHWC) memory format. + """ + if len(shape) <= 2 or spatial_rank <= 0: + return False + channel_idx = len(shape) - (spatial_rank + 1) + channel_idx = max(0, min(channel_idx, len(shape) - 1)) + spatial_dims = shape[channel_idx + 1 :] + if not spatial_dims: + return False + channel_dim = shape[channel_idx] + return channel_dim > 1 and any(dim > 1 for dim in spatial_dims) + + @staticmethod + def is_channel_reshape( + input_shape, output_shape, input_spatial_rank, output_spatial_rank + ): + """ + Check whether a reshape touches the logical channel or consolidated + batch dimensions, which would invalidate dim-order annotations. + """ + + valid_ranks = {4, 5, 6} + + if not (len(input_shape) in valid_ranks and len(output_shape) in valid_ranks): + return False + + def channel_index(shape, spatial_rank): + if len(shape) <= 2: + return len(shape) - 1 + idx = len(shape) - (spatial_rank + 1) + return max(0, min(idx, len(shape) - 1)) + + C_old = input_shape[channel_index(input_shape, input_spatial_rank)] + C_new = output_shape[channel_index(output_shape, output_spatial_rank)] + + def get_batch_prod_dim(shape, spatial_rank): + product = 1 + + for dim in shape[: channel_index(shape, spatial_rank)]: + product = product * dim + + return product + + N_old = get_batch_prod_dim(input_shape, input_spatial_rank) + N_new = get_batch_prod_dim(output_shape, output_spatial_rank) + + return (N_old != N_new) or (C_old != C_new) + + @staticmethod + def insert_input_transpose(node, input_node, graph_module): + """ + Ensure an input tensor is converted to channels-last ordering by + inserting (or folding) a backend `TRANSPOSE` node. + """ + if input_node.target == exir_ops.backend.tosa.TRANSPOSE.default: + pre_permute_node = input_node.all_input_nodes[0] + node.replace_input_with(input_node, pre_permute_node) + return + + rank = len(get_first_fake_tensor(input_node).size()) + spatial_rank = input_node.meta["tosa_spatial_rank"] + mem_format = ToTosaMemoryFormatPass._channels_last_inverse_order( + rank, spatial_rank + ) + # Guard: mem_format must be a true permutation for the current rank + assert sorted(mem_format) == list( + range(rank) + ), f"bad perm {mem_format} for rank {rank} in insert_input_transpose" + + with graph_module.graph.inserting_before(node): + permute_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.TRANSPOSE.default, + args=( + input_node, + list(mem_format), + ), + from_node=node, + ) + node.replace_input_with(input_node, permute_node) + + permute_node.meta["tosa_dim_order"] = tuple( + range(len(input_node.meta["val"].size())) + ) + permute_node.meta["tosa_spatial_rank"] = spatial_rank + + @staticmethod + def insert_output_transpose(node, graph_module): + """ + Convert a producer's output to channels-last by appending a backend + `TRANSPOSE` node and rewiring its users. + """ + + rank = len(get_first_fake_tensor(node).size()) + spatial_rank = node.meta["tosa_spatial_rank"] + mem_format = ToTosaMemoryFormatPass._channels_last_order(rank, spatial_rank) + # Guard: mem_format must be a true permutation for the current rank + assert sorted(mem_format) == list( + range(rank) + ), f"bad perm {mem_format} for rank {rank} in insert_input_transpose" + + with graph_module.graph.inserting_after(node): + permute_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.TRANSPOSE.default, + args=( + node, + list(mem_format), + ), + from_node=node, + ) + + rank = len(get_first_fake_tensor(node).size()) + permute_node.meta["tosa_dim_order"] = mem_format + + node.meta["tosa_dim_order"] = tuple( + range(len(get_first_fake_tensor(node).size())) + ) + permute_node.meta["tosa_spatial_rank"] = spatial_rank + + users = [user for user in node.users if user != permute_node] + for user in users: + user.replace_input_with(node, permute_node) + + @staticmethod + def _insert_view_transpose( + input_shape, output_shape, node, input_node, graph_module + ): + """ + Insert the necessary input/output transposes around reshapes that cross + the (N)NCHW -> (N)NHWC boundary or that touch channel dimensions. + """ + nchw_to_nhwc = len(input_shape) < 4 and len(output_shape) >= 4 + nhwc_to_nchw = len(input_shape) >= 4 and len(output_shape) < 4 + + input_sr = input_node.meta["tosa_spatial_rank"] + output_sr = node.meta["tosa_spatial_rank"] + + channel_reshape = ToTosaMemoryFormatPass.is_channel_reshape( + input_shape, + output_shape, + input_sr, + output_sr, + ) + + if ( + channel_reshape or nhwc_to_nchw + ) and ToTosaMemoryFormatPass.memory_format_differs(input_shape, input_sr): + ToTosaMemoryFormatPass.insert_input_transpose( + node, input_node, graph_module + ) + + if ( + channel_reshape or nchw_to_nhwc + ) and ToTosaMemoryFormatPass.memory_format_differs(output_shape, output_sr): + ToTosaMemoryFormatPass.insert_output_transpose(node, graph_module) + + def insert_tosa_transposes(self, graph_module: torch.fx.GraphModule): + """ + Transposes are needed for operators transforming the input to a different rank, as 4D and 5D-tensors are assumed to be in (N)NHWC-format, whereas all other are in (N)NCHW format. + This is relevant for the following cases: + - view: <4D -> >=4D + - view: >=4D -> <4D + Additionally, a 4D/5D->4D/5D view operation acting on the channel dimension currently needs to be performed in (N)NCHW format, leading to one extra input and output transpose for this case. + + Transposes can be avoided for shapes where there is no difference in actual memory, e.g for + - H == W == 1 + - C == 1 + - 1D/2D tensors + """ + for node in graph_module.graph.nodes: + # call_function and placeholder allowed due to + # index.Tensor being able to come in as both + if node.op != "call_function": + continue + + # Transpose views + elif node.target in ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.index.Tensor, + ): + # For index.Tensor: + # If we want to support 4D indexing tensors this logic + # should be updated. + input_node = node.args[0] + input_shape = input_node.meta["val"].shape + output_shape = node.meta["val"].shape + self._insert_view_transpose( + input_shape, + output_shape, + node, + input_node, + graph_module, + ) + + output_node = graph_module.graph.output_node() + + # Transpose inputs if they are in (N)NCHW format + inputs = [ + n for n in graph_module.graph.nodes if _is_input(n, self.exported_program) + ] + for input_node in inputs: + input_dim_order = get_first_fake_tensor(input_node).dim_order() + if input_dim_order in (NCHW_ORDER, NNCHW_ORDER, NNNCHW_ORDER): + self.insert_output_transpose(input_node, graph_module) + + # Transpose outputs if they are in (N)NCHW format + outputs = output_node.args[0] + if not isinstance(outputs, (list, tuple)): + raise TypeError( + f"Expected output node args to be a list or tuple, got {type(outputs)}" + ) + output_dim_orders = output_node.meta.get("original_dim_orders") + if output_dim_orders is None: + raise RuntimeError( + f"{AnnotateDecomposedMatmulPass.__name__} is required to run at the beginning of the pass pipeline when using {ToTosaMemoryFormatPass.__name__}." + ) + + for output_node_input, output_dim_order in zip( + outputs, output_dim_orders, strict=True + ): + if output_dim_order in ( + NCHW_ORDER, + NNCHW_ORDER, + NNNCHW_ORDER, + ): + self.insert_input_transpose( + output_node, output_node_input, graph_module + ) + + def remove_dim_order_kwargs( + self, graph_module: torch.fx.GraphModule, node: torch.fx.Node + ): + """ + Drop any user-specified `dim_order` keyword arguments so the pass remains + the single source of truth for dim-order annotations. + """ + if node.op != "call_function": + return + + kwargs = dict(node.kwargs) + + if "dim_order" in kwargs: + logger.warning( + f"Ignoring dim_order kwarg '{kwargs['dim_order']}' for '{node.name}'." + ) + del kwargs["dim_order"] + + node.kwargs = kwargs + + def call(self, graph_module: torch.fx.GraphModule): + """ + Entry point for the pass: annotate spatial ranks, compute dim orders, + insert bridging transposes, and forward to child passes. + """ + nodes = list(graph_module.graph.nodes) + for node in nodes: + if "val" not in node.meta: + continue + node.meta["tosa_spatial_rank"] = self._initial_spatial_rank(node) + self.remove_dim_order_kwargs(graph_module, node) + + self._propagate_spatial_ranks(nodes) + + for node in nodes: + if "val" not in node.meta: + continue + node_data = get_first_fake_tensor(node).data + spatial_rank = node.meta["tosa_spatial_rank"] + if _is_input(node, self.exported_program) or node.op == "output": + dim_order = node_data.dim_order() + else: + if node_data.dim() >= 4: + dim_order = self._channels_last_order(node_data.dim(), spatial_rank) + else: + dim_order = tuple(range(node_data.dim())) # type: ignore[assignment] + node.meta["tosa_dim_order"] = dim_order + + # Insert TOSA transposes to convert between (N)NCHW and (N)NHWC format. + # See insert_tosa_transposes for insertion conditions. + self.insert_tosa_transposes(graph_module) + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) + + def _propagate_spatial_ranks(self, nodes): + """ + Propagate `tosa_spatial_rank` metadata backwards so earlier nodes learn + about upcoming spatial requirements from future ops. + """ + changed = True + while changed: + changed = False + for node in reversed(nodes): + if "val" not in node.meta: + continue + tensor = get_first_fake_tensor(node) + limit = max(tensor.dim() - 2, 0) + current = node.meta.get("tosa_spatial_rank") + propagated = current + for user in node.users: + user_rank = user.meta.get("tosa_spatial_rank") + if user_rank is None: + continue + propagated = max(propagated, min(user_rank, limit)) + if propagated != current: + node.meta["tosa_spatial_rank"] = propagated + changed = True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_before_repeat_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_before_repeat_pass.py new file mode 100644 index 0000000..ed6aa82 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_before_repeat_pass.py @@ -0,0 +1,66 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Set, Type + +import torch +import torch.fx +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class UnsqueezeBeforeRepeatPass(ArmPass): + """ + A TOSA TILE op only supports rank(in) == rank(out). + To support Pytorch's repeat which can also add dimensions, + we add an explicit view op before which adds the new dimensions. + New dimensions are appendend at the front, see + https://pytorch.org/docs/stable/generated/torch.Tensor.expand.html + + Original: + repeat(multiples) + After pass: + view(shape = [1]*num_new_dims + old_shape) + repeat(multiples) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target != exir_ops.edge.aten.repeat.default: + continue + + old_shape = list(get_first_fake_tensor(node.all_input_nodes[0]).shape) + old_rank = len(old_shape) + multiples = node.args[1] + new_rank = len(multiples) + if old_rank == new_rank: + continue + + num_new_dims = new_rank - old_rank + new_shape = [1] * num_new_dims + old_shape + + with graph_module.graph.inserting_before(node): + view_node = create_node( + graph_module.graph, + exir_ops.edge.aten.view_copy.default, + (node.all_input_nodes[0], new_shape), + ) + node.replace_input_with(node.all_input_nodes[0], view_node) + modified_graph = True + + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py new file mode 100644 index 0000000..573922e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py @@ -0,0 +1,85 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass, PassResult +from torch._export.utils import is_buffer, is_param +from torch.export.graph_signature import InputKind + + +class UnsqueezeScalarPlaceholdersPass(ArmPass): + """ + Placeholders that have node.meta["val"].shape = () cause issues later in the lowering. + This pass unsqueezes the placeholders to make sure shape is at least (1,). + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def call(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if node.op != "placeholder": + continue + rank = node.meta["val"].dim() + if rank == 0: + if is_buffer(self.exported_program, node): + name = self.exported_program.graph_signature.inputs_to_buffers[ + node.name + ] + elif is_param(self.exported_program, node): + name = self.exported_program.graph_signature.inputs_to_parameters[ + node.name + ] + else: + continue + + tensor = self.exported_program.state_dict.get(name) + + # If we have a persistent=False buffer with no entry in state_dict + spec = next( + s + for s in self.exported_program.graph_signature.input_specs + if getattr(s.arg, "name", None) == node.name + ) + is_non_persistent_buffer = ( + spec.kind is InputKind.BUFFER and spec.persistent is False + ) + if tensor is None and is_non_persistent_buffer: + fake = node.meta["val"] + tensor = torch.ones_like(fake) + + # If we have a scalar, unsqueeze it + if tensor.dim() == 0: + tensor = tensor.unsqueeze(0) + + # update or create entry in state_dict, recreate fake + self.exported_program.state_dict[name] = tensor + node.meta["val"] = node.meta["val"].fake_mode.from_tensor( + tensor, static_shapes=True + ) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) + + def ensures(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if node.op == "placeholder": + rank = node.meta["val"].dim() + if rank == 0: + if not ( + is_buffer(self.exported_program, node) + or is_param(self.exported_program, node) + ): + continue + raise ValueError("Placeholders of rank 0 are not supported!") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/arm_vela.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/arm_vela.py new file mode 100644 index 0000000..1ecaca3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/arm_vela.py @@ -0,0 +1,137 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import os +import struct +import tempfile + +from typing import List + +import numpy as np + +try: + from ethosu.vela import vela # type: ignore + + has_vela = True +except ImportError: + has_vela = False + + +# Pack either input or output tensor block, compose the related arrays into +# per-io structs to simplify runtime use. +def vela_bin_pack_io(prefix, data): + vela_input_shapes = data[prefix + "_shape"] + # Vela input/output shape is fixed to 6D + vela_io_shape_dims = 6 + + ios = struct.pack(" bytes: + tosaname = "out.tosa" + tosa_path = os.path.join(dir, tosaname) + with open(tosa_path, "wb") as f: + f.write(tosa_flatbuffer) + + # invoke vela + output_dir = os.path.join(dir, "output") + args.append(f"--output-dir={output_dir}") + args.append(tosa_path) + if verbose: + args.append("--verbose-all") + vela.main(" ".join(args).split(" ")) + + if any("ethos-u85" in arg for arg in args) or any( + "debug-force-regor" in arg for arg in args + ): + np_path = os.path.join(dir, "output", "out_vela.npz") + else: + np_path = os.path.join(dir, "output", "out_sg0_vela.npz") + + blocks = b"" + with np.load(np_path, allow_pickle=False) as data: + # Construct our modified output_blocks with data in a form easily + # digested on the device side + bin_blocks = {"vela_bin_stream": b""} + + # copy command data through unmodified + bin_blocks["cmd_data"] = data["cmd_data"].tobytes() + + # copy weight data through unmodified + bin_blocks["weight_data"] = data["weight_data"].tobytes() + + # Add a block for scratch, inputs and outputs; scratch shape is a 1 element + # array giving us size in bytes so extract this and add a block of 0's. + # Currently we preallocated this on the host to provide SRAM for computation. + if not isinstance(data["scratch_shape"][0], np.int64): + raise RuntimeError("Expected scratch to be int64") + block_length = int(data["scratch_shape"][0]) + bin_blocks["scratch_size"] = struct.pack(" None: + if quantized is not None: + resolved = bool(quantized) + + elif isinstance(value, Mapping): + resolved = bool(value.get("quantized", False)) + + else: + raise TypeError( + "ArmAnnotationInfo expects a mapping with a 'quantized' entry or a keyword 'quantized'." + ) + dict.__init__(self, quantized=resolved) + object.__setattr__(self, "quantized", resolved) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/arm_compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/arm_compile_spec.py new file mode 100644 index 0000000..dda2930 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/arm_compile_spec.py @@ -0,0 +1,271 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Main implementation of AoT flow to partition and preprocess for Arm target +# backends. Converts via TOSA as an intermediate form supported by AoT and +# JIT compiler flows. +# + +import json +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from enum import Enum + +from executorch.backends.arm.common.pipeline_config import ArmPassPipelineConfig +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.exir.backend.compile_spec_schema import CompileSpec + + +@dataclass(init=False) +class ArmCompileSpec(ABC): + class DebugMode(Enum): + JSON = 1 + TOSA = 2 + + tosa_spec: TosaSpecification + compiler_flags: list[str] = field(default_factory=list) + path_for_intermediates: str | None = None + tosa_debug_mode: DebugMode | None = None + + _TOSA_SPEC_KEY = "tosa_spec" + _COMPILE_FLAGS_KEY = "compile_flags" + _OUTPUT_FORMAT_KEY = "output_format" + _DEBUG_ARTIFACT_KEY = "debug_artifact_path" + _DEBUG_MODE_KEY = "dump_debug_info" + _OUTPUT_REORDER_KEY = "ouput_reorder_workaround" + _TRANSFORM_PIPELINE_CONFIG_KEY = "transform_pipeline_config" + + def _set_compile_specs( + self, + tosa_spec: TosaSpecification, + compiler_flags: list[str], + path_for_intermediates: str | None = None, + tosa_debug_mode: DebugMode | None = None, + output_order_workaround: bool = True, + pipeline_config: ArmPassPipelineConfig | None = None, + ): + """Set all values of dataclass directly.""" + self.tosa_spec = tosa_spec + self.compiler_flags = compiler_flags + self.path_for_intermediates = path_for_intermediates + self.tosa_debug_mode = tosa_debug_mode + self.output_order_workaround = output_order_workaround + self._pipeline_config = pipeline_config + + @classmethod + def from_list(cls, compile_specs: list[CompileSpec]): # noqa: C901 + tosa_spec: TosaSpecification | None = None + output_format: str | None = None + compiler_flags: list[str] | None = None + path_for_intermediates: str | None = None + tosa_debug_mode: ArmCompileSpec.DebugMode | None = None + output_order_workaround: bool = True + pipeline_config: ArmPassPipelineConfig | None = None + unknown_specs: dict[str, str] = {} + for spec in compile_specs: + key = spec.key + val = ( + spec.value.decode() + if isinstance(spec.value, (bytes, bytearray)) + else spec.value + ) + if key == ArmCompileSpec._TOSA_SPEC_KEY: + if tosa_spec is not None: + raise ValueError("More than one tosa_spec entry in compile spec.") + tosa_spec = TosaSpecification.create_from_string(val) + elif key == ArmCompileSpec._COMPILE_FLAGS_KEY: + if compiler_flags is not None: + raise ValueError( + "More than one compiler flags entry in compile spec." + ) + compiler_flags = val.split(" ") + elif key == ArmCompileSpec._OUTPUT_FORMAT_KEY: + if output_format is not None: + raise ValueError( + "More than one output format entry in compile spec." + ) + output_format = val + elif key == ArmCompileSpec._DEBUG_ARTIFACT_KEY: + if path_for_intermediates is not None: + raise ValueError( + "More than one debug artifact path entry in compile spec." + ) + path_for_intermediates = val + elif key == ArmCompileSpec._DEBUG_MODE_KEY: + if tosa_debug_mode is not None: + raise ValueError( + "More than one tosa_debug_mode entry in compile spec." + ) + tosa_debug_mode = ArmCompileSpec.DebugMode[val] + elif key == ArmCompileSpec._OUTPUT_REORDER_KEY: + output_order_workaround = val # type: ignore[assignment] + elif key == ArmCompileSpec._TRANSFORM_PIPELINE_CONFIG_KEY: + if pipeline_config is not None: + raise ValueError( + "More than one transform pipeline entry in compile spec." + ) + pipeline_config = ArmPassPipelineConfig.from_dict(json.loads(val)) + else: + unknown_specs[key] = val + + if tosa_spec is None: + raise ValueError("No tosa_spec in compile spec.") + if output_format is None: + raise ValueError("No output_format in compile spec.") + if output_format != cls.get_output_format(): + raise ValueError( + f"Incorrect output format '{output_format}' for {cls.__name__}, expected '{cls.get_output_format()}'" + ) + if compiler_flags is None: + compiler_flags = [] + + # Create new object from class, but bypass __init__ and use _set_compile_specs instead. + compile_spec = cls.__new__(cls) + compile_spec._set_compile_specs( + tosa_spec=tosa_spec, + compiler_flags=compiler_flags, + path_for_intermediates=path_for_intermediates, + tosa_debug_mode=tosa_debug_mode, + output_order_workaround=output_order_workaround, + pipeline_config=pipeline_config, + ) + cls.from_list_hook(compile_spec, unknown_specs) + compile_spec.validate() + return compile_spec + + @classmethod + def from_list_hook(cls, compile_spec, specs: dict[str, str]): # noqa: B027 + """Allows subclasses to hook into parsing compile spec lists.""" + pass + + @abstractmethod + def validate(self): + """Throws an error if the compile spec is not valid.""" + + def to_list(self): + """Get the ArmCompileSpec in list form.""" + if not self.tosa_spec: + raise ValueError("tosa_spec must be set before calling to_list()") + + # Always supply a TOSA version + compile_spec = [ + CompileSpec(ArmCompileSpec._TOSA_SPEC_KEY, str(self.tosa_spec).encode()) + ] + + # Add compile flags, these are backend specific, refer to the backend + # documentation. + if len(self.compiler_flags) > 0: + compile_spec += [ + CompileSpec( + ArmCompileSpec._COMPILE_FLAGS_KEY, + " ".join(self.compiler_flags).encode(), + ), + ] + + # Add output format to identify kind of compile spec. + compile_spec.append( + CompileSpec( + ArmCompileSpec._OUTPUT_FORMAT_KEY, self.get_output_format().encode() + ) + ) + + if self.path_for_intermediates is not None: + compile_spec.append( + CompileSpec( + ArmCompileSpec._DEBUG_ARTIFACT_KEY, + self.path_for_intermediates.encode(), + ) + ) + + if self.tosa_debug_mode is not None: + if not self.path_for_intermediates: + raise ValueError( + "dump_debug_info() must be used in conjunction with dump_intermediate_artifacts_to()" + ) + + compile_spec.append( + CompileSpec( + ArmCompileSpec._DEBUG_MODE_KEY, self.tosa_debug_mode.name.encode() + ) + ) + + if not self.output_order_workaround: + compile_spec.append( + CompileSpec( + ArmCompileSpec._OUTPUT_REORDER_KEY, + self.output_order_workaround, + ) + ) + + if self._pipeline_config is not None and not self._pipeline_config.is_default(): + compile_spec.append( + CompileSpec( + ArmCompileSpec._TRANSFORM_PIPELINE_CONFIG_KEY, + self._pipeline_config.serialize(), + ) + ) + return compile_spec + + def get_pass_pipeline_config(self) -> ArmPassPipelineConfig: + """ + Returns configuration that controls how the Arm pass pipeline should behave. + Subclasses may override to tweak defaults for specific targets. + """ + if self._pipeline_config is None: + self._pipeline_config = self._create_default_pipeline_config() + return self._pipeline_config + + def set_pass_pipeline_config(self, config: ArmPassPipelineConfig) -> None: + self._pipeline_config = config + + def _create_default_pipeline_config(self) -> ArmPassPipelineConfig: + config = ArmPassPipelineConfig() + if self.tosa_spec.is_U55_subset: + config.disable_masked_softmax() + return config + + def get_intermediate_path(self) -> str | None: + """ + Gets the path used for dumping intermediate results such as tosa and pte. + + Returns: + Path where intermediate results are saved. + """ + return self.path_for_intermediates + + def dump_intermediate_artifacts_to(self, output_path: str | None): + """ + Sets a path for dumping intermediate results during such as tosa and pte. + + Args: + output_path: Path to dump intermediate results to. + """ + self.path_for_intermediates = output_path + return self + + def dump_debug_info(self, debug_mode: DebugMode | None): + """ + Dump debugging information into the intermediates path. + + Args: + debug_mode: The debug mode to use for dumping debug information. + """ + self.tosa_debug_mode = debug_mode + return self + + def set_output_order_workaround(self, output_order_workaround: bool): + self.output_order_workaround = output_order_workaround + return self + + def get_output_order_workaround(self) -> bool: + return self.output_order_workaround + + @classmethod + @abstractmethod + def get_output_format(cls) -> str: + """Returns a constant string that is the output format of the class.""" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/debug.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/debug.py new file mode 100644 index 0000000..e5c90fe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/debug.py @@ -0,0 +1,79 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from typing import Optional + +import torch + +import tosa_serializer as ts +from executorch.exir.print_program import inspect_node + +logger = logging.getLogger(__name__) + + +def debug_node(node: torch.fx.Node, graph_module: torch.fx.GraphModule): + # Debug output of node information + logger.info(get_node_debug_info(node, graph_module)) + + +def get_node_debug_info( + node: torch.fx.Node, graph_module: torch.fx.GraphModule | None = None +) -> str: + output = ( + f" {inspect_node(graph=graph_module.graph, node=node)}\n" + if graph_module + else "" + "-- NODE DEBUG INFO --\n" + f" Op is {node.op}\n" + f" Name is {node.name}\n" + f" Node target is {node.target}\n" + f" Node args is {node.args}\n" + f" Node kwargs is {node.kwargs}\n" + f" Node users is {node.users}\n" + " Node.meta = \n" + ) + for k, v in node.meta.items(): + if k == "stack_trace": + matches = v.split("\n") + output += " 'stack_trace =\n" + for m in matches: + output += f" {m}\n" + else: + output += f" '{k}' = {v}\n" + + if isinstance(v, list): + for i in v: + output += f" {i}\n" + return output + + +# Output TOSA flatbuffer for debugging +def debug_tosa_dump(tosa_graph: bytes, path: str, suffix: str = ""): + filename = f"output{suffix}.tosa" + + logger.info(f"Emitting debug output to: {path=}, {suffix=}") + + os.makedirs(path, exist_ok=True) + + filepath_tosa_fb = os.path.join(path, filename) + with open(filepath_tosa_fb, "wb") as f: + f.write(tosa_graph) + if not os.path.exists(filepath_tosa_fb): + raise IOError("Failed to write TOSA flatbuffer") + + +def debug_fail( + node, + graph_module, + tosa_graph: Optional[ts.TosaSerializer] = None, + path: Optional[str] = None, +): + logger.warning("Internal error due to poorly handled node:") + if tosa_graph is not None and path: + debug_tosa_dump(tosa_graph.serialize(), path) + logger.warning(f"Debug output captured in '{path}'.") + debug_node(node, graph_module) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/pipeline_config.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/pipeline_config.py new file mode 100644 index 0000000..bbceb3c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/pipeline_config.py @@ -0,0 +1,59 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import json +from dataclasses import dataclass, fields +from enum import auto, Enum +from typing import Any + + +class SoftmaxDecompositionConfig(Enum): + MASKED = auto() + UNSTABLE = auto() + + +class FuseDuplicateUsersConfig(Enum): + ENABLED = auto() + DISABLED = auto() + + +@dataclass +class ArmPassPipelineConfig: + softmax: SoftmaxDecompositionConfig = SoftmaxDecompositionConfig.MASKED + fuse_duplicate_users: FuseDuplicateUsersConfig = FuseDuplicateUsersConfig.ENABLED + + def disable_masked_softmax(self) -> None: + self.softmax = SoftmaxDecompositionConfig.UNSTABLE + + def disable_fuse_duplicate_users(self) -> None: + self.fuse_duplicate_users = FuseDuplicateUsersConfig.DISABLED + + def is_default(self) -> bool: + return ( + self.softmax is SoftmaxDecompositionConfig.MASKED + and self.fuse_duplicate_users is FuseDuplicateUsersConfig.ENABLED + ) + + def to_dict(self) -> dict[str, str]: + return {f.name: getattr(self, f.name).name for f in fields(self)} + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "ArmPassPipelineConfig": + config = cls() + for f in fields(cls): + raw_value = data.get(f.name) + if raw_value is None: + continue + enum_type = f.type + setattr(config, f.name, enum_type[raw_value]) + return config + + def serialize(self) -> bytes: + """Return a serialized representation of this config.""" + return json.dumps(self.to_dict()).encode() + + def __repr__(self): + fields = ", ".join(f"{name}={value!r}" for name, value in self.__dict__.items()) + return f"({fields})" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/type.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/type.py new file mode 100644 index 0000000..e53dc1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/common/type.py @@ -0,0 +1,28 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Type checking utilities.""" + +from typing import TypeVar + +T = TypeVar("T") + + +def ensure_type(expected_type: type[T], arg: object) -> T: + """Ensure that the argument is of the expected type. + + Args: + expected_type (type[T]): The expected type. + arg (object): The argument to check. + + Returns: + T: The argument, if it is of the expected type. + + """ + if isinstance(arg, expected_type): + return arg + + expected_name = getattr(expected_type, "__name__", str(expected_type)) + actual_name = type(arg).__name__ + raise TypeError(f"Expected value of type {expected_name}, got {actual_name!r}") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/constants.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/constants.py new file mode 100644 index 0000000..c0d9c45 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/constants.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, Final + +from executorch.exir.dialects._ops import ops as exir_ops + +exir_ops = cast(Any, exir_ops) + +qd = exir_ops.edge.quantized_decomposed + +QUANT_PER_TENSOR_OP: Final = qd.quantize_per_tensor.default +QUANT_PER_TENSOR_OP_T: Final = qd.quantize_per_tensor.tensor +QUANT_PER_CHANNEL_OP: Final = qd.quantize_per_channel.default + +DEQUANT_PER_TENSOR_OP: Final = qd.dequantize_per_tensor.default +DEQUANT_PER_TENSOR_OP_T: Final = qd.dequantize_per_tensor.tensor +DEQUANT_PER_CHANNEL_OP: Final = qd.dequantize_per_channel.default + +Q_OPS: Final = (QUANT_PER_TENSOR_OP, QUANT_PER_TENSOR_OP_T, QUANT_PER_CHANNEL_OP) +DQ_OPS: Final = (DEQUANT_PER_TENSOR_OP, DEQUANT_PER_TENSOR_OP_T, DEQUANT_PER_CHANNEL_OP) + +PER_TENSOR_QDQ_OPS: Final = ( + QUANT_PER_TENSOR_OP, + QUANT_PER_TENSOR_OP_T, + DEQUANT_PER_TENSOR_OP, + DEQUANT_PER_TENSOR_OP_T, +) +PER_CHANNEL_QDQ_OPS: Final = (QUANT_PER_CHANNEL_OP, DEQUANT_PER_CHANNEL_OP) + +NHWC_ORDER: Final = (0, 2, 3, 1) +NHWC_INVERSE_ORDER: Final = (0, 3, 1, 2) +NNHWC_ORDER: Final = (0, 1, 3, 4, 2) +NNHWC_INVERSE_ORDER: Final = (0, 1, 4, 2, 3) +NNNHWC_ORDER: Final = (0, 1, 2, 4, 5, 3) +NNNHWC_INVERSE_ORDER: Final = (0, 1, 2, 5, 3, 4) + +NCHW_ORDER: Final = (0, 1, 2, 3) +NNCHW_ORDER: Final = (0, 1, 2, 3, 4) +NNNCHW_ORDER: Final = (0, 1, 2, 3, 4, 5) + +HWCM_ORDER: Final = (2, 3, 0, 1) + +MAX_RANK: Final = 6 + +DISALLOW_TFA_META_KEY: Final = "_arm_disallow_tfa" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/TARGETS new file mode 100644 index 0000000..a88e3b0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/TARGETS @@ -0,0 +1,14 @@ +# @noautodeps +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "schema", + srcs = [ + "__init__.py", + "schema.py", + ], + deps = [ + "fbsource//third-party/tosa_tools:serializer", + "//caffe2:torch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/schema.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/schema.py new file mode 100644 index 0000000..d4df228 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/debug/schema.py @@ -0,0 +1,145 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +import json + +from dataclasses import asdict, dataclass +from typing import Any, Optional + +import torch +import tosa_serializer as ts + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec + +from torch.fx.traceback import NodeSource + + +@dataclass +class TosaDebugSchema: + node_name: str + operator_name: str + operator_id: int + + +@dataclass +class ATenDebugSchema: + node_name: str + operator_name: str + + @staticmethod + def from_node(node: torch.fx.Node) -> ATenDebugSchema: + # node.target is Union[Callable[..., Any], str], so we need to access this correctly depending on the type + if callable(node.target): + operator_name = node.target.__name__ + else: + operator_name = node.target + + return ATenDebugSchema(node_name=node.name, operator_name=operator_name) + + +@dataclass +class TorchDebugSchema: + stack_trace: list[str] + node_trace: list[dict[str, Any]] | str + nn_module_stack: dict[str, Any] | str + torch_fn: tuple[str, str] | str + + @staticmethod + def serialize_node_trace(node_trace: list[NodeSource]) -> list[dict[str, Any]]: + """Flatten the from_node dictionary to remove nesting.""" + flattened = [] + node_stack = [] + + for n in node_trace: + node_stack.append((n, -1)) + + while len(node_stack) > 0: + node, parent_id = node_stack.pop() + flattened.append( + { + "name": node.name, + "target": node.target, + "graph_id": node.graph_id, + "pass_name": node.pass_name, + "action": node._get_action_string(), + "parent_graph_id": parent_id, + } + ) + + for n in node.from_node: + node_stack.append((n, node.graph_id)) + + return flattened + + @staticmethod + def from_node(node: torch.fx.Node) -> TorchDebugSchema: + node_trace: str | list[dict[str, Any]] = "No node trace available." + + if "from_node" in node.meta: + # Flatten the node_trace dictionary, so there is no nesting + node_trace = TorchDebugSchema.serialize_node_trace(node.meta["from_node"]) + + return TorchDebugSchema( + stack_trace=node.meta.get("stack_trace", "No stack trace available").split( + "\n" + ), + node_trace=node_trace, + nn_module_stack=node.meta.get( + "nn_module_stack", "No module stack trace available" + ), + torch_fn=node.meta.get("torch_fn", "No torch_fn available"), + ) + + +@dataclass +class DebugSchema: + event_id: int + aten_info: ATenDebugSchema + tosa_info: Optional[TosaDebugSchema] + torch_info: TorchDebugSchema + + def to_dict(self) -> dict[str, Any]: + output = asdict(self) + + if self.tosa_info is None: + output.pop("tosa_info") + + return output + + +class DebugHook: + def __init__(self, debug_mode: ArmCompileSpec.DebugMode) -> None: + self._debug_events: list[DebugSchema] = [] + self.mode = debug_mode + + def add(self, node: torch.fx.Node, tosa_op: Any, tosa_op_id: ts.Op) -> DebugSchema: + tosa_debug_info = None + + # If the debug data is being embedded into the TOSA flatbuffer + # do not collect TOSADebugSchema data, it's redundent + if self.mode != ArmCompileSpec.DebugMode.TOSA: + tosa_debug_info = TosaDebugSchema( + node_name=str(tosa_op), + operator_name=str(tosa_op_id), + operator_id=int(tosa_op_id), + ) + + aten_debug_info = ATenDebugSchema.from_node(node) + torch_debug_info = TorchDebugSchema.from_node(node) + + debug_info = DebugSchema( + event_id=len(self._debug_events), + aten_info=aten_debug_info, + tosa_info=tosa_debug_info, + torch_info=torch_debug_info, + ) + self._debug_events.append(debug_info) + + return debug_info + + def serialize(self) -> str: + return json.dumps([event.to_dict() for event in self._debug_events], indent=4) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/__init__.py new file mode 100644 index 0000000..10b14d4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/__init__.py @@ -0,0 +1,11 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +from .backend import EthosUBackend # noqa: F401 +from .compile_spec import EthosUCompileSpec # noqa: F401 +from .partitioner import EthosUPartitioner # noqa: F401 + +__all__ = ["EthosUBackend", "EthosUPartitioner", "EthosUCompileSpec"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/backend.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/backend.py new file mode 100644 index 0000000..bd6da08 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/backend.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Main implementation of AoT flow to partition and preprocess for Arm target +# backends. Converts via TOSA as an intermediate form supported by AoT and +# JIT compiler flows. +# +"""Ahead-of-time Arm Ethos-U backend built on the shared TOSA pipeline.""" + +import logging +from typing import final, List + +from executorch.backends.arm.arm_vela import vela_compile +from executorch.backends.arm.ethosu.compile_spec import EthosUCompileSpec + +from executorch.backends.arm.tosa.backend import TOSABackend +from executorch.exir.backend.backend_details import BackendDetails, PreprocessResult +from executorch.exir.backend.compile_spec_schema import CompileSpec +from torch.export.exported_program import ExportedProgram + +# debug functionality +logger = logging.getLogger(__name__) + + +@final +class EthosUBackend(BackendDetails): + """BackendDetails subclass for delegation to Ethos-U. + + Deduce the TOSA lowering from the compile spec list by filtering out the + compile spec values that are of interest for the TOSABackend. + + """ + + @staticmethod + def _compile_tosa_flatbuffer( + tosa_flatbuffer: bytes, compile_spec: EthosUCompileSpec + ) -> bytes: + """Compile a TOSA flatbuffer into a target-specific binary stream. + + Args: + tosa_flatbuffer (bytes): Serialized TOSA graph produced by + ``TOSABackend``. + compile_spec (EthosUCompileSpec): Compile specification providing + Vela flags and intermediate paths. + + Returns: + bytes: Target-specific binary stream produced by Vela. + + """ + compile_flags = compile_spec.compiler_flags + + if len(compile_flags) == 0: + # Not testing for compile_flags correctness here, just that they are + # present. The compiler will give errors if they are not valid. + raise RuntimeError( + "compile_flags are required in the CompileSpec list for EthosUBackend" + ) + + # Vela tooling only supports flatbuffers up to 2 GiB. + max_flatbuffer_size = 2 * 1024 * 1024 * 1024 + flatbuffer_size = len(tosa_flatbuffer) + if flatbuffer_size > max_flatbuffer_size: + raise RuntimeError( + "TOSA flatbuffer is too large for Vela " + f"({flatbuffer_size} bytes > {max_flatbuffer_size} bytes limit)." + ) + + # Pass on the TOSA flatbuffer to the vela compiler. + binary = vela_compile( + tosa_flatbuffer, + compile_flags, + verbose=logger.getEffectiveLevel() <= logging.INFO, + intermediate_path=compile_spec.get_intermediate_path(), + ) + return binary + + @staticmethod + def preprocess( + edge_program: ExportedProgram, + compile_specs: List[CompileSpec], + ) -> PreprocessResult: + """Lower the exported program and compile it for an Ethos-U target. + + Args: + edge_program (ExportedProgram): Program to lower to Ethos-U. + compile_specs (List[CompileSpec]): Serialized Ethos-U compile specs + supplied by the frontend. + + Returns: + PreprocessResult: Result containing the compiled Ethos-U binary. + + """ + logger.info(f"{EthosUBackend.__name__} preprocess") + + compile_spec = EthosUCompileSpec.from_list(compile_specs) + # deduce TOSA compile_spec from Ethos-U compile spec. We get a new + # compile spec list, containing only elements relevant for the + # TOSABackend. + tosa_compile_spec = TOSABackend.filter_tosa_compile_specs(compile_spec) + + # Backends doesn't allow inheritance, as stated in comments in exir/backend/backend_api.py + # ('All backend implementation are final...'), so use composition instead. + # preprocess returns the serialized TOSA flatbuffer in .processed_bytes, + # which can be passed on to next compilation step. + tosa_preprocess = TOSABackend._preprocess(edge_program, tosa_compile_spec) + + binary = EthosUBackend._compile_tosa_flatbuffer( + tosa_preprocess.processed_bytes, compile_spec + ) + + return PreprocessResult(processed_bytes=binary) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/compile_spec.py new file mode 100644 index 0000000..1d311cb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/compile_spec.py @@ -0,0 +1,117 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( # noqa: unused + ArmPassPipelineConfig, +) +from executorch.backends.arm.tosa import ( # type: ignore[import-not-found] + TosaSpecification, +) +from executorch.exir.backend.compile_spec_schema import CompileSpec + + +class EthosUCompileSpec(ArmCompileSpec): + """Compile specification for Ethos-U NPU targets.""" + + _TARGET_KEY = "target" + + def __init__( + self, + target: str, + system_config: str | None = None, + memory_mode: str | None = None, + extra_flags: list[str] | None = None, + config_ini: str | None = "Arm/vela.ini", + ): + """Normalise Ethos-U compile configuration and compiler flags. + + Args: + target (str): Ethos-U accelerator configuration (for example, + ``"ethos-u55-128"``). + system_config (str | None): System configuration name from the Vela + config file. Defaults based on ``target`` when omitted. + memory_mode (str | None): Memory mode selection from the Vela config + file. Defaults based on ``target`` when omitted. + extra_flags (list[str] | None): Additional command-line flags for + Vela. + config_ini (str | None): Path to a Vela .ini configuration file. + Defaults to ``"Arm/vela.ini"``. + + """ + self.target = target + # Set vela compiler flags + if config_ini is None: + config_ini = "Arm/vela.ini" + compiler_flags = [] if extra_flags is None else extra_flags + compiler_flags.extend( + [ + f"--accelerator-config={target}", + f"--config={config_ini}", + "--output-format=raw", + "--debug-force-regor", + ] + ) + # default system config and memory mode + target_lower = self.target.lower() + if "ethos-u55" in target_lower: + if system_config is None: + system_config = "Ethos_U55_High_End_Embedded" + if memory_mode is None: + memory_mode = "Shared_Sram" + elif "ethos-u85" in target_lower: + if system_config is None: + system_config = "Ethos_U85_SYS_DRAM_Mid" + if memory_mode is None: + memory_mode = "Sram_Only" + else: + raise RuntimeError(f"Unknown ethos target: {target}") + + compiler_flags.append(f"--system-config={system_config}") + compiler_flags.append(f"--memory-mode={memory_mode}") + + # Set TOSA version. + base_tosa_version = "TOSA-1.0+INT+int16+int4" + if "u55" in target_lower: + # Add the Ethos-U55 extension marker + base_tosa_version += "+u55" + if "u85" in self.target: + base_tosa_version += "+cf" + tosa_spec = TosaSpecification.create_from_string(base_tosa_version) + + self._set_compile_specs(tosa_spec, compiler_flags) + self.validate() + + def to_list(self): + """Return compile specs including the encoded Ethos-U target.""" + compile_specs = super().to_list() + compile_specs.append(CompileSpec(self._TARGET_KEY, self.target.encode())) + return compile_specs + + @classmethod + def from_list_hook(cls, compile_spec, specs: dict[str, str]): + """Restore target-specific metadata from serialized compile specs.""" + compile_spec.target = specs.get(cls._TARGET_KEY, None) + + def validate(self): + """Validate the configuration against supported Ethos-U settings.""" + if len(self.compiler_flags) == 0: + raise ValueError( + "compile_flags are required in the CompileSpec list for EthosUBackend" + ) + if "u55" in self.target and not self.tosa_spec.is_U55_subset: + raise ValueError( + f"Target was {self.target} but tosa spec was not u55 subset." + ) + + @classmethod + def get_output_format(cls) -> str: + """Return the artifact format emitted by this compile spec.""" + return "vela" + + def _create_default_pipeline_config(self) -> ArmPassPipelineConfig: + # Any u55 subset passes are treated as tosa specification configs + # As such, they should be added to the base class default. + return super()._create_default_pipeline_config() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/partitioner.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/partitioner.py new file mode 100644 index 0000000..9acc043 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/ethosu/partitioner.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import final, Optional, Sequence + +from executorch.backends.arm.ethosu import EthosUBackend, EthosUCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.exir.backend.partitioner import DelegationSpec +from torch.fx.passes.operator_support import OperatorSupportBase + + +@final +class EthosUPartitioner(TOSAPartitioner): + """ + Partitions subgraphs supported by the Arm Ethos-U backend. + + Args: + compile_spec: List of CompileSpec objects for Ethos-U backend. + additional_checks: Optional sequence of additional operator support checks. + """ + + def __init__( + self, + compile_spec: EthosUCompileSpec, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + ) -> None: + # Override the delegation spec for Ethos-U + self.delegation_spec = DelegationSpec( + EthosUBackend.__name__, compile_spec.to_list() + ) + self.additional_checks = additional_checks + self.tosa_spec = compile_spec.tosa_spec diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/TARGETS new file mode 100644 index 0000000..8f6721b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/TARGETS @@ -0,0 +1,14 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "operator_support", + srcs = glob(["*.py"]), + deps = [ + "//executorch/backends/arm:constants", + "//executorch/backends/arm/_passes:passes", + "//executorch/backends/arm/tosa:tosa", + "//executorch/backends/transforms:remove_getitem_op", + "//executorch/backends/xnnpack/_passes:xnnpack_passes", + "//executorch/exir:lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/__init__.py new file mode 100644 index 0000000..01d936b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/__init__.py @@ -0,0 +1,23 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from . import ( # noqa + clone_dim_order_support, + control_flow_support, + convolution_support, + embedding_support, + ethos_u55_support, + index_select_support, + index_tensor_support, + minmax_support, + pool_2d_support, + reduce_sum_support, + right_shift_support, + slice_copy_support, + to_dim_order_copy_support, + tosa_supported_operators, + where_support, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/clone_dim_order_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/clone_dim_order_support.py new file mode 100644 index 0000000..ae6445c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/clone_dim_order_support.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for dim-order clone in TOSA. + +This module registers a support check for ``dim_order_ops._clone_dim_order`` +ensuring input/output dtypes match and the value types are FakeTensors. + +""" + +import logging + +import torch +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + + +@register_tosa_support_check +class CloneSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``_clone_dim_order``.""" + + targets = [exir_ops.edge.dim_order_ops._clone_dim_order.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Verify the operator target, the number and types of inputs/outputs, and + check that input and output dtypes match. + + """ + if node.target not in self.targets: + self.reporter.report_reject(node, f"Target {node.target} is not supported.") + return False + + input_node = node.args[0] + if not isinstance(input_node, fx.Node): + self.reporter.report_reject(node, "Non tensor clones are not supported") + return False + + # Check input node + if len(node.all_input_nodes) != 1: + self.reporter.report_reject( + node, f"Expected 1 input node, got {len(node.all_input_nodes)}" + ) + return False + + input_val = node.all_input_nodes[0].meta["val"] + if not isinstance(input_val, torch._subclasses.FakeTensor): + self.reporter.report_reject(node, "Expected input to be a FakeTensor.") + return False + + input_dtype = input_val.dtype + + # Check output node + output_val = node.meta["val"] + if not isinstance(output_val, torch._subclasses.FakeTensor): + self.reporter.report_reject(node, "Expected output to be a FakeTensor.") + return False + + if output_val.dtype != input_dtype: + self.reporter.report_reject( + node, + f"Input dtype {input_val.dtype} does not match {output_val.dtype}.", + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/control_flow_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/control_flow_support.py new file mode 100644 index 0000000..24fa34f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/control_flow_support.py @@ -0,0 +1,162 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import typing +from typing import cast + +import torch +import torch.fx as fx + +from executorch.backends.arm._passes.arm_pass_utils import is_submodule_node +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.specification import Tosa_1_00 +from executorch.exir import ExportedProgram +from executorch.exir.backend.utils import WhyNoPartitionReporter + +from torch.fx.passes.operator_support import OperatorSupportBase + + +def _fully_partitioned(submodule: fx.GraphModule) -> bool: + partition_tag = None + for submodule_node in submodule.graph.nodes: + if submodule_node.op == "call_function": + # Input Q ops and output DQ ops will be de-tagged even if the submodule is fully supported. + if ( + submodule_node.target in Q_OPS + and list(submodule_node.all_input_nodes)[0].op == "placeholder" + ): + continue + if ( + submodule_node.target in DQ_OPS + and list(submodule_node.users)[0].op == "output" + ): + continue + if "delegation_tag" not in submodule_node.meta: + return False + if partition_tag is None: + partition_tag = submodule_node.meta["delegation_tag"] + elif submodule_node.meta["delegation_tag"] != partition_tag: + return False + return True + + +def _submodules_fully_partitioned( + node: fx.Node, exported_program: ExportedProgram +) -> bool: + """Returns whether the submodule arguments to a cond node were fully partitioned. + Updates "val" meta of the submodules if they are. + """ + match node.target: + case torch.ops.higher_order.cond: + submodule_args = node.args[1:3] + case torch.ops.higher_order.while_loop: + submodule_args = node.args[0:2] + case _: + raise ValueError(f"Unexpected target: {node.target}") + cond_submodules = ( + ( + exported_program.graph_module.get_submodule( + str(cast(torch.fx.Node, submodule_node).target) + ), + cast(torch.fx.Node, submodule_node), + ) + for submodule_node in submodule_args + ) + for submodule, submodule_node in cond_submodules: + submodule = cast(torch.fx.GraphModule, submodule) + + if _fully_partitioned(submodule): + submodule_node.meta["val"] = submodule.graph.output_node().meta["val"] + else: + return False + return True + + +def _tosa_spec_supports_cf(tosa_spec: TosaSpecification) -> bool: + if not isinstance(tosa_spec, Tosa_1_00): + return False + return tosa_spec.support_extension("cf") + + +class ControlFlowSubmoduleSupported(OperatorSupportBase): + """Check whether control flow submodule args should be partitioned. + Applies control-flow extension constraints before allowing delegation.""" + + def __init__( + self, + exported_program: ExportedProgram, + tosa_spec: TosaSpecification, + reporter: WhyNoPartitionReporter, + ): + self.exported_program = exported_program + self.reporter = reporter + self.tosa_spec = tosa_spec + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + if is_submodule_node(node): + if not _tosa_spec_supports_cf(self.tosa_spec): + self.reporter.report_reject( + node, + f"TOSA spec {self.tosa_spec} does not support control flow extension.", + ) + return False + for user in node.users: + if user.target not in ControlFlowOpSupported._targeted_ops: + self.reporter.report_reject( + node, f"Submodule had unsupported user {user}" + ) + return False + if not _submodules_fully_partitioned(user, self.exported_program): + self.reporter.report_reject( + node, "One submodule was not fully partitioned" + ) + return False + return True + return False + + +class ControlFlowOpSupported(OperatorSupportBase): + """Check whether control flow ops should be partitioned. + Applies control-flow extension constraints before allowing delegation.""" + + _targeted_ops = { + torch.ops.higher_order.cond, + torch.ops.higher_order.while_loop, + } + + def __init__( + self, + exported_program: ExportedProgram, + tosa_spec: TosaSpecification, + reporter: WhyNoPartitionReporter, + ): + self.exported_program = exported_program + self.reporter = reporter + self.tosa_spec = tosa_spec + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + if node.target in self._targeted_ops: + if not _tosa_spec_supports_cf(self.tosa_spec): + self.reporter.report_reject( + node, + f"TOSA spec {self.tosa_spec} does not support control flow extension.", + ) + return False + + if not _submodules_fully_partitioned(node, self.exported_program): + self.reporter.report_reject( + node, "Submodule was not fully partitioned." + ) + return False + return True + + return False diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/convolution_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/convolution_support.py new file mode 100644 index 0000000..f335c50 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/convolution_support.py @@ -0,0 +1,160 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.convolution`` in TOSA. + +Provide general checks and hardware-specific constraints (e.g., U55 subset) for +convolution nodes prior to delegation to the TOSA backend. + +""" + +from typing import cast + +import torch +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class ConvolutionSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for convolutions.""" + + targets = [exir_ops.edge.aten.convolution.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Reject transposed convolutions and convolutions with non-zero output + padding. Apply additional hardware-specific constraints for U55. + + """ + # Not implemented + transposed = cast(bool, node.args[6]) + output_padding = cast(list[int], node.args[7]) + if transposed: + return False + + for pad in output_padding: + if pad != 0: + self.reporter.report_reject( + node, "Convolutions with non-zero output padding not implemented." + ) + return False + + # Hardware specific constraints + if tosa_spec.is_U55_subset: + return self._is_node_supported_u55(node) + else: + return True + + def _is_node_supported_u55(self, node: fx.Node) -> bool: + """Enforce Ethos-U55-specific constraints (Vela 4.2.0). + + Check channel dimensions, kernel sizes, and stride/pad/dilation + combinations permitted on U55. + + Args: + node (fx.Node): Convolution node to validate. + + Returns: + bool: True if supported; otherwise, False. + + """ + shape_in = cast(torch.Tensor, node.all_input_nodes[0].meta["val"]).shape + shape_out = node.meta["val"].shape + kernel = cast(fx.Node, node.args[1]).meta["val"].shape + group = cast(int, node.args[8]) + + C_in = shape_in[1] + C_out = shape_out[1] + if (C_in == group) and (C_out % C_in) == 0 and len(shape_in) <= 4: + # Depthwise convolution + for dim in shape_in[1:]: + if not 1 <= dim <= 65536: + self.reporter.report_reject( + node, + f"Depthwise convolution must have CWH <= 65536, got {dim})", + ) + return False + else: + # Convolution + if not 1 <= C_in <= 65536: + self.reporter.report_reject( + node, f"Convolution must have C <= 65536, got {C_in})" + ) + return False + + kernel_w = kernel[2] + kernel_h = kernel[3] if len(kernel) > 3 else 1 + kernel_z = kernel[4] if len(kernel) > 4 else 1 + # Kernel condition misses constraint on sum of absolute weights + if not 1 <= kernel_h <= 64 or not 1 <= kernel_w * kernel_h <= 4096: + self.reporter.report_reject( + node, + f"Convolution needs to have kernel_y<=64, kernel_x*kernel_y<=4096, got kernel ({kernel_w}, {kernel_h})", + ) + return False + if kernel_z != 1: + self.reporter.report_reject( + node, f"Convolution3d needs to have kernel_z==1, got {kernel_z}." + ) + return False + + if not self._stride_condition(node): + self.reporter.report_reject( + node, "Failed condition on stride, pad and dilation combination." + ) + return False + + return True + + def _stride_condition(self, node: fx.Node) -> bool: + """Check a simplified stride/padding/dilation constraint. + + Disallow strides greater than 3 unless there is no padding and the + dilation is 1. For 3D convolutions, enforce ``stride_z <= 1``. + + Args: + node (fx.Node): Convolution node to evaluate. + + Returns: + bool: True if the condition is satisfied. + + """ + strides = cast(list[int], node.args[3]) + has_padding = any(pad > 0 for pad in cast(list[int], node.args[4])) + dilations = cast(list[int], node.args[5]) + if len(dilations) == 1: + dilations = [dilations[0]] * 2 + if len(strides) == 1: + strides = [strides[0]] * 2 + + if len(strides) > 2: + stride_z = strides[2] + if stride_z > 1: + self.reporter.report_reject( + node, f"Convolution3d only supports stride_z<=1, got {stride_z}." + ) + return False + + for stride, dilation in zip(strides, dilations): + stride_condition = 1 <= stride <= 3 + dilation_condition = (not has_padding) and (dilation == 1) + if (not stride_condition) and (not dilation_condition): + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/embedding_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/embedding_support.py new file mode 100644 index 0000000..3ad1701 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/embedding_support.py @@ -0,0 +1,61 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.embedding`` in TOSA. + +Permit embeddings with int32 indices (TOSA lacks int64 support); other dtypes +are rejected by this check. + +""" + +import torch + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class EmbeddingSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.embedding``.""" + + targets = [exir_ops.edge.aten.embedding.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if the node is supported by TOSA. + + PyTorch's ``aten.embedding`` typically takes int64 indices, but for + TOSA we only allow int32 indices. The export path decomposes the op so + that int32 indices are ok. + + """ + if len(node.all_input_nodes) != 2: + self.reporter.report_reject( + node, + (f"Expected exactly two input nodes, got {len(node.all_input_nodes)}"), + ) + return False + + indices_val = node.all_input_nodes[1].meta["val"] + indices_dtype = indices_val.dtype + + if indices_dtype != torch.int32: + self.reporter.report_reject( + node, + f"Indices dtype {indices_val.dtype} is not supported in {node.target}.", + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/ethos_u55_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/ethos_u55_support.py new file mode 100644 index 0000000..bd43233 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/ethos_u55_support.py @@ -0,0 +1,598 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide Ethos-U55 specific operator support checks. + +Contains dtype validation, explicit unsupported-op filtering, and shape/ +permutation constraints for view and permute operations when targeting the +Ethos-U55 subset of TOSA. + +""" + + +import typing +from typing import cast + +import torch +import torch.fx as fx + +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm._passes.convert_permute_singleton_to_view_pass import ( + is_singleton_permutation, +) +from executorch.backends.arm._passes.insert_table_ops import TableOps +from executorch.backends.arm.operators.op_permute import transform_permutation_vector +from executorch.backends.arm.tosa.utils import tosa_shape +from executorch.exir.backend.utils import WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops +from torch.fx.passes.operator_support import OperatorSupportBase + + +def _try_determine_dtype(node: fx.Node) -> torch.dtype | None: + """Return an inferred dtype for a node when possible. + + Uses fake tensor metadata and nearby quantize/dequantize nodes to infer the + integer dtype used by the operator. Returns ``None`` when the dtype cannot + be determined reliably. + + Args: + node (fx.Node): FX node to inspect. + + Returns: + torch.dtype | None: Inferred dtype or ``None`` if unknown. + + """ + dtype = get_first_fake_tensor(node).dtype + if not dtype.is_floating_point: + return dtype + if node.target is exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default: + return get_first_fake_tensor(node.all_input_nodes[0]).dtype + q_node = list(node.users)[0] + if q_node.target is exir_ops.edge.quantized_decomposed.quantize_per_tensor.default: + return typing.cast(torch.dtype, q_node.args[-1]) + # We can't easily figure out dtype, return None + return None + + +class EthosU55DtypeSupport(OperatorSupportBase): + """Validate dtypes for U55-supported operators. + + Ensures operators use a supported integer dtype according to U55 + constraints, with specific rules for convolution, matmul, and table ops. + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + targeted_ops_i8_i16_i32 = [ + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.repeat.default, + exir_ops.edge.aten.constant_pad_nd.default, + exir_ops.edge.aten.view.default, + exir_ops.edge.aten.permute.default, + exir_ops.edge.aten.permute_copy.default, + ] + + target_ops_i8 = tuple(TableOps.included_ops()) + + def is_node_supported( # noqa: C901 + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node uses supported dtypes. + + Applies per-operator dtype rules for U55, including specialized input + and weight constraints for convolution and int8-only checks for table + operations and matmul variants. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: True if supported; otherwise, False. + + """ + dtype = _try_determine_dtype(node) + if dtype is None: + # If we couldn't determine dtype, just return ok. + return True + + if node.target in self.targeted_ops_i8_i16_i32: + if dtype not in (torch.int8, torch.int16, torch.int32): + self.reporter.report_reject( + node, f"Unsupported dtype {dtype} (Supports i8, i16, i32)." + ) + return False + + if node.target in self.target_ops_i8: + if dtype not in (torch.int8, torch.int16): + self.reporter.report_reject( + node, f"Unsupported dtype {dtype} (Supports i8, i16)." + ) + return False + + if node.target == exir_ops.edge.aten.convolution.default: + ifm, weight = node.all_input_nodes[0:2] + ifm_dtype = _try_determine_dtype(ifm) + if ifm_dtype is not None and ifm_dtype not in (torch.int8, torch.int16): + self.reporter.report_reject( + node, f"Unsupported input dtype {dtype} (Supports i8, i16)." + ) + return False + weight_dtype = _try_determine_dtype(weight) + if weight_dtype is not None and weight_dtype not in (torch.int8,): + self.reporter.report_reject( + node, f"Unsupported weight dtype {dtype} (Supports i8)." + ) + return False + if len(node.all_input_nodes) > 2: + bias = node.all_input_nodes[2] + bias_dtype = _try_determine_dtype(bias) + if bias_dtype is not None and bias_dtype not in (torch.int32,): + self.reporter.report_reject( + node, f"Unsupported bias dtype {dtype} (Supports i32)." + ) + return False + + if node.target in ( + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.bmm.default, + ): + for input_node in node.all_input_nodes: + dtype = _try_determine_dtype(input_node) + if dtype is not None and dtype != torch.int8: + self.reporter.report_reject( + input_node, + f"Input {input_node.name} has unsupported dtype {dtype} (Supports i8).", + ) + return False + + return True + + +class EthosU55NotSupported(OperatorSupportBase): + """Reject operators not supported by Ethos-U55. + + The ``unsupported_ops`` list contains aten ops that either map to TOSA + operators the U55 cannot run or remain unimplemented. The mapping comments + capture expected TOSA equivalents when not obvious. + + """ + + unsupported_ops = [ + exir_ops.edge.aten.any.default, # REDUCE_ANY + exir_ops.edge.aten.any.dim, # REDUCE_ANY + exir_ops.edge.aten.any.dims, # REDUCE_ANY + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.bitwise_and.Scalar, + exir_ops.edge.aten.bitwise_or.Scalar, + exir_ops.edge.aten.bitwise_xor.Scalar, + exir_ops.edge.aten.bitwise_not.default, + exir_ops.edge.aten.logical_and.default, + exir_ops.edge.aten.logical_or.default, + exir_ops.edge.aten.logical_xor.default, + exir_ops.edge.aten.logical_not.default, + exir_ops.edge.aten.amax.default, # REDUCE_MAX + exir_ops.edge.aten.amin.default, # REDUCE_MIN + exir_ops.edge.aten.conv3d.default, # CONV3D + exir_ops.edge.aten.conv3d.padding, # CONV3D (deprecated alias) + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.ne.Tensor, + exir_ops.edge.aten.ne.Scalar, + exir_ops.edge.aten.flip.default, # REVERSE + exir_ops.edge.aten.grid_sampler_2d, # GATHER + exir_ops.edge.aten.index.Tensor, # GATHER + exir_ops.edge.aten.index_select.default, # GATHER + exir_ops.edge.aten.scatter.src, + exir_ops.edge.aten.scatter.value, + exir_ops.edge.aten.select_scatter.default, + exir_ops.edge.aten.scatter_reduce.two, + exir_ops.edge.aten.scatter_add.default, + exir_ops.edge.aten.upsample_nearest2d.vec, # RESIZE + exir_ops.edge.aten.upsample_bilinear2d.vec, # RESIZE + exir_ops.edge.aten.reflection_pad1d.default, # REVERSE + exir_ops.edge.aten.reflection_pad2d.default, # REVERSE + exir_ops.edge.aten.reflection_pad3d.default, # REVERSE + exir_ops.edge.aten.where.self, # SELECT + ] + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + self.reporter = reporter + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return False for nodes explicitly unsupported on U55. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: False if ``node.target`` is in ``unsupported_ops``; else True. + + """ + if node.target in self.unsupported_ops: + self.reporter.report_reject(node, "Op is not supported on U55.") + return False + + return True + + +shape_t = list[int] + + +class EthosU55ViewCheck(OperatorSupportBase): + """Validate view/select shapes and dtypes for U55. + + Performs lightweight checks on output shape rank and product constraints, + with awareness that transposes may be inserted around view/select during + lowering to channels-last. + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + def axes_product(self, nhwc_shape: shape_t) -> int: + """Return the product of all axes in ``nhwc_shape``. + + Args: + nhwc_shape (list[int]): Shape in NHWC order. + + Returns: + int: Product of the axis sizes. + + """ + product = 1 + for axes in nhwc_shape: + product *= axes + return product + + # TODO: Extend this check to comply with u55 restrictions + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Check whether a given view/select node is U55-supported. + + Currently only checks dtypes and product of axes. + + It is not the view operator itself that is not supported on U55. In + order for the view operator to be compatible with the channels-last + format of TosaBackend, transposes may need to be inserted before and + after the view op. If that happens and that transpose operator does not + adhere to the limitations then it will result in the following error: + + CPU performance estimation for "Transpose" not implemented. + ... + CPU operations are not supported for GraphAPI input + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node for ``view_copy`` or ``select``. + + Returns: + bool: False if rejected by constraints; otherwise, True. + + """ + # Select decomposes into squeeze, which in turn becomes a view. Therefore, + # perform the same check on select operators as view operators. + if node.target not in ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.select.int, + exir_ops.edge.aten.select_copy.int, + ): + return True + + if node.target in ( + exir_ops.edge.aten.select.int, + exir_ops.edge.aten.select_copy.int, + ): + input_node, dim, index = cast(tuple[fx.Node, int, int], node.args) + + shape = input_node.meta["val"].shape + rank = len(shape) + if not -rank <= dim < rank: + self.reporter.report_reject( + node, + (f"Dimension {dim} out of range for rank {rank}."), + ) + return False + dim = dim % rank + + size = shape[dim] + if not -size <= index < size: + self.reporter.report_reject( + node, + (f"Index {index} out of range for dim {dim} with size {size}."), + ) + return False + index = index % size + + # Shape after squeeze. This may get converted into a view which may become + # a transpose. This is why we're checking select. + squeezed_shape = shape[:dim] + shape[dim + 1 :] + shape = squeezed_shape + else: + shape = list(get_first_fake_tensor(node).shape) + + dtype = _try_determine_dtype(node) + + rank = len(shape) + if rank > 4: + if dtype == torch.int32: + self.reporter.report_reject(node, "No support for rank > 4 in int32.") + return False + + if dtype in (torch.int8, torch.int16): + if self.axes_product(shape) > 65536: + self.reporter.report_reject( + node, + f"No support for {shape=}, {dtype=}. Product of axes must be <65536", + ) + return False + + return True + + +class EthosU55TransposeCheck(OperatorSupportBase): + """Validate permute nodes against U55 reshape/transpose limits. + + Applies dtype- and rank-specific constraints to permutations. Tests both + NCHW and NHWC interpretations for rank-3/4 shapes since dim order is unknown + at partition time. + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + def _pad_to_rank_4( + self, shape: shape_t, permutation: list[int] + ) -> tuple[shape_t, shape_t]: + """Pad shape/permutation to rank 4 by prepending ones/indices. + + Args: + shape (list[int]): Original shape. + permutation (list[int]): Original permutation indices. + + Returns: + tuple[list[int], list[int]]: Padded shape and permutation. + + """ + diff = 4 - len(shape) + padded_shape = [1] * diff + shape + for i in range(len(permutation)): + permutation[i] += diff + padded_permutation = list(range(diff)) + permutation + return padded_shape, padded_permutation + + def axes_product(self, nhwc_shape: shape_t) -> int: + """Return the product of all axes in ``nhwc_shape``. + + Args: + nhwc_shape (list[int]): Shape in NHWC order. + + Returns: + int: Product of the axis sizes. + + """ + product = 1 + for axes in nhwc_shape: + product *= axes + return product + + def _permute_constraint_i8_i16( + self, nhwc_shape: list[int], permutation: list[int] + ) -> bool: + """Return True if permutation meets i8/i16 constraints.""" + N, H, W, C = nhwc_shape + + if is_singleton_permutation(nhwc_shape, permutation): + return True + + match permutation: + case (0, 1, 2, 3): # NHWC -> NHWC + return True + case ( + (0, 2, 1, 3) | (0, 1, 3, 2) | (0, 3, 1, 2) | (0, 2, 3, 1) | (0, 3, 2, 1) + ): + # NHWC -> NWHC, NHCW, NCWH, NCHW, NCHW -> NHWC + return N * H <= 65536 and W <= 65536 and C <= 65536 + case _: + return self.axes_product(nhwc_shape) <= 65536 + + def _permute_constraint_i32( + self, nhwc_shape: list[int], permutation: list[int] + ) -> bool: + """Return True if permutation meets i32 constraints.""" + N, H, W, C = nhwc_shape + match permutation: + case (0, 1, 2, 3): # NHWC -> NHWC + return C <= 32768 + case (0, 2, 1, 3): # NHWC -> NHWC + return N == 1 and H <= 65536 and W <= 65536 and C <= 16384 + case (0, 1, 3, 2): # NHWC -> NHCW + return N * H <= 65536 and W <= 65536 and C <= 65536 + case _: + return False + + def _permute_constraint(self, shape, permutation, dtype): + """Return True if permutation meets dtype-specific constraints.""" + if dtype in (torch.int8, torch.int16): + return self._permute_constraint_i8_i16(shape, permutation) + if dtype == torch.int32: + return not self._permute_constraint_i32(shape, permutation) + return True + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if a permute node satisfies U55 constraints. + + Tests both NCHW and NHWC interpretations for rank-3/4 shapes, and + applies dtype-specific limits to shapes and permutations. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: True if supported; otherwise, False. + + """ + if not node.target == exir_ops.edge.aten.permute_copy.default: + return True + + shape = list(get_first_fake_tensor(node).shape) + dtype = _try_determine_dtype(node) + permutation = list(typing.cast(list[int], node.args[1])) + + rank = len(shape) + if rank > 4: + if dtype == torch.int32: + self.reporter.report_reject( + node, f"No support for {permutation=} in int32." + ) + return False + if dtype in (torch.int8, torch.int16): + if self.axes_product(shape) > 65536: + self.reporter.report_reject( + node, + f"No support for {shape=}, {dtype=}. Product of axes must be <65536", + ) + return False + return True + + shape, permutation = self._pad_to_rank_4(shape, permutation) + if rank == 3 or rank == 4: + # For rank 3 and 4, we can have channels first or channels last dim order. + # Since we don't know which at partition-time, test both. + + nhwc_shape = tosa_shape(shape, [0, 2, 3, 1]) + nhwc_permutation = transform_permutation_vector(permutation, [0, 2, 3, 1]) + + if not self._permute_constraint(nhwc_shape, nhwc_permutation, dtype): + self.reporter.report_reject( + node, + f"Unsupported NHWC {nhwc_shape=} for {nhwc_permutation=}, {dtype=}", + ) + return False + + if not self._permute_constraint(shape, permutation, dtype): + self.reporter.report_reject( + node, f"Unsupported NCHW {shape=} for {permutation=}, {dtype=}" + ) + return False + + return True + + +class EthosU55CastCheck(OperatorSupportBase): + """Reject unsupported casts on U55. + + U55 does not support casting from INT32 or any casts involving BOOL. Note that + casting from one dtype to the same dtype is a no-op and is supported. + + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + targets = [ + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ] + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node satisfies the cast constraints of U55. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: True if supported; otherwise, False. + + """ + if node.target not in self.targets: + return True + input_dtype = get_first_fake_tensor(node.all_input_nodes[0]).dtype + output_dtype = get_first_fake_tensor(node).dtype + if input_dtype == output_dtype: + # This is ok as this will not result in a cast + return True + if input_dtype in (torch.bool, torch.int32): + self.reporter.report_reject( + node, f"Casting from {input_dtype} is not supported on U55." + ) + return False + if output_dtype in (torch.bool,): + self.reporter.report_reject( + node, f"Casting to {output_dtype} is not supported on U55." + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_select_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_select_support.py new file mode 100644 index 0000000..a83151a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_select_support.py @@ -0,0 +1,60 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.index_select`` in TOSA. + +Accept int32 indices and restrict supported weight shapes to 2D or 3D with a +unit batch dimension. + +""" +import torch +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class IndexSelectSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.index_select``.""" + + targets = [exir_ops.edge.aten.index_select.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if the node is supported by TOSA. + + Require int32 indices and limit weight shapes to 2D or 3D with a leading + dimension of 1. + + """ + weights_shape = node.all_input_nodes[0].meta["val"].shape + indices_val = node.all_input_nodes[1].meta["val"] + indices_dtype = indices_val.dtype + + if indices_dtype != torch.int32: + self.reporter.report_reject( + node, + f"Indices dtype {indices_val.dtype} is not supported in {node.target}.", + ) + return False + + if not ( + len(weights_shape) == 2 + or (len(weights_shape) == 3 and weights_shape[0] == 1) + ): + self.reporter.report_reject( + node, f"{node.target} with weights shape {weights_shape} not supported." + ) + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_tensor_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_tensor_support.py new file mode 100644 index 0000000..5de70c0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/index_tensor_support.py @@ -0,0 +1,160 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide TOSA support checks for ``aten.index.Tensor``. + +Reject unsupported patterns such as high-rank index tensors, front-positioned +slice/ellipsis/None markers, and cases that exceed ``int32`` element limits. + +""" + +import math + +import torch +import torch.fx as fx +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.common.type import ensure_type +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class IndexTensorSupported(SupportedTOSAOperatorCheck): + """Prevent partitioning of unsupported ``index.Tensor`` usages. + + This support check is intended to prevent the partitioning of + currently unsupported usages of the index.Tensor operator. + + 1. Usages where indexing tensors are of rank 4 or higher. + This is due to the AnnotateChannelsLastDimOrder pass and + the rarity of such operation. + Support is possible but would require further changes to the above + pass which can be added at such a time as is necessary. + + 2. Usages where slice, ellipsis or None are present before an indexing tensor: + t[{start}:{end}, indexTensor] - slicing + t[None, indexTensor] - unsqueeze + t[..., indexTensor] - ellipsis + + 3. Usages where the value tensor contains more than int32.max elements + This is due to int32 TOSA limitation and the fact that we flatten out + and accumulate all index tensors. + As such to avoid overflow we reject lowering of this operator if it is + possible for indices to go over the int32 limit. + + Extra information regarding #2: + Pytorch decomposes slice and None usages before they reach aten. + In the case of Slicing and Unsqueeze, Pytorch will add the relevant + operation just before the index.Tensor op. + In the case of Ellipsis no extra operation is added. + + In all three cases Pytorch will insert "None"(s) in the index list + only if the above operations are done on a dimension BEFORE one being indexed. + + When slicing, unsqueeze and ellipsis are done on dimensions after + the ones being indexed, then they do not affect the final output + values, only the shape. Thus None is not passed to the index.Tensor op. + + The purpose of None is to signify to index.Tensor that a dimension + should not be indexed. + In such cases the logic behaves similar to batching along that dimension. + For the sake of simplicity we have not implemented this behavior yet + and thus have put this support check in place to prevent the partitioning + of index.Tensor ops which include None. + + Examples: + #1 - Slice ----------------------------------------------------- + t = torch.randint(25, size(25, 3, 6)) + t[1:5, torch.arange(3)] + + Turns into: (edge pseudo code) + slice_res = ...edge__ops_aten_slice_copy_Tensor(t, dim=0, start=1, end=2) + out = ...edge__ops_aten_index_Tensor(slice_res, [None, torch.arange(3)]) + + #2 - None (Unsqueeze) ------------------------------------------ + t = torch.randint(25, size(25, 3, 6)) + t[None, torch.arange(3)] + + Turns into: edge pseudo code) + unsqueeze_res = ...edge__ops_aten_unsqueeze(t, dim=0) + out = ...edge__ops_aten_index_Tensor(unsqueeze_res, [None, torch.arange(3)]) + + #3 - None (Unsqueeze) After index ------------------------------ + t = torch.randint(25, size(25, 3, 6)) + t[torch.arange(3), None] + + Turns into: edge pseudo code) + unsqueeze_res = ...edge__ops_aten_unsqueeze(t, dim=1) + out = ...edge__ops_aten_index_Tensor(unsqueeze_res, [torch.arange(3)]) + + NB. + With the current implementation of flattening tensors and indices out, + supporting None (Unsqueeze) is simply a matter of ignoring the + None dimension. + This is not the case for Slice and Ellipsis operators, where + the size of the new dimension can be > 1. + + Note that slice ops interleaved between indexes such as: + t[1:3, torch.arange(5), 2:3, torch.arange(3).reshape(3,1)] + are also possible and can result in some unintuitive behaviors + where batching and indexing are mixed together. + + """ + + targets = [exir_ops.edge.aten.index.Tensor] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if ``aten.index.Tensor`` usage fits supported patterns. + + Enforces the following constraints: + - No ``None`` (unsqueeze), slice, or ellipsis before an indexing tensor. + - Indexing tensors have rank <= 3. + - The value tensor element count fits in ``int32``. + + """ + indices = node.args[1] + for index in indices: # type: ignore[union-attr] + # Usage 2 guard + if index is None: + self.reporter.report_reject( + node, + ( + "None (from slice/unsqueeze/ellipsis) before an indexing tensor" + " is not supported." + ), + ) + return False + + # Usage 1 guard + index = ensure_type(torch.fx.Node, index) + fake_tensor = get_first_fake_tensor(index) + if len(fake_tensor.size()) > 3: + self.reporter.report_reject( + node, + ("Indexing tensors of rank >= 4 is not supported."), + ) + return False + + # Usage 3 guard + input_node = ensure_type(torch.fx.Node, node.args[0]) + total_vals = math.prod(get_first_fake_tensor(input_node).shape) + if total_vals > torch.iinfo(torch.int32).max: + self.reporter.report_reject( + node, + ("Value size exceeds int32 range; would overflow flattened indexing."), + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/minmax_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/minmax_support.py new file mode 100644 index 0000000..8ba5d93 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/minmax_support.py @@ -0,0 +1,61 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for min/max along a dimension in TOSA. + +Provide support checks ensuring that argmax/argmin indices are not consumed, +restricting to float profiles until index quantization is supported. + +""" + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class MinMaxSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.max.dim`` and ``aten.min.dim``.""" + + targets = [ + exir_ops.edge.aten.max.dim, + exir_ops.edge.aten.min.dim, + ] + + # TODO : "MLETORCH-718 : Quantization of indices in arm_quantizer" + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Allow max/min when the argmax/argmin output is unused or dropped (i.e., + only the value is consumed). Disallow cases where arg indices are + further used. + + """ + if node.target in [exir_ops.edge.aten.max.dim, exir_ops.edge.aten.min.dim]: + no_argmax = len(node.users) == 1 + no_argmax_users = (len(node.users) == 2) and ( + len(list(node.users)[1].users) == 0 + ) + + if not (no_argmax or no_argmax_users): + self.reporter.report_reject( + node, + ( + "Using the indices output is not supported; only usage of the " + "values output is supported." + ), + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/pool_2d_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/pool_2d_support.py new file mode 100644 index 0000000..c0428e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/pool_2d_support.py @@ -0,0 +1,214 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide TOSA support checks for 2D pooling. + +Validate ``avg_pool2d`` and ``max_pool2d_with_indices`` against U55 profile +constraints including kernel size, stride, padding, and dimensionality. + +""" + +from typing import cast + +import torch +import torch.fx as fx +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +def kernel_check(kernel: tuple[int, int]) -> bool: + """Check if kernel size is within U55 constraints. + + Checks that ``kernel_x * kernel_y`` is in ``[1, 65536]`` and + ``kernel_y`` is in ``[1, 256]`` as required by the U55 profile. + + Args: + kernel (tuple[int, int]): Kernel height and width ``(kh, kw)``. + + Returns: + bool: True if the kernel passes validation. + + """ + if not (1 <= kernel[0] * kernel[1] <= 65536): + return False + return 1 <= kernel[1] <= 256 + + +def stride_check(strides: tuple[int, int]) -> bool: + """Check if strides are within U55 constraints. + + Args: + strides (tuple[int, int]): Vertical and horizontal strides. + + Returns: + bool: True if each stride is in ``[1, 3]``. + + """ + return all(1 <= stride <= 3 for stride in strides) + + +def dim_check(shape=torch.Size) -> bool: + """Check if non-batch dims are within U55 constraints. + + Verifies that all dimensions except batch are in ``[1, 65536]``. + + Args: + shape (torch.Size): Input tensor shape. + + Returns: + bool: True if all checked dimensions pass. + + """ + check = True + for dim in shape[1:]: + check &= 1 <= dim <= 65536 + return check + + +@register_tosa_support_check +class AvgPool2dSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support checks for ``aten.avg_pool2d``. + + Applies additional constraints when targeting the U55 subset, including + limits on kernel size, stride, padding behavior, and tensor ranks. + + """ + + targets = [ + exir_ops.edge.aten.avg_pool2d.default, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported(self, node: fx.Node, tosa_spec: TosaSpecification): + """Return True if ``avg_pool2d`` satisfies U55 constraints. + + Computes the effective TOSA padding (depending on ``count_include_pad`` + and ``divisor_override``) and validates kernel, stride, and shape limits. + + """ + if not tosa_spec.is_U55_subset: + return True + + # U55 case, Vela 4.2.0 (25.02 release) + input_arg = node.args[0] + if isinstance(input_arg, torch.fx.Node): + input_arg = get_first_fake_tensor(input_arg) + shape = input_arg.data.shape # type: ignore[union-attr] + + # Calculate padding used in the final TOSA operator + kernel = cast(tuple[int, int], node.args[1]) + stride = cast(tuple[int, int], node.args[2]) + padding = cast(tuple[int, int], node.args[3]) if len(node.args) > 3 else (0, 0) + ceil_mode = cast(bool, node.args[4]) if len(node.args) > 4 else False + count_include_pad = cast(bool, node.args[5]) if len(node.args) > 5 else True + divisor_override = cast(int, node.args[6]) if len(node.args) > 6 else None + + # If count_include_pad is True or divior_override is given, padding is applied + # by concating zero-elements rather than setting it in the avg_pool op. + if count_include_pad or divisor_override is not None: + tosa_padding = (0, 0, 0, 0) + # Otherwise, calculate the padding as done in the node visitor + else: + post_pad_h = adjust_pooling_pad_if_needed( + shape[2], kernel[0], stride[0], padding[0], ceil_mode + ) + post_pad_w = adjust_pooling_pad_if_needed( + shape[3], kernel[1], stride[1], padding[1], ceil_mode + ) + tosa_padding = (padding[0], post_pad_h, padding[1], post_pad_w) + + if not all(1 <= k <= 8 for k in kernel) and not all( + v == 0 for v in tosa_padding + ): + self.reporter.report_reject( + node, f"Avgpool2d with padding needs kernel dims < 8, got {kernel}" + ) + return False + + if not kernel_check(kernel): + self.reporter.report_reject( + node, + f"Avgpool2d needs kernel_y < 256, kernel_x*kernel_y<=65536, got {kernel}", + ) + return False + + if not dim_check(shape): + self.reporter.report_reject( + node, + f"Avgpool2d needs N == 1, rest dims <= 65536, got shape {list(shape)}", + ) + return False + if not stride_check(stride): + self.reporter.report_reject( + node, f"Avgpool2d needs stride <= 3, got {stride}" + ) + return False + if not shape[0] == 1: + self.reporter.report_reject( + node, f"Avgpool2d needs N==1, got N=={shape[0]}" + ) + return False + return True + + +@register_tosa_support_check +class MaxPool2dSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support checks for ``aten.max_pool2d_with_indices``. + + Applies additional constraints when targeting the U55 subset, including + limits on kernel size, stride, and tensor ranks. + + """ + + targets = [ + exir_ops.edge.aten.max_pool2d_with_indices.default, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported(self, node: fx.Node, tosa_spec: TosaSpecification): + """Return True if ``max_pool2d_with_indices`` satisfies U55 + constraints. + """ + if not tosa_spec.is_U55_subset: + return True + + # U55 case, Vela 4.2.0 (25.02 release) + shape = cast(torch.Tensor, node.all_input_nodes[0].meta["val"]).shape + kernel = cast(tuple[int, int], node.args[1]) + stride = cast(tuple[int, int], node.args[2]) + + if not kernel_check(kernel): + self.reporter.report_reject( + node, + f"Maxpool2d needs kernel_y < 256, kernel_x*kernel_y<=65536, got {kernel}", + ) + return False + if not dim_check(shape): + self.reporter.report_reject( + node, + f"Maxpool2d needs N == 1, rest dims <= 65536, got shape {list(shape)}", + ) + return False + if not stride_check(stride): + self.reporter.report_reject( + node, f"Maxpool2d needs stride <= 3, got {stride}" + ) + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/reduce_sum_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/reduce_sum_support.py new file mode 100644 index 0000000..02e9e0d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/reduce_sum_support.py @@ -0,0 +1,76 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.sum.dim_IntList`` in TOSA. + +Provide shape constraints for U55 subsets; otherwise allow reductions. + +""" +from typing import cast + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class SumSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for sum over dimensions.""" + + targets = [exir_ops.edge.aten.sum.dim_IntList] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + On U55 subsets, enforce bounds on the reduced dimension and the products + of sizes before/after the reduction axis. On other targets, accept the + operation unconditionally. + + """ + if not tosa_spec.is_U55_subset: + return True + + # U55 case, Vela 4.2.0 (25.02 release) + input_shape = node.all_input_nodes[0].meta["val"].shape + + if node.args[1] is None: + # Dim is allowed to be None, which means to sum all dimensions + dim_list = list(range(len(input_shape))) + else: + dim_list = cast(list[int], node.args[1]) + dim_list = [dim % len(input_shape) for dim in dim_list] + + for dim in dim_list: + if not 1 <= input_shape[dim] <= 65536: + self.reporter.report_reject( + node, f"sum needs dims < 65536, got shape {input_shape}" + ) + return False + + # We can't be certain of which dim is the last in memory yet, + # Always go for stricter condition. + pre_R_product = 1.0 + for length in input_shape[:dim]: + pre_R_product *= length + post_R_product = 1.0 + for length in input_shape[dim + 1 :]: + post_R_product *= length + if not 1 <= pre_R_product <= 65536: + self.reporter.report_reject(node, "Failed dim check") + return False + if not 1 <= post_R_product <= 65536: + self.reporter.report_reject(node, "Failed dim check") + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/right_shift_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/right_shift_support.py new file mode 100644 index 0000000..7670ede --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/right_shift_support.py @@ -0,0 +1,52 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for bitwise right-shift in TOSA. + +Provide support checks for ``aten.bitwise_right_shift`` and ``__rshift__`` +targets across integer and float TOSA profiles. + +""" + + +import logging + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + + +@register_tosa_support_check +class RightShiftSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for right-shift operations.""" + + targets = [ + exir_ops.edge.aten.bitwise_right_shift.Tensor, + exir_ops.edge.aten.__rshift__.Scalar, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Emit a warning on U55 subsets where one-off errors may occur. Otherwise + accept all matching targets. + + """ + # TODO MLETORCH-525 Remove warning + if tosa_spec.is_U55_subset: + logger.warning(f"{node.target} may introduce one-off errors.") + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/slice_copy_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/slice_copy_support.py new file mode 100644 index 0000000..77f3e97 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/slice_copy_support.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.slice_copy`` in TOSA. + +Support slicing with unit step only; emit a warning and reject otherwise. + +""" + +import logging + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + + +@register_tosa_support_check +class SliceCopySupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.slice_copy``.""" + + targets = [exir_ops.edge.aten.slice_copy.Tensor] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if the node is supported by TOSA. + + Accept slice_copy when the step is 1 (or unspecified). Warn and reject + non-unit step sizes. + + """ + args = node.args + if len(args) == 5 and (step := args[4]) != 1: + logger.warning(f"{node.target} with step size of {step} not supported.") + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/to_dim_order_copy_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/to_dim_order_copy_support.py new file mode 100644 index 0000000..bd600a4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/to_dim_order_copy_support.py @@ -0,0 +1,200 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``_to_dim_order_copy`` in TOSA. + +Provide dtype-compatibility checks for casting when converting to a specific +dimension order. Supported input/output dtype pairs depend on the active TOSA +profile (integer and/or float). + +""" + +import copy +import logging + +import torch + +import torch.fx as fx + +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + +SupportedTypeDict = dict[torch.dtype, list[torch.dtype]] + + +@register_tosa_support_check +class ToCopySupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``_to_dim_order_copy``. + + Attributes: + SUPPORTED_INT_PROFILE_DTYPES (dict[torch.dtype, list[torch.dtype]]): + Allowed output dtypes for each integer input dtype. + SUPPORTED_FP_PROFILE_DTYPES (dict[torch.dtype, list[torch.dtype]]): + Allowed output dtypes for each floating input dtype. + + """ + + targets = [ + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + @staticmethod + def _merge_supported_types( + dtypes1: SupportedTypeDict, + dtypes2: SupportedTypeDict, + ) -> SupportedTypeDict: + """Return a merged mapping of supported dtype transitions. + + Args: + dtypes1 (dict[torch.dtype, list[torch.dtype]]): Base mapping. + dtypes2 (dict[torch.dtype, list[torch.dtype]]): Mapping to merge in. + + Returns: + dict[torch.dtype, list[torch.dtype]]: Combined mapping. + + """ + merged_dtypes = copy.deepcopy( + dtypes1 + ) # Use deepcopy to avoid unintentionally modifying SUPPORTED_INT_PROFILE_DTYPES + for k, v in dtypes2.items(): + merged_dtypes[k] = merged_dtypes.get(k, []) + v + return merged_dtypes + + SUPPORTED_INT_PROFILE_DTYPES: SupportedTypeDict = { + torch.bool: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int8: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int16: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int32: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int64: [torch.bool, torch.int8, torch.int16, torch.int32], + } + SUPPORTED_FP_PROFILE_DTYPES: SupportedTypeDict = { + torch.int8: [torch.int8, torch.float16, torch.bfloat16, torch.float32], + torch.int16: [torch.int16, torch.float16, torch.bfloat16, torch.float32], + torch.int32: [torch.int32, torch.float16, torch.bfloat16, torch.float32], + # INT64 inputs to casts *should* be ok, since they should be rejected by + # CheckInt64InputsAndOutputs if the cast can't be done AOT. + torch.int64: [ + torch.int8, + torch.int16, + torch.int32, + torch.float16, + torch.bfloat16, + torch.float32, + ], + torch.bfloat16: [ + torch.int8, + torch.int16, + torch.int32, + torch.bfloat16, + torch.float32, + ], + torch.float16: [ + torch.int8, + torch.int16, + torch.int32, + torch.float16, + torch.float32, + ], + torch.float32: [ + torch.float32, + torch.int8, + torch.int16, + torch.int32, + torch.bfloat16, + torch.float16, + torch.float32, + ], + } + SUPPORTED_INT_FP_PROFILE_DTYPES: SupportedTypeDict = { + torch.bool: [torch.float32], + } + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Check FakeTensor metadata, validate input dtype is supported for the + active profile, and ensure the output dtype is allowed for the given + input dtype. + + """ + supported_dtypes: SupportedTypeDict = {} + if tosa_spec.support_integer(): + supported_dtypes = self._merge_supported_types( + self.SUPPORTED_INT_PROFILE_DTYPES, supported_dtypes + ) + if tosa_spec.support_float(): + supported_dtypes = self._merge_supported_types( + self.SUPPORTED_FP_PROFILE_DTYPES, supported_dtypes + ) + if tosa_spec.support_integer() and tosa_spec.support_float(): + supported_dtypes = self._merge_supported_types( + self.SUPPORTED_INT_FP_PROFILE_DTYPES, supported_dtypes + ) + + if len(node.all_input_nodes) != 1: + self.reporter.report_reject( + node, + ( + "Expected exactly one input node, " + f"got {len(node.all_input_nodes)} for {node.target}." + ), + ) + return False + input_val = node.all_input_nodes[0].meta["val"] + if not isinstance(input_val, torch._subclasses.FakeTensor): + self.reporter.report_reject( + node, + ( + "Invalid or missing meta: expected FakeTensor input, got " + f"{type(input_val).__name__} for {node.target}." + ), + ) + return False + + # Check input type + input_dtype = input_val.dtype + if input_dtype not in supported_dtypes: + self.reporter.report_reject( + node, + f"Input dtype {input_val.dtype} is not supported in {node.target}.", + ) + return False + + # Check output type + output_val = node.meta["val"] + if not isinstance(output_val, torch._subclasses.FakeTensor): + self.reporter.report_reject( + node, + ( + "Invalid or missing meta: expected FakeTensor output, got " + f"{type(output_val).__name__} for {node.target}." + ), + ) + return False + if output_val.dtype not in supported_dtypes[input_dtype]: + self.reporter.report_reject( + node, + ( + f"Output dtype {output_val.dtype} is not supported in " + f"{node.target} for input dtype {input_dtype}. " + f"Supported output types: " + f"{', '.join(str(t) for t in supported_dtypes[input_dtype])}" + ), + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_profile_supported_op_lists.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_profile_supported_op_lists.py new file mode 100644 index 0000000..46a92fe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_profile_supported_op_lists.py @@ -0,0 +1,251 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Define TOSA profile support lists for INT and FP. + +Expose static sets of EXIR operator overloads used by the TOSA partitioner to +seed positive support checks for different profiles. + +""" + +import operator +from typing import Final, Set + +import torch + +from executorch.exir.dialects._ops import ops as exir_ops + + +# INT profile: ops supported via native TOSA ops, decompositions/transformations, precompute, TableOps, etc. +# Note that ops supported via pre-quantization decompositions are not included here. +TOSA_PRO_INT_SupportList: Final[Set] = { + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.any.default, + exir_ops.edge.aten.any.dim, + exir_ops.edge.aten.any.dims, + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.bitwise_and.Scalar, + exir_ops.edge.aten.bitwise_or.Scalar, + exir_ops.edge.aten.bitwise_xor.Scalar, + exir_ops.edge.aten.cos.default, + exir_ops.edge.aten.logical_and.default, + exir_ops.edge.aten.logical_or.default, + exir_ops.edge.aten.logical_xor.default, + exir_ops.edge.aten.logical_not.default, + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.clamp.Tensor, + exir_ops.edge.aten.cumsum.default, + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.permute_copy.default, + exir_ops.edge.aten.hardsigmoid.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.hardswish.default, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.erf.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.expm1.default, + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.log1p.default, + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.split_with_sizes_copy.default, + exir_ops.edge.aten.split_copy.Tensor, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.sigmoid.default, + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.repeat.default, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.remainder.Tensor, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.select_copy.int, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.tanh.default, + exir_ops.edge.aten.upsample_bilinear2d.vec, + exir_ops.edge.aten.upsample_nearest2d.vec, + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.unsqueeze_copy.default, + exir_ops.edge.aten.squeeze_copy.dims, + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.pow.Tensor_Tensor, + operator.getitem, + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.quantize_per_channel.default, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.dequantize_per_channel.default, + exir_ops.edge.aten.constant_pad_nd.default, + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + exir_ops.edge.aten.eye.default, + exir_ops.edge.aten.linspace.default, + exir_ops.edge.aten.bitwise_left_shift.Tensor, + exir_ops.edge.aten.__lshift__.Scalar, + torch.ops.aten.scalar_tensor.default, + exir_ops.edge.aten.gelu.default, + exir_ops.edge.aten.alias_copy.default, + exir_ops.edge.aten.sin.default, + exir_ops.edge.aten.sinh.default, + exir_ops.edge.aten.atan.default, + exir_ops.edge.aten.acosh.default, + exir_ops.edge.aten._adaptive_avg_pool2d.default, + exir_ops.edge.aten.sign.default, + exir_ops.edge.aten.asin.default, + exir_ops.edge.aten.atanh.default, + exir_ops.edge.aten.masked_fill.Scalar, + exir_ops.edge.aten.asinh.default, + exir_ops.edge.aten.cosh.default, + exir_ops.edge.aten.acos.default, + exir_ops.edge.aten.elu.default, + exir_ops.edge.aten.bitwise_not.default, + exir_ops.edge.aten.copy.default, + exir_ops.edge.aten.tan.default, +} + + +# FP profile: ops supported via native TOSA ops, decompositions/transformations, precompute, etc. +TOSA_PRO_FP_SupportList: Final[Set] = { + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.any.default, + exir_ops.edge.aten.any.dim, + exir_ops.edge.aten.any.dims, + exir_ops.edge.aten.logical_and.default, + exir_ops.edge.aten.logical_or.default, + exir_ops.edge.aten.logical_xor.default, + exir_ops.edge.aten.logical_not.default, + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.clamp.Tensor, + exir_ops.edge.aten.cos.default, + exir_ops.edge.aten.cumsum.default, + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.permute_copy.default, + exir_ops.edge.aten.hardsigmoid.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.hardswish.default, + exir_ops.edge.aten.div.Tensor, + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.erf.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.expm1.default, + exir_ops.edge.aten.log1p.default, + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.split_with_sizes_copy.default, + exir_ops.edge.aten.split_copy.Tensor, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.ne.Tensor, + exir_ops.edge.aten.ne.Scalar, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.div.Scalar, + exir_ops.edge.aten._native_batch_norm_legit_no_training.default, + exir_ops.edge.aten.native_layer_norm.default, + exir_ops.edge.aten.native_group_norm.default, + exir_ops.edge.aten.sigmoid.default, + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.mean.default, + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.repeat.default, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.remainder.Scalar, + exir_ops.edge.aten.remainder.Tensor, + exir_ops.edge.aten.leaky_relu.default, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.round.default, + exir_ops.edge.aten._softmax.default, + exir_ops.edge.aten.select_copy.int, + exir_ops.edge.aten._log_softmax.default, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.tanh.default, + exir_ops.edge.aten.upsample_bilinear2d.vec, + exir_ops.edge.aten.upsample_nearest2d.vec, + exir_ops.edge.aten.var.correction, + exir_ops.edge.aten.var.dim, + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.unsqueeze_copy.default, + exir_ops.edge.aten.squeeze_copy.dims, + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.pow.Tensor_Tensor, + operator.getitem, + exir_ops.edge.aten.constant_pad_nd.default, + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + exir_ops.edge.aten.eye.default, + exir_ops.edge.aten.linspace.default, + exir_ops.edge.aten.bitwise_left_shift.Tensor, + exir_ops.edge.aten.__lshift__.Scalar, + torch.ops.aten.scalar_tensor.default, + exir_ops.edge.aten.gelu.default, + exir_ops.edge.aten.alias_copy.default, + exir_ops.edge.aten.sin.default, + exir_ops.edge.aten.sinh.default, + exir_ops.edge.aten.atan.default, + exir_ops.edge.aten.acosh.default, + exir_ops.edge.aten._adaptive_avg_pool2d.default, + exir_ops.edge.aten.sign.default, + exir_ops.edge.aten.asin.default, + exir_ops.edge.aten.atanh.default, + exir_ops.edge.aten.addmm.default, + exir_ops.edge.aten.masked_fill.Scalar, + exir_ops.edge.aten.asinh.default, + exir_ops.edge.aten.cosh.default, + exir_ops.edge.aten.glu.default, + exir_ops.edge.aten.logit.default, + exir_ops.edge.aten.acos.default, + exir_ops.edge.aten.elu.default, + exir_ops.edge.aten.copy.default, + exir_ops.edge.aten.floor_divide.default, + exir_ops.edge.aten.tan.default, +} + + +__all__ = [ + "TOSA_PRO_INT_SupportList", + "TOSA_PRO_FP_SupportList", +] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_supported_operators.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_supported_operators.py new file mode 100644 index 0000000..9240f14 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/tosa_supported_operators.py @@ -0,0 +1,748 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide operator-support checks and registries for TOSA delegation. + +Define a base check class, a registry/dispatcher, and several generic checks +used by the TOSA partitioner to decide if FX nodes are eligible for delegation. + +""" + + +import itertools +import operator +import typing +from typing import final, Optional, Sequence, Type + +import torch +import torch.fx as fx + +from executorch.backends.arm._passes.arm_pass_utils import ( + get_first_fake_tensor, + is_submodule_node, +) +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.fuse_quantized_activation_pass import ( + FuseQuantizedActivationPass, +) +from executorch.backends.arm._passes.insert_table_ops import TableOps +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.constants import DQ_OPS, MAX_RANK, Q_OPS +from executorch.backends.arm.operator_support.control_flow_support import ( + ControlFlowOpSupported, + ControlFlowSubmoduleSupported, +) +from executorch.backends.arm.operator_support.ethos_u55_support import ( + EthosU55CastCheck, + EthosU55DtypeSupport, + EthosU55NotSupported, + EthosU55TransposeCheck, + EthosU55ViewCheck, +) +from executorch.backends.arm.operator_support.tosa_profile_supported_op_lists import ( + TOSA_PRO_FP_SupportList, + TOSA_PRO_INT_SupportList, +) +from executorch.backends.arm.tosa.specification import ( + TosaSpecification, + TosaSpecMapping, +) +from executorch.exir import ExportedProgram +from executorch.exir.backend.utils import WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops + +from torch._subclasses.fake_tensor import FakeTensor +from torch.export.graph_signature import InputKind +from torch.fx.passes.operator_support import any_chain, chain, OperatorSupportBase +from torch.fx.passes.utils.source_matcher_utils import get_source_partitions + + +class SupportedTOSAOperatorCheck(OperatorSupportBase): + """Provide a base operator-support check for TOSA lowering. + + Subclasses should implement :py:meth:`is_node_tosa_supported` and declare + the class attributes below to indicate what they support. + + Attributes: + targets (list[OpOverload]): Operator overloads supported by this + check. + tosa_specs (list[TosaSpecification]): TOSA specs where the check is + applicable. + + """ + + def __init__(self, tosa_spec: TosaSpecification, reporter: WhyNoPartitionReporter): + """Initialize the check with a TOSA spec and reporter. + + Args: + tosa_spec (TosaSpecification): Active TOSA specification. + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + self.tosa_spec = tosa_spec + self.reporter = reporter + + # Class attributes populated by subclasses + tosa_specs: list[TosaSpecification] = [] + targets: list[str] = [] + + @final + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node matches targets and subclass-specific checks. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported program + modules. + node (fx.Node): Node to evaluate. + + Returns: + bool: True if both the target and TOSA-specific checks pass. + + """ + if node.target not in self.targets: + return False + return self.is_node_tosa_supported(node, self.tosa_spec) + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Check if the node is lowerable under the given TOSA spec. + + Args: + node (fx.Node): FX node to check. + tosa_spec (TosaSpecification): Active TOSA specification. + + Returns: + bool: True if supported; otherwise, False. + + """ + raise NotImplementedError("SupportedTOSAOperatorCheck must be extended.") + + +# container for all SupportedTosaOperatorCheck classes +_tosa_spec_support: TosaSpecMapping[Type[SupportedTOSAOperatorCheck]] = ( + TosaSpecMapping() +) + + +def register_tosa_support_check(checker: Type[SupportedTOSAOperatorCheck]): + """Register an operator-support checker for one or more TOSA specs. + + Decorate subclasses of :py:class:`SupportedTOSAOperatorCheck` so they are + picked up by the factory and partitioner for the specs declared in their + ``tosa_specs`` class attribute. + + Args: + checker (Type[SupportedTOSAOperatorCheck]): Checker class to register. + + """ + for tosa_spec in checker.tosa_specs: + _tosa_spec_support.add(tosa_spec, checker) + return checker + + +def _is_integer_dtype(dtype: torch.dtype) -> bool: + return not dtype.is_floating_point and not dtype.is_complex + + +def _is_quantized_constant(node: torch.fx.Node) -> bool: + if node.target not in ( + exir_ops.edge.aten.full_like.default, + *ComputeConstantOpsAOTPass.targeted_ops, + ): + return False + + users = tuple(node.users) + if users and all(user.target in Q_OPS for user in users): + # The node feeds directly into only quantized ops. + return True + + for user in users: + if user.target == exir_ops.edge.dim_order_ops._to_dim_order_copy.default: + dim_order_dtype = get_first_fake_tensor(user).dtype + if not _is_integer_dtype(dim_order_dtype): + return False + else: + return False + + return len(users) > 0 + + +def is_quantized(node: torch.fx.Node) -> bool: + """Checks if the node is quantized. + + A node is considered quantized if any of the following is true: + - Its output dtype is not floating point or complex => integer + - It is an op that produces a constant that in turn feeds only quantized users + - It has been marked as quantized in the ArmAnnotationInfo custom meta. + + Args: + node (torch.fx.Node): The FX node to check. + + Returns: + bool: True if the node is quantized, False otherwise. + """ + + try: + node_dtype = get_first_fake_tensor(node).dtype + # Integer-like dtype implies the node is already quantized as long + # as inputs are not floating-point. + if _is_integer_dtype(node_dtype): + input_nodes = node.all_input_nodes + input_nodes_dtypes = [ + get_first_fake_tensor(input_node).dtype for input_node in input_nodes + ] + if all( + _is_integer_dtype(input_node_dtype) + for input_node_dtype in input_nodes_dtypes + ): + return True + + except TypeError: + # Could not determine dtype, fall back to other checks. + pass + + # Nodes introduced during lowering that exclusively feed quantized users. + if _is_quantized_constant(node): + return True + + # Finally, fall back to the explicit annotation emitted by Arm passes. + custom_meta = node.meta.get("custom", {}) + if ArmAnnotationInfo.CUSTOM_META_KEY in custom_meta: + return custom_meta[ArmAnnotationInfo.CUSTOM_META_KEY]["quantized"] + + return False + + +def get_registered_tosa_support_checks( + tosa_spec: TosaSpecification, +) -> list[Type[SupportedTOSAOperatorCheck]]: + """Get all registered operator-support checkers for a given spec. + + Args: + tosa_spec (TosaSpecification): TOSA spec to query. + + Returns: + list[Type[SupportedTOSAOperatorCheck]]: Registered checker classes. + + """ + checks = _tosa_spec_support.get(tosa_spec) + if not checks: + raise RuntimeError( + f"TOSA specification not valid: {tosa_spec} not in {list(_tosa_spec_support._mapping.keys())}" + ) + return checks + + +def tosa_support_factory( + tosa_spec: TosaSpecification, + exported_program: ExportedProgram, + reporter: WhyNoPartitionReporter, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, +) -> OperatorSupportBase: + """Create an OperatorSupport composite for a TOSA spec. + + Combine profile-specific positive checks, registered operator checks, and + negative checks into a single :py:class:`OperatorSupportBase` chain. + + Args: + tosa_spec (TosaSpecification): Active TOSA specification. + exported_program (ExportedProgram): Program context for checks. + reporter (WhyNoPartitionReporter): Reporter for rejections. + additional_checks (Optional[Sequence[OperatorSupportBase]]): Extra + negative checks to apply. + + Returns: + OperatorSupportBase: Composite checker for the given spec. + + """ + # Postive checks: Add nodes to partitioning + positive_checks: list[OperatorSupportBase] = [ + ControlFlowSubmoduleSupported(exported_program, tosa_spec, reporter), + ControlFlowOpSupported(exported_program, tosa_spec, reporter), + ] + + if tosa_spec.support_integer() and tosa_spec.support_float(): + positive_checks.append(TOSAProINTFPSupportList()) + elif tosa_spec.support_integer(): + positive_checks.append(TOSAProINTSupportList()) + elif tosa_spec.support_float(): + positive_checks.append(TOSAProFPSupportList()) + # TODO: Refactor to use TOSAProSupportLists + negtive checks + positive_checks += [ + check(tosa_spec, reporter) + for check in get_registered_tosa_support_checks(tosa_spec) + ] + + # Negative checks: Remove nodes from partitioning + negative_checks: list[OperatorSupportBase] = [ + CheckInt64InputsAndOutputs(exported_program, reporter), + CheckFloat64Inputs(exported_program, reporter), + RankCheck(reporter, max_rank=MAX_RANK), + *[ + reporter.wrap_check(check, f"Rejected by {check.__class__.__name__}") + for check in (additional_checks if additional_checks else []) + ], + ] + + if not tosa_spec.support_float(): + negative_checks.append(CheckArmQuantized(reporter)) + negative_checks.append(CheckProperQuantization(reporter)) + if tosa_spec.is_U55_subset: + negative_checks.append(EthosU55NotSupported(reporter)) + negative_checks.append(EthosU55DtypeSupport(reporter)) + negative_checks.append(EthosU55TransposeCheck(reporter)) + negative_checks.append(EthosU55ViewCheck(reporter)) + negative_checks.append(EthosU55CastCheck(reporter)) + + return chain( + reporter.wrap_check( + any_chain(*positive_checks), + "Not included in BaseTOSASupportList or a registered tosa_support_check", + ), + *negative_checks, + ) + + +class TOSAProINTSupportList(OperatorSupportBase): + """Provide the INT profile support list for TOSA. + + TOSA_PRO_INT_SupportList enumerates ops supported in the INT profile via + native TOSA ops, decompositions, pre-compute steps, or TableOps. + + Note: + Ops supported via pre-quantization decompositions are not included + here. + + """ + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node is in the INT profile support list.""" + return node.op == "call_function" and node.target in TOSA_PRO_INT_SupportList + + +class TOSAProFPSupportList(OperatorSupportBase): + """Provide the FP profile support list for TOSA. + + Includes ops supported natively, via decomposition/transformation, and pre- + compute. + + """ + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node is in the FP profile support list.""" + return node.op == "call_function" and node.target in TOSA_PRO_FP_SupportList + + +class TOSAProINTFPSupportList(OperatorSupportBase): + """ + TOSA_PRO_INT_FP_SupportList: + Ops supported in INT+FP profile via native TOSA ops, decomposition/transformation, pre-compute, or TableOp. + """ + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + if node.op != "call_function": + return False + + # Select list based on whether the node is quantized. + if is_quantized(node) or node.target in (*Q_OPS, *DQ_OPS): + support_list = TOSA_PRO_INT_SupportList + else: + support_list = TOSA_PRO_FP_SupportList + + return node.target in support_list + + +class CheckArmQuantized(OperatorSupportBase): + """ + Check if the node was marked as quantized in the Arm backend. + This is used to ensure that nodes that were quantized in the Arm backend + are only partitioned if they are supported by the TOSA backend. + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + self.reporter = reporter + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + + if node.target in (*DQ_OPS, *Q_OPS): + return True + + if not is_quantized(node): + self.reporter.report_reject( + node, "Node was not marked as quantized in the Arm backend." + ) + return False + return True + + +class CheckProperQuantization(OperatorSupportBase): + """Ensure targeted nodes are properly quantized. + + Verify that a pair of quantize/dequantize nodes surrounds targeted ops so + rescaling and table operators behave correctly. + + """ + + targeted_ops = ( + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.avg_pool2d.default, + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.convolution.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.max_pool2d_with_indices.default, + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.upsample_bilinear2d.vec, + exir_ops.edge.aten.upsample_nearest2d.vec, + torch.ops.aten.scalar_tensor.default, + exir_ops.edge.aten.mean.dim, + *TableOps.included_ops(), + ) + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter.""" + self.reporter = reporter + + def _is_matmul_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ): + """Check quantization for decomposed matmul partitions. + + Handles an edge case where the quantized pipeline + `dq -> torch.matmul/operator.matmul -> q` decomposes into + `dq -> expand -> view -> aten.mm -> view -> q`. + + Args: + submodules (Mapping[str, torch.nn.Module]): Map of child modules to + inspect for matmul partitions. + node (fx.Node): Node that should belong to a quantized matmul + partition. + + Returns: + bool: True if the matched partition uses quantized inputs and + outputs. + + """ + for graph_module in submodules.values(): + graph_module = typing.cast(fx.GraphModule, graph_module) + matmul_partitions_map = get_source_partitions( + graph_module.graph, + [ + torch.matmul, + operator.matmul, + ], + None, + ) + matmul_partitions = list( + itertools.chain.from_iterable(matmul_partitions_map.values()) + ) + matched_partition = None + for partition in matmul_partitions: + if node in partition.nodes: + matched_partition = partition + if matched_partition is not None: + input_quantized = all( + input_node.target in DQ_OPS + for input_node in matched_partition.input_nodes + ) + if not input_quantized: + self.reporter.report_reject( + node, "One or more matmul inputs were not quantized." + ) + return False + output_quantized = all( + output_node_user.target in Q_OPS + for output_node_user in matched_partition.output_nodes[0].users + ) + if not output_quantized: + self.reporter.report_reject( + node, "One or more matmul outputs were not quantized." + ) + return False + else: + self.reporter.report_reject( + node, "Node did not match any matmul source partition." + ) + return False + + return True + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node passes constant-cast and multi-output checks. + + Ensures decomposition-specific matmul partitions keep quantized inputs + and outputs. + + """ + output_quantized = False + input_quantized = False + if node.target not in self.targeted_ops: + return True + elif node.target in ( + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.mm.default, + ): + source_fn_stack: tuple[typing.Any] = node.meta.get("source_fn_stack", []) + if len(source_fn_stack) > 0: + if source_fn_stack[-1][1] in (torch.matmul, operator.matmul): + return self._is_matmul_node_supported(submodules, node) + + elif node.target in (exir_ops.edge.aten.max_pool2d_with_indices.default,): + users = node.users + output_quantized = all( + user.target == operator.getitem + and all(user_user.target in Q_OPS for user_user in user.users) + for user in users + ) + elif FuseQuantizedActivationPass._is_fuseable_input(node): + users = node.users + output_quantized = all( + FuseQuantizedActivationPass._is_fuseable_quantized_activation(user) + for user in users + ) + elif FuseQuantizedActivationPass._is_fuseable_quantized_activation(node): + input_node = node.all_input_nodes[0] + input_quantized = FuseQuantizedActivationPass._is_fuseable_input(input_node) + + input_quantized = input_quantized or all( + (input_node.target in DQ_OPS) + or _is_integer_dtype(get_first_fake_tensor(input_node).dtype) + for input_node in node.all_input_nodes + ) + + if not input_quantized: + self.reporter.report_reject(node, "One or more inputs were not quantized.") + return False + + all_q_users = all((output_node.target in Q_OPS) for output_node in node.users) + output_dtype = get_first_fake_tensor(node).dtype + output_quantized = ( + output_quantized or all_q_users or _is_integer_dtype(output_dtype) + ) + + if not output_quantized: + self.reporter.report_reject(node, "One or more outputs were not quantized.") + return False + return True + + +class CheckInt64InputsAndOutputs(OperatorSupportBase): + """Reject general int64 tensors while allowing safe exceptions. + + Exceptions are: + - Nodes with contant int64 output within int32 range that are cast away + from int64 by all users. + - Int64 output where all users are getitem nodes with non-int64 outputs. + In this case there are multiple outputs and the int64 output is unused. + - Nodes where all inputs are int64 constant placeholders or constant ops + that fulfill the above exceptions. + + """ + + def __init__( + self, exported_program: ExportedProgram, reporter: WhyNoPartitionReporter + ): + """Initialize the check with program context and reporter.""" + self.input_names = [ + spec.arg.name + for spec in exported_program.graph_signature.input_specs + if spec.kind == InputKind.USER_INPUT + ] + self.reporter = reporter + self.int32_min = torch.iinfo(torch.int32).min + self.int32_max = torch.iinfo(torch.int32).max + super().__init__() + + def inside_int32_bounds(self, node: torch.fx.Node) -> bool: + """Node is assumed to be call_function with int64 output.""" + if isinstance(node.target, str): + return False + data = node.target(*node.args, **node.kwargs) + min_val, max_val = int(torch.min(data)), int(torch.max(data)) + return min_val >= self.int32_min and max_val <= self.int32_max + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True when int64 use is absent or safe per exceptions.""" + if is_submodule_node(node): + return True + vals = node.meta["val"] + tensor_list = vals if isinstance(vals, (list, tuple)) else [vals] + + any_int64 = any(tensor.dtype == torch.int64 for tensor in tensor_list) + # Don't partition nodes with int64 output... + if any_int64: + # ... Except for constant ops that are directly cast to something non-int64. + # This could be an explicit cast, or something like a less than that outputs a different dtype than the input. + users_output_non_int64 = all( + get_first_fake_tensor(output_node).dtype != torch.int64 + for output_node in node.users + ) + if ( + node.target in ComputeConstantOpsAOTPass.targeted_ops + and users_output_non_int64 + ): + if not self.inside_int32_bounds(node): + self.reporter.report_reject( + node, "Constant node outside int32 range." + ) + return False + # Will never have input nodes, safe to return True + return True + + # ... Or ops with multiple outputs where only non-int64 are used. + users_are_getitem = all( + user.target == operator.getitem for user in node.users + ) + if users_are_getitem and users_output_non_int64: + # Passed output check, go to input check. + pass + else: + self.reporter.report_reject( + node, "Non-constant node with int64 output." + ) + return False + + # Ops with int64 inputs are only partitioned if input nodes are constant and will be partitioned. + # If it is not partitioned, the partition will get an int64 input and fail. + for input_node in ( + input_node + for input_node in node.all_input_nodes + if input_node.op != "get_attr" + ): + tensor_in = get_first_fake_tensor(input_node) + if tensor_in.dtype != torch.int64: + continue + # Constant placeholder + if ( + input_node.op != "call_function" + and input_node.name not in self.input_names + ): + continue + # Constant operator + if input_node.op == "call_function": + if input_node.target in ComputeConstantOpsAOTPass.targeted_ops: + # This is not perfect since the input_node can still be rejected by other checks but + # this should cover the majority of cases. + if self.is_node_supported({}, input_node): + continue + self.reporter.report_reject( + node, f"Non-constant int64 input {input_node.name}" + ) + return False + + return True + + +class CheckFloat64Inputs(OperatorSupportBase): + """Reject nodes with float64 inputs. + + Useful as a negative check for specs that do not allow float64. + + """ + + def __init__( + self, exported_program: ExportedProgram, reporter: WhyNoPartitionReporter + ): + """Initialize the check with program context and reporter.""" + self.reporter = reporter + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if no float64 inputs are present.""" + if is_submodule_node(node): + return True + for input_node in ( + input_node + for input_node in node.all_input_nodes + if input_node.op != "get_attr" + ): + tensor = get_first_fake_tensor(input_node) + if tensor.dtype == torch.float64: + self.reporter.report_reject( + node, + f"Had float64 input {input_node.name} that couldn't be handled.", + ) + return False + return True + + +class RankCheck(OperatorSupportBase): + """Reject nodes with rank greater than ``max_rank``.""" + + def __init__(self, reporter: WhyNoPartitionReporter, max_rank: int): + """Initialize the check with a reporter and maximum rank.""" + self.reporter = reporter + self.max_rank = max_rank + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if input/output tensor ranks are within the limit.""" + if is_submodule_node(node): + return True + input_nodes = ( + input_node + for input_node in node.all_input_nodes + if input_node.op != "get_attr" + ) + # check if any input node has an unsupported rank + for input_node in input_nodes: + input_node_shape = get_first_fake_tensor(input_node).shape + if len(input_node_shape) > self.max_rank: + self.reporter.report_reject( + node, + f"{node.name} has input_node {input_node.name} with shape {input_node_shape}, " + f"rank {len(input_node_shape)} which is unsupported. " + f"Max supported rank is {self.max_rank}.", + ) + return False + + meta_val = node.meta["val"] + if isinstance( + meta_val, (Sequence, torch.fx.immutable_collections.immutable_list) + ): + for val in meta_val: + if isinstance(val, FakeTensor): + if len(val.shape) > self.max_rank: + self.reporter.report_reject( + node, + f"{node.name} has a shape {val.shape}, rank {len(val.shape)} which is unsupported." + f"Max supported rank is {self.max_rank}.", + ) + return False + elif isinstance(meta_val, FakeTensor): + if len(meta_val.shape) > self.max_rank: + self.reporter.report_reject( + node, + f"{node.name} has shape {meta_val.shape}, rank={len(meta_val.shape)} which is unsupported." + f"Max supported rank is {self.max_rank}.", + ) + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/where_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/where_support.py new file mode 100644 index 0000000..2ec7c30 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operator_support/where_support.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch + +import torch.fx as fx +from executorch.backends.arm.constants import DQ_OPS +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class WhereSupported(SupportedTOSAOperatorCheck): + targets = [exir_ops.edge.aten.where.self] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + + if len(node.all_input_nodes) != 3: + self.reporter.report_reject( + node, + ( + "Expected exactly three input nodes, " + f"got {len(node.all_input_nodes)} for {node.target}." + ), + ) + return False + + condition, x, y = node.all_input_nodes + if condition.meta["val"].dtype != torch.bool: + self.reporter.report_reject( + node, + f"Type of condition in {node.target} is not torch.bool", + ) + return False + + x_dtype, y_dtype = x.meta["val"].dtype, y.meta["val"].dtype + if tosa_spec.support_float(): + if x_dtype in (torch.bool, torch.float16, torch.float32) and y_dtype in ( + torch.bool, + torch.float16, + torch.float32, + ): + return True + + if tosa_spec.support_integer(): + if ( + x_dtype in (torch.bool, torch.int8, torch.int16, torch.int32) + or (x_dtype == torch.float32 and x.target in DQ_OPS) + ) and ( + y_dtype in (torch.bool, torch.int8, torch.int16, torch.int32) + or (y_dtype == torch.float32 and y.target in DQ_OPS) + ): + return True + + self.reporter.report_reject( + node, + ( + f"Tensor x dtype {x_dtype} and/or tensor y dtype {y_dtype} is not supported in {node.target} " + f"for tosa specification {tosa_spec}" + ), + ) + + return False diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/TARGETS new file mode 100644 index 0000000..38eb9e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/TARGETS @@ -0,0 +1,40 @@ +# @noautodeps +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "node_visitor", + srcs = ["node_visitor.py"], + deps = [ + "//executorch/backends/arm/debug:schema", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm/tosa:tosa", + ], +) + +runtime.python_library( + name = "operator_validation_utils", + srcs = ["operator_validation_utils.py"], +) + +runtime.python_library( + name = "ops", + srcs = glob(["op_*.py", "ops_*.py"]), + deps = [ + "fbsource//third-party/tosa_tools:tosa", + ":node_visitor", + ":operator_validation_utils", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm/tosa:utils", + "//executorch/backends/arm/_passes:passes", + "//executorch/exir:lib", + ], +) + +runtime.python_library( + name = "lib", + srcs = ["__init__.py"], + deps = [ + ":node_visitor", + ":ops", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/__init__.py new file mode 100644 index 0000000..15be109 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/__init__.py @@ -0,0 +1,71 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Import and register Arm TOSA operator visitors. + +Importing this package loads all visitor modules so their classes can be +registered via decorators and discovered at runtime. + +""" + + +from . import ( # noqa + node_visitor, + op_abs, + op_add, + op_amax, + op_amin, + op_any, + op_avg_pool2d, + op_bitwise_not, + op_cat, + op_ceil, + op_clamp, + op_cond_if, + op_constant_pad_nd, + op_cos, + op_eq, + op_erf, + op_exp, + op_floor, + op_ge, + op_gt, + op_index_select, + op_index_tensor, + op_le, + op_log, + op_logical_not, + op_lt, + op_max_pool2d, + op_maximum, + op_minimum, + op_mul, + op_neg, + op_permute, + op_pow, + op_reciprocal, + op_repeat, + op_rshift_tensor, + op_rsqrt, + op_sigmoid, + op_sin, + op_slice, + op_sub, + op_sum, + op_tanh, + op_to_dim_order_copy, + op_tosa_conv2d, + op_tosa_conv3d, + op_tosa_depthwise_conv2d, + op_tosa_matmul, + op_tosa_rescale, + op_tosa_resize, + op_tosa_table, + op_tosa_transpose, + op_view, + op_where, + op_while, + ops_binary, + ops_identity, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/node_visitor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/node_visitor.py new file mode 100644 index 0000000..68120d1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/node_visitor.py @@ -0,0 +1,177 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide utilities to register and apply TOSA node visitors. + +Use this module to construct and serialize TOSA operators from FX nodes. +- Define the NodeVisitor base class and registry +- Register concrete visitors per TOSA specification + +""" + +import json + +import logging +from typing import Any, Dict, List, Optional + +import torch +import tosa_serializer as ts + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.debug.schema import DebugHook +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import ( + TosaSpecification, + TosaSpecMapping, +) +from torch.export import ExportedProgram + +logger = logging.getLogger(__name__) + + +class NodeVisitor: + """Provide a visitor pattern to lower edge IR to TOSA. + + Attributes: + _exported_program (torch.export.ExportedProgram): Source program being lowered. + tosa_spec (TosaSpecification): Active TOSA specification for lowering. + debug_hook (Optional[DebugHook]): Optional hook for debug metadata. + + """ + + # Add the currently supported node_visitor specs as default. + # This should be overriden in the NodeVisitor subclasses to target + # a specific TOSA version. + # When all node_visitors has been refactored to target a specific + # version, this list should be removed. + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__( + self, + exported_program: ExportedProgram, + tosa_spec: TosaSpecification, + debug_hook: Optional[DebugHook] = None, + ): + self._exported_program = exported_program + self.tosa_spec = tosa_spec + self.debug_hook = debug_hook + + def _serialize_operator( + self, + node: torch.fx.Node, + tosa_graph: Any, + tosa_op: ts.Op, + inputs: List[str], + outputs: List[str], + attributes: Optional[Any] = None, + ) -> None: + """Serialize a TOSA operator into the graph. + + When a ``DebugHook`` is active, attach location metadata (in JSON) to + the operator for traceability. + + Args: + node (torch.fx.Node): Source FX node being lowered. + tosa_graph: Target TOSA serializer/graph object. + tosa_op: TOSA operator enum value to emit. + inputs (List[str]): Names of input tensors. + outputs (List[str]): Names of output tensors. + attributes (Optional[Any]): Optional TOSA attribute object. + + Returns: + None: Mutates ``tosa_graph`` in place. + + """ + op_location = None + if self.debug_hook: + debug_info = self.debug_hook.add( + node, + tosa_op=outputs[0], + tosa_op_id=tosa_op, + ) + + if self.debug_hook.mode == ArmCompileSpec.DebugMode.TOSA: + op_location = json.dumps(debug_info.to_dict()) + + tosa_graph.addOperator( + tosa_op, + inputs=inputs, + outputs=outputs, + attributes=attributes, + location=op_location, + ) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """Define a TOSA operator node. + + Args: + node (torch.fx.Node): FX node being lowered. + tosa_graph (serializer.tosa_serializer.TosaSerializer): Target TOSA graph. + inputs (List[TosaArg]): Input tensor arguments. + output (TosaArg): Output tensor descriptor. + + Returns: + None: Mutates ``tosa_graph`` in place. + + Raises: + ValueError: If input count or dtypes are invalid. + + """ + raise NotImplementedError("NodeVisitor must be extended.") + + +# container for all node visitors +_node_visitor_tuples: TosaSpecMapping[tuple] = TosaSpecMapping() + + +def register_node_visitor(visitor): + """Register a concrete ``NodeVisitor`` class for its TOSA specs.""" + for tosa_spec in visitor.tosa_specs: + # Try to get the tuple to make sure it doesn't exist + visitor_tuple = (visitor.target, visitor) + try: + tuples = _node_visitor_tuples.get(tosa_spec) + except KeyError: + tuples = [] + + if visitor_tuple in tuples: + raise RuntimeError( + f"Visitor for target {visitor.target} already registered for TOSA spec {tosa_spec}" + ) + _node_visitor_tuples.add(tosa_spec, visitor_tuple) + return visitor + + +def get_node_visitors(*args) -> Dict[str, NodeVisitor]: + """Return a mapping from target names to visitor instances for a spec.""" + node_visitors: Dict[str, NodeVisitor] = {} + tosa_spec: TosaSpecification | None = None + for arg in args: + if isinstance(arg, TosaSpecification): + tosa_spec = arg + break + + if tosa_spec is None: + raise RuntimeError("No TOSA specification supplied.") + + # Use the mapping to get the dict for this spec (handles combined specs) + for node_visitor_tuple in _node_visitor_tuples.get(tosa_spec): + target, visitor = node_visitor_tuple + if target in node_visitors and node_visitors[target].__class__ != visitor: + logger.warning( + f"Target {target} already has visitor class {node_visitors[target].__class__.__name__} registered, overwriting with class: {visitor.__name__}" + ) + node_visitors[target] = visitor(*args) + + return node_visitors diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_abs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_abs.py new file mode 100644 index 0000000..b5a5813 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_abs.py @@ -0,0 +1,59 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class AbsVisitor(NodeVisitor): + target = "aten.abs.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.AbsAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.ABS, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_add.py new file mode 100644 index 0000000..6c1ff2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_add.py @@ -0,0 +1,60 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class AddVisitor(NodeVisitor): + target = "aten.add.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.AddAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.ADD, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amax.py new file mode 100644 index 0000000..e4824fb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amax.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class MaxVisitor(NodeVisitor): + target = "aten.amax.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + input = inputs[0] + dim = inputs[1].number + + if dim < 0: + tensor = get_first_fake_tensor(node) + rank = len(tensor.size()) + dim = rank + dim + + keep_dims = inputs[2].number + if not keep_dims: + raise RuntimeError( + "TOSA only supports keepdims == True; Did you run the convert_minmax pass?" + ) + + attr = ts.TosaSerializerAttribute() + nan_mode = ts.NanPropagationMode.PROPAGATE + attr.ReduceMaxAttribute(axis=input.dim_order.index(dim), nan_mode=nan_mode) + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_MAX, + [input.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amin.py new file mode 100644 index 0000000..34d4d37 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_amin.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class MinVisitor(NodeVisitor): + target = "aten.amin.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + input = inputs[0] + dim = inputs[1].number + + if dim < 0: + tensor = get_first_fake_tensor(node) + rank = len(tensor.size()) + dim = rank + dim + + keep_dims = inputs[2].number + if not keep_dims: + raise RuntimeError( + "TOSA only supports keepdims == True; Did you run the convert_minmax pass?" + ) + + attr = ts.TosaSerializerAttribute() + attr.ReduceMinAttribute( + axis=input.dim_order.index(dim), nan_mode=ts.NanPropagationMode.PROPAGATE + ) + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_MIN, + [input.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_any.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_any.py new file mode 100644 index 0000000..2a850c0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_any.py @@ -0,0 +1,61 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( # type: ignore + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) + +from executorch.backends.arm.tosa.mapping import TosaArg # type: ignore +from torch.fx import Node + + +@register_node_visitor +class AnyVisitor(NodeVisitor): + target = "aten.any.dim" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, [inputs[0], output], ts.DType.BOOL, output.tosa_spec + ) + + input_shape = list(inputs[0].shape) + dim = cast(int, inputs[1].number) % len( + input_shape + ) # process the negative index + keep_dim = cast(bool, inputs[2].number if len(inputs) > 2 else False) + if not keep_dim: + raise ValueError("This case should be handled by DecomposeAnyPass") + + attr = ts.TosaSerializerAttribute() + attr.ReduceAnyAttribute(inputs[0].dim_order.index(dim)) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_ANY, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_avg_pool2d.py new file mode 100644 index 0000000..ec9d429 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_avg_pool2d.py @@ -0,0 +1,142 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class AvgPool2dVisitor(NodeVisitor): + target = "aten.avg_pool2d.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def _build_generic_avgpool2d( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + input_zp: int, + output_zp: int, + accumulator_type: Any, + ) -> None: + + input_tensor = inputs[0] + kernel_size_list = inputs[1].special + stride_size_list = inputs[2].special + + if len(inputs) > 4: + ceil_mode = bool(inputs[4].number) + else: + ceil_mode = False + + try: + pad_size_list = inputs[3].special + pad_size_list = [ + pad_size_list[0], + pad_size_list[0], + pad_size_list[1], + pad_size_list[1], + ] + except IndexError: + pad_size_list = [0, 0, 0, 0] + + # Adjust the padding as necessary + pad_size_list[1] = adjust_pooling_pad_if_needed( + input_tensor.shape[2], + kernel_size_list[0], + stride_size_list[0], + pad_size_list[1], + ceil_mode, + ) + pad_size_list[3] = adjust_pooling_pad_if_needed( + input_tensor.shape[3], + kernel_size_list[1], + stride_size_list[1], + pad_size_list[3], + ceil_mode, + ) + + attr = ts.TosaSerializerAttribute() + attr.AvgPool2dAttribute( + kernel=kernel_size_list, + stride=stride_size_list, + pad=pad_size_list, + acc_type=accumulator_type, + ) + dt: ts.DType = output.dtype + input_zp_tensor = tosa_graph.addConst(shape=[1], dtype=dt, vals=[input_zp]) + output_zp_tensor = tosa_graph.addConst(shape=[1], dtype=dt, vals=[output_zp]) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.AVG_POOL2D, + [input_tensor.name, input_zp_tensor.name, output_zp_tensor.name], + [output.name], + attr, + ) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [3, 4, 5, 6, 7]) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ts.DType.INT8, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + if inputs[0].dtype == ts.DType.INT8 or inputs[0].dtype == ts.DType.INT16: + accumulator_type = ts.DType.INT32 + input_qargs = get_input_qparams(node) + input_zp = input_qargs[0].get_zp_per_tensor() + + output_qargs = get_output_qparams(node) + output_zp = output_qargs[0].get_zp_per_tensor() + else: + accumulator_type = ts.DType.FP32 + input_zp = 0 + output_zp = 0 + + self._build_generic_avgpool2d( + node, tosa_graph, inputs, output, input_zp, output_zp, accumulator_type + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_bitwise_not.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_bitwise_not.py new file mode 100644 index 0000000..ac0f758 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_bitwise_not.py @@ -0,0 +1,62 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class BitwiseNotVisitor(NodeVisitor): + target = "aten.bitwise_not.default" + + # bitwise_not is not supported on the FP profile + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.BitwiseNotAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.BITWISE_NOT, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cat.py new file mode 100644 index 0000000..71c1853 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cat.py @@ -0,0 +1,68 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class CatVisitor(NodeVisitor): + target = "aten.cat.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + supported_dtypes = [ts.DType.BOOL, ts.DType.INT8, ts.DType.INT32, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_num_inputs(self.target, inputs, [1, 2]) + input_tosa_args = [TosaArg(arg, output.tosa_spec) for arg in inputs[0].special] + validate_same_dtype(self.target, [*input_tosa_args, output], ts) + validate_valid_dtype( + self.target, + [*input_tosa_args, output], + supported_dtypes, + output.tosa_spec, + ) + + dim = 0 if len(inputs) < 2 else inputs[1].number + rank = len(output.shape) + dim = (dim + rank) % rank + dim = output.dim_order.index(dim) + + attr = ts.TosaSerializerAttribute() + attr.ConcatAttribute(dim) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.CONCAT, + [tensor.name for tensor in input_tosa_args], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ceil.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ceil.py new file mode 100644 index 0000000..27ee81d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ceil.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class CeilVisitor(NodeVisitor): + target = "aten.ceil.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + inputs[0], + ts.DType.FP32, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.CeilAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.CEIL, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_clamp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_clamp.py new file mode 100644 index 0000000..d90f92f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_clamp.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree + + +from typing import Any, List, Tuple + +import numpy as np +import torch +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class ClampVisitor(NodeVisitor): + target = "aten.clamp.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def _get_min_max_arguments( + self, node: Node, dtype: torch.dtype + ) -> Tuple[int | float, int | float]: + def cast_type(value: Any) -> int | float: + if isinstance(value, int): + return value + else: + # Attempt to cast to float + return float(value) + + if dtype.is_floating_point: + dtype_min = torch.finfo(dtype).min + dtype_max = torch.finfo(dtype).max + else: + dtype_min = torch.iinfo(dtype).min + dtype_max = torch.iinfo(dtype).max + + min_arg = dtype_min + max_arg = dtype_max + + if node.args[1] is not None: + min_arg = cast_type(node.args[1]) + + if len(node.args) > 2: + if node.args[2] is not None: + max_arg = cast_type(node.args[2]) + + return min_arg, max_arg + + def _to_bytes(self, value: int | float, dtype: torch.dtype) -> bytes: + if dtype == torch.float32: + return np.frombuffer(np.float32(value).tobytes(), dtype=np.uint8).tolist() + elif dtype == torch.float16: + return np.frombuffer(np.float16(value).tobytes(), dtype=np.uint8).tolist() + elif dtype == torch.int8: + return np.frombuffer(np.int8(value).tobytes(), dtype=np.uint8).tolist() + elif dtype == torch.int16: + return np.frombuffer(np.int16(value).tobytes(), dtype=np.uint8).tolist() + else: + raise ValueError(f"Unsupported dtype for to_bytes: {dtype}") + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [2, 3]) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ts.DType.INT8, ts.DType.FP16, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + node_input_dtype = node.meta["val"].dtype + # NOTE: Quantization of the min/max arguments is handled by QuantizeOperatorArguments + min_val, max_val = self._get_min_max_arguments(node, node_input_dtype) + + attr = ts.TosaSerializerAttribute() + attr.ClampAttribute( + self._to_bytes(min_val, node_input_dtype), + self._to_bytes(max_val, node_input_dtype), + nan_mode=ts.NanPropagationMode.PROPAGATE, + ) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.CLAMP, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cond_if.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cond_if.py new file mode 100644 index 0000000..4cf5120 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cond_if.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe +from typing import Any, cast, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( # type: ignore + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_cf_extension, + validate_num_inputs, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg # type: ignore +from torch.fx import Node + + +@register_node_visitor +class CondVisitor(NodeVisitor): + target = "cond" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + validate_num_inputs(self.target, inputs, 4) + validate_valid_dtype(self.target, [inputs[0]], ts.DType.BOOL, self.tosa_spec) + validate_cf_extension(self.target, self.tosa_spec) + + attr = ts.TosaSerializerAttribute() + if_graph, else_graph = (cast(Node, arg).target for arg in node.args[1:3]) + attr.CondIfAttribute(if_graph, else_graph) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.COND_IF, + [ + inputs[0].name, + *(subgraph_input.name for subgraph_input in inputs[-1].special), + ], + output.multiple_output_names, + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_constant_pad_nd.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_constant_pad_nd.py new file mode 100644 index 0000000..47d11fb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_constant_pad_nd.py @@ -0,0 +1,117 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ConstantPadNDVisitor(NodeVisitor): + + target = "aten.constant_pad_nd.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ts.DType.BOOL, + ], + output.tosa_spec, + ) + + if inputs[0].dtype == ts.DType.INT8: + input_qparams = get_input_qparams(node) + qargs = input_qparams[0] + pad_const_val = qargs.quantize_value(inputs[2].number).item() + pad_const_dtype = ts.DType.INT8 + elif inputs[0].dtype == ts.DType.INT16: + input_qparams = get_input_qparams(node) + qargs = input_qparams[0] + pad_const_val = qargs.quantize_value(inputs[2].number).item() + pad_const_dtype = ts.DType.INT16 + else: + pad_const_val = inputs[2].number + pad_const_dtype = inputs[0].dtype + + rank = len(output.shape) + # Each dim needs 2 padding values. For example, to pad the last dimension, the pad has the form + # (padding_left, padding_right); to pad the last two dimensions, the pad has the form + # (padding_left, padding_right, padding_top, padding_bottom), and so on. For PyTorch NCHW format, the padding + # values are in the reverse order. So, firstly we need to reverse the input padding parameters. + input_pad = sum( + [ + [inputs[1].special[i], inputs[1].special[i + 1]] + for i in range(0, len(inputs[1].special), 2) + ][::-1], + [], + ) + # Then, add dummy zeros to make sure that both input_pad and output_pad has the same size. + input_pad = [0] * (rank * 2 - len(inputs[1].special)) + input_pad + # For PyTorch NCHW format, dim order is [0,...,rank-1] + input_dim_order = list(range(rank)) + output_pad = [0] * rank * 2 + + # Map input padding parameters into output padding parameters. TOSA is NHWC format. + for input_dim_idx, input_dim in enumerate(input_dim_order): + output_dim_idx = output.dim_order.index(input_dim) + output_pad[output_dim_idx * 2 : (output_dim_idx + 1) * 2] = input_pad[ + input_dim_idx * 2 : (input_dim_idx + 1) * 2 + ] + + padding = tosa_graph.addConst( + shape=[len(output_pad)], dtype=ts.DType.SHAPE, vals=output_pad + ) + + pad_const = tosa_graph.addConst( + shape=[1], dtype=pad_const_dtype, vals=[pad_const_val] + ) + + attr = ts.TosaSerializerAttribute() + attr.PadAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.PAD, + [inputs[0].name, padding.name, pad_const.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cos.py new file mode 100644 index 0000000..e603973 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_cos.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class CosVisitor(NodeVisitor): + target = "aten.cos.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: ts.TosaSerializer, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.CosAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.COS, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_eq.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_eq.py new file mode 100644 index 0000000..bd72c94 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_eq.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class EqualVisitor(NodeVisitor): + target = "aten.eq.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.EqualAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.EQUAL, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_erf.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_erf.py new file mode 100644 index 0000000..e642a40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_erf.py @@ -0,0 +1,54 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ERFVisitor(NodeVisitor): + target = "aten.erf.default" + + # INT case handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + ts.DType.FP32, + output.tosa_spec, + ) + + # MI lowering + attr = ts.TosaSerializerAttribute() + attr.ErfAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.ERF, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_exp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_exp.py new file mode 100644 index 0000000..72e89b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_exp.py @@ -0,0 +1,54 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class ExpVisitor(NodeVisitor): + target = "aten.exp.default" + + # BI case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + ts.DType.FP32, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.ExpAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.EXP, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_floor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_floor.py new file mode 100644 index 0000000..d9f831d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_floor.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class FloorVisitor(NodeVisitor): + target = "aten.floor.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + inputs[0], + ts.DType.FP32, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.FloorAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.FLOOR, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ge.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ge.py new file mode 100644 index 0000000..7547784 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_ge.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class GreaterEqualVisitor(NodeVisitor): + target = "aten.ge.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterEqualAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER_EQUAL, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_gt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_gt.py new file mode 100644 index 0000000..2a483f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_gt.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class GreaterThanVisitor(NodeVisitor): + target = "aten.gt.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_select.py new file mode 100644 index 0000000..ba2aa03 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_select.py @@ -0,0 +1,109 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + +from executorch.backends.arm.tosa.utils import build_reshape_tosa +from torch.fx import Node + + +@register_node_visitor +class IndexSelectVisitor(NodeVisitor): + """ + Simple example: + o = index_select(weights, index, indices) + Becomes: + i = view_copy(i) # reshape flattened indicies, i.e. [I] => [1, I] + o = index_select(w, index, i) + + Additional steps in case weights (w) are rank 2: + - before: insert view_copy to make rank 3, [x,y] => [1, x, y] + - after: insert view_copy to squeeze back output dims, [1, x, y] = [x,y] + """ + + target = "aten.index_select.default" + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + weights, _, indices = inputs + + if len(weights.shape) == 2: + weights_new_shape = [1, weights.shape[0], weights.shape[1]] + weights_reshaped = tosa_graph.addIntermediate( + weights_new_shape, + weights.dtype, + ) + build_reshape_tosa( + tosa_graph, weights.name, weights_new_shape, weights_reshaped.name + ) + + output_new_shape = [1, output.shape[0], output.shape[1]] + output_reshaped = tosa_graph.addIntermediate( + output_new_shape, + output.dtype, + ) + + else: + weights_reshaped = weights + output_reshaped = output + + output_name = output_reshaped.name + + # Reshape flattened indicies, i.e. [I] => [1, I] + indices_new_shape = [1, indices.shape[0]] + indices_reshaped = tosa_graph.addIntermediate( + indices_new_shape, + indices.dtype, + ) + build_reshape_tosa( + tosa_graph, indices.name, indices_new_shape, indices_reshaped.name + ) + + attr = ts.TosaSerializerAttribute() + attr.GatherAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GATHER, + [weights_reshaped.name, indices_reshaped.name], + [output_name], + attr, + ) + + if len(weights.shape) == 2: + output_real_shape = [output.shape[0], output.shape[1]] + build_reshape_tosa(tosa_graph, output_name, output_real_shape, output.name) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_tensor.py new file mode 100644 index 0000000..cd0809d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_index_tensor.py @@ -0,0 +1,247 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Any, List + +import executorch.backends.arm.tosa.utils as tutils + +import numpy as np +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_same_dtype, +) +from executorch.backends.arm.tosa.mapping import extract_tensor_meta, TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +class CommonIndexTensorVisitor(NodeVisitor): + target = "aten.index.Tensor" + + def __init__(self, *args): + super().__init__(*args) + + def _get_tensor_info(self, tensor: Node): + """ + Consolidates obtaining name, dtype and shape into a common function + reconciling access based on the type of the input. + + Args: + fake_tensors (list[FakeTensor]): List of 2 or more FakeTensors + who's shapes to evaluate + + Returns: + tuple[bool, list[int]]: First element is whether the shapes are + broadcastable. Second element is the common shape if compatible. + If not, empty list. + + """ + if isinstance(tensor, Node): + dtype, shape, _ = extract_tensor_meta(tensor.meta, self.tosa_spec) + return tensor.name, dtype, shape + else: + return tensor.name, tensor.dtype, tensor.shape + + def _calculate_tosa_vals( + self, + index_shape: List[int], + index_nodes: List[Node], + values_shape: List[int], + ): + # From TOSA spec + # N - number of batches + # W - number of indices in each batch + # K - range of each index (number of elements to index through) + # C - number of data channels for each index + N, K, W, C = 1, 1, 1, 1 + + # Calculate K, W, C + # N - kept to 1 for generic n-dim implementation + # Note: If/when slice and ellipsis support is added batching + # may have to be used to facilitate proper implementation of + # the relevant logic. + # W - common between all indices as they have been broadcast + # to a common shape in a pass. + W = math.prod(index_shape) + + for i, dim in enumerate(values_shape): + if i < len(index_nodes): + K *= dim + + total_vals = math.prod(values_shape) + C = int(total_vals / K) + + return N, K, W, C + + def _calculate_value_strides(self, values_shape: List[int]) -> List[int]: + values_strides: List[int] = [] + stride = 1 + for dim in reversed(values_shape): + values_strides.insert(0, stride) + stride *= dim + + return values_strides + + +@register_node_visitor +class IndexTensorVisitor(CommonIndexTensorVisitor): + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """ + This approach uses the fact that all indexing tensors are incremented + simultaneously and they essentially act as a map along the corresponding + dimensions of the values tensor. + Note: that this does not hold true when slicing or ellipsis ops + are involved as such they are not currently not supported. + + As such this approach flattens out the values tensor and + constructs a flattened out index obtained by flattening out the + index tensors, multiplying them by the relevant stride and accumulating them. + + This approach suffers from the fact that we are taking a number of index tensors of + type int32 and applying multiplications and additions. + + If the number of total elements in the values tensor exceeds int32 limits + then this approach falls apart. + """ + + validate_same_dtype(self.target, [inputs[0], output]) + + values, indices = inputs + index_nodes = indices.special + + # Broadcast indices + broadcasted_tensors = tutils.broadcast_tensors( + tosa_graph, index_nodes, self.tosa_spec + ) + + # Calculate strides so we can shift indices down the line. + values_strides = self._calculate_value_strides(values.shape) + + # The indices have already been broadcast to a common shape + # in so they are all the same. + _, index_dtype, index_shape = self._get_tensor_info(broadcasted_tensors[0]) + + N, K, W, C = self._calculate_tosa_vals(index_shape, index_nodes, values.shape) + + gather_idx_shape = [N, W] + + gather_index_name = "" + # Flatten out and shift indexes. + for i, index_node in enumerate(broadcasted_tensors): + index_name, _, _ = self._get_tensor_info(index_node) + index_name = index_node.name + + stride_shifted_indices = tosa_graph.addIntermediate( + index_shape, + index_dtype, + ) + + # Division by C is necessary when len(indices) < values.rank + # When there are dimensions left unindexed that changes the + # channels and thus the stride-shift. + data = np.full(index_shape, int(values_strides[i] / C)) + mul_const = tosa_graph.addConst(index_shape, index_dtype, data) + tosa_graph.addConst([1], ts.DType.INT8, 0, name=f"{output.name}_{i}_shift") + attr = ts.TosaSerializerAttribute() + attr.MulAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.MUL, + [index_name, mul_const.name, f"{output.name}_{i}_shift"], + [stride_shifted_indices.name], + attr, + ) + + reshaped_idxs = tosa_graph.addIntermediate( + gather_idx_shape, + index_dtype, + ) + tutils.build_reshape_tosa( + tosa_graph, + stride_shifted_indices.name, + gather_idx_shape, + reshaped_idxs.name, + shape_name_override=f"{output.name}_{i}_shape", + ) + + # Guarantees that the accumulation tensor is properly + # initialized and does not contain junk data. + if i == 0: + gather_index_name = reshaped_idxs.name + else: + add_idxs = tosa_graph.addIntermediate( + reshaped_idxs.shape, + reshaped_idxs.dtype, + ) + attr = ts.TosaSerializerAttribute() + attr.AddAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.ADD, + [gather_index_name, reshaped_idxs.name], + [add_idxs.name], + attr, + ) + gather_index_name = add_idxs.name + + gather_vals_shape = [N, K, C] + reshaped_input = tosa_graph.addIntermediate(gather_vals_shape, values.dtype) + + tutils.build_reshape_tosa( + tosa_graph, + values.name, + gather_vals_shape, + reshaped_input.name, + shape_name_override=f"{output.name}_index_shape", + ) + + gather_out_shape = (N, W, C) + gather_out = tosa_graph.addIntermediate( + gather_out_shape, + output.dtype, + ) + attr = ts.TosaSerializerAttribute() + attr.GatherAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GATHER, + [reshaped_input.name, gather_index_name], + [gather_out.name], + attr, + ) + + output_shape = tutils.tosa_shape(output.shape, output.dim_order) + + tutils.build_reshape_tosa( + tosa_graph, + gather_out.name, + list(output_shape), + output.name, + shape_name_override=f"{output.name}_output_shape", + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_le.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_le.py new file mode 100644 index 0000000..aa6b52b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_le.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class LessEqualVisitor(NodeVisitor): + target = "aten.le.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterEqualAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER_EQUAL, + [inputs[1].name, inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_log.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_log.py new file mode 100644 index 0000000..565d6d5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_log.py @@ -0,0 +1,50 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class LogVisitor(NodeVisitor): + target = "aten.log.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.LogAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.LOG, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_logical_not.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_logical_not.py new file mode 100644 index 0000000..695af5f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_logical_not.py @@ -0,0 +1,62 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class LogicalNotVisitor(NodeVisitor): + target = "aten.logical_not.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.BOOL], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.LogicalNotAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.LOGICAL_NOT, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_lt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_lt.py new file mode 100644 index 0000000..4b2b1a1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_lt.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class LessThanVisitor(NodeVisitor): + target = "aten.lt.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER, + [inputs[1].name, inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_max_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_max_pool2d.py new file mode 100644 index 0000000..bee0cc3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_max_pool2d.py @@ -0,0 +1,108 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class MaxPool2dVisitor(NodeVisitor): + target = "aten.max_pool2d.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [3, 4, 5, 6]) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ts.DType.INT8, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + input_tensor = inputs[0] + kernel_size = inputs[1].special + stride = inputs[2].special + + if len(inputs) == 6: + ceil_mode = bool(inputs[5].number) + else: + ceil_mode = False + + try: + pad_size_list = inputs[3].special + pad_size_list = [ + pad_size_list[0], + pad_size_list[0], + pad_size_list[1], + pad_size_list[1], + ] + except (IndexError, AttributeError): + pad_size_list = [0, 0, 0, 0] + + # Adjust the padding as necessary + pad_size_list[1] = adjust_pooling_pad_if_needed( + input_tensor.shape[2], + kernel_size[0], + stride[0], + pad_size_list[1], + ceil_mode, + ) + pad_size_list[3] = adjust_pooling_pad_if_needed( + input_tensor.shape[3], + kernel_size[1], + stride[1], + pad_size_list[3], + ceil_mode, + ) + + attr = ts.TosaSerializerAttribute() + attr.MaxPool2dAttribute( + kernel=kernel_size, + stride=stride, + pad=pad_size_list, + nan_mode=ts.NanPropagationMode.PROPAGATE, + ) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MAX_POOL2D, + [input_tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_maximum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_maximum.py new file mode 100644 index 0000000..d3ab305 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_maximum.py @@ -0,0 +1,66 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class MaxVisitor(NodeVisitor): + target = "aten.maximum.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr_maximum = ts.TosaSerializerAttribute() + attr_maximum.MaximumAttribute(nan_mode=ts.NanPropagationMode.PROPAGATE) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MAXIMUM, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr_maximum, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_minimum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_minimum.py new file mode 100644 index 0000000..7f72d15 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_minimum.py @@ -0,0 +1,67 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class MinVisitor(NodeVisitor): + target = "aten.minimum.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr_minimum = ts.TosaSerializerAttribute() + attr_minimum.MinimumAttribute(nan_mode=ts.NanPropagationMode.PROPAGATE) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MINIMUM, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr_minimum, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_mul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_mul.py new file mode 100644 index 0000000..0e10443 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_mul.py @@ -0,0 +1,61 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification + + +@register_node_visitor +class MulVisitor(NodeVisitor): + target = "aten.mul.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ] + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + tosa_graph.addConst([1], ts.DType.INT8, 0, name=f"{output.name}_shift") + attr = ts.TosaSerializerAttribute() + attr.MulAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.MUL, + [inputs[0].name, inputs[1].name, f"{output.name}_shift"], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_neg.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_neg.py new file mode 100644 index 0000000..e0bb408 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_neg.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def get_negate_zero_points(node: torch.fx.Node, is_int8: bool) -> tuple[int, int]: + """ + Returns (input1_zp, output_zp) for TOSA NEGATE. + Must be zero for non-int8 types. + """ + if is_int8: + return ( + get_input_qparams(node)[0].get_zp_per_tensor(), + get_output_qparams(node)[0].get_zp_per_tensor(), + ) + return (0, 0) + + +@register_node_visitor +class NegVisitor(NodeVisitor): + target = "aten.neg.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + supported_dtypes = [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP16, + ts.DType.BF16, + ts.DType.FP32, + ] + + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], supported_dtypes, output.tosa_spec + ) + + input_zp, output_zp = get_negate_zero_points( + node, inputs[0].dtype == ts.DType.INT8 + ) + + input_zp_tensor = tosa_graph.addConst( + (1,), inputs[0].dtype, [input_zp], name=output.name + "_input_zp" + ) + + output_zp_tensor = tosa_graph.addConst( + (1,), output.dtype, [output_zp], name=output.name + "_output_zp" + ) + attr = ts.TosaSerializerAttribute() + attr.NegateAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.NEGATE, + [inputs[0].name, input_zp_tensor.name, output_zp_tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_permute.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_permute.py new file mode 100644 index 0000000..fea0aea --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_permute.py @@ -0,0 +1,150 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def permutation_vector_to_matrix(permutation_vector: list[int]) -> torch.Tensor: + """ + Converts a permutation vector of length N to a NxN matrix that describes the same permutation. + for example: + (1,0,2) + -> + [0 1 0] + |1 0 0| + [0 0 1] + """ + N = len(permutation_vector) + P = torch.zeros(N, N) + for row_index, col_index in enumerate(permutation_vector): + P[row_index][col_index] = 1 + return P + + +def permutation_matrix_to_vector(permutation_matrix: torch.Tensor) -> list[int]: + """ + Converts a NxN permutation matrix to a permutation vector of length N that describes the same permutation. + [0 1 0] + |1 0 0| + [0 0 1] + -> + (1,0,2) + """ + N = len(permutation_matrix) + if N != len(permutation_matrix[0]): + raise ValueError( + f"A permutation matrix must be square, got shape {permutation_matrix.shape}" + ) + + p = [0] * N + for row_index, row in enumerate(permutation_matrix): + saw_one = False + for col_index, value in enumerate(row): + if value == 1: + if saw_one: + raise ValueError( + f"A permutation matrix can only have one 1 per row, got {row=}" + ) + p[row_index] = col_index + saw_one = True + elif value != 0: + raise ValueError( + f"A permutation matrix only contains 1's and 0's, got {value=}" + ) + return p + + +def transform_permutation_vector(permutation_vector: list[int], dim_order: list[int]): + """Transforms a permutation to dim_order.""" + + # We need to first transform to dim_order, apply the permutation P, + # and then transform back to the original dim_order. + # This transformation, S, is also a permutation, with the dim_order as permutation vector. + + # To do this, represent P and S with permutation matrices. + # Matrices can handle chained transformations and inversion easily. + S = permutation_vector_to_matrix(dim_order) + # The inverse of a permutation matrix is its transpose. + S_inverse = S.t() + P = permutation_vector_to_matrix(permutation_vector) + + # The complete transformation is S * P * S_inverse. + transformation_matrix = S.matmul(P.matmul(S_inverse)) + + # Luckily, since it is just a combination of permutations, the result is also a permutation + # that can again be described by a new permutation vector. + permutation_vector = permutation_matrix_to_vector(transformation_matrix) + return permutation_vector + + +@register_node_visitor +class PermuteVisitor(NodeVisitor): + target = "aten.permute_copy.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + # The permutation vector describes a permutation P in default Pytorch dim_order. + # For rank 4, the default dim_order NCHW. + # E.g. (2,3,0,1) -> permute (n,c,h,w) to (w,c,n,h) + permutation_vector = inputs[1].special + + if output.dim_order != tuple(range(len(output.dim_order))): + # the permutation vector can't be used directly if we are not in NCHW dim_order. + # Transform to dim_order. + permutation_vector = transform_permutation_vector( + permutation_vector, output.dim_order + ) + + attr = ts.TosaSerializerAttribute() + attr.TransposeAttribute(permutation_vector) + self._serialize_operator( + node, + tosa_graph, + ts.Op.TRANSPOSE, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_pow.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_pow.py new file mode 100644 index 0000000..33cbc29 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_pow.py @@ -0,0 +1,63 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class PowVisitor(NodeVisitor): + target = "aten.pow.Tensor_Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.FP16, ts.DType.FP32], + output.tosa_spec, + ) + attr = ts.TosaSerializerAttribute() + attr.PowAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.POW, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_reciprocal.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_reciprocal.py new file mode 100644 index 0000000..108a4fa --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_reciprocal.py @@ -0,0 +1,51 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ReciprocalVisitor(NodeVisitor): + target = "aten.reciprocal.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.ReciprocalAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.RECIPROCAL, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_repeat.py new file mode 100644 index 0000000..e44fede --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_repeat.py @@ -0,0 +1,77 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.utils import tosa_shape + + +@register_node_visitor +class RepeatVisitor(NodeVisitor): + target = "aten.repeat.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: list[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + multiples = inputs[1].special + + if len(multiples) == 0: + raise ValueError(f"Length of multiples argument is 0: {inputs[1]}!") + + multiple_shapes = tosa_graph.addConst( + (len(multiples),), + ts.DType.SHAPE, + list(tosa_shape(multiples, output.dim_order)), + name=output.name + "_multiples", + ) + + attr = ts.TosaSerializerAttribute() + attr.TileAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.TILE, + [inputs[0].name, multiple_shapes.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rshift_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rshift_tensor.py new file mode 100644 index 0000000..0b5717a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rshift_tensor.py @@ -0,0 +1,62 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class RshiftVisitor(NodeVisitor): + target = "aten.bitwise_right_shift.Tensor" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + round = False + if self.tosa_spec.is_U55_subset: + # U55 only supports INT32 and round == True + # TODO MLETORCH-525 Emulate round == False with different decomposition + round = True + attr.ArithmeticRightShiftAttribute(round=round) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.ARITHMETIC_RIGHT_SHIFT, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rsqrt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rsqrt.py new file mode 100644 index 0000000..a86eaa4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_rsqrt.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class RsqrtVisitor(NodeVisitor): + target = "aten.rsqrt.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.RsqrtAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.RSQRT, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sigmoid.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sigmoid.py new file mode 100644 index 0000000..908544f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sigmoid.py @@ -0,0 +1,50 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class SigmoidVisitor(NodeVisitor): + target = "aten.sigmoid.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.SigmoidAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.SIGMOID, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sin.py new file mode 100644 index 0000000..faa2499 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sin.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class SinVisitor(NodeVisitor): + target = "aten.sin.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: ts.TosaSerializer, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.SinAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.SIN, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_slice.py new file mode 100644 index 0000000..21c86e5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_slice.py @@ -0,0 +1,151 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +def _fixup_start(start, shape, dim): + # Normalize start index and clamp into [0, shape[dim]]. + # If not a constant, default to 0. + idx = getattr(start, "number", 0) + # Handle negative wrap-around + if idx < 0: + idx = idx % shape[dim] + # Clamp into valid bounds + if idx < 0: + idx = 0 + elif idx > shape[dim]: + idx = shape[dim] + return idx + + +def _fixup_end(end, shape, dim): + # Normalize end index and clamp into [0, shape[dim]]. + max_dim = shape[dim] + # If not a constant, default to the full size + idx = getattr(end, "number", max_dim) + # Handle negative wrap-around + if idx < 0: + idx = idx % max_dim + # Clamp into valid bounds + if idx < 0: + idx = 0 + elif idx > max_dim: + idx = max_dim + return idx + + +@register_node_visitor +class SliceVisitor(NodeVisitor): + target = "aten.slice_copy.Tensor" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [4, 5]) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + # See slice_copy_support.py + if not (len(inputs) == 4 or (len(inputs) == 5 and inputs[4].number == 1)): + raise ValueError("Unsupported combination of inputs") + + # aten.slice_copy supports slicing in 1d at a time. + # The arguments are the actual input, dimension of slicing, start index, end index and optinal step or stride. + input_node, dim, start, end = inputs + + # Translate and check parameters in Pytorch dim order. + shape = input_node.shape + dim = dim.number + + start_index = _fixup_start(start, shape, dim) + end_index = _fixup_end(end, shape, dim) + size = end_index - start_index + + if size <= 0: + raise ValueError( + f"The calculated slice size must be positive. Got {size=} " + f"with {start_index=} and {end_index=}." + ) + if size > shape[dim]: + raise ValueError( + f"The calculated slice size cannot be greater than the dimension size" + f". Got {size=} and {shape[dim]=}." + ) + + # Convert aten args to Tosa's start and size shape_t tensors and in TOSA dim order. + starts = [ + _fixup_start(start, shape, dim) if i == dim else 0 + for i in input_node.dim_order + ] + + if len(starts) != 0: + starts_len = len(starts) + else: + starts_len = 1 + starts = [0] + + start_tensor = tosa_graph.addConst( + (starts_len,), + ts.DType.SHAPE, + starts, + output.name + "_start_shape", + ) + + sizes = [size if i == dim else shape[i] for i in input_node.dim_order] + if len(sizes) != 0: + sizes_len = len(starts) + else: + sizes_len = 1 + sizes = [0] + sizes_tensor = tosa_graph.addConst( + (sizes_len,), ts.DType.SHAPE, sizes, output.name + "_sizes_shape" + ) + + attr = ts.TosaSerializerAttribute() + attr.SliceAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.SLICE, + [input_node.name, start_tensor.name, sizes_tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sub.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sub.py new file mode 100644 index 0000000..039a2f6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sub.py @@ -0,0 +1,63 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class SubVisitor(NodeVisitor): + target = "aten.sub.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.SubAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.SUB, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sum.py new file mode 100644 index 0000000..e956359 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_sum.py @@ -0,0 +1,64 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class SumVisitor(NodeVisitor): + target = "aten.sum.dim_IntList" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + tensor = inputs[0] + input_shape = list(tensor.shape) + dim = int(inputs[1].number % len(input_shape)) + + attr = ts.TosaSerializerAttribute() + attr.ReduceSumAttribute(tensor.dim_order.index(dim)) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_SUM, + [tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tanh.py new file mode 100644 index 0000000..c4603e9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tanh.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class TanhVisitor(NodeVisitor): + target = "aten.tanh.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.TanhAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.TANH, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_to_dim_order_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_to_dim_order_copy.py new file mode 100644 index 0000000..9d3aff8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_to_dim_order_copy.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ToDimOrderCopyVisitor(NodeVisitor): + """ + Implement the type cast functionality of _to_dim_order_copy. + + Other features like setting of the dim_order or moving a tensor to a + different device are not supported. + + Also note that the node should not be quantized. + """ + + target = "dim_order_ops._to_dim_order_copy.default" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + attr = ts.TosaSerializerAttribute() + attr.CastAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.CAST, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv2d.py new file mode 100644 index 0000000..7b7e415 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv2d.py @@ -0,0 +1,139 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import tosa_serializer as ts + +"""Provide a visitor for lowering 2D convolution to TOSA (INT/FP).""" + +from typing import Any, List + +import torch + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification + + +@register_node_visitor +class Conv2dVisitor(NodeVisitor): + """Provide a visitor that serializes TOSA ``CONV2D``.""" + + target = "tosa.CONV2D.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def _get_tosa_op(self): + return ts.Op.CONV2D + + def _get_attr_func(self, attr): + return attr.Conv2dAttribute + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """Define the TOSA CONV2D/DEPTHWISE_CONV2D operator.""" + + input, weight, bias, stride, pad, dilation = inputs + validate_num_inputs(self.target, inputs, 6) + + valid_input_dtypes = [] + if self.tosa_spec.support_float(): + valid_input_dtypes.append(ts.DType.FP32) + if self.tosa_spec.support_integer(): + valid_input_dtypes.append(ts.DType.INT8) + + if self.tosa_spec.support_extension("int16"): + valid_input_dtypes.append(ts.DType.INT16) + # Check constraints for int16 activations + if inputs[0].dtype == ts.DType.INT16: + validate_valid_dtype( + self.target, [inputs[1]], [ts.DType.INT8], self.tosa_spec + ) + validate_valid_dtype( + self.target, [inputs[2]], [ts.DType.INT48], self.tosa_spec + ) + + validate_valid_dtype( + self.target, + [inputs[0]], + valid_input_dtypes, + self.tosa_spec, + ) + + # Get the attributes of convolution. + pad_attr = pad.special + stride_attr = stride.special + dilation_attr = dilation.special + + input_zp = 0 + if inputs[0].dtype in (ts.DType.INT8, ts.DType.INT16): + # int8 and int16 input requires quantization information + input_qparams = get_input_qparams(node) + input_zp = input_qparams[0].get_zp_per_tensor() + + weight_zp = 0 + if inputs[1].dtype == ts.DType.INT8: + # int8 weights requires quantization information + input_qparams = get_input_qparams(node) + weight_zp = input_qparams[1].zp # type: ignore[assignment] + + conv2d_output_name = output.name + acc_type = output.dtype + + tosa_graph.addConst( + [1], inputs[0].dtype, [input_zp], name=f"{conv2d_output_name}_input_zp" + ) + tosa_graph.addConst( + [1], + inputs[1].dtype, + weight_zp, + name=f"{conv2d_output_name}_weight_zp", + ) + + tosa_op = self._get_tosa_op() + + attr = ts.TosaSerializerAttribute() + self._get_attr_func(attr)( + pad=pad_attr, + stride=stride_attr, + dilation=dilation_attr, + local_bound=False, + acc_type=acc_type, + ) + + self._serialize_operator( + node, + tosa_graph, + tosa_op, + [ + input.name, + weight.name, + bias.name, + f"{conv2d_output_name}_input_zp", + f"{conv2d_output_name}_weight_zp", + ], + [conv2d_output_name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv3d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv3d.py new file mode 100644 index 0000000..e0a8d2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_conv3d.py @@ -0,0 +1,24 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide a visitor for lowering 3D convolution to TOSA (INT/FP).""" + +from executorch.backends.arm.operators.node_visitor import register_node_visitor +from executorch.backends.arm.operators.op_tosa_conv2d import Conv2dVisitor + + +@register_node_visitor +class Conv3dVisitor(Conv2dVisitor): + """Provide a visitor that serializes TOSA ``CONV3D``.""" + + target = "tosa.CONV3D.default" + + def _get_tosa_op(self): + import serializer.tosa_serializer as ts # type: ignore + + return ts.Op.CONV3D + + def _get_attr_func(self, attr): + return attr.Conv3dAttribute diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_depthwise_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_depthwise_conv2d.py new file mode 100644 index 0000000..78e6e44 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_depthwise_conv2d.py @@ -0,0 +1,32 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide a visitor for lowering 2D depthwise convolution to TOSA (INT/FP).""" + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import register_node_visitor +from executorch.backends.arm.operators.op_tosa_conv2d import Conv2dVisitor +from executorch.backends.arm.tosa import TosaSpecification + + +@register_node_visitor +class DepthwiseConv2dVisitor(Conv2dVisitor): + """Provide a visitor that serializes TOSA ``DEPTHWISE_CONV2D``.""" + + target = "tosa.DEPTHWISE_CONV2D.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def _get_tosa_op(self): + return ts.Op.DEPTHWISE_CONV2D + + def _get_attr_func(self, attr): + return attr.DepthwiseConv2dAttribute + + # Inheriting the define_node method from Conv2dVisitor diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_matmul.py new file mode 100644 index 0000000..993caff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_matmul.py @@ -0,0 +1,102 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide a visitor for lowering batched matmul (BMM) to TOSA.""" + +from typing import Any, List + +import torch +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class MatmulVisitor(NodeVisitor): + """Provide a visitor that serializes TOSA ``MATMUL``.""" + + target = "tosa.MATMUL.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """Define the TOSA ``MATMUL`` operator.""" + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs], ts) + supported_input_dtypes = [ts.DType.INT8, ts.DType.INT32, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_input_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [*inputs], + supported_input_dtypes, + output.tosa_spec, + ) + supported_output_dtypes = [ts.DType.INT32, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_output_dtypes.append(ts.DType.INT48) + validate_valid_dtype( + self.target, + [output], + supported_output_dtypes, + output.tosa_spec, + ) + + # We need to get the zero points and add an intermediate tensor for INT16 case + if inputs[0].dtype in (ts.DType.INT8, ts.DType.INT16): + input_qparams = get_input_qparams(node) + input0_zp = input_qparams[0].get_zp_per_tensor() + input1_zp = input_qparams[1].get_zp_per_tensor() + else: + input0_zp, input1_zp = 0, 0 + + input_A_ZP_name = f"{output.name}_A_ZP" + input_B_ZP_name = f"{output.name}_B_ZP" + tosa_graph.addConst([1], inputs[0].dtype, [input0_zp], name=input_A_ZP_name) + tosa_graph.addConst([1], inputs[1].dtype, [input1_zp], name=input_B_ZP_name) + + # Add the MATMUL to the TOSA graph. + attr = ts.TosaSerializerAttribute() + attr.MatMulAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MATMUL, + [ + inputs[0].name, + inputs[1].name, + input_A_ZP_name, + input_B_ZP_name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_rescale.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_rescale.py new file mode 100644 index 0000000..ae87dcc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_rescale.py @@ -0,0 +1,261 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Any, cast, List, Tuple + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, +) + +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import map_dtype, TosaArg +from torch.fx import Node + + +def _compute_multiplier_and_shift( + scales: list[float], scaleWidth: int = 32 +) -> Tuple[list[int], list[int]]: + """Derive integer multipliers and shifts from floating-point scales. + + TOSA uses the RESCALE operation to scale between values with differing + precision. The RESCALE operator is defined using an integer multiply, add, + and shift. This utility function is for calculating the multiplier and shift + given a scale. + Ref: https://www.mlplatform.org/tosa/tosa_spec.html#_precision_scaling + + Args: + scales (list[float]): Scale factors to decompose into multiplier and + shift pairs. + scaleWidth (int): Bit-width of the multiplier representation; expects + ``16`` or ``32``. + + Returns: + Tuple[list[int], list[int]]: Parallel lists containing the computed + multipliers and right shifts. + + Raises: + ValueError: If ``scaleWidth`` is not supported. + + """ + if scaleWidth == 16: + offset = 15 + elif scaleWidth == 32: + offset = 31 + else: + raise ValueError( + f"Unsupported scale width: {scaleWidth}, only 16 and 32 are valid values." + ) + + multipliers = [] + shifts = [] + for scale in scales: + mantissa, exponent = math.frexp(scale) + shift = exponent + + const_2_power_15_or_31 = 1 << offset + shifted_mantissa = round(mantissa * const_2_power_15_or_31) + + assert ( + shifted_mantissa <= const_2_power_15_or_31 + ), f"Mantissa {shifted_mantissa} exceeds limit {const_2_power_15_or_31}" + + if shifted_mantissa == const_2_power_15_or_31: + shifted_mantissa = shifted_mantissa // 2 + shift += 1 + + # TOSA expects right shift to be positive, and embed (1 << offset) into right shift bits. + shift = offset - shift + + # INT32_MAX, 2^31 - 1 + assert shifted_mantissa <= (const_2_power_15_or_31 - 1), ( + f"Mantissa {shifted_mantissa} exceeds signed max " + f"{const_2_power_15_or_31 - 1}" + ) + + multiplier = shifted_mantissa + + if shift > 62: + multiplier = multiplier >> min(31, shift - 62) + shift = 62 + + assert multiplier >= 0, "Multiplier should be non-negative" + assert shift >= 2 and shift <= 62, "Shift should be in range [2, 62]" + multipliers.append(multiplier) + shifts.append(shift) + return multipliers, shifts + + +def _create_const_ops_for_rescale( + tosa_fb, + scale_32, + input_dtype, + node_name, + multipliers, + shifts, + input_zp, + output_zp, + output_dtype, + ts, +): + """Materialize constant operands required by the TOSA RESCALE op. + + For TOSA spec v1.0 RESCALE operator requires multiplier, shifts, input_zp + and output_zp to be const inputs. Create constant operators from the data + already initialized. + + Args: + tosa_fb (Any): Graph builder used to emit TOSA operators and tensors. + scale_32 (bool): Flag indicating whether multipliers use 32-bit width. + input_dtype (ts.DType): Data type of the input tensor. + node_name (str): Base name reused for created constant tensors. + multipliers (list[int]): Precomputed multiplier coefficients. + shifts (list[int]): Precomputed shift coefficients. + input_zp (list[int]): Quantization zero points for the input. + output_zp (list[int]): Quantization zero points for the output. + output_dtype (ts.DType): Data type of the output tensor. + ts (module): Reference to the ``tosa_serializer`` module. + + Returns: + list[str]: Names of the constant tensors added to ``tosa_fb`` in the + order expected by RESCALE. + + """ + + multipliers = tosa_fb.addConst( + (len(multipliers),), + ts.DType.INT32 if scale_32 else ts.DType.INT16, + multipliers, + name=node_name + "_multipliers", + ) + shifts = tosa_fb.addConst( + (len(shifts),), ts.DType.INT8, shifts, name=node_name + "_shifts" + ) + input_zp = tosa_fb.addConst( + [1], input_dtype, input_zp, name=node_name + "_input_zp" + ) + output_zp = tosa_fb.addConst( + [1], output_dtype, output_zp, name=node_name + "_output_zp" + ) + + return [multipliers.name, shifts.name, input_zp.name, output_zp.name] + + +def _build_rescale( + tosa_fb: Any, + scale: list[float], + input_node: Any, + output_name: str, + output_type: Any, + input_zp: list[int], + output_zp: list[int], + rounding_mode: ts.RoundingMode, + per_channel: bool = False, + is_scale32: bool = True, +): + """Insert a TOSA RESCALE operator configured for the quantized path. + + Args: + tosa_fb (Any): Graph builder receiving the RESCALE operator. + scale (list[float]): Scale factors applied during rescaling. + input_node (Any): Input tensor node feeding the operator. + output_name (str): Name assigned to the RESCALE output tensor. + output_type (ts.DType): Data type of the output tensor. + input_zp (list[int]): Quantization zero points for the input tensor. + output_zp (list[int]): Quantization zero points for the output tensor. + rounding_mode (ts.RoundingMode): Rounding policy for the RESCALE op. + per_channel (bool): Whether scales are applied per output channel. + is_scale32 (bool): Declared scale width; ignored when the input type is + ``ts.DType.INT48``. + + """ + scaleWidth = 16 if input_node.dtype == ts.DType.INT48 else 32 + is_scale32 = False if input_node.dtype == ts.DType.INT48 else True + multipliers, shifts = _compute_multiplier_and_shift(scale, scaleWidth) + rescale_inputs = _create_const_ops_for_rescale( + tosa_fb, + is_scale32, + input_node.dtype, + output_name, + multipliers, + shifts, + input_zp, + output_zp, + output_type, + ts, + ) + attr_rescale = ts.TosaSerializerAttribute() + attr_rescale.RescaleAttribute( + scale32=is_scale32, + rounding_mode=rounding_mode, + per_channel=per_channel, + input_unsigned=False, + output_unsigned=False, + ) + + tosa_fb.addOperator( + ts.Op.RESCALE, + [input_node.name, *rescale_inputs], + [output_name], + attr_rescale, + ) + + +@register_node_visitor +class RescaleVisitor(NodeVisitor): + target = "tosa.RESCALE.default" + + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+INT")] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 5) + + input_dtype = inputs[0].dtype + output_dtype = cast(torch.dtype, node.args[1]) + scales = cast(list[float], node.args[2]) + input_zp = cast(int, node.args[3]) + output_zp = cast(int, node.args[4]) + + if ( + input_dtype + not in [ + map_dtype(torch.int8, self.tosa_spec), + map_dtype(torch.int16, self.tosa_spec), + ] + and input_zp != 0 + ): + raise ValueError( + f"If input dtype is not int8 or int16, input_zp must be 0. Got input_dtype {input_dtype=}, {input_zp=}" + ) + if output_dtype not in [torch.int8, torch.int16] and output_zp != 0: + raise ValueError( + f"If output dtype is not int8 or int16, output_zp must be 0. Got {ts.DTypeNames[output_dtype]}, {output_zp=}" + ) + + _build_rescale( + tosa_graph, + scale=scales, + input_node=inputs[0], + output_name=output.name, + output_type=output.dtype, + input_zp=[input_zp], + output_zp=[output_zp], + rounding_mode=ts.RoundingMode.SINGLE_ROUND, + per_channel=len(scales) > 1, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_resize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_resize.py new file mode 100644 index 0000000..e7e63f1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_resize.py @@ -0,0 +1,124 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.utils import get_resize_parameters + + +@register_node_visitor +class ResizeVisitor(NodeVisitor): + target = "tosa.RESIZE.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [3, 4]) + supported_input_dtypes = [ts.DType.INT8, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_input_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0]], + supported_input_dtypes, + output.tosa_spec, + ) + supported_output_dtypes = [ts.DType.FP32] + if node.kwargs.get("resize_mode") == "bilinear": + resize_mode = ts.ResizeMode.BILINEAR + align_corners = bool(node.args[2]) + supported_output_dtypes.append(ts.DType.INT32) + if self.tosa_spec.support_extension("int16"): + supported_output_dtypes.append(ts.DType.INT48) + else: + resize_mode = ts.ResizeMode.NEAREST + align_corners = False + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_output_dtypes.append(ts.DType.INT8) + if self.tosa_spec.support_extension("int16"): + supported_output_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, [output], supported_output_dtypes, output.tosa_spec + ) + # tosa_shape output is NHWC, take HW + input_size_yx = tuple([inputs[0].shape[dim] for dim in inputs[0].dim_order])[ + 1:3 + ] + output_size_yx = tuple([output.shape[dim] for dim in output.dim_order])[1:3] + + # Align corners shouldn't make a difference for nearest upsampling. We set to False so + # half pixel centers are used for resize parameter logic. + scale_n_yx, scale_d_yx, offset_yx, border_yx = get_resize_parameters( + input_size_yx, output_size_yx, resize_mode, align_corners=align_corners + ) + + def in_int16_range(x): + return torch.all(x >= -(2**15)) and torch.all(x <= 2**15 - 1) + + if not in_int16_range(scale_n_yx): + raise ValueError("scale_n_yx is out of the int16 range") + if not in_int16_range(scale_d_yx): + raise ValueError("scale_d_yx is out of the int16 range") + if not in_int16_range(border_yx): + raise ValueError("border_yx is out of the int16 range") + + scale_n_vals = [int(v) for v in scale_n_yx.tolist()] + scale_d_vals = [int(v) for v in scale_d_yx.tolist()] + scales = [ + scale_n_vals[0], + scale_d_vals[0], + scale_n_vals[1], + scale_d_vals[1], + ] + scales_tensor = tosa_graph.addConst( + [len(scales)], ts.DType.SHAPE, scales, output.name + "_scales" + ) + offset = [int(v) for v in offset_yx.tolist()] + offset_tensor = tosa_graph.addConst( + [len(offset)], ts.DType.SHAPE, offset, output.name + "_offset" + ) + border = [int(v) for v in border_yx.tolist()] + border_tensor = tosa_graph.addConst( + [len(border)], ts.DType.SHAPE, border, output.name + "_border" + ) + attr = ts.TosaSerializerAttribute() + attr.ResizeAttribute(resize_mode) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.RESIZE, + [ + inputs[0].name, + scales_tensor.name, + offset_tensor.name, + border_tensor.name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_table.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_table.py new file mode 100644 index 0000000..7448898 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_table.py @@ -0,0 +1,72 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_valid_dtype, +) + +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class TableVisitor(NodeVisitor): + target = "tosa.TABLE.default" + + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+INT")] + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + supported_input_dtypes = [ts.DType.INT8] + supported_output_dtypes = [ts.DType.INT8] + if self.tosa_spec.support_extension("int16"): + supported_input_dtypes.append(ts.DType.INT16) + supported_output_dtypes.append(ts.DType.INT32) + + validate_valid_dtype( + self.target, inputs, supported_input_dtypes, output.tosa_spec + ) + validate_valid_dtype( + self.target, output, supported_output_dtypes, output.tosa_spec + ) + + # The name of the table constant is a bit complex. + # The name of the pytorch buffer will be the target of last node argument. + # However, when it is serialized to TOSA, a submodule suffix might be added. The TOSA buffer name thus + # needs to be taken from the last TosaArg. + pytorch_table_buffer_name = node.args[-1].target # type: ignore[union-attr] + tosa_table_buffer_name = inputs[-1].name + if pytorch_table_buffer_name not in self._exported_program.state_dict.keys(): + raise RuntimeError( + f"Did not find key {node.name} in state_dict {self._exported_program.state_dict.keys()}." + ) + + attr = ts.TosaSerializerAttribute() + attr.TableAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.TABLE, + [inputs[0].name, tosa_table_buffer_name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_transpose.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_transpose.py new file mode 100644 index 0000000..c5aa66a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_tosa_transpose.py @@ -0,0 +1,71 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class TransposeVisitor(NodeVisitor): + """ + This node visitor targets the tosa::TRANSPOSE op defined in the + TOSA backend dialect. Used when switching between tosa_dim_orders. + Inserts a TOSA TRANSPOSE. + """ + + target = "tosa.TRANSPOSE.default" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP16, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + output_rank = len(output.shape) + perms = [dim % output_rank for dim in inputs[1].special] + attr = ts.TosaSerializerAttribute() + attr.TransposeAttribute(perms) + self._serialize_operator( + node, + tosa_graph, + ts.Op.TRANSPOSE, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_view.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_view.py new file mode 100644 index 0000000..a32cb3a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_view.py @@ -0,0 +1,81 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.utils import tosa_shape + + +@register_node_visitor +class ViewVisitor(NodeVisitor): + target = "aten.view_copy.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ts.DType.BOOL, + ], + output.tosa_spec, + ) + + tosa_graph = cast(ts.TosaSerializer, tosa_graph) + + if len(output.shape) != 0: + shape_len = [len(output.shape)] + shape_data = list(tosa_shape(output.shape, output.dim_order)) + else: + shape_len = [] + shape_data = [] + + shape = tosa_graph.addConst( + shape_len, + ts.DType.SHAPE, + shape_data, + name=output.name + "_shape", + ) + + attr = ts.TosaSerializerAttribute() + attr.ReshapeAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.RESHAPE, + [inputs[0].name, shape.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_where.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_where.py new file mode 100644 index 0000000..f0b6538 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_where.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) + +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class WhereVisitor(NodeVisitor): + target = "aten.where.self" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + supported_dtypes = [ts.DType.BOOL] + if output.tosa_spec.support_integer(): + supported_dtypes += [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ] + if output.tosa_spec.support_float(): + supported_dtypes += [ts.DType.FP16, ts.DType.FP32] + + validate_num_inputs(self.target, inputs, 3) + # Not first input, which is condition tensor. + validate_same_dtype(self.target, inputs[1:], ts) + validate_valid_dtype(self.target, inputs[0], ts.DType.BOOL, output.tosa_spec) + validate_valid_dtype( + self.target, + [*inputs[1:], output], + supported_dtypes, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.SelectAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.SELECT, + [inputs[0].name, inputs[1].name, inputs[2].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_while.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_while.py new file mode 100644 index 0000000..b4ac4f4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/op_while.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, List + +import tosa_serializer as ts +from executorch.backends.arm._passes.arm_pass_utils import get_output_dim_orders + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_cf_extension, + validate_num_inputs, +) +from executorch.backends.arm.tosa.mapping import map_dtype, TosaArg +from executorch.backends.arm.tosa.utils import tosa_shape + +from torch.fx import Node + + +@register_node_visitor +class WhileLoopVisitor(NodeVisitor): + target = "while_loop" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + validate_num_inputs(self.target, inputs, 4) + validate_cf_extension(self.target, self.tosa_spec) + + carried_inputs = inputs[2].special if hasattr(inputs[2], "special") else None + if carried_inputs is None: + raise ValueError(f"{self.target}: Expected loop input arguments to be set.") + + additional_inputs = inputs[3].special if hasattr(inputs[3], "special") else None + if additional_inputs: + raise ValueError( + "Additional inputs is not supported, use carried inputs instead." + ) + + attr = ts.TosaSerializerAttribute() + cond_graph, body_graph = (str(cast(Node, arg).target) for arg in node.args[:2]) + attr.WhileLoopAttribute(cond_graph, body_graph) + + input_names: list[str] = [] + for loop_input in carried_inputs: + if not isinstance(loop_input, Node): + raise ValueError( + f"{self.target}: Unsupported carried input type {type(loop_input)}." + ) + input_names.append(loop_input.name) + + num_inputs = len(input_names) + num_outputs = len(output.multiple_output_names) + if num_inputs > num_outputs: + # If we have more inputs than outputs, we can just add missing output tensors. + body_module = getattr(node.graph.owning_module, body_graph) + output_dim_orders = get_output_dim_orders(body_module) + body_outputs = body_module.graph.output_node().args[0] + outputs_needing_tensors = body_outputs[num_outputs - num_inputs :] + output_dim_orders = output_dim_orders[num_outputs - num_inputs :] + for ( + output_needing_tensor, + dim_order, + ) in zip(outputs_needing_tensors, output_dim_orders, strict=True): + tensor_name = output_needing_tensor.name + "_dummy" + shape = output_needing_tensor.meta["val"].shape + dtype = map_dtype( + output_needing_tensor.meta["val"].dtype, self.tosa_spec + ) + + tosa_graph.currRegion.currBasicBlock.addTensor( + tensor_name, + tosa_shape(shape, dim_order), + dtype, + ) + output.multiple_output_names.append(tensor_name) + elif num_inputs < num_outputs: + # This is a strange case, if we reach it something bad has happened. + raise ValueError( + f"TOSA specifies that the number of inputs, {input_names}, need to be the " + f"same as the number of outputs, {output.multiple_output_names}." + ) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.WHILE_LOOP, + input_names, + output.multiple_output_names, + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/operator_validation_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/operator_validation_utils.py new file mode 100644 index 0000000..20ee105 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/operator_validation_utils.py @@ -0,0 +1,201 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide validation helpers for operator inputs and dtypes. + +Use these utilities to validate input counts, ensure dtype consistency, check +allowed dtypes, and compute pooling padding adjustments. + +""" + +from math import ceil, floor +from typing import Any, List, Optional + +from executorch.backends.arm.tosa.specification import Tosa_1_00, TosaSpecification + + +def validate_num_inputs(op_name: str, inputs: List[Any], expected: int | List[int]): + """Validate the number of inputs against expected values. + + This function checks whether the length of the input list matches the + expected number(s) of inputs. + + Args: + op_name (str): The name of the operation for which the inputs are being + validated. Used in the error message to provide context. + inputs (List[TosaArg]): A list of inputs to be validated, where each + input is assumed to be an instance of ``TosaArg``. + expected (int | List[int]): The expected number of inputs. Can be either + an integer or a list of integers. + + Raises: + ValueError: If the number of inputs does not match the expected + value(s); the message indicates the operation name and the mismatch + in expected versus provided counts. + + Example: + from executorch.backends.arm.operators.operator_validation_utils import \ + validate_num_inputs + + validate_num_inputs(self.target, inputs, [3, 4]) + + """ + if isinstance(expected, int): + expected = [expected] + if len(inputs) not in expected: + expected_str = ", ".join(map(str, expected)) + raise ValueError( + f"{op_name}: Expected number of input(s) to be " + f"[{expected_str}], got {len(inputs)}" + ) + + +def validate_same_dtype(op_name: str, tensors: List[Any], ts: Optional[Any] = None): + """Validate that all given tensors have the same dtype. + + This function checks whether all items in the ``tensors`` list have the + same ``dtype`` as the first item. + + Args: + op_name (str): The name of the operation for which the dtype validation + is being performed. Used in the error message to provide context. + tensors (List[Any]): A list of tensors to be validated, each assumed to + have a ``dtype`` attribute. + ts (Optional[Any]): TOSA serializer (optional) to improve readability of + dtype names in error messages. + + Raises: + ValueError: If the dtype of any item in the list does not match the + dtype of the first item, or if the list is empty. + + Example: + from executorch.backends.arm.operators.operator_validation_utils import \ + validate_same_dtype + + validate_same_dtype(self.target, [input1, input2, output]) + + """ + if not tensors: + raise ValueError( + f"{op_name}: Input tensor list is empty, cannot validate dtypes" + ) + + # Get dtype of the first tensor to reference for comparison + reference_dtype = tensors[0].dtype + reference_dtype_name = str(reference_dtype) + + for tensor in tensors: + if tensor.dtype != reference_dtype: + inconsistent_dtype_name = str(tensor.dtype) + raise ValueError( + f"{op_name}: Expected all tensors to have dtype {reference_dtype_name}, " + f"but found inconsistent dtype {inconsistent_dtype_name}." + ) + + +def validate_valid_dtype( + op_name: str, tensors: Any | List[Any], valid_dtypes: Any | List[Any], tosa_spec +): + """Validate that one or more tensors have allowed dtypes. + + This function checks whether the ``dtype`` attribute of the provided + tensor(s) is one of the valid dtype values. It supports checking a single + tensor or a list of tensors. + + Args: + op_name (str): The name of the operation performing the validation. + tensors (Any | List[Any]): A tensor or list of tensors (each assumed to + have ``dtype`` and ``name`` attributes) whose dtype will be + validated. + valid_dtypes (Any | List[Any]): A dtype enum or list of dtype enums + representing allowed dtype values. + tosa_spec (Any): A TosaSpecification instance indicating which TOSA + version is targeted. This determines which serializer to use for + dtype name resolution. + + Raises: + ValueError: If no tensors are provided, or if any tensor has a dtype not + in ``valid_dtypes``. + + Example: + from executorch.backends.arm.operators.operator_validation_utils import \ + validate_valid_dtype + import serializer.tosa_serializer as ts + + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT32], + output.tosa_spec, + ) + + """ + if not tensors: + raise ValueError( + f"{op_name}: Input tensor list is empty, cannot validate dtypes" + ) + + if not isinstance(valid_dtypes, List): + valid_dtypes = [valid_dtypes] + + if not isinstance(tensors, List): + tensors = [tensors] + + for tensor in tensors: + if tensor.dtype not in valid_dtypes: + valid_names = [str(dtype) for dtype in valid_dtypes] + got_name = str(tensor.dtype) + raise ValueError( + f"Expected tensor {tensor.name} in {op_name} to have one of the " + f"following dtypes: {valid_names}, got: {got_name}" + ) + + +def validate_cf_extension(op_name: str, tosa_spec: TosaSpecification) -> None: + """Ensure that the requested control-flow operator is supported by the active TOSA spec.""" + if not isinstance(tosa_spec, Tosa_1_00): + raise ValueError( + f"Got TOSA version {tosa_spec.version}, that does not support extensions." + ) + if not tosa_spec.support_extension("cf"): + raise ValueError( + f"Trying to lower {op_name}, but TOSA specification {tosa_spec} does not " + "support the cf extension." + ) + + +def adjust_pooling_pad_if_needed( + input_size: int, kernel_size: int, stride: int, pad: int, ceil_mode: bool +) -> int: + """Compute the post padding needed for pooling. + + ATen pooling uses a single symmetric ``pad`` per dimension and rounds the + output size up or down depending on ``ceil_mode``. TOSA requires distinct + pre- and post-padding values that satisfy: + + output_size == (input_size + pre_pad + post_pad - kernel_size) / stride + 1 + + This function returns the required ``post_pad`` given a symmetric ``pad``. + + Args: + input_size (int): Input size. + kernel_size (int): Kernel size. + stride (int): Stride size. + pad (int): Symmetric padding specified by ATen. + ceil_mode (bool): Use ceil when computing output size. + + Returns: + int: Post-padding to satisfy the TOSA formula. + + """ + if ceil_mode: + output_size = ceil((input_size - kernel_size + 2 * pad) / stride) + 1 + else: + output_size = floor((input_size - kernel_size + 2 * pad) / stride) + 1 + + # Solve for post_pad from + # output_size = (input_size + pre_pad + post_pad - kernel_size) / stride + 1 + adjusted_post_pad = (output_size - 1) * stride - input_size + kernel_size - pad + + return adjusted_post_pad diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_binary.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_binary.py new file mode 100644 index 0000000..3e8cda7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_binary.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, Callable, List + +import torch +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def binary_operator_factory( + bw_target: str, tosa_op, attr_builder: Callable[[Any], None] +): + """Creates and registers NodeVisitors for operators that have two inputs and map directly to a TOSA op.""" + + class BinaryOperator(NodeVisitor): + target = bw_target + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + + if self.target in [ + "aten.bitwise_and.Tensor", + "aten.bitwise_xor.Tensor", + "aten.bitwise_or.Tensor", + "aten.bitwise_left_shift.Tensor", + ]: + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32], + output.tosa_spec, + ) + if self.target in [ + "aten.logical_and.default", + "aten.logical_xor.defaul", + "aten.logical_or.default", + ]: + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.BOOL], + output.tosa_spec, + ) + attr = ts.TosaSerializerAttribute() + attr_builder(attr) + self._serialize_operator( + node, + tosa_graph, + tosa_op, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) + + register_node_visitor(BinaryOperator) + + +binary_operator_factory( + "aten.bitwise_and.Tensor", + ts.Op.BITWISE_AND, + lambda attr: attr.BitwiseAndAttribute(), +) +binary_operator_factory( + "aten.bitwise_xor.Tensor", + ts.Op.BITWISE_XOR, + lambda attr: attr.BitwiseXorAttribute(), +) +binary_operator_factory( + "aten.bitwise_or.Tensor", ts.Op.BITWISE_OR, lambda attr: attr.BitwiseOrAttribute() +) +binary_operator_factory( + "aten.logical_and.default", + ts.Op.LOGICAL_AND, + lambda attr: attr.LogicalAndAttribute(), +) +binary_operator_factory( + "aten.logical_xor.default", + ts.Op.LOGICAL_XOR, + lambda attr: attr.LogicalXorAttribute(), +) +binary_operator_factory( + "aten.logical_or.default", ts.Op.LOGICAL_OR, lambda attr: attr.LogicalOrAttribute() +) +binary_operator_factory( + "aten.bitwise_left_shift.Tensor", + ts.Op.LOGICAL_LEFT_SHIFT, + lambda attr: attr.LogicalLeftShiftAttribute(), +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_identity.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_identity.py new file mode 100644 index 0000000..0930d7e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/operators/ops_identity.py @@ -0,0 +1,80 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def identity_operator_factory(identity_target: str): + """ + Creates and registers NodeVisitors for operators that map directly + to a TOSA IDENTITY op. + """ + + class IdentityOperatorVisitor(NodeVisitor): + target = identity_target + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ] + if output.tosa_spec.support_float(): + supported_dtypes += [ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes += [ts.DType.INT48] + if self.tosa_spec.support_extension("int4"): + supported_dtypes += [ts.DType.INT4] + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + # Simply add an identityOp + attr = ts.TosaSerializerAttribute() + attr.IdentityAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.IDENTITY, + [inputs[0].name], + [output.name], + attr, + ) + + register_node_visitor(IdentityOperatorVisitor) + + +identity_operator_factory("aten.alias_copy.default") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/process_node.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/process_node.py new file mode 100644 index 0000000..b85b1b4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/process_node.py @@ -0,0 +1,230 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +import operator +from typing import Any, cast, Dict + +import numpy as np +import torch +import torch.fx +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import NodeVisitor +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.arm.tosa.utils import tosa_shape +from torch._export.utils import ( + get_buffer, + get_lifted_tensor_constant, + get_param, + is_buffer, + is_lifted_tensor_constant, + is_param, +) +from torch.export.exported_program import ExportedProgram + + +def process_call_function( + node: torch.fx.Node, + tosa_graph: Any, + node_visitors: Dict[str, NodeVisitor], + tosa_spec: TosaSpecification, +): + # Unpack arguments and convert + try: + inputs = [TosaArg(arg, tosa_spec) for arg in node.args] + except ValueError as e: + raise ValueError(f"Failed processing args to op:\n{node}") from e + + # Convert output (this node itself) + try: + output = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing call_function: {node.name}. " + "Is the original torch function supported?" + ) from e + + if not output.multiple_output_names: + tosa_graph.currRegion.currBasicBlock.addTensor( + output.name, tosa_shape(output.shape, output.dim_order), output.dtype + ) + + # Get item nodes just add tensors, no node visitor is needed. + if node.target == operator.getitem: + return + + # Visiting each Node + if node.target.__name__ in node_visitors: # type: ignore[union-attr] + node_visitors[node.target.__name__].define_node( # type: ignore[union-attr] + node, + tosa_graph, + inputs, + output, + ) + else: + raise RuntimeError(f"Unknown operator {node.target} for TOSA : {tosa_spec}") + + +def process_inputs( + node: torch.fx.Node, + tosa_graph: Any, + tosa_spec: TosaSpecification, +): + """Serialize an input node""" + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing input placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + + input_shape = tosa_arg.shape + input_dim_order = tosa_arg.dim_order + tensor = ts.TosaSerializerTensor( + tosa_arg.name, + tosa_shape(input_shape, input_dim_order), + tosa_arg.dtype, + data=None, + ) + tosa_graph.addInputTensor(tensor) + + +def process_inputs_to_parameters( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + tosa_spec: TosaSpecification, +): + """Serialize bias and non-quantized weights""" + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing parameter placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + parameter_data = get_param(edge_program, node) + + if not isinstance(parameter_data, torch.Tensor): + raise TypeError( + f"Expected parameter '{node.name}' to be a torch.Tensor, got " + f"{type(parameter_data).__name__}" + ) + parameter_values = parameter_data.detach().numpy() + + parameter_values = np.transpose(parameter_values, tosa_arg.dim_order) + + tosa_graph.addConst( + parameter_values.shape, tosa_arg.dtype, parameter_values, name=tosa_arg.name + ) + + +def process_inputs_to_buffers( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + tosa_spec: TosaSpecification, +): + """Serialize quantized weights""" + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing buffer placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + buffer_data = get_buffer(edge_program, node) + + if not isinstance(buffer_data, torch.Tensor): + raise TypeError( + f"Expected buffer '{node.name}' to be a torch.Tensor, got " + f"{type(buffer_data).__name__}" + ) + buffer_values = buffer_data.detach().numpy() + + # TODO: fragile code for temporary fix + # the mean and var tensors are also stored here but they have shape (1, ) + # we only transpose weights here + buffer_values = np.transpose(buffer_values, tosa_arg.dim_order) + + tosa_graph.addConst( + buffer_values.shape, tosa_arg.dtype, buffer_values, name=tosa_arg.name + ) + + +def process_inputs_to_lifted_tensor_constants( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + tosa_spec: TosaSpecification, +): + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing lifted tensor constant placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + tensor = get_lifted_tensor_constant(edge_program, node) + tensor_data = tensor.detach().numpy() # type: ignore[union-attr] + tensor_values = np.transpose(tensor_data, tosa_arg.dim_order) + + tosa_graph.addConst( + tensor_values.shape, tosa_arg.dtype, tensor_values, name=tosa_arg.name + ) + + +def _is_submodule_input( + node: torch.fx.Node, containing_graph_module: torch.fx.GraphModule +) -> bool: + """Determines whether 'node' is an input to a submodule of 'containing_graph_module'.""" + if node.op != "placeholder": + return False + return node.meta.get("is_input", False) + + +def process_placeholder( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + containing_graph_module: torch.fx.GraphModule | None, + tosa_spec: TosaSpecification, +): + """Wrapper for processing and serializing all types of placeholders""" + if node.name != node.target: + raise ValueError( + f"Placeholder name '{node.name}' does not match target '{node.target}'" + ) + if len(node.args) != 0: + raise ValueError(f"Placeholder '{node.name}' must not have default values") + + if node.name in edge_program.graph_signature.user_inputs: + process_inputs(node, tosa_graph, tosa_spec) + elif containing_graph_module and _is_submodule_input(node, containing_graph_module): + process_inputs(node, tosa_graph, tosa_spec) + elif is_param(edge_program, node): + process_inputs_to_parameters(node, tosa_graph, edge_program, tosa_spec) + elif is_buffer(edge_program, node): + process_inputs_to_buffers(node, tosa_graph, edge_program, tosa_spec) + elif is_lifted_tensor_constant(edge_program, node): + process_inputs_to_lifted_tensor_constants( + node, tosa_graph, edge_program, tosa_spec + ) + elif node.name in edge_program.graph_signature.inputs_to_lifted_custom_objs: + raise NotImplementedError( + "Placeholder is of type 'lifted custom object' which is not supported." + ) + else: + raise RuntimeError(f"Placeholder '{node.name}' is of unknown type.") + + +def process_output(node: torch.fx.Node, tosa_graph: Any, tosa_spec: TosaSpecification): + for output in cast(tuple[torch.fx.Node, ...], node.args[0]): + output_arg = TosaArg(output, tosa_spec) + tosa_graph.addOutputTensor( + tosa_graph.currRegion.currBasicBlock.tensors[output_arg.name] + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/TARGETS new file mode 100644 index 0000000..1a02340 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/TARGETS @@ -0,0 +1,54 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +# Exposed through __init__.py +runtime.python_library( + name = "quantization_config", + srcs = ["quantization_config.py"], + deps = [ + "//caffe2:torch", + "//pytorch/ao:torchao", + ], +) + +# Exposed through __init__.py +runtime.python_library( + name = "arm_quantizer", + srcs = ["arm_quantizer.py"], + deps = [ + ":arm_quantizer_utils", + ":quantization_annotator", + "//caffe2:torch", + "//executorch/exir:lib", + "//pytorch/ao:torchao", + ], +) + +runtime.python_library( + name = "quantization_annotator", + srcs = ["quantization_annotator.py"], + deps = [ + ":arm_quantizer_utils", + ":quantization_config", + "//caffe2:torch", + "//pytorch/ao:torchao", + ], +) + +runtime.python_library( + name = "arm_quantizer_utils", + srcs = ["arm_quantizer_utils.py"], + deps = [ + ":quantization_config", + "//pytorch/ao:torchao", + ], +) + +runtime.python_library( + name = "lib", + srcs = ["__init__.py"], + deps = [ + ":arm_quantizer", + ":quantization_config", + ":arm_quantizer_utils", + ] +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/__init__.py new file mode 100644 index 0000000..2018b84 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/__init__.py @@ -0,0 +1,35 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Expose quantizer APIs and load optional quantized kernels. + +Import the public quantizer classes and configuration helpers for Arm +backends. Attempt to load portable and quantized libraries; fall back to a +log message if unavailable. +""" + +from .quantization_config import QuantizationConfig # noqa # usort: skip +from .arm_quantizer import ( # noqa + EthosUQuantizer, + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, + VgfQuantizer, +) + +# Used in tests +from .arm_quantizer_utils import is_annotated # noqa + +# Load quantized ops library. +try: + import executorch.extension.pybindings.portable_lib + import executorch.kernels.quantized # noqa +except: + import logging + + logging.info( + "Failed to load portable_lib and quantized_aot_lib. To run quantized kernels AOT, either build " + "Executorch with pybindings, or load your own custom built op library using torch.ops.load_library." + ) + del logging diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer.py new file mode 100644 index 0000000..fb65455 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer.py @@ -0,0 +1,710 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Quantizer for Arm backend +# + +from __future__ import annotations + +import functools +from typing import Any, Callable, Dict, Iterable, List, Optional + +import torch +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from executorch.backends.arm.ethosu import EthosUCompileSpec + +from executorch.backends.arm.quantizer import QuantizationConfig +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.common.arm_compile_spec import ( + ArmCompileSpec, +) # isort: skip +from executorch.backends.arm.vgf import VgfCompileSpec +from executorch.exir.graph_module import get_cond_while_submodules + +from torch.fx import GraphModule, Node +from torchao.quantization.pt2e import ( + FakeQuantize, + FusedMovingAvgObsFakeQuantize, + HistogramObserver, + MinMaxObserver, + MovingAverageMinMaxObserver, + ObserverOrFakeQuantizeConstructor, + PerChannelMinMaxObserver, + PlaceholderObserver, +) +from torchao.quantization.pt2e.quantize_pt2e import ( + convert_pt2e, + prepare_pt2e, + prepare_qat_pt2e, +) + +from torchao.quantization.pt2e.quantizer import ( + annotate_input_qspec_map, + annotate_output_qspec, + get_module_name_filter, + QuantizationSpec, + Quantizer, +) + +from .arm_quantizer_utils import is_annotated, mark_node_as_annotated +from .quantization_annotator import annotate_graph + +__all__ = [ + "TOSAQuantizer", + "EthosUQuantizer", + "VgfQuantizer", + "get_symmetric_a16w8_quantization_config", + "get_symmetric_quantization_config", +] + + +@functools.lru_cache +def get_symmetric_quantization_config( + is_per_channel: bool = True, + is_qat: bool = False, + is_dynamic: bool = False, + act_qmin: int = -128, + act_qmax: int = 127, + weight_qmin: int = -127, + weight_qmax: int = 127, +) -> QuantizationConfig: + """Create symmetric quantization config for activations and weights. + + Args: + is_per_channel (bool): Whether to use per-channel quantization for + weights. + is_qat (bool): Whether the configuration targets quantization aware + training. + is_dynamic (bool): Whether to generate dynamic activation observers. + act_qmin (int): Minimum activation quantization value. + act_qmax (int): Maximum activation quantization value. + weight_qmin (int): Minimum weight quantization value. + weight_qmax (int): Maximum weight quantization value. + + Returns: + QuantizationConfig: Quantization settings for activations, weights, and + bias. + + """ + extra_args: Dict[str, Any] = {"eps": 2**-12} + if is_qat: + if is_dynamic: + act_observer_or_fake_quant_ctr = FakeQuantize + dynamic_quant_observer = MovingAverageMinMaxObserver.with_args( + averaging_constant=1 + ) + extra_args["observer"] = dynamic_quant_observer + else: + act_observer_or_fake_quant_ctr = FusedMovingAvgObsFakeQuantize # type: ignore[assignment] + else: + if is_dynamic: + act_observer_or_fake_quant_ctr = PlaceholderObserver # type: ignore[assignment] + else: + act_observer_or_fake_quant_ctr = HistogramObserver # type: ignore[assignment] + + act_quantization_spec = QuantizationSpec( + dtype=torch.int8, + quant_min=act_qmin, + quant_max=act_qmax, + qscheme=torch.per_tensor_affine, + is_dynamic=is_dynamic, + observer_or_fake_quant_ctr=act_observer_or_fake_quant_ctr.with_args( + **extra_args, + ), + ) + + # Setup quantization config for weights + weight_qscheme = ( + torch.per_channel_symmetric if is_per_channel else torch.per_tensor_symmetric + ) + weight_observer_or_fake_quant_ctr: ObserverOrFakeQuantizeConstructor = ( + MinMaxObserver + ) + + # Determine the right observer/fake-quant constructor + if is_qat: + if is_per_channel: + weight_observer_or_fake_quant_ctr = FakeQuantize.with_args( + observer=PerChannelMinMaxObserver, + quant_min=weight_qmin, + quant_max=weight_qmax, + dtype=torch.qint8, + qscheme=torch.per_channel_symmetric, + reduce_range=False, + ch_axis=0, + **extra_args, + ) + else: + # Set plain fake-quant with true min/max + weight_observer_or_fake_quant_ctr = FakeQuantize.with_args(**extra_args) + else: + # PTQ: set min/max observer + weight_observer_or_fake_quant_ctr = ( + PerChannelMinMaxObserver if is_per_channel else MinMaxObserver + ) + weight_observer_or_fake_quant_ctr = weight_observer_or_fake_quant_ctr.with_args( + **extra_args, + ) + + weight_quantization_spec = QuantizationSpec( + dtype=torch.int8, + quant_min=weight_qmin, + quant_max=weight_qmax, + qscheme=weight_qscheme, + ch_axis=0, + is_dynamic=False, + observer_or_fake_quant_ctr=weight_observer_or_fake_quant_ctr, + ) + + bias_quantization_spec = None + if is_dynamic: + quantization_config = QuantizationConfig( + act_quantization_spec, + None, + weight_quantization_spec, + bias_quantization_spec, + ) + else: + quantization_config = QuantizationConfig( + act_quantization_spec, + act_quantization_spec, + weight_quantization_spec, + bias_quantization_spec, + ) + return quantization_config + + +def get_symmetric_a8w4_quantization_config( + is_per_channel: bool = True, is_qat: bool = True, is_dynamic: bool = False +): + return get_symmetric_quantization_config( + is_per_channel, is_qat, is_dynamic, weight_qmin=-7, weight_qmax=7 + ) + + +@functools.lru_cache +def get_symmetric_a16w8_quantization_config( + is_per_channel: bool = True, + is_qat: bool = False, + is_dynamic: bool = False, + weight_qmin: int = -127, + weight_qmax: int = 127, + epsilon: float = 2**-12, +) -> QuantizationConfig: + """16A8W quantization config: 16-bit activations, 8-bit weights. + + This configuration provides better accuracy than 8A8W while maintaining + reasonable memory usage through 8-bit weights. + + Args: + is_per_channel (bool): Whether to use per-channel quantization for + weights. + is_qat (bool): Whether this is for quantization aware training. + is_dynamic (bool): Whether to use dynamic quantization. + weight_qmin (int): Minimum quantization value for weights. + weight_qmax (int): Maximum quantization value for weights. + epsilon (float): Value used to pad observed [qmin, qmax] before initial + zero-point and scale calculation. + + Returns: + QuantizationConfig: Configuration with 16-bit activations and 8-bit + weights. + + """ + extra_args: Dict[str, Any] = {"eps": epsilon} + + # Setup observer/fake-quant for 16-bit activations + if is_qat: + if is_dynamic: + act_observer_or_fake_quant_ctr = FakeQuantize + dynamic_quant_observer = MovingAverageMinMaxObserver.with_args( + averaging_constant=1 + ) + extra_args["observer"] = dynamic_quant_observer + else: + act_observer_or_fake_quant_ctr = FusedMovingAvgObsFakeQuantize # type: ignore[assignment] + else: + if is_dynamic: + act_observer_or_fake_quant_ctr = PlaceholderObserver # type: ignore[assignment] + else: + # HistogramObserver works well for 16-bit range + act_observer_or_fake_quant_ctr = HistogramObserver # type: ignore[assignment] + + # 16-bit activation quantization spec + act_quantization_spec = QuantizationSpec( + dtype=torch.int16, + quant_min=torch.iinfo(torch.int16).min + 1, # -32767 + quant_max=torch.iinfo(torch.int16).max, # 32767 + qscheme=torch.per_tensor_symmetric, + is_dynamic=is_dynamic, + observer_or_fake_quant_ctr=act_observer_or_fake_quant_ctr.with_args( + **extra_args, + ), + ) + + # Instead of reconstructing quantization_config, just clone and update as needed + # Clone the quantization_config from get_symmetric_quantization_config and update activation spec + base_config = get_symmetric_quantization_config( + is_per_channel=is_per_channel, + is_qat=is_qat, + is_dynamic=is_dynamic, + ) + # Replace activation quantization spec with 16-bit version + if is_dynamic: + quantization_config = QuantizationConfig( + act_quantization_spec, # 16-bit input activations + None, + base_config.weight, # 8-bit weights from base config + None, + ) + else: + quantization_config = QuantizationConfig( + act_quantization_spec, # 16-bit input activations + act_quantization_spec, # 16-bit output activations + base_config.weight, # 8-bit weights from base config + None, + ) + return quantization_config + + +NodeFilterType = Callable[[Node], bool] +"""Type for a Node Filter used by annotators. + +A Node filter is a function that takes a Node and returns whether the node +should be annotated or not. + +""" + + +def _get_module_type_filter(tp: Callable) -> NodeFilterType: + """Get the module_type_filter function for a given module type. + + The filter accepts a node and checks if the node comes from a module that + has a certain module type. + + Args: + tp (Callable): Module class to match against the graph node metadata. + + Returns: + NodeFilterType: Predicate that returns True for nodes from the module + type. + + For example: + node: linear_op = call_function[...](...) # type Block -> Sub -> Linear + + >> module_type_filter = _get_module_type_filter(Sub) + >> print(module_type_filter(node)) + True # the node is from the submodule `Sub` (same for `Block` and `Linear`) + + """ + tp_str = tp.__module__ + "." + tp.__qualname__ + + def module_type_filter(n: Node) -> bool: + """Return True if the node originates from the target module type.""" + # node_stack example: { + # 'L__self___sub': ("L['self'].sub", ), + # 'L__self___sub_linear': ("L['self'].sub.linear", ) + # } + nn_module_stack = n.meta.get("nn_module_stack", {}) + types = [t for _, t in nn_module_stack.values()] + return tp_str in types + + return module_type_filter + + +def _get_not_module_type_or_name_filter( + tp_list: List[Callable], module_name_list: List[str] +) -> NodeFilterType: + """Create a filter that excludes provided module types and names. + + Args: + tp_list (List[Callable]): Module types to exclude from annotation. + module_name_list (List[str]): Module names to exclude from annotation. + + Returns: + NodeFilterType: Filter that returns True when the node does not match + any provided module type or name. + + """ + module_type_filters = [_get_module_type_filter(tp) for tp in tp_list] + module_name_list_filters = [get_module_name_filter(m) for m in module_name_list] + + def not_module_type_or_name_filter(n: Node) -> bool: + """Return True when the node matches none of the blocked filters.""" + return not any(f(n) for f in module_type_filters + module_name_list_filters) + + return not_module_type_or_name_filter + + +def _get_composite_filter( + filters: List[NodeFilterType], reduce_func: Callable[[Iterable[bool]], bool] +): + """Get a composite filter function given a list of filters, the composite + filter accepts a node and checks it with every filter in the list. The + filters' outputs are reduced into a single bool output using reduce_func. + + Example: + >>> filters = [ + ... _get_module_name_filter("blocks.sub"), + ... _get_module_type_filter(torch.nn.Linear), + ... ] + >>> composite = _get_composite_filter(filters, any) + >>> composite(node) # True if any individual filter matches + True + """ + + def composite_filter(n: Node) -> bool: + return reduce_func((f(n) for f in filters)) + + return composite_filter + + +class TOSAQuantizer(Quantizer): + """Manage quantization annotations for TOSA-compatible backends.""" + + def __init__( + self, compile_spec_or_tosa_spec: TosaSpecification | ArmCompileSpec + ) -> None: + super().__init__() + self.compile_spec: ArmCompileSpec + if isinstance(compile_spec_or_tosa_spec, TosaSpecification): + from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec + + self.compile_spec = TosaCompileSpec(compile_spec_or_tosa_spec) + self.tosa_spec = self.compile_spec.tosa_spec + elif isinstance(compile_spec_or_tosa_spec, ArmCompileSpec): + self.compile_spec = compile_spec_or_tosa_spec + self.tosa_spec = self.compile_spec.tosa_spec + else: + raise TypeError( + f"TOSAQuantizer constructor expects " + f"a TosaSpecification or compile_spec list, " + f"got {type(compile_spec_or_tosa_spec)}" + ) + + self.global_config: Optional[QuantizationConfig] = None + self.io_config: Optional[QuantizationConfig] = None + self.module_type_config: Dict[Callable, Optional[QuantizationConfig]] = {} + self.module_name_config: Dict[str, Optional[QuantizationConfig]] = {} + + def set_global(self, quantization_config: QuantizationConfig) -> TOSAQuantizer: + """Set quantization_config for submodules not matched by other filters. + + Args: + quantization_config (QuantizationConfig): Configuration to apply to + modules that are not captured by name or type filters. + + """ + self.global_config = quantization_config + return self + + def set_module_type( + self, module_type: Callable, quantization_config: QuantizationConfig + ) -> TOSAQuantizer: + """Set quantization_config for submodules with a given module type. + + For example, calling set_module_type(Sub) quantizes supported patterns + in each Sub instance with the provided quantization_config. + + Args: + module_type (Callable): Type whose submodules should use the + provided quantization configuration. + quantization_config (QuantizationConfig): Configuration to apply to + submodules of the given type. + + """ + self.module_type_config[module_type] = quantization_config + return self + + def set_module_name( + self, module_name: str, quantization_config: Optional[QuantizationConfig] + ) -> TOSAQuantizer: + """Set quantization_config for submodules with a given module name. + + For example, calling set_module_name("blocks.sub") quantizes supported + patterns for that submodule with the provided quantization_config. + + Args: + module_name (str): Fully qualified module name to configure. + quantization_config (QuantizationConfig): Configuration applied to + the named submodule. + + """ + # Validate that quantization_config is provided + self.module_name_config[module_name] = quantization_config + return self + + def set_io(self, quantization_config: QuantizationConfig) -> TOSAQuantizer: + """Set quantization_config for input and output nodes. + + Args: + quantization_config (QuantizationConfig): Configuration describing + activation quantization for model inputs and outputs. + + """ + self.io_config = quantization_config + return self + + def _set_disallow_tfa_for_nodes(self, model: GraphModule) -> None: + """Populate `disallow_tfa` metadata for each FX node. + + Transform-for-annotation passes inspect this flag to decide whether + they may transform a node. Typically, a node should not be transformed + in case it is not to be quantized, which is relevant for partially + quantized models. + """ + + unquantized_modules_types = [ + m + for m in self.module_type_config.keys() + if self.module_type_config[m] is None + ] + module_filters = [ + _get_module_type_filter(module_type) + for module_type in unquantized_modules_types + ] + # Create a composite filter that returns True if any of the + # "unquantized" modules contains the node. + composite_filter = _get_composite_filter(module_filters, any) + + for node in model.graph.nodes: + node.meta[DISALLOW_TFA_META_KEY] = composite_filter(node) + + def transform_for_annotation(self, model: GraphModule) -> GraphModule: + """Transform the graph to prepare it for quantization annotation. + + Currently transforms scalar values to tensor attributes. + + Args: + model (GraphModule): Model whose graph will be transformed. + + Returns: + GraphModule: Transformed model prepared for annotation. + + """ + + self._set_disallow_tfa_for_nodes(model) + + # TODO: Fix the need to lazily import this. + from executorch.backends.arm._passes import ArmPassManager + + pass_manager = ArmPassManager(self.compile_spec) + return pass_manager.transform_for_annotation_pipeline(graph_module=model) + + def annotate(self, model: GraphModule) -> GraphModule: + """Annotate the graph with the configured quantization settings. + + Currently only does static quantization annotation. + + Args: + model (GraphModule): Model to annotate statically. + + Returns: + GraphModule: Annotated model ready for export. + + """ + model = self._annotate_for_static_quantization_config(model) + return model + + def _annotate_all_static_patterns( + self, + model: GraphModule, + quantization_config: Optional[QuantizationConfig], + filter_fn: Optional[Callable[[Node], bool]] = None, + ) -> GraphModule: + """Annotate all static patterns registered for the backend. + + Args: + model (GraphModule): Model to annotate statically. + quantization_config (Optional[QuantizationConfig]): Quantization + specs for input activations, output activations, weights, and + biases. + filter_fn (Optional[Callable[[Node], bool]]): Optional node filter + specifying which nodes to annotate. + + Returns: + GraphModule: Model populated with quantization annotations. + + """ + # TODO: implement the support for None to be canceling out previous annotations + if quantization_config is None: + return model + + annotate_graph(model, quantization_config, filter_fn) + return model + + def _annotate_for_static_quantization_config( + self, model: GraphModule + ) -> GraphModule: + """Match QuantizationConfigs to modules before annotating patterns. + + Args: + model (GraphModule): Model whose modules are being matched to + quantization configs. + + Returns: + GraphModule: Annotated model after applying configured filters. + + """ + if self.io_config: + self._annotate_io(model, self.io_config) + + module_name_list = list(self.module_name_config.keys()) + for module_name, config in self.module_name_config.items(): + self._annotate_all_static_patterns( + model, config, get_module_name_filter(module_name) + ) + + tp_list = list(self.module_type_config.keys()) + for module_type, config in self.module_type_config.items(): + self._annotate_all_static_patterns( + model, config, _get_module_type_filter(module_type) + ) + + self._annotate_all_static_patterns( + model, + self.global_config, + _get_not_module_type_or_name_filter(tp_list, module_name_list), + ) + + return model + + def _annotate_io( + self, + model: GraphModule, + quantization_config: QuantizationConfig, + ): + """Annotate graph inputs and outputs with the provided configuration. + + Args: + model (GraphModule): GraphModule being annotated. + quantization_config (QuantizationConfig): Activation qspecs to apply + to IO nodes. + + """ + for node in model.graph.nodes: + if is_annotated(node): + continue + if node.op == "placeholder" and len(node.users) > 0: + annotate_output_qspec( + node, + quantization_config.get_output_act_qspec(), + ) + mark_node_as_annotated(node) + if node.op == "output": + for parent in node.all_input_nodes: + annotate_input_qspec_map( + node, parent, quantization_config.get_input_act_qspec() + ) + mark_node_as_annotated(node) + + def validate(self, model: GraphModule) -> None: + """Validate the quantization results. Currently, this includes: + - Ensure tensor inputs to each operator live on the same device. + + Args: + model (GraphModule): GraphModule being validated. + Raises: + ValueError: If tensor inputs for any operator span more than one + device. + """ + for node in model.graph.nodes: + if node.op != "call_function": + continue + + devices = set() + for arg_node in node.all_input_nodes: + meta_val = arg_node.meta.get("val", None) + if meta_val is None: + continue + if isinstance(meta_val, (tuple, list)): + for tensor in meta_val: + devices.add( + str( + getattr( + tensor, + "device", + f"Could not get device from {tensor}", + ) + ) + ) + else: + devices.add( + str( + getattr( + meta_val, + "device", + f"Could not get device from {meta_val}", + ) + ) + ) + + if len(devices) > 1: + raise ValueError( + f"Quantizer detected operator {node.name} with different device inputs: {devices}." + ) + + def quantize_with_submodules( + self, + model: GraphModule, + calibration_samples: list[tuple], + is_qat: bool = False, + ): + """Quantizes a GraphModule in a way such that conditional submodules are handled properly. + + Args: + model (GraphModule): The model to quantize. + calibration_samples (list[tuple]): A list of inputs to used to + calibrate the model during quantization. To properly calibrate a + model with submodules, at least one sample per code path is + needed. + is_qat (bool): Whether to do quantization aware training or not. + + Returns: + GraphModule: The quantized model. + + """ + prepare_fn = prepare_qat_pt2e if is_qat else prepare_pt2e + + prepared = prepare_fn(model, self) + for name, submodule, _ in get_cond_while_submodules(prepared): + prepared.set_submodule(name, prepare_fn(submodule, self), strict=True) + for inp in calibration_samples: + prepared(*inp) + + for name, submodule, _ in get_cond_while_submodules(prepared): + prepared.set_submodule(name, convert_pt2e(submodule), strict=True) + converted = convert_pt2e(prepared) + return converted + + +class EthosUQuantizer(TOSAQuantizer): + """Quantizer supported by the Arm Ethos-U backend. + + Args: + compile_spec (EthosUCompileSpec): Backend compile specification for + Ethos-U targets. + + """ + + def __init__(self, compile_spec: EthosUCompileSpec) -> None: + super().__init__(compile_spec) + + +class VgfQuantizer(TOSAQuantizer): + """Quantizer supported by the Arm Vgf backend. + + Args: + compile_spec (VgfCompileSpec): Backend compile specification for Vgf + targets. + + """ + + def __init__(self, compile_spec: VgfCompileSpec) -> None: + super().__init__(compile_spec) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer_utils.py new file mode 100644 index 0000000..7bd8e00 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/arm_quantizer_utils.py @@ -0,0 +1,76 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide utilities for quantization annotations. + +Use these helpers to check and mark annotation state when working with +``QuantizationAnnotation`` entries in FX node metadata. + +""" + +from typing import cast + +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo + +from torch.fx import Node + +from torchao.quantization.pt2e.quantizer import QuantizationAnnotation +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + + +def is_annotated(node: Node) -> bool: + """Return True if the node is annotated. + + Args: + node (Node): FX node to inspect. + + Returns: + bool: True if ``Q_ANNOTATION_KEY`` exists and ``_annotated`` is set. + + """ + return ( + Q_ANNOTATION_KEY in node.meta + and cast(QuantizationAnnotation, node.meta[Q_ANNOTATION_KEY])._annotated + ) + + +def is_output_annotated(node: Node) -> bool: + """Return True if the node's output is annotated. + + Args: + node (Node): FX node to inspect. + + Returns: + bool: True if annotated and an output qspec is present. + + """ + if Q_ANNOTATION_KEY in node.meta: + annotation = cast(QuantizationAnnotation, node.meta[Q_ANNOTATION_KEY]) + return annotation._annotated and annotation.output_qspec is not None + else: + return False + + +def mark_node_as_annotated(node: Node) -> None: + """Mark a node as annotated. + + Create an empty ``QuantizationAnnotation`` on the node when missing and set + its ``_annotated`` flag to True. + + Args: + node (Node): FX node to update. + + """ + if Q_ANNOTATION_KEY not in node.meta: + node.meta[Q_ANNOTATION_KEY] = QuantizationAnnotation() + annotation_info = ArmAnnotationInfo( + quantized=True, + ) + node.meta[Q_ANNOTATION_KEY]._annotated = True + meta_custom = node.meta.get("custom", {}) + meta_custom[ArmAnnotationInfo.CUSTOM_META_KEY] = dict(annotation_info) + node.meta["custom"] = meta_custom diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_annotator.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_annotator.py new file mode 100644 index 0000000..34a9027 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_annotator.py @@ -0,0 +1,815 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide quantization annotation logic for Arm backends. + +This module computes per-node quantization properties and applies input/output +annotations to FX graphs using TorchAO qspecs. + +""" + +import logging +import operator +from dataclasses import dataclass +from typing import Callable, cast, List, Optional, Sequence + +import torch +import torch.fx +from executorch.backends.arm.common.debug import get_node_debug_info +from executorch.backends.arm.common.type import ensure_type +from executorch.backends.arm.quantizer import QuantizationConfig +from torch._subclasses import FakeTensor + +from torch.fx import Node +from torchao.quantization.pt2e.quantizer import ( + annotate_input_qspec_map, + annotate_output_qspec, + QuantizationSpecBase, + SharedQuantizationSpec, +) + +from .arm_quantizer_utils import ( + is_annotated, + is_output_annotated, + mark_node_as_annotated, +) + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class _QuantProperty: + """Specify how the input/output at 'index' must be quantized.""" + + index: int + qspec: QuantizationSpecBase | List[QuantizationSpecBase] + optional: bool = False + mark_annotated: bool = False + + +class _OpQuantProperties: + """Collect input/output quantization properties for a node. + + Attributes: + quant_inputs (List[_QuantProperty]): Quantization specs for inputs + indexed by argument positions. + quant_output (Optional[_QuantProperty]): Quantization spec for the + node's output when applicable. + + """ + + def __init__(self): + self.quant_inputs: List[_QuantProperty] = [] + self.quant_output: Optional[_QuantProperty] = None + + +def _as_list(x): + """Return ``x`` wrapped as a list if needed. + + Args: + x: Value or list of values. + + Returns: + list: ``x`` if already a list; otherwise ``[x]``. + + """ + if isinstance(x, (list, tuple)): + return x + else: + return [ + x, + ] + + +def _is_ok_for_quantization( + node: Node, quant_properties: _OpQuantProperties, gm: torch.fx.GraphModule +) -> bool: + """Check if a node can be quantized. + + A node can be quantized if: + - All inputs that are required for quantization are of type `float32` + and are not large scalar values. + - The output of the node itself is of type `float32` and is not a large + scalar. + + Args: + node (Node): The node being analyzed. + quant_properties (_OpQuantProperties): Contains quantization properties + for the node, including input and output quantization specifications. + gm (torch.fx.GraphModule): The graph module containing the computational + graph. + + Returns: + bool: `True` if the node can be quantized, otherwise `False`. + + """ + # Check output + if quant_properties.quant_output is not None: + if _is_non_float_tensor(node): + logger.debug( + "Could not quantize non float tensor for the following output node: " + f"{get_node_debug_info(node, gm)}" + ) + + return False + elif _is_large_scalar(node, gm): + logger.debug( + "Could not quantize large scalar node for the following output node: " + f"{get_node_debug_info(node, gm)}" + ) + + return False + + # Check inputs + for quant_property in quant_properties.quant_inputs: + if quant_property.optional and ( + quant_property.index >= len(node.args) + or node.args[quant_property.index] is None + ): + continue + + for n_arg in _as_list(node.args[quant_property.index]): + if not isinstance(n_arg, Node): + raise TypeError( + f"n_arg must be a Node instance, got {type(n_arg).__name__!r}" + ) + + if _is_non_float_tensor(n_arg): + logger.debug( + "Could not quantize non float tensor for the following input " + f"node: {get_node_debug_info(node, gm)}" + ) + + return False + elif _is_large_scalar(n_arg, gm): + logger.debug( + "Could not quantize large scalar node for the following input " + f"node: {get_node_debug_info(node, gm)}" + ) + + return False + + return True + + +def _get_node_target(module: torch.nn.Module | torch.fx.GraphModule, target_str: str): + """Get an attribute from a module by dotted path. + + Args: + module (torch.nn.Module | torch.fx.GraphModule): Root module. + target_str (str): Dotted attribute path, e.g., ``"sub.weight"``. + + Returns: + Any: Resolved attribute on the module. + + """ + targets = target_str.split(".") + for target in targets[:-1]: + module = module.get_submodule(target) + return getattr(module, targets[-1]) + + +def _is_large_scalar(node: Node, gm: torch.fx.GraphModule): + """Return True if input is a large scalar value. + + Large scalars are skipped because ``torch.histc`` supports values only up + to a certain upper bound. + + """ + HISTC_UPPER_BOUND = 3.4028235e15 + if node.op == "get_attr" and isinstance(node.target, str): + tensor = _get_node_target(gm, node.target) + # torch.histc works until this upper bound + return tensor.numel() == 1 and abs(tensor.item()) > HISTC_UPPER_BOUND + if node.op == "call_function" and node.target in ( + torch.ops.aten.full.default, + torch.ops.aten.full, + torch.ops.aten.fill_.Scalar, + ): + fill_value = cast(float, node.args[1]) + return abs(fill_value) > HISTC_UPPER_BOUND + return False + + +def _is_non_float_tensor(node: Node) -> bool: + """Check if the output of a node has a data type other than `torch.float32`. + + If the output is not `torch.float32`, quantization cannot be performed, as + observers only work with floating-point tensors. + + Args: + node (Node): The node to check the output(s) for. + + Returns: + bool: `True` if the data type is not float32, otherwise `False`. + + Note: + - If `node.meta["val"]` is a `list`, the function returns `True` if + any element is not an instance of `FakeTensor` or does not have + `torch.float32` as its data type. + - If node.meta["val"] is missing or is not an instance of `FakeTensor`, + the function returns True. + + """ + if "val" in node.meta and isinstance(node.meta["val"], Sequence): + return any( + not isinstance(fake_tensor, FakeTensor) + or fake_tensor.dtype != torch.float32 + for fake_tensor in node.meta["val"] + ) + + if "val" not in node.meta or not isinstance(node.meta["val"], FakeTensor): + return True + + return node.meta["val"].dtype != torch.float32 + + +def _annotate_input(node: Node, quant_property: _QuantProperty): + """Annotate a node's input with the given qspec. + + Maps the specified input argument(s) to the provided quantization spec and + optionally marks the input node(s) as annotated. + + Args: + node (Node): Node whose input should be annotated. + quant_property (_QuantProperty): Input index and qspec(s). + + Raises: + RuntimeError: If the node is already annotated. + TypeError: If an input argument is not a ``Node`` instance. + + """ + if is_annotated(node): + raise RuntimeError( + f"Cannot annotate input: node '{node.name}' is already annotated" + ) + if quant_property.optional and ( + quant_property.index >= len(node.args) + or node.args[quant_property.index] is None + ): + return + + for n_arg, qspec in zip( + _as_list(node.args[quant_property.index]), + _as_list(quant_property.qspec), + strict=True, + ): + if not isinstance(n_arg, Node): + raise TypeError( + f"n_arg must be a Node instance, got {type(n_arg).__name__!r}" + ) + annotate_input_qspec_map(node, n_arg, qspec) + if quant_property.mark_annotated: + mark_node_as_annotated(n_arg) # type: ignore[attr-defined] + + +def _annotate_output(node: Node, quant_property: _QuantProperty): + """Annotate a node's output with the given qspec. + + Args: + node (Node): Node whose output should be annotated. + quant_property (_QuantProperty): Output index and qspec. + + Raises: + RuntimeError: If the node is already annotated. + ValueError: If ``mark_annotated`` is True, ``optional`` is True, or + ``index`` is not zero. + + """ + if is_annotated(node): + raise RuntimeError( + f"Cannot annotate output: node '{node.name}' is already annotated" + ) + if quant_property.mark_annotated: + raise ValueError( + "quant_property.mark_annotated must be False for output annotation" + ) + if quant_property.optional: + raise ValueError("quant_property.optional must be False for output annotation") + if quant_property.index != 0: + raise ValueError("Only one output annotation supported currently") + + annotate_output_qspec(node, quant_property.qspec) + + +def _match_pattern( + node: Node, pattern: List[List], filter_fn: Optional[Callable[[Node], bool]] = None +) -> bool: + """Check whether a node chain matches a pattern. + + Verify a chain of ancestors -> node -> descendants matches the provided + ``pattern``. If ``filter_fn`` is provided, require all nodes in the chain + to pass the filter. Each pattern element is a list of disjunctive node + targets. + + """ + if len(pattern) < 1: + raise ValueError("No pattern provided") + + if filter_fn is not None: + if not filter_fn(node): + return False + if len(pattern) == 1: + # Base case where it has passed the filter_fn. Simply look if node.target is in pattern. + return node.target in pattern[0] + if node.target not in [op for sub_pattern in pattern for op in sub_pattern]: + # node.target not in pattern. No need to look at the rest of the pattern. + return False + # Find the index of this node's target in pattern + idx = [node.target in sub_pattern for sub_pattern in pattern].index(True) + left_pattern = pattern[:idx] + # Exclude idx as this contains node.target which we have already matched + right_pattern = pattern[idx + 1 :] + left_condition = True + right_condition = True + # Recursively look at the rest of the pattern by calling this function for + # node's input and user node with updated patterns. + if len(left_pattern) > 0: + parent = node.all_input_nodes[0] + if len(parent.users) != 1: + return False + left_condition = _match_pattern(parent, left_pattern, filter_fn) + if len(right_pattern) > 0: + right_condition = _match_pattern(list(node.users)[0], right_pattern, filter_fn) + return left_condition and right_condition + + +_conv_ops = [ + torch.ops.aten.conv1d.default, + torch.ops.aten.conv2d.default, + torch.ops.aten.conv2d.padding, + torch.ops.aten.conv3d.default, + torch.ops.aten.conv3d.padding, +] + +_one_to_one = [ + torch.ops.aten.abs.default, + torch.ops.aten.ceil.default, + torch.ops.aten.erf.default, + torch.ops.aten.exp.default, + torch.ops.aten.expm1.default, + torch.ops.aten.elu.default, + torch.ops.aten.floor.default, + torch.ops.aten.log.default, + torch.ops.aten.reciprocal.default, + torch.ops.aten.rsqrt.default, + torch.ops.aten.sigmoid.default, + torch.ops.aten.cos.default, + torch.ops.aten.sin.default, + torch.ops.aten.tanh.default, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.sum.default, + torch.ops.aten.hardsigmoid.default, + torch.ops.aten.hardswish.default, + torch.ops.aten.hardswish_.default, + torch.ops.aten.full_like.default, + torch.ops.aten.zeros_like.default, + torch.ops.aten.pow.Tensor_Scalar, + torch.ops.aten.gelu.default, + torch.ops.aten.sinh.default, + torch.ops.aten.atan.default, + torch.ops.aten.log1p.default, + torch.ops.aten.acosh.default, + torch.ops.aten.sign.default, + torch.ops.aten.asin.default, + torch.ops.aten.atanh.default, + torch.ops.aten.asinh.default, + torch.ops.aten.cosh.default, + torch.ops.aten.acos.default, + torch.ops.aten.cumsum.default, + torch.ops.aten.tan.default, +] + +_one_to_one_shared_input_qspec = [ + torch.ops.aten.squeeze.default, + torch.ops.aten.squeeze_copy.default, + torch.ops.aten.squeeze_copy.dim, + torch.ops.aten.squeeze.dim, + torch.ops.aten.squeeze.dims, + torch.ops.aten.unbind.int, + torch.ops.aten.unsqueeze.default, + torch.ops.aten.unsqueeze_copy.default, + torch.ops.aten.reshape.default, + torch.ops.aten.repeat.default, + torch.ops.aten.repeat_interleave.self_int, + torch.ops.aten.expand_copy.default, + torch.ops.aten.expand.default, + # Disabling these as there seems to be an issue with support for complex + # datatypes in torch: + # torch.ops.aten.view_as_complex.default, + # torch.ops.aten.view_as_complex_copy.default, + # torch.ops.aten.view_as_real.default, + # torch.ops.aten.view_as_real_copy.default, + torch.ops.aten.view.default, + torch.ops.aten.view_as.default, + torch.ops.aten.view_copy.default, + torch.ops.aten._unsafe_view.default, + torch.ops.aten.select.int, + torch.ops.aten.select_copy.int, + torch.ops.aten.slice.Tensor, + torch.ops.aten.slice_copy.Tensor, + torch.ops.aten.split.Tensor, + torch.ops.aten.split_with_sizes.default, + torch.ops.aten.split_copy.Tensor, + torch.ops.aten.transpose.Dimname, + torch.ops.aten.transpose.int, + torch.ops.aten.transpose_copy.int, + torch.ops.aten.t_copy.default, + torch.ops.aten.tile.default, + torch.ops.aten.flip.default, + torch.ops.aten.chunk.default, + torch.ops.aten.contiguous.default, + torch.ops.aten.upsample_bilinear2d.vec, + torch.ops.aten.upsample_nearest2d.vec, + torch.ops.aten.pad.default, + torch.ops.aten.amax.default, + torch.ops.aten.amin.default, + torch.ops.aten.clamp.default, + torch.ops.aten.clamp.Tensor, + torch.ops.aten.unflatten.int, + torch.ops.aten.index_select.default, + torch.ops.aten.index.Tensor, + # Neg operator flips the range, but keps the magnitude the same. + # That is why we force it to use the same qparams and avoid + # dequant -> neg -> requant chain. + torch.ops.aten.neg.default, +] + +_one_to_one_shared_input_or_input_act_qspec = [ + torch.ops.aten.alias.default, + torch.ops.aten.clone.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.mean.default, + torch.ops.aten.mean.dim, + torch.ops.aten.permute.default, + torch.ops.aten.permute_copy.default, + torch.ops.aten.avg_pool2d.default, + torch.ops.aten.max_pool2d.default, + torch.ops.aten.flatten.using_ints, + torch.ops.aten.dropout.default, + torch.ops.aten.dropout_.default, + torch.ops.aten.adaptive_avg_pool2d.default, + torch.ops.aten.alias_copy.default, + torch.ops.aten.pixel_shuffle.default, + torch.ops.aten.pixel_unshuffle.default, +] + + +def get_quant_properties( # noqa: C901 + node: Node, gm: torch.fx.GraphModule, quantization_config +) -> _OpQuantProperties | None: + """Compute quantization properties for a node. + + Determine which inputs and/or outputs should be annotated for quantization + based on the node's operator and surrounding pattern. + + Args: + node (Node): Node to analyze. + gm (torch.fx.GraphModule): Owning graph module. + quantization_config: Source for activation/weight/bias qspecs. + + Returns: + _OpQuantProperties | None: Properties to apply, or ``None`` if the + node is unsupported or not suitable for quantization. + + """ + input_act_qspec = quantization_config.get_input_act_qspec() + weight_qspec = quantization_config.get_weight_qspec() + output_act_qspec = quantization_config.get_output_act_qspec() + bias_qspec = quantization_config.get_bias_qspec(node) + if output_act_qspec is not None: + # Check if output activation qspec is symmetric. In that case + # we avoid conv + relu fusion for quantization annotation. + is_symmetric = output_act_qspec.qscheme == torch.per_tensor_symmetric + else: + is_symmetric = False + + quant_properties = _OpQuantProperties() + + def any_or_hardtanh_min_zero(n: Node): + """Return True for any op or hardtanh with ``min_val == 0``.""" + # Check that if the node is a hardtanh, its min_val is zero + return ( + n.target + not in (torch.ops.aten.hardtanh.default, torch.ops.aten.hardtanh_.default) + or n.args[1] == 0 + ) + + if not is_symmetric and _match_pattern( + node, + [ + _conv_ops, + [torch.ops.aten.batch_norm.default], + [ + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + ], + ], + filter_fn=any_or_hardtanh_min_zero, + ): + if node.target in _conv_ops: + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + elif node.target in ( + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + ): + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + + elif _match_pattern( + node, + [ + _conv_ops, + [torch.ops.aten.batch_norm.default], + ], + ): + if node.target in _conv_ops: + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + elif node.target in [ + torch.ops.aten.batch_norm.default, + ]: + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif not is_symmetric and _match_pattern( + node, + [ + [ + *_conv_ops, + torch.ops.aten.linear.default, + ], + [ + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + ], + ], + any_or_hardtanh_min_zero, + ): + if node.target in ( + *_conv_ops, + torch.ops.aten.linear.default, + ): + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + else: + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in ( + *_conv_ops, + torch.ops.aten.linear.default, + ): + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in ( + torch.ops.aten.add.Tensor, + torch.ops.aten.add_.Tensor, + torch.ops.aten.sub.Tensor, + torch.ops.aten.sub_.Tensor, + torch.ops.aten.matmul.default, + torch.ops.aten.mm.default, + torch.ops.aten.bmm.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.mul_.Tensor, + ): + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, input_act_qspec), + ] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in ( + torch.ops.aten.minimum.default, + torch.ops.aten.maximum.default, + ): + lhs_node = ensure_type(Node, node.args[0]) + shared_qspec = SharedQuantizationSpec((lhs_node, node)) + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty( + 1, + input_act_qspec if node.args[0] == node.args[1] else shared_qspec, + ), + ] + quant_properties.quant_output = _QuantProperty(0, shared_qspec) + elif node.target in (torch.ops.aten.where.self,): + true_node = ensure_type(Node, node.args[1]) + input_qspec = ( + SharedQuantizationSpec(true_node) + if is_output_annotated(true_node) + else input_act_qspec + ) + quant_properties.quant_inputs = [ + _QuantProperty(1, input_qspec), + _QuantProperty(2, SharedQuantizationSpec((true_node, node))), + ] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((true_node, node)), + ) + elif node.target in _one_to_one_shared_input_or_input_act_qspec: + input_node = ensure_type(Node, node.args[0]) + input_qspec = ( + SharedQuantizationSpec(input_node) + if is_output_annotated(input_node) + else input_act_qspec + ) + quant_properties.quant_inputs = [_QuantProperty(0, input_qspec)] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((input_node, node)), + ) + elif node.target in ( + torch.ops.aten.cat.default, + torch.ops.aten.concatenate.default, + torch.ops.aten.stack.default, + ): + # first argument should be a non-empty list of nodes + if not isinstance(node.args[0], list): + raise TypeError( + "Expected node.args[0] to be a list, got " + f"{type(node.args[0]).__name__!r}" + ) + if len(node.args[0]) == 0: + raise ValueError("Expected non-empty list for node.args[0]") + inputs = [ensure_type(Node, element) for element in node.args[0]] + shared_qspec = SharedQuantizationSpec((inputs[0], node)) + quant_properties.quant_inputs = [ + _QuantProperty( + 0, + [input_act_qspec if n == inputs[0] else shared_qspec for n in inputs], + ) + ] + quant_properties.quant_output = _QuantProperty(0, shared_qspec) + elif node.target in _one_to_one: + quant_properties.quant_inputs = [_QuantProperty(0, input_act_qspec)] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in _one_to_one_shared_input_qspec: + input_node = ensure_type(Node, node.args[0]) + quant_properties.quant_inputs = [_QuantProperty(0, input_act_qspec)] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((input_node, node)), + ) + elif node.target in [torch.ops.aten.copy_.default]: + input_node = ensure_type(Node, node.args[1]) + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, input_act_qspec), + ] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((input_node, node)), + ) + elif node.target in [ + torch.ops.aten.eq.Tensor, + torch.ops.aten.ge.Tensor, + torch.ops.aten.gt.Tensor, + torch.ops.aten.le.Tensor, + torch.ops.aten.lt.Tensor, + ]: + input_node = ensure_type(Node, node.args[0]) + shared_qspec = SharedQuantizationSpec((input_node, node)) + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty( + 1, + input_act_qspec if node.args[0] == node.args[1] else shared_qspec, + ), + ] + quant_properties.quant_output = None + elif node.target in [ + torch.ops.aten.full.default, + torch.ops.aten.full, + torch.ops.aten.zeros.default, + torch.ops.aten.ones.default, + torch.ops.aten.fill_.Scalar, + torch.ops.aten.scalar_tensor.default, + ]: + quant_properties.quant_inputs = [] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in [operator.getitem]: + input_node = ensure_type(Node, node.args[0]) + if not is_output_annotated(input_node): + return None + shared_qspec = SharedQuantizationSpec(input_node) + quant_properties.quant_inputs = [_QuantProperty(0, shared_qspec)] + quant_properties.quant_output = _QuantProperty(0, shared_qspec) + elif node.target in ( + torch.ops.higher_order.cond, + torch.ops.higher_order.while_loop, + ): + submodule_args_pos = -1 if node.target == torch.ops.higher_order.cond else -2 + submodule_args = node.args[submodule_args_pos] + output_qspec = output_act_qspec + if len(submodule_args) > 0: # type: ignore[arg-type] + # The way the TOSA backend handles quantized inputs, arrays of input tensors (such as the input to a + # conditional graph) need shared quantization. + shared_qspec = SharedQuantizationSpec( + (cast(list[Node], submodule_args)[0], node) + ) + quant_properties.quant_inputs = [ + _QuantProperty( + submodule_args_pos, + [ + input_act_qspec, + *([shared_qspec] * (len(submodule_args) - 1)), # type: ignore[arg-type] + ], + ) + ] + if node.target == torch.ops.higher_order.while_loop: + # The output of the while loop body can either re-enter the body, or exit the while loop. + # Therefore, A and B in the diagram below need to share the same quantization parameters. + # A -> while ( RESCALE -> ... RESCALE -> ) -> B + output_qspec = shared_qspec + + quant_properties.quant_output = _QuantProperty(0, output_qspec) + + else: + return None + + # Don't check if operator.getitem is ok for quantization, it's always ok + if node.target == operator.getitem: + return quant_properties + + # Check that each inputs/outputs can be quantized properly with the + # provided quantization properties. + if not _is_ok_for_quantization(node, quant_properties, gm): + return None + + return quant_properties + + +def annotate_graph( # type: ignore[return] + gm: torch.fx.GraphModule, + quantization_config: QuantizationConfig, + filter_fn: Optional[Callable[[Node], bool]] = None, +) -> Optional[List[List[Node]]]: + """Annotate supported nodes in a graph with quantization specs. + + Iterate through call_function nodes, computes quantization properties, and + apply input/output annotations. A filter can restrict which nodes are + considered. + + Args: + gm (torch.fx.GraphModule): Graph to annotate. + quantization_config (QuantizationConfig): Default qspecs for nodes. + filter_fn (Optional[Callable[[Node], bool]]): Optional node predicate. + + Returns: + Optional[List[List[Node]]]: Reserved for future use; currently None. + + """ + for node in gm.graph.nodes: + if node.op != "call_function": + continue + + if is_annotated(node): + continue + + if filter_fn is not None and not filter_fn(node): + continue + + quant_properties = get_quant_properties(node, gm, quantization_config) + if quant_properties is None: + continue + + for quant_property in quant_properties.quant_inputs: + _annotate_input(node, quant_property) + + if quant_properties.quant_output is not None: + _annotate_output(node, quant_properties.quant_output) + + mark_node_as_annotated(node) # type: ignore[attr-defined] + + # Quantization does not allow kwargs for some reason. + # Remove from ops we know have and where we know it does not break anything. + if node.target in [ + torch.ops.aten.full_like.default, + torch.ops.aten.full.default, + torch.ops.aten.full, + torch.ops.aten.fill_.Scalar, + torch.ops.aten.scalar_tensor.default, + torch.ops.aten.zeros.default, + torch.ops.aten.ones.default, + ]: + node.kwargs = {} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_config.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_config.py new file mode 100644 index 0000000..b2bc4a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/quantizer/quantization_config.py @@ -0,0 +1,228 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide quantization configuration helpers for the Arm backend. + +Define a small dataclass to carry activation/weight/bias specs and helper +accessors that validate specs before use. Use this module to build and validate +quantization specs consumed by the annotator. + +""" + + +from dataclasses import dataclass + +import torch +from torchao.quantization.pt2e import ObserverOrFakeQuantize + +from torchao.quantization.pt2e.quantizer import ( + DerivedQuantizationSpec, + QuantizationSpec, +) + + +@dataclass(eq=True, frozen=True) +class QuantizationConfig: + """Provide a container for quantization specs. + + Hold optional specs for input/output activations, weights, and bias, and + expose validated accessors. + + Attributes: + input_activation (QuantizationSpec | None): Spec for input activations. + output_activation (QuantizationSpec | None): Spec for output activations. + weight (QuantizationSpec | None): Spec for weights. + bias (QuantizationSpec | None): Spec for bias values. + + """ + + input_activation: QuantizationSpec | None + output_activation: QuantizationSpec | None + weight: QuantizationSpec | None + bias: QuantizationSpec | None + + def get_input_act_qspec(self) -> QuantizationSpec | None: + """Get the validated input activation spec. + + Validate that the input activation qscheme is supported before + returning the spec. + + Returns: + QuantizationSpec | None: Input activation spec, or ``None`` when + unset. + + Raises: + ValueError: If the qscheme is not per-tensor affine or symmetric. + + """ + if self.input_activation is None: + return None + # Validate that input_activation uses a supported qscheme + if self.input_activation.qscheme not in [ + torch.per_tensor_affine, + torch.per_tensor_symmetric, + ]: + raise ValueError( + f"Unsupported quantization_spec {self.input_activation} for input_activation." + ) + return self.input_activation + + def get_output_act_qspec(self) -> QuantizationSpec | None: + """Get the validated output activation spec. + + Validate that the output activation qscheme is supported before + returning the spec. + + Returns: + QuantizationSpec | None: Output activation spec, or ``None`` when + unset. + + Raises: + ValueError: If the qscheme is not per-tensor affine or symmetric. + + """ + if self.output_activation is None: + return None + # Validate that output_activation uses a supported qscheme + if self.output_activation.qscheme not in [ + torch.per_tensor_affine, + torch.per_tensor_symmetric, + ]: + raise ValueError( + f"Unsupported quantization_spec {self.output_activation} for output_activation." + ) + return self.output_activation + + def get_weight_qspec(self) -> QuantizationSpec | None: + """Get the validated weight spec. + + Validate that the weight qscheme is supported (per-tensor or + per-channel symmetric) before returning the spec. + + Returns: + QuantizationSpec | None: Weight spec, or ``None`` when unset. + + Raises: + ValueError: If the qscheme is not a supported symmetric scheme. + + """ + if self.weight is None: + return None + # Validate that weight uses a supported qscheme + if self.weight.qscheme not in [ + torch.per_tensor_symmetric, + torch.per_channel_symmetric, + ]: + raise ValueError(f"Unsupported quantization_spec {self.weight} for weight") + return self.weight + + def get_bias_qspec(self, node: torch.fx.Node) -> QuantizationSpec | None: + """Get the derived or validated bias spec. + + For conv/linear ops, derive bias qparams from the input/weight observers. + Otherwise, validate a user-provided floating-point bias spec. + + Args: + node (torch.fx.Node): Node whose bias spec is requested. + + Returns: + QuantizationSpec | None: Derived or provided bias spec, or ``None`` + when unset. + + Raises: + ValueError: If deriving qparams sees an unexpected number of + observers/fake-quantizers, or if a provided bias dtype is not + floating-point. + + """ + + def _derive_qparams_fn( + obs_or_fqs: list[ObserverOrFakeQuantize], + ) -> tuple[torch.Tensor, torch.Tensor]: + """Compute bias scale/zero-point from activation/weight observers. + + Expect two observers or fake-quantize modules: one for the input + activation and one for the weight. The bias scale is the product of + input and weight scales, and the zero-point is a tensor of zeros. + + Args: + obs_or_fqs (list[ObserverOrFakeQuantize]): Observers/fake-quant + in order ``[act, weight]``. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Bias scale tensor and + integer zero-point tensor. + + Raises: + ValueError: If the list does not contain exactly two items. + + """ + # Validate expected number of observers/fake-quantizes + if len(obs_or_fqs) != 2: + raise ValueError( + f"Expecting two obs/fqs, one for activation and one for weight, got: {len(obs_or_fqs)}" + ) + act_obs_or_fq = obs_or_fqs[0] + weight_obs_or_fq = obs_or_fqs[1] + act_scale, _ = act_obs_or_fq.calculate_qparams() + weight_scale, _ = weight_obs_or_fq.calculate_qparams() + return torch.tensor(act_scale * weight_scale).to( + torch.float32 + ), torch.full_like(weight_scale, fill_value=0, dtype=torch.int32) + + if node.target in [ + torch.ops.aten.conv1d.default, + torch.ops.aten.conv2d.default, + torch.ops.aten.linear.default, + torch.ops.aten.conv2d.padding, + torch.ops.aten.conv3d.default, + torch.ops.aten.conv3d.padding, + ]: + if self.input_activation is None or self.weight is None: + raise ValueError( + "Input activation and weight QuantizationConfig must be specified." + ) + + if (self.input_activation.dtype == self.weight.dtype == torch.int8) or ( + self.input_activation.dtype == torch.int16 + and self.weight.dtype == torch.int8 + ): + input_act = node.args[0] + weight = node.args[1] + + # If the weights are quantized per_tensor, do the same with bias + qscheme = ( + torch.per_tensor_symmetric + if self.weight is None + else self.weight.qscheme + ) + ch_axis = None + if self.weight is not None: + if qscheme == torch.per_channel_symmetric: + ch_axis = self.weight.ch_axis + + quantization_spec = DerivedQuantizationSpec( + derived_from=[(input_act, node), (weight, node)], # type: ignore[list-item] + derive_qparams_fn=_derive_qparams_fn, + dtype=torch.int32, + quant_min=torch.iinfo(torch.int32).min + 1, + quant_max=torch.iinfo(torch.int32).max, + qscheme=qscheme, + ch_axis=ch_axis, + ) + return quantization_spec # type: ignore[return-value] + else: + raise NotImplementedError( + f"Bias quantization of types: i:{self.input_activation.dtype}, w:{self.weight.dtype} not implemented" + ) + + if self.bias is None: + return None + # Validate that bias dtype is floating-point + if self.bias.dtype != torch.float: + raise ValueError( + "Only float dtype for bias is supported for bias right now" + ) + return self.bias diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-ethos-u.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-ethos-u.txt new file mode 100644 index 0000000..62e7143 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-ethos-u.txt @@ -0,0 +1,6 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +ethos-u-vela == 4.5.0 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-models-test.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-models-test.txt new file mode 100644 index 0000000..238e9d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-models-test.txt @@ -0,0 +1,6 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +diffusers[torch] == 0.33.1 \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-tosa.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-tosa.txt new file mode 100644 index 0000000..f16d967 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-tosa.txt @@ -0,0 +1,7 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +ml_dtypes == 0.5.1 +flatbuffers == 24.3.25 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-vgf.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-vgf.txt new file mode 100644 index 0000000..586976d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/requirements-arm-vgf.txt @@ -0,0 +1,8 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +ai_ml_emulation_layer_for_vulkan == 0.8.0 +ai_ml_sdk_model_converter == 0.8.0 +ai_ml_sdk_vgf_library == 0.8.0 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/BUCK new file mode 100644 index 0000000..67f2bab --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/BUCK @@ -0,0 +1,5 @@ +load("targets.bzl", "define_common_targets") + +oncall("odai_jarvis") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/EthosUBackend.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/EthosUBackend.cpp new file mode 100644 index 0000000..f7ad624 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/EthosUBackend.cpp @@ -0,0 +1,579 @@ +/* + * Copyright 2023-2025 Arm Limited and/or its affiliates. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * Arm backend for Ethos-U baremetal driver stack, this relies on the + * ethos-u-core-driver for hardware interaction. + */ + +// Workaround for runtime/core/portable_type/c10/c10/util/Float16-math.h +#if defined(__GNUC__) && defined(__ZEPHYR__) +#pragma GCC diagnostic ignored "-Wdouble-promotion" +#endif + +#include +#include +#include + +#include + +#if defined(ET_EVENT_TRACER_ENABLED) +#include +#include +using executorch::runtime::EventTracer; +using executorch::runtime::EventTracerEntry; + +class EventTraceScope { + public: + EventTraceScope(EventTracer* event_tracer_, const char* name) { + event_tracer = event_tracer_; + event_tracer_entry_scope = event_tracer->start_profiling(name); + } + ~EventTraceScope() { + event_tracer->end_profiling(event_tracer_entry_scope); + } + + private: + EventTracer* event_tracer; + EventTracerEntry event_tracer_entry_scope; +}; +#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) \ + EventTraceScope event_tracer_scope = EventTraceScope(EVENTTRACER, NAME) +#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) \ + SCOPE = EVENTTRACER->start_profiling(NAME) +#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) \ + EVENTTRACER->end_profiling(SCOPE) + +#else +#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) +#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) +#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) +#endif + +#include +#include +#include +#include +#include +#include + +using namespace std; + +using executorch::aten::ScalarType; +using executorch::runtime::ArrayRef; +using executorch::runtime::Backend; +using executorch::runtime::BackendExecutionContext; +using executorch::runtime::BackendInitContext; +using executorch::runtime::CompileSpec; +using executorch::runtime::DelegateHandle; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +#define ETHOSU_NUM_BASE_ADDRS 3 + +namespace executorch { +namespace backends { +namespace arm { + +typedef struct { + FreeableBuffer* processed; +} ExecutionHandle; + +extern "C" { +void __attribute__((weak)) EthosUBackend_execute_begin() {} +void __attribute__((weak)) EthosUBackend_execute_end() {} +__attribute__((weak)) unsigned char* ethosu_fast_scratch = nullptr; +__attribute__((weak)) size_t ethosu_fast_scratch_size = 0; +} + +class EthosUBackendExecuteCallbacks { + public: + EthosUBackendExecuteCallbacks() { + EthosUBackend_execute_begin(); + } + ~EthosUBackendExecuteCallbacks() { + EthosUBackend_execute_end(); + } +}; + +class EthosUBackend final : public ::executorch::runtime::BackendInterface { + public: + EthosUBackend() {} + + ~EthosUBackend() = default; + + virtual bool is_available() const override { + // TODO: revise to use a register check/init function + return 1; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + ET_LOG(Info, "data:%p", processed->data()); + + const char* data = static_cast(processed->data()); + size_t size = processed->size(); + + // Verify format of vela_bin + if (vela_bin_validate(data, size) == false) { + ET_LOG(Error, "Malformed vela_bin_stream found"); + return Error::InvalidProgram; + } + + MemoryAllocator* allocator = context.get_runtime_allocator(); + ExecutionHandle* handle = allocator->allocateInstance(); + if (handle == nullptr) { + return Error::MemoryAllocationFailed; + } + + handle->processed = processed; + + // Return the same buffer we were passed - this data will be + // executed directly + return handle; + } + + Error execute( + BackendExecutionContext& context, + DelegateHandle* input_handle, + Span args) const override { +#if defined(ET_EVENT_TRACER_ENABLED) + EventTracer* event_tracer = context.event_tracer(); + EventTracerEntry event_tracer_local_scope; +#endif + + EXECUTORCH_PROF_SCOPE(event_tracer, "EthosUBackend::execute()"); + + // CollectArm_CPU_Cycles is just used to save the numbers of CPU cycles + // used, If etdump is used the EXECUTORCH_PROF_SCOPE() above will do the + // same. If not, this is a cheap way of getting some stats and the + // CollectArm_CPU_Cycles object can safely be removed in production code. + // + // The EthosUBackendExecuteCallbacks class uses the C++ + // constructor/destructor to make sure that EthosUBackend_execute_begin() + // and EthosUBackend_execute_end() is called while CollectArm_CPU_Cycles is + // in scope. e.g. We meassure from now until we exit this metod (in any way + // we might do it). + EthosUBackendExecuteCallbacks CollectArm_CPU_Cycles; + + ExecutionHandle* execution_handle = + static_cast(input_handle); + VelaHandles handles; + + // Command stream - we know at this point it's aligned + EXECUTORCH_PROF_START( + event_tracer, + event_tracer_local_scope, + "+EthosUBackend::execute()processed_data"); + const char* data = + static_cast(execution_handle->processed->data()); + EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); + + ET_LOG(Debug, "data:%p", data); + + EXECUTORCH_PROF_START( + event_tracer, + event_tracer_local_scope, + "+EthosUBackend::execute()vela_bin_read()"); + // Read key sections from the vela_bin_stream + if (vela_bin_read(data, &handles, execution_handle->processed->size()) == + false) { + ET_LOG(Error, "vela_read: error, invalid binary layout"); + return Error::InvalidProgram; + } + EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); + + MemoryAllocator* temp_allocator = context.get_temp_allocator(); + // Use a temporary allocator for the intermediate tensors of the + // computation. The allocator is released in runtime/executor/method.cpp at + // the end of the execution of the Ethos-U custom delegate + // Ethos-U driver requires 16 bit alignment. + char* ethosu_scratch = static_cast( + temp_allocator->allocate(handles.scratch_data_size, 16UL)); + if (ethosu_scratch == nullptr) { + ET_LOG( + Error, + "Failed to allocate scratch buffer of %zu bytes from temp_allocator", + handles.scratch_data_size); + return Error::MemoryAllocationFailed; + } + ET_LOG( + Debug, + "Running program data:\n cmd %p %zu\n weight %p %zu\n scratch %p %zu\n fast scratch %p %zu\n", + handles.cmd_data, + handles.cmd_data_size, + handles.weight_data, + handles.weight_data_size, + ethosu_scratch, + handles.scratch_data_size, + ethosu_fast_scratch, + ethosu_fast_scratch_size); + + // Write argument values (from EValue tensor) into Ethos-U scratch + // TODO(MLETORCH-123): Optimise into direct write from Vela into the SRAM + // or DRAM output for compatible data layouts. + for (int i = 0; i < handles.inputs->count; i++) { + auto tensor_count = 1, io_count = 1; + auto tensor_in = args[i]->toTensor(); + char* scratch_addr = ethosu_scratch + handles.inputs->io[i].offset; + + // We accept: + bool supported = 0; + // 32 bit int (simple non-quantised test cases) + supported |= + (tensor_in.scalar_type() == ScalarType::Int and + handles.inputs->io[i].elem_size == 4); + // 8 bit int (IOQDQ pass prepared networks) + supported |= + (tensor_in.scalar_type() == ScalarType::Char and + handles.inputs->io[i].elem_size == 1); + // 16 bit int (IOQDQ pass prepared networks) + supported |= + (tensor_in.scalar_type() == ScalarType::Short and + handles.inputs->io[i].elem_size == 2); + // bool (IOQDQ pass prepared networks) + supported |= + (tensor_in.scalar_type() == ScalarType::Bool and + handles.inputs->io[i].elem_size == 1); + if (!supported) { + ET_LOG( + Error, + "Input %d expected Integer (4 byte), Char (1 byte) or Bool (1 byte) integer inputs, got ScalarType id %s size %d", + i, + executorch::runtime::toString(tensor_in.scalar_type()), + handles.inputs->io[i].elem_size); + return Error::InvalidProgram; + } + + // Select a compatible copy routine including checking for input layouts + // which require permutation. + bool both_int = tensor_in.scalar_type() == ScalarType::Int && + handles.inputs->io[i].elem_size == 4; + bool both_char = tensor_in.scalar_type() == ScalarType::Char && + handles.inputs->io[i].elem_size == 1; + bool both_short = tensor_in.scalar_type() == ScalarType::Short && + handles.inputs->io[i].elem_size == 2; + bool both_bool = tensor_in.scalar_type() == ScalarType::Bool && + (handles.inputs->io[i].elem_size == 1); + + if (both_char || both_int || both_short || both_bool) { + EXECUTORCH_PROF_SCOPE( + event_tracer, "+EthosUBackend::execute()handles.input.memcpy()"); + // Sizes match and elt size matches so memcpy + memcpy( + scratch_addr, + tensor_in.mutable_data_ptr(), + tensor_in.nbytes()); + } else { + ET_LOG(Error, "No matching input copy routine"); + return Error::InvalidProgram; + } + calculate_dimensions( + tensor_in, &handles.inputs->io[i], &tensor_count, &io_count); + if (tensor_count != io_count) { + ET_LOG(Error, "Input tensor sizes do not match"); + ET_LOG( + Error, + "Program expects %d elements but got %d", + io_count, + tensor_count); + return Error::InvalidProgram; + } + } + + // Allocate driver handle and synchronously invoke driver + auto driver = + std::unique_ptr( + ethosu_reserve_driver(), ethosu_release_driver); + if (driver == NULL) { + ET_LOG(Error, "ethosu_reserve_driver failed"); + return Error::InvalidState; + } + + // Ethos-U low level driver expected order for Ethos U-55, we have + // constant weight data, then scratch (which contains input and output) + // scratch is written above in this function. + + uint64_t bases[ETHOSU_NUM_BASE_ADDRS] = { + static_cast( + reinterpret_cast((handles.weight_data))), + static_cast(reinterpret_cast(ethosu_scratch)), + static_cast( + reinterpret_cast(ethosu_fast_scratch))}; + size_t bases_size[ETHOSU_NUM_BASE_ADDRS] = { + handles.weight_data_size, + handles.scratch_data_size, + ethosu_fast_scratch_size}; + int result = 0; + EXECUTORCH_PROF_START( + event_tracer, event_tracer_local_scope, "+EthosUBackend::execute()NPU"); + result = ethosu_invoke_v3( + driver.get(), + static_cast(handles.cmd_data), + handles.cmd_data_size, + bases, + bases_size, + ETHOSU_NUM_BASE_ADDRS, /* fixed array of pointers to binary interface*/ + nullptr); + EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); + + if (result != 0) { + ET_LOG(Error, "Ethos-U invocation failed error (%d)", result); + return Error::InvalidProgram; + } + size_t tensor_bytes_total = 0; + size_t io_bytes_total = 0; + // Write outputs from scratch into EValue pointers + for (int i = 0; i < handles.outputs->count; i++) { + int tensor_count = 1, io_count = 1; + const char* output_addr = ethosu_scratch + handles.outputs->io[i].offset; + // Process input EValue into scratch + // Outputs are in the index immediately after inputs + auto tensor_out = args[handles.inputs->count + i]->toTensor(); + + calculate_dimensions( + tensor_out, &handles.outputs->io[i], &tensor_count, &io_count); + + size_t tensor_bytes = tensor_out.nbytes(); + size_t io_bytes = static_cast(io_count) * + static_cast(handles.outputs->io[i].elem_size); + + if (tensor_bytes != io_bytes) { + Error status = copy_with_layout_adjustment( + handles.outputs->io[i], i, output_addr, tensor_out, tensor_bytes); + if (status != Error::Ok) { + return status; + } + io_bytes_total += tensor_bytes; + } else { + EXECUTORCH_PROF_SCOPE( + event_tracer, "+EthosUBackend::execute()handles.output.memcpy()"); + + memcpy( + tensor_out.mutable_data_ptr(), + static_cast(output_addr), + tensor_bytes); + io_bytes_total += io_bytes; + } + + // At times the topological order of the outputs may change. + // Lets instead ensure that the sum of output bytes match. + tensor_bytes_total += tensor_bytes; + } + if (tensor_bytes_total != io_bytes_total) { + ET_LOG(Error, "Total output tensor sizes do not match"); + ET_LOG( + Error, + "Program expects %zu bytes but got %zu", + io_bytes_total, + tensor_bytes_total); + return Error::InvalidProgram; + } + return Error::Ok; + } + + void destroy(DelegateHandle* handle) const override { + return; + } + + private: + // Copies Vela output into the ExecuTorch tensor, adjusting for padding or + // packed layouts produced by the delegate. + Error copy_with_layout_adjustment( + const VelaIO& output_io, + int output_index, + const char* src, + executorch::aten::Tensor& tensor_out, + size_t tensor_bytes) const { + const int elem_size = output_io.elem_size; + if (elem_size == 0) { + ET_LOG( + Error, "Ethos-U output %d reports zero element size", output_index); + return Error::InvalidProgram; + } + + size_t chunk_count = 1; + for (int dim = 0; dim < shapeDim - 1; ++dim) { + const int vela_dim = output_io.shape[dim]; + chunk_count *= static_cast(vela_dim == 0 ? 1 : vela_dim); + } + const int last_dim = output_io.shape[shapeDim - 1]; + const size_t vela_chunk_elems = + static_cast(last_dim == 0 ? 1 : last_dim); + const size_t vela_chunk_size = + vela_chunk_elems * static_cast(elem_size); + + if (tensor_bytes % chunk_count != 0) { + ET_LOG( + Error, + "Ethos-U output %d tensor bytes %zu not divisible by chunk count %zu", + output_index, + tensor_bytes, + chunk_count); + return Error::InvalidProgram; + } + + const size_t chunk_size = tensor_bytes / chunk_count; + + // If Vela writes fewer bytes than the tensor expects we may need to + // expand 4-bit data to 8-bit. Ethos-U outputs may be + // packed 4-bit values but ExecuTorch tensors are at least 8-bit. + if (vela_chunk_size < chunk_size) { + if (chunk_size % vela_chunk_size != 0) { + ET_LOG( + Error, + "Ethos-U output %d chunk bytes %zu not divisible by vela chunk bytes %zu", + output_index, + chunk_size, + vela_chunk_size); + return Error::InvalidProgram; + } + + const size_t expand_factor = chunk_size / vela_chunk_size; + if (expand_factor == 2 && elem_size == 1 && + tensor_out.scalar_type() == ScalarType::Char) { + return unpack_chunks_4bit_to_int8( + reinterpret_cast(src), + tensor_out.mutable_data_ptr(), + chunk_count, + chunk_size, + vela_chunk_size); + } + + ET_LOG( + Error, + "Ethos-U output %d expansion factor %zu with element size %d not supported", + output_index, + expand_factor, + elem_size); + return Error::InvalidProgram; + } + + return strip_delegate_padding( + src, + tensor_out.mutable_data_ptr(), + chunk_count, + chunk_size, + vela_chunk_size); + } + + Error unpack_chunks_4bit_to_int8( + const uint8_t* src, + int8_t* dest, + size_t chunk_count, + size_t dest_chunk_size, + size_t src_chunk_size) const { + const uint8_t* chunk_src = src; + int8_t* chunk_dest = dest; + for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { + unpack_single_chunk_4bit_to_int8(chunk_src, chunk_dest, src_chunk_size); + chunk_src += src_chunk_size; + chunk_dest += dest_chunk_size; + } + return Error::Ok; + } + + void unpack_single_chunk_4bit_to_int8( + const uint8_t* src, + int8_t* dest, + size_t chunk_size) const { + for (size_t byte_idx = 0; byte_idx < chunk_size; ++byte_idx) { + const uint8_t packed = src[byte_idx]; + int8_t low = static_cast(packed & 0x0F); + int8_t high = static_cast((packed >> 4) & 0x0F); + if (low >= 8) { + low -= 16; + } + if (high >= 8) { + high -= 16; + } + dest[2 * byte_idx] = low; + dest[2 * byte_idx + 1] = high; + } + } + + Error strip_delegate_padding( + const char* src, + char* dest, + size_t chunk_count, + size_t dest_chunk_size, + size_t src_chunk_size) const { + if (dest_chunk_size > src_chunk_size) { + ET_LOG( + Error, + "dest chunk size %zu must not exceed src chunk size %zu", + dest_chunk_size, + src_chunk_size); + return Error::InvalidProgram; + } + if (src == nullptr || dest == nullptr) { + ET_LOG(Error, "Ethos-U padded copy received null buffer"); + return Error::InvalidState; + } + for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { + memcpy(dest, src, dest_chunk_size); + src += src_chunk_size; + dest += dest_chunk_size; + } + return Error::Ok; + } + + void calculate_dimensions( + const executorch::aten::Tensor tensor, + VelaIO* io, + int* tensor_count, + int* io_count) const { + for (int i = 0; i < tensor.dim(); i++) { + *tensor_count = *tensor_count * tensor.size(i); + } + + // The VelaIO type has a shape of fixed size 6 + for (int i = 0; i < shapeDim; i++) { + *io_count = *io_count * io->shape[i]; + } + } +}; + +namespace { +auto EthosUBackend_backend = EthosUBackend(); +Backend EthosUBackend_id{"EthosUBackend", &EthosUBackend_backend}; +static executorch::runtime::Error EthosUBackend_registered = + register_backend(EthosUBackend_id); + +#ifdef __ZEPHYR__ +/** + * This function serves as a linker force-include mechanism to ensure the + * EthosU backend module gets properly linked into the final executable, + * even when it might otherwise be optimized out by the linker due to + * linker options that remove unused code or data for example + * if you link with --gc-sections + * This function can be called from your runner to force the inclusion of + * the EthosU backend module. As a bonus it will return the status of the + * backend registration, so you can also check if the registration was + * successful. + */ + +// Warning: This should not be considered to be an API and might get removed +// without notice in a future release if a better way to solve this is +// implemented. +extern "C" executorch::runtime::Error +executorch_delegate_EthosUBackend_registered() { + return EthosUBackend_registered; +} +#endif + +} // namespace + +} // namespace arm +} // namespace backends +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/TARGETS new file mode 100644 index 0000000..67f2bab --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/TARGETS @@ -0,0 +1,5 @@ +load("targets.bzl", "define_common_targets") + +oncall("odai_jarvis") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFBackend.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFBackend.cpp similarity index 85% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFBackend.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFBackend.cpp index 8ac804f..ce18205 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFBackend.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFBackend.cpp @@ -1,14 +1,14 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ -#include +#include +#include using namespace std; -#include #include #include #include @@ -75,9 +75,7 @@ void vkml_free_basics( VkInstance* instance, VkDevice* device, VkCommandPool* command_pool) { - if (*device != VK_NULL_HANDLE && *command_pool != VK_NULL_HANDLE) { - vkDestroyCommandPool(*device, *command_pool, nullptr); - } + vkDestroyCommandPool(*device, *command_pool, nullptr); // Note: These primitives are used by the emulation layer for vulkan // object allocation, the vulkan objects are freed in in library // shutdown, so we can't yet destroy these here without causing @@ -88,14 +86,7 @@ void vkml_free_basics( class VGFBackend final : public ::executorch::runtime::BackendInterface { public: - VGFBackend() = default; - - // Lazy Vulkan init — runs on first use, not in the constructor. - void ensure_initialized() { - if (is_initialized_) { - return; - } - + VGFBackend() { VkResult result; // Fetch basic vulkan objects once @@ -120,20 +111,21 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { result); return; } - - is_initialized_ = true; } ~VGFBackend() { vkml_free_basics(&vk_instance, &vk_device, &vk_command_pool); } bool is_available() const override { + VkResult result; + ET_LOG(Info, "Checking VGFBackend is available"); - const_cast(this)->ensure_initialized(); - if (!is_initialized_) { + // Query the device prepared in constructor for needed extensions + result = vkml_load_extensions(&vk_device); + if (result != VK_SUCCESS) return false; - } - return vkml_load_extensions(&vk_device) == VK_SUCCESS; + + return true; } Result init( @@ -142,14 +134,6 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { ArrayRef compile_specs) const override { ET_LOG(Info, "Entered VGF init"); - const_cast(this)->ensure_initialized(); - if (!is_initialized_) { - ET_LOG( - Error, - "VGF backend is unavailable because Vulkan initialization failed"); - return Error::NotSupported; - } - const char* vgf_data = reinterpret_cast(processed->data()); MemoryAllocator* allocator = context.get_runtime_allocator(); @@ -157,8 +141,7 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { new (repr) VgfRepr( vk_instance, vk_physical_device, vk_device, vk_queue, vk_command_pool); - auto valid_vgf = - repr->process_vgf(vgf_data, processed->size(), compile_specs); + auto valid_vgf = repr->process_vgf(vgf_data, compile_specs); if (!valid_vgf) { ET_LOG(Error, "Failed to process VGF blob."); return Error::Internal; @@ -191,18 +174,8 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { if (!io->is_input) continue; - size_t io_size = io->elt_size; - for (int64_t dim : io->size) { - ET_CHECK_OR_RETURN_ERROR( - dim >= 0, - InvalidArgument, - "Negative dimension in IO size: %" PRId64, - dim); - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(io_size, static_cast(dim), &io_size), - InvalidArgument, - "Overflow computing IO buffer size"); - } + size_t io_size = accumulate( + io->size.begin(), io->size.end(), io->elt_size, std::multiplies<>()); void* data; if (!repr->map_io(io, &data)) { @@ -236,18 +209,8 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { if (io->is_input) continue; - size_t io_size = io->elt_size; - for (int64_t dim : io->size) { - ET_CHECK_OR_RETURN_ERROR( - dim >= 0, - InvalidArgument, - "Negative dimension in IO size: %" PRId64, - dim); - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(io_size, static_cast(dim), &io_size), - InvalidArgument, - "Overflow computing IO buffer size"); - } + size_t io_size = accumulate( + io->size.begin(), io->size.end(), io->elt_size, std::multiplies<>()); void* data; if (!repr->map_io(io, &data)) { @@ -267,12 +230,11 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { } private: - VkInstance vk_instance = VK_NULL_HANDLE; - VkPhysicalDevice vk_physical_device = VK_NULL_HANDLE; - VkDevice vk_device = VK_NULL_HANDLE; - VkQueue vk_queue = VK_NULL_HANDLE; - VkCommandPool vk_command_pool = VK_NULL_HANDLE; - bool is_initialized_ = false; + VkInstance vk_instance; + VkPhysicalDevice vk_physical_device; + VkDevice vk_device; + VkQueue vk_queue; + VkCommandPool vk_command_pool; }; namespace { @@ -291,7 +253,6 @@ VkResult vkml_allocate_basics( if (VK_SUCCESS != volkInitialize()) { ET_LOG(Error, "Volk failed to initialize"); - return VK_ERROR_INITIALIZATION_FAILED; } VkApplicationInfo app_info{ @@ -364,16 +325,6 @@ VkResult vkml_allocate_basics( } volkLoadInstance(*instance); - // Bail out if the driver lacks ARM tensor/datagraph extensions. - if (!vkCreateTensorARM) { - ET_LOG( - Error, - "Vulkan driver does not support ARM tensor extensions (VK_ARM_tensors)"); - vkDestroyInstance(*instance, nullptr); - *instance = VK_NULL_HANDLE; - return VK_ERROR_FEATURE_NOT_PRESENT; - } - // Pick first GPU uint32_t gpu_count = 0; vkEnumeratePhysicalDevices(*instance, &gpu_count, nullptr); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFSetup.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFSetup.cpp similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFSetup.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFSetup.cpp index b62a6b2..fd3a114 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFSetup.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFSetup.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -31,7 +31,6 @@ namespace { constexpr int64_t kScalarSentinelDimension = 1; } -#if defined(ET_ARM_VGF_DEBUG) // Debug function to inspect memory properties static string memory_flags_to_string(VkMemoryPropertyFlags flags) { if (flags == 0) @@ -55,7 +54,7 @@ static string memory_flags_to_string(VkMemoryPropertyFlags flags) { #undef TRY_FLAG if (flags) { - // Preserve any unrecognized bits in hex so debug logs stay complete. + // any leftover bits we didn’t name ostringstream hex; hex << "0x" << std::hex << flags; parts.emplace_back(hex.str()); @@ -69,7 +68,6 @@ static string memory_flags_to_string(VkMemoryPropertyFlags flags) { } return joined.str(); } -#endif /** * Tensor free helper function @@ -175,12 +173,7 @@ VkResult allocate_tensor( .memoryTypeIndex = memory_index, }; - result = vkAllocateMemory(device, &allocate_info, nullptr, memory); - if (result != VK_SUCCESS) { - ET_LOG(Error, "Failed to allocate tensor memory, error %d", result); - vkDestroyTensorARM(device, *tensor, nullptr); - return result; - } + vkAllocateMemory(device, &allocate_info, nullptr, memory); // Bind tensor to memory const VkBindTensorMemoryInfoARM bind_info = { @@ -190,13 +183,7 @@ VkResult allocate_tensor( .memory = *memory, .memoryOffset = 0, }; - result = vkBindTensorMemoryARM(device, 1, &bind_info); - if (result != VK_SUCCESS) { - ET_LOG(Error, "Failed to bind tensor memory, error %d", result); - vkDestroyTensorARM(device, *tensor, nullptr); - vkFreeMemory(device, *memory, nullptr); - return result; - } + vkBindTensorMemoryARM(device, 1, &bind_info); VkTensorViewCreateInfoARM tensor_view_info = { .sType = VK_STRUCTURE_TYPE_TENSOR_VIEW_CREATE_INFO_ARM, @@ -249,7 +236,6 @@ static void debug_print_sequence( } } -#if defined(ET_ARM_VGF_DEBUG) static void debug_print_resources( unique_ptr& resource_decoder) { ET_LOG(Info, "Resources:"); @@ -274,7 +260,7 @@ static void debug_print_resources( case vgflib::ResourceCategory::INPUT: case vgflib::ResourceCategory::OUTPUT: { ET_LOG(Info, " Category INPUT/OUTPUT"); - // Log the tensor layout metadata carried in the resource table. + // Get tensor shape and strides auto shape = resource_decoder->getTensorShape(i); const vector the_shape(shape.begin(), shape.end()); auto stride = resource_decoder->getTensorStride(i); @@ -291,15 +277,7 @@ static void debug_print_resources( j, static_cast(the_shape[j])); } - // Show the memory property combination the runtime currently targets. - ET_LOG( - Info, - " memory flags %s", - memory_flags_to_string( - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) - .c_str()); + // Allocate a tensor with bound memory break; } case vgflib::ResourceCategory::INTERMEDIATE: @@ -314,7 +292,6 @@ static void debug_print_resources( } } } -#endif static void debug_print_modules( unique_ptr& module_decoder) { @@ -336,38 +313,26 @@ static void debug_print_modules( } } -bool VgfRepr::process_vgf( - const char* vgf_data, - size_t vgf_size, - ArrayRef specs) { +bool VgfRepr::process_vgf(const char* vgf_data, ArrayRef specs) { ET_LOG(Info, "Preparing VGF as Vulkan objects"); VkResult result; // Prepare temporary decoders unique_ptr header_decoder = - vgflib::CreateHeaderDecoder(vgf_data, vgflib::HeaderSize(), vgf_size); - if (!header_decoder) { - ET_LOG(Error, "Failed to create VGF header decoder"); - return false; - } - + vgflib::CreateHeaderDecoder(vgf_data); unique_ptr sequence_decoder = vgflib::CreateModelSequenceTableDecoder( - vgf_data + header_decoder->GetModelSequenceTableOffset(), - header_decoder->GetModelSequenceTableSize()); + vgf_data + header_decoder->GetModelSequenceTableOffset()); unique_ptr module_decoder = vgflib::CreateModuleTableDecoder( - vgf_data + header_decoder->GetModuleTableOffset(), - header_decoder->GetModuleTableSize()); + vgf_data + header_decoder->GetModuleTableOffset()); unique_ptr resource_decoder = vgflib::CreateModelResourceTableDecoder( - vgf_data + header_decoder->GetModelResourceTableOffset(), - header_decoder->GetModelResourceTableSize()); + vgf_data + header_decoder->GetModelResourceTableOffset()); unique_ptr constant_decoder = vgflib::CreateConstantDecoder( - vgf_data + header_decoder->GetConstantsOffset(), - header_decoder->GetConstantsSize()); + vgf_data + header_decoder->GetConstantsOffset()); // Check the VGF decoders if (not(header_decoder && module_decoder && sequence_decoder && resource_decoder && constant_decoder && header_decoder->IsValid() && @@ -382,9 +347,6 @@ bool VgfRepr::process_vgf( const int segment_id = 0; debug_print_sequence(sequence_decoder); -#if defined(ET_ARM_VGF_DEBUG) - debug_print_resources(resource_decoder); -#endif if (sequence_decoder->modelSequenceTableSize() != 1) { ET_LOG(Error, "Expected sequence length 1"); return false; @@ -576,7 +538,7 @@ bool VgfRepr::process_vgf( .pNext = nullptr, .flags = 0, .bindingCount = static_cast(layout_bindings.size()), - .pBindings = layout_bindings.data(), + layout_bindings.data(), }; result = vkCreateDescriptorSetLayout(vk_device, &layout_info, nullptr, &vk_layout); @@ -727,7 +689,8 @@ bool VgfRepr::process_vgf( VkDataGraphPipelineCreateInfoARM graph_pipeline_info{ .sType = VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_CREATE_INFO_ARM, .pNext = &shader_info, - .flags = VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR, + .flags = VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT | + VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR, .layout = vk_pipeline_layout, .resourceInfoCount = static_cast(data_graph_resources.size()), .pResourceInfos = data_graph_resources.data(), @@ -836,10 +799,7 @@ bool VgfRepr::process_vgf( .bindPoint = bind_point_requirement.bindPoint, .objectIndex = 0, // NOTE: tied to numObjects assert above }; - VkMemoryRequirements2 memory_requirements = { - .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, - .pNext = nullptr, - }; + VkMemoryRequirements2 memory_requirements; vkGetDataGraphPipelineSessionMemoryRequirementsARM( vk_device, &memory_requirements_info, &memory_requirements); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFSetup.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFSetup.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFSetup.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFSetup.h index 8e07b36..3faa7ca 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFSetup.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VGFSetup.h @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -58,10 +58,7 @@ class VgfRepr { /* * Process a VGF ready for execution, allocate necessary Vulkan objects. */ - bool process_vgf( - const char* vgf_data, - size_t vgf_size, - ArrayRef specs); + bool process_vgf(const char* vgf_data, ArrayRef specs); /* * Execute the VGF we've previously processed. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VelaBinStream.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VelaBinStream.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VelaBinStream.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VelaBinStream.cpp index 70c5b0c..c8d5684 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VelaBinStream.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VelaBinStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2023, 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -65,10 +65,8 @@ bool vela_bin_read(const char* data, VelaHandles* handles, int size) { return false; } else if (!strncmp(b->name, "cmd_data", strlen("cmd_data"))) { // This driver magic header confirms a valid command stream in binary - if (strncmp(b->data, "COP1", strlen("COP1")) && - strncmp(b->data, "COP2", strlen("COP2"))) { + if (strncmp(b->data, "COP1", strlen("COP1"))) return false; - } handles->cmd_data = b->data; handles->cmd_data_size = b->size; } else if (!strncmp(b->name, "weight_data", strlen("weight_data"))) { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VelaBinStream.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VelaBinStream.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VelaBinStream.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/VelaBinStream.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/targets.bzl new file mode 100644 index 0000000..7dd0d74 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/runtime/targets.bzl @@ -0,0 +1,31 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + runtime.cxx_library( + name = "vela_bin_stream", + srcs = ["VelaBinStream.cpp"], + exported_headers = ["VelaBinStream.h"], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/core:core", + ], + ) + runtime.cxx_library( + name = "arm_backend", + srcs = ["EthosUBackend.cpp"], + headers = [], + compatible_with = ["ovr_config//cpu:arm32-embedded", "ovr_config//cpu:arm32-embedded-fpu"], + # arm_executor_runner.cpp needs to compile with executor as whole + # @lint-ignore BUCKLINT: Avoid `link_whole=True` (https://fburl.com/avoid-link-whole) + link_whole = True, + supports_python_dlopen = True, + # Constructor needed for backend registration. + compiler_flags = ["-Wno-global-constructors"], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/backend:interface", + ":vela_bin_stream", + "//executorch/runtime/core:core", + "fbsource//third-party/ethos-u-core-driver:core_driver", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/TOSA_minimal_example.ipynb b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/TOSA_minimal_example.ipynb new file mode 100644 index 0000000..996082b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/TOSA_minimal_example.ipynb @@ -0,0 +1,266 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright 2025-2026 Arm Limited and/or its affiliates.\n", + "#\n", + "# This source code is licensed under the BSD-style license found in the\n", + "# LICENSE file in the root directory of this source tree." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TOSA delegate flow example\n", + "\n", + "This guide walks through the complete process of running a module on Arm TOSA using ExecuTorch, with a focus on TOSA lowering exploration. \n", + "This workflow is intended for validating and experimenting with model lowering to TOSA, and is aimed at contributors and developers, rather than production deployment.\n", + "It’s important to note that the compilation flow and passes applied can vary based on the target, so this flow does not necessarily produce TOSA flatbuffers and PTE files which are optimal (or even compatible) with any one target.\n", + "If something is not working for you, please raise a GitHub issue and tag Arm.\n", + "\n", + "Before you begin:\n", + "1. (In a clean virtual environment with a compatible Python version) Install executorch using `./install_executorch.sh`\n", + "2. Install Arm TOSA dependencies using `examples/arm/setup.sh --disable-ethos-u-deps`\n", + "\n", + "With all commands executed from the base `executorch` folder.\n", + "\n", + "\n", + "\n", + "*Some scripts in this notebook produces long output logs: Configuring the 'Customizing Notebook Layout' settings to enable 'Output:scrolling' and setting 'Output:Text Line Limit' makes this more manageable*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## AOT Flow\n", + "\n", + "The first step is creating the PyTorch module and exporting it. Exporting converts the python code in the module into a graph structure. The result is still runnable python code, which can be displayed by printing the `graph_module` of the exported program. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "\n", + "print(torch.__version__)\n", + "\n", + "class Add(torch.nn.Module):\n", + " def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:\n", + " return x + y\n", + "\n", + "example_inputs = (torch.ones(1,1,1,1),torch.ones(1,1,1,1))\n", + "\n", + "model = Add()\n", + "model = model.eval()\n", + "exported_program = torch.export.export(model, example_inputs)\n", + "graph_module = exported_program.module(check_guards=False)\n", + "\n", + "_ = graph_module.print_readable()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TOSA backend supports both INT and FP targets.\n", + "\n", + "To lower the graph_module for FP targets using the TOSA backend, we run it through the default FP lowering pipeline.\n", + "\n", + "FP lowering can be customized for different subgraphs; the sequence shown here is the recommended workflow for TOSA. Because we are staying in floating-point precision, no calibration with example inputs is required.\n", + "\n", + "If you print the module again, you will see that nodes are left in FP form (or annotated with any necessary casts) without any quantize/dequantize wrappers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec\n", + "from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e\n", + "from pathlib import Path\n", + "\n", + "target = \"TOSA-1.0+FP\"\n", + "base_name = \"tosa_simple_example\"\n", + "cwd_dir = Path.cwd()\n", + "\n", + "# Create a compilation spec describing the target for configuring the quantizer\n", + "# Dump intermediate artifacts (in this case TOSA flat buffers) to specified location\n", + "compile_spec = TosaCompileSpec(target).dump_intermediate_artifacts_to(str(cwd_dir / base_name))\n", + "\n", + "_ = graph_module.print_readable()\n", + "\n", + "# Create a new exported program using the quantized_graph_module\n", + "lowered_exported_program = torch.export.export(graph_module, example_inputs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To lower the graph_module for INT targets using the TOSA backend, we apply the arm_quantizer.\n", + "\n", + "Quantization can be performed in various ways and tailored to different subgraphs; the sequence shown here represents the recommended workflow for TOSA.\n", + "\n", + "This step also requires calibrating the module with representative inputs.\n", + "\n", + "If you print the module again, you’ll see that each node is now wrapped in quantization/dequantization nodes that embed the calculated quantization parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec\n", + "from executorch.backends.arm.quantizer import (\n", + " TOSAQuantizer,\n", + " get_symmetric_quantization_config,\n", + ")\n", + "from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e\n", + "from pathlib import Path\n", + "\n", + "target = \"TOSA-1.0+INT\"\n", + "base_name = \"tosa_simple_example\"\n", + "cwd_dir = Path.cwd()\n", + "\n", + "# Create a compilation spec describing the target for configuring the quantizer\n", + "# Dump intermediate artifacts (in this case TOSA flat buffers) to specified location\n", + "compile_spec = TosaCompileSpec(target).dump_intermediate_artifacts_to(str(cwd_dir / base_name))\n", + "\n", + "# Create and configure quantizer to use a symmetric quantization config globally on all nodes\n", + "quantizer = TOSAQuantizer(compile_spec)\n", + "operator_config = get_symmetric_quantization_config()\n", + "quantizer.set_global(operator_config)\n", + "\n", + "# Post training quantization\n", + "quantized_graph_module = prepare_pt2e(graph_module, quantizer)\n", + "quantized_graph_module(*example_inputs) # Calibrate the graph module with the example input\n", + "quantized_graph_module = convert_pt2e(quantized_graph_module)\n", + "\n", + "_ = quantized_graph_module.print_readable()\n", + "\n", + "# Create a new exported program using the quantized_graph_module\n", + "lowered_exported_program = torch.export.export(quantized_graph_module, example_inputs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The lowering in the TOSABackend happens in four steps:\n", + "\n", + "1. **Lowering to core Aten operator set**: Transform module to use a subset of operators applicable to edge devices. \n", + "2. **Partitioning**: Find subgraphs which are supported for running on TOSA\n", + "3. **Lowering to TOSA compatible operator set**: Perform transforms to make the TOSA subgraph(s) compatible with TOSA operator set\n", + "4. **Serialization to TOSA**: Compiles the graph module into a TOSA graph \n", + "Step 4 also prints a Network summary for each processed subgraph.\n", + "\n", + "All of this happens behind the scenes in `to_edge_transform_and_lower`. Printing the graph module shows that what is left in the graph is two quantization nodes for `x` and `y` going into an `executorch_call_delegate` node, followed by a dequantization node." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from executorch.backends.arm.tosa.partitioner import TOSAPartitioner\n", + "from executorch.exir import (\n", + " EdgeCompileConfig,\n", + " ExecutorchBackendConfig,\n", + " to_edge_transform_and_lower,\n", + ")\n", + "from executorch.extension.export_util.utils import save_pte_program\n", + "\n", + "# Create partitioner from compile spec\n", + "partitioner = TOSAPartitioner(compile_spec)\n", + "\n", + "# Lower the exported program to the TOSA backend\n", + "edge_program_manager = to_edge_transform_and_lower(\n", + " lowered_exported_program,\n", + " partitioner=[partitioner],\n", + " compile_config=EdgeCompileConfig(\n", + " _check_ir_validity=False,\n", + " ),\n", + " )\n", + "\n", + "# Convert edge program to executorch\n", + "executorch_program_manager = edge_program_manager.to_executorch(\n", + " config=ExecutorchBackendConfig(extract_delegate_segments=False)\n", + " )\n", + "\n", + "executorch_program_manager.exported_program().graph_module.print_readable()\n", + "\n", + "# Save pte file\n", + "pte_name = base_name + \".pte\"\n", + "pte_path = cwd_dir / base_name / pte_name\n", + "save_pte_program(executorch_program_manager, str(pte_path))\n", + "assert pte_path.exists(), \"Build failed; no .pte-file found\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Use TOSA reference model to verify TOSA graph\n", + "\n", + "After the AOT compilation flow is done, the resulting lowered TOSA graph can be verified using the TOSA reference model tool." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import subprocess\n", + "import tosa_reference_model as reference_model\n", + "from executorch.backends.arm.test.runner_utils import TosaReferenceModelDispatch\n", + "\n", + "# Run TOSA graph through reference model using sample inputs\n", + "with TosaReferenceModelDispatch():\n", + " executorch_program_manager.exported_program().module()(*example_inputs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner.sh new file mode 100755 index 0000000..4a14044 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +toolchain=arm-none-eabi-gcc +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." +source "${script_dir}/utils.sh" + +pte_file="" +target="ethos-u55-128" +build_type="Release" +bundleio=false +system_config="" +memory_mode="" +build_with_etdump=false +extra_build_flags="" +output_folder_set=false +output_folder="." +et_build_root="${et_root_dir}/arm_test" +ethosu_tools_dir=${et_root_dir}/examples/arm/arm-scratch +select_ops_list="" + +build_bundleio_flags=" -DET_BUNDLE_IO=OFF " +build_with_etdump_flags=" -DEXECUTORCH_ENABLE_EVENT_TRACER=OFF " + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --pte=||semihosting Set to a pte file (generated by the aot_arm_compier) to include the model in the elf." + echo " Or a hex address in the format of 0x00000000 if placed in memory you need to place it on this ADDR on your target, with your flash tool or other means." + echo " Or specify the word 'semihosting' to supply pte at runtime." + echo " --target= Target to build and run for Default: ${target}" + echo " --build_type= Build with Release, Debug or RelWithDebInfo, default is ${build_type}" + echo " --bundleio Support both pte and Bundle IO bpte using Devtools BundelIO with Input/RefOutput included" + echo " --system_config= System configuration to select from the Vela configuration file (see vela.ini). Default: Ethos_U55_High_End_Embedded for EthosU55 targets, Ethos_U85_SYS_DRAM_Mid for EthosU85 targets." + echo " NOTE: If given, this option must match the given target. This option along with the memory_mode sets timing adapter values customized for specific hardware, see ./executor_runner/CMakeLists.txt." + echo " --memory_mode= Vela memory mode, used for setting the Timing Adapter parameters of the Corstone platforms." + echo " Valid values are Shared_Sram(for Ethos-U55, Ethos-U65, Ethos-85), Sram_Only(for Ethos-U55, Ethos-U65, Ethos-U85) or Dedicated_Sram(for Ethos-U65, Ethos-U85)." + echo " Default: Shared_Sram for the Ethos-U55 and Sram_Only for the Ethos-U85" + echo " --etdump Adds Devtools etdump support to track timing and output, etdump area will be base64 encoded in the log" + echo " --extra_build_flags= Extra flags to pass to cmake like -DET_ARM_BAREMETAL_METHOD_ALLOCATOR_POOL_SIZE=60000 Default: none " + echo " --output= Output folder Default: /_.pte" + echo " --et_build_root= Build output root folder to use, defaults to ${et_build_root}" + echo " --ethosu_tools_dir= Path to your Ethos-U tools dir if you not using default: ${ethosu_tools_dir}" + echo " --toolchain= Toolchain can be specified (e.g. bare metal as arm-none-eabi-gcc or zephyr as arm-zephyr-eabi-gcc Default: ${toolchain}" + echo " --select_ops_list= Comma separated list of portable (non delagated) kernels to include Default: ${select_ops_list}" + echo " NOTE: This is used when select_ops_model is not possible to use, e.g. for semihosting or bundleio." + echo " See https://docs.pytorch.org/executorch/stable/kernel-library-selective-build.html for more information." + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --pte=*) pte_file="${arg#*=}";; + --target=*) target="${arg#*=}";; + --build_type=*) build_type="${arg#*=}";; + --bundleio) bundleio=true ;; + --system_config=*) system_config="${arg#*=}";; + --memory_mode=*) memory_mode="${arg#*=}";; + --etdump) build_with_etdump=true ;; + --extra_build_flags=*) extra_build_flags="${arg#*=}";; + --output=*) output_folder="${arg#*=}" ; output_folder_set=true ;; + --et_build_root=*) et_build_root="${arg#*=}";; + --ethosu_tools_dir=*) ethosu_tools_dir="${arg#*=}";; + --toolchain=*) toolchain="${arg#*=}";; + --select_ops_list=*) select_ops_list="${arg#*=}";; + *) + ;; + esac +done + +if [[ ${toolchain} == "arm-none-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/${toolchain}.cmake +elif [[ ${toolchain} == "arm-zephyr-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/zephyr/x86_64-linux-arm-zephyr-eabi-gcc.cmake +else + echo "Error: Invalid toolchain selection, provided: ${toolchain}" + echo " Valid options are {arm-none-eabi-gcc, arm-zephyr-eabi-gcc}" + exit 1; +fi +toolchain_cmake=$(realpath ${toolchain_cmake}) + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +if [[ ${pte_file} == "semihosting" ]]; then + pte_data="-DSEMIHOSTING=ON" +else + if [[ "$pte_file" =~ ^0x[0-9a-fA-F]{1,16}$ ]]; then + echo "PTE in memory at ${pte_file}, make sure to put it there on your target before starting." + pte_data="-DET_MODEL_PTE_ADDR=${pte_file}" + if [ "$output_folder_set" = false ] ; then + # Not locked down to a PTE use + output_folder=${et_build_root}/${target}_${pte_file}/cmake-out + fi + else + echo "PTE included in elf from file ${pte_file}" + pte_file=$(realpath ${pte_file}) + pte_data="-DET_PTE_FILE_PATH:PATH=${pte_file}" + if [ "$output_folder_set" = false ] ; then + # remove file ending + output_folder=${pte_file%.*}/cmake-out + fi + fi +fi +ethosu_tools_dir=$(realpath ${ethosu_tools_dir}) +ethos_u_root_dir="$ethosu_tools_dir/ethos-u" +mkdir -p "${ethos_u_root_dir}" +ethosu_tools_dir=$(realpath ${ethos_u_root_dir}) + +et_build_dir=${et_build_root}/cmake-out +mkdir -p ${et_build_dir} +et_build_dir=$(realpath ${et_build_dir}) + +if [[ ${system_config} == "" ]] +then + system_config="Ethos_U55_High_End_Embedded" + if [[ ${target} =~ "ethos-u85" ]] + then + system_config="Ethos_U85_SYS_DRAM_Mid" + fi +fi + +if [[ ${memory_mode} == "" ]] +then + memory_mode="Shared_Sram" + if [[ ${target} =~ "ethos-u85" ]] + then + memory_mode="Dedicated_Sram_384KB" + fi +fi + +mkdir -p "${output_folder}" +output_folder=$(realpath ${output_folder}) + +if [[ ${target} == *"ethos-u55"* ]]; then + target_cpu=cortex-m55 +else + target_cpu=cortex-m85 +fi +echo "--------------------------------------------------------------------------------" +echo "Build Arm ${toolchain/-gcc/} executor_runner for ${target} PTE: ${pte_file} using ${system_config} ${memory_mode} ${extra_build_flags} to '${output_folder}'" +echo "--------------------------------------------------------------------------------" + +cd ${et_root_dir}/examples/arm/executor_runner + +if [ "$bundleio" = true ] ; then + build_bundleio_flags=" -DET_BUNDLE_IO=ON " +fi + +if [ "$build_with_etdump" = true ] ; then + build_with_etdump_flags=" -DEXECUTORCH_ENABLE_EVENT_TRACER=ON -DET_DUMP_INTERMEDIATE_OUTPUTS=ON " +fi + +echo "Building with BundleIO/etdump/extra flags: ${build_bundleio_flags} ${build_with_etdump_flags} ${extra_build_flags}" +cmake \ + -DCMAKE_BUILD_TYPE=${build_type} \ + -DCMAKE_TOOLCHAIN_FILE=${toolchain_cmake} \ + -DTARGET_CPU=${target_cpu} \ + -DET_DIR_PATH:PATH=${et_root_dir} \ + -DET_BUILD_DIR_PATH:PATH=${et_build_dir} \ + -DETHOS_SDK_PATH:PATH=${ethos_u_root_dir} \ + -DETHOSU_TARGET_NPU_CONFIG=${target} \ + ${pte_data} \ + ${build_bundleio_flags} \ + ${build_with_etdump_flags} \ + -DPYTHON_EXECUTABLE=$(which python3) \ + -DSYSTEM_CONFIG=${system_config} \ + -DMEMORY_MODE=${memory_mode} \ + -DEXECUTORCH_SELECT_OPS_LIST="${select_ops_list}" \ + ${extra_build_flags} \ + -B ${output_folder} + +echo "[${BASH_SOURCE[0]}] Configured CMAKE" + +parallel_jobs="$(get_parallel_jobs)" + +cmake --build ${output_folder} -j"${parallel_jobs}" -- arm_executor_runner + +echo "[${BASH_SOURCE[0]}] Generated ${toolchain} elf file:" +find ${output_folder} -name "arm_executor_runner" +echo "executable_text: $(find ${output_folder} -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $1}') bytes" +echo "executable_data: $(find ${output_folder} -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $2}') bytes" +echo "executable_bss: $(find ${output_folder} -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $3}') bytes" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner_vkml.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner_vkml.sh new file mode 100755 index 0000000..f443032 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executor_runner_vkml.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." +build_type="Release" +build_with_etdump=false +extra_build_flags="" +output_folder="cmake-out-vkml" +build_with_etdump_flags="-DEXECUTORCH_ENABLE_EVENT_TRACER=OFF" +build_with_bundleio_flags="-DEXECUTORCH_ENABLE_BUNDLE_IO=OFF" + +source "${script_dir}/utils.sh" + + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --build_type= Build with Release, Debug or RelWithDebInfo, default is ${build_type}" + echo " --etdump Adds Devtools etdump support to track timing, etdump area will be base64 encoded in the log" + echo " --extra_build_flags= Extra flags to pass to cmake. Default: none " + echo " --output= Output folder Default: $(output_folder)" + echo " --bundleio Support BundleIO using Devtools with Input/RefOutput included" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --build_type=*) build_type="${arg#*=}";; + --etdump) build_with_etdump=true ;; + --extra_build_flags=*) extra_build_flags="${arg#*=}";; + --output=*) output_folder="${arg#*=}";; + --select_ops_list=*) select_ops_list="${arg#*=}";; + --bundleio) build_with_bundleio_flags="-DEXECUTORCH_ENABLE_BUNDLE_IO=ON" ;; + *) + ;; + esac +done + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +mkdir -p "${output_folder}" +output_folder=$(realpath "${output_folder}") + +cd ${et_root_dir}/examples/arm/executor_runner + +if [ "$build_with_etdump" = true ] ; then + build_with_etdump_flags="-DEXECUTORCH_ENABLE_EVENT_TRACER=ON" +fi + +echo "-----------------------------------------------------------------------------------------------" +echo "Build Arm VKML executor runner: '${output_folder}' with extra build flags: " +echo "${build_with_etdump_flags} ${build_with_bundleio_flags} ${extra_build_flags}" +echo "-----------------------------------------------------------------------------------------------" + +cmake \ + -S "${et_root_dir}" \ + -B "${output_folder}" \ + -Wall \ + -Werror \ + -DCMAKE_BUILD_TYPE=${build_type} \ + -DCMAKE_CXX_FLAGS="${extra_build_flags} ${CMAKE_CXX_FLAGS:-}" \ + -DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \ + -DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \ + -DEXECUTORCH_BUILD_EXTENSION_NAMED_DATA_MAP=ON \ + -DEXECUTORCH_BUILD_EXTENSION_FLAT_TENSOR=ON \ + -DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \ + -DEXECUTORCH_BUILD_XNNPACK=OFF \ + -DEXECUTORCH_BUILD_VULKAN=ON \ + -DEXECUTORCH_BUILD_VGF=ON \ + -DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \ + -DEXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT=ON \ + -DEXECUTORCH_ENABLE_LOGGING=ON \ + -DEXECUTORCH_BUILD_DEVTOOLS=ON \ + -DPYTHON_EXECUTABLE="$(which python3)" \ + ${build_with_etdump_flags} \ + ${build_with_bundleio_flags} + +echo "[${BASH_SOURCE[0]}] Configured CMAKE" + +parallel_jobs="$(get_parallel_jobs)" + +cmake --build "${output_folder}" --parallel "${parallel_jobs}" + +echo "[${BASH_SOURCE[0]}] Built VKML runner: " +find ${output_folder} -name "executor_runner" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executorch.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executorch.sh new file mode 100755 index 0000000..b0a93c9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_executorch.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Optional parameter: +# --build_type= "Release" | "Debug" | "RelWithDebInfo" | "UndefinedSanitizer" | "AddressSanitizer" +# --etdump build with devtools-etdump support + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +toolchain=arm-none-eabi-gcc +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + +source "${script_dir}/utils.sh" + +et_build_root="${et_root_dir}/arm_test" +build_type="Release" +build_devtools=OFF +build_with_etdump=OFF + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --et_build_root= Build output root folder to use, defaults to ${et_build_root}" + echo " --build_type= Build with Release, Debug, RelWithDebInfo, UndefinedSanitizer or AddressSanitizer, default is ${build_type}" + echo " --devtools Build Devtools libs" + echo " --etdump Adds Devtools etdump support to track timing, etdump area will be base64 encoded in the log" + echo " --toolchain= Toolchain can be specified (e.g. bare metal as arm-none-eabi-gcc or zephyr as arm-zephyr-eabi-gcc Default: ${toolchain}" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --et_build_root=*) et_build_root="${arg#*=}";; + --build_type=*) build_type="${arg#*=}";; + --devtools) build_devtools=ON ;; + --etdump) build_with_etdump=ON ;; + --toolchain=*) toolchain="${arg#*=}";; + *) + ;; + esac +done + +if [[ ${toolchain} == "arm-none-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/${toolchain}.cmake +elif [[ ${toolchain} == "arm-zephyr-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/zephyr/x86_64-linux-arm-zephyr-eabi-gcc.cmake +else + echo "Error: Invalid toolchain selection, provided: ${toolchain}" + echo " Valid options are {arm-none-eabi-gcc, arm-zephyr-eabi-gcc}" + exit 1; +fi +toolchain_cmake=$(realpath ${toolchain_cmake}) + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +et_build_dir="${et_build_root}/cmake-out" + +set -x +cd "${et_root_dir}" + +( set +x ; + echo "--------------------------------------------------------------------------------" ; + echo "Build ExecuTorch target libs ${build_type} into '${et_build_dir}'" ; + echo "--------------------------------------------------------------------------------" ) + +# Build +cmake -DCMAKE_TOOLCHAIN_FILE=${toolchain_cmake} \ +-DCMAKE_BUILD_TYPE=${build_type} \ +-DEXECUTORCH_BUILD_DEVTOOLS=$build_devtools \ +-DEXECUTORCH_BUILD_ARM_ETDUMP=$build_with_etdump \ +--preset arm-baremetal -B${et_build_dir} + +parallel_jobs="$(get_parallel_jobs)" + +cmake --build ${et_build_dir} -j"${parallel_jobs}" --target install --config ${build_type} -- + +set +x + +echo "[$(basename $0)] Generated static libraries for ExecuTorch:" +find ${et_build_dir} -name "*.a" -exec ls -al {} \; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_portable_kernels.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_portable_kernels.sh new file mode 100755 index 0000000..cfa008c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/build_portable_kernels.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +echo "DEPRECATED: build_portable_kernels.sh is deprecated and will be removed. The kernel registration library is now built directly with the arm_executor_runner." diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/collect_testname_resources.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/collect_testname_resources.py new file mode 100644 index 0000000..54d4a9c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/collect_testname_resources.py @@ -0,0 +1,194 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +import ast +import pathlib +import re + +from executorch.exir.dialects.edge.spec.utils import SAMPLE_INPUT as _SAMPLE_INPUT + +# Add all targets and TOSA profiles we support here. +TARGETS = [ + "tosa_FP", + "tosa_INT", + "tosa_INT+FP", + "u55_INT", + "u85_INT", + "vgf_INT", + "vgf_FP", + "vgf_quant", + "vgf_no_quant", + "no_target", +] + +# Add edge ops which we lower but which are not included in exir/dialects/edge/edge.yaml here. +_CUSTOM_EDGE_OPS = [ + "linspace.default", + "cond.default", + "eye.default", + "expm1.default", + "vector_norm.default", + "hardsigmoid.default", + "hardswish.default", + "linear.default", + "maximum.default", + "mean.default", + "multihead_attention.default", + "adaptive_avg_pool2d.default", + "bitwise_right_shift.Tensor", + "bitwise_right_shift.Scalar", + "bitwise_left_shift.Tensor", + "bitwise_left_shift.Scalar", + "native_group_norm.default", + "silu.default", + "sdpa.default", + "sum.default", + "unbind.int", + "unflatten.int", + "_native_batch_norm_legit_no_training.default", + "_native_batch_norm_legit.no_stats", + "alias_copy.default", + "pixel_shuffle.default", + "pixel_unshuffle.default", + "while_loop.default", + "matmul.default", + "upsample_bilinear2d.vec", + "upsample_nearest2d.vec", +] +_ALL_EDGE_OPS = _SAMPLE_INPUT.keys() | _CUSTOM_EDGE_OPS + +_NON_ARM_PASSES = ["quantize_io_pass"] + +_MODEL_ENTRY_PATTERN = re.compile(r"^\s*(?:[-*]|\d+\.)\s+(?P.+?)\s*$") +_NUMERIC_SERIES_PATTERN = re.compile(r"(\d+)(?=[a-z])") +_CAMEL_BOUNDARY = re.compile( + r"(? set[str]: + names: set[str] = set() + names.update(_extract_pass_names_from_init(init_path)) + names.update(_NON_ARM_PASSES) + return {_separate_numeric_series(_strip_pass_suffix(name)) for name in names} + + +def _extract_pass_names_from_init(init_path: pathlib.Path) -> set[str]: + source = init_path.read_text(encoding="utf-8") + module = ast.parse(source, filename=str(init_path)) + names: set[str] = set() + + for node in module.body: + if not isinstance(node, ast.ImportFrom): + continue + for alias in node.names: + candidate = alias.asname or alias.name + if not candidate or not candidate.endswith("Pass"): + continue + if candidate == "ArmPass": + continue + names.add(_camel_to_snake(candidate)) + return names + + +def _strip_pass_suffix(name: str) -> str: + return name[:-5] if name.endswith("_pass") else name + + +def _separate_numeric_series(name: str) -> str: + def repl(match: re.Match[str]) -> str: + next_index = match.end() + next_char = match.string[next_index] if next_index < len(match.string) else "" + if next_char == "d": # Avoid creating patterns like 3_d + return match.group(1) + return f"{match.group(1)}_" + + return _NUMERIC_SERIES_PATTERN.sub(repl, name) + + +def _collect_arm_models(models_md: pathlib.Path) -> set[str]: + models: set[str] = set() + for line in models_md.read_text(encoding="utf-8").splitlines(): + stripped = line.strip() + if not stripped or stripped.startswith("#"): + continue + match = _MODEL_ENTRY_PATTERN.match(line) + if not match: + continue + base, alias, is_parent = _split_model_entry(match.group("entry")) + if is_parent: + continue + if alias: + models.add(_normalize_model_entry(alias)) + else: + models.add(_normalize_model_entry(base)) + + if not models: + raise RuntimeError(f"No supported models found in {models_md}") + return models + + +def _collect_arm_ops() -> set[str]: + """ + Returns a mapping from names on the form to be used in unittests to edge op: + 1. Names are in lowercase. + 2. Overload is ignored if 'default', otherwise it's appended with an underscore. + 3. Overly verbose name are shortened by removing certain prefixes/suffixes. + + Examples: + abs.default -> abs + split_copy.Tensor -> split_tensor + """ + ops: set[str] = set() + for edge_name in _ALL_EDGE_OPS: + op, overload = edge_name.split(".") + + # Normalize names + op = op.lower() + op = op.removeprefix("_") + op = op.removesuffix("_copy") + op = op.removesuffix("_with_indices") + overload = overload.lower() + + if overload == "default": + ops.add(op) + else: + ops.add(f"{op}_{overload}") + + return ops + + +def _split_model_entry(entry: str) -> tuple[str, str | None, bool]: + entry = entry.strip() + if not entry: + return "", None, False + is_parent = entry.endswith(":") + if is_parent: + entry = entry[:-1].rstrip() + if "(" in entry and entry.endswith(")"): + base, _, rest = entry.partition("(") + alias = rest[:-1].strip() + return base.strip(), alias or None, is_parent + return entry, None, is_parent + + +def _normalize_model_entry(name: str) -> str: + cleaned = name.lower() + cleaned = re.sub(r"[^a-z0-9\s]", "", cleaned) + cleaned = re.sub(r"\s+", " ", cleaned).strip() + return cleaned.replace(" ", "_") + + +def _camel_to_snake(name: str) -> str: + if not name: + return "" + name = name.replace("-", "_").replace(" ", "_") + return _CAMEL_BOUNDARY.sub("_", name).lower() + + +OP_LIST = sorted(_collect_arm_ops()) +PASS_LIST = sorted( + _collect_arm_passes(pathlib.Path("backends/arm/_passes/__init__.py")) +) +MODEL_LIST = sorted(_collect_arm_models(pathlib.Path("backends/arm/MODELS.md"))) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/corstone_utils.cmake b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/corstone_utils.cmake new file mode 100644 index 0000000..8253f39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/corstone_utils.cmake @@ -0,0 +1,463 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +function(fetch_ethos_u_content ETHOS_SDK_PATH ET_DIR_PATH) + message(STATUS "Fetching Ethos-U content into ${ETHOS_SDK_PATH}") + + file(MAKE_DIRECTORY ${ETHOS_SDK_PATH}/../ethos_u) + include(FetchContent) + set(ethos_u_base_tag "25.05") + FetchContent_Declare( + ethos_u + GIT_REPOSITORY + https://git.gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u.git + GIT_TAG ${ethos_u_base_tag} + SOURCE_DIR + ${ETHOS_SDK_PATH} + BINARY_DIR + ${ETHOS_SDK_PATH} + SUBBUILD_DIR + ${ETHOS_SDK_PATH}/../ethos_u-subbuild + SOURCE_SUBDIR + none + ) + FetchContent_MakeAvailable(ethos_u) + # Patch manifest to remove unused projects. + set(patch_dir "${ET_DIR_PATH}/examples/arm/ethos-u-setup") + set(ethos_u_base_rev "24950bd4381b6c51db0349a229f8ba86b8e1093f") + execute_process( + COMMAND + bash -c + "pwd && source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH} ${ethos_u_base_rev} ${patch_dir}" + WORKING_DIRECTORY ${ET_DIR_PATH} COMMAND_ECHO STDOUT + ) + # Get ethos_u externals only if core_platform folder does not already exist. + if(NOT EXISTS "${ETHOS_SDK_PATH}/core_platform") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} fetch_externals.py -c + ${ethos_u_base_tag}.json fetch + WORKING_DIRECTORY ${ETHOS_SDK_PATH} COMMAND_ECHO STDOUT + ) + endif() + # Patch core_software to remove unused projects. + set(core_software_base_rev "55904c3da73c876c6d6c58290938ae217a8b94bd") + execute_process( + COMMAND + bash -c + "pwd && source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH}/core_software ${core_software_base_rev} ${patch_dir}" + WORKING_DIRECTORY ${ET_DIR_PATH} COMMAND_ECHO STDOUT + ) + # Always patch the core_platform repo since this is fast enough. + set(core_platform_base_rev "1916a9c984819c35b19c9e5c4c80d47e4e866420") + execute_process( + COMMAND + bash -c + "pwd && source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH}/core_platform ${core_platform_base_rev} ${patch_dir}" + WORKING_DIRECTORY ${ET_DIR_PATH} COMMAND_ECHO STDOUT + ) +endfunction() + +function(add_corstone_subdirectory SYSTEM_CONFIG ETHOS_SDK_PATH) + if(SYSTEM_CONFIG MATCHES "Ethos_U55") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-300 target + ) + elseif(SYSTEM_CONFIG MATCHES "Ethos_U85") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-320 target + ) + else() + message(FATAL_ERROR "Unsupported SYSTEM_CONFIG ${SYSTEM_CONFIG}.") + endif() + if(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_target_common INTERFACE ETHOSU_MODEL=1 ETHOSU_ARENA=1 + ) + elseif(MEMORY_MODE MATCHES "Shared_Sram" OR MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common INTERFACE ETHOSU_MODEL=1 ETHOSU_ARENA=0 + ) + else() + message( + FATAL_ERROR + "Unsupported MEMORY_MODE ${MEMORY_MODE}. Memory_mode can be Shared_Sram, Sram_Only or Dedicated_Sram(applicable for the Ethos-U85)" + ) + endif() +endfunction() + +function(configure_timing_adapters SYSTEM_CONFIG MEMORY_MODE) + if(SYSTEM_CONFIG MATCHES "Ethos_U55_High_End_Embedded") + set(TARGET_BOARD + "corstone-300" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Shared_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Flash + ETHOSU_TA_MAXR_1=2 + ETHOSU_TA_MAXW_1=0 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=64 + ETHOSU_TA_WLATENCY_1=0 + ETHOSU_TA_PULSE_ON_1=320 + ETHOSU_TA_PULSE_OFF_1=80 + ETHOSU_TA_BWCAP_1=50 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # This is just example numbers and you should make this match + # your hardware SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=8 + ETHOSU_TA_MAXW_1=8 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=32 + ETHOSU_TA_WLATENCY_1=32 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + + else() + message( + FATAL_ERROR + "Unsupported memory_mode ${MEMORY_MODE} for the Ethos-U55. The Ethos-U55 supports only Shared_Sram and Sram_Only." + ) + endif() + elseif(SYSTEM_CONFIG MATCHES "Ethos_U55_Deep_Embedded") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-300 target + ) + set(TARGET_BOARD + "corstone-300" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Shared_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=4 + ETHOSU_TA_MAXW_0=4 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=8 + ETHOSU_TA_WLATENCY_0=8 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Flash + ETHOSU_TA_MAXR_1=2 + ETHOSU_TA_MAXW_1=0 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=32 + ETHOSU_TA_WLATENCY_1=0 + ETHOSU_TA_PULSE_ON_1=360 + ETHOSU_TA_PULSE_OFF_1=40 + ETHOSU_TA_BWCAP_1=25 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=4 + ETHOSU_TA_MAXW_0=4 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=8 + ETHOSU_TA_WLATENCY_0=8 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=4 + ETHOSU_TA_MAXW_1=4 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=8 + ETHOSU_TA_WLATENCY_1=8 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + else() + message( + FATAL_ERROR + "Unsupported memory_mode ${MEMORY_MODE} for the Ethos-U55. The Ethos-U55 supports only Shared_Sram and Sram_Only." + ) + endif() + elseif(SYSTEM_CONFIG MATCHES "Ethos_U85_SYS_DRAM_Low") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-320 target + ) + set(TARGET_BOARD + "corstone-320" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=16 + ETHOSU_TA_WLATENCY_0=16 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # DRAM + ETHOSU_TA_MAXR_1=24 + ETHOSU_TA_MAXW_1=12 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=250 + ETHOSU_TA_WLATENCY_1=125 + ETHOSU_TA_PULSE_ON_1=4000 + ETHOSU_TA_PULSE_OFF_1=1000 + ETHOSU_TA_BWCAP_1=2344 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=16 + ETHOSU_TA_WLATENCY_0=16 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=8 + ETHOSU_TA_MAXW_1=8 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=16 + ETHOSU_TA_WLATENCY_1=16 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + endif() + elseif(SYSTEM_CONFIG STREQUAL "Ethos_U85_SYS_DRAM_Mid" + OR SYSTEM_CONFIG STREQUAL "Ethos_U85_SYS_DRAM_High" + ) + set(TARGET_BOARD + "corstone-320" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # DRAM + ETHOSU_TA_MAXR_1=64 + ETHOSU_TA_MAXW_1=32 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=500 + ETHOSU_TA_WLATENCY_1=250 + ETHOSU_TA_PULSE_ON_1=4000 + ETHOSU_TA_PULSE_OFF_1=1000 + ETHOSU_TA_BWCAP_1=3750 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=8 + ETHOSU_TA_MAXW_1=8 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=32 + ETHOSU_TA_WLATENCY_1=32 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + endif() + else() + message(FATAL_ERROR "Unsupported SYSTEM_CONFIG: ${SYSTEM_CONFIG}") + endif() + + # The REGIONCFG registers of the Ethos-U control whether the NPU reads/writes + # data through the SRAM or the external memory. By default, the Ethos-U driver + # provides REGIONCFG configuration for Shared Sram memory mode. For Sram_Only + # and Dedicated_Sram memory modes, we need to change the settings for optimal + # performance. + # + # Currently, the convention used by Vela and the Ethos-U driver is that the + # NPU uses: Region 0 for traffic of the Read-Only data(weights & biases) + # Region 1 for traffic of of the intermediate Read/Write buffers required for + # the computation Region 2 for traffic of of the cache in Dedicated_Sram + # memory mode(not applicable in Sram_Only or Shared_Sram) + # + # NOTE: The above convention is determined by the Vela compiler and the + # Ethos-U driver and can change in the future. + # + # Common definitions: For Ethos-U55/U65/U85, region configs are set as: 0 or 1 + # = AXI0 (Ethos-U55 or Ethos-U65) or AXI_SRAM(Ethos-U85) 2 or 3 = AXI1 + # (Ethos-U55 or Ethos-U65) or AXI_EXT(Ethos-U85) + # + # When we compile a model for Sram_Only, the memory traffic for Region 0 and + # Region 1 should pass via the SRAM(hence regioncfg = 1) When we compile a + # model for Dedicated_Sram, the memory traffic for Region 0 should pass via + # the external memory(3), the memory traffic of Region 1 should pass via the + # external memory(3) and the traffic for Region 2 should pass via the SRAM(0) + # + + if(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_core_driver + PRIVATE NPU_QCONFIG=1 + NPU_REGIONCFG_0=1 + NPU_REGIONCFG_1=0 + NPU_REGIONCFG_2=0 + NPU_REGIONCFG_3=0 + NPU_REGIONCFG_4=0 + NPU_REGIONCFG_5=0 + NPU_REGIONCFG_6=0 + NPU_REGIONCFG_7=0 + ) + elseif(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_core_driver + PRIVATE NPU_QCONFIG=3 + NPU_REGIONCFG_0=3 + NPU_REGIONCFG_1=3 + NPU_REGIONCFG_2=0 + NPU_REGIONCFG_3=0 + NPU_REGIONCFG_4=0 + NPU_REGIONCFG_5=0 + NPU_REGIONCFG_6=0 + NPU_REGIONCFG_7=0 + ) + endif() + +endfunction() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/fvp_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/fvp_utils.sh new file mode 100644 index 0000000..c320507 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/fvp_utils.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# The purpose of this file is to isolate all the functions to download +# and setup FVP. The reasons for behind this are multiple. +# The FVP needs a EULA acceptance and since the software download +# differs for arch and os it becomes quite messy to try and handle +# inside setup.sh. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source "${script_dir}/utils.sh" + +if [[ "${ARCH}" == "x86_64" ]]; then + # FVPs + corstone300_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.22_20_Linux64.tgz?rev=018659bd574f4e7b95fa647e7836ccf4&hash=22A79103C6FA5FFA7AFF3BE0447F3FF9" + corstone300_model_dir="Linux64_GCC-9.3" + corstone300_md5_checksum="98e93b949d0fbac977292d8668d34523" + + corstone320_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-320/FVP_Corstone_SSE-320_11.27_25_Linux64.tgz?rev=a507bffc219a4d5792f1192ab7002d89&hash=D9A824AA8227D2E679C9B9787FF4E8B6FBE3D7C6" + corstone320_model_dir="Linux64_GCC-9.3" + corstone320_md5_checksum="3deb3c68f9b2d145833f15374203514d" +elif [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]]; then + # FVPs + corstone300_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.22_20_Linux64_armv8l.tgz?rev=9cc6e9a32bb947ca9b21fa162144cb01&hash=7657A4CF27D42E892E3F08D452AAB073" + corstone300_model_dir="Linux64_armv8l_GCC-9.3" + corstone300_md5_checksum="cbbabbe39b07939cff7a3738e1492ef1" + + corstone320_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-320/FVP_Corstone_SSE-320_11.27_25_Linux64_armv8l.tgz?rev=b6ebe0923cb84f739e017385fd3c333c&hash=8965C4B98E2FF7F792A099B08831FE3CB6120493" + corstone320_model_dir="Linux64_armv8l_GCC-9.3" + corstone320_md5_checksum="3889f1d80a6d9861ea4aa6f1c88dd0ae" +else + log_step "fvp" "Error: only x86-64 & aarch64/arm64 architecture is supported for now!" + exit 1 +fi + +function install_fvp() { + # Download and install the Corstone 300 FVP simulator platform + fvps=("corstone300" "corstone320") + + for fvp in "${fvps[@]}"; do + cd "${root_dir}" + if [[ ! -e "FVP_${fvp}.tgz" ]]; then + log_step "fvp" "Downloading FVP ${fvp}" + url_variable=${fvp}_url + fvp_url=${!url_variable} + curl --output "FVP_${fvp}.tgz" "${fvp_url}" + md5_variable=${fvp}_md5_checksum + fvp_md5_checksum=${!md5_variable} + verify_md5 ${fvp_md5_checksum} FVP_${fvp}.tgz || exit 1 + fi + + log_step "fvp" "Installing FVP ${fvp}" + rm -rf FVP-${fvp} + mkdir -p FVP-${fvp} + cd FVP-${fvp} + tar xf ../FVP_${fvp}.tgz + + # Install the FVP + case ${fvp} in + corstone300) + ./FVP_Corstone_SSE-300.sh --i-agree-to-the-contained-eula --force --destination ./ --quiet --no-interactive + ;; + corstone320) + ./FVP_Corstone_SSE-320.sh --i-agree-to-the-contained-eula --force --destination ./ --quiet --no-interactive + ;; + *) + log_step "fvp" "Error: Unknown FVP model ${fvp}. Exiting." + exit 1 + ;; + esac + done +} + +function check_fvp_eula () { + # Mandatory user arg --i-agree-to-the-contained-eula + eula_acceptance_by_variable="${ARM_FVP_INSTALL_I_AGREE_TO_THE_CONTAINED_EULA:-False}" + + if [[ "${eula_acceptance}" -eq 0 ]]; then + if [[ ${eula_acceptance_by_variable} != "True" ]]; then + log_step "fvp" "Must pass '--i-agree-to-the-contained-eula' to download the FVP" + log_step "fvp" "Alternatively set ARM_FVP_INSTALL_I_AGREE_TO_THE_CONTAINED_EULA=True" + log_step "fvp" "Exiting due to missing EULA acceptance" + exit 1 + else + log_step "fvp" "Arm EULA accepted via ARM_FVP_INSTALL_I_AGREE_TO_THE_CONTAINED_EULA=True" + fi + fi +} + +function setup_fvp() { + if [[ "${OS}" != "Linux" ]]; then + # Check if FVP is callable + if command -v FVP_Corstone_SSE-300_Ethos-U55 &> /dev/null; then + log_step "fvp" "Detected pre-installed MacOS FVP binaries; continuing" + return 0 # If true exit gracefully and proceed with setup + else + log_step "fvp" "Warning: FVP setup only supported on Linux; Mac users should install via https://github.com/Arm-Examples/FVPs-on-Mac and ensure binaries are on PATH" + return 1 # Throw error. User need to install FVP according to ^^^ + fi + fi +} + +function setup_path_fvp() { + fvps=("corstone300" "corstone320") + for fvp in "${fvps[@]}"; do + model_dir_variable=${fvp}_model_dir + fvp_model_dir=${!model_dir_variable} + fvp_bin_path="${root_dir}/FVP-${fvp}/models/${fvp_model_dir}" + append_env_in_setup_path PATH ${fvp_bin_path} + done + + # Fixup for Corstone-320 python dependency + append_env_in_setup_path LD_LIBRARY_PATH "${root_dir}/FVP-corstone320/python/lib/" + + echo "hash FVP_Corstone_SSE-300_Ethos-U55" >> ${setup_path_script}.sh + echo "hash FVP_Corstone_SSE-300_Ethos-U65" >> ${setup_path_script}.sh + echo "hash FVP_Corstone_SSE-320" >> ${setup_path_script}.sh +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/install_models_for_test.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/install_models_for_test.sh new file mode 100644 index 0000000..d6a7b9c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/install_models_for_test.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -e +pip install -r backends/arm/requirements-arm-models-test.txt + +# Install model gym repository +git clone https://github.com/arm/neural-graphics-model-gym.git +cd neural-graphics-model-gym +# Remove model-converter installation from model-gym repository (to prevent overwriting executorch version) +if [[ "$(uname)" == "Darwin" ]]; then + sed -i '' 's/^model-converter = "ng_model_gym.bin.model_converter_launcher:main"/#&/' pyproject.toml +else + sed -i 's/^model-converter = "ng_model_gym.bin.model_converter_launcher:main"/#&/' pyproject.toml +fi +pip install . --no-deps +cd .. +rm -rf neural-graphics-model-gym \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/mlsdk_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/mlsdk_utils.sh new file mode 100755 index 0000000..87fc206 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/mlsdk_utils.sh @@ -0,0 +1,258 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -euo pipefail + +# URL and tag of the MLSDK manifest repository. Can be overridden by environment variables. +# eg. export MLSDK_MANIFEST_URL=...; export MLSDK_MANIFEST_TAG=... +mlsdk_manifest_url="${MLSDK_MANIFEST_URL:-https://github.com/arm/ai-ml-sdk-manifest.git}" +mlsdk_manifest_tag="${MLSDK_MANIFEST_TAG:-refs/tags/v2025.12.0}" + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) + +source ${script_dir}/utils.sh + +function mlsdk_sync_manifest() { + local manifest_dir="$1" + + mkdir -p "${manifest_dir}" + pushd "${manifest_dir}" || return 1 + local parallel_jobs="$(get_parallel_jobs)" + + if [[ ! -f repo ]]; then + log_step "mlsdk" "Fetching repo tool" + curl https://storage.googleapis.com/git-repo-downloads/repo > repo + chmod u+x repo + fi + + ./repo init \ + --depth=1 \ + --no-repo-verify \ + --manifest-url "${mlsdk_manifest_url}" \ + --manifest-branch "${mlsdk_manifest_tag}" \ + -g model-converter,emulation-layer,vgf-library + + local default_manifest=".repo/manifests/default.xml" + + ./repo sync --force-sync -j"${parallel_jobs}" + + popd +} + +function download_ai_mlsdk_manifest() { + local _manifest_dir="$1" + + if [[ -z "${_manifest_dir}" ]]; then + log_step "mlsdk" "Error: _manifest_dir parameter missing" + return 1 + fi + + if [[ -z "${mlsdk_manifest_url}" ]]; then + log_step "mlsdk" "Error: mlsdk_manifest_url parameter missing" + return 1 + fi + + if [[ ! -d "${_manifest_dir}/sw" ]] || [[ ! -d "${_manifest_dir}/dependencies" ]]; then + log_step "mlsdk" "MLSDK checkout not found at ${_manifest_dir}; performing initial download" + mlsdk_sync_manifest "${_manifest_dir}" + return 0 + fi + + # If a checkout exists, get the URL and tag of the existing checkout. + local cached_url="" + local cached_tag="" + local repo_config="${_manifest_dir}/.repo/manifests.git/config" + if [[ -f "${repo_config}" ]]; then + cached_url="$(git config --file "${repo_config}" remote.origin.url 2>/dev/null || echo "")" + cached_tag="$(git config --file "${repo_config}" branch.default.merge 2>/dev/null || echo "")" + fi + + # If the tag is main or refs/heads/main, always refresh the checkout. + # This allows users to track the latest main branch without needing to manually + # delete the checkout. + local tag_tracks_main=0 + if [[ "${mlsdk_manifest_tag}" == "main" ]] || [[ "${mlsdk_manifest_tag}" == "refs/heads/main" ]]; then + tag_tracks_main=1 + fi + + # If the URL and tag match, and the tag does not track main, reuse the existing checkout. + # Skip fetching updates. + if [[ "${cached_url}" == "${mlsdk_manifest_url}" ]] && [[ "${cached_tag}" == "${mlsdk_manifest_tag}" ]] && [[ "${tag_tracks_main}" -eq 0 ]]; then + log_step "mlsdk" "Reusing cached MLSDK dependencies at ${_manifest_dir}" + return 0 + fi + + # If we reach here, either the URL or tag changed, or the tag tracks main. + # In all cases, refresh the checkout. + if [[ "${tag_tracks_main}" -eq 1 ]]; then + log_step "mlsdk" "Manifest tracks branch ${mlsdk_manifest_tag}; refreshing checkout" + else + log_step "mlsdk" "Manifest changed (url=${cached_url:-} -> ${mlsdk_manifest_url}, tag=${cached_tag:-} -> ${mlsdk_manifest_tag}); refreshing checkout" + fi + + # Clean up any local manifest changes to avoid repo sync errors. + # Since we patched in a local manifest for tosa_gitlab.xml, + # remove any existing local manifests to avoid conflicts. + # TODO: we should remove this at some point in the future, but its not hurting anything for now. + if [[ -d "${_manifest_dir}/.repo/local_manifests" ]]; then + rm -rf "${_manifest_dir}/.repo/local_manifests/" + fi + + # Clean up any local changes in the manifests repository. + if [[ -d "${_manifest_dir}/.repo/manifests.git" ]]; then + git -C "${_manifest_dir}/.repo/manifests.git" reset --hard HEAD >/dev/null 2>&1 || true + git -C "${_manifest_dir}/.repo/manifests.git" clean -fd >/dev/null 2>&1 || true + fi + + # Clean up any local changes in the manifests working copy. + if [[ -d "${_manifest_dir}/.repo/manifests" ]]; then + git -C "${_manifest_dir}/.repo/manifests" reset --hard HEAD >/dev/null 2>&1 || true + git -C "${_manifest_dir}/.repo/manifests" clean -fd >/dev/null 2>&1 || true + fi + + # Going from v2025.10.0 to v2025.12.0 seems particular hard so just keep it simple. + # TODO: Remove once this is history + if [[ "${cached_tag}" == "refs/tags/v2025.10.0" ]] && [[ "${mlsdk_manifest_tag}" == "refs/tags/v2025.12.0" ]]; then + pushd "${_manifest_dir}/.." + log_step "mlsdk" "Deleting ${mlsdk_manifest_dir} and starting fresh" + manifest_base_dir=$(basename "${_manifest_dir}") + rm -fr $manifest_base_dir + popd + fi + + mlsdk_sync_manifest "${_manifest_dir}" +} + +function setup_mlsdk() { + local work_dir="$1" + local manifest_dir="$2" + local enable_model_converter="$3" + local enable_vgf_lib="$4" + local enable_emulation_layer="$5" + + if [[ -z "$work_dir" ]]; then + log_step "mlsdk" "Error: work_dir parameter is required" + return 1 + fi + + if [[ -z "$manifest_dir" ]]; then + log_step "mlsdk" "Error: manifest_dir parameter is required" + return 1 + fi + + mkdir -p "$work_dir" + pushd "$work_dir" || exit 1 + + log_step "mlsdk" "Syncing MLSDK manifest into ${manifest_dir}" + download_ai_mlsdk_manifest "${manifest_dir}" + + pushd "$manifest_dir" + local parallel_jobs="$(get_parallel_jobs)" + + # model-converter + if [[ "${enable_model_converter}" -eq 1 ]]; then + log_step "mlsdk" "Building MLSDK model-converter" + python sw/model-converter/scripts/build.py -j"${parallel_jobs}" + log_step "mlsdk" "MLSDK model-converter build complete" + fi + + # libvgf + if [[ "${enable_vgf_lib}" -eq 1 ]]; then + log_step "mlsdk" "Building MLSDK VGF library" + pushd sw/vgf-lib + python scripts/build.py -j"${parallel_jobs}" + cmake --install build --prefix deploy + log_step "mlsdk" "MLSDK VGF library build complete" + popd + fi + + # emu layer + if [[ "${enable_emulation_layer}" -eq 1 ]]; then + log_step "mlsdk" "Building MLSDK Vulkan emulation layer" + pushd sw/emulation-layer + cmake -B build \ + -DGLSLANG_PATH=../../dependencies/glslang \ + -DSPIRV_CROSS_PATH=../../dependencies/SPIRV-Cross \ + -DSPIRV_HEADERS_PATH=../../dependencies/SPIRV-Headers \ + -DSPIRV_TOOLS_PATH=../../dependencies/SPIRV-Tools \ + -DVULKAN_HEADERS_PATH=../../dependencies/Vulkan-Headers + + cmake --build build -j"${parallel_jobs}" + cmake --install build --prefix deploy + log_step "mlsdk" "MLSDK Vulkan emulation layer build complete" + popd + fi + + popd +} + +function setup_path_model_converter() { + cd "${root_dir}" + model_converter_bin_path="$(cd "${mlsdk_manifest_dir}/sw/model-converter/build" && pwd)" + append_env_in_setup_path PATH "${model_converter_bin_path}" +} + +function setup_path_vgf_lib() { + cd "${root_dir}" + model_vgf_path="$(cd "${mlsdk_manifest_dir}/sw/vgf-lib/deploy" && pwd)" + append_env_in_setup_path PATH "${model_vgf_path}/bin" + append_env_in_setup_path LD_LIBRARY_PATH "${model_vgf_path}/lib" + append_env_in_setup_path DYLD_LIBRARY_PATH "${model_vgf_path}/lib" +} + +function setup_path_emulation_layer() { + cd "${root_dir}" + model_emulation_layer_path="$(cd "${mlsdk_manifest_dir}/sw/emulation-layer/" && pwd)" + prepend_env_in_setup_path LD_LIBRARY_PATH "${model_emulation_layer_path}/deploy/lib" + prepend_env_in_setup_path DYLD_LIBRARY_PATH "${model_emulation_layer_path}/deploy/lib" + prepend_env_in_setup_path VK_LAYER_PATH "${model_emulation_layer_path}/deploy/share/vulkan/explicit_layer.d" + prepend_env_in_setup_path VK_INSTANCE_LAYERS VK_LAYER_ML_Tensor_Emulation + prepend_env_in_setup_path VK_INSTANCE_LAYERS VK_LAYER_ML_Graph_Emulation +} + +function setup_path_emulation_layer_from_pip() { + if ! command -v emulation_layer >/dev/null 2>&1; then + echo "[mlsdk_utils] 'emulation_layer' command not found; skipping pip emulation layer path setup" + return + fi + + local output + if ! output=$(emulation_layer 2>/dev/null); then + echo "[mlsdk_utils] Failed to query emulation_layer environment; skipping" + return + fi + + local exports + exports=$(echo "$output" | grep '^export ' || true) + + local ld_line + ld_line=$(echo "$exports" | grep 'LD_LIBRARY_PATH=' || true) + if [[ -n "${ld_line}" ]]; then + local ld_value=${ld_line#export LD_LIBRARY_PATH=} + ld_value=${ld_value%%:\$LD_LIBRARY_PATH*} + if [[ -n "${ld_value}" ]]; then + prepend_env_in_setup_path LD_LIBRARY_PATH "${ld_value}" + fi + fi + + local vk_add_line + vk_add_line=$(echo "$exports" | grep 'VK_ADD_LAYER_PATH=' || true) + if [[ -n "${vk_add_line}" ]]; then + local vk_add_value=${vk_add_line#export VK_ADD_LAYER_PATH=} + if [[ -n "${vk_add_value}" ]]; then + prepend_env_in_setup_path VK_ADD_LAYER_PATH "${vk_add_value}" + fi + fi + + local vk_instance_line + vk_instance_line=$(echo "$exports" | grep 'VK_INSTANCE_LAYERS=' || true) + if [[ -n "${vk_instance_line}" ]]; then + local vk_instance_value=${vk_instance_line#export VK_INSTANCE_LAYERS=} + if [[ -n "${vk_instance_value}" ]]; then + prepend_env_in_setup_path VK_INSTANCE_LAYERS "${vk_instance_value}" + fi + fi +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/parse_test_names.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/parse_test_names.py new file mode 100644 index 0000000..beb8f73 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/parse_test_names.py @@ -0,0 +1,271 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from __future__ import annotations + +import ast +import os + +import pathlib +import re + +import sys + +from executorch.backends.arm.scripts.collect_testname_resources import ( + MODEL_LIST, + OP_LIST, + PASS_LIST, + TARGETS, +) + + +ALLOWED_DIRNAMES = ("misc", "passes", "models", "quantizer", "ops") + +SUFFIX_GROUP = r"(?:" + r"|".join(TARGETS) + r")" +DEFAULT_PATTERN = re.compile( + rf"^test_.*_(?P{SUFFIX_GROUP})(?:_.*)?$", +) +TARGET_EXTRACT_PATTERN = re.compile(rf"(?P{SUFFIX_GROUP})(?:_.*)?$") +TARGET_CHOICES_DISPLAY = ", ".join(TARGETS) + + +class TestCollector(ast.NodeVisitor): + def __init__(self, path: pathlib.Path, collected: list[str]): + self.path = path + self._collected = collected + self._class_stack: list[str] = [] + + def visit_ClassDef(self, node: ast.ClassDef): + self._class_stack.append(node.name) + self.generic_visit(node) + self._class_stack.pop() + + def visit_FunctionDef(self, node: ast.FunctionDef): + self._record_test(node) + self.generic_visit(node) + + def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef): + self._record_test(node) + self.generic_visit(node) + + def _record_test(self, node: ast.AST): + name = getattr(node, "name", "") + if name.startswith("test_"): + self._collected.append(str(self.path) + "::" + name) + + +def collect_test_files(test_root: pathlib.Path): + search_dirs = [] + for dirname in ALLOWED_DIRNAMES: + dir_path = test_root / dirname + if dir_path.is_dir(): + search_dirs.append(dir_path) + else: + print(f"warning: skipped missing directory {dir_path}", file=sys.stderr) + + file_paths: list[pathlib.Path] = [] + for dir_path in search_dirs: + file_paths.extend(dir_path.rglob("test_*.py")) + return sorted(file_paths) + + +def collect_tests(file_paths: list[pathlib.Path]) -> list[str]: + tests: list[str] = [] + for file_path in file_paths: + try: + source = file_path.read_text(encoding="utf-8") + except OSError as error: + print(f"warning: failed to read {file_path}: {error}", file=sys.stderr) + continue + + try: + tree = ast.parse(source, filename=str(file_path)) + except SyntaxError as error: + print(f"warning: failed to parse {file_path}: {error}", file=sys.stderr) + continue + + TestCollector(file_path, tests).visit(tree) + + return tests + + +def _match_allowed_op_prefix(test_name: str) -> tuple[str, str, bool]: + """ + Parses a test name on the form + test_OP_TARGET__ + where OP must match a key in op_name_map and TARGET one string in TARGETS. The + "not_delegated" suffix indicates that the test tests that the op is not delegated. + + Examples of valid names: "test_mm_u55_INT_not_delegated" and + "test_add_scalar_tosa_FP_two_inputs". + + Returns a tuple (OP, TARGET, IS_DELEGATED) if valid. + """ + test_name = test_name.removeprefix("test_") + is_delegated = "not_delegated" not in test_name + + op = "None" + target = "None" + for potential_target in TARGETS: + index = test_name.find(potential_target) + if index != -1: + op = test_name[: index - 1] + target = potential_target + break + # Special case for convolution + op = op.removesuffix("_1d") + op = op.removesuffix("_2d") + op = op.removesuffix("_3d") + + # Remove suffix for 16 bit activation and 8 bit weight test cases + op = op.removesuffix("_16a8w") + + return op, target, is_delegated + + +def _match_allowed_model_prefix(token: str, allowed_models: list[str]) -> str | None: + for allowed_model in allowed_models: + if token == allowed_model: + return allowed_model + return None + + +def _match_allowed_pass_prefix(token: str, allowed_passes: list[str]) -> str | None: + for allowed_pass in allowed_passes: + if token == allowed_pass: + return allowed_pass + return None + + +def _extract_target(name: str) -> str | None: + match = TARGET_EXTRACT_PATTERN.search(name) + if match and match.end() == len(name): + return match.group("target") + return None + + +def _parse_name_tokens(name: str) -> tuple[str, str]: + rest = name[5:] + target = _extract_target(name) + token = rest.rstrip("_") + if target: + idx = rest.rfind(target) + token = rest[:idx].rstrip("_") + return token, target # type: ignore[return-value] + + +def _describe_name_issue(kind: str, name: str) -> str: + token, target = _parse_name_tokens(name) + details: list[str] = [] + if token: + details.append(f"{kind} token parsed as '{token}'\n ") + else: + details.append(f"missing {kind} token before target\n ") + + if target: + details.append(f"target token parsed as '{target}'") + else: + details.append( + f"missing target suffix (expected one of: {TARGET_CHOICES_DISPLAY}" + ) + + details.append( + "\n please follow the test naming convention: https://confluence.arm.com/display/MLENG/Executorch+naming+conventions" + ) + + return "".join(details) + + +def check_test_convention( # noqa: C901 + tests: list[str], + allowed_ops: list[str], + allowed_models: list[str], + allowed_passes: list[str], +) -> list[str]: + violations: list[str] = [] + for test in tests: + path = test.split("::")[0] + name = test.split("::")[1] + try: + assert name[:5] == "test_", f"Unexpected input: {name}" + if str(os.sep) + "ops" + str(os.sep) in path: + matched_op, target, delegated = _match_allowed_op_prefix(name) + if "reject" in name: + desc = _describe_name_issue("op", name) + violations.append( + f"{test}\n expected test_OP_TARGET_*\n Use 'not_delegated' instead of 'reject' in {name}\n" + ) + if target == "None" or matched_op not in allowed_ops: + desc = _describe_name_issue("op", name) + violations.append( + f"{test}\n expected test_OP_TARGET_*\n {desc}\n" + ) + continue + if str(os.sep) + "models" + str(os.sep) in path: + token, target = _parse_name_tokens(name) + if not target or not token: + desc = _describe_name_issue("model", name) + violations.append( + f"{test}\n expected test_MODEL_TARGET_*\n {desc}\n" + ) + continue + matched_model = _match_allowed_model_prefix(token, allowed_models) + if matched_model is None: + desc = _describe_name_issue("model", name) + violations.append( + f"{test}\n unknown model prefix '{token}'\n expected test_MODEL_TARGET_* with MODEL in MODEL_LIST\n {desc}\n" + ) + continue + continue + if str(os.sep) + "passes" + str(os.sep) in path: + token, target = _parse_name_tokens(name) + if not target or not token: + desc = _describe_name_issue("pass", name) + violations.append( + f"{test}\n expected test_PASS_TARGET_*\n {desc}\n" + ) + continue + matched_pass = _match_allowed_pass_prefix(token, allowed_passes) + if matched_pass is None: + desc = _describe_name_issue("pass", name) + violations.append( + f"{test}\n unknown pass prefix '{token}'\n expected test_PASS_TARGET_* with PASS in PASS_LIST\n {desc}\n" + ) + continue + continue + if ( + str(os.sep) + "quantizer" + str(os.sep) in path + or str(os.sep) + "misc" + str(os.sep) in path + ): + token, target = _parse_name_tokens(name) + if not target or not token: + desc = _describe_name_issue("name", name) + violations.append( + f"{test}\n expected test_*_TARGET_*\n {desc}\n" + ) + continue + continue + except AssertionError as e: + print(e) + return violations + + +if __name__ == "__main__": + """Parses a list of test names given on the commandline.""" + + sys.tracebacklimit = 0 # Do not print stack trace + tests: list[str] = [] + path_list: list[pathlib.Path] = [pathlib.Path(path) for path in sys.argv[1:]] + + if path_list == []: + tests = collect_tests(collect_test_files(pathlib.Path("backends/arm/test"))) + else: + tests = collect_tests(path_list) + + violations = check_test_convention(tests, OP_LIST, MODEL_LIST, PASS_LIST) + + for entry in violations: + print(entry) + + print(f"Total tests needing renaming: {len(violations)}") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-commit b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-commit new file mode 100755 index 0000000..2000585 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-commit @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Check 1: If commit header contains WIP, everything is ok +git rev-list --format=%s --max-count=1 HEAD | grep -q WIP && exit 0 + +# Check 2: lintunner on latest patch. +lintrunner -a --revision 'HEAD^' --skip MYPY +commit_files=$(git diff-tree --no-commit-id --name-only --diff-filter=M HEAD -r) +git add $commit_files || true \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-push b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-push new file mode 100755 index 0000000..ce96a92 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/pre-push @@ -0,0 +1,215 @@ +#!/bin/bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Calling this script with one argument is equal to launching it in +# non-interactive mode. "$#" gives the number of positional arguments. +[ "$#" -eq 1 ] && is_script_interactive=1 || is_script_interactive=0 + +if [ $is_script_interactive -eq 1 ]; then + RESET='\e[0m' + RED='\e[31m' + GREEN='\e[32m' + YELLOW='\e[33m' + BLUE='\e[34m' +fi + +INFO="${BLUE}[INFO]${RESET}" +WARNING="${YELLOW}[WARNING]${RESET}" +ERROR="${RED}[ERROR]${RESET}" +SUCCESS="${GREEN}[SUCCESS]${RESET}" + +# This list of imperative verbs was compiled from the entire list of Executorch +# commits. It should be fairly exhaustive, but add more verbs if you find one +# that's missing. +VERBS="Add|Fix|Update|Refactor|Improve|Remove|Change|Implement|Create|Modify|"\ +"Enable|Integrate|Make|Support|Deprecate|Extend|Enhance|Convert|Rewrite|Unify|"\ +"Optimize|Expand|Reorganize|Adjust|Streamline|Clarify|Introduce|Document|"\ +"Polish|Standardize|Revise|Simplify|Restore|Resolve|Replace|Suppress|Migrate|"\ +"Generate|Delete|Exclude|Register|Include|Upgrade|Validate|Verify|Refine|"\ +"Reimplement|Patch|Sync|Revert|Fixup|Enhance|Append|Annotate|Disable|Emit|"\ +"Handle|Ignore|Interpret|Instantiate|Invoke|Limit|Load|Modify|Permit|Print|"\ +"Profile|Recalculate|Reconstruct|Redefine|Redesign|Reevaluate|Relocate|Remap|"\ +"Render|Reposition|Request|Revert|Sanitize|Specify|Strengthen|Stub|Substitute|"\ +"Tag|Tweak|Unify|Unlock|Unset|Use|Validate|Verify|Rename|Relax" + +# Remote branch +REMOTE=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null) +if [ $is_script_interactive -eq 0 ]; then + # Just use the one commit + COMMITS=$(git rev-list HEAD -n 1) +elif [ -z "$REMOTE" ]; then + echo -e "${WARNING} Could not find upstream branch to compare to." + echo "Please specify the number of commits you are pushing." + echo -n "Enter number of commits to check (default 1): " > /dev/tty + read NUM_COMMITS < /dev/tty + NUM_COMMITS=${NUM_COMMITS:-1} # Default to 1 if empty + RANGE=$(git rev-list HEAD -n "$NUM_COMMITS") + COMMITS=${RANGE} +elif [ "$(git rev-parse --abbrev-ref HEAD)" == "HEAD" ]; then + echo -e "${WARNING} You're in a detached HEAD state." + echo "Please specify the number of commits you are pushing." + echo -n "Enter number of commits to check (default 1): " > /dev/tty + read NUM_COMMITS < /dev/tty + NUM_COMMITS=${NUM_COMMITS:-1} # Default to 1 if empty + RANGE=$(git rev-list HEAD -n "$NUM_COMMITS") + COMMITS=${RANGE} +else + # Determine commits to check + RANGE="$REMOTE..HEAD" + COMMITS=$(git rev-list "$RANGE") +fi + +if [ -z "$COMMITS" ]; then + echo -e "${INFO} No new commits to check." + exit 0 +fi + +for COMMIT in ${COMMITS}; do + if [ -n "$REMOTE" ] && git merge-base --is-ancestor "$COMMIT" "$REMOTE"; then + echo -e "${INFO} Skipping commit ${COMMIT} (already on $REMOTE)" + continue + fi + + # If commit header contains WIP, everything is ok + git rev-list --format=%s --max-count=1 ${COMMIT} | grep -q WIP && \ + continue + + echo -e "${INFO} Checking commit ${COMMIT}" + + # lintrunner on latest patches. + echo -e "${INFO} Lintrunner" + MYPYPATH=./src/ lintrunner --revision ${COMMIT}^1 + if [[ $? != 0 ]]; then + echo -e "${ERROR} Failed linting" + FAILED=1 + else + echo -e "${SUCCESS} Lintrunner OK" + fi + + # Check license headers + # We do a simple check of if all committed headers contain + # "$current_year Arm". This does not guarantee OK in ci but should be ok + # most of the time. + echo -e "${INFO} License check" + + current_year=$(date +%Y) + failed_license_check=false + commit_files=$(git diff-tree --no-commit-id --name-only \ + --diff-filter=ACMR ${COMMIT} -r) + for commited_file in $commit_files; do + file_header=$(head "$commited_file") + if ! echo "$file_header" | grep -qi "Arm"; then + echo -e "${WARNING} No Arm copyright header in ${commited_file}"\ + " (skipping license year check)" + continue + fi + + if ! echo "$file_header" | grep -q "$current_year Arm"; then + echo -e "${ERROR} Header in $commited_file did not contain"\ + "'$current_year Arm'" + failed_license_check=true + else + echo -e "${SUCCESS} $commited_file passed license check" + fi + done + + if [[ $failed_license_check == true ]]; then + FAILED=1 + else + echo -e "${SUCCESS} All files passed license check" + fi + + # Check commit message + echo -e "${INFO} Checking commit message" + COMMIT_MSG=$(git log -1 --format=%B "$COMMIT") + + SUBJECT=$(echo "$COMMIT_MSG" | head -n1) + BODY=$(echo "$COMMIT_MSG" | tail -n +2) + + # Check subject length (72 chars) + SUBJECT_MAX_LEN=72 + if [ ${#SUBJECT} -gt ${SUBJECT_MAX_LEN} ]; then + echo -e "${ERROR} Subject exceeds ${SUBJECT_MAX_LEN} characters:"\ + "'${SUBJECT}'" >&2 + + FAILED=1 + else + echo -e "${SUCCESS} Commit message subject OK" + fi + + # Check body line length (72 chars) + BODY_MAX_LEN=72 + line_number=2 # Subject + 1 empty line + failed_body_check=false + while IFS= read -r line; do + if [ ${#line} -gt ${BODY_MAX_LEN} ]; then + echo -e "${ERROR} Line ${line_number} in body exceeds"\ + "${BODY_MAX_LEN} characters: '$line'" >&2 + + failed_body_check=true + fi + + ((line_number++)) + done <<< "$BODY" + + if [[ $failed_body_check == true ]]; then + FAILED=1 + else + echo -e "${SUCCESS} Commit message body OK" + fi + + # Check for Signed-off-by + if ! echo "$COMMIT_MSG" | grep -qE "^Signed-off-by: "; then + echo -e "${ERROR} Commit message must contain a 'Signed-off-by'"\ + "footer." >&2 + + FAILED=1 + fi + + # Check subject format, should start with 'Arm backend: ' and be + # imperative mood. + if [[ ! "$SUBJECT" =~ ^"Arm backend":\ (${VERBS}) ]]; then + echo -e "${WARNING} Subject should start with 'Arm backend: '"\ + "followed by an imperative verb." >&2 + + if [ $is_script_interactive -eq 1 ]; then + echo -n "There are warnings in your commit message. Do you want to"\ + "ignore the warning (y/N): " > /dev/tty + + read USER_INPUT < /dev/tty + + # Check user input for warnings + if [[ ! "$USER_INPUT" =~ ^[Yy]$ ]]; then + FAILED=1 + fi + fi + fi + + # Test name checks + test_files=$(echo $commit_files | grep -oE 'backends/arm/test/\S+') + if [ "$test_files" ]; then + + # Check that the test name follows the specified convention + python ./backends/arm/scripts/parse_test_names.py $test_files + if [ $? -ne 0 ]; then + echo -e "${ERROR} Failed op test name check." >&2 + FAILED=1 + fi + fi + + echo "" # Newline to visually separate commit processing +done + +if [[ $FAILED ]]; then + echo -e "${INFO} Fix your commit message errors with"\ + "'git commit --amend' or 'git commit --fixup='" + + exit 1 +else + echo -e "${SUCCESS} All checks passed" +fi + +exit 0 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_fvp.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_fvp.sh new file mode 100755 index 0000000..7dcebb2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_fvp.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Optional parameter: +# --build_type= "Release" | "Debug" | "RelWithDebInfo" +# --etdump build with devtools-etdump support + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + + +elf_file="" +data_file="" +target="ethos-u55-128" +timeout="600" +etrecord_file="" +trace_file="" + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --elf= elf file to run" + echo " --data=@
Place a file in memory at this address, useful to emulate a PTE flashed into memory instead as part of the code." + echo " --target= Target to build and run for Default: ${target}" + echo " --timeout= Maximum target runtime, used to detect hanging, might need to be higer on large models Default: ${timeout}" + echo " --etrecord= If ETDump is used you can supply a ETRecord file matching the PTE" + echo " --trace_file= File to write PMU trace output to" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --elf=*) elf_file="${arg#*=}";; + --data=*) data_file="--data ${arg#*=}";; + --target=*) target="${arg#*=}";; + --timeout=*) timeout="${arg#*=}";; + --etrecord=*) etrecord_file="${arg#*=}";; + --trace_file=*) trace_file="${arg#*=}";; + *) + ;; + esac +done + +elf_file=$(realpath ${elf_file}) + +if [[ ${target} == *"ethos-u55"* ]]; then + fvp_model=FVP_Corstone_SSE-300_Ethos-U55 +else + fvp_model=FVP_Corstone_SSE-320 +fi + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +# basic checks before we get started +hash ${fvp_model} \ + || { echo "Could not find ${fvp_model} on PATH, ${_setup_msg}"; exit 1; } + + +[[ ! -f $elf_file ]] && { echo "[${BASH_SOURCE[0]}]: Unable to find executor_runner elf: ${elf_file}"; exit 1; } +num_macs=$(echo ${target} | cut -d - -f 3) + +echo "--------------------------------------------------------------------------------" +echo "Running ${elf_file} for ${target} run with FVP:${fvp_model} num_macs:${num_macs} timeout:${timeout}" +echo "WARNING: Corstone FVP is not cycle accurate and should NOT be used to determine valid runtime" +echo "--------------------------------------------------------------------------------" + +# Check if stdbuf is intalled and use stdbuf -oL together with tee below to make the output +# go all the way to the console more directly and not be buffered + +if hash stdbuf 2>/dev/null; then + nobuf="stdbuf -oL" +else + nobuf="" +fi + +log_file=$(mktemp) + +extra_args_u55=() +extra_args_u85=() + +if [[ -n "${trace_file}" ]]; then + extra_args_u55+=(-C "ethosu.extra_args=--pmu-trace ${trace_file}") + extra_args_u85+=(-C "mps4_board.subsystem.ethosu.extra_args=--pmu-trace ${trace_file}") +fi + +if [[ ${target} == *"ethos-u55"* ]]; then + ${nobuf} ${fvp_model} \ + -C ethosu.num_macs=${num_macs} \ + -C mps3_board.visualisation.disable-visualisation=1 \ + -C mps3_board.telnetterminal0.start_telnet=0 \ + -C mps3_board.uart0.out_file='-' \ + -C mps3_board.uart0.shutdown_on_eot=1 \ + "${extra_args_u55[@]}" \ + -a "${elf_file}" \ + ${data_file} \ + --timelimit ${timeout} 2>&1 | sed 's/\r$//' | tee ${log_file} || true # seconds + echo "[${BASH_SOURCE[0]}] Simulation complete, $?" +elif [[ ${target} == *"ethos-u85"* ]]; then + ${nobuf} ${fvp_model} \ + -C mps4_board.subsystem.ethosu.num_macs=${num_macs} \ + -C mps4_board.visualisation.disable-visualisation=1 \ + -C vis_hdlcd.disable_visualisation=1 \ + -C mps4_board.telnetterminal0.start_telnet=0 \ + -C mps4_board.uart0.out_file='-' \ + -C mps4_board.uart0.shutdown_on_eot=1 \ + "${extra_args_u85[@]}" \ + -a "${elf_file}" \ + ${data_file} \ + --timelimit ${timeout} 2>&1 | sed 's/\r$//' | tee ${log_file} || true # seconds + echo "[${BASH_SOURCE[0]}] Simulation complete, $?" +else + echo "Running ${elf_file} for ${target} is not supported" + exit 1 +fi + +echo "Checking for a etdump in log" +! grep "#\[RUN THIS\]" ${log_file} >/dev/null +if [ $? != 0 ]; then + echo "Found ETDump in log!" + devtools_extra_args="" + echo "#!/bin/sh" > etdump_script.sh + sed -n '/^#\[RUN THIS\]$/,/^#\[END\]$/p' ${log_file} >> etdump_script.sh + # You can run etdump_script.sh if you do + # $ chmod a+x etdump_script.sh + # $ ./etdump_script.sh + # But lets not trust the script as a bad patch would run bad code on your machine + grep ">etdump.bin" etdump_script.sh | cut -d\" -f2- | cut -d\" -f1 | base64 -d >etdump.bin + ! grep ">debug_buffer.bin" etdump_script.sh >/dev/null + if [ $? != 0 ]; then + grep ">debug_buffer.bin" etdump_script.sh | cut -d\" -f2- | cut -d\" -f1 | base64 -d >debug_buffer.bin + devtools_extra_args="${devtools_extra_args} --debug_buffer_path debug_buffer.bin" + fi + if [[ ${etrecord_file} != "" ]]; then + devtools_extra_args="${devtools_extra_args} --etrecord_path ${etrecord_file}" + fi + python3 -m devtools.inspector.inspector_cli --etdump_path etdump.bin ${devtools_extra_args} --source_time_scale cycles --target_time_scale cycles +fi + +echo "Checking for problems in log:" +! grep -E "^(F|E|\\[critical\\]|Hard fault.|Info: Simulation is stopping. Reason: CPU time has been exceeded.).*$" ${log_file} +if [ $? != 0 ]; then + echo "Found ERROR" + rm "${log_file}" + exit 1 +fi +echo "No problems found!" +rm "${log_file}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_vkml.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_vkml.sh new file mode 100755 index 0000000..d65600e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/run_vkml.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Optional parameter: +# --build_type= "Release" | "Debug" | "RelWithDebInfo" +# --etdump build with devtools-etdump support + +set -eu +set -o pipefail + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + + +model="" +opt_flags="" +build_path="cmake-out-vkml" +converter="model-converter" + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --model= .pte model file to run" + echo " --build_path= Path to executor_runner build. for Default: ${build_path}" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --optional_flags=*) opt_flags="${arg#*=}";; + --model=*) model="${arg#*=}";; + --build_path=*) build_path="${arg#*=}";; + *) + ;; + esac +done + +if [[ -z ${model} ]]; then echo "Model name needs to be provided"; exit 1; fi + + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +if ! command -v "${converter}" >/dev/null 2>&1; then + if command -v model_converter >/dev/null 2>&1; then + converter="model_converter" + fi +fi + +command -v "${converter}" >/dev/null 2>&1 \ + || { echo "Could not find a model converter executable (tried model-converter, model_converter). ${_setup_msg}"; exit 1; } + + +runner=$(find ${build_path} -name executor_runner -type f) + + +echo "--------------------------------------------------------------------------------" +echo "Running ${model} with ${runner} ${opt_flags}" +echo "WARNING: The VK_ML layer driver will not provide accurate performance information" +echo "--------------------------------------------------------------------------------" + +# Check if stdbuf is intalled and use stdbuf -oL together with tee below to make the output +# go all the way to the console more directly and not be buffered + +if hash stdbuf 2>/dev/null; then + nobuf="stdbuf -oL" +else + nobuf="" +fi + +log_file=$(mktemp) + + +${nobuf} ${runner} -model_path ${model} ${opt_flags} | tee ${log_file} +echo "[${BASH_SOURCE[0]}] execution complete, $?" + +# Most of these can happen for bare metal or linx executor_runner runs. +echo "Checking for problems in log:" +! grep -E "^(F|E|\\[critical\\]|Hard fault.|Info: Simulation is stopping. Reason: CPU time has been exceeded.).*$" ${log_file} +if [ $? != 0 ]; then + echo "Found ERROR" + rm "${log_file}" + exit 1 +fi +echo "No problems found!" +rm "${log_file}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/setup-dev-env.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/setup-dev-env.sh new file mode 100755 index 0000000..b8c9b3b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/setup-dev-env.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +git_dir=$(git rev-parse --git-dir) +ln $git_dir/../backends/arm/scripts/pre-push $git_dir/hooks +ln $git_dir/../backends/arm/scripts/pre-commit $git_dir/hooks \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/toolchain_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/toolchain_utils.sh new file mode 100644 index 0000000..d9e1cf0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/toolchain_utils.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source "${script_dir}/utils.sh" + +function gcc_select_toolchain() { + if [[ "${ARCH}" == "x86_64" ]] ; then + toolchain_url="https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz" + toolchain_dir="arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi" + toolchain_md5_checksum="0601a9588bc5b9c99ad2b56133b7f118" + elif [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]] ; then + if [[ "${OS}" == "Darwin" ]]; then + toolchain_url="https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-darwin-arm64-arm-none-eabi.tar.xz" + toolchain_dir="arm-gnu-toolchain-13.3.rel1-darwin-arm64-arm-none-eabi" + toolchain_md5_checksum="f1c18320bb3121fa89dca11399273f4e" + elif [[ "${OS}" == "Linux" ]]; then + toolchain_url="https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-aarch64-arm-none-eabi.tar.xz" + toolchain_dir="arm-gnu-toolchain-13.3.rel1-aarch64-arm-none-eabi" + toolchain_md5_checksum="303102d97b877ebbeb36b3158994b218" + fi + else + # This should never happen, it should be covered by setup.sh but catch it anyway + log_step "toolchain" "Error: Unsupported architecture ${ARCH}" + exit 1 + fi +} + +function zephyr_select_toolchain() { + if [[ "${OS}" != "Linux" ]] ; then + log_step "toolchain" "Error: Linux is required for Zephyr toolchain support" + exit 1 + fi + + if [[ "${ARCH}" == "x86_64" ]] ; then + toolchain_url="https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.2/toolchain_linux-x86_64_arm-zephyr-eabi.tar.xz" + toolchain_dir="arm-zephyr-eabi" + toolchain_md5_checksum="93128be0235cf5cf5f1ee561aa6eac5f" + elif [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]] ; then + toolchain_url="https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.2/toolchain_linux-aarch64_arm-zephyr-eabi.tar.xz" + toolchain_dir="arm-zephyr-eabi" + toolchain_md5_checksum="ef4ca56786204439a75270ba800cc64b" + else + # This should never happen, it should be covered by setup.sh but catch it anyway + log_step "toolchain" "Error: Unsupported architecture ${ARCH}" + exit 1 + fi +} + +function select_toolchain() { + if [[ "${target_toolchain}" == "zephyr" ]]; then + zephyr_select_toolchain + else + gcc_select_toolchain + fi + log_step "toolchain" "Selected ${toolchain_dir} for ${ARCH}/${OS}" +} + +function setup_toolchain() { + # Download and install the arm toolchain (default is arm-none-eabi) + # setting --target-toolchain to zephyr sets this to arm-zephyr-eabi + cd "${root_dir}" + if [[ ! -e "${toolchain_dir}.tar.xz" ]]; then + log_step "toolchain" "Downloading ${toolchain_dir} toolchain" + curl --output "${toolchain_dir}.tar.xz" -L "${toolchain_url}" + verify_md5 ${toolchain_md5_checksum} "${toolchain_dir}.tar.xz" || exit 1 + fi + + log_step "toolchain" "Installing ${toolchain_dir} toolchain" + rm -rf "${toolchain_dir}" + tar xf "${toolchain_dir}.tar.xz" +} + +function setup_path_toolchain() { + toolchain_bin_path="$(cd ${toolchain_dir}/bin && pwd)" + append_env_in_setup_path PATH ${toolchain_bin_path} +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/utils.sh new file mode 100644 index 0000000..1b4a920 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/utils.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +# Usage: +# log_step +# eg. +# log_step "step" "information message" +# outputs: +# [setup/step] information message +function log_step() { + local context="${1:-main}" + shift || true + local message="$*" + printf "[Arm Setup/%s] %s\n" "${context}" "${message}" +} + +function get_parallel_jobs() { + if command -v nproc >/dev/null 2>&1; then + nproc + elif command -v sysctl >/dev/null 2>&1 && sysctl hw.logicalcpu >/dev/null 2>&1; then + sysctl -n hw.logicalcpu + elif command -v getconf >/dev/null 2>&1; then + getconf _NPROCESSORS_ONLN + elif [[ -n "${NUMBER_OF_PROCESSORS:-}" ]]; then + echo "${NUMBER_OF_PROCESSORS}" + else + echo 1 + fi +} + +function verify_md5() { + # Compare the md5 of a file with a provided expected value. + + # Arg 1: Expected checksum for file + # Arg 2: Path to file + # Exits with return code 1 if the number of arguments is incorrect. + # Exits with return code 2 if the calculated mf5 does not match the given. + + [[ $# -ne 2 ]] \ + && { echo "[${FUNCNAME[0]}] Invalid number of args, expecting 2, but got $#"; exit 1; } + local ref_checksum="${1}" + local file="${2}" + + if [[ "${OS}" == "Darwin" ]]; then + local file_checksum="$(md5 -q $file)" + else + local file_checksum="$(md5sum $file | awk '{print $1}')" + fi + if [[ ${ref_checksum} != ${file_checksum} ]]; then + echo "Mismatched MD5 checksum for file: ${file}. Expecting ${ref_checksum} but got ${file_checksum}. Exiting." + exit 2 + fi +} + +function patch_repo() { + # Patch git repo found in $repo_dir, starting from patch $base_rev and applying patches found in $patch_dir/$name. + + # Arg 1: Directory of repo to patch + # Arg 2: Rev to start patching at + # Arg 3: Directory 'setup-dir' containing patches in 'setup-dir/$name' + # Exits with return code 1 if the number of arguments is incorrect. + # Does not do any error handling if the base_rev or patch_dir is not found etc. + + [[ $# -ne 3 ]] \ + && { echo "[${FUNCNAME[0]}] Invalid number of args, expecting 3, but got $#"; exit 1; } + + local repo_dir="${1}" + local base_rev="${2}" + local name="$(basename $repo_dir)" + local patch_dir="${3}/$name" + + echo -e "[${FUNCNAME[0]}] Patching ${name} repo_dir:${repo_dir} base_rev:${base_rev} patch_dir:${patch_dir}" + pushd $repo_dir + git fetch + git reset --hard ${base_rev} + + [[ -e ${patch_dir} && $(ls -A ${patch_dir}) ]] && \ + git am -3 ${patch_dir}/*.patch + + echo -e "[${FUNCNAME[0]}] Patched ${name} @ $(git describe --all --long 2> /dev/null) in ${repo_dir} dir.\n" + popd +} + +function check_platform_support() { + # No args + # Exits with return code 1 if the platform is unsupported + + # Make sure we are on a supported platform + if [[ "${ARCH}" != "x86_64" ]] && [[ "${ARCH}" != "aarch64" ]] \ + && [[ "${ARCH}" != "arm64" ]]; then + echo "[main] Error: only x86-64 & aarch64 architecture is supported for now!" + exit 1 + fi +} + +function check_os_support() { + # No args + # Exits with return code 1 if invalid combination of platform and os + + # Check valid combinations of OS and platform + + # Linux on x86_64 + if [[ "${ARCH}" == "x86_64" ]] && [[ "${OS}" != "Linux" ]]; then + echo "Error: Only Linux is supported on x86_64" + exit 1 + fi + + # Linux on arm64/aarch64 + # Darwin on arm64/aarch64 + if [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]]; then + if [[ "${OS}" != "Darwin" ]] && [[ "${OS}" != "Linux" ]]; then + echo "Error: Only Linux and Darwin are supported on arm64" + exit 1 + fi + fi +} + +function prepend_env_in_setup_path() { + echo "export $1=$2:\${$1-}" >> ${setup_path_script}.sh + echo "set --path -pgx $1 $2" >> ${setup_path_script}.fish +} + +function append_env_in_setup_path() { + echo "export $1=\${$1-}:$2" >> ${setup_path_script}.sh + echo "set --path -agx $1 $2" >> ${setup_path_script}.fish +} + +function clear_setup_path() { + # Clear setup_path_script + echo "" > "${setup_path_script}.sh" + echo "" > "${setup_path_script}.fish" +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/vulkan_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/vulkan_utils.sh new file mode 100644 index 0000000..2bbecff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/scripts/vulkan_utils.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source "${script_dir}/utils.sh" + +vulkan_sdk_version="1.4.321.1" +vulkan_sdk_base_dir="vulkan_sdk" + +# MLSDK dependencies +mlsdk_manifest_dir="ml-sdk-for-vulkan-manifest" + +os_name="${OS:-$(uname -s)}" +vulkan_sdk_arch="${ARCH}" + +# Vulkan SDK selection differs between macOS and Linux; macOS has its own SDK version +if [[ "${os_name}" == "Darwin" ]]; then + # Latest published macOS SDK is 1.4.321.0 (1.4.321.1 is not available for macOS) + vulkan_sdk_version="1.4.321.0" + vulkan_sdk_arch="macOS" + vulkan_sdk_url="https://sdk.lunarg.com/sdk/download/${vulkan_sdk_version}/mac/vulkansdk-macos-${vulkan_sdk_version}.zip" + vulkan_sdk_sha256="d873c43acacec1e3330fb530dafd541aa5d8a5726575a98a3f70ca505fc203db" +elif [[ "${os_name}" == "Linux" ]] && [[ "${ARCH}" == "x86_64" ]]; then + vulkan_sdk_url="https://sdk.lunarg.com/sdk/download/${vulkan_sdk_version}/linux/vulkansdk-linux-x86_64-${vulkan_sdk_version}.tar.xz" + vulkan_sdk_sha256="f22a3625bd4d7a32e7a0d926ace16d5278c149e938dac63cecc00537626cbf73" +elif [[ "${os_name}" == "Linux" ]] && ([[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]]); then + if [[ "${vulkan_sdk_arch}" == "arm64" ]]; then + vulkan_sdk_arch="aarch64" + fi + vulkan_sdk_url="https://github.com/jakoch/vulkan-sdk-arm/releases/download/1.4.321.1/vulkansdk-ubuntu-22.04-arm-1.4.321.1.tar.xz" + vulkan_sdk_sha256="c57e318d0940394d3a304034bb7ddabda788b5b0b54638e80e90f7264efe9f84" +else + log_step "vulkan" "Error: only macOS and Linux are supported (detected ${os_name}); architecture must be x86-64 or aarch64/arm64" + exit 1 +fi + +vulkan_sdk_bin_dir="${vulkan_sdk_base_dir}/${vulkan_sdk_version}/${vulkan_sdk_arch}/bin" + +function download_and_extract_vulkan_sdk_linux() { + local vulkan_sdk_tar_file="${vulkan_sdk_url##*/}" + + if [[ ! -e "${vulkan_sdk_tar_file}" ]]; then + log_step "vulkan" "Downloading Vulkan SDK (${vulkan_sdk_version})" + curl -L --output "${vulkan_sdk_tar_file}" "${vulkan_sdk_url}" + echo "${vulkan_sdk_sha256} ${vulkan_sdk_tar_file}" | sha256sum -c - || exit 1 + rm -fr ${vulkan_sdk_base_dir} + fi + + mkdir -p ${vulkan_sdk_base_dir} + tar -C ${vulkan_sdk_base_dir} -xJf "${vulkan_sdk_tar_file}" +} + +function install_vulkan_sdk_macos() { + local vulkan_sdk_zip_file="${vulkan_sdk_url##*/}" + + if [[ ! -e "${vulkan_sdk_zip_file}" ]]; then + log_step "vulkan" "Downloading Vulkan SDK (${vulkan_sdk_version}) for macOS" + curl -L --output "${vulkan_sdk_zip_file}" "${vulkan_sdk_url}" + echo "${vulkan_sdk_sha256} ${vulkan_sdk_zip_file}" | shasum -a 256 -c - || exit 1 + rm -fr ${vulkan_sdk_base_dir} + fi + + log_step "vulkan" "Extracting Vulkan SDK installer" + unzip -q -o "${vulkan_sdk_zip_file}" + + local vulkan_sdk_app_path="" + vulkan_sdk_app_path="$(find . -maxdepth 3 -type d -name "vulkansdk-macOS-${vulkan_sdk_version}.app" -print -quit)" + if [[ -z "${vulkan_sdk_app_path}" ]]; then + vulkan_sdk_app_path="$(find . -maxdepth 3 -type d -name "vulkansdk-macos-${vulkan_sdk_version}.app" -print -quit)" + fi + if [[ -z "${vulkan_sdk_app_path}" ]]; then + log_step "vulkan" "Error: Vulkan SDK installer app not found after extracting ${vulkan_sdk_zip_file}" + exit 1 + fi + + local vulkan_sdk_installer="${vulkan_sdk_app_path}/Contents/MacOS/$(basename "${vulkan_sdk_app_path}" .app)" + if [[ ! -x "${vulkan_sdk_installer}" ]]; then + log_step "vulkan" "Error: Vulkan SDK installer binary not found at ${vulkan_sdk_installer}" + exit 1 + fi + + local install_root="$(cd "${root_dir}" && pwd)/${vulkan_sdk_base_dir}/${vulkan_sdk_version}" + mkdir -p "${install_root}" + local vulkan_sdk_root="${root_dir}/${vulkan_sdk_base_dir}" + + log_step "vulkan" "Installing Vulkan SDK (${vulkan_sdk_version}) to ${install_root}" + ${vulkan_sdk_installer} --root "${install_root}" --accept-licenses --default-answer --confirm-command install +} + +function setup_vulkan_sdk() { + cd "${root_dir}" + + if [[ "${os_name}" == "Darwin" ]]; then + install_vulkan_sdk_macos + else + download_and_extract_vulkan_sdk_linux + fi + + if [[ ! -d "${root_dir}/${vulkan_sdk_bin_dir}" ]]; then + log_step "vulkan" "Error: Vulkan SDK bin directory not found at ${root_dir}/${vulkan_sdk_bin_dir}" + exit 1 + fi + + vulkan_sdk_bin_path="$(cd "${root_dir}/${vulkan_sdk_bin_dir}" && pwd)" + if [[ ! -x "${vulkan_sdk_bin_path}/glslc" ]]; then + log_step "vulkan" "Error: glslc not found at ${vulkan_sdk_bin_path}/glslc" + exit 1 + fi + + if ${vulkan_sdk_bin_path}/glslc --version > /dev/null 2>&1; then + log_step "vulkan" "Vulkan SDK validation (glslc) succeeded" + else + log_step "vulkan" "Error: Vulkan SDK validation failed" + ${vulkan_sdk_bin_path}/glslc --version + exit 1 + fi +} + +function setup_path_vulkan() { + cd "${root_dir}" + if [[ ! -d "${root_dir}/${vulkan_sdk_bin_dir}" ]]; then + log_step "vulkan" "Vulkan SDK not found; skipping PATH update" + return + fi + + local vulkan_sdk_arch_root="${vulkan_sdk_base_dir}/${vulkan_sdk_version}/${vulkan_sdk_arch}" + + if [[ ! -d "${vulkan_sdk_arch_root}" ]]; then + log_step "vulkan" "Vulkan SDK arch path not found; skipping PATH update" + return + fi + + vulkan_sdk_arch_root="$(cd "${vulkan_sdk_arch_root}" && pwd)" + vulkan_sdk_bin_path="$(cd "${vulkan_sdk_bin_dir}" && pwd)" + + append_env_in_setup_path PATH ${vulkan_sdk_bin_path} + if [[ "${OS:-}" == "Darwin" ]]; then + prepend_env_in_setup_path DYLD_LIBRARY_PATH "${vulkan_sdk_arch_root}/lib" + local moltenvk_icd_path="${vulkan_sdk_arch_root}/share/vulkan/icd.d/MoltenVK_icd.json" + if [[ -f "${moltenvk_icd_path}" ]]; then + prepend_env_in_setup_path VK_DRIVER_FILES "${moltenvk_icd_path}" + log_step "vulkan" "Configured VK_DRIVER_FILES to include ${moltenvk_icd_path}" + else + log_step "vulkan" "MoltenVK ICD manifest not found at ${moltenvk_icd_path}; skipping VK_DRIVER_FILES update" + fi + else + prepend_env_in_setup_path LD_LIBRARY_PATH "${vulkan_sdk_arch_root}/lib" + fi + prepend_env_in_setup_path VULKAN_SDK "${vulkan_sdk_arch_root}" +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/.coveragerc b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/.coveragerc new file mode 100644 index 0000000..4172a3d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/.coveragerc @@ -0,0 +1,8 @@ +[run] +omit = + *__init__.py* + +[report] +skip_covered = true +exclude_also = + raise NotImplementedError diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/TARGETS new file mode 100644 index 0000000..f3cb00e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/TARGETS @@ -0,0 +1,86 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load(":targets.bzl", "define_arm_tests") + + +oncall("executorch") + +runtime.python_library( + name = "conftest", + srcs = ["conftest.py"], + deps = [ + "//executorch/exir:lib", + "//executorch/exir/backend:compile_spec_schema", + "fbsource//third-party/pypi/pytest:pytest", + ] +) + +runtime.python_library( + name = "runner_utils", + srcs = ["runner_utils.py"], + resources = { + "fbsource//third-party/flatbuffers:flatc-host": "flatbuffers-flatc", + }, + deps = [ + ":conftest", + "//executorch/backends/arm:arm_compile_spec", + "//executorch/backends/arm:ethosu", + "//executorch/backends/arm/tosa:compile_spec", + "//executorch/backends/arm/tosa:schemas", + "//executorch/backends/arm:vgf", + "//executorch/backends/arm/tosa:specification", + "//executorch/exir:lib", + "//executorch/exir/backend:compile_spec_schema", + ] +) + +runtime.python_library( + name = "common", + srcs = ["common.py"], + deps = [ + ":runner_utils", + "//executorch/backends/arm/tosa:tosa", + "fbsource//third-party/pypi/pytest:pytest", + ] +) + +runtime.python_library( + name = "arm_tester_serialize", + srcs = ["tester/serialize.py"], + deps = [ + "//executorch/backends/xnnpack/test/tester:tester", + "//executorch/devtools/backend_debug:delegation_info", + ] +) + +runtime.python_library( + name = "arm_tester_lib", + srcs = glob(["tester/*.py"], exclude = ["tester/serialize.py"]), + deps = [ + ":common", + "//executorch/backends/xnnpack/test/tester:tester", + "//executorch/backends/arm:ethosu", + "//executorch/backends/arm/quantizer:lib", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm:vgf", + "//executorch/backends/arm:_factory", + "//executorch/devtools/backend_debug:delegation_info", + "//executorch/exir/backend:operator_support", + "fbsource//third-party/pypi/tabulate:tabulate", + ] +) + + +runtime.python_library( + name = "arm_tester", + deps = [ + "//executorch/backends/arm/test:arm_tester_lib", + "//executorch/backends/arm/test:arm_tester_serialize", + ] +) + +define_arm_tests() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/common.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/common.py new file mode 100644 index 0000000..c252294 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/common.py @@ -0,0 +1,302 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import os + +import tempfile +from datetime import datetime + +from pathlib import Path +from typing import Any, Callable, Optional, ParamSpec, TypeVar + +import pytest +from executorch.backends.arm.ethosu import EthosUCompileSpec + +from executorch.backends.arm.test.runner_utils import ( + arm_executor_runner_exists, + corstone300_installed, + corstone320_installed, + model_converter_installed, + vkml_emulation_layer_installed, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.vgf import VgfCompileSpec + + +def get_time_formatted_path(path: str, log_prefix: str) -> str: + """ + Returns the log path with the current time appended to it. Used for debugging. + + Args: + path: The path to the folder where the log file will be stored. + log_prefix: The name of the test. + + Example output: + './my_log_folder/test_INT_artifact_28-Nov-14:14:38.log' + """ + return str( + Path(path) / f"{log_prefix}_{datetime.now().strftime('%d-%b-%H:%M:%S')}.log" + ) + + +def maybe_get_tosa_collate_path() -> str | None: + """ + Checks the environment variable TOSA_TESTCASES_BASE_PATH and returns the + path to the where to store the current tests if it is set. + """ + tosa_test_base = os.environ.get("TOSA_TESTCASES_BASE_PATH") + if tosa_test_base: + current_test = os.environ.get("PYTEST_CURRENT_TEST") + # '::test_collate_tosa_INT_tests[randn] (call)' + test_name = current_test.split("::")[1].split(" ")[0] # type: ignore[union-attr] + if "INT" in test_name: + tosa_test_base = os.path.join(tosa_test_base, "tosa-int") + elif "FP" in test_name: + tosa_test_base = os.path.join(tosa_test_base, "tosa-fp") + else: + tosa_test_base = os.path.join(tosa_test_base, "other") + return os.path.join(tosa_test_base, test_name) + + return None + + +def get_tosa_compile_spec( + tosa_spec: str | TosaSpecification, + custom_path: Optional[str] = None, + tosa_debug_mode: TosaCompileSpec.DebugMode | None = None, +) -> TosaCompileSpec: + """Get the compile spec for default TOSA tests.""" + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + if custom_path is not None: + os.makedirs(custom_path, exist_ok=True) + + compile_spec = ( + TosaCompileSpec(tosa_spec) + .dump_intermediate_artifacts_to(custom_path) + .dump_debug_info(tosa_debug_mode) + ) + return compile_spec + + +def get_u55_compile_spec( + macs: int = 128, + system_config: str = "Ethos_U55_High_End_Embedded", + memory_mode: str = "Shared_Sram", + extra_flags: str = "--debug-force-regor --output-format=raw --arena-cache-size=2097152", + custom_path: Optional[str] = None, + config: Optional[str] = None, + tosa_debug_mode: EthosUCompileSpec.DebugMode | None = None, +) -> EthosUCompileSpec: + """Default compile spec for Ethos-U55 tests.""" + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + artifact_path = custom_path or tempfile.mkdtemp(prefix="arm_u55_") + if not os.path.exists(artifact_path): + os.makedirs(artifact_path, exist_ok=True) + + # https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-vela/-/blob/main/OPTIONS.md + assert macs in [32, 64, 128, 256], "Unsupported MACs value" + + if extra_flags is not None: + extra_flags_list = extra_flags.split(" ") + else: + extra_flags_list = [] + compile_spec = ( + EthosUCompileSpec( + f"ethos-u55-{macs}", + system_config=system_config, + memory_mode=memory_mode, + extra_flags=extra_flags_list, + config_ini=config, + ) + .dump_intermediate_artifacts_to(artifact_path) + .dump_debug_info(tosa_debug_mode) + ) + return compile_spec + + +def get_u85_compile_spec( + macs: int = 128, + system_config="Ethos_U85_SYS_DRAM_Mid", + memory_mode="Shared_Sram", + extra_flags="--output-format=raw --arena-cache-size=2097152", + custom_path: Optional[str] = None, + config: Optional[str] = None, + tosa_debug_mode: EthosUCompileSpec.DebugMode | None = None, +) -> EthosUCompileSpec: + """Default compile spec for Ethos-U85 tests.""" + + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + artifact_path = custom_path or tempfile.mkdtemp(prefix="arm_u85_") + if not os.path.exists(artifact_path): + os.makedirs(artifact_path, exist_ok=True) + + assert macs in [128, 256, 512, 1024, 2048], "Unsupported MACs value" + + if extra_flags is not None: + extra_flags_list = extra_flags.split(" ") + else: + extra_flags_list = [] + + compile_spec = ( + EthosUCompileSpec( + f"ethos-u85-{macs}", + system_config=system_config, + memory_mode=memory_mode, + extra_flags=extra_flags_list, + config_ini=config, + ) + .dump_intermediate_artifacts_to(artifact_path) + .dump_debug_info(tosa_debug_mode) + ) + return compile_spec # type: ignore[return-value] + + +def get_vgf_compile_spec( + tosa_spec: str | TosaSpecification, + compiler_flags: Optional[str] = "", + custom_path: Optional[str] = None, + tosa_debug_mode: VgfCompileSpec.DebugMode | None = None, +) -> VgfCompileSpec: + """Get the ArmCompileSpec for the default VGF tests, to modify + the compile spec before calling .build() to finalize it. + """ + + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + profiles = [] + if "FP" in repr(tosa_spec): + profiles.append("fp") + if "INT" in repr(tosa_spec): + profiles.append("int") + if len(profiles) == 0: + raise ValueError(f"Unsupported vgf compile_spec: {repr(tosa_spec)}") + + if custom_path is None: + artifact_path = "arm_vgf_" + for profile in profiles: + artifact_path = artifact_path + f"_{profile}" + artifact_path = tempfile.mkdtemp(artifact_path) + else: + artifact_path = custom_path + + if not os.path.exists(artifact_path): + os.makedirs(artifact_path, exist_ok=True) + + if compiler_flags is not None: + compiler_flags_list = compiler_flags.split(" ") + else: + compiler_flags_list = [] + + compile_spec = ( + VgfCompileSpec(tosa_spec, compiler_flags_list) + .dump_intermediate_artifacts_to(artifact_path) + .dump_debug_info(tosa_debug_mode) + ) + + return compile_spec + + +XfailIfNoCorstone300 = pytest.mark.xfail( + condition=not ( + corstone300_installed() and arm_executor_runner_exists("corstone-300") + ), + raises=FileNotFoundError, + reason="Did not find Corstone-300 FVP or executor_runner on path", +) +"""Xfails a test if Corsone300 FVP is not installed, or if the executor runner is not built""" + +XfailIfNoCorstone320 = pytest.mark.xfail( + condition=not ( + corstone320_installed() and arm_executor_runner_exists("corstone-320") + ), + raises=FileNotFoundError, + reason="Did not find Corstone-320 FVP or executor_runner on path", +) +"""Xfails a test if Corsone320 FVP is not installed, or if the executor runner is not built""" + +SkipIfNoModelConverter = pytest.mark.skipif( # type: ignore[call-arg] + condition=not (model_converter_installed()), + raises=FileNotFoundError, + reason="Did not find model-converter on path", +) +"""Skips a test if model-converter is not installed""" + +XfailfNoVKMLEmulationLayer = pytest.mark.xfail( + condition=not (vkml_emulation_layer_installed()), + raises=TypeError, + reason="VKML environment is not set properly or executor_runner path is misused", +) +"""Xfails a test if VKML Emulation Layer is not installed""" + +xfail_type = str | tuple[str, type[Exception]] + +_P = ParamSpec("_P") +_R = TypeVar("_R") +Decorator = Callable[[Callable[_P, _R]], Callable[_P, _R]] + + +def parametrize( + arg_name: str, + test_data: dict[str, Any], + xfails: dict[str, xfail_type] | None = None, + skips: dict[str, str] | None = None, + strict: bool = True, + flakies: dict[str, int] | None = None, +) -> Decorator: + """ + Custom version of pytest.mark.parametrize with some syntatic sugar and added xfail functionality + - test_data is expected as a dict of (id, test_data) pairs + - alllows to specifiy a dict of (id, failure_reason) pairs to mark specific tests as xfail. + Failure_reason can be str, type[Exception], or tuple[str, type[Exception]]. + Strings set the reason for failure, the exception type sets expected error. + """ + if xfails is None: + xfails = {} + if skips is None: + skips = {} + if flakies is None: + flakies = {} + + def decorator_func(func: Callable[_P, _R]) -> Callable[_P, _R]: + """Test data is transformed from a dict of (id, data) pairs to a list of pytest params to work with the native pytests parametrize function""" + pytest_testsuite = [] + for id, test_parameters in test_data.items(): + if id in flakies: + # Mark this parameter as flaky with given reruns + marker = (pytest.mark.flaky(reruns=flakies[id]),) + elif id in skips: + # fail markers do not work with 'buck' based ci, so use skip instead + marker = (pytest.mark.skip(reason=skips[id]),) + elif id in xfails: + xfail_info = xfails[id] + reason = "" + raises = None + if isinstance(xfail_info, str): + reason = xfail_info + elif isinstance(xfail_info, tuple): + reason, raises = xfail_info + else: + raise RuntimeError( + "xfail info needs to be str, or tuple[str, type[Exception]]" + ) + # Set up our fail marker + marker: tuple[pytest.MarkDecorator, ...] # type: ignore[no-redef] + marker = ( + pytest.mark.xfail(reason=reason, raises=raises, strict=strict), + ) + else: + marker = () # type: ignore[assignment] + + pytest_param = pytest.param(test_parameters, id=id, marks=marker) + pytest_testsuite.append(pytest_param) + decorator = pytest.mark.parametrize(arg_name, pytest_testsuite) + return decorator(func) + + return decorator_func diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/conftest.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/conftest.py new file mode 100644 index 0000000..c33f551 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/conftest.py @@ -0,0 +1,134 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import random +import sys +from typing import Any + +import pytest + +""" +This file contains the pytest hooks, fixtures etc. for the Arm test suite. +""" + + +# ==== Pytest hooks ==== + + +def pytest_configure(config): + pytest._test_options = {} # type: ignore[attr-defined] + + if getattr(config.option, "llama_inputs", False) and config.option.llama_inputs: + pytest._test_options["llama_inputs"] = config.option.llama_inputs # type: ignore[attr-defined] + + pytest._test_options["tosa_version"] = "1.0" # type: ignore[attr-defined] + if config.option.arm_run_tosa_version: + pytest._test_options["tosa_version"] = config.option.arm_run_tosa_version + + logging.basicConfig(stream=sys.stdout) + + +def pytest_collection_modifyitems(config, items): + pass + + +def pytest_addoption(parser): + def try_addoption(*args, **kwargs): + try: + parser.addoption(*args, **kwargs) + except Exception: # nosec B110 - pytest redefines options, safe to ignore + pass + + try_addoption("--arm_quantize_io", action="store_true", help="Deprecated.") + try_addoption("--arm_run_corstoneFVP", action="store_true", help="Deprecated.") + try_addoption( + "--llama_inputs", + nargs="+", + help="List of two files. Firstly .pt file. Secondly .json", + ) + try_addoption("--arm_run_tosa_version", action="store", default="1.0") + + +def pytest_sessionstart(session): + pass + + +def pytest_sessionfinish(session, exitstatus): + pass + + +# ==== End of Pytest hooks ===== + + +# ==== Pytest fixtures ===== + + +@pytest.fixture(autouse=True) +def set_random_seed(): + """ + Control random numbers in Arm test suite. Default behavior is random seed, + which is set before each test. Use the env variable ARM_TEST_SEED to set the + seed you want to use to overrride the default behavior. Or set it to RANDOM + if you want to be explicit. + + Examples: + As default use random seed for each test + ARM_TEST_SEED=RANDOM pytest --config-file=/dev/null --verbose -s --color=yes backends/arm/test/ops/test_avg_pool.py -k + Rerun with a specific seed found under a random seed test + ARM_TEST_SEED=3478246 pytest --config-file=/dev/null --verbose -s --color=yes backends/arm/test/ops/test_avg_pool.py -k + """ + import torch + + if os.environ.get("ARM_TEST_SEED", "RANDOM") == "RANDOM": + random.seed() # reset seed, in case any other test has fiddled with it + seed = random.randint(0, 2**32 - 1) # nosec B311 - non-crypto seed for tests + torch.manual_seed(seed) + else: + seed_str = os.environ.get("ARM_TEST_SEED", "0") + if str.isdigit(seed_str): + seed = int(seed_str) + random.seed(seed) + torch.manual_seed(seed) + else: + raise TypeError( + "ARM_TEST_SEED env variable must be integers or the string RANDOM" + ) + + print(f" ARM_TEST_SEED={seed} ", end=" ") + + +# ==== End of Pytest fixtures ===== + + +def is_option_enabled(option: str, fail_if_not_enabled: bool = False) -> bool: + """ + Returns whether an option is successfully enabled, i.e. if the flag was + given to pytest and the necessary requirements are available. + + The optional parameter 'fail_if_not_enabled' makes the function raise + a RuntimeError instead of returning False. + """ + + if hasattr(pytest, "_test_options") and option in pytest._test_options and pytest._test_options[option]: # type: ignore[attr-defined] + return True + else: + if fail_if_not_enabled: + raise RuntimeError(f"Required option '{option}' for test is not enabled") + else: + return False + + +def get_option(option: str) -> Any | None: + """ + Returns the value of an pytest option if it is set, otherwise None. + + Args: + option (str): The option to check for. + """ + if option in pytest._test_options: # type: ignore[attr-defined] + return pytest._test_options[option] # type: ignore[attr-defined] + return None diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/TARGETS new file mode 100644 index 0000000..00b836c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/TARGETS @@ -0,0 +1,16 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +oncall("executorch") + +runtime.python_library( + name = "dw_convs_shared_weights_module", + srcs = ["test_dw_convs_with_shared_weights.py"], + deps = [ + "//executorch/backends/arm/test:arm_tester_lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_bn_relu_folding_qat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_bn_relu_folding_qat.py new file mode 100644 index 0000000..41675b3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_bn_relu_folding_qat.py @@ -0,0 +1,124 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.xnnpack.test.tester.tester import Quantize +from torch import nn + + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Conv2dModule(torch.nn.Module): + input_shape = (1, 28, 28) + batch_size = 64 + test_data: input_t1 = (torch.randn(batch_size, *input_shape),) + + def __init__(self, batch_norm: bool = True, inplace: bool = False) -> None: + super().__init__() + self.conv = torch.nn.Conv2d(1, 16, 3, stride=2) + self.bn = nn.BatchNorm2d(num_features=16) if batch_norm else nn.Identity() + self.relu = nn.ReLU(inplace=inplace) + + def forward(self, x: torch.Tensor): + x = self.conv(x) + x = self.bn(x) + x = self.relu(x) + + return x + + +class Conv1dModule(torch.nn.Module): + input_shape = (3, 10) + batch_size = 2 + test_data: input_t1 = (torch.randn(batch_size, *input_shape),) + + def __init__(self, batch_norm: bool = True, inplace: bool = False) -> None: + super().__init__() + self.conv = torch.nn.Conv1d(3, 8, 5, padding=2) + self.bn = nn.BatchNorm1d(num_features=8) if batch_norm else nn.Identity() + self.relu = nn.ReLU(inplace=inplace) + + def forward(self, x: torch.Tensor): + x = self.conv(x) + x = self.bn(x) + x = self.relu(x) + + return x + + +models = { + # name : (model, is_per_channel) + "conv1d_bn_relu_per_channel": (Conv1dModule(batch_norm=True), True), + "conv1d_relu_per_channel": (Conv1dModule(batch_norm=False), True), + "conv1d_bn_relu_per_tensor": (Conv1dModule(batch_norm=True), False), + "conv1d_relu_per_tensor": (Conv1dModule(batch_norm=False), False), + "conv2d_bn_relu_per_channel": (Conv2dModule(batch_norm=True), True), + "conv2d_relu_per_channel": (Conv2dModule(batch_norm=False), True), + "conv2d_bn_relu_per_tensor": (Conv2dModule(batch_norm=True), False), + "conv2d_relu_per_tensor": (Conv2dModule(batch_norm=False), False), + "conv1d_bn_relu_inplace_per_channel": ( + Conv1dModule(batch_norm=True, inplace=True), + True, + ), + "conv1d_relu_inplace_per_channel": ( + Conv1dModule(batch_norm=False, inplace=True), + True, + ), + "conv1d_bn_relu_inplace_per_tensor": ( + Conv1dModule(batch_norm=True, inplace=True), + False, + ), + "conv1d_relu_inplace_per_tensor": ( + Conv1dModule(batch_norm=False, inplace=True), + False, + ), + "conv2d_bn_relu_inplace_per_channel": ( + Conv2dModule(batch_norm=True, inplace=True), + True, + ), + "conv2d_relu_inplace_per_channel": ( + Conv2dModule(batch_norm=False, inplace=True), + True, + ), + "conv2d_bn_relu_inplace_per_tensor": ( + Conv2dModule(batch_norm=True, inplace=True), + False, + ), + "conv2d_relu_inplace_per_tensor": ( + Conv2dModule(batch_norm=False, inplace=True), + False, + ), +} + + +@common.parametrize( + "test_data", + models, +) +def test_bn_relu_folding_qat_tosa_INT(test_data): + model, per_channel = test_data + pipeline = TosaPipelineINT[input_t1](model, model.test_data, [], [], qtol=1) + quantizer = TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + pipeline.change_args( + "quantize", + Quantize( + quantizer=quantizer, + quantization_config=get_symmetric_quantization_config( + is_qat=True, is_per_channel=per_channel + ), + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_call_operator_submodule.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_call_operator_submodule.py new file mode 100644 index 0000000..5c4029d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_call_operator_submodule.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, Optional + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_manager import ArmPassManager +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from torch.fx import GraphModule +from torch.fx.passes.infra.pass_base import PassResult + + +class _DepthRecordingPass(ArmPass): + _passes_required_after = set() + + def __init__(self, initial_graph_module): + super().__init__() + self.depths: list[int] = [] + self.initial_submodule = initial_graph_module + self.submodule = None + self.num_submodules_called = 0 + + def call_operator(self, op, args, kwargs, meta, updated: Optional[bool] = False): + """Should only be called from the top-level graph module.""" + self.depths.append(self.submodule_depth) + assert self.submodule == self.initial_submodule + return super().call_operator(op, args, kwargs, meta, updated) + + def call_submodule( + self, graph_module: GraphModule, inputs: tuple[Any, ...] + ) -> PassResult: + """Should be called for all three graph_modules: top-level, if, and else.""" + self.submodule = graph_module + self.num_submodules_called += 1 + return super().call_submodule(graph_module, inputs) + + +class _CondModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def _true_branch(arg: torch.Tensor) -> torch.Tensor: + return arg + 1 + + def _false_branch(arg: torch.Tensor) -> torch.Tensor: + return arg - 1 + + predicate = x.sum() > 0 + return torch.cond(predicate, _true_branch, _false_branch, [x]) + + +def test_call_operator_runs_once_for_cond_submodules_tosa_FP() -> None: + module = _CondModule() + example_inputs = (torch.randn(2, 3),) + exported = torch.export.export(module, example_inputs) + graph_module = exported.graph_module + + recording_pass = _DepthRecordingPass(graph_module) + pass_manager = ArmPassManager(TosaCompileSpec("TOSA-1.00+FP")) + pass_manager.add_pass(recording_pass) + pass_manager._transform(graph_module) + + assert recording_pass.num_submodules_called == 3 + assert recording_pass.depths, "call_operator was never invoked" + assert ( + max(recording_pass.depths) == 1 + ), "call_operator was invoked with larger than one submodule depth." + assert ( + min(recording_pass.depths) == 1 + ), "call_operator was invoked with zero submodule depth." diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_compile_spec.py new file mode 100644 index 0000000..e40776e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_compile_spec.py @@ -0,0 +1,55 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.ethosu import EthosUCompileSpec +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.vgf import VgfCompileSpec +from pytest import raises + + +def test_ethos_u_compile_spec_no_target(): + compile_spec = ( + EthosUCompileSpec("ethos-u55", extra_flags=["--my-flag"]) + .dump_intermediate_artifacts_to("my_path") + .dump_debug_info(EthosUCompileSpec.DebugMode.TOSA) + ) + spec_list = compile_spec.to_list() + + assert EthosUCompileSpec.from_list(spec_list) == compile_spec + assert "--my-flag" in compile_spec.compiler_flags + assert "--output-format=raw" in compile_spec.compiler_flags + with raises(ValueError, match="Incorrect output format"): + VgfCompileSpec.from_list(spec_list) + + spec_list.pop(0) + with raises(ValueError, match="No tosa_spec in compile spec."): + EthosUCompileSpec.from_list(spec_list) + + +def test_vgf_compile_spec_no_target(): + compile_spec = ( + VgfCompileSpec(compiler_flags=["--my-flag"]) + .dump_intermediate_artifacts_to("my_path") + .dump_debug_info(None) + ) + compile_spec2 = VgfCompileSpec( + compiler_flags=["--my-flag2"] + ).dump_intermediate_artifacts_to("my_path") + + spec_list = compile_spec.to_list() + + assert VgfCompileSpec.from_list(spec_list) == compile_spec + assert VgfCompileSpec.from_list(spec_list) != compile_spec2 + with raises(ValueError, match="Incorrect output format"): + EthosUCompileSpec.from_list(spec_list) + + +def test_tosa_compile_spec_no_target(): + compile_spec = TosaCompileSpec("TOSA-1.0+INT") + spec_list = compile_spec.to_list() + + assert TosaCompileSpec.from_list(spec_list) == compile_spec + with raises(ValueError, match="Incorrect output format"): + VgfCompileSpec.from_list(spec_list) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_conv_relu_residual_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_conv_relu_residual_add.py new file mode 100644 index 0000000..982cc1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_conv_relu_residual_add.py @@ -0,0 +1,108 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +import torch.nn as nn +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + + +# Model with Conv1D - ReLU sequence and a residual add. +# Testing the annotation of Conv1D-ReLU(to be fused) and annotation of add. +# ReLU outputs positive numbers and linear outputs positive and negative numbers, so they +# should have different quantisation parameters. If the ReLU gets wrong quantisation parameters(e.g. qmin!=zp) +# because of a shared observer of a following operators(e.g. add), the Conv1D-ReLU sequence is not fused +# and is left in FP32. As a result, the test fails. +class AddDifferentRanges(torch.nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, input_dim): + super().__init__() + self.conv1 = nn.Conv1d(in_channels, out_channels, kernel_size) + self.relu = torch.nn.ReLU() + self.linear = nn.Linear(out_channels, out_channels) + + def forward(self, x): + # Permute: (N, T, C) -> (N, C, T) + x = x.permute(0, 2, 1) + x = self.conv1(x) + x = self.relu(x) + x = x.permute(0, 2, 1) + out = x + self.linear(x) + return out + + +input_t = Tuple[torch.Tensor] +model = AddDifferentRanges(in_channels=3, out_channels=16, kernel_size=3, input_dim=10) +model_inputs = (torch.randn(1, 10, 3),) +quant_test_data = { + "per_channel_quantization=true": True, + "per_channel_quantization=false": False, +} + + +def test_conv_relu_residual_add_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("per_channel_quantization", quant_test_data) +def test_conv_relu_residual_add_tosa_INT(per_channel_quantization): + pipeline = TosaPipelineINT[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + qtol=0, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_conv_relu_residual_add_u55_INT(per_channel_quantization): + pipeline = EthosU55PipelineINT[input_t]( + model, + model_inputs, + [], + [], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + qtol=0, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_conv_relu_residual_add_u85_INT(per_channel_quantization): + pipeline = EthosU85PipelineINT[input_t]( + model, + model_inputs, + [], + [], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + qtol=0, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_custom_partition.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_custom_partition.py new file mode 100644 index 0000000..e38c98a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_custom_partition.py @@ -0,0 +1,183 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineFP +from executorch.exir.backend.operator_support import ( + DontPartition, + DontPartitionModule, + DontPartitionName, +) +from executorch.exir.dialects._ops import ops as exir_ops + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class CustomPartitioning(torch.nn.Module): + inputs = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + z = x + y + s = torch.sigmoid(z) + return s * z + + +class NestedModule(torch.nn.Module): + inputs = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def __init__(self): + super().__init__() + self.nested = CustomPartitioning() + + def forward(self, x: torch.Tensor, y: torch.Tensor): + a = x.sigmoid() + b = a + y + return self.nested(a, b) + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_single_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = CustomPartitioning() + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + check = DontPartition(exir_ops.edge.aten.sigmoid.default) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartition" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_multiple_reject_tosa_FP(test_data: input_t1): + module = CustomPartitioning() + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + check = DontPartition( + exir_ops.edge.aten.sigmoid.default, exir_ops.edge.aten.mul.Tensor + ) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_torch_op_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = CustomPartitioning() + check = DontPartition(torch.ops.aten.sigmoid.default) + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartition" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_string_op_reject_tosa_FP(test_data: input_t1): + module = CustomPartitioning() + check = DontPartition("aten.sigmoid.default") + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_name_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = CustomPartitioning() + check = DontPartitionName("mul", "sigmoid", exact=False) + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartitionName" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_module_reject_tosa_FP(test_data: input_t1): + module = NestedModule() + check = DontPartitionModule(module_name="CustomPartitioning") + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_inexact_module_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = NestedModule() + check = DontPartitionModule(module_name="Custom", exact=False) + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartitionModule" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_module_instance_reject_tosa_FP(test_data: input_t1): + module = NestedModule() + check = DontPartitionModule(instance_name="nested") + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_feats.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_feats.py new file mode 100644 index 0000000..718e3a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_feats.py @@ -0,0 +1,316 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import json +import os +import shutil +import tempfile + +from pathlib import Path +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.test import common +from executorch.backends.arm.test.runner_utils import dbg_tosa_fb_to_json +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) +from executorch.backends.test.harness.stages import StageType + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Linear(torch.nn.Module): + inputs = { + "randn": (torch.randn(5, 10, 25, 3),), + } + + def __init__( + self, + ): + super().__init__() + self.fc = torch.nn.Linear( + in_features=3, + out_features=5, + bias=True, + ) + + def forward(self, x): + return self.fc(x) + + +"""Tests dumping the partition artifact in ArmTester. Both to file and to stdout.""" + + +def _tosa_FP_pipeline(module: torch.nn.Module, test_data: input_t1, dump_file=None): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1](module, test_data, aten_ops, exir_ops) + pipeline.dump_artifact("to_edge_transform_and_lower") + pipeline.dump_artifact("to_edge_transform_and_lower", suffix=dump_file) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +def _tosa_INT_pipeline(module: torch.nn.Module, test_data: input_t1, dump_file=None): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](module, test_data, aten_ops, exir_ops) + pipeline.dump_artifact("to_edge_transform_and_lower") + pipeline.dump_artifact("to_edge_transform_and_lower", suffix=dump_file) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +def _is_tosa_marker_in_file(tmp_file): + for line in open(tmp_file).readlines(): + if "'name': 'main'" in line: + return True + return False + + +@common.parametrize("test_data", Linear.inputs) +def test_artifact_tosa_FP(test_data: input_t1): + model = Linear() + tmp_file = common.get_time_formatted_path( + tempfile.mkdtemp(), test_artifact_tosa_FP.__name__ + ) + _tosa_FP_pipeline(model, test_data, dump_file=tmp_file) + assert os.path.exists(tmp_file), f"File {tmp_file} was not created" + if _is_tosa_marker_in_file(tmp_file): + return # Implicit pass test + pytest.fail("File does not contain TOSA dump!") + + +@common.parametrize("test_data", Linear.inputs) +def test_artifact_tosa_INT(test_data: input_t1): + model = Linear() + tmp_file = common.get_time_formatted_path( + tempfile.mkdtemp(), test_artifact_tosa_INT.__name__ + ) + _tosa_INT_pipeline(model, test_data, dump_file=tmp_file) + assert os.path.exists(tmp_file), f"File {tmp_file} was not created" + if _is_tosa_marker_in_file(tmp_file): + return # Implicit pass test + pytest.fail("File does not contain TOSA dump!") + + +"""Tests trigging the exception printout from the ArmTester's run and compare function.""" + + +@common.parametrize("test_data", Linear.inputs) +def test_numerical_diff_print_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + Linear(), + test_data, + aten_ops, + exir_ops, + custom_path="diff_print_test", + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + tester = pipeline.tester + # We expect an assertion error here. Any other issues will cause the + # test to fail. Likewise the test will fail if the assertion error is + # not present. + try: + # Tolerate 0 difference => we want to trigger a numerical diff + tester.run_method_and_compare_outputs( + stage=StageType.INITIAL_MODEL, atol=0, rtol=0, qtol=0 + ) + except AssertionError: + pass # Implicit pass test + else: + pytest.fail() + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_ops_and_dtypes_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.add_stage_after("quantize", pipeline.tester.dump_dtype_distribution) + pipeline.add_stage_after("quantize", pipeline.tester.dump_operator_distribution) + pipeline.add_stage_after("export", pipeline.tester.dump_dtype_distribution) + pipeline.add_stage_after("export", pipeline.tester.dump_operator_distribution) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_dtype_distribution + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_operator_distribution + ) + pipeline.run() + # Just test that there are no execptions. + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_ops_and_dtypes_parseable_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.add_stage_after("quantize", pipeline.tester.dump_dtype_distribution, False) + pipeline.add_stage_after( + "quantize", pipeline.tester.dump_operator_distribution, False + ) + pipeline.add_stage_after("export", pipeline.tester.dump_dtype_distribution, False) + pipeline.add_stage_after( + "export", pipeline.tester.dump_operator_distribution, False + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_dtype_distribution, False + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_operator_distribution, False + ) + pipeline.run() + # Just test that there are no execptions. + + +"""Tests the collation of TOSA tests through setting the environment variable TOSA_TESTCASE_BASE_PATH.""" + + +@common.parametrize("test_data", Linear.inputs) +def test_collate_tests_tosa_INT(test_data: input_t1): + # Set the environment variable to trigger the collation of TOSA tests + os.environ["TOSA_TESTCASES_BASE_PATH"] = "test_collate_tosa_tests" + # Clear out the directory + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + test_collate_dir = ( + "test_collate_tosa_tests/tosa-int/test_collate_tests_tosa_INT[randn]" + ) + # test that the output directory is created and contains the expected files + assert os.path.exists(test_collate_dir) + for file in os.listdir(test_collate_dir): + file_name_prefix = "TOSA-1.0+INT" + assert file.endswith((f"{file_name_prefix}.json", f"{file_name_prefix}.tosa")) + + os.environ.pop("TOSA_TESTCASES_BASE_PATH") + shutil.rmtree("test_collate_tosa_tests", ignore_errors=True) + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_tosa_debug_json_tosa_INT(test_data: input_t1): + with tempfile.TemporaryDirectory() as tmpdir: + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + module=Linear(), + test_data=test_data, + aten_op=aten_ops, + exir_op=exir_ops, + custom_path=tmpdir, + tosa_debug_mode=ArmCompileSpec.DebugMode.JSON, + ) + + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + json_output_path = Path(tmpdir) / "debug.json" + + # The file should exist + assert json_output_path.exists() + + # Check the file is valid JSON and can be loaded + with json_output_path.open("r") as file: + try: + data = json.load(file) + + # Check it's not empty + assert data + except json.JSONDecodeError: + pytest.fail("Failed to load debug JSON file") + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_tosa_debug_tosa_FP(test_data: input_t1): + output_dir = "test_dump_tosa_debug" + + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1]( + module=Linear(), + test_data=test_data, + use_to_edge_transform_and_lower=True, + aten_op=aten_ops, + exir_op=exir_ops, + custom_path=output_dir, + tosa_debug_mode=ArmCompileSpec.DebugMode.TOSA, + ) + + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + output_path = Path(output_dir) + json_output_path = output_path / "debug.json" + + # A JSON file should not be created when TOSA mode used + assert not json_output_path.exists() + + # At least one TOSA file should exist + tosa_files = list(output_path.glob("*.tosa")) + assert len(tosa_files) > 0 + + tosa_file = tosa_files[0] + with tosa_file.open("rb") as f: + tosa_json = dbg_tosa_fb_to_json(f.read()) + + # Check all non-empty JSON strings are valid + ops = tosa_json["regions"][0]["blocks"][0]["operators"] + for op in ops: + if op["location"]["text"]: + try: + json.loads(op["location"]["text"]) + except json.JSONDecodeError: + pytest.fail("Failed to load debug JSON string") + + shutil.rmtree(output_dir, ignore_errors=True) + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_tosa_ops_tosa_INT(capsys, test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.dump_operator_distribution("to_edge_transform_and_lower") + pipeline.run() + assert "TOSA operators:" in capsys.readouterr().out + + +class Add(torch.nn.Module): + inputs = { + "ones": (torch.ones(5),), + } + + def forward(self, x): + return x + x + + +@common.parametrize("test_data", Add.inputs) +@common.XfailIfNoCorstone300 +def test_fail_dump_ops_u55_INT(capsys, test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = EthosU55PipelineINT[input_t1]( + Add(), test_data, aten_ops, exir_ops, use_to_edge_transform_and_lower=True + ) + pipeline.dump_operator_distribution("to_edge_transform_and_lower") + error_msg = "Can not get operator distribution for Vela command stream." + with pytest.raises(NotImplementedError, match=error_msg): + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_hook.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_hook.py new file mode 100644 index 0000000..2dfe130 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_debug_hook.py @@ -0,0 +1,186 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass +from types import SimpleNamespace +from typing import cast + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.debug.schema import DebugHook, DebugSchema +from executorch.backends.arm.test import common + +from torch.fx import Node + + +@dataclass +class DebugHookTestCase: + mock_node: SimpleNamespace + tosa_op: str + op_id: int + expected_events: int + num_nodes_traced: int + + +def create_mock_node_1(): + def _get_action_str() -> str: + return "create" + + from_node_2 = SimpleNamespace( + name="convolution", + target="aten.convolution.default", + graph_id=6052414368, + pass_name="ExportedProgram.module()", # nosec B106 - static test string, not a secret + action="create", + from_node=[], + _get_action_string=_get_action_str, + ) + + from_node_1 = SimpleNamespace( + name="convolution", + target="aten.convolution.default", + graph_id=5705954832, + pass_name="Interpreter_PropagateUnbackedSymInts", # nosec B106 - static test string, not a secret + action="create", + from_node=[from_node_2], + _get_action_string=_get_action_str, + ) + + fx_node_mock = SimpleNamespace( + name="aten_convolution_default", + target="aten.convolution.default", + meta={ + "stack_trace": 'File "models/model.py", line 221, in forward\nreturn self.features(x)', + "nn_module_stack": {"__self__": ["", "model.Model"]}, + "torch_fn": ("conv2d", "builtin_function_or_method.conv2d"), + "from_node": [from_node_1], + }, + ) + + return fx_node_mock + + +def create_mock_node_2(): + def _get_action_str() -> str: + return "create" + + from_node_1 = SimpleNamespace( + name="convolution", + target="aten.convolution.default", + graph_id=5705954832, + pass_name="Interpreter_PropagateUnbackedSymInts", # nosec B106 - static test string, not a secret + action="create", + from_node=[], + _get_action_string=_get_action_str, + ) + + fx_node_mock = SimpleNamespace( + name="aten_convolution_default", + target="aten.convolution.default", + meta={ + "from_node": [from_node_1], + }, + ) + + return fx_node_mock + + +def create_mock_node_3(): + fx_node_mock = SimpleNamespace( + name="aten_convolution_default", + target="aten.convolution.default", + meta={ + "from_node": [], + }, + ) + + return fx_node_mock + + +def _compare_tosa_and_schema(debug_event: DebugSchema, tosa_op: str) -> None: + tosa_info = debug_event.tosa_info + assert tosa_info is not None + assert tosa_info.node_name == tosa_op + + # The mapping between op_ids to operator names could change + # So just check operator_name is a string + assert isinstance(tosa_info.operator_name, str) + + +def _compare_node_and_schema(debug_event: DebugSchema, mocked_node): + # Check aten info + aten_info = debug_event.aten_info + + assert aten_info.node_name == mocked_node.name + assert aten_info.operator_name == mocked_node.target + + # Check torch info + torch_info = debug_event.torch_info + + if "nn_module_stack" in mocked_node.meta: + assert torch_info.nn_module_stack == mocked_node.meta["nn_module_stack"] + else: + assert torch_info.nn_module_stack == "No module stack trace available" + + if "stack_trace" in mocked_node.meta: + assert torch_info.stack_trace == mocked_node.meta["stack_trace"].split("\n") + else: + assert torch_info.stack_trace == ["No stack trace available"] + + if "torch_fn" in mocked_node.meta: + assert torch_info.torch_fn == mocked_node.meta["torch_fn"] + else: + assert torch_info.torch_fn == "No torch_fn available" + + +TESTCASES = { + "mocked_node": DebugHookTestCase( + mock_node=create_mock_node_1(), + tosa_op="layer-1", + op_id=3, + expected_events=1, + num_nodes_traced=2, + ), + "mocked_node_partially_empty": DebugHookTestCase( + mock_node=create_mock_node_2(), + tosa_op="layer-1", + op_id=1, + expected_events=1, + num_nodes_traced=1, + ), + "mocked_node_all_empty": DebugHookTestCase( + mock_node=create_mock_node_3(), + tosa_op="layer-2", + op_id=1, + expected_events=1, + num_nodes_traced=0, + ), +} + + +@common.parametrize("test_data", TESTCASES) +def test_debug_hook_add_json_no_target(test_data: DebugHookTestCase): + hook = DebugHook(ArmCompileSpec.DebugMode.JSON) + hook.add(cast(Node, test_data.mock_node), test_data.tosa_op, test_data.op_id) + + debug_events = hook._debug_events + assert len(debug_events) == test_data.expected_events + assert len(debug_events[0].torch_info.node_trace) == test_data.num_nodes_traced + + _compare_tosa_and_schema(debug_events[0], test_data.tosa_op) + _compare_node_and_schema(debug_events[0], test_data.mock_node) + + +@common.parametrize("test_data", TESTCASES) +def test_debug_hook_add_tosa_no_target(test_data: DebugHookTestCase): + hook = DebugHook(ArmCompileSpec.DebugMode.TOSA) + hook.add(cast(Node, test_data.mock_node), test_data.tosa_op, test_data.op_id) + + debug_events = hook._debug_events + assert len(debug_events) == test_data.expected_events + assert len(debug_events[0].torch_info.node_trace) == test_data.num_nodes_traced + + assert debug_events[0].tosa_info is None + + _compare_node_and_schema(debug_events[0], test_data.mock_node) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dim_order.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dim_order.py new file mode 100644 index 0000000..14e1246 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dim_order.py @@ -0,0 +1,127 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + + +input_t1 = Tuple[torch.Tensor, ...] # Input x + + +class ChannelsLastInput(torch.nn.Module): + """ + Test a complex case with (channels last, channels first) input, + and (channels first, channels last) output. + """ + + inputs: input_t1 = ( + torch.arange(1, 25, dtype=torch.float32) + .reshape((1, 2, 3, 4)) + .to(memory_format=torch.channels_last), + torch.arange(1, 25, dtype=torch.float32).reshape((1, 2, 3, 4)), + ) + + def forward(self, x, y): + x = x * x + return y, x + + +class ChannelsFirstOutput(torch.nn.Module): + """ + Test coverting to channels_first inside the delegate. + """ + + inputs: input_t1 = ( + torch.arange(1, 25, dtype=torch.float32) + .reshape((1, 2, 3, 4)) + .to(memory_format=torch.channels_last), + ) + + def forward(self, x): + x = x.clone(memory_format=torch.contiguous_format) * x + return x + + +class ChannelsLastOutput(torch.nn.Module): + """ + Test changing of dim_order inside the delegate. + """ + + inputs: input_t1 = (torch.arange(1, 9, dtype=torch.float32).reshape((1, 2, 2, 2)),) + + def forward(self, x): + x = x * x + x = x.clone(memory_format=torch.channels_last) + return x + + +class ChannelsLastInsidePartition(torch.nn.Module): + """ + Test dim_order changes inside the partiton, but no dim_order changes at input/output. + """ + + inputs: input_t1 = (torch.randn((1, 2, 3, 3)),) + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d(in_channels=2, out_channels=2, kernel_size=(3, 3)) + + def forward(self, x): + return ( + self.conv2d(x.clone(memory_format=torch.channels_last)).clone( + memory_format=torch.contiguous_format + ) + * 1 + ) + + +test_modules = { + "channels_last_input": ChannelsLastInput, + "channels_first_output": ChannelsFirstOutput, + "channels_last_output": ChannelsLastOutput, + "channels_last_inside_partition": ChannelsLastInsidePartition, +} + + +@common.parametrize("module", test_modules) +def test_dim_order_tosa_FP(module) -> None: + aten_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1](module(), module.inputs, aten_ops) + pipeline.run() + + +@common.parametrize("module", test_modules) +def test_dim_order_tosa_INT(module) -> None: + aten_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + module(), module.inputs, aten_ops, symmetric_io_quantization=True + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("module", test_modules) +def test_dim_order_u55_INT(module) -> None: + aten_ops: list[str] = [] + pipeline = EthosU55PipelineINT[input_t1](module(), module.inputs, aten_ops) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("module", test_modules) +def test_dim_order_u85_INT(module) -> None: + aten_ops: list[str] = [] + pipeline = EthosU85PipelineINT[input_t1](module(), module.inputs, aten_ops) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dw_convs_with_shared_weights.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dw_convs_with_shared_weights.py new file mode 100644 index 0000000..9e09185 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_dw_convs_with_shared_weights.py @@ -0,0 +1,46 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, Tuple + +import torch +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor] + + +class DWConvsModule(torch.nn.Module): + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + conv = torch.nn.Conv2d(6, 6, kernel_size=(2, 2), groups=6) + relu = torch.nn.ReLU() + self.sequential = torch.nn.ModuleList([conv, relu, conv]) + + def forward(self, x) -> torch.Tensor: + for m in self.sequential: + x = m(x) + return x + + def get_inputs(self) -> input_t: + return (torch.randn(1, 6, 24, 24),) + + +def test_convs_tosa_FP(): + module = DWConvsModule() + pipeline = TosaPipelineFP[input_t]( + module, module.get_inputs(), aten_op=[], exir_op=[] + ) + pipeline.run() + + +def test_convs_tosa_INT(): + module = DWConvsModule() + pipeline = TosaPipelineINT[input_t]( + module, module.get_inputs(), aten_op=[], exir_op=[] + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_extract_io_params_tosa.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_extract_io_params_tosa.py new file mode 100644 index 0000000..229970b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_extract_io_params_tosa.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import copy + +import pytest +import torch +from executorch.backends.arm.quantizer import VgfQuantizer +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test.common import SkipIfNoModelConverter +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.vgf import VgfCompileSpec, VgfPartitioner +from executorch.exir import to_edge_transform_and_lower +from executorch.exir.passes.quantize_io_pass import extract_io_quant_params +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + + +class SimpleAdd(torch.nn.Module): + def forward(self, x, y): + return x + y + + +@pytest.mark.parametrize( + "compile_spec_cls, quantizer_cls, partitioner_cls", + [ + (TosaCompileSpec, TOSAQuantizer, TOSAPartitioner), + pytest.param( + VgfCompileSpec, + VgfQuantizer, + VgfPartitioner, + marks=SkipIfNoModelConverter, + id="VGF", + ), + ], +) +def test_roundtrip_extracts_io_params_tosa_INT( + compile_spec_cls: type[TosaCompileSpec] | type[VgfCompileSpec], + quantizer_cls, + partitioner_cls, +): + """ + Validates that IO quantization parameters round-trip for both flows. + """ + example_inputs = ( + torch.ones(1, 5), + torch.full((1, 5), 2.0), + ) + mod = SimpleAdd().eval() + + compile_spec = compile_spec_cls("TOSA-1.0+INT") + + quantizer = quantizer_cls(compile_spec) + operator_config = get_symmetric_quantization_config(is_qat=True) + quantizer.set_global(operator_config) + + exported = torch.export.export(mod, copy.deepcopy(example_inputs), strict=True) + prepared = prepare_pt2e(exported.module(), quantizer) + _ = prepared(*example_inputs) + + converted = convert_pt2e(prepared) + final_export = torch.export.export(converted, example_inputs, strict=True) + partitioner = partitioner_cls(compile_spec) + edge_prog = to_edge_transform_and_lower(final_export, partitioner=[partitioner]) + + # Extract IO quantization parameters + q = extract_io_quant_params( + edge_prog, + input_idxs=(0, 1), + output_idxs=(0,), + ) + + assert "inputs" in q + assert "outputs" in q + assert len(q["inputs"]) == 2 + assert len(q["outputs"]) == 1 + + for name, params in q["inputs"].items(): + assert isinstance(name, str) + assert isinstance(params["scale"], float) + assert isinstance(params["zero_point"], int) + + out_name, out_params = next(iter(q["outputs"].items())) + assert isinstance(out_name, str) + assert isinstance(out_params["scale"], float) + assert isinstance(out_params["zero_point"], int) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_int64.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_int64.py new file mode 100644 index 0000000..46a97ff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_int64.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.arm_tester import ArmTester + + +class ConstAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype, bias=0): + super().__init__() + self.dtype = dtype + self.bias = bias + + def forward(self, x: torch.Tensor): + c = torch.arange(self.bias, self.bias + 10, 1, dtype=self.dtype) + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +class BufferAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype, bias=0): + super().__init__() + self.dtype = dtype + self.buffer = torch.arange(0, 10, 1, dtype=self.dtype) + bias + self.bias = bias + + def forward(self, x: torch.Tensor): + c = self.buffer + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +class ConstChainAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype): + super().__init__() + self.dtype = dtype + + def forward(self, x: torch.Tensor): + c = torch.arange(0, 10, 1, dtype=self.dtype).reshape((2, 5)).unsqueeze(-1) + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +class BufferChainAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype): + super().__init__() + self.dtype = dtype + self.buffer = torch.arange(0, 10, 1, dtype=self.dtype) + + def forward(self, x: torch.Tensor): + c = self.buffer.reshape((2, 5)).unsqueeze(-1) + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +test_data_suite = { + "fp32_in+int64_buffer": (BufferAdd(torch.int64), (torch.rand(10) - 0.5,)), + "fp32_in+int64_buffer_overflow": ( + BufferAdd(torch.int64, 2**40), + (torch.rand(10) - 0.5,), + ), + "fp32_in+int64_const": (ConstAdd(torch.int64), (torch.rand(10) - 0.5,)), + "fp32_in+int64_const_overflow": ( + ConstAdd(torch.int64, 2**40), + (torch.rand(10) - 0.5,), + ), + "fp32_in+int64_buffer_chain": ( + BufferChainAdd(torch.int64), + (torch.rand(2, 5, 3) - 0.5,), + ), + "fp32_in+int64_const_chain": ( + ConstChainAdd(torch.int64), + (torch.rand(2, 5, 3) - 0.5,), + ), + "int64_in+float_const_chain": ( + ConstChainAdd(torch.float32), + (torch.randint(0, 10, (2, 5, 3)),), + ), +} + + +@common.parametrize("test_data", test_data_suite) +def test_int64_tosa_FP(test_data: Tuple): + model, inputs = test_data + ( + ArmTester( + model, + inputs, + common.get_tosa_compile_spec("TOSA-1.0+FP"), + ) + .export() + .to_edge_transform_and_lower() + .to_executorch() + .run_method_and_compare_outputs(inputs) + ) + + +@common.parametrize("test_data", test_data_suite) +def test_int64_tosa_INT(test_data: Tuple): + model, inputs = test_data + ( + ArmTester(model, inputs, common.get_tosa_compile_spec("TOSA-1.0+INT")) + .quantize() + .export() + .to_edge_transform_and_lower() + .to_executorch() + .run_method_and_compare_outputs(inputs) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_lifted_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_lifted_tensor.py new file mode 100644 index 0000000..ee9812b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_lifted_tensor.py @@ -0,0 +1,146 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import operator +from collections.abc import Callable +from typing import Union + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) +from executorch.backends.test.harness.stages import StageType + + +LiftedTensorInputs = tuple[torch.Tensor, int] +LiftedTensorCase = tuple[ + Callable[[torch.Tensor, torch.Tensor], torch.Tensor], + LiftedTensorInputs, +] +LiftedScalarTensorInputs = tuple[torch.Tensor, ...] +LiftedScalarTensorCase = tuple[ + Callable[[torch.Tensor, Union[float, int, torch.Tensor]], torch.Tensor], + LiftedScalarTensorInputs, + Union[float, int, torch.Tensor], +] + + +class LiftedTensor(torch.nn.Module): + + test_data: dict[str, LiftedTensorCase] = { + # test_name: (operator, test_data, length) + "add": (operator.add, (torch.randn(2, 2), 2)), + "truediv": (operator.truediv, (torch.ones(2, 2), 2)), + "mul": (operator.mul, (torch.randn(2, 2), 2)), + "sub": (operator.sub, (torch.rand(2, 2), 2)), + } + + def __init__(self, op: callable): # type: ignore[valid-type] + super().__init__() + self.op = op + self.lifted_tensor = torch.Tensor([[1, 2], [3, 4]]) + + def forward(self, x: torch.Tensor, length) -> torch.Tensor: + sliced = self.lifted_tensor[:, :length] + return self.op(sliced, x) # type: ignore[misc] + + +class LiftedScalarTensor(torch.nn.Module): + test_data: dict[str, LiftedScalarTensorCase] = { + # test_name: (operator, test_data) + "add": (operator.add, (torch.randn(2, 2),), 1.0), + "truediv": (operator.truediv, (torch.randn(4, 2),), 1.0), + "mul": (operator.mul, (torch.randn(1, 2),), 2.0), + "sub": (operator.sub, (torch.randn(3),), 1.0), + } + + def __init__(self, op: callable, arg1: Union[int, float, torch.tensor]): # type: ignore[valid-type] + super().__init__() + self.op = op + self.arg1 = arg1 + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.op(x, self.arg1) # type: ignore[misc] + + +"""Tests the ArmPartitioner with a placeholder of type lifted tensor.""" + + +@common.parametrize("test_data", LiftedTensor.test_data) +def test_partition_lifted_tensor_tosa_FP(test_data: LiftedTensorCase) -> None: + op, inputs = test_data + module = LiftedTensor(op) + aten_ops: list[str] = [] + pipeline = TosaPipelineFP[LiftedTensorInputs]( + module, + inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + signature = ( + pipeline.tester.stages[StageType.TO_EDGE] + .artifact.exported_program() + .graph_signature + ) + assert len(signature.lifted_tensor_constants) > 0 + + +@common.parametrize("test_data", LiftedTensor.test_data) +def test_partition_lifted_tensor_tosa_INT(test_data: LiftedTensorCase) -> None: + op, inputs = test_data + module = LiftedTensor(op) + aten_ops: list[str] = [] + pipeline = TosaPipelineINT[LiftedTensorInputs]( + module, + inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + signature = ( + pipeline.tester.stages[StageType.TO_EDGE] + .artifact.exported_program() + .graph_signature + ) + assert len(signature.lifted_tensor_constants) == 0 + + +@common.parametrize("test_data", LiftedScalarTensor.test_data) +def test_partition_lifted_scalar_tensor_tosa_FP( + test_data: LiftedScalarTensorCase, +) -> None: + op, tensor_inputs, scalar_arg = test_data + module = LiftedScalarTensor(op, scalar_arg) + aten_ops: list[str] = [] + pipeline = TosaPipelineFP[LiftedScalarTensorInputs]( + module, + tensor_inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LiftedScalarTensor.test_data) +def test_partition_lifted_scalar_tensor_tosa_INT( + test_data: LiftedScalarTensorCase, +) -> None: + op, tensor_inputs, scalar_arg = test_data + module = LiftedScalarTensor(op, scalar_arg) + aten_ops: list[str] = [] + pipeline = TosaPipelineINT[LiftedScalarTensorInputs]( + module, + tensor_inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_mixed_type_lowering.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_mixed_type_lowering.py new file mode 100644 index 0000000..6a2a1e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_mixed_type_lowering.py @@ -0,0 +1,83 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from collections import Counter, defaultdict + +import torch +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT + + +def combine_op_dicts(*dicts): + merged = defaultdict(Counter) + for d in dicts: + for op, dtypes in d.items(): + merged[op].update(dtypes) + return {op: dict(counts) for op, counts in merged.items()} + + +def repeat_op_dict(op_dict, times): + repeated = {} + for op, dtypes in op_dict.items(): + repeated[op] = {dtype: count * times for (dtype, count) in dtypes.items()} + return repeated + + +# TODO Figure out how to handle multiple dq/q nodes properly +# See backends/arm/_passes/decompose_quant_nodes.py for details +dq_tosa_ops = { + "CAST": {"FP32": 1, "INT32": 1}, + "SUB": {"INT32": 1}, # zero-point subtraction + "MUL": {"FP32": 1}, # scale multiplication +} +q_tosa_ops = { + "CAST": {"INT8": 1}, + "MUL": {"FP32": 1}, # scale multiplication + "ADD": {"FP32": 2}, # zero-point addition, rounding + "SUB": {"FP32": 1}, # for rounding + "CLAMP": {"FP32": 1}, # clamp + "GREATER_EQUAL": {"BOOL": 1}, # for rounding + "SELECT": {"FP32": 1}, # for rounding + "CEIL": {"FP32": 1}, # for rounding + "FLOOR": {"FP32": 1}, # for rounding +} + + +class AddSigmoidMul(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x, y): + return self.sigmoid(x + y) * x + + +def test_mixed_type_lowering_tosa_INT_FP(): + model = AddSigmoidMul() + input_data = (torch.randn(1, 16, 16, 16), torch.randn(1, 16, 16, 16)) + + pipeline = TosaPipelineINT[type(input_data)]( + model, input_data, [], [], qtol=1, tosa_extensions=["FP"] + ) + pipeline.quantizer.set_module_type(torch.nn.Sigmoid, None) + expected_tosa_dtype_counts = combine_op_dicts( + { + "SIGMOID": {"FP32": 1}, # SIGMOID should be executed in FP32 + "ADD": {"INT32": 1}, # ADD should be executed in INT32 + "MUL": {"INT32": 1}, # MUL should be executed in INT32 + }, + repeat_op_dict( + q_tosa_ops, 3 + ), # Two decomposed boundary Q nodes + one for SIGMOID + repeat_op_dict( + dq_tosa_ops, 2 + ), # One decomposed boundary DQ nodes + one for SIGMOID + ) + + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + expected_tosa_dtype_counts, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_model_evaluator.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_model_evaluator.py new file mode 100644 index 0000000..d9b8659 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_model_evaluator.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import tempfile +import unittest + +import torch +from executorch.backends.arm.util.arm_model_evaluator import GenericModelEvaluator + +# Create an input that is hard to compress +COMPRESSION_RATIO_TEST = torch.rand([1024, 1024]) + + +def mocked_model_1(input: torch.Tensor) -> torch.Tensor: + return torch.tensor([1.0, 2.0, 3.0, 4.0]) + + +def mocked_model_2(input: torch.Tensor) -> torch.Tensor: + return torch.tensor([1.0, 2.0, 3.0, 3.0]) + + +class TestGenericModelEvaluator(unittest.TestCase): + """Tests the GenericModelEvaluator class.""" + + def test_get_model_error_no_target(self): + example_input = torch.tensor([[1.0, 2.0, 3.0, 4.0]]) + evaluator = GenericModelEvaluator( + "dummy_model", + mocked_model_1, + mocked_model_2, + example_input, + "tmp/output_tag0.tosa", + ) + + model_error_dict = evaluator.get_model_error() + + self.assertEqual(model_error_dict["max_error"], [1.0]) + self.assertEqual(model_error_dict["max_absolute_error"], [1.0]) + self.assertEqual(model_error_dict["max_percentage_error"], [25.0]) + self.assertEqual(model_error_dict["mean_absolute_error"], [0.25]) + + def test_get_compression_ratio_no_target(self): + with tempfile.NamedTemporaryFile(delete=True) as temp_bin: + torch.save(COMPRESSION_RATIO_TEST, temp_bin) + + example_input = torch.tensor([[1.0, 2.0, 3.0, 4.0]]) + evaluator = GenericModelEvaluator( + "dummy_model", + mocked_model_1, + mocked_model_2, + example_input, + temp_bin.name, + ) + + ratio = evaluator.get_compression_ratio() + self.assertAlmostEqual(ratio, 1.1, places=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_delegates.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_delegates.py new file mode 100644 index 0000000..bbc0b2b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_delegates.py @@ -0,0 +1,53 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class MultipleDelegatesModule(torch.nn.Module): + inputs = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + z = x + y + s = torch.max(z) + return s * z + + +@common.parametrize("test_data", MultipleDelegatesModule.inputs) +def test_multiple_delegates_tosa_FP(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1]( + MultipleDelegatesModule(), test_data, aten_ops, exir_ops + ) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleDelegatesModule.inputs) +def test_multiple_delegates_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + MultipleDelegatesModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_outputs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_outputs.py new file mode 100644 index 0000000..6160bf4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_multiple_outputs.py @@ -0,0 +1,70 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class MultipleOutputsModule(torch.nn.Module): + inputs: dict[str, input_t1] = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return (x * y, x.sum(dim=-1, keepdim=True)) + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +def test_multiple_outputs_tosa_FP(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +def test_multiple_outputs_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +@common.XfailIfNoCorstone300 +def test_multiple_outputs_u55_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = EthosU55PipelineINT[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +@common.XfailIfNoCorstone320 +def test_multiple_outputs_u85_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = EthosU85PipelineINT[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_non_persistent_buffers.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_non_persistent_buffers.py new file mode 100644 index 0000000..374eb0a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_non_persistent_buffers.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn as nn + +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +class NonPersistentBuffer(nn.Module): + """ + Min code version registering a non-persistent input buffer. + """ + + def __init__(self): + super().__init__() + self.register_buffer("test_buff", torch.rand(2, 2, 2, 2), persistent=False) + + def forward(self, x): + return x - self.test_buff + + +test_input = {"input": (torch.ones(2, 2, 2, 2),)} + +input_t = tuple[torch.Tensor] + + +@parametrize("test_data", test_input) +def test_non_persistent_buffer_tosa_FP(test_data: input_t): + """ + Test validates Arm backend handling of non-persistent buffers + and ensures that there are no asserts or errors when they are used. + """ + TosaPipelineFP[input_t](NonPersistentBuffer(), test_data, "").run() + + +@parametrize("test_data", test_input) +def test_non_persistent_buffer_tosa_INT(test_data: input_t): + """ + Test validates Arm backend handling of non-persistent buffers + and ensures that there are no asserts or errors when they are used. + """ + TosaPipelineINT[input_t](NonPersistentBuffer(), test_data, "").run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_outputs_order.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_outputs_order.py new file mode 100644 index 0000000..f241b9a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_outputs_order.py @@ -0,0 +1,122 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +import importlib +import tempfile +from pathlib import Path +from typing import Any + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.exir import to_edge_transform_and_lower +from torch import nn +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + +_TOSA_GRAPH: Any = importlib.import_module("tosa.TosaGraph") + + +class Network(nn.Module): + def __init__(self, batch_norm=False): + super().__init__() + self.conv2d_0 = nn.Sequential( + nn.Conv2d(1, 8, 3, padding=1, bias=False), + nn.BatchNorm2d(8) if batch_norm else nn.Identity(), + nn.ReLU(), + ) + self.conv2d_1 = nn.Sequential( + nn.Conv2d(8, 8, 3, padding=1, bias=False), + nn.BatchNorm2d(8) if batch_norm else nn.Identity(), + nn.ReLU(), + ) + self.conv2d_2 = nn.Sequential( + nn.Conv2d(8, 8, 3, padding=1, bias=False), + nn.BatchNorm2d(8) if batch_norm else nn.Identity(), + nn.ReLU(), + ) + self.out_0 = nn.Sequential(nn.Conv2d(8, 1, 3, padding=1, bias=False), nn.ReLU()) + self.out_1 = nn.Sequential(nn.Conv2d(8, 2, 3, padding=1, bias=False), nn.ReLU()) + self.out_2 = nn.Sequential(nn.Conv2d(8, 3, 3, padding=1, bias=False), nn.ReLU()) + + def forward(self, x): + x = self.conv2d_0(x) + x = self.conv2d_1(x) + x = self.conv2d_2(x) + out0 = self.out_0(x) + out1 = self.out_1(x) + out2 = self.out_2(x) + return out0, out1, out2 + + +def _read_tosa_outputs(tosa_path: Path): + # Find output tensor names in order and return shapes + buf = tosa_path.read_bytes() + buf_arr = bytearray(buf) + graph = _TOSA_GRAPH.TosaGraph.GetRootAsTosaGraph(buf_arr, 0) + region = graph.Regions(0) + block = region.Blocks(0) + # Build a dict name - tensor‑shape + tensors = {} + for i in range(block.TensorsLength()): + t = block.Tensors(i) + name = t.Name().decode() + # NHWC + shape = [t.Shape(j) for j in range(t.ShapeLength())] + tensors[name] = shape + shapes = [] + for i in range(block.OutputsLength()): + out_name = block.Outputs(i).decode() + shapes.append(tensors[out_name]) + return shapes + + +# TODO: MLETORCH-1266 Investigate output order issue +@pytest.mark.parametrize("batch_size", [1, 4]) +@pytest.mark.parametrize("output_order_workaround", [True, False]) +def test_network_output_order_and_restore_tosa_INT(batch_size, output_order_workaround): + model = Network(batch_norm=True).eval() + # Prepare spec + spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + tosa_compile_spec = TosaCompileSpec(spec).set_output_order_workaround( + output_order_workaround + ) + # Setup quantizer + quantizer = TOSAQuantizer(tosa_compile_spec) + quantizer.set_global( + get_symmetric_quantization_config(is_qat=True, is_per_channel=False) + ) + # Trace the model + dummy = torch.randn(batch_size, 1, 28, 28) + fx_mod = torch.export.export(model, (dummy,)).module() + model = prepare_pt2e(fx_mod, quantizer) + model(dummy) + model = convert_pt2e(model) + # Export to aten dialect + aten_gm = torch.export.export(model, args=(dummy,), strict=True) + with tempfile.TemporaryDirectory(dir="") as tmpdir: + art_dir = Path(tmpdir) + part = TOSAPartitioner( + tosa_compile_spec.dump_intermediate_artifacts_to(str(art_dir)) + ) + _ = to_edge_transform_and_lower(aten_gm, partitioner=[part]) + # Expect exactly one .tosa file in the artefact dir + tosa_files = list(art_dir.glob("*.tosa")) + assert ( + len(tosa_files) == 1 + ), f"Expected 1 .tosa artefact, found {len(tosa_files)} in {art_dir}" + out_shapes = _read_tosa_outputs(tosa_files[0]) + # We use shape that is unique to output to check + # that we preserve output order + channel_dims = [s[1] for s in reversed(out_shapes)] + assert channel_dims == [1, 2, 3], ( + "Outputs in .tosa do not keep author order: " + f"expected [1, 2, 3], got {channel_dims}" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py new file mode 100644 index 0000000..0514ad5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py @@ -0,0 +1,181 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Test that tosa_supported_operators reject operators that are not +# quantized properly. This is typically a consequence of a torch op +# such a Softplus that is decompsed into many other ops without +# surrounding q/dq nodes. + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +input_t1 = tuple[torch.Tensor, ...] +softplus_aten_op: list[str] = [ + "torch.ops.aten.add.Tensor", + "torch.ops.aten.softplus.default", +] +softplus_exir_op: list[str] = [ + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_exp_default", + "executorch_exir_dialects_edge__ops_aten_div_Tensor", +] + +linear_residual_aten_op: list[str] = [ + "torch.ops.aten.linear.default", + "torch.ops.aten.gelu.default", + "torch.ops.aten.dropout.default", + "torch.ops.aten.add.Tensor", +] +linear_residual_exir_op: list[str] = [ + "executorch_exir_dialects_edge__ops_aten_gelu_default", + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default", + "executorch_exir_dialects_edge__ops_aten_linear_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", +] + + +test_data: dict[str, input_t1] = { + "3d_rand": (torch.rand(1, 5, 5),), +} + + +class SoftplusModule(torch.nn.Module): + """Module containing an addition followed by a Softplus. Softplus is currently not supported by TosaBackend.""" + + def __init__(self): + super().__init__() + self.softplus = torch.nn.Softplus() + + def forward(self, x: torch.Tensor): + return self.softplus(x + x) + + +class LinearResidualModule(torch.nn.Module): + """Module containing a residual and a linear layer followed by GELU and a Dropout. + GELU is currently not supported by TosaBackend nor TosaQuantizer. + """ + + def __init__( + self, + ): + super().__init__() + self.linear = torch.nn.Linear(in_features=5, out_features=3) + self.gelu = torch.nn.GELU() + self.dropout = torch.nn.Dropout(0.5) + + def forward(self, x: torch.Tensor): + x1 = self.linear(x) + x2 = self.gelu(x1) + x3 = self.dropout(x2) + return x1 + x3 + + +# Softplus is decomposed which messes up the quantization. This test tests that CheckProperQuantization does not +# partition nodes where quantization is not as expected. +@common.parametrize("test_data", test_data) +def test_softplus_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SoftplusModule(), + test_data=test_data, + aten_op=softplus_aten_op, + exir_op=softplus_exir_op, + ) + # remove check_count.exir as there will be more than one delegate + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_softplus_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + SoftplusModule(), + test_data=test_data, + aten_op=softplus_aten_op, + exir_op=softplus_exir_op, + ) + pipeline.pop_stage("check_not.exir") + # check that all ops in softplus_exir_op except add are rejected + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check, + softplus_exir_op[1:], + suffix="exir_post_partition", + ) + pipeline.run() + + +# Since GELU will not be quantized by TosaQuantizer, the Dropout's input will not be quantized either. +# If so, the Dropout should not be partitioned by TosaPartitioner for TOSA INT profile. This test tests that the +# partitioner indeed does not partition the Dropout (clone) for TOSA INT. +@common.parametrize( + "test_data", + test_data, + {"3d_rand": "MLETORCH-909: Partition test to not rely on unsupported ops"}, + strict=False, +) +def test_linear_residaul_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + LinearResidualModule(), + test_data=test_data, + aten_op=linear_residual_aten_op, + exir_op=linear_residual_exir_op, + use_to_edge_transform_and_lower=True, + ) + # remove check_count.exir as there will be more than one delegate + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("check_not.exir") + # check that all ops in linear_residual_exir_op except GELU are partitioned + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_not, + linear_residual_exir_op[1:], + suffix="exir_post_partition", + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check, + linear_residual_exir_op[:1], + suffix="exir_post_partition", + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data, + {"3d_rand": "MLETORCH-855: Issue with Quantization folding."}, + strict=False, +) +def test_linear_residual_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + LinearResidualModule(), + test_data=test_data, + aten_op=linear_residual_aten_op, + exir_op=linear_residual_exir_op, + use_to_edge_transform_and_lower=True, + ) + # remove check_count.exir as there will be more than one delegate + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("check_not.exir") + # check that all ops in linear_residual_exir_op except GELU and Dropout are partitioned + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_not, + linear_residual_exir_op[2:], + suffix="exir_post_partition", + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check, + linear_residual_exir_op[:2], + suffix="exir_post_partition", + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_pipeline_config.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_pipeline_config.py new file mode 100644 index 0000000..6a031bf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_pipeline_config.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm._passes import ( + DecomposeSoftmaxUnstablePass, + FuseDuplicateUsersPass, +) +from executorch.backends.arm._passes.arm_pass_manager import ArmPassManager +from executorch.backends.arm.common.pipeline_config import ArmPassPipelineConfig +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.specification import TosaSpecification + + +def test_pipeline_config_override_outside_compile_spec_no_target(): + compile_spec = TosaCompileSpec( + TosaSpecification.create_from_string("TOSA-1.00+INT") + ) + default_manager = ArmPassManager(compile_spec) + default_skip_passes = default_manager._skip_pass_types + assert FuseDuplicateUsersPass not in default_skip_passes + assert DecomposeSoftmaxUnstablePass in default_skip_passes + + override_compile_spec = TosaCompileSpec( + TosaSpecification.create_from_string("TOSA-1.00+INT") + ) + override_config = ArmPassPipelineConfig() + override_config.disable_fuse_duplicate_users() + override_compile_spec.set_pass_pipeline_config(override_config) + override_manager = ArmPassManager(override_compile_spec) + skip_passes = override_manager._skip_pass_types + + assert FuseDuplicateUsersPass in skip_passes + assert DecomposeSoftmaxUnstablePass in skip_passes diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_required_order.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_required_order.py new file mode 100644 index 0000000..615a5a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_pass_required_order.py @@ -0,0 +1,97 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import re +from typing import List, Set, Type + +import pytest +from executorch.backends.arm._passes.arm_pass_manager import ArmPass, ArmPassManager +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.exir.pass_base import ExportPass + + +class PassC(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = set() + + +class PassB(ArmPass): + _passes_required_after = {PassC} + + +class PassA(ArmPass): + _passes_required_after = {PassB, PassC} + + +class IndependentPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = set() + + +def _setup_pass_manager(passes: List[ArmPass] | None = None): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.00+INT") + compile_spec = TosaCompileSpec(tosa_spec) + pass_manager = ArmPassManager(compile_spec) + if passes is not None: + for p in passes: + pass_manager.add_pass(p) + return pass_manager + + +def test_no_passes_tosa_INT(): + pass_manager = _setup_pass_manager() + pass_manager.validate_constraints_mandatory() + + +def test_correct_order_tosa_INT(): + pass_manager = _setup_pass_manager([PassA(), PassB(), PassC()]) + pass_manager.validate_constraints_mandatory() + + +def test_run_pass_twice_tosa_INT(): + pass_manager = _setup_pass_manager([PassA(), PassB(), PassB(), PassC()]) + pass_manager.validate_constraints_mandatory() + + +def test_independent_pass_tosa_INT(): + pass_manager = _setup_pass_manager( + [ + IndependentPass(), + PassA(), + IndependentPass(), + PassB(), + IndependentPass(), + PassC(), + IndependentPass(), + ] + ) + pass_manager.validate_constraints_mandatory() + + +def test_duplicated_requiring_pass_put_last_tosa_INT(): + error_msg = """The following constraints for passes are not met: + - PassC must run after PassB +""" + pass_manager = _setup_pass_manager([PassA(), PassB(), PassC(), PassB()]) + with pytest.raises(RuntimeError, match=re.escape(error_msg)): + pass_manager.validate_constraints_mandatory() + + +def test_two_passes_wrong_order_tosa_INT(): + error_msg = """The following constraints for passes are not met: + - PassC must run after PassB +""" + pass_manager = _setup_pass_manager([PassC(), PassB()]) + with pytest.raises(RuntimeError, match=re.escape(error_msg)): + pass_manager.validate_constraints_mandatory() + + +def test_missing_passes_tosa_INT(): + error_msg = """The following constraints for passes are not met: + - PassC must run after PassA + - PassC must run after PassB +""" + pass_manager = _setup_pass_manager([PassA(), PassB()]) + with pytest.raises(RuntimeError, match=re.escape(error_msg)): + pass_manager.validate_constraints_mandatory() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_qat_training_loop.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_qat_training_loop.py new file mode 100644 index 0000000..425849b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_qat_training_loop.py @@ -0,0 +1,100 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.export import export +from torchao.quantization.pt2e import ( + move_exported_model_to_eval, + move_exported_model_to_train, +) +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_qat_pt2e + +logger = logging.getLogger(__name__) + + +class MLP(torch.nn.Module): + def __init__(self): + super().__init__() + self.sequential = torch.nn.Sequential( + torch.nn.Linear(1, 10), + torch.nn.ReLU(), + torch.nn.Linear(10, 10), + torch.nn.ReLU(), + torch.nn.Linear(10, 1), + ) + + def forward(self, x): + return self.sequential(x) + + +def evaluate_model(model, inputs, expected_outputs): + with torch.no_grad(): + test_outputs = model(inputs) + loss = torch.nn.functional.mse_loss(test_outputs, expected_outputs) + logger.info(f"Mean squared error: {loss.item()}") + + +def test_qat_training_loop_tosa_INT(): + """Test the QAT training loop with a simple MLP model. + This function creates a simple MLP model, prepares it for QAT, runs a training loop, + and evaluates the quantized model to make sure everything works as expected.""" + + model = MLP() + logger.info("Starting training loop test") + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + for epoch in range(100): + model.train() + optimizer.zero_grad() + inputs = torch.randn(100, 1).clamp(-1, 1) + outputs = model(inputs) + loss = torch.nn.functional.mse_loss(outputs, torch.sin(inputs)) + loss.backward() + optimizer.step() + if epoch % 5 == 0: + logger.info(f"Epoch {epoch}, Loss: {loss.item()}") + logger.info("Training loop test completed successfully") + + logger.info("Evaluating model before QAT") + test_inputs = torch.randn(20, 1).clamp(-1, 1) + test_outputs = torch.sin(test_inputs) + evaluate_model(model, test_inputs, test_outputs) + + exported_model = export(model, (torch.randn(1, 1),), strict=True) + quantizer = TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + quantizer.set_global(get_symmetric_quantization_config(is_qat=True)) + + prepared_model = prepare_qat_pt2e(exported_model.module(), quantizer) + prepared_model = move_exported_model_to_train(prepared_model) + logger.info("QAT model prepared successfully") + + logger.info("Starting QAT training loop") + + for epoch in range(25): + inputs = torch.randn(100, 1).clamp(-1, 1) + optimizer.zero_grad() + outputs = prepared_model(inputs) + loss = torch.nn.functional.mse_loss(outputs, torch.sin(inputs)) + loss.backward() + optimizer.step() + if epoch % 5 == 0: + logger.info(f"QAT Epoch {epoch}, Loss: {loss.item()}") + logger.info("QAT training loop completed successfully") + prepared_model = move_exported_model_to_eval(prepared_model) + + quantized_model = convert_pt2e(prepared_model) + logger.info("QAT model quantized successfully") + + logger.info("Evaluating quantized model") + test_inputs = torch.randn(100, 1).clamp(-1, 1) + test_outputs = torch.sin(test_inputs) + evaluate_model(quantized_model, test_inputs, test_outputs) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_quant_custom_meta.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_quant_custom_meta.py new file mode 100644 index 0000000..59156c2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_quant_custom_meta.py @@ -0,0 +1,105 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT + + +class AddSigmoidMul(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x, y): + return self.sigmoid(x + y) * x + + +@pytest.mark.parametrize("fp_extension", [True, False]) +def test_qdq_squeezed_fp_op_tosa_INT_FP(fp_extension: bool): + """Test that a float operation surrounded by quantize-dequantize pairs + is correctly handled by the partitioner and the TOSA backend. + Pattern: + q -> dq -> add -> q -> dq -> sigmoid -> q -> dq -> mul -> dq -> q + |_____unquantized_____| + """ + aten_op = "torch.ops.aten.add.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_add_Tensor" + module = AddSigmoidMul() + x = torch.randn(2, 3, 4) + y = torch.randn(2, 3, 4) + pipeline = TosaPipelineINT( + module=module, + test_data=(x, y), + aten_op=aten_op, + exir_op=exir_op, + tosa_extensions=["FP"] if fp_extension else None, + ) + pipeline.quantizer.set_module_type(torch.nn.Sigmoid, None) # type: ignore + + if not fp_extension: + # In case we don't have the FP extension, the unquantized part of the + # graph should not be delegated to the Arm backend. Modify the op count + # checks to reflect this behavior. + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 2, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + }, + ) + pipeline.run() + + +class MulAddSigmoidConv(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sigmoid = torch.nn.Sigmoid() + self.conv = torch.nn.Conv1d(3, 3, 1) + + def forward(self, x, y): + return self.conv(self.sigmoid(x + y * x)) + + +@pytest.mark.parametrize("fp_extension", [True, False]) +def test_quantized_to_float_transition_tosa_INT_FP(fp_extension: bool): + """Test that a model executing quantized ops followed by float ops + is correctly handled by the partitioner and the TOSA backend. + Pattern: + q -> dq -> mul -> q -> dq -> add -> q -> dq -> sigmoid -> conv + |___unquantized___| + """ + aten_op = "torch.ops.aten.add.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_add_Tensor" + module = MulAddSigmoidConv() + x = torch.randn(2, 3, 4) + y = torch.randn(2, 3, 4) + pipeline = TosaPipelineINT( + module=module, + test_data=(x, y), + aten_op=aten_op, + exir_op=exir_op, + tosa_extensions=["FP"] if fp_extension else None, + ) + if not fp_extension: + # In case we don't have the FP extension, the unquantized part of the + # graph should not be delegated to the Arm backend. Modify the op count + # checks to reflect this behavior. + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 1, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + }, + ) + pipeline.quantizer.set_module_type(torch.nn.Sigmoid, None) # type: ignore + pipeline.quantizer.set_module_type(torch.nn.Conv1d, None) # type: ignore + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_rescale_range.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_rescale_range.py new file mode 100644 index 0000000..1075dd4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_rescale_range.py @@ -0,0 +1,130 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch + +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from torch._subclasses.fake_tensor import FakeTensorMode + +input_t = Tuple[torch.Tensor, torch.Tensor] # Input x + + +def test_rescale_op_tosa_INT(): + sample_inputs = [ + # (data, out_dtype, scale, in_zp, out_zp) + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int32, + [0.2], + 2, + 0, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int32), + torch.int8, + [0.2], + 0, + -128, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int8, + [0.8], + 10, + 127, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input in sample_inputs: + exir_ops.backend.tosa.RESCALE.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_nonzero_zp_for_int32_tosa_INT(): + + sample_inputs = [ + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int32, + [0.2], + 2, # Should be 0, expect error + 1, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int32), + torch.int8, + [0.2], + 1, + 1, # Should be 0, expect error + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input in sample_inputs: + with pytest.raises( + ValueError, match="TOSA requires (output|input)_zp to be zero" + ): + exir_ops.backend.tosa.RESCALE.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_zp_outside_range_tosa_INT(): + + sample_inputs = [ + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int32, + [0.2], + 128, # Should be <128, expect error + 0, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int32), + torch.int8, + [0.2], + 0, + -129, # Should be >-129 expect error + ), + ] + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input in sample_inputs: + with pytest.raises( + Exception, match="(in_zp|out_zp)=-?[0-9]* outside valid range" + ): + exir_ops.backend.tosa.RESCALE.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_save_exported_model.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_save_exported_model.py new file mode 100644 index 0000000..4ac5d46 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_save_exported_model.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import os + +import torch +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.tosa import TosaSpecification +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + + +class SimpleModule(torch.nn.Module): + example_inputs = (torch.randn(1, 10),) + + def __init__(self): + super().__init__() + self.linear = torch.nn.Linear(10, 10) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.linear(x) + + +def test_save_load_exported_int_model_tosa_INT(): + module = SimpleModule().eval() + example_inputs = module.example_inputs + exported_module = torch.export.export(module, example_inputs) + + # Set up quantizer + quantizer = TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + quantizer.set_global(get_symmetric_quantization_config()) + # Quantize model + prepared_module = prepare_pt2e(exported_module.module(), quantizer) + prepared_module(*example_inputs) + quantized_module = convert_pt2e(prepared_module) + quantized_exported_module = torch.export.export(quantized_module, example_inputs) + + base_path = "arm_test/misc/" + if not os.path.exists(base_path): + os.makedirs(base_path) + file_path = base_path + "exported_module.pt2" + # Verify that we can save the model + torch.export.save(quantized_exported_module, file_path) + + # Verify that we can load the model back + loaded_model = torch.export.load( + file_path + ) # nosec B614 - loads trusted test artifact + for original_node, loaded_node in zip( + quantized_exported_module.graph.nodes, loaded_model.graph.nodes + ): + # Verify that the custom metadata is preserved after save/load + assert original_node.meta.get("custom", {}) == loaded_node.meta.get( + "custom", {} + ) + if original_node.target == torch.ops.aten.linear.default: + assert ArmAnnotationInfo.CUSTOM_META_KEY in original_node.meta.get( + "custom", {} + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_conv2d.py new file mode 100644 index 0000000..7cee503 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_conv2d.py @@ -0,0 +1,220 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import executorch.backends.arm.tosa.dialect # noqa: unused +import pytest +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops +from torch._subclasses.fake_tensor import FakeTensorMode + + +def test_conv2d_tosa_INT(): + sample_inputs = [ + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (8, 2, 5, 5), dtype=torch.int8), + torch.randint(-(2**31), 2**31, (8,), dtype=torch.int32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 8, 20, 20), + torch.int32, + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (4, 2, 5, 5), dtype=torch.int8), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 4, 10, 10), + torch.int32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_conv2d_invalid_tosa_INT(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.float32} but found input type {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int8} weights for {torch.int8} input but found {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (8, 2, 5, 5), dtype=torch.int8), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int32} bias for {torch.int8} input but found {torch.float32}", + ), + ] + + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_conv2d_tosa_FP(): + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 8, 20, 20), + torch.float32, + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((4, 2, 5, 5), dtype=torch.float32), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 4, 10, 10), + torch.float32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+FP") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_conv2d_invalid_tosa_FP(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+FP") + sample_inputs = [ + ( + ( + torch.randint(-127, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.int8} but found input type {torch.int8}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float16), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires weights {torch.float16} to be of the same type as input {torch.float32}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float16), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires bias {torch.float16} to be of the same type as input {torch.float32}", + ), + ] + + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py new file mode 100644 index 0000000..3a6b5ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py @@ -0,0 +1,227 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import executorch.backends.arm.tosa.dialect # noqa: unused +import pytest +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops +from torch._subclasses.fake_tensor import FakeTensorMode + + +def test_depthwise_conv2d_tosa_INT(): + sample_inputs = [ + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randint(-127, 127, (5, 2, 5, 8), dtype=torch.int8), + torch.randint(-(2**31), 2**31, (16,), dtype=torch.int32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 16, 20, 20), + torch.int32, + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randint(-127, 127, (5, 4, 5, 8), dtype=torch.int8), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 32, 10, 10), + torch.int32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_depthwise_conv2d_invalid_tosa_INT(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.float32} but found input type {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int8} weights for {torch.int8} input but found {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (5, 2, 5, 8), dtype=torch.int8), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int32} bias for {torch.int8} input but found {torch.float32}", + ), + ] + + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_depthwise_conv2d_tosa_FP(): + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 16, 20, 20), + torch.float32, + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 4, 5, 8), dtype=torch.float32), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 32, 10, 10), + torch.float32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+FP") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_depthwise_conv2d_invalid_tosa_FP(): + + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+FP") + + sample_inputs = [ + ( + ( + torch.randint(-127, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.int8} but found input type {torch.int8}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((5, 2, 5, 8), dtype=torch.float16), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires weights {torch.float16} to be of the same type as input {torch.float32}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float16), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires bias {torch.float16} to be of the same type as input {torch.float32}", + ), + ] + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_spec.py new file mode 100644 index 0000000..9d8882e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/misc/test_tosa_spec.py @@ -0,0 +1,169 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +from executorch.backends.arm.tosa.specification import ( + Tosa_1_00, + TosaSpecification, + TosaSpecMapping, +) + +from parameterized import parameterized # type: ignore[import-untyped] + +test_valid_strings = [ + "TOSA-1.0.0+INT+FP+fft", + "TOSA-1.0.0+FP+bf16+fft", + "TOSA-1.0.0+INT+int4+cf", + "TOSA-1.0.0+FP+cf+bf16+8k", + "TOSA-1.0.0+FP+INT+bf16+fft+int4+cf", + "TOSA-1.0.0+FP+INT+fft+int4+cf+8k", + "TOSA-1.0+INT+FP+fft", + "TOSA-1.0+FP+bf16+fft", + "TOSA-1.0+INT+int4+cf", + "TOSA-1.0+FP+cf+bf16+8k", + "TOSA-1.0+FP+INT+bf16+fft+int4+cf", + "TOSA-1.0+FP+INT+fft+int4+cf+8k", +] + +test_valid_extensions = { + "INT": ["int16", "int4", "var", "cf"], + "FP": ["bf16", "fp8e4m3", "fp8e5m2", "fft", "var", "cf"], +} + +test_invalid_strings = [ + "TOSA-1.0.0+fft", + "TOSA-1.0.0+fp+bf16+fft", + "TOSA-1.0.0+INT+INT4+cf", + "TOSA-1.0.0+FP+FP+INT", + "TOSA-1.0.0+FP+CF+bf16", + "TOSA-1.0.0+BF16+fft+int4+cf+INT", +] + + +class TestTosaSpecification(unittest.TestCase): + """Tests the TOSA specification class""" + + @parameterized.expand(test_valid_strings) # type: ignore[misc] + def test_version_string_no_target(self, version_string: str): + tosa_spec = TosaSpecification.create_from_string(version_string) + assert isinstance(tosa_spec, Tosa_1_00) + assert [profile in ["INT", "FP"] for profile in tosa_spec.profiles].count( + True + ) > 0 + + for profile in tosa_spec.profiles: + assert [e in test_valid_extensions[profile] for e in tosa_spec.extensions] + + @parameterized.expand(test_invalid_strings) # type: ignore[misc] + def test_invalid_version_strings_no_target(self, version_string: str): + tosa_spec = None + with self.assertRaises(ValueError): + tosa_spec = TosaSpecification.create_from_string(version_string) + + assert tosa_spec is None + + @parameterized.expand(test_valid_strings) + def test_correct_string_representation_no_target(self, version_string: str): + tosa_spec = TosaSpecification.create_from_string(version_string) + assert isinstance(tosa_spec, Tosa_1_00) + assert f"{tosa_spec}" == version_string + + +class TestTosaSpecMapping(unittest.TestCase): + """Tests the TosaSpecMapping class""" + + def test_mapping_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + # check that the mapping is correct + vals = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + assert vals == ["A"] + assert len(vals) == 1 + + def test_mapping_multiple_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "B") + # check that the mapping is correct + vals = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + assert vals == ["A", "B"] + assert len(vals) == 2 + + def test_mapping_different_profiles_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "B") + # check that the mapping is correct + vals_int = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + vals_fp = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+FP")) + + assert vals_int == ["A"] + assert vals_fp == ["B"] + assert len(vals_int) == 1 + assert len(vals_fp) == 1 + + def test_mapping_different_profiles_combined_consumer_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "B") + # check that the mapping is correct + combined_vals = mapping.get( + TosaSpecification.create_from_string("TOSA-1.0+INT+FP") + ) + + assert "A" in combined_vals + assert "B" in combined_vals + assert len(combined_vals) == 2 + + def test_mapping_no_spec_no_target(self): + mapping = TosaSpecMapping() + with self.assertRaises(KeyError): + mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + def test_mapping_no_values_for_spec_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "A") + with self.assertRaises(KeyError): + mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + def test_spec_with_different_profiles_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "B") + # check that the mapping is correct + vals_int = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + vals_fp = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+FP")) + vals_int_fp = mapping.get( + TosaSpecification.create_from_string("TOSA-1.0+INT+FP") + ) + + assert vals_fp == ["A"] + assert vals_int == ["B"] + assert len(vals_int) == 1 + assert len(vals_fp) == 1 + assert len(vals_int_fp) == 2 + + def test_combined_profiles_no_target(self): + mapping = TosaSpecMapping() + with self.assertRaises(ValueError): + # Don't allow multiple profiles in a single spec + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT+FP"), "A") + + def test_spec_add_with_extension_no_target(self): + mapping = TosaSpecMapping() + with self.assertRaises(ValueError): + mapping.add( + TosaSpecification.create_from_string("TOSA-1.0.0+INT+int16"), "A" + ) + + def test_spec_non_canonical_key_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + + val = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT+u55")) + assert val == ["A"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py new file mode 100644 index 0000000..86e9453 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +# Adapted from Hugging Face's diffusers library: +# https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py +# +# Licensed under the Apache License, Version 2.0 +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from transformers import CLIPTextConfig, T5Config + + +""" +This file defines test configs used to initialize Stable Diffusion module tests. +Module tests in the same directory will import these configs. + +To stay aligned with the Stable Diffusion implementation in the HuggingFace Diffusers library, +the configs here are either directly copied from corresponding test files or exported from +pre-trained models used in the Diffusers library. + +Licenses: +The test parameters are from Hugging Face's diffusers library and under the Apache 2.0 License, +while the remainder of the code is under the BSD-style license found in the LICENSE file in the +root directory of this source tree. +""" + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py#L56 +CLIP_text_encoder_config = CLIPTextConfig( + bos_token_id=0, + eos_token_id=2, + hidden_size=32, + intermediate_size=37, + layer_norm_eps=1e-05, + num_attention_heads=4, + num_hidden_layers=5, + pad_token_id=1, + vocab_size=1000, + hidden_act="gelu", + projection_dim=32, +) + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py#L76 +# Exported from: T5EncoderModel.from_pretrained("hf-internal-testing/tiny-random-t5").config +T5_encoder_config = T5Config( + bos_token_id=0, + classifier_dropout=0.0, + d_ff=37, + d_kv=8, + d_model=32, + decoder_start_token_id=0, + dense_act_fn="relu", + dropout_rate=0.1, + eos_token_id=1, + feed_forward_proj="relu", + gradient_checkpointing=False, + initializer_factor=0.002, + is_encoder_decoder=True, + is_gated_act=False, + layer_norm_epsilon=1e-06, + model_type="t5", + num_decoder_layers=5, + num_heads=4, + num_layers=5, + pad_token_id=0, + relative_attention_max_distance=128, + relative_attention_num_buckets=8, + transformers_version="4.47.1", + vocab_size=1000, +) + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/models/transformers/test_models_transformer_sd3.py#L142 +SD3Transformer2DModel_init_dict = { + "sample_size": 32, + "patch_size": 1, + "in_channels": 4, + "num_layers": 4, + "attention_head_dim": 8, + "num_attention_heads": 4, + "caption_projection_dim": 32, + "joint_attention_dim": 32, + "pooled_projection_dim": 64, + "out_channels": 4, + "pos_embed_max_size": 96, + "dual_attention_layers": (0,), + "qk_norm": "rms_norm", +} + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py#L83 +AutoencoderKL_config = { + "sample_size": 32, + "in_channels": 3, + "out_channels": 3, + "block_out_channels": (4,), + "layers_per_block": 1, + "latent_channels": 4, + "norm_num_groups": 1, + "use_quant_conv": False, + "use_post_quant_conv": False, + "shift_factor": 0.0609, + "scaling_factor": 1.5035, +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py new file mode 100644 index 0000000..b68ad39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py @@ -0,0 +1,168 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import ( + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, + InsertInt32CastsAfterInt64PlaceholdersPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + CLIP_text_encoder_config, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from transformers import CLIPTextModelWithProjection + +input_t = Tuple[torch.Tensor] + + +class TestCLIPTextModelWithProjection: + """ + Test class of CLIPTextModelWithProjection. + CLIPTextModelWithProjection is one of the text_encoder used by Stable Diffusion 3.5 Medium + """ + + # Adjust nbr below as we increase op support. + ops_after_partitioner_FP = { + "executorch_exir_dialects_edge__ops_aten_argmax_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 2, + } + + ops_after_partitioner_INT = { + "executorch_exir_dialects_edge__ops_aten_argmax_default": 1, + "executorch_exir_dialects_edge__ops_aten_index_select_default": 1, + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 2, + } + + ops_after_partitioner_vgf_quantize = ops_after_partitioner_FP + ops_after_partitioner_vgf_no_quantize = ops_after_partitioner_FP + + def _prepare_inputs( + self, + batch_size=12, + seq_length=7, + vocab_size=1000, + ): + input_ids = torch.randint( + low=0, + high=vocab_size, + size=(batch_size, seq_length), + dtype=torch.long, + ) + return (input_ids,) + + def prepare_model_and_inputs(self): + clip_text_encoder_config = CLIP_text_encoder_config + + text_encoder_model = CLIPTextModelWithProjection(clip_text_encoder_config) + text_encoder_model.eval() + text_encoder_model_inputs = self._prepare_inputs() + + return text_encoder_model, text_encoder_model_inputs + + +def test_clip_text_with_projection_tosa_FP(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + ) + pipeline.change_args( + "check_count.exir", TestCLIPTextModelWithProjection.ops_after_partitioner_FP + ) + pipeline.run() + + +def test_clip_text_with_projection_tosa_INT(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.8, + ) + pipeline.change_args( + "check_count.exir", + TestCLIPTextModelWithProjection.ops_after_partitioner_INT, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_clip_text_with_projection_vgf_no_quant(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=4, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + quantize=False, + ) + pipeline.change_args( + "check_count.exir", + TestCLIPTextModelWithProjection.ops_after_partitioner_vgf_no_quantize, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_clip_text_with_projection_vgf_quant(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.8, + quantize=True, + ) + pipeline.change_args( + "check_count.exir", + TestCLIPTextModelWithProjection.ops_after_partitioner_vgf_quantize, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py new file mode 100644 index 0000000..aa736d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py @@ -0,0 +1,193 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from diffusers.models.transformers import ( # type: ignore[import-not-found] + SD3Transformer2DModel, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + SD3Transformer2DModel_init_dict, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t4 = Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor] + + +class TestSD3Transformer2DModel: + """ + Test class of AutoenSD3Transformer2DModelcoderKL. + SD3Transformer2DModel is the transformer model used by Stable Diffusion 3.5 Medium + """ + + # Adjust nbr below as we increase op support. + ops_after_partitioner_FP = { + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "torch.ops.higher_order.executorch_call_delegate": 1, + } + + ops_after_partitioner_INT = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 3, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + } + + ops_after_partitioner_vgf_quantize = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "torch.ops.higher_order.executorch_call_delegate": 1, + } + ops_after_partitioner_vgf_no_quantize = ops_after_partitioner_FP + + def _prepare_inputs( + self, + batch_size=2, + num_channels=4, + height=32, + width=32, + embedding_dim=32, + sequence_length=154, + max_timestep=1000, + ): + hidden_states = torch.randn( + ( + batch_size, + num_channels, + height, + width, + ) + ) + encoder_hidden_states = torch.randn( + ( + batch_size, + sequence_length, + embedding_dim, + ) + ) + pooled_prompt_embeds = torch.randn( + ( + batch_size, + embedding_dim * 2, + ) + ) + timestep = torch.randint(low=0, high=max_timestep, size=(batch_size,)) + + input_dict = { + "hidden_states": hidden_states, + "encoder_hidden_states": encoder_hidden_states, + "pooled_projections": pooled_prompt_embeds, + "timestep": timestep, + } + + return tuple(input_dict.values()) + + def prepare_model_and_inputs(self): + + class SD3Transformer2DModelWrapper(SD3Transformer2DModel): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs).sample + + init_dict = SD3Transformer2DModel_init_dict + + sd35_transformer2D_model = SD3Transformer2DModelWrapper(**init_dict) + sd35_transformer2D_model_inputs = self._prepare_inputs() + + return sd35_transformer2D_model, sd35_transformer2D_model_inputs + + +def test_sd3_transformer_tosa_FP(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + rtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT + atol=4.0, + ) + pipeline.change_args( + "check_count.exir", TestSD3Transformer2DModel.ops_after_partitioner_FP + ) + pipeline.run() + + +def test_sd3_transformer_tosa_INT(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + qtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT + rtol=1.0, + atol=4.0, + ) + pipeline.change_args( + "check_count.exir", TestSD3Transformer2DModel.ops_after_partitioner_INT + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sd3_transformer_vgf_no_quant(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + rtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT, + atol=4.0, + quantize=False, + ) + pipeline.change_args( + "check_count.exir", + TestSD3Transformer2DModel.ops_after_partitioner_vgf_no_quantize, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sd3_transformer_vgf_quant(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + qtol=1.0, + rtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT, + atol=4.0, + quantize=True, + ) + pipeline.change_args( + "check_count.exir", + TestSD3Transformer2DModel.ops_after_partitioner_vgf_quantize, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py new file mode 100644 index 0000000..ce6e5d5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py @@ -0,0 +1,161 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import ( + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, + InsertInt32CastsAfterInt64PlaceholdersPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + T5_encoder_config, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from transformers import T5EncoderModel + +input_t = Tuple[torch.Tensor] + + +class TestT5EncoderModel: + """ + Test class of T5EncoderModel. + T5EncoderModel is one of the text_encoder used by Stable Diffusion 3.5 Medium + """ + + # Adjust nbr below as we increase op support. + ops_after_partitioner_FP = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 2, + } + + ops_after_partitioner_INT = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 3, + "torch.ops.higher_order.executorch_call_delegate": 3, + } + + ops_after_partitioner_vgf_quantize = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "torch.ops.higher_order.executorch_call_delegate": 1, + } + + ops_after_partitioner_vgf_no_quantize = ops_after_partitioner_vgf_quantize + + def _prepare_inputs( + self, + batch_size=12, + seq_length=7, + vocab_size=1000, + ): + input_ids = torch.randint( + low=0, + high=vocab_size, + size=(batch_size, seq_length), + dtype=torch.long, + ) + return (input_ids,) + + def prepare_model_and_inputs(self): + t5_encoder_config = T5_encoder_config + + t5_encoder_model = T5EncoderModel(t5_encoder_config) + t5_encoder_model.eval() + t5_encoder_model_inputs = self._prepare_inputs() + + return t5_encoder_model, t5_encoder_model_inputs + + +def test_t5_encoder_tosa_FP(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_FP + ) + pipeline.run() + + +def test_t5_encoder_tosa_INT(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_INT + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_t5_encoder_vgf_no_quant(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + quantize=False, + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_vgf_no_quantize + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_t5_encoder_vgf_quant(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_vgf_quantize + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py new file mode 100644 index 0000000..d57cded --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from diffusers.models.autoencoders import ( # type: ignore[import-not-found] + AutoencoderKL, +) +from diffusers.utils.testing_utils import ( # type: ignore[import-not-found] + floats_tensor, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + AutoencoderKL_config, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + + +class TestAutoencoderKL: + """ + Test class of AutoencoderKL. + AutoencoderKL is the encoder/decoder used by Stable Diffusion 3.5 Medium + """ + + def _prepare_inputs(self, batch_size=4, num_channels=3, sizes=(32, 32)): + image = floats_tensor((batch_size, num_channels) + sizes) + return (image,) + + def prepare_model_and_inputs(self): + + class AutoencoderWrapper(AutoencoderKL): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs).sample + + vae_config = AutoencoderKL_config + + auto_encoder_model = AutoencoderWrapper(**vae_config) + + auto_encoder_model_inputs = self._prepare_inputs() + + return auto_encoder_model, auto_encoder_model_inputs + + +def test_vae_tosa_FP(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +def test_vae_tosa_INT(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.0, # TODO: MLETORCH-990 Reduce tolerance of vae(AutoencoderKL) with INT + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_vae_vgf_no_quant(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_vae_vgf_quant(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.0, # TODO: MLETORCH-990 Reduce tolerance of vae(AutoencoderKL) with INT + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_conformer.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_conformer.py new file mode 100644 index 0000000..e04d8bd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_conformer.py @@ -0,0 +1,138 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchaudio.models import Conformer # type: ignore[import-untyped] + +input_t = Tuple[torch.Tensor, torch.IntTensor] # Input x, y + + +def get_test_inputs(dim, lengths, num_examples): + return (torch.rand(num_examples, int(lengths.max()), dim), lengths) + + +class TestConformer: + """Tests Torchaudio Conformer""" + + # Adjust nbr below as we increase op support. Note: most of the delegates + # calls are directly consecutive to each other in the .pte. The reason + # for that is some assert ops are removed by passes in the + # .to_executorch step, i.e. after Arm partitioner. + aten_ops = ["torch.ops.aten._assert_scalar.default"] + + # TODO(MLETORCH-635): reduce tolerance + atol = 0.4 + rtol = 0.4 + + dim = 16 + num_examples = 10 + lengths = torch.randint(1, 100, (num_examples,), dtype=torch.int32) + model_example_inputs = get_test_inputs(dim, lengths, num_examples) + conformer = Conformer( + input_dim=dim, + num_heads=4, + ffn_dim=64, + num_layers=2, + depthwise_conv_kernel_size=31, + ) + conformer = conformer.eval() + + +def test_conformer_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=TestConformer.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +def test_conformer_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@pytest.mark.xfail( + reason="TODO(MLETORCH-635): Expected failure under FVP option, but test passed." +) +def test_conformer_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_conformer_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_conformer_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_conformer_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=TestConformer.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_deit_tiny_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_deit_tiny_arm.py new file mode 100644 index 0000000..c53ab4f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_deit_tiny_arm.py @@ -0,0 +1,120 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import timm # type: ignore[import-untyped] + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from timm.data import ( # type: ignore[import-untyped] + IMAGENET_INCEPTION_MEAN, + IMAGENET_INCEPTION_STD, +) +from torchvision import transforms # type: ignore[import-untyped] + +deit_tiny = timm.models.deit.deit_tiny_patch16_224(pretrained=True) + +deit_tiny.eval() + +normalize = transforms.Normalize( + mean=IMAGENET_INCEPTION_MEAN, std=IMAGENET_INCEPTION_STD +) +model_inputs = (normalize(torch.rand((1, 3, 224, 224))),) + +input_t = Tuple[torch.Tensor] + + +def test_deit_tiny_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +def test_deit_tiny_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + ) + pipeline.run() + + +def test_deit_tiny_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + deit_tiny, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + ) + # Multiple partitions + pipeline.pop_stage("check_count.exir") + # Don't run inference as model is too large for Corstone-300 + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_deit_tiny_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + deit_tiny, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_deit_tiny_vgf_quant(): + pipeline = VgfPipeline[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_deit_tiny_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_dl3_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_dl3_arm.py new file mode 100644 index 0000000..8e10001 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_dl3_arm.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from executorch.examples.models import deeplab_v3 + +input_t = Tuple[torch.Tensor] # Input x + + +class TestDl3: + """Tests DeepLabv3.""" + + dl3 = deeplab_v3.DeepLabV3ResNet50Model() + model_example_inputs = dl3.get_example_inputs() + dl3 = dl3.get_eager_model() + + +def test_dl3_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +def test_dl3_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.XfailIfNoCorstone300 +@pytest.mark.skip(reason="upsample_bilinear2d operator is not supported on U55") +def test_dl3_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_ops=[], + exir_ops=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.XfailIfNoCorstone320 +@pytest.mark.skip(reason="Runs out of memory on U85") +def test_dl3_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_ops=[], + exir_ops=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_dl3_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=0.1, atol=0.1 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_dl3_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_inception_v3_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_inception_v3_arm.py new file mode 100644 index 0000000..174d2c1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_inception_v3_arm.py @@ -0,0 +1,120 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchvision import models, transforms # type: ignore[import-untyped] + +ic3 = models.inception_v3(weights=models.Inception_V3_Weights) +ic3 = ic3.eval() + +# Normalization values referenced from here: +# https://docs.pytorch.org/vision/main/models/generated/torchvision.models.quantization.inception_v3.html +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +model_inputs = (normalize(torch.rand(1, 3, 224, 224)),) +input_t = Tuple[torch.Tensor] + + +@pytest.mark.slow +def test_ic3_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow +def test_ic3_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.65, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.XfailIfNoCorstone300 +def test_ic3_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + ic3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.6, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.XfailIfNoCorstone320 +def test_ic3_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + ic3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.6, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.SkipIfNoModelConverter +def test_ic3_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.SkipIfNoModelConverter +def test_ic3_vgf_quant(): + pipeline = VgfPipeline[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_llama.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_llama.py new file mode 100644 index 0000000..ec0e34d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_llama.py @@ -0,0 +1,227 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import os +import sys + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm._passes import InsertInt32CastsAfterInt64PlaceholdersPass +from executorch.backends.arm.quantizer import get_symmetric_quantization_config + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.examples.models.llama.export_llama_lib import ( + build_args_parser, + get_llama_model, +) + +from executorch.extension.llm.export.config.llm_config import LlmConfig + +input_t = Tuple[torch.Tensor] + +# Add project dir to sys path to workaround importlib.import_module() conditions in model_factory.py +this_files_dir = os.path.dirname(os.path.abspath(__file__)) +project_dir = os.path.abspath(os.path.join(this_files_dir, "../../../..")) +sys.path.append(project_dir) + +logger = logging.getLogger(__name__) + + +class TestLlama: + """ + Test class of Llama models. Type of Llama model depends on command line parameters: + --llama_inputs + Example: --llama_inputs stories110M/stories110M.pt stories110M/params.json stories110m + For more examples and info see examples/models/llama/README.md. + """ + + def prepare_model(self): + checkpoint = None + params_file = None + usage = "To run use --llama_inputs <.pt/.pth> <.json> " + + if conftest.is_option_enabled("llama_inputs"): + param_list = conftest.get_option("llama_inputs") + + if not isinstance(param_list, list) or len(param_list) != 3: + raise RuntimeError( + f"Invalid number of inputs for --llama_inputs. {usage}" + ) + if not all(isinstance(param, str) for param in param_list): + raise RuntimeError( + f"All --llama_inputs are expected to be strings. {usage}" + ) + + checkpoint = param_list[0] + params_file = param_list[1] + model_name = param_list[2] + else: + logger.warning( + "Skipping Llama tests because of missing --llama_inputs. {usage}" + ) + return None, None, None + + assert os.path.isfile(checkpoint) and os.path.isfile( + params_file + ), "Invalid file paths" + + logger.info("Running test_llama.py") + + # TODO: Enable key value cache + args = [ + "--disable_dynamic_shape", + "-c", + checkpoint, + "-p", + params_file, + "--model", + model_name, + ] + parser = build_args_parser() + args = parser.parse_args(args) + llm_config = LlmConfig.from_args(args) + + llama_model, llama_inputs, llama_meta = get_llama_model(llm_config) + + return llama_model, llama_inputs, llama_meta + + +def _use_partial_quantizer(pipeline): + """Set the pipeline's quantizer to only include Linear layers""" + pipeline.quantizer.set_global(None) + pipeline.quantizer.set_module_type( + torch.nn.Linear, get_symmetric_quantization_config() + ) + + +def test_llama_tosa_FP(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + custom_path="llama_tosa_fb", + run_on_tosa_ref_model=False, # Just want to write TOSA FB to disk + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + ) + pipeline.add_stage_after("to_executorch", pipeline.tester.serialize) + pipeline.run() + + +def test_llama_tosa_INT(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + custom_path="llama_tosa_fb_int", + run_on_tosa_ref_model=False, # Just want to write TOSA FB to disk + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("to_executorch", pipeline.tester.serialize) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_llama_vgf_no_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_llama_vgf_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +def test_llama_tosa_INT_FP_partial_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + tosa_extensions=["FP"], + ) + _use_partial_quantizer(pipeline) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_llama_partial_quant_vgf_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + quantize=True, + ) + _use_partial_quantizer(pipeline) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_lstm_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_lstm_arm.py new file mode 100644 index 0000000..d83618a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_lstm_arm.py @@ -0,0 +1,194 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torch.nn.quantizable.modules import rnn + +input_t = Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] # (h0, c0) + + +def get_test_inputs(): + return ( + torch.randn(5, 3, 10), # input + (torch.randn(2, 3, 20), torch.randn(2, 3, 20)), # (h0, c0) + ) + + +class TestLSTM: + """Tests quantizable LSTM module.""" + + """ + Currently only the quantizable LSTM module has been verified with the arm backend. + There may be plans to update this to use torch.nn.LSTM. + TODO: MLETORCH-622 + """ + lstm = rnn.LSTM(10, 20, 2) + lstm = lstm.eval() + + # Used e.g. for quantization calibration and shape extraction in the tester + model_example_inputs = get_test_inputs() + + +def test_lstm_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", inputs=get_test_inputs(), atol=3e-1 + ) + pipeline.run() + + +def test_lstm_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", + inputs=get_test_inputs(), + atol=3e-1, + qtol=1.0, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +def test_lstm_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", + inputs=get_test_inputs(), + atol=3e-1, + qtol=1.0, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_lstm_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", + inputs=get_test_inputs(), + atol=3e-1, + qtol=1.0, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_lstm_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_lstm_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +def test_lstm_tosa_INT_16a8w(): + """Test LSTM model with 16A8W quantization (16-bit activations, 8-bit weights)""" + + pipeline = TosaPipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + per_channel_quantization=False, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=False, epsilon=2**-16) + ) + pipeline.run() + + +@pytest.mark.xfail( + reason="MLETORCH-1452: AssertionError: Output 0 does not match reference output." +) +@common.XfailIfNoCorstone300 +def test_lstm_u55_INT_16a8w(): + pipeline = EthosU55PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=False, epsilon=2**-16) + ) + + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_lstm_u85_INT_16a8w(): + pipeline = EthosU85PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=False, epsilon=2**-16) + ) + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v2_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v2_arm.py new file mode 100644 index 0000000..a0a758a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v2_arm.py @@ -0,0 +1,179 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.quantizer import get_symmetric_quantization_config +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchvision import models, transforms # type: ignore[import-untyped] +from torchvision.models.mobilenetv2 import ( # type: ignore[import-untyped] + MobileNet_V2_Weights, +) + + +mv2 = models.mobilenetv2.mobilenet_v2(weights=MobileNet_V2_Weights.DEFAULT) +mv2 = mv2.eval() +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +model_inputs = (normalize(torch.rand((1, 3, 224, 224))),) +input_t = Tuple[torch.Tensor] + + +quant_test_data = { + "per_channel_quantization=true": True, + "per_channel_quantization=false": False, +} + + +def _use_partial_quantizer(pipeline): + """Set the pipeline's quantizer to only include Conv2d and ReLU6""" + quant_cfg = get_symmetric_quantization_config() + pipeline.quantizer.set_global(None) + pipeline.quantizer.set_module_type(torch.nn.Conv2d, quant_cfg) + pipeline.quantizer.set_module_type(torch.nn.ReLU6, quant_cfg) + + +def test_mv2_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + mv2, model_inputs, aten_op=[], exir_op=[], use_to_edge_transform_and_lower=True + ) + pipeline.run() + + +def test_mv2_tosa_FP_channels_last(): + input_tensor = model_inputs[0].to(memory_format=torch.channels_last) + pipeline = TosaPipelineFP[input_t]( + mv2, + (input_tensor,), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + # Changing memory format leads to an unsupported as_strided_copy op being inserted into the graph, + # leading to a graph break. + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.run() + + +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_tosa_INT(per_channel_quantization): + pipeline = TosaPipelineINT[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_u55_INT(per_channel_quantization): + pipeline = EthosU55PipelineINT[input_t]( + mv2, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_u85_INT(per_channel_quantization): + pipeline = EthosU85PipelineINT[input_t]( + mv2, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_vgf_quant(per_channel_quantization): + pipeline = VgfPipeline[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_mv2_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +def test_mv2_tosa_INT_FP_partial_quant(): + pipeline = TosaPipelineINT[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + tosa_extensions=["FP"], + use_to_edge_transform_and_lower=True, + atol=0.20, + ) + _use_partial_quantizer(pipeline) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_mv2_partial_quant_vgf_quant(): + pipeline = VgfPipeline[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + quantize=True, + atol=0.10, + ) + _use_partial_quantizer(pipeline) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v3_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v3_arm.py new file mode 100644 index 0000000..d17fc48 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_mobilenet_v3_arm.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchvision import models, transforms # type: ignore[import-untyped] + +mv3 = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights) +mv3 = mv3.eval() + +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +input_tensor = torch.rand(1, 3, 232, 232) + +model_inputs = (normalize(input_tensor),) +input_t = Tuple[torch.Tensor] + + +@pytest.mark.slow +def test_mv3_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + mv3, model_inputs, aten_op=[], exir_op=[], use_to_edge_transform_and_lower=True + ) + pipeline.run() + + +@pytest.mark.slow +def test_mv3_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + mv3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +def test_mv3_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + mv3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +def test_mv3_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + mv3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@pytest.mark.slow +def test_mv3_vgf_quant(): + pipeline = VgfPipeline[input_t]( + mv3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_mv3_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + mv3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_functional.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_functional.py new file mode 100644 index 0000000..7892534 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_functional.py @@ -0,0 +1,124 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +""" +Tests 10 popular torch.nn.functional not tested in other ways or training related +- normalize +- grid_sample +- one_hot +- softplus +- cosine_similarity +- unfold +- elu +- fold +- affine_grid +- max_pool1d +- threshold +""" +from typing import Callable + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +def module_factory(function: Callable) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def forward(self, *args): + return function(*args) + + return ModuleWrapper() + + +example_input = torch.rand(1, 6, 16, 16) + +module_tests = { + "normalize": (module_factory(torch.nn.functional.normalize), (example_input,)), + "grid_sample": ( + module_factory(torch.nn.functional.grid_sample), + (torch.rand(1, 1, 4, 4), torch.rand(1, 5, 5, 2)), + ), + "one_hot": ( + module_factory(torch.nn.functional.one_hot), + (torch.randint(0, 5, (2, 2, 5, 5)), 5), + ), + "softplus": (module_factory(torch.nn.functional.softplus), (example_input,)), + "cosine_similarity": ( + module_factory(torch.nn.functional.cosine_similarity), + (example_input, example_input), + ), + "unfold": ( + module_factory(torch.nn.functional.unfold), + (torch.randn(1, 3, 10, 12), (4, 5)), + ), + "elu": (module_factory(torch.nn.functional.elu), (example_input,)), + "fold": ( + module_factory(torch.nn.functional.fold), + (torch.randn(1, 12, 12), (4, 5), (2, 2)), + ), + "affine_grid": ( + module_factory(torch.nn.functional.affine_grid), + (torch.rand(1, 2, 3), (1, 2, 10, 10)), + ), + "max_pool1d": ( + module_factory(torch.nn.functional.max_pool1d), + (torch.randn(20, 16, 50), 4), + ), + "threshold": ( + module_factory(torch.nn.functional.threshold), + (example_input, 0.5, 0.1), + ), +} + +input_t = tuple[torch.Tensor] + + +@parametrize( + "test_data", + module_tests, +) +def test_nn_functional_tosa_FP(test_data): + module, inputs = test_data + pipeline = TosaPipelineFP[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=False + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e + + +@parametrize( + "test_data", + module_tests, +) +def test_nn_functional_tosa_INT(test_data): + module, inputs = test_data + pipeline = TosaPipelineINT[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + if pipeline.has_stage("check_not.quant_nodes"): + pipeline.pop_stage("check_not.quant_nodes") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_modules.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_modules.py new file mode 100644 index 0000000..c798e99 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nn_modules.py @@ -0,0 +1,161 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +""" +Tests 10 popular nn modules not tested in other ways or training related. +- Embedding +- LeakyReLU +- BatchNorm1d +- AdaptiveAvgPool2d +- ConvTranspose2d +- GRU +- GroupNorm +- InstanceNorm2d +- PReLU +- Transformer +""" + +from typing import Callable + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +def make_module_wrapper( + name: str, module_factory: Callable[[], torch.nn.Module] +) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def __init__(self): + super().__init__() + self._module = module_factory() + + def forward(self, *args, **kwargs): + return self._module(*args, **kwargs) + + ModuleWrapper.__name__ = name + ModuleWrapper.__qualname__ = name + return ModuleWrapper() + + +example_input = torch.rand(1, 6, 16, 16) + +module_tests = [ + ( + make_module_wrapper( + "EmbeddingModule", + lambda: torch.nn.Embedding(10, 10), + ), + (torch.LongTensor([[1, 2, 4, 5], [4, 3, 2, 9]]),), + ), + ( + make_module_wrapper("LeakyReLUModule", torch.nn.LeakyReLU), + (example_input,), + ), + ( + make_module_wrapper("BatchNorm1dModule", lambda: torch.nn.BatchNorm1d(16)), + (torch.rand(6, 16, 16),), + ), + ( + make_module_wrapper( + "AdaptiveAvgPool2dModule", + lambda: torch.nn.AdaptiveAvgPool2d((12, 12)), + ), + (example_input,), + ), + ( + make_module_wrapper( + "ConvTranspose2dModule", lambda: torch.nn.ConvTranspose2d(6, 3, 2) + ), + (example_input,), + ), + ( + make_module_wrapper("GRUModule", lambda: torch.nn.GRU(10, 20, 2)), + (torch.randn(5, 3, 10), torch.randn(2, 3, 20)), + ), + ( + make_module_wrapper("GroupNormModule", lambda: torch.nn.GroupNorm(2, 6)), + (example_input,), + ), + ( + make_module_wrapper( + "InstanceNorm2dModule", lambda: torch.nn.InstanceNorm2d(16) + ), + (example_input,), + ), + ( + make_module_wrapper("PReLUModule", torch.nn.PReLU), + (example_input,), + ), + ( + make_module_wrapper( + "TransformerModule", + lambda: torch.nn.Transformer( + d_model=64, + nhead=1, + num_encoder_layers=1, + num_decoder_layers=1, + dtype=torch.float32, + ), + ), + (torch.rand((10, 32, 64)), torch.rand((20, 32, 64))), + ), +] + +input_t = tuple[torch.Tensor] + +test_parameters = {str(test[0].__class__.__name__): test for test in module_tests} + + +@parametrize( + "test_data", + test_parameters, +) +def test_nn_modules_tosa_FP(test_data): + module, inputs = test_data + pipeline = TosaPipelineFP[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e + + +@parametrize( + "test_data", + test_parameters, + xfails={ + "TransformerModule": "AssertionError: Output 0 does not match reference output.", + }, +) +def test_nn_modules_tosa_INT(test_data): + module, inputs = test_data + pipeline = TosaPipelineINT[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + if pipeline.has_stage("check_not.quant_nodes"): + pipeline.pop_stage("check_not.quant_nodes") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nss.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nss.py new file mode 100644 index 0000000..e5e381c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_nss.py @@ -0,0 +1,146 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from huggingface_hub import hf_hub_download + +from ng_model_gym.usecases.nss.model.model_blocks import ( # type: ignore[import-not-found,import-untyped] + AutoEncoderV1, +) + +input_t = Tuple[torch.Tensor] # Input x + + +class NSS(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.auto_encoder = AutoEncoderV1() + + +def nss() -> AutoEncoderV1: + """Get an instance of NSS with weights loaded.""" + + weights = hf_hub_download( + repo_id="Arm/neural-super-sampling", + filename="nss_v0.1.0_fp32.pt", + revision="2e9b606acd9fa25071825a12f0764f1c3bef9480", + ) + + nss_model = NSS() + nss_model.load_state_dict( + torch.load(weights, map_location=torch.device("cpu"), weights_only=True), + strict=False, + ) + return nss_model.auto_encoder + + +def example_inputs(): + return (torch.randn((1, 12, 544, 960)),) + + +def test_nss_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("export", pipeline.tester.dump_operator_distribution) + pipeline.run() + + +def test_nss_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.skip(reason="No support for aten_upsample_nearest2d_vec on U55") +@common.XfailIfNoCorstone300 +def test_nss_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + nss().eval(), + example_inputs(), + aten_ops=[], + exir_ops=[], + run_on_fvp=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="Fails at input memory allocation for input shape: [1, 12, 544, 960]" +) +@common.XfailIfNoCorstone320 +def test_nss_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + nss().eval(), + example_inputs(), + aten_ops=[], + exir_ops=[], + run_on_fvp=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.xfail( + reason="[MLETORCH-1430]: Double types are not supported in buffers in MSL" +) +@common.SkipIfNoModelConverter +def test_nss_vgf_FP(): + pipeline = VgfPipeline[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=False, + # Override tosa version to test FP-only path + tosa_version="TOSA-1.0+FP", + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_nss_vgf_INT(): + pipeline = VgfPipeline[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + symmetric_io_quantization=True, + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=True, + # Override tosa version to test INT-only path + tosa_version="TOSA-1.0+INT", + ) + pipeline.run() + + +ModelUnderTest = nss().eval() +ModelInputs = example_inputs() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_resnet18.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_resnet18.py new file mode 100644 index 0000000..8d795f3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_resnet18.py @@ -0,0 +1,98 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + +from torchvision import transforms # type: ignore[import-untyped] +from torchvision.models import ( # type: ignore[import-untyped] + resnet18, + ResNet18_Weights, +) + +model = resnet18(weights=ResNet18_Weights) +model = model.eval() +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +# Using torch.rand * 2 - 1 to generate numbers in the range [-1;1] like an RGB image +model_inputs = (normalize(torch.rand((1, 3, 224, 224)) * 2 - 1),) + +input_t = Tuple[torch.Tensor] + + +quant_test_data = { + "per_channel_quantization=true": True, + "per_channel_quantization=false": False, +} + + +def test_resnet_18_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("per_channel_quantization", quant_test_data) +def test_resnet_18_tosa_INT(per_channel_quantization): + pipeline = TosaPipelineINT[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_resnet_18_u55_INT(per_channel_quantization): + pipeline = EthosU55PipelineINT[input_t]( + model, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_resnet_18_u85_INT(per_channel_quantization): + pipeline = EthosU85PipelineINT[input_t]( + model, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_torch_functions.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_torch_functions.py new file mode 100644 index 0000000..5a6e4f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_torch_functions.py @@ -0,0 +1,151 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +""" +Tests 10 popular torch ops, not tested in other ways, training related or requring randomness. +- t +- zeros +- ones +- stack +- arange +- norm +- nonzero +- eye +- topk +- sort +""" + +from typing import Callable + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +def module_add_factory(function: Callable) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def forward(self, x, *args): + return x + function(*args).to(torch.float32) + + return ModuleWrapper() + + +def module_factory(function: Callable) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def forward(self, *args): + return function(*args) + + return ModuleWrapper() + + +example_input = torch.rand(1, 6, 16, 16) + +module_tests = [ + ( + "t", + module_add_factory(torch.t), + ( + torch.rand(10, 6), + torch.rand(6, 10), + ), + ), + ( + "zeros", + module_add_factory(torch.zeros), + ( + torch.rand(4, 3, 2), + (4, 1, 2), + ), + ), + ( + "ones", + module_add_factory(torch.ones), + ( + torch.rand(4, 3, 2), + (4, 1, 2), + ), + ), + ( + "stack", + module_add_factory(torch.stack), + ( + torch.rand(1, 1, 1, 1), + (torch.rand(2, 3, 3), torch.rand(2, 3, 3)), + -2, + ), + ), + ("arange", module_add_factory(torch.arange), (torch.rand(1), 0, 10, 2)), + ("norm", module_factory(torch.norm), (torch.randn(5, 5),)), + ("nonzero", module_factory(torch.nonzero), (example_input,)), + ("eye", module_add_factory(torch.eye), (torch.rand(4, 4), 4)), + ("topk", module_factory(torch.topk), (torch.rand(10), 5)), + ("sort", module_factory(torch.sort), (torch.rand(5),)), +] + +input_t = tuple[torch.Tensor] + +test_parameters = {test[0]: test[1:] for test in module_tests} + + +@parametrize( + "test_data", + test_parameters, + xfails={ + "nonzero": "torch.fx.experimental.symbolic_shapes.GuardOnDataDependentSymNode: Could not guard on data-dependent expression Eq(u4, 0). " + "Requires dynamic output shape.", + "topk": "NotImplementedError: No registered serialization name for found", + "sort": "NotImplementedError: No registered serialization name for found", + }, +) +def test_torch_functions_tosa_FP(test_data): + module, inputs = test_data + pipeline = TosaPipelineFP[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e + + +@parametrize( + "test_data", + test_parameters, + xfails={ + "nonzero": "torch.fx.experimental.symbolic_shapes.GuardOnDataDependentSymNode: Could not guard on data-dependent expression Eq(u4, 0). " + "Requires dynamic output shape.", + "topk": "NotImplementedError: No registered serialization name for found", + "sort": "NotImplementedError: No registered serialization name for found", + }, + strict=True, +) +def test_torch_functions_tosa_INT(test_data): + module, inputs = test_data + pipeline = TosaPipelineINT[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("check.quant_nodes") + pipeline.pop_stage("check_not.quant_nodes") + + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_w2l_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_w2l_arm.py new file mode 100644 index 0000000..91e7732 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/models/test_w2l_arm.py @@ -0,0 +1,136 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchaudio import models # type: ignore[import-untyped] + +input_t = Tuple[torch.Tensor] # Input x + + +def get_test_inputs(batch_size, num_features, input_frames): + return (torch.randn(batch_size, num_features, input_frames),) + + +class TestW2L(unittest.TestCase): + """Tests Wav2Letter.""" + + batch_size = 10 + input_frames = 400 + num_features = 1 + + model_example_inputs = get_test_inputs(batch_size, num_features, input_frames) + + all_operators = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten__log_softmax_default", + "executorch_exir_dialects_edge__ops_aten_relu_default", + ] + + @staticmethod + def create_model(input_type: str = "waveform"): + return models.Wav2Letter( + num_features=TestW2L.num_features, input_type=input_type + ).eval() + + +@pytest.mark.slow # about 3min on std laptop +def test_w2l_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow # about 1min on std laptop +@pytest.mark.flaky +def test_w2l_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@pytest.mark.xfail( + reason="Wav2Letter fails on U55 due to insufficient memory", + strict=True, +) +def test_w2l_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + # Use "power_spectrum" variant because the default ("waveform") has a + # conv1d layer with an unsupported stride size. + TestW2L.create_model("power_spectrum"), + TestW2L.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@pytest.mark.skip(reason="Intermittent timeout issue: MLETORCH-856") +def test_w2l_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@pytest.mark.slow +def test_w2l_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_w2l_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_abs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_abs.py new file mode 100644 index 0000000..9e8ad2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_abs.py @@ -0,0 +1,101 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.abs.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_abs_default" + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Abs(torch.nn.Module): + test_parameters = { + "zeros": lambda: (torch.zeros(5),), + "full": lambda: (torch.full((5,), -1, dtype=torch.float32),), + "ones": lambda: (torch.ones(5) * -1,), + "randn_1d": lambda: (torch.randn(8),), + "randn_3d": lambda: (torch.randn(2, 3, 4),), + "randn_4d": lambda: (torch.randn(1, 2, 3, 4),), + "torch_normal": lambda: (torch.normal(mean=0, std=10, size=(2, 3, 4)),), + } + + def forward(self, x): + return torch.abs(x) + + +@common.parametrize("test_data", Abs.test_parameters) +def test_abs_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1](Abs(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +def test_abs_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1](Abs(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.XfailIfNoCorstone300 +def test_abs_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.XfailIfNoCorstone320 +def test_abs_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.SkipIfNoModelConverter +def test_abs_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.SkipIfNoModelConverter +def test_abs_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acos.py new file mode 100644 index 0000000..be91bd7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acos.py @@ -0,0 +1,121 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] +aten_op = "torch.ops.aten.acos.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__acos_default" + + +test_data_suite = { + "ones": lambda: torch.ones(1, 7, 10, 12), + "rand_in_range": lambda: (torch.rand(10, 10) - 0.5) * 2, # Uniform in [-1, 1) + "ramp_valid": lambda: torch.linspace(-1.0, 1.0, steps=160), + "edge_cases": lambda: torch.tensor([-1.0, 0.0, 1.0]), + "1d_tensor": lambda: torch.linspace(-1.0, 1.0, steps=10), # Shape: [10] + "2d_batch": lambda: torch.tensor( + [[-1.0, -0.5, 0.0, 0.5, 1.0], [0.9, -0.9, 0.3, -0.3, 0.0]] + ), # Shape: [2, 5] + "3d_batch": lambda: torch.rand(4, 5, 6) * 2 - 1, # Shape: [4, 5, 6] in [-1, 1) + "3d_mixed_shape": lambda: (torch.rand(7, 15, 2) - 0.5) * 2, + "4d_mixed": lambda: torch.linspace(-1, 1, steps=1 * 3 * 4 * 5).reshape( + 1, 3, 4, 5 + ), # Shape: [2, 3, 4, 5] + "4d_random": lambda: (torch.rand(1, 5, 10, 7) - 0.5) * 2, + "bool_casted": lambda: torch.ones(3, 3, dtype=torch.bool).to( + dtype=torch.float32 + ), # All 1.0 (edge case) +} + + +class Acos(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.acos(x) + + +@common.parametrize("test_data", test_data_suite) +def test_acos_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Acos(), + (test_data(),), + aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_acos_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Acos(), + (test_data(),), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_acos_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acos(), + (test_data(),), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_acos_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Acos(), + (test_data(),), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acos_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acos(), + (test_data(),), + [], + [], + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acos_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acos(), + (test_data(),), + [], + [], + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acosh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acosh.py new file mode 100644 index 0000000..48490a9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_acosh.py @@ -0,0 +1,137 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x +aten_op = "torch.ops.aten.acosh.default" + + +test_data_suite = { + # Valid input cases + "ones": lambda: torch.ones(1, 7, 10, 12), + "just_above_one": lambda: torch.tensor([1.0001, 1.01, 1.1, 2.0]), + "rand_valid": lambda: torch.rand(10, 10) * 10 + 1, # [1, 11) + "ramp_valid": lambda: torch.linspace(1.0, 20.0, steps=160), + "large": lambda: torch.tensor([10.0, 100.0, 1000.0, 1e6]), + "mixed_valid": lambda: torch.tensor([1.0, 2.0, 10.0, 100.0]), +} + +test_data_suite_xfails = { + # Invalid input cases (should return nan or error) + "zeros": lambda: torch.zeros(1, 5, 3, 2), + "neg_ones": lambda: -torch.ones(10, 10, 10), + "rand_invalid": lambda: torch.rand(10, 10), # [0, 1) + "ramp_invalid": lambda: torch.linspace(-10.0, 0.99, steps=160), + "near_zero": lambda: torch.tensor([-1e-6, 0.0, 1e-6]), + "large_negative": lambda: torch.tensor([-100.0, -10.0, 0.0]), +} + + +class Acosh(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.acosh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_acosh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Acosh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_acosh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_acosh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_xfails) +@pytest.mark.xfail(reason="Invalid inputs are currently not handled") +def test_acosh_u55_INT_xfail(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_acosh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_xfails) +@pytest.mark.xfail(reason="Invalid inputs are currently not handled") +def test_acosh_u85_INT_xfail(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acosh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acosh(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acosh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acosh(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_adaptive_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_adaptive_avg_pool2d.py new file mode 100644 index 0000000..6197c37 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_adaptive_avg_pool2d.py @@ -0,0 +1,242 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +exir_op = "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default" + +input_t = Tuple[torch.Tensor] + + +class AdaptiveAvgPool2d(torch.nn.AdaptiveAvgPool2d): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs) + + +test_modules = { + "output_bigger_than_input_1_to_3": lambda: ( + AdaptiveAvgPool2d((3, 3)), + (torch.rand(1, 3, 1, 1),), + ), + "output_bigger_than_input_7_to_10": lambda: ( + AdaptiveAvgPool2d((10, 10)), + (torch.rand(1, 3, 7, 7),), + ), + "output_1x1": lambda: (AdaptiveAvgPool2d((1, 1)), (torch.rand(1, 4, 8, 8),)), + "output_2x2": lambda: (AdaptiveAvgPool2d((2, 2)), (torch.rand(1, 4, 10, 10),)), + "output_4x4": lambda: (AdaptiveAvgPool2d((4, 4)), (torch.rand(1, 5, 15, 15),)), + "output_2x3": lambda: (AdaptiveAvgPool2d((2, 3)), (torch.rand(1, 3, 9, 13),)), + "output_h_keep": lambda: ( + AdaptiveAvgPool2d((2, None)), + (torch.rand(1, 3, 10, 16),), + ), + "output_w_keep": lambda: ( + AdaptiveAvgPool2d((None, 4)), + (torch.rand(1, 3, 14, 20),), + ), + "output_5x5": lambda: (AdaptiveAvgPool2d((5, 5)), (torch.rand(1, 3, 25, 25),)), + "output_3x5": lambda: (AdaptiveAvgPool2d((3, 5)), (torch.rand(1, 3, 15, 20),)), + "output_7x1": lambda: (AdaptiveAvgPool2d((7, 1)), (torch.rand(1, 3, 21, 3),)), + "output_1x7": lambda: (AdaptiveAvgPool2d((1, 7)), (torch.rand(1, 3, 3, 21),)), + "output_3xNone": lambda: (AdaptiveAvgPool2d((3, None)), (torch.rand(1, 3, 9, 24),)), + "output_Nonex3": lambda: (AdaptiveAvgPool2d((None, 3)), (torch.rand(1, 3, 24, 9),)), + "pool_h_static_w_none": lambda: ( + AdaptiveAvgPool2d((3, None)), + (torch.rand(1, 3, 9, 17),), + ), + "pool_h_none_w_static": lambda: ( + AdaptiveAvgPool2d((None, 5)), + (torch.rand(1, 3, 15, 25),), + ), + "identity_pool": lambda: ( + AdaptiveAvgPool2d((10, 10)), + (torch.rand(1, 3, 10, 10),), + ), + "non_divisible_5x5_from_17x17": lambda: ( + AdaptiveAvgPool2d((5, 5)), + (torch.rand(1, 3, 17, 17),), + ), + "pool_height_only": lambda: ( + AdaptiveAvgPool2d((1, 6)), + (torch.rand(1, 3, 12, 6),), + ), + "pool_width_only": lambda: ( + AdaptiveAvgPool2d((6, 1)), + (torch.rand(1, 3, 6, 12),), + ), + "extreme_input_large": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 3, 128, 128),), + ), + "single_channel_input": lambda: ( + AdaptiveAvgPool2d((4, 4)), + (torch.rand(1, 1, 16, 16),), + ), + "high_channel_count": lambda: ( + AdaptiveAvgPool2d((2, 2)), + (torch.rand(1, 1024, 32, 32),), + ), + # Common input/output sizes found in models + "output_7x7_from_14x14": lambda: ( + AdaptiveAvgPool2d((7, 7)), + (torch.rand(1, 512, 14, 14),), + ), + "output_1x1_from_8x8": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 2048, 8, 8),), + ), + "output_1x1_from_19": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 2560, 19, 19),), + ), + "output_1x1_from_7x7": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 1280, 7, 7),), + ), +} + + +@common.parametrize("test_module", test_modules) +def test_adaptive_avg_pool2d_tosa_FP(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineFP[input_t]( + model, + input_tensor, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_adaptive_avg_pool2d_tosa_INT(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_adaptive_avg_pool2d_tosa_INT_a16w8(test_module): + """Test adaptive_avg_pool2d with int16 I/O quantization for TOSA INT.""" + model, input_tensor = test_module() + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op=[], + exir_op=exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_adaptive_avg_pool2d_u55_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +# Remove high_channel_count & output_1x1_from_19 due to 2MB SRAM access on U55 +u55_test_modules = test_modules +for key in ["high_channel_count", "output_1x1_from_19"]: + u55_test_modules.pop(key) + + +@common.parametrize("test_module", u55_test_modules) +@common.XfailIfNoCorstone300 +def test_adaptive_avg_pool2d_u55_INT_a16w8(test_module): + """Test adaptive_avg_pool2d with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + a16w8_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_adaptive_avg_pool2d_u85_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_adaptive_avg_pool2d_u85_INT_a16w8(test_module): + """Test adaptive_avg_pool2d with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + a16w8_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_no_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + [], + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + [], + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_add.py new file mode 100644 index 0000000..31c31c3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_add.py @@ -0,0 +1,291 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer import arm_quantizer +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from torchao.quantization.pt2e import HistogramObserver +from torchao.quantization.pt2e.quantizer import QuantizationSpec + +aten_op = "torch.ops.aten.add.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_add_Tensor" + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Add(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x + x + + test_data: list[input_t1] = { + "5d_float": lambda: (torch.FloatTensor([1, 2, 3, 5, 7]),), + "1d_ones": lambda: ((3 * torch.ones(8),)), + "1d_randn": lambda: (10 * torch.randn(8),), + "4d_ones_1": lambda: (torch.ones(1, 1, 4, 4),), + "4d_ones_2": lambda: (torch.ones(1, 3, 4, 2),), + } + + +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class Add2(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x + y + + test_data: list[input_t2] = { + "5d_float": lambda: ( + torch.FloatTensor([1, 2, 3, 5, 7]), + (torch.FloatTensor([2, 1, 2, 1, 10])), + ), + "4d_ones": lambda: (torch.ones(1, 10, 4, 6), torch.ones(1, 10, 4, 6)), + "4d_randn_1": lambda: (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "4d_randn_2": lambda: (torch.randn(1, 3, 4, 4), torch.randn(1, 3, 4, 4)), + "4d_randn_big": lambda: ( + (1 << 30) * torch.randn(1, 1, 4, 4), + torch.randn(1, 1, 4, 1), + ), + "4d_randn_1_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.ones(1, 1, 4, 4), + ), + "4d_big_small": lambda: ( + (10e10) * torch.randn(1, 10, 20, 30), + torch.randn(1, 10, 20, 30), + ), + } + + +class Add3(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return torch.add(x, y, alpha=1.5) + + test_data: list[input_t2] = { + "3d_randn_diff_rank": lambda: (torch.randn(1, 4, 5), torch.randn(4, 1)), + "4d_randn_diff_rank": lambda: (torch.randn(1, 1, 4, 4), torch.randn(4, 1)), + "4d_randn_diff_rank_2": lambda: (torch.randn(4, 1), torch.randn(1, 1, 4, 5)), + } + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Add(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Add(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_INT_i32(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Add(), test_data(), aten_op, exir_op) + + pipeline.quantizer.set_io(arm_quantizer.get_symmetric_quantization_config()) + observer_options = {"eps": 2**-16} + observer = HistogramObserver.with_args(**observer_options) + input_act_qspec = QuantizationSpec( + torch.int32, + observer, + qscheme=torch.per_tensor_symmetric, + quant_max=2**31 - 1, + quant_min=-(2**31), + ) + output_act_qspec = QuantizationSpec( + torch.int32, + observer, + qscheme=torch.per_tensor_symmetric, + quant_max=2**31 - 1, + quant_min=-(2**31), + ) + quantization_config = arm_quantizer.QuantizationConfig( + input_act_qspec, output_act_qspec, None, None + ) + pipeline.quantizer.set_global(quantization_config) + + # Check that we get the additional (dq -> q + pipeline.add_stage_after( + "export", pipeline.tester.check_count, {"torch.ops.quantized_decomposed": 8} + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone300 +def test_add_tensor_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone320 +def test_add_tensor_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +def test_add_tensor_tosa_FP_2(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2](Add2(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Add3.test_data) +def test_add_tensor_tosa_FP_3(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2](Add3(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Add3.test_data) +def test_add_tensor_tosa_INT_3(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2](Add3(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +def test_add_tensor_tosa_INT_2(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2](Add2(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +@common.XfailIfNoCorstone300 +def test_add_tensor_u55_INT_2(test_data: input_t2): + pipeline = EthosU55PipelineINT[input_t2]( + Add2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +@common.XfailIfNoCorstone320 +def test_add_tensor_u85_INT_2(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Add2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.SkipIfNoModelConverter +def test_add_tensor_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.SkipIfNoModelConverter +def test_add_tensor_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_INT_16a8w(test_data: input_t1): + """Test add operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone300 +def test_add_tensor_u55_INT_16a8w(test_data: input_t1): + """Test add operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone320 +def test_add_tensor_u85_INT_16a8w(test_data: input_t1): + """Test add operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_addmm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_addmm.py new file mode 100644 index 0000000..e951ced --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_addmm.py @@ -0,0 +1,285 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.addmm.default" + +exir_op = "executorch_exir_dialects_edge__ops_aten__addmm_default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor, torch.Tensor] # Input x1, x2, x3 + + +test_data_suite = { + "basic": [ + torch.tensor([[1.0, 2.0], [3.0, 4.0]]), + torch.tensor([[1.0, 0.0], [0.0, 1.0]]), + torch.tensor([[1.0, 2.0], [3.0, 4.0]]), + 1.0, + 1.0, + ], + "zeros": [torch.zeros(2, 2), torch.zeros(2, 3), torch.zeros(3, 2), 1.0, 1.0], + "beta_only": [ + torch.tensor([[10.0, 20.0], [30.0, 40.0]]), + torch.randn(2, 3), + torch.randn(3, 2), + 0.0, + 1.0, + ], + "alpha_only": [ + torch.tensor([[10.0, 20.0], [30.0, 40.0]]), + torch.randn(2, 3), + torch.randn(3, 2), + 1.0, + 0.0, + ], + "scaled": [ + torch.ones(2, 2), + torch.tensor([[1.0, 2.0], [3.0, 4.0]]), + torch.tensor([[5.0, 6.0], [7.0, 8.0]]), + 0.5, + 2.0, + ], + "negative_scalars": [ + torch.tensor([[1.0, -1.0], [-1.0, 1.0]]), + torch.tensor([[2.0, 0.0], [0.0, 2.0]]), + torch.tensor([[1.0, 1.0], [1.0, 1.0]]), + -1.0, + -1.0, + ], + "non_square": [torch.ones(3, 4), torch.rand(3, 2), torch.rand(2, 4), 1.0, 1.0], + "large_values": [ + torch.full((2, 2), 1e6), + torch.full((2, 3), 1e3), + torch.full((3, 2), 1e3), + 1.0, + 1.0, + ], + "small_values": [ + torch.full((2, 2), 1e-6), + torch.full((2, 3), 1e-3), + torch.full((3, 2), 1e-3), + 1.0, + 1.0, + ], + "random": [torch.randn(4, 5), torch.randn(4, 3), torch.randn(3, 5), 1.0, 1.0], + "broadcast_bias_row": [ + torch.randn(1, 2), + torch.randn(3, 4), + torch.randn(4, 2), + 1.0, + 1.0, + ], + "row_bias": [ + torch.randn(3, 1), + torch.randn(3, 4), + torch.randn(4, 4), + 1.0, + 1.0, + ], + "scalar_bias": [ + torch.tensor(2.0), + torch.randn(5, 3), + torch.randn(3, 6), + 1.0, + 1.0, + ], +} + + +class Addmm(torch.nn.Module): + def forward( + self, + x1: torch.Tensor, + x2: torch.Tensor, + x3: torch.Tensor, + alpha: float, + beta: float, + ) -> torch.Tensor: + return torch.addmm(x1, x2, x3, alpha=alpha, beta=beta) + + +@common.parametrize("test_data", test_data_suite) +def test_addmm_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Addmm(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_addmm_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_addmm_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_addmm_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_addmm_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Addmm(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_addmm_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Addmm(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_addmm_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_addmm_16a8w_tosa_INT(test_data: input_t1): + """Test addmm (FC layer) operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_op=[], + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_addmm_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +@pytest.mark.xfail( + reason="Vela compilation fails with 'Invalid arguments' for int16 addmm operations" +) +def test_addmm_16a8w_u55_INT(test_data: input_t1): + """Test addmm (FC layer) operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_addmm_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_addmm_16a8w_u85_INT(test_data: input_t1): + """Test addmm (FC layer) operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_addmm_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_alias_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_alias_copy.py new file mode 100644 index 0000000..29c6893 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_alias_copy.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class AliasCopy(torch.nn.Module): + """ + Tests proper handling of alias_copy when used directly. + + alias_copy can also appear from PyTorch/ExecuTorch optimizations + such as `x.transpose(0, 0)`. This is optimized to an alias_copy but + not before dq/q operators are added. + """ + + aten_op = "torch.ops.aten.alias_copy.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_alias_copy_default" + + test_data: dict[input_t1] = { + "1d_ramp": lambda: (torch.arange(-16, 16, 0.2),), + "2d_ones": lambda: (torch.ones(5, 5),), + "3d_rand": lambda: (torch.rand(3, 5, 5),), + "4d_zeros": lambda: (torch.zeros(1, 10, 10, 10),), + } + + def __init__(self): + super().__init__() + + def forward(self, x: torch.Tensor): + return ( + torch.alias_copy(x) * 1 + ) # Multiply by one to make sure it is partitioned. + + +@common.parametrize("test_data", AliasCopy.test_data) +def test_alias_tosa_FP(test_data: input_t1): + TosaPipelineFP[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +def test_alias_tosa_INT(test_data: input_t1): + TosaPipelineINT[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.XfailIfNoCorstone300 +def test_alias_u55_INT(test_data: input_t1): + EthosU55PipelineINT[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.XfailIfNoCorstone320 +def test_alias_u85_INT(test_data: input_t1): + EthosU85PipelineINT[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.SkipIfNoModelConverter +def test_alias_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.SkipIfNoModelConverter +def test_alias_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amax.py new file mode 100644 index 0000000..7109def --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amax.py @@ -0,0 +1,191 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Amax(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int | Tuple[int], bool] + aten_op = ["torch.ops.aten.amax"] + + def __init__(self, dim, keep_dims): + self.dim = dim + self.keep_dims = keep_dims + super().__init__() + + def forward(self, x): + return torch.amax(x, self.dim, self.keep_dims) + + test_data: Dict[str, input_t] = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0, False), + "rank_2_dim_1_keep_dims": lambda: ((torch.rand([2, 2]),), (1,), True), + "rank_4_all_dim": lambda: ((torch.rand([1, 2, 5, 5]),), (0, 1, 2, 3), False), + "rank_4_0,3_keep_dims": lambda: ((torch.rand([1, 2, 2, 2]),), (0, 3), True), + "rank_4_mult_batches": lambda: ((torch.rand([2, 2, 2, 2]),), (0), True), + } + + +class Max(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int] + aten_op = ["torch.ops.aten.amax"] + + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x = torch.max(x, self.dim, False) + return x[0] + + test_data: Dict[str, input_t] = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0), + "rank_2_dim_1": lambda: ((torch.rand([2, 2]),), 1), + "rank_4_dim_2": lambda: ((torch.rand([2, 2, 2, 2]),), 2), + "rank_4_dim_3": lambda: ((torch.rand([2, 2, 2, 2]),), 3), + } + + +class MaxWithIndex(torch.nn.Module): + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x, i = torch.max(x, self.dim) + return x, i + + +@common.parametrize("test_data", Amax.test_data) +def test_amax_tosa_FP(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineFP[Amax.input_t](Amax(dim, keep_dims), data, Amax.aten_op) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +def test_amax_tosa_INT(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineINT[Amax.input_t](Amax(dim, keep_dims), data, Amax.aten_op) + pipeline.run() + + +def test_amax_u55_INT_not_delegated(): + data, dim, keep_dims = Amax.test_data["rank_4_all_dim"]() + pipeline = OpNotSupportedPipeline[Amax.input_t]( + Amax(dim, keep_dims), + data, + {" executorch_exir_dialects_edge__ops_aten_amax_default": 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +@common.XfailIfNoCorstone320 +def test_amax_u85_INT(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + pipeline = EthosU85PipelineINT[Amax.input_t]( + Amax(dim, keep_dims), + data, + Amax.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +def test_max_dim_tosa_FP_to_amax(test_data: Max.input_t): + data, dim = test_data() + pipeline = TosaPipelineFP[Max.input_t](Max(dim), data, "torch.ops.aten.max") + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +def test_max_dim_tosa_INT_to_amax(test_data: Max.input_t): + data, dim = test_data() + module = Max(dim) + pipeline = TosaPipelineINT[Max.input_t](module, data, "torch.ops.aten.amax") + pipeline.run() + + +@pytest.mark.xfail(reason="MLETORCH-718 : Quantization of indices in arm_quantizer") +def test_max_dim_tosa_INT_not_delegated(): + data, dim = Max.test_data()["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Max.input_t]( + MaxWithIndex(dim), data, {}, quantize=True + ) + pipeline.run() + + +def test_max_dim_tosa_FP_not_delegated(): + data, dim = Max.test_data["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Max.input_t](MaxWithIndex(dim), data, {}) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +@common.SkipIfNoModelConverter +def test_amax_vgf_no_quant(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + module = Amax(dim, keep_dims) + pipeline = VgfPipeline[Amax.input_t]( + module, + data, + Amax.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +@common.SkipIfNoModelConverter +def test_amax_vgf_quant(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + module = Amax(dim, keep_dims) + pipeline = VgfPipeline[Amax.input_t]( + module, + data, + Amax.aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +@common.SkipIfNoModelConverter +def test_max_dim_vgf_no_quant_to_amax(test_data: Max.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Max.input_t]( + Max(dim), + data, + "torch.ops.aten.max", + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +@common.SkipIfNoModelConverter +def test_max_dim_vgf_quant_to_amax(test_data: Max.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Max.input_t]( + Max(dim), + data, + "torch.ops.aten.amax", + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amin.py new file mode 100644 index 0000000..c90980f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_amin.py @@ -0,0 +1,205 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Amin(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int | Tuple[int], bool] + aten_op = ["torch.ops.aten.amin"] + + def __init__(self, dim, keep_dims): + self.dim = dim + self.keep_dims = keep_dims + super().__init__() + + def forward(self, x): + if self.dim is None: + return torch.amin(x, keepdim=self.keep_dims) + else: + return torch.amin(x, self.dim, self.keep_dims) + + test_data: Dict = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0, False), + "rank_2_dim_1_keep_dims": lambda: ((torch.rand([2, 2]),), (1,), True), + "rank_4_all_dim": lambda: ((torch.rand([1, 2, 5, 5]),), (0, 1, 2, 3), False), + "rank_4_no_dim": lambda: ((torch.rand([1, 2, 5, 5]),), None, False), + "rank_4_0,3_keep_dims": lambda: ((torch.rand([1, 2, 2, 2]),), (0, 3), True), + "rank_4_mult_batches": lambda: ((torch.rand([2, 2, 2, 2]),), (0), True), + } + + +class Min(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int] + aten_op = ["torch.ops.aten.amin"] + + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x = torch.min(x, self.dim) + return x[0] + + test_data: Dict = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0), + "rank_2_dim_1": lambda: ((torch.rand([2, 2]),), 1), + "rank_4_dim_2": lambda: ((torch.rand([2, 2, 2, 2]),), 2), + "rank_4_dim_3": lambda: ((torch.rand([2, 2, 2, 2]),), 3), + } + + +class MinWithIndex(torch.nn.Module): + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x, i = torch.min(x, self.dim) + return x, i + + +@common.parametrize("test_data", Amin.test_data) +def test_amin_tosa_FP(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineFP[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +def test_amin_tosa_INT(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineINT[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + ) + pipeline.run() + + +def test_amin_u55_INT_not_delegated(): + data, dim, keep_dims = Amin.test_data["rank_4_all_dim"]() + pipeline = OpNotSupportedPipeline[Amin.input_t]( + Amin(dim, keep_dims), + data, + {" executorch_exir_dialects_edge__ops_aten_amin_default": 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +@common.XfailIfNoCorstone320 +def test_amin_u85_INT(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = EthosU85PipelineINT[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +def test_min_dim_tosa_FP_to_amin(test_data: Min.input_t): + data, dim = test_data() + pipeline = TosaPipelineFP[Min.input_t](Min(dim), data, "torch.ops.aten.min") + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +def test_min_dim_tosa_INT_to_amin(test_data: Min.input_t): + data, dim = test_data() + module = Min(dim) + pipeline = TosaPipelineINT[Min.input_t](module, data, "torch.ops.aten.amin") + pipeline.run() + + +@pytest.mark.xfail(reason="MLETORCH-718 : Quantization of indices in arm_quantizer") +def test_min_dim_tosa_INT_not_delegated(): + data, dim = Min.test_data["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Min.input_t]( + MinWithIndex(dim), + data, + {}, + quantize=True, + ) + pipeline.run() + + +def test_min_dim_tosa_FP_not_delegated(): + data, dim = Min.test_data["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Min.input_t](MinWithIndex(dim), data, {}) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +@common.SkipIfNoModelConverter +def test_amin_vgf_no_quant(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = VgfPipeline[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +@common.SkipIfNoModelConverter +def test_amin_vgf_quant(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = VgfPipeline[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +@common.SkipIfNoModelConverter +def test_min_dim_vgf_no_quant_to_amin(test_data: Min.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Min.input_t]( + Min(dim), + data, + "torch.ops.aten.min", + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +@common.SkipIfNoModelConverter +def test_min_dim_vgf_quant_to_amin(test_data: Min.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Min.input_t]( + Min(dim), + data, + "torch.ops.aten.amin", + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_any.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_any.py new file mode 100644 index 0000000..3cc3432 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_any.py @@ -0,0 +1,210 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class AnyDim(torch.nn.Module): + aten_op = "torch.ops.aten.any.dim" + exir_op = "executorch_exir_dialects_edge__ops_aten_any_dim" + + def forward(self, x: torch.Tensor, dim: int, keepdim: bool): + return torch.any(x, dim=dim, keepdim=keepdim) + + +class AnyDims(torch.nn.Module): + aten_op = "torch.ops.aten.any.dims" + exir_op = "executorch_exir_dialects_edge__ops_aten_any_dims" + + def forward(self, x: torch.Tensor, dim: List[int], keepdim: bool): + return torch.any(x, dim=dim, keepdim=keepdim) + + +class AnyReduceAll(torch.nn.Module): + aten_op = "torch.ops.aten.any.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_any_default" + + def forward(self, x: torch.Tensor): + return torch.any(x) + + +input_t1 = Tuple[torch.Tensor] # Input x + + +test_input: dict[input_t1] = { + "rank1": lambda: (torch.tensor([True, False, False], dtype=torch.bool), 0, True), + "rank1_squeeze": lambda: ( + torch.tensor([True, False, False], dtype=torch.bool), + -1, + False, + ), + "rank2": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + 0, + True, + ), + "rank2_squeeze": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + 0, + False, + ), + "rank2_dims": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + [0, 1], + True, + ), + "rank2_dims_squeeze": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + [-2, 1], + False, + ), + "rank3_dims_squeeze": lambda: ( + torch.randint(0, 2, (6, 8, 10), dtype=torch.bool), + [1, 2], + False, + ), + "rank4": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + 1, + True, + ), + "rank4_squeeze": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + 1, + False, + ), + "rank4_dims": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + [0, 2], + True, + ), + "rank4_dims_squeeze": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + [1, -1], + False, + ), + "rank1_reduce_all": lambda: (torch.tensor([True, False, False], dtype=torch.bool),), + "rank2_reduce_all": lambda: (torch.randint(0, 2, (2, 3), dtype=torch.bool),), + "rank3_reduce_all": lambda: (torch.randint(0, 2, (6, 8, 10), dtype=torch.bool),), + "rank4_reduce_all": lambda: (torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool),), +} + + +test_data = { + "any_rank1": lambda: (AnyDim(), test_input["rank1"]), + "any_rank1_squeeze": lambda: (AnyDim(), test_input["rank1_squeeze"]), + "any_rank2": lambda: (AnyDim(), test_input["rank2"]), + "any_rank2_squeeze": lambda: (AnyDim(), test_input["rank2_squeeze"]), + "any_rank2_dims": lambda: (AnyDims(), test_input["rank2_dims"]), + "any_rank2_dims_squeeze": lambda: (AnyDims(), test_input["rank2_dims_squeeze"]), + "any_rank3_dims_squeeze": lambda: (AnyDims(), test_input["rank3_dims_squeeze"]), + "any_rank4": lambda: (AnyDim(), test_input["rank4"]), + "any_rank4_squeeze": lambda: (AnyDim(), test_input["rank4_squeeze"]), + "any_rank4_dims": lambda: (AnyDims(), test_input["rank4_dims"]), + "any_rank4_dims_squeeze": lambda: (AnyDims(), test_input["rank4_dims_squeeze"]), + "any_rank1_reduce_all": lambda: (AnyReduceAll(), test_input["rank1_reduce_all"]), + "any_rank2_reduce_all": lambda: (AnyReduceAll(), test_input["rank2_reduce_all"]), + "any_rank3_reduce_all": lambda: (AnyReduceAll(), test_input["rank3_reduce_all"]), + "any_rank4_reduce_all": lambda: (AnyReduceAll(), test_input["rank4_reduce_all"]), +} + + +@common.parametrize("test_data", test_data) +def test_any_tosa_FP(test_data: input_t1): + op, test_input = test_data() + pipeline = TosaPipelineFP[input_t1]( + op, + test_input(), + op.aten_op, + op.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_any_tosa_INT(test_data: input_t1): + op, test_input = test_data() + pipeline = TosaPipelineINT[input_t1]( + op, + test_input(), + op.aten_op, + op.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_any_u55_INT(test_data: input_t1): + # Tests that we don't delegate these ops since they are not supported on U55. + op, test_input = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + op, + test_input(), + {op.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone320 +def test_any_u85_INT(test_data: input_t1): + op, test_input = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + op, + test_input(), + op.aten_op, + op.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_any_vgf_no_quant(test_data: input_t1): + op, data_fn = test_data() + pipeline = VgfPipeline[input_t1]( + op, + data_fn(), + op.aten_op, + op.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_any_vgf_quant(test_data: input_t1): + op, data_fn = test_data() + pipeline = VgfPipeline[input_t1]( + op, + data_fn(), + op.aten_op, + op.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_arange.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_arange.py new file mode 100644 index 0000000..90ab437 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_arange.py @@ -0,0 +1,258 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[Callable[[], input_t], tuple[float, float, float, torch.dtype]] + + +class ArangeAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.arange.start_step" + exir_op: str = "executorch_exir_dialects_edge__ops_aten_arange_start_step" + + def __init__(self, start: float, stop: float, step: float, dtype: torch.dtype): + super().__init__() + self.args = (start, stop, step) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.arange(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10": (lambda: (torch.randn(10, 1),), (0.0, 10.0, 1.0, torch.float32)), + "15": (lambda: (torch.randn(10),), (0.0, 15.0, 1.5, torch.float32)), + "100": (lambda: (torch.randn(10, 1),), (0.0, 10.0, 0.1, torch.float32)), + } + + test_data_dtypes: dict[str, test_data_t] = { + "fp32_int32": (lambda: (torch.randn(10),), (0.0, 10.0, 1.0, torch.int32)), + "fp32_int64": (lambda: (torch.randn(10),), (0.0, 10.0, 1.0, torch.int64)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (0.0, 10.0, 1.0, torch.int32), + ), + } + test_reject: dict[str, test_data_t] = { + "int32_int64": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (0.0, 10.0, 1.0, torch.int64), + ), + } + + +@common.parametrize("test_data", ArangeAdd.test_data) +def test_arange_start_step_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ArangeAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data_dtypes) +def test_arange_start_step_tosa_FP_dtypes(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ArangeAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_reject) +def test_arange_start_step_tosa_FP_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + ArangeAdd(*init_data), input_data(), non_delegated_ops={ArangeAdd.exir_op: 1} + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +def test_arange_start_step_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ArangeAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.XfailIfNoCorstone300 +def test_arange_start_step_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.XfailIfNoCorstone320 +def test_arange_start_step_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.SkipIfNoModelConverter +def test_arange_start_step_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + module = ArangeAdd(*init_data) + pipeline = VgfPipeline[input_t]( + module, + input_data(), + module.aten_op, + module.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.SkipIfNoModelConverter +def test_arange_start_step_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + module = ArangeAdd(*init_data) + pipeline = VgfPipeline[input_t]( + module, + input_data(), + module.aten_op, + module.exir_op, + quantize=True, + ) + pipeline.run() + + +class LinspaceAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.linspace.default" + exir_op: str = "executorch_exir_dialects_edge__ops_aten_arange_default" + + def __init__(self, start: float, stop: float, step: int, dtype: torch.dtype): + super().__init__() + self.args = (start, stop, step) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.linspace(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10": (lambda: (torch.randn(10, 1),), (0.0, 10.0, 100, torch.float32)), + "15": (lambda: (torch.randn(20),), (0.0, 15.0, 20, torch.float32)), + } + + +@common.parametrize("test_data", LinspaceAdd.test_data) +def test_linspace_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LinspaceAdd.test_data) +def test_linspace_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LinspaceAdd.test_data) +@common.SkipIfNoModelConverter +def test_linspace_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LinspaceAdd.test_data) +@common.SkipIfNoModelConverter +def test_linspace_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + quantize=True, + ) + pipeline.run() + + +skip_str = "aten.arange.default is decomposed to aten.arange.start_step, so it will never exist in a lowered graph." + + +@pytest.mark.skip(reason=skip_str) +def test_arange_tosa_FP(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_tosa_INT(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_u55_INT(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_u85_INT(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_vgf_no_quant(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_vgf_quant(): + pass diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asin.py new file mode 100644 index 0000000..e00e636 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asin.py @@ -0,0 +1,105 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x +aten_op = "torch.ops.aten.asin.default" + +test_data_suite = { + "zeros": lambda: torch.zeros(1, 5, 3, 2), # valid: asin(0) = 0 + "ones": lambda: torch.ones(10, 5, 15), # edge case: asin(1) = pi/2 + "neg_ones": lambda: -torch.ones(10, 5, 15), # edge case: asin(-1) = -pi/2 + "rand": lambda: (torch.rand(10, 10, 5) * 2) - 1, # uniform random in [-1, 1] + "ramp": lambda: torch.linspace(-1.0, 1.0, steps=160), # full domain coverage + "near_bounds": lambda: torch.tensor( + [-0.999, -0.9, -0.5, 0.0, 0.5, 0.9, 0.999] + ), # precision edge values + "pos_rand": lambda: torch.rand(7, 10, 2), # positive random values in [0, 1] +} + + +class Asin(torch.nn.Module): + def forward(self, x): + return torch.asin(x) + + +@common.parametrize("test_data", test_data_suite) +def test_asin_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Asin(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_asin_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Asin(), + (test_data(),), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_asin_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Asin(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_asin_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Asin(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asin_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asin(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asin_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asin(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asinh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asinh.py new file mode 100644 index 0000000..db902a3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_asinh.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x +aten_op = "torch.ops.aten.asinh.default" + +test_data_suite = { + "zeros": lambda: torch.zeros(1, 5, 3, 2), + "ones": lambda: torch.ones(10, 10, 10), + "neg_ones": lambda: -torch.ones(10, 10, 10), + "rand": lambda: (torch.rand(10, 10) - 0.5) * 20, + "ramp": lambda: torch.linspace(-10.0, 10.0, steps=160), + "near_zero": lambda: torch.tensor([-1e-6, 0.0, 1e-6]), + "large": lambda: torch.tensor([-100.0, -10.0, 0.0, 10.0, 100.0]), + "rand_4d": lambda: torch.randn(1, 3, 4, 5), +} + + +class Asinh(torch.nn.Module): + def forward(self, x): + return torch.asinh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_asinh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Asinh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_asinh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Asinh(), + (test_data(),), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_asinh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Asinh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_asinh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Asinh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asinh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asinh(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asinh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asinh(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_at.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_at.py new file mode 100644 index 0000000..8caa242 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_at.py @@ -0,0 +1,256 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op_mm = "torch.ops.aten.matmul.default" +exir_op_mm = "executorch_exir_dialects_edge__ops_aten_matmul_default" +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class AtMatMulSingleInput(torch.nn.Module): + test_data_generators = { + "rand_3d": lambda: (torch.rand(2, 5, 5),), + "rand_4d": lambda: (torch.rand(1, 2, 5, 5),), + } + + def forward(self, x: torch.Tensor): + return x @ x + + +class AtMatMulDoubleInput(torch.nn.Module): + test_data_generators = { + "rand_rand_3d": lambda: (torch.rand(2, 3, 5), torch.rand(2, 5, 2)), + "rand_rand_4d": lambda: (torch.rand(1, 2, 3, 5), torch.rand(1, 2, 5, 2)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x @ y + + +class AtMatMulMixedPattern1(torch.nn.Module): + test_data_generators = { + "rand_rand_rand_3d": lambda: ( + torch.rand(2, 5, 5), + torch.rand(2, 5, 2), + torch.rand(2, 2, 5), + ), + "rand_rand_rand_4d": lambda: ( + torch.rand(1, 2, 5, 5), + torch.rand(1, 2, 5, 2), + torch.rand(1, 2, 2, 5), + ), + } + + def forward(self, x1: torch.Tensor, x2: torch.Tensor, x3: torch.Tensor): + y1 = torch.matmul(x1, x1) + y2 = torch.matmul(x2, x3) + return y1 + y2 + + +class AtMatMulMixedPattern2(torch.nn.Module): + test_data_generators = { + "rand_rand_rand_3d": lambda: ( + torch.rand(2, 5, 5), + torch.rand(2, 5, 2), + torch.rand(2, 2, 5), + ), + "rand_rand_rand_4d": lambda: ( + torch.rand(1, 2, 5, 5), + torch.rand(1, 2, 5, 2), + torch.rand(1, 2, 2, 5), + ), + } + + def forward(self, x1: torch.Tensor, x2: torch.Tensor, x3: torch.Tensor): + y1 = torch.matmul(x1, x1) + y2 = torch.matmul(x2, x3) + return y1 @ y2 + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +def test_matmul_tosa_FP_at_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulSingleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +def test_matmul_tosa_FP_at_double_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulDoubleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +def test_matmul_tosa_FP_at_mixed_pattern1(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulMixedPattern1(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +def test_matmul_tosa_FP_at_mixed_pattern2(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulMixedPattern2(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +def test_matmul_tosa_INT_at_single_input(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulSingleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +def test_matmul_tosa_INT_at_double_input(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulDoubleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +def test_matmul_tosa_INT_at_mixed_pattern1(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulMixedPattern1(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +def test_matmul_tosa_INT_at_mixed_pattern2(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulMixedPattern2(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_double_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulDoubleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_mixed_pattern1(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern1(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_mixed_pattern2(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern2(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_double_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulDoubleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_mixed_pattern1(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern1(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_mixed_pattern2(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern2(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atan.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atan.py new file mode 100644 index 0000000..4e103dc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atan.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.atan.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__atan_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10), + "zeros_alt_shape": torch.zeros(1, 10, 3, 5), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(1, 10, 3, 5) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Atan(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.atan(x) + + +@common.parametrize("test_data", test_data_suite) +def test_atan_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Atan(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_atan_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Atan(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_atan_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Atan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_atan_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Atan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atan_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Atan(), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atan_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Atan(), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atanh.py new file mode 100644 index 0000000..8ac2708 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_atanh.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.atanh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__atanh_default" + + +input_t1 = Tuple[torch.Tensor] + + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10), + "zeros_alt_shape": torch.zeros(1, 10, 3, 5), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(1, 10, 3, 5) - 0.5, + "ramp": torch.arange(-1, 1, 0.2), + "near_bounds": torch.tensor([-0.999999, -0.999, -0.9, 0.9, 0.999, 0.999999]), + "on_bounds": torch.tensor([-1.0, 1.0]), +} + + +class Atanh(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.atanh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_atanh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_atanh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_atanh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Atanh(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_atanh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Atanh(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atanh_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atanh_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_avg_pool2d.py new file mode 100644 index 0000000..8885d19 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_avg_pool2d.py @@ -0,0 +1,295 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import conftest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "avg_pool2d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default" + +input_t = Tuple[torch.Tensor] + + +class AvgPool2d(torch.nn.modules.AvgPool2d): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs) + + +class BecomesMeanInToEdge(torch.nn.Module): + """This averagepool will be converted to mean when lowering to edge. This causes the decompose_meandim pass to not + trigger until the backend pipeline, which requires extra care. + """ + + def forward(self, x: torch.Tensor): + return torch.nn.functional.adaptive_avg_pool2d(x, (1, 1)) + + +test_modules = { + "zeros": lambda: (AvgPool2d(4, 2, 0, False), (torch.zeros(1, 16, 50, 32),)), + "ones": lambda: (AvgPool2d(4, 2, 0, False, True), (torch.ones(1, 16, 50, 32),)), + "rand": lambda: (AvgPool2d(4, 2, 0, False, True, 16), (torch.rand(1, 16, 50, 32),)), + "randn": lambda: ( + AvgPool2d(4, 2, 0, divisor_override=16), + (torch.randn(1, 16, 50, 32),), + ), + "kernel_3x3_stride_1_pad_1": lambda: ( + AvgPool2d((3, 3), (1, 1), 1), + (torch.rand(1, 16, 50, 32),), + ), + "kernel_3x2_stride_1x2_pad_1x0": lambda: ( + AvgPool2d((3, 2), (1, 2), (1, 0)), + (torch.rand(1, 16, 50, 32),), + ), + "kernel_4x6_stride_1x2_pad_2x3": lambda: ( + AvgPool2d((4, 6), (1, 2), (2, 3)), + (torch.rand(1, 16, 50, 32),), + ), + "non_divisible_window_adjust_padding": lambda: ( + AvgPool2d(3, 2, 1, count_include_pad=False), + (torch.rand(1, 16, 112, 112),), + ), + "non_divisible_window_adjust_padding_height": lambda: ( + AvgPool2d(3, (2, 1), 1), + (torch.rand(1, 16, 56, 56),), + ), + "non_divisible_window_adjust_padding_width": lambda: ( + AvgPool2d(3, (1, 2), 1, count_include_pad=False), + (torch.rand(1, 16, 56, 56),), + ), + "non_divisible_window_ceil_mode": lambda: ( + AvgPool2d(3, 2, 1, True), + (torch.rand(1, 16, 112, 112),), + ), + "non_divisible_window_height_ceil_mode": lambda: ( + AvgPool2d(3, (2, 1), 1, True, False), + (torch.rand(1, 1, 14, 14),), + ), + "non_divisible_window_width_ceil_mode": lambda: ( + AvgPool2d(3, (1, 2), 1, True, True), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override": lambda: ( + AvgPool2d(3, 2, 1, False, False, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override_count_include_pad": lambda: ( + AvgPool2d(3, 2, 1, False, True, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override_ceil_mode": lambda: ( + AvgPool2d(3, 2, 1, True, False, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override_ceil_mode_count_include_pad": lambda: ( + AvgPool2d(3, 2, 1, True, True, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "non_divisible_no_padding": lambda: ( + AvgPool2d(3, 2, 0), + (torch.rand(1, 16, 56, 56),), + ), + "non_divibile_window_adjust_padding+input": lambda: ( + AvgPool2d(3, 3, 1, count_include_pad=False), + (torch.rand(1, 16, 54, 54),), + ), + "non_divibile_window_height_adjust_padding+input": lambda: ( + AvgPool2d(3, (3, 1), 1), + (torch.rand(1, 16, 54, 54),), + ), + "non_divibile_window_width_adjust_padding+input": lambda: ( + AvgPool2d(3, (1, 3), 1, count_include_pad=False), + (torch.rand(1, 16, 54, 54),), + ), + "becomes_mean_rank3": lambda: (BecomesMeanInToEdge(), (torch.rand(2, 8, 8),)), + "becomes_mean_rank4": lambda: (BecomesMeanInToEdge(), (torch.rand(2, 2, 8, 8),)), + "becomes_mean_rank5": lambda: (BecomesMeanInToEdge(), (torch.rand(2, 2, 8, 8),)), +} + + +@common.parametrize("test_module", test_modules) +def test_avg_pool2d_tosa_FP(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineFP[input_t]( + model, + input_tensor, + aten_op, + exir_op, + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_avg_pool2d_tosa_INT(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_avg_pool2d_tosa_INT_a16w8(test_module): + """Test avg_pool2d operation with int16 I/O quantization for TOSA INT.""" + model, input_tensor = test_module() + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + tosa_extensions=["int16"], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_avg_pool2d_u55_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_avg_pool2d_16a8w_u55_INT(test_module): + """Test avg_pool2d with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_avg_pool2d_u85_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_avg_pool2d_16a8w_u85_INT(test_module): + """Test avg_pool2d with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_avg_pool2d_vgf_no_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_avg_pool2d_vgf_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +reject_modules = { + "kernel_1x1_stride_1_pad_0": lambda: (AvgPool2d(1, 1, 0), torch.rand(2, 5, 5, 5)), + "kernel_2x9_stride_1_pad_1": lambda: ( + AvgPool2d((2, 9), 1, 1, count_include_pad=False), + torch.rand(1, 16, 5, 32), + ), + "kernel_1x4_stride_0_pad_0": lambda: ( + AvgPool2d(1, 4, 0, count_include_pad=False), + torch.rand(1, 10, 10, 10), + ), + "kernel_1x257_stride_1_pad_0_large": lambda: ( + AvgPool2d((1, 257), 1, 0, count_include_pad=False), + torch.rand(1, 16, 5, 300), + ), + "kernel_800x90_stride_1_pad_0_extreme": lambda: ( + AvgPool2d((800, 90), 1, 0, count_include_pad=False), + torch.rand(1, 16, 850, 100), + ), +} + + +@common.parametrize("reject_module", reject_modules) +def test_avg_pool2d_u55_INT_not_delegated(reject_module): + + model, test_data = reject_module() + + pipeline = OpNotSupportedPipeline[input_t]( + module=model, + test_data=(test_data,), + non_delegated_ops={}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_batch_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_batch_norm.py new file mode 100644 index 0000000..7c91588 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_batch_norm.py @@ -0,0 +1,385 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +test_data_suite = { + # (test_name, test_data, [num_features, affine, weight, bias] ) + "ones_1_32_112_112": lambda: (torch.rand(1, 32, 112, 112), [32, False, None, None]), + "rand_1_4_5_6": lambda: (torch.rand(1, 4, 5, 6), [4, False, None, torch.rand(4)]), + "rand_1_3_254_254": lambda: ( + torch.rand(1, 3, 254, 254), + [3, False, torch.rand(3), torch.rand(3)], + ), + "rand_1_32_112_112_affine": lambda: ( + torch.rand(1, 32, 112, 112), + [32, True, None, None], + ), + "ones_1_4_5_6_affine": lambda: ( + torch.rand(1, 4, 5, 6), + [4, True, torch.rand(4), torch.rand(4)], + ), + "rand_1_3_254_254_affine": lambda: ( + torch.rand(1, 3, 254, 254), + [3, True, torch.rand(3), None], + ), +} + + +class BatchNorm2d(torch.nn.Module): + aten_op = "torch.ops.aten.batch_norm.default" + + def __init__( + self, + num_features: int, + affine: bool, + weights: torch.tensor, + bias: torch.tensor, + ): + super().__init__() + self.batch_norm_2d = torch.nn.BatchNorm2d( + num_features, affine=affine, track_running_stats=True + ) + + # Optional + if weights is not None: + self.batch_norm_2d.weight = torch.nn.Parameter(weights) + if bias is not None: + self.batch_norm_2d.bias = torch.nn.Parameter(bias) + + # These will be 1 if not set since no training is done, randomize for more realistic values + self.batch_norm_2d.running_var = torch.rand(num_features) + self.batch_norm_2d.running_mean = torch.rand(num_features) * 2 - 1 + + def forward(self, x): + return self.batch_norm_2d(x) + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_training_tosa_FP(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + aten_op=BatchNorm2d.aten_op, + ) + pipeline.run() + + +# TODO(MLETORCH-100: Quantized stand-alone batch norms) +def test_native_batch_norm_legit_no_training_tosa_INT_not_delegated(): + test_data, model_params = test_data_suite["rand_1_3_254_254"]() + OpNotSupportedPipeline[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 1 + }, + quantize=True, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_no_quant(test_data: Tuple): + inp, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2d(*model_params), + (inp,), + aten_op=BatchNorm2d.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_quant(test_data: Tuple): + # TODO(MLETORCH-100: Quantized stand-alone batch norms) + pass + + +# TODO(MLETORCH-100: Quantized stand-alone batch norms) +def test_native_batch_norm_legit_no_training_u55_INT_not_delegated(): + test_data, model_params = test_data_suite["rand_1_3_254_254"]() + OpNotSupportedPipeline[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 1 + }, + quantize=True, + u55_subset=True, + ).run() + + +# TODO(MLETORCH-100: Quantized stand-alone batch norms) +def test_native_batch_norm_legit_no_training_u85_INT_not_delegated(): + test_data, model_params = test_data_suite["rand_1_3_254_254"]() + OpNotSupportedPipeline[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 1 + }, + quantize=True, + ).run() + + +class BatchNorm2dConv(torch.nn.Module): + aten_ops = ["torch.ops.aten.conv2d.default", "torch.ops.aten.batch_norm.default"] + + def __init__( + self, + num_features: int, + affine: bool, + weights: torch.tensor, + bias: torch.tensor, + ): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=num_features, + out_channels=num_features, + kernel_size=3, + stride=1, + groups=1, + ) + + self.batch_norm_2d = torch.nn.BatchNorm2d( + num_features, affine=affine, track_running_stats=True + ) + + # Optional + if weights is not None: + self.batch_norm_2d.weight = torch.nn.Parameter(weights) + if bias is not None: + self.batch_norm_2d.bias = torch.nn.Parameter(bias) + + # These will be 1 if not set since no training is done, randomize for more realistic values + self.batch_norm_2d.running_var = torch.rand(num_features) + self.batch_norm_2d.running_mean = torch.rand(num_features) * 2 - 1 + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x): + x = self.conv2d(x) + x = self.batch_norm_2d(x) + return x + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_training_tosa_FP_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_training_tosa_INT_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops[0], # Bn is removed before check + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_batch_norm_legit_no_training_u55_INT_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_ops=BatchNorm2dConv.aten_ops[0], # Bn is removed before check + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_batch_norm_legit_no_training_u85_INT_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_ops=BatchNorm2dConv.aten_ops[0], # Bn is removed before check + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_no_quant_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_quant_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops[0], + qtol=1, + quantize=True, + ) + pipeline.run() + + +class BatchNorm2dNoStats(torch.nn.Module): + """ + Decomposes into _native_batch_norm_legit.no_stats + """ + + aten_ops = ["torch.ops.aten.batch_norm.default"] + + def __init__( + self, + num_features: int, + affine: bool, + weights: torch.tensor, + bias: torch.tensor, + ): + super().__init__() + self.batch_norm_2d = torch.nn.BatchNorm2d( + num_features, affine=affine, track_running_stats=False + ) + + # Optional + if weights is not None: + self.batch_norm_2d.weight = torch.nn.Parameter(weights) + if bias is not None: + self.batch_norm_2d.bias = torch.nn.Parameter(bias) + + # These will be 1 if not set since no training is done, randomize for more realistic values + self.batch_norm_2d.running_var = torch.rand(num_features) + self.batch_norm_2d.running_mean = torch.rand(num_features) * 2 - 1 + + def forward(self, x): + return self.batch_norm_2d(x) + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_stats_tosa_FP(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +def test_native_batch_norm_legit_no_stats_tosa_INT(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_batch_norm_legit_no_stats_u55_INT(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_batch_norm_legit_no_stats_u85_INT(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_stats_vgf_no_quant(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + quantize=False, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_stats_vgf_quant(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise.py new file mode 100644 index 0000000..1565fe6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise.py @@ -0,0 +1,672 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from copy import copy +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineINT, + VgfPipeline, +) + +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class BitwiseBinary(torch.nn.Module): + test_data: dict[input_t2] = { + "zeros": lambda: ( + torch.zeros(1, 10, 10, 10, dtype=torch.int32), + torch.zeros(1, 10, 10, 10, dtype=torch.int32), + ), + "ones": lambda: ( + torch.ones(10, 10, 10, dtype=torch.int8), + torch.ones(10, 10, 10, dtype=torch.int8), + ), + "pattern_int8": lambda: ( + 0xAA * torch.ones(1, 2, 2, 2, dtype=torch.int8), + 0xCC * torch.ones(1, 2, 2, 2, dtype=torch.int8), + ), + "pattern_int16": lambda: ( + 0xAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int16), + 0xCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int16), + ), + "pattern_int32": lambda: ( + 0xAAAAAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int32), + 0xCCCCCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int32), + ), + "pattern_bool": lambda: ( + torch.tensor([True, False, True], dtype=torch.bool), + torch.tensor([True, True, False], dtype=torch.bool), + ), + "rand_rank2": lambda: ( + torch.randint(-128, 127, (10, 10), dtype=torch.int8), + torch.randint(-128, 127, (10, 10), dtype=torch.int8), + ), + "rand_rank4": lambda: ( + torch.randint(-128, -127, (1, 10, 10, 10), dtype=torch.int8), + torch.randint(-128, 127, (1, 10, 10, 10), dtype=torch.int8), + ), + } + + test_data_u85 = copy(test_data) + del test_data_u85["zeros"] + + +class BitwiseBinaryScalar(torch.nn.Module): + test_data = { + "zeros": lambda: (torch.zeros(1, 10, 10, 10, dtype=torch.int32), 0), + "ones_int8": lambda: (torch.ones(10, 10, 10, dtype=torch.int8), 1), + "pattern_int8": lambda: (0xAA * torch.ones(1, 2, 2, 2, dtype=torch.int8), 0x77), + "pattern_int16": lambda: ( + 0xAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int16), + 0x7777, + ), + "pattern_int32": lambda: ( + 0xAAAAAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int32), + 0x77777777, + ), + "rand_rank2": lambda: (torch.randint(-128, 127, (10, 10), dtype=torch.int8), 5), + "rand_rank4": lambda: ( + torch.randint(-128, 127, (1, 10, 10, 10), dtype=torch.int8), + -7, + ), + } + + test_data_u85 = copy(test_data) + del test_data_u85["zeros"] + + +class And(BitwiseBinary): + aten_op = "torch.ops.aten.bitwise_and.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.bitwise_and(tensor2) + + +class Xor(BitwiseBinary): + aten_op = "torch.ops.aten.bitwise_xor.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_xor_Tensor" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.bitwise_xor(tensor2) + + +class Or(BitwiseBinary): + aten_op = "torch.ops.aten.bitwise_or.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_or_Tensor" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.bitwise_or(tensor2) + + +class AndScalar(BitwiseBinaryScalar): + # Tensor because it gets converted from Scalar -> Tensor in lowering + aten_op = "torch.ops.aten.bitwise_and.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_bitwise_and_Scalar" + + def forward(self, tensor: torch.Tensor, scalar: int): + return tensor.bitwise_and(scalar) + + +class XorScalar(BitwiseBinaryScalar): + # Tensor because it gets converted from Scalar -> Tensor in lowering + aten_op = "torch.ops.aten.bitwise_xor.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_xor_Tensor" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_bitwise_xor_Scalar" + + def forward(self, tensor: torch.Tensor, scalar: int): + return tensor.bitwise_xor(scalar) + + +class OrScalar(BitwiseBinaryScalar): + # Tensor because it gets converted from Scalar -> Tensor in lowering + aten_op = "torch.ops.aten.bitwise_or.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_or_Tensor" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_bitwise_or_Scalar" + + def forward(self, tensor: torch.Tensor, scalar: int): + return tensor.bitwise_or(scalar) + + +######### +## AND ## +######### + + +@common.parametrize("test_data", And().test_data) +def test_bitwise_and_tensor_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data) +def test_bitwise_and_scalar_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + AndScalar(), + test_data(), + {AndScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_bitwise_and_tensor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data) +def test_bitwise_and_scalar_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + AndScalar(), + test_data(), + AndScalar.aten_op, + AndScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_bitwise_and_tensor_u55_INT(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data) +def test_bitwise_and_scalar_u55_INT(test_data: input_t2): + # There will be one full op which will be delegated. + num_delegates = 1 + num_exir = 0 + pipeline = OpNotSupportedPipeline[input_t2]( + AndScalar(), + test_data(), + { + AndScalar.exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_and_scalar_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + AndScalar(), + test_data(), + AndScalar.aten_op, + AndScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_and_tensor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_tensor_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_scalar_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + AndScalar(), + test_data(), + {AndScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_tensor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_scalar_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + AndScalar(), + test_data(), + AndScalar().aten_op, + AndScalar().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +######### +## XOR ## +######### + + +@common.parametrize("test_data", Xor().test_data) +def test_bitwise_xor_tensor_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data) +def test_bitwise_xor_scalar_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + XorScalar(), + test_data(), + {XorScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_bitwise_xor_tensor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data) +def test_bitwise_xor_scalar_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + XorScalar(), + test_data(), + XorScalar.aten_op, + XorScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_bitwise_xor_tensor_u55_INT(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data) +def test_bitwise_xor_scalar_u55_INT(test_data: input_t2): + # There will be one full op which will be delegated. + num_delegates = 1 + num_exir = 0 + pipeline = OpNotSupportedPipeline[input_t2]( + XorScalar(), + test_data(), + { + XorScalar.exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_xor_tensor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_xor_scalar_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + XorScalar(), + test_data(), + XorScalar.aten_op, + XorScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_tensor_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_scalar_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + XorScalar(), + test_data(), + {XorScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_tensor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_scalar_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + XorScalar(), + test_data(), + XorScalar().aten_op, + XorScalar().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +######## +## OR ## +######## + + +@common.parametrize("test_data", Or().test_data) +def test_bitwise_or_tensor_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data) +def test_bitwise_or_scalar_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + OrScalar(), + test_data(), + {OrScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_bitwise_or_tensor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data) +def test_bitwise_or_scalar_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + OrScalar(), + test_data(), + OrScalar.aten_op, + OrScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_bitwise_or_tensor_u55_INT(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data) +def test_bitwise_or_scalar_u55_INT(test_data: input_t2): + # There will be one full op which will be delegated. + num_delegates = 1 + num_exir = 0 + pipeline = OpNotSupportedPipeline[input_t2]( + OrScalar(), + test_data(), + { + OrScalar.exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_or_tensor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_or_scalar_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + OrScalar(), + test_data(), + OrScalar.aten_op, + OrScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_tensor_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_scalar_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + OrScalar(), + test_data(), + {OrScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_tensor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_scalar_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + OrScalar(), + test_data(), + OrScalar().aten_op, + OrScalar().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@pytest.mark.xfail( + reason="MLBEDSW-11029: Fatal Python floating point error in Vela for rank 4 bitwse ops with int32 dtype." +) +def test_bitwise_or_tensor_u85_INT_zeros(): + raise RuntimeError( + "Dummy test to xfail mark u85 zeros test case since running the actual test causes a fatal crash." + ) + + +@pytest.mark.xfail( + reason="MLBEDSW-11029: Fatal Python floating point error in Vela for rank 4 bitwse ops with int32 dtype." +) +def test_bitwise_and_tensor_u85_INT_zeros(): + raise RuntimeError( + "Dummy test to xfail mark u85 zeros test case since running the actual test causes a fatal crash." + ) + + +@pytest.mark.xfail( + reason="MLBEDSW-11029: Fatal Python floating point error in Vela for rank 4 bitwse ops with int32 dtype." +) +def test_bitwise_xor_tensor_u85_INT_zeros(): + raise RuntimeError( + "Dummy test to xfail mark u85 zeros test case since running the actual test causes a fatal crash." + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise_not.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise_not.py new file mode 100644 index 0000000..2f60fda --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bitwise_not.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.bitwise_not.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_not_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10, dtype=torch.int32), + "ones": torch.ones(10, 2, 3, dtype=torch.int8), + "pattern1_int8": 0xAA * torch.ones(1, 2, 2, 2, dtype=torch.int8), + "pattern1_int16": 0xAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int16), + "pattern1_int32": 0xAAAAAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int32), + "pattern2_int8": 0xCC * torch.ones(1, 2, 2, 2, dtype=torch.int8), + "pattern2_int16": 0xCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int16), + "pattern2_int32": 0xCCCCCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int32), + "pattern_bool": torch.tensor([True, False, True], dtype=torch.bool), + "rand_rank2": torch.randint(-128, 127, (10, 10), dtype=torch.int8), + "rand_rank4": torch.randint(-128, 127, (1, 10, 10, 10), dtype=torch.int8), +} + + +class BitwiseNot(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.bitwise_not(x) + + +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_tosa_FP(test_data: Tuple): + # We don't delegate bitwise_not since it is not supported on the FP profile. + pipeline = OpNotSupportedPipeline[input_t1]( + BitwiseNot(), + (test_data,), + {exir_op: 1}, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + BitwiseNot(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_u55_INT(test_data: Tuple): + # We don't delegate bitwise_not since it is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t1]( + BitwiseNot(), + (test_data,), + {exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + BitwiseNot(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_bitwise_not_vgf_no_quant(test_data: Tuple): + # We don't delegate bitwise_not since it is not supported on the FP profile. + pipeline = OpNotSupportedPipeline[input_t1]( + BitwiseNot(), + (test_data,), + {exir_op: 1}, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_bitwise_not_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + BitwiseNot(), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bmm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bmm.py new file mode 100644 index 0000000..d21b33c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_bmm.py @@ -0,0 +1,193 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op_bmm = "torch.ops.aten.bmm.default" +exir_op_bmm = "executorch_exir_dialects_edge__ops_aten_bmm_default" + +aten_op_mm = "torch.ops.aten.matmul.default" +exir_op_mm = "executorch_exir_dialects_edge__ops_aten_matmul_default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class BMM(torch.nn.Module): + test_data_generators = { + "rand_same": lambda: (torch.rand(2, 1, 1), torch.rand(2, 1, 1)), + "rand_diff": lambda: (torch.rand(5, 3, 5), torch.rand(5, 5, 2)), + "rand_ones": lambda: (torch.ones(1, 55, 3), torch.ones(1, 3, 44)), + "rand_big": lambda: (10000 * torch.randn(10, 1, 10), torch.randn(10, 10, 5)), + "rand_neg": lambda: ( + -10 * torch.randn(2, 32, 64), + 5 + 5 * torch.randn(2, 64, 32), + ), + } + + def forward(self, x, y): + return torch.bmm(x, y) + + +class BMMSingleInput(torch.nn.Module): + test_data_generators = { + "rand_3d_1": lambda: (torch.rand(20, 3, 3),), + "rand_3d_2": lambda: (torch.rand(2, 128, 128),), + "rand_big_1": lambda: (10000 * torch.randn(4, 25, 25),), + "rand_big_2": lambda: (5 + 5 * torch.randn(3, 64, 64),), + } + + def forward(self, x): + return torch.bmm(x, x) + + +@common.parametrize("test_data", BMM.test_data_generators) +def test_bmm_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](BMM(), test_data(), aten_op_bmm, exir_op_bmm) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLETORCH-534) +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +def test_bmm_tosa_FP_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + BMMSingleInput(), test_data(), aten_op_bmm, exir_op_bmm + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +def test_bmm_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + BMM(), test_data(), aten_op_bmm, exir_op_bmm, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +def test_bmm_tosa_INT_single_input(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + BMMSingleInput(), test_data(), aten_op_bmm, exir_op_bmm + ) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.XfailIfNoCorstone300 +def test_bmm_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.XfailIfNoCorstone320 +def test_bmm_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +@common.XfailIfNoCorstone300 +def test_bmm_u55_INT_single_input(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +@common.XfailIfNoCorstone320 +def test_bmm_u85_INT_single_input(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.SkipIfNoModelConverter +def test_bmm_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + BMMSingleInput.test_data_generators, + flakies={"rand_big_1": 3}, +) +@common.SkipIfNoModelConverter +def test_bmm_vgf_no_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.SkipIfNoModelConverter +def test_bmm_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_bmm_vgf_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cat.py new file mode 100644 index 0000000..a037d0e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cat.py @@ -0,0 +1,219 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, +) +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.cat.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_cat_default" + + +class Cat(torch.nn.Module): + test_parameters = { + "cat_ones_two_tensors": lambda: ((torch.ones(1), torch.ones(1)), 0), + "cat_ones_and_rand_three_tensors": lambda: ( + (torch.ones(1, 2), torch.randn(1, 5), torch.randn(1, 1)), + 1, + ), + "cat_ones_and_rand_four_tensors": lambda: ( + ( + torch.ones(1, 2, 5), + torch.randn(1, 2, 4), + torch.randn(1, 2, 2), + torch.randn(1, 2, 1), + ), + -1, + ), + "cat_rand_two_tensors": lambda: ( + (torch.randn(1, 2, 4, 4), torch.randn(1, 2, 4, 1)), + 3, + ), + "cat_rand_two_tensors_dim_0": lambda: ( + (torch.randn(1, 2, 4, 4), torch.randn(1, 2, 4, 4)), + 0, + ), + "cat_rand_two_tensors_dim_3": lambda: ( + (torch.randn(2, 2, 4, 4), torch.randn(2, 2, 4, 1)), + 3, + ), + "cat_rand_large": lambda: ( + ( + 10000 * torch.randn(2, 3, 1, 4), + torch.randn(2, 7, 1, 4), + torch.randn(2, 1, 1, 4), + ), + -3, + ), + } + + def __init__(self): + super().__init__() + + def forward(self, t: tuple[torch.Tensor, ...], dim: int) -> torch.Tensor: + return torch.cat(t, dim=dim) + + +@common.parametrize("test_data", Cat.test_parameters) +def test_cat_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +def test_cat_tosa_FP_4d(): + square = torch.ones((2, 2, 2, 2)) + for dim in range(-3, 3): + test_data = ((square, square.clone()), dim) + pipeline = TosaPipelineFP[input_t1]( + Cat(), + test_data, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +def test_cat_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone300 +def test_cat_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone320 +def test_cat_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.SkipIfNoModelConverter +def test_cat_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.SkipIfNoModelConverter +def test_cat_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +def test_cat_16a8w_tosa_INT(test_data: Tuple): + """Test cat operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone300 +def test_cat_16a8w_u55_INT(test_data: Tuple): + """Test cat operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone320 +def test_cat_16a8w_u85_INT(test_data: Tuple): + """Test cat operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ceil.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ceil.py new file mode 100644 index 0000000..93b5f9c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ceil.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Ceil(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.ceil(x) + + aten_op = "torch.ops.aten.ceil.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_ceil_default" + + +zeros = torch.zeros(1, 10, 10, 10) +ones = torch.ones(10, 10, 10) +rand = torch.rand(10, 10) - 0.5 +randn_pos = torch.randn(1, 4, 4, 4) + 10 +randn_neg = torch.randn(1, 4, 4, 4) - 10 +ramp = torch.arange(-16, 16, 0.2) + +test_data = { + "ceil_zeros": lambda: (Ceil(), zeros), + "ceil_ones": lambda: (Ceil(), ones), + "ceil_rand": lambda: (Ceil(), rand), + "ceil_randn_pos": lambda: (Ceil(), randn_pos), + "ceil_randn_neg": lambda: (Ceil(), randn_neg), + "ceil_ramp": lambda: (Ceil(), ramp), +} + + +@common.parametrize("test_data", test_data) +def test_ceil_tosa_FP(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_ceil_tosa_INT(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone300 +def test_ceil_u55_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone320 +def test_ceil_u85_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_ceil_vgf_no_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_ceil_vgf_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clamp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clamp.py new file mode 100644 index 0000000..13c3479 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clamp.py @@ -0,0 +1,474 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from numbers import Number +from typing import Tuple, Union + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.clamp.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_clamp_default" + +input_t = Tuple[torch.Tensor] + + +test_data_suite = { + # test_name: (test_data, min, max) + "rank_1": lambda: (torch.rand(10) * 2, -1.0, 1.0), + "rank_2": lambda: (torch.rand(1, 35), 0.5, 0.8), + "rank_3": lambda: (torch.ones(1, 10, 10), -1, -1), + "rank_4": lambda: (torch.rand(1, 10, 10, 1) * 2, -0.1, 2.0), + "rank_4_mixed_min_max_dtype": lambda: (torch.rand(1, 10, 10, 5) + 10, 8.0, 10), + "rank_4_no_min": lambda: (torch.rand(1, 10, 10, 1) * 10, None, 5), + "rank_4_no_max": lambda: (torch.rand(1, 10, 10, 1) - 3, -3.3, None), +} + +test_data_suite_int32 = { + "int32_rank2": lambda: (torch.randint(-50, 50, (2, 3), dtype=torch.int32), -10, 10), + "int32_rank3_no_min": lambda: ( + torch.randint(-100, 100, (1, 3, 3), dtype=torch.int32), + None, + 25, + ), + "int32_rank3_no_max": lambda: ( + torch.randint(-100, 100, (1, 3, 3), dtype=torch.int32), + -25, + None, + ), + "int32_rank4_large_range": lambda: ( + torch.randint(-200, 200, (1, 2, 4, 4), dtype=torch.int32), + torch.iinfo(torch.int32).min, + torch.iinfo(torch.int32).max, + ), +} + + +class Clamp(torch.nn.Module): + def __init__( + self, + clamp_min: Union[torch.Tensor, Number, None], + clamp_max: Union[torch.Tensor, Number, None], + ): + super().__init__() + + self.clamp_min = clamp_min + self.clamp_max = clamp_max + + def forward(self, x): + return torch.clamp(x, self.clamp_min, self.clamp_max) + + +@common.parametrize("test_data", test_data_suite) +def test_clamp_tosa_FP(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineFP[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_clamp_tosa_INT(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +def test_clamp_tosa_INT_int32_inputs(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.pop_stage("quantize") + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_clamp_tosa_INT_a16w8(test_data): + """Test clamp operation with int16 I/O quantization for TOSA INT.""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT_16a8w(test_data): + """Test clamp operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT_16a8w(test_data): + """Test clamp operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_clamp_vgf_no_quant(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_clamp_vgf_quant(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +aten_op_tensor = "torch.ops.aten.clamp.Tensor" +exir_op_tensor = "executorch_exir_dialects_edge__ops_aten_clamp_Tensor" + +test_data_suite_tensor_FP = { + # test_name: (test_data, min, max) + "rank_1": lambda: (torch.rand(10) * 2, torch.tensor(-1.0), torch.tensor(1.0)), + "rank_2": lambda: (torch.rand(1, 35), torch.tensor(0.5), torch.tensor(0.8)), + "rank_3": lambda: ( + torch.ones(1, 10, 10), + torch.rand(1, 10, 10) * 0.5, + torch.rand(1, 10, 10) * -0.5, + ), + "rank_4": lambda: ( + torch.rand(1, 10, 10, 1) * 2, + torch.tensor(-0.1), + torch.tensor(2.0), + ), + "rank_4_no_max": lambda: ( + torch.rand(10, 20, 30, 40) - 3, + torch.rand(30, 40) - 3.3, + None, + ), + "rank_4_no_min": lambda: ( + torch.rand(10, 20, 30, 40) * 10, + None, + torch.rand(10, 20, 30, 40) * 5.0, + ), +} + +test_data_suite_tensor_INT32 = { + "int32_rank2": lambda: ( + torch.randint(-50, 50, (2, 3), dtype=torch.int32), + torch.tensor(-10), + torch.tensor(10), + ), + "int32_rank3_no_min_broadcast_1_3": lambda: ( + torch.randint(0, 100, (1, 3, 3), dtype=torch.int32) + 10, + None, + torch.tensor([[3, 5, 7]], dtype=torch.int32), # torch.Size([1, 3]) + ), + "int32_rank3_no_max_broadcast_3_1": lambda: ( + torch.randint(-100, 100, (1, 3, 3), dtype=torch.int32), + torch.tensor([[3], [5], [7]], dtype=torch.int32), # torch.Size([3, 1]) + None, + ), + "int32_rank4_large_range": lambda: ( + torch.randint(-200, 200, (1, 2, 4, 4), dtype=torch.int32), + torch.tensor((torch.iinfo(torch.int32).min)), + torch.tensor((torch.iinfo(torch.int32).max)), + ), + "int32_rank4_broadcast_1_2": lambda: ( + torch.ones(1, 2, 4, 4, dtype=torch.int32) * 100, + torch.randint(-10, 10, (4,), dtype=torch.int32), # torch.Size([4]) + torch.randint( + -10, + 10, + ( + 4, + 4, + ), + dtype=torch.int32, + ), # torch.Size([4, 4]) + ), + "int32_rank4_broadcast_3_4": lambda: ( + torch.ones(1, 2, 4, 4, dtype=torch.int32) * 100, + torch.randint( + -10, + 10, + ( + 1, + 4, + 4, + ), + dtype=torch.int32, + ), # torch.Size([1, 4, 4]) + torch.randint( + -10, + 10, + ( + 1, + 1, + 4, + 4, + ), + dtype=torch.int32, + ), # torch.Size([1, 1, 4, 4]) + ), +} + +test_data_suite_tensor_INT64 = { + "int64_rank_3": lambda: ( + torch.ones(1, 10, 10, dtype=torch.int64), + torch.tensor(-1), + torch.tensor(-1), + ), + "int64_rank_4": lambda: ( + torch.randint(-100, 100, (1, 3, 3)), + torch.tensor(-10), + torch.tensor(20), + ), +} + + +@common.parametrize("test_data", test_data_suite_tensor_FP) +def test_clamp_tosa_FP_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineFP[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + + pipeline.run() + + +@common.parametrize( + "test_data", test_data_suite_tensor_INT32 | test_data_suite_tensor_INT64 +) +def test_clamp_tosa_INT_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize( + "test_data", test_data_suite_tensor_INT32 | test_data_suite_tensor_INT64 +) +def test_clamp_tosa_INT_a16w8_tensor(test_data): + """Test clamp operation with int16 I/O quantization for TOSA INT.""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT_16a8w_tensor(test_data): + """Test clamp operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT_16a8w_tensor(test_data): + """Test clamp operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_FP) +@common.SkipIfNoModelConverter +def test_clamp_vgf_no_quant_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", test_data_suite_tensor_INT32 | test_data_suite_tensor_INT64 +) +@common.SkipIfNoModelConverter +def test_clamp_vgf_quant_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clone.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clone.py new file mode 100644 index 0000000..3aec2ed --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_clone.py @@ -0,0 +1,150 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.clone.default" +exir_op = "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default" + +input_t = Tuple[torch.Tensor] + + +class CloneFirstArg(torch.nn.Module): + def forward(self, x): + return x.clone() + x + + +class CloneSecondArg(torch.nn.Module): + def forward(self, x): + return x * x.clone() + + +class CloneOutput(torch.nn.Module): + def forward(self, x): + return (x / x).clone() + + +class CloneBothArgs(torch.nn.Module): + def forward(self, x): + return x.clone() + x.clone() + + +class CloneAfterOtherOp(torch.nn.Module): + def forward(self, x): + x = x * 2 + return x.clone() + x + + +class CloneParallelToOtherOp(torch.nn.Module): + def forward(self, x): + return x * 2 + x.clone() + + +delegated_clones = { + "clone_first_arg": lambda: (CloneFirstArg, (torch.rand(1, 2, 3, 4),)), + "clone_second_arg": lambda: (CloneSecondArg, (torch.rand(1, 2, 3, 4),)), + "clone_output": lambda: (CloneOutput, (torch.rand(1, 2, 3, 4),)), + "clone_both_args": lambda: (CloneBothArgs, (torch.rand(1, 2, 3, 4),)), + "clone_after_other_op": lambda: (CloneAfterOtherOp, (torch.rand(1, 2, 3, 4),)), + "clone_parallel_to_other_op": lambda: ( + CloneParallelToOtherOp, + (torch.rand(1, 2, 3, 4),), + ), +} + + +@common.parametrize("input_data", delegated_clones) +def test_clone_tosa_FP(input_data): + module, input_tensor = input_data() + pipeline = TosaPipelineFP[input_t]( + module(), + input_tensor, + [], + ) + pipeline.run() + + +@common.parametrize("input_data", delegated_clones) +def test_clone_tosa_INT(input_data): + module, input_tensor = input_data() + + pipeline = TosaPipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", delegated_clones) +@common.XfailIfNoCorstone300 +def test_clone_u55_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU55PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("input_data", delegated_clones) +@common.XfailIfNoCorstone320 +def test_clone_u85_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU85PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("test_data", delegated_clones) +@common.SkipIfNoModelConverter +def test_clone_vgf_no_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", delegated_clones) +@common.SkipIfNoModelConverter +def test_clone_vgf_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cond.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cond.py new file mode 100644 index 0000000..b430bf9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cond.py @@ -0,0 +1,338 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.arm_tester import ArmTester +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from pytest import mark + +aten_op = "torch.ops.higher_order.cond" +exir_op = "torch.ops.higher_order.cond" + +input_t1 = Tuple[torch.Tensor] +input_t2 = Tuple[torch.Tensor, torch.Tensor] + + +class CondZeroArgsOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch() -> torch.Tensor: + return torch.zeros(10) + + def false_branch() -> torch.Tensor: + return torch.ones(10) + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, []) + + +class CondOneArgOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch(arg: torch.Tensor) -> torch.Tensor: + return torch.sin(arg) + + def false_branch(arg: torch.Tensor) -> torch.Tensor: + return torch.cos(arg) + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x]) + + +class CondOneArgBufferOneOutput(torch.nn.Module): + def __init__(self, *args: common.Any, **kwargs: common.Any) -> None: + super().__init__(*args, **kwargs) + self.buffer = torch.rand(1, 1, 2, 2) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch(arg: torch.Tensor, buffer: torch.Tensor) -> torch.Tensor: + return torch.sin(arg) + buffer + + def false_branch(arg: torch.Tensor, buffer: torch.Tensor) -> torch.Tensor: + return torch.cos(arg) + buffer + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x, self.buffer]) + + +class CondOneArgAndScalarOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch(arg: torch.Tensor) -> torch.Tensor: + return arg + 1.0 + + def false_branch(arg: torch.Tensor) -> torch.Tensor: + return arg - 1.0 + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x]) + + +class CondOneArgTwoOutputs(torch.nn.Module): + def forward(self, x: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: + def true_branch(arg: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: + return arg + torch.sin(arg), arg - torch.sin(arg) + + def false_branch(arg: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: + return arg - arg.mean(), arg + arg.mean() + + predicate = x.flatten().sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x]) + + +class CondNestedOneArgOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def inner_true(arg: torch.Tensor) -> torch.Tensor: + return arg + torch.full((1,), (1.0)) + + def inner_false(arg: torch.Tensor) -> torch.Tensor: + return arg - torch.full((1,), (1.0)) + + def outer_true(arg: torch.Tensor) -> torch.Tensor: + inner_predicate = arg.mean() > 0 + return torch.cond(inner_predicate, inner_true, inner_false, [arg]) + + def outer_false(arg: torch.Tensor) -> torch.Tensor: + return arg * torch.full((1,), (1.0)) + + predicate = x.sum() > 0 + return torch.cond(predicate, outer_true, outer_false, [x]) + + +class CondMultipleOneArgOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def first_true(arg: torch.Tensor) -> torch.Tensor: + return arg.sigmoid() + + def first_false(arg: torch.Tensor) -> torch.Tensor: + return arg.relu() + + first_predicate = x.sum() > 0 + intermediate = torch.cond(first_predicate, first_true, first_false, [x]) + + def second_true(arg: torch.Tensor) -> torch.Tensor: + return arg.sin() + + def second_false(arg: torch.Tensor) -> torch.Tensor: + return arg.cos() + + second_predicate = intermediate.mean() > 0 + return torch.cond(second_predicate, second_true, second_false, [intermediate]) + + +class CondTwoArgsOneOutput(torch.nn.Module): + def forward(self, lhs: torch.Tensor, rhs: torch.Tensor) -> torch.Tensor: + def true_branch(arg_l: torch.Tensor, arg_r: torch.Tensor) -> torch.Tensor: + return arg_l + arg_r + + def false_branch(arg_l: torch.Tensor, arg_r: torch.Tensor) -> torch.Tensor: + return arg_l - arg_r + + predicate = (lhs - rhs).sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [lhs, rhs]) + + +class CondTwoArgsTwoOutputs(torch.nn.Module): + def forward( + self, lhs: torch.Tensor, rhs: torch.Tensor + ) -> tuple[torch.Tensor, torch.Tensor]: + def true_branch( + arg_l: torch.Tensor, arg_r: torch.Tensor + ) -> tuple[torch.Tensor, torch.Tensor]: + return arg_l + arg_r, arg_l * arg_r + + def false_branch( + arg_l: torch.Tensor, arg_r: torch.Tensor + ) -> tuple[torch.Tensor, torch.Tensor]: + diff = arg_l - arg_r + return diff, arg_l + diff + + predicate = (lhs * rhs).sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [lhs, rhs]) + + +def _single_input_case( + module_factory: Callable[[], torch.nn.Module] +) -> Callable[[], tuple[torch.nn.Module, input_t1]]: + def _create() -> tuple[torch.nn.Module, input_t1]: + return module_factory(), (torch.randn(1, 1, 2, 2),) + + return _create + + +def _dual_input_case( + module_factory: Callable[[], torch.nn.Module] +) -> Callable[[], tuple[torch.nn.Module, input_t2]]: + def _create() -> tuple[torch.nn.Module, input_t2]: + return module_factory(), (torch.randn(2, 3, 4, 6), torch.randn(2, 3, 4, 6)) + + return _create + + +test_cases: dict[str, Callable[[], tuple[torch.nn.Module, tuple]]] = { + "zero_args_one_output": _single_input_case(CondZeroArgsOneOutput), + "one_arg_one_output": _single_input_case(CondOneArgOneOutput), + "one_arg_const_one_output": _single_input_case(CondOneArgBufferOneOutput), + "one_arg_and_scalar_one_output": _single_input_case(CondOneArgAndScalarOneOutput), + "one_arg_two_outputs": _single_input_case(CondOneArgTwoOutputs), + "two_args_one_output": _dual_input_case(CondTwoArgsOneOutput), + "two_args_two_outputs": _dual_input_case(CondTwoArgsTwoOutputs), + "nested_one_arg_one_output": _single_input_case(CondNestedOneArgOneOutput), + "multiple_one_arg_one_output": _single_input_case(CondMultipleOneArgOneOutput), +} + + +def _make_calibration_samples( + module: torch.nn.Module, example_inputs: tuple +) -> tuple[tuple[torch.Tensor, ...], ...]: + """Return one example input that triggers the if branch, and one that triggers the else branch.""" + + if isinstance(module, CondTwoArgsOneOutput): + # Predicate is sum(lhs-rhs) > 0 + lhs, rhs = example_inputs + if_example_inputs = (lhs, rhs) + else_example_inputs = (rhs, lhs) + elif isinstance(module, CondTwoArgsTwoOutputs): + # Predicate is sum(lhs*rhs) > 0 + lhs, rhs = example_inputs + if_example_inputs = (lhs, rhs) + else_example_inputs = (lhs, -rhs) + else: + # Predicate is sum(x) > 0 + (x,) = example_inputs + if_example_inputs = (x,) + else_example_inputs = (-x,) + + return (if_example_inputs, else_example_inputs) + + +def _set_branch_calibration_samples( + pipeline, module: torch.nn.Module, example_inputs: tuple +) -> None: + calibration_samples = _make_calibration_samples(module, example_inputs) + quant_stage_pos = pipeline.find_pos("quantize") + quant_stage = pipeline._stages[quant_stage_pos].args[0] + quant_stage.calibration_samples = calibration_samples + + +@common.parametrize( + "case", + test_cases, + xfails={ + "one_arg_and_scalar_one_output": "Scalars become get_attr nodes that are not supported.", + "nested_one_arg_one_output": "Not fully delegated.", + }, +) +def test_cond_tosa_FP(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineFP[tuple]( + module, example_inputs, aten_op, tosa_extensions=["cf"] + ) + + # Make sure no cond ops are left after partitioning. + pipeline.add_stage_after( + "to_edge_transform_and_lower", + ArmTester.check_not, + pipeline.tester, + ["torch.ops.higher_order.cond"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, + xfails={ + "one_arg_and_scalar_one_output": "Incorrect quantization on the scalar.", + "nested_one_arg_one_output": "Node submodule_0 target submodule_0 references nonexistent attribute submodule_0", + }, +) +def test_cond_tosa_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineINT[tuple]( + module, example_inputs, aten_op, tosa_extensions=["cf"] + ) + _set_branch_calibration_samples(pipeline, module, example_inputs) + + # Make sure no cond ops are left after partitioning. + pipeline.add_stage_after( + "to_edge_transform_and_lower", + ArmTester.check_not, + pipeline.tester, + ["torch.ops.higher_order.cond"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, +) +def test_cond_u55_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = OpNotSupportedPipeline[tuple](module, example_inputs, {aten_op: 1}) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize( + "case", + test_cases, + xfails={ + "one_arg_and_scalar_one_output": "Incorrect quantization on the scalar.", + "nested_one_arg_one_output": "Node submodule_0 target submodule_0 references nonexistent attribute submodule_0", + }, + skips={ + "one_arg_one_output": "Segfault when transpose goes into cond. MLBEDSW-11416.", + "one_arg_const_one_output": "Segfault when transpose goes into cond. MLBEDSW-11416.", + "multiple_one_arg_one_output": "Segfault when transpose goes into cond. MLBEDSW-11416.", + }, +) +@common.XfailIfNoCorstone320.with_args(raises=None) +def test_cond_u85_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = EthosU85PipelineINT[tuple](module, example_inputs, aten_op, exir_op) + _set_branch_calibration_samples(pipeline, module, example_inputs) + pipeline.run() + + +@mark.skip("Cond not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_cond_vgf_FP(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + VgfPipeline[tuple]( + module, + example_inputs, + aten_op, + exir_op, + ).run() + + +@mark.skip("Cond not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_cond_vgf_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = VgfPipeline[tuple]( + module, + example_inputs, + aten_op, + exir_op, + ) + _set_branch_calibration_samples(pipeline, module, example_inputs) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_constant_pad_nd.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_constant_pad_nd.py new file mode 100644 index 0000000..05f14e6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_constant_pad_nd.py @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +# Test the pad_constant_nd op which pads the input tensor at specific dimension(s). +# +from typing import Tuple + +import torch +import torch.nn.functional as F +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.pad.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_pad_default" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + "4dim_last1dim": lambda: (torch.rand(1, 1, 16, 16), (1, 1, 0, 0, 0, 0, 0, 0), 1), + "4dim_last2dim": lambda: (torch.rand(1, 1, 16, 16), (1, 0, 1, 0, 0, 0, 0, 0), 2), + "4dim_last3dim": lambda: (torch.rand(1, 1, 16, 16), (1, 1, 0, 2, 0, 2, 0, 0), 3), + "4dim_last4dim": lambda: (torch.rand(1, 1, 16, 16), (1, 0, 1, 1, 0, 2, 0, 2), 4), + "3dim_last1dim": lambda: (torch.rand(1, 1, 16), (1, 1, 0, 0, 0, 0), 1), + "3dim_last2dim": lambda: (torch.rand(1, 1, 16), (1, 0, 1, 1, 0, 0), 2), + "3dim_last3dim": lambda: (torch.rand(1, 1, 16), (1, 0, 1, 0, 1, 1), 3), + "2dim_last1dim": lambda: (torch.rand(1, 1, 16), (1, 1, 0, 0), 1), + "2dim_last2dim": lambda: (torch.rand(1, 1, 16), (1, 0, 1, 1), 2), +} + + +class ConstantPadND(torch.nn.Module): + def __init__(self, pad: Tuple, value: float | None = None): + super().__init__() + self.value = value + nonzero_idx = len(pad) + for i in range(0, len(pad), 2): + if pad[i] + pad[i + 1] == 0: + nonzero_idx = i + break + self.pad = pad[:nonzero_idx] + + def forward(self, x: torch.Tensor): + x = F.pad(x, pad=self.pad, mode="constant", value=self.value) + return x + + +@common.parametrize( + "test_data", + test_data_suite, +) +def test_constant_pad_nd_tosa_FP(test_data: Tuple): + test_data, padding, value = test_data() + pipeline = TosaPipelineFP[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_INT(test_data: Tuple): + test_data, padding, value = test_data() + pipeline = TosaPipelineINT[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_INT_a16w8(test_data: Tuple): + """Test constant_pad_nd op with int16 I/O quantization for TOSA INT.""" + test_data, padding, value = test_data() + pipeline = TosaPipelineINT[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_no_quant(test_data: Tuple): + inp, padding, value = test_data() + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (inp,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_quant(test_data: Tuple): + inp, padding, value = test_data() + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (inp,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv1d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv1d.py new file mode 100644 index 0000000..7135167 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv1d.py @@ -0,0 +1,356 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple, Union + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.conv1d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + +input_t = Tuple[torch.Tensor] + + +class Conv1d(torch.nn.Module): + """ + Creates one or many chained 1D-convolutions. For multiple convolutions, the + respective parameteres are provided as lists. + """ + + def __init__( + self, + length=8, + nbr_conv=1, # Number of chained convs + in_channels: Union[List, int, None] = None, + out_channels: Union[List, int, None] = None, + kernel_size: Union[List, Tuple, None] = None, + stride: Union[List, Tuple, None] = None, + padding: Union[List, Tuple, None] = None, + dilation: Union[List, Tuple, None] = None, + groups: Union[List, int, None] = None, + bias: Union[List, bool, None] = None, + padding_mode: Union[List, str, None] = None, + batches=1, + dtype=torch.float32, + ): + super().__init__() + self.nbr_convs = nbr_conv + + # Handle default values + in_channels = [2] * nbr_conv if in_channels is None else in_channels + out_channels = [1 * nbr_conv] if out_channels is None else out_channels + kernel_size = [3] * nbr_conv if kernel_size is None else kernel_size + stride = [2] * nbr_conv if stride is None else stride + padding = [1] * nbr_conv if padding is None else padding + dilation = [1] * nbr_conv if dilation is None else dilation + groups = [1] * nbr_conv if groups is None else groups + bias = [True] * nbr_conv if bias is None else bias + padding_mode = ["zeros"] * nbr_conv if padding_mode is None else padding_mode + + # This allows the input parameters to be either a single value or a list + # as type hint implies + if not isinstance(in_channels, List): + in_channels = [in_channels] + if not isinstance(out_channels, List): + out_channels = [out_channels] + if not isinstance(kernel_size, List): + kernel_size = [kernel_size] + if not isinstance(stride, List): + stride = [stride] + if not isinstance(padding, List): + padding = [padding] + if not isinstance(dilation, List): + dilation = [dilation] + if not isinstance(groups, List): + groups = [groups] + if not isinstance(bias, List): + bias = [bias] + if not isinstance(padding_mode, List): + padding_mode = [padding_mode] + + self.batches = batches + self.in_channels = in_channels + self.length = length + self.dtype = dtype + + # Build chain of convs + for i in range(self.nbr_convs): + setattr( + self, + f"conv_{i}", + torch.nn.Conv1d( + in_channels=in_channels[i], + out_channels=out_channels[i], + kernel_size=kernel_size[i], + stride=stride[i], + padding=padding[i], + dilation=dilation[i], + groups=groups[i], + bias=bias[i], + padding_mode=padding_mode[i], + ).to(dtype), + ) + + def get_inputs(self): + return ( + torch.randn(self.batches, self.in_channels[0], self.length).to(self.dtype), + ) + + def forward(self, x): + for i in range(self.nbr_convs): + conv = getattr(self, f"conv_{i}") + x = conv(x) + return x + + +conv1d_2_3x2x40_nobias = Conv1d( + in_channels=2, + out_channels=3, + kernel_size=2, + stride=1, + bias=False, + padding=0, + length=40, + batches=1, +) + +conv1d_3_1x3x256_st1 = Conv1d( + in_channels=3, + out_channels=10, + kernel_size=3, + stride=1, + padding=0, + length=256, + batches=1, +) + +conv1d_3_1x3x12_st2_pd1 = Conv1d( + in_channels=3, + out_channels=4, + kernel_size=3, + stride=2, + padding=1, + length=12, + batches=1, +) + +conv1d_1_1x2x128_st1 = Conv1d( + in_channels=2, + out_channels=1, + kernel_size=1, + stride=1, + padding=0, + length=128, + batches=1, +) + +conv1d_2_1x2x14_st2 = Conv1d( + in_channels=2, + out_channels=1, + kernel_size=2, + stride=2, + padding=0, + length=14, + batches=1, +) + +conv1d_5_3x2x128_st1 = Conv1d( + in_channels=2, + out_channels=3, + kernel_size=5, + stride=1, + padding=0, + length=128, + batches=3, +) + +conv1d_3_1x3x224_st2_pd1 = Conv1d( + in_channels=3, + out_channels=16, + kernel_size=3, + stride=2, + padding=1, + length=224, + batches=1, +) + +conv1d_7_1x3x16_st2_pd1_dl2 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=7, + stride=2, + padding=1, + dilation=2, + length=16, + batches=1, +) +conv1d_7_1x3x15_st1_pd0_dl1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=7, + stride=1, + padding=0, + dilation=1, + length=15, + batches=1, +) +conv1d_5_1x3x14_st5_pd0_dl1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=5, + stride=5, + padding=0, + dilation=1, + length=14, + batches=1, +) +conv1d_5_1x3x9_st5_pd0_dl1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=5, + stride=5, + padding=0, + dilation=1, + length=9, + batches=1, +) + +two_conv1d_nobias = Conv1d( + nbr_conv=2, + length=256, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[5, 5], + stride=[1, 1], + padding=[0, 0], + bias=[False, False], + batches=1, +) + +two_conv1d = Conv1d( + nbr_conv=2, + length=256, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[5, 5], + stride=[1, 1], + padding=[0, 0], + bias=[True, True], + batches=1, +) + +test_data_FP = { + "2_3x2x40_nobias": lambda: conv1d_2_3x2x40_nobias, + "3_1x3x256_st1": lambda: conv1d_3_1x3x256_st1, + "3_1x3x12_st2_pd1": lambda: conv1d_3_1x3x12_st2_pd1, + "1_1x2x128_st1": lambda: conv1d_1_1x2x128_st1, + "2_1x2x14_st2": lambda: conv1d_2_1x2x14_st2, + "5_3x2x128_st1": lambda: conv1d_5_3x2x128_st1, + "3_1x3x224_st2_pd1": lambda: conv1d_3_1x3x224_st2_pd1, + "7_1x3x16_st2_pd1_dl2_needs_adjust_pass": lambda: conv1d_7_1x3x16_st2_pd1_dl2, + "7_1x3x15_st1_pd0_dl1_needs_adjust_pass": lambda: conv1d_7_1x3x15_st1_pd0_dl1, + "5_1x3x14_st5_pd0_dl1_needs_adjust_pass": lambda: conv1d_5_1x3x14_st5_pd0_dl1, + "5_1x3x9_st5_pd0_dl1_needs_adjust_pass": lambda: conv1d_5_1x3x9_st5_pd0_dl1, + "two_conv1d_nobias": lambda: two_conv1d_nobias, + "two_conv1d": lambda: two_conv1d, +} + +test_data_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + + +@common.parametrize("test_data", test_data_FP) +def test_convolution_1d_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t]( + test_data(), + test_data().get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_1d_tosa_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_1d_u55_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_1d_u85_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_1d_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t]( + test_data(), + test_data().get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_1d_vgf_quant(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv2d.py new file mode 100644 index 0000000..55eee29 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv2d.py @@ -0,0 +1,592 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple, Union + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a8w4_quantization_config, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +aten_op = "torch.ops.aten.conv2d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + + +class Conv2d(torch.nn.Module): + """ + Creates one or many chained 2D-convolutions. For multiple convolutions, the + respective parameteres are provided as lists. + """ + + def __init__( + self, + height=8, + width=8, + nbr_conv=1, # Number of chained convs + in_channels: Union[List, int, None] = None, + out_channels: Union[List, int, None] = None, + kernel_size: Union[List, Tuple, None] = None, + stride: Union[List, Tuple, int, None] = None, + padding: Union[List, Tuple, int, None] = None, + dilation: Union[List, Tuple, int, None] = None, + groups: Union[List, int, None] = None, + bias: Union[List, bool, None] = None, + padding_mode: Union[List, str, None] = None, + batches=1, + dtype=torch.float, + ): + super().__init__() + self.nbr_convs = nbr_conv + + # Handle default values + in_channels = [2] * nbr_conv if in_channels is None else in_channels + out_channels = [1 * nbr_conv] if out_channels is None else out_channels + kernel_size = [(3, 3)] * nbr_conv if kernel_size is None else kernel_size + stride = [(2, 2)] * nbr_conv if stride is None else stride + padding = [(1, 1)] * nbr_conv if padding is None else padding + dilation = [(1, 1)] * nbr_conv if dilation is None else dilation + groups = [1] * nbr_conv if groups is None else groups + bias = [True] * nbr_conv if bias is None else bias + padding_mode = ["zeros"] * nbr_conv if padding_mode is None else padding_mode + + # This allows the input parameters to be either a single value or a list + # as type hint implies + if not isinstance(in_channels, List): + in_channels = [in_channels] + if not isinstance(out_channels, List): + out_channels = [out_channels] + if not isinstance(kernel_size, List): + kernel_size = [kernel_size] + if not isinstance(stride, List): + stride = [stride] + if not isinstance(padding, List): + padding = [padding] + if not isinstance(dilation, List): + dilation = [dilation] + if not isinstance(groups, List): + groups = [groups] + if not isinstance(bias, List): + bias = [bias] + if not isinstance(padding_mode, List): + padding_mode = [padding_mode] + + self.batches = batches + self.in_channels = in_channels + self.height = height + self.width = width + self.dtype = dtype + + # Build chain of convs + for i in range(self.nbr_convs): + setattr( + self, + f"conv_{i}", + torch.nn.Conv2d( + in_channels=in_channels[i], + out_channels=out_channels[i], + kernel_size=kernel_size[i], + stride=stride[i], + padding=padding[i], + dilation=dilation[i], + groups=groups[i], + bias=bias[i], + padding_mode=padding_mode[i], + ).to(dtype), + ) + + def get_inputs(self): + return ( + torch.randn(self.batches, self.in_channels[0], self.height, self.width).to( + self.dtype + ), + ) + + def forward(self, x): + for i in range(self.nbr_convs): + conv = getattr(self, f"conv_{i}") + x = conv(x) + return x + + +conv2d_2x2_3x2x14x14_nobias = Conv2d( + in_channels=2, + out_channels=3, + kernel_size=(2, 2), + stride=1, + bias=False, + padding=0, + width=14, + height=14, + batches=2, +) + +conv2d_3x3_1x3x24x24_st1 = Conv2d( + in_channels=3, + out_channels=10, + kernel_size=(3, 3), + stride=1, + padding=0, + width=24, + height=24, + batches=1, +) + +conv2d_3x3_1x3x12x12_st2_pd1 = Conv2d( + in_channels=3, + out_channels=4, + kernel_size=(3, 3), + stride=2, + padding=1, + width=12, + height=12, + batches=1, +) + +conv2d_1x1_1x2x16x16_st1 = Conv2d( + in_channels=2, + out_channels=1, + kernel_size=(1, 1), + stride=1, + padding=0, + width=16, + height=16, + batches=1, +) + +conv2d_2x2_2x1x14x13_st2 = Conv2d( + in_channels=2, + out_channels=1, + kernel_size=(2, 2), + stride=2, + padding=0, + width=14, + height=13, + batches=1, +) + +conv2d_5x5_3x2x24x24_st1 = Conv2d( + in_channels=2, + out_channels=3, + kernel_size=(5, 5), + stride=1, + padding=0, + width=24, + height=24, + batches=2, +) + +conv2d_3x3_1x3x28x28_st2_pd1 = Conv2d( + in_channels=3, + out_channels=16, + kernel_size=(3, 3), + stride=2, + padding=1, + width=28, + height=28, + batches=1, +) + +conv2d_5x5_1x3x14x15_st3_pd1 = Conv2d( + in_channels=3, + out_channels=16, + kernel_size=(5, 5), + stride=3, + padding=1, + width=14, + height=15, + batches=1, +) + +conv2d_7x7_1x3x16x16_st2_pd1_dl2 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7), + stride=2, + padding=1, + dilation=2, + width=16, + height=16, + batches=1, +) + +conv2d_7x7_1x3x15x15_st1_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7), + stride=1, + padding=0, + dilation=1, + width=15, + height=15, + batches=1, +) + +conv2d_5x5_1x3x14x14_st5_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5), + stride=5, + padding=0, + dilation=1, + width=14, + height=14, + batches=1, +) + +conv2d_5x5_1x3x9x9_st5_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5), + stride=5, + padding=0, + dilation=1, + width=9, + height=9, + batches=1, +) + +conv2d_3x3_1x3x8x9_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv2d_3x3_1x3x9x8_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv2d_3x4_1x3x7x7_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 4), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +conv2d_4x3_1x3x7x7_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(4, 3), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +two_conv2d_nobias = Conv2d( + nbr_conv=2, + width=32, + height=32, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[(5, 5), (5, 5)], + stride=[1, 1], + padding=[0, 0], + bias=[False, False], + batches=1, +) + +two_conv2d = Conv2d( + nbr_conv=2, + width=32, + height=32, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[(5, 5), (5, 5)], + stride=[1, 1], + padding=[0, 0], + bias=[True, True], + batches=1, +) + +conv2d_groups = Conv2d( + in_channels=12, + out_channels=9, + kernel_size=(3, 3), + stride=1, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, + groups=3, + bias=False, +) + +conv2d_groups_bias = Conv2d( + in_channels=15, + out_channels=5, + kernel_size=(3, 3), + stride=1, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, + groups=5, + bias=True, +) + +# Shenanigan to get a nicer output when test fails. With unittest it looks like: +# FAIL: test_convolution_2d_tosa_INT_2_3x3_1x3x12x12_st2_pd1 +test_data_FP = { + "2x2_3x2x14x14_nobias": lambda: conv2d_2x2_3x2x14x14_nobias, + "3x3_1x3x24x24_st1": lambda: conv2d_3x3_1x3x24x24_st1, + "3x3_1x3x12x12_st2_pd1": lambda: conv2d_3x3_1x3x12x12_st2_pd1, + "1x1_1x2x16x16_st1": lambda: conv2d_1x1_1x2x16x16_st1, + "2x2_2x1x14x13_st2_needs_adjust_pass": lambda: conv2d_2x2_2x1x14x13_st2, + "5x5_1x3x14x15_st3_pd1_needs_adjust_pass": lambda: conv2d_5x5_1x3x14x15_st3_pd1, + "7x7_1x3x16x16_st2_pd1_dl2_needs_adjust_pass": lambda: conv2d_7x7_1x3x16x16_st2_pd1_dl2, + "7x7_1x3x15x15_st1_pd0_dl1_needs_adjust_pass": lambda: conv2d_7x7_1x3x15x15_st1_pd0_dl1, + "5x5_1x3x14x14_st5_pd0_dl1_needs_adjust_pass": lambda: conv2d_5x5_1x3x14x14_st5_pd0_dl1, + "5x5_1x3x9x9_st5_pd0_dl1_needs_adjust_pass": lambda: conv2d_5x5_1x3x9x9_st5_pd0_dl1, + "3x3_1x3x9x8_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_3x3_1x3x9x8_st3_pd0_dl1, + "3x3_1x3x8x9_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_3x3_1x3x8x9_st3_pd0_dl1, + "3x4_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_3x4_1x3x7x7_st3_pd0_dl1, + "4x3_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_4x3_1x3x7x7_st3_pd0_dl1, + "5x5_3x2x24x24_st1": lambda: conv2d_5x5_3x2x24x24_st1, + "3x3_1x3x28x28_st2_pd1": lambda: conv2d_3x3_1x3x28x28_st2_pd1, + "two_conv2d_nobias": lambda: two_conv2d_nobias, + "two_conv2d": lambda: two_conv2d, + "groups": lambda: conv2d_groups, + "groups_bias": lambda: conv2d_groups_bias, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + +input_t = Tuple[torch.Tensor] + + +def _get_dtype_count(model: torch.nn.Module): + nbr_convs: int = model.nbr_convs # noqa + return { + "CONST": {"INT4": nbr_convs * 2}, # One for the weight, one for the zp. + "CONV2D": {"INT32": nbr_convs}, + "RESCALE": {"INT8": nbr_convs}, + } + + +@common.parametrize("test_data", test_data_FP) +def test_convolution_2d_tosa_FP(test_data): + model = test_data() + pipeline = TosaPipelineFP[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_2d_tosa_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_INT, + xfails={ + "groups,per_channel_quant=True": "Int4 not supported for grouped convolutions. MLETORCH-1726", + "groups,per_channel_quant=False": "Int4 not supported for grouped convolutions. MLETORCH-1726", + "groups_bias,per_channel_quant=True": "Int4 not supported for grouped convolutions. MLETORCH-1726", + "groups_bias,per_channel_quant=False": "Int4 not supported for grouped convolutions. MLETORCH-1726", + }, +) +def test_convolution_2d_tosa_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + tosa_extensions=["int4"], + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + _get_dtype_count(model), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_2d_u55_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_u85_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_2d_u85_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant(test_data): + model = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +reject_suite = { + "large_stride": lambda: Conv2d( + in_channels=1, + out_channels=1, + kernel_size=(2, 4), + stride=(2, 4), + padding=1, + width=10, + height=14, + batches=1, + ), + "large_kernel_height": lambda: Conv2d( + in_channels=1, + out_channels=1, + kernel_size=(2, 65), + stride=(1, 1), + padding=0, + width=70, + height=70, + batches=1, + ), + "large_kernel": lambda: Conv2d( + in_channels=1, + out_channels=1, + kernel_size=(70, 60), + stride=(1,), + padding=0, + width=80, + height=80, + batches=1, + ), +} + + +@common.parametrize("module", reject_suite) +def test_convolution_2d_u55_INT_not_delegated(module: Conv2d): + OpNotSupportedPipeline( + module(), + module().get_inputs(), + {"executorch_exir_dialects_edge__ops_aten_convolution_default": 1}, + quantize=True, + u55_subset=True, + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv3d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv3d.py new file mode 100644 index 0000000..f28315d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv3d.py @@ -0,0 +1,711 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple, Union + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_a8w4_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.conv3d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + + +class Conv3d(torch.nn.Module): + """ + Creates one or many chained 3D-convolutions. For multiple convolutions, the + respective parameteres are provided as lists. + """ + + def __init__( + self, + height=8, + width=8, + depth=8, + nbr_conv=1, # Number of chained convs + in_channels: Union[List, int, None] = None, + out_channels: Union[List, int, None] = None, + kernel_size: Union[List, Tuple, None] = None, + stride: Union[List, Tuple, int, None] = None, + padding: Union[List, Tuple, int, None] = None, + dilation: Union[List, Tuple, int, None] = None, + groups: Union[List, int, None] = None, + bias: Union[List, bool, None] = None, + padding_mode: Union[List, str, None] = None, + batches=1, + dtype=torch.float, + ): + super().__init__() + self.nbr_convs = nbr_conv + + # Handle default values + in_channels = [2] * nbr_conv if in_channels is None else in_channels + out_channels = [1 * nbr_conv] if out_channels is None else out_channels + kernel_size = [(3, 3, 1)] * nbr_conv if kernel_size is None else kernel_size + stride = [(2, 2, 1)] * nbr_conv if stride is None else stride + padding = [(1, 1, 1)] * nbr_conv if padding is None else padding + dilation = [(1, 1, 1)] * nbr_conv if dilation is None else dilation + groups = [1] * nbr_conv if groups is None else groups + bias = [True] * nbr_conv if bias is None else bias + padding_mode = ["zeros"] * nbr_conv if padding_mode is None else padding_mode + + # This allows the input parameters to be either a single value or a list + # as type hint implies + if not isinstance(in_channels, List): + in_channels = [in_channels] + if not isinstance(out_channels, List): + out_channels = [out_channels] + if not isinstance(kernel_size, List): + kernel_size = [kernel_size] + if not isinstance(stride, List): + stride = [stride] + if not isinstance(padding, List): + padding = [padding] + if not isinstance(dilation, List): + dilation = [dilation] + if not isinstance(groups, List): + groups = [groups] + if not isinstance(bias, List): + bias = [bias] + if not isinstance(padding_mode, List): + padding_mode = [padding_mode] + + self.batches = batches + self.in_channels = in_channels + self.height = height + self.width = width + self.depth = depth + self.dtype = dtype + + # Build chain of convs + for i in range(self.nbr_convs): + setattr( + self, + f"conv_{i}", + torch.nn.Conv3d( + in_channels=in_channels[i], + out_channels=out_channels[i], + kernel_size=kernel_size[i], + stride=stride[i], + padding=padding[i], + dilation=dilation[i], + groups=groups[i], + bias=bias[i], + padding_mode=padding_mode[i], + ).to(dtype), + ) + + def get_inputs(self): + return ( + torch.randn( + self.batches, + self.in_channels[0], + self.depth, + self.height, + self.width, + ).to(self.dtype), + ) + + def forward(self, x): + for i in range(self.nbr_convs): + conv = getattr(self, f"conv_{i}") + x = conv(x) + return x + + +class Conv3dMultiOp(torch.nn.Module): + """ + Mixed Conv3d/Conv2d pipeline used to verify spatial-rank propagation across ops. + + Topology: + conv3d -> reshape -> conv2d -> reshape/permutation -> conv2d -> reshape -> add(5D) + """ + + def __init__(self, dtype=torch.float): + super().__init__() + self.dtype = dtype + self.conv3d = torch.nn.Conv3d( + in_channels=2, + out_channels=4, + kernel_size=(3, 3, 3), + stride=1, + padding=1, + ).to(dtype) + self.conv2d_main = torch.nn.Conv2d( + in_channels=4, + out_channels=4, + kernel_size=3, + stride=1, + padding=1, + ).to(dtype) + self.conv2d_pointwise = torch.nn.Conv2d( + in_channels=4, + out_channels=4, + kernel_size=1, + stride=1, + padding=0, + ).to(dtype) + self.activation = torch.nn.ReLU() + + def get_inputs(self): + return (torch.randn(1, 2, 3, 8, 8).to(self.dtype),) + + def forward(self, x): + x3d = self.conv3d(x) + batches, channels, depth, height, width = x3d.shape + + reshaped = x3d.reshape(batches * depth, channels, height, width) + conv2d_out = self.activation(self.conv2d_main(reshaped)) + + conv2d_out_5d = ( + conv2d_out.reshape(batches, depth, channels, height, width) + .permute(0, 2, 1, 3, 4) + .contiguous() + ) + + reshaped_again = conv2d_out_5d.permute(0, 2, 1, 3, 4).reshape( + batches * depth, channels, height, width + ) + conv2d_pointwise_out = self.conv2d_pointwise(reshaped_again) + conv2d_pointwise_out_5d = ( + conv2d_pointwise_out.reshape(batches, depth, channels, height, width) + .permute(0, 2, 1, 3, 4) + .contiguous() + ) + + return conv2d_pointwise_out_5d + x3d + + +class DepthwiseConv3d(torch.nn.Module): + def __init__(self, dtype=torch.float): + super().__init__() + self.dtype = dtype + self.conv = torch.nn.Conv3d( + in_channels=2, + out_channels=4, + kernel_size=(3, 3, 3), + padding=1, + groups=2, + ).to(dtype) + + def get_inputs(self): + return (torch.randn(1, 2, 3, 8, 8).to(self.dtype),) + + def forward(self, x): + return self.conv(x) + + +conv3d_2x2_3x2x14x14_nobias = Conv3d( + in_channels=2, + out_channels=3, + kernel_size=(2, 2, 2), + stride=1, + bias=False, + padding=0, + width=14, + height=14, + batches=2, +) + +conv3d_3x3_1x3x24x24_st1 = Conv3d( + in_channels=3, + out_channels=10, + kernel_size=(3, 3, 3), + stride=1, + padding=0, + width=24, + height=24, + batches=1, +) + +conv3d_3x3_1x3x12x12_st2_pd1 = Conv3d( + in_channels=3, + out_channels=4, + kernel_size=(3, 3, 3), + stride=2, + padding=1, + width=12, + height=12, + batches=1, +) + +conv3d_1x1_1x2x16x16_st1 = Conv3d( + in_channels=2, + out_channels=1, + kernel_size=(1, 1, 1), + stride=1, + padding=0, + width=16, + height=16, + batches=1, +) + +conv3d_2x2_1x1x14x13_st2 = Conv3d( + in_channels=1, + out_channels=1, + kernel_size=(2, 2, 2), + stride=2, + padding=0, + width=14, + height=13, + batches=1, +) + +conv3d_5x5_3x2x24x24_st1 = Conv3d( + in_channels=2, + out_channels=3, + kernel_size=(5, 5, 5), + stride=1, + padding=0, + width=24, + height=24, + batches=2, +) + +conv3d_3x3_1x3x28x28_st2_pd1 = Conv3d( + in_channels=3, + out_channels=16, + kernel_size=(3, 3, 3), + stride=2, + padding=1, + width=28, + height=28, + batches=1, +) + +conv3d_5x5_1x3x14x15_st3_pd1 = Conv3d( + in_channels=3, + out_channels=16, + kernel_size=(5, 5, 5), + stride=3, + padding=1, + width=14, + height=15, + batches=1, +) + +conv3d_7x7_1x3x16x16_st2_pd1_dl2 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7, 7), + stride=2, + padding=3, + dilation=1, + width=16, + height=16, + batches=1, +) + +conv3d_7x7_1x3x15x15_st1_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7, 7), + stride=1, + padding=0, + dilation=1, + width=15, + height=15, + batches=1, +) + +conv3d_5x5_1x3x14x14_st5_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5, 5), + stride=5, + padding=0, + dilation=1, + width=14, + height=14, + batches=1, +) + +conv3d_5x5_1x3x9x9_st5_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5, 5), + stride=5, + padding=0, + dilation=1, + width=9, + height=9, + batches=1, +) + +conv3d_3x3_1x3x8x9_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv3d_3x3_1x3x9x8_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv3d_3x4_1x3x7x7_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(3, 4, 3), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +conv3d_4x3_1x3x7x7_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(4, 3, 3), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +test_data_FP = { + "2x2_3x2x14x14_nobias": lambda: conv3d_2x2_3x2x14x14_nobias, + "3x3_1x3x24x24_st1": lambda: conv3d_3x3_1x3x24x24_st1, + "3x3_1x3x12x12_st2_pd1": lambda: conv3d_3x3_1x3x12x12_st2_pd1, + "1x1_1x2x16x16_st1": lambda: conv3d_1x1_1x2x16x16_st1, + "2x2_1x1x14x13_st2_needs_adjust_pass": lambda: conv3d_2x2_1x1x14x13_st2, + "5x5_1x3x14x15_st3_pd1_needs_adjust_pass": lambda: conv3d_5x5_1x3x14x15_st3_pd1, + "7x7_1x3x16x16_st2_pd1_dl2_needs_adjust_pass": lambda: conv3d_7x7_1x3x16x16_st2_pd1_dl2, + "7x7_1x3x15x15_st1_pd0_dl1_needs_adjust_pass": lambda: conv3d_7x7_1x3x15x15_st1_pd0_dl1, + "5x5_1x3x14x14_st5_pd0_dl1_needs_adjust_pass": lambda: conv3d_5x5_1x3x14x14_st5_pd0_dl1, + "5x5_1x3x9x9_st5_pd0_dl1_needs_adjust_pass": lambda: conv3d_5x5_1x3x9x9_st5_pd0_dl1, + "3x3_1x3x9x8_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_3x3_1x3x9x8_st3_pd0_dl1, + "3x3_1x3x8x9_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_3x3_1x3x8x9_st3_pd0_dl1, + "3x4_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_3x4_1x3x7x7_st3_pd0_dl1, + "4x3_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_4x3_1x3x7x7_st3_pd0_dl1, + "5x5_3x2x24x24_st1": lambda: conv3d_5x5_3x2x24x24_st1, + "3x3_1x3x28x28_st2_pd1": lambda: conv3d_3x3_1x3x28x28_st2_pd1, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + +test_data_INT16 = { + f"{k},16a8w,per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + + +def _get_dtype_count(model: torch.nn.Module): + nbr_convs: int = model.nbr_convs # noqa + return { + "CONST": {"INT4": nbr_convs * 2}, + "CONV3D": {"INT32": nbr_convs}, + "RESCALE": {"INT8": nbr_convs}, + } + + +def get_symmetric_a16w8_conv3d_quantizer(per_channel_quantization: bool = False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quant_config = get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ) + quantizer.set_global(quant_config) + quantizer.set_module_type(torch.nn.Conv3d, quant_config) + + return Quantize( + quantizer, + quant_config, + ) + + +input_t = Tuple[torch.Tensor] + + +@common.parametrize("test_data", test_data_FP) +def test_convolution_3d_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t]( + test_data(), test_data().get_inputs(), aten_op, exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_3d_tosa_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_3d_tosa_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + tosa_extensions=["int4"], + qtol=1, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + _get_dtype_count(model), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT16) +def test_convolution_3d_tosa_INT_a16w8(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + qtol=1, + ) + pipeline.change_args( + "quantize", + get_symmetric_a16w8_conv3d_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +def test_convolution_3d_tosa_FP_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = TosaPipelineFP[input_t](model, model.get_inputs(), aten_op, exir_op) + pipeline.run() + + +def test_convolution_3d_tosa_INT_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +def test_convolution_3d_tosa_FP_depthwise(): + """Depthwise or Grouped Conv3d should be rejected until grouped support exists.""" + model = DepthwiseConv3d() + pipeline = TosaPipelineFP[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + run_on_tosa_ref_model=False, + ) + with pytest.raises(RuntimeError, match="CONV3D with groups != 1"): + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U55 does not support CONV3D yet.") +def test_convolution_3d_u55_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U55 does not support CONV3D yet.") +def test_convolution_3d_u55_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U85 does not support CONV3D yet.") +def test_convolution_3d_u85_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U85 does not support CONV3D yet.") +def test_convolution_3d_u85_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t]( + test_data(), + test_data().get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_quant(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_no_quant_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_quant_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +reject_suite = { + "large_stride": lambda: Conv3d( + in_channels=1, + out_channels=1, + kernel_size=(2, 2, 1), + stride=(2, 4, 2), + padding=1, + width=10, + height=14, + batches=1, + ), + "large_kernel_z": lambda: Conv3d( + in_channels=1, + out_channels=1, + kernel_size=(2, 2, 2), + stride=1, + padding=0, + width=80, + height=80, + batches=1, + ), +} + + +@common.parametrize("module", reject_suite) +def test_convolution_u55_INT_not_delegated_3d(module: Conv3d): + OpNotSupportedPipeline( + module(), + module().get_inputs(), + {"executorch_exir_dialects_edge__ops_aten_convolution_default": 1}, + quantize=True, + u55_subset=True, + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_combos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_combos.py new file mode 100644 index 0000000..1b69768 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_combos.py @@ -0,0 +1,668 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + +from torch.nn.parameter import Parameter + + +""" +This file contain unit tests where conv are combined with other ops. +""" + + +class ComboBlockBottleneckResidual(torch.nn.Module): + # This is the essence of MobileNetV2. Ref: https://arxiv.org/abs/1801.04381 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default", + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + test_data_INT = { + "per_channel_quant=True": True, + "per_channel_quant=False": False, + } + + def __init__(self): + super().__init__() + # (t, c, n, s) = (6, 96, 1, 1) + # 1. 1x1 CONV2d + ReLU6 (Pointwise) + self.pointwise_conv2d = torch.nn.Conv2d( + in_channels=16, out_channels=96, kernel_size=1, stride=1, groups=1 + ) ## Example output shape (1, 96, 33, 33) + self.batch_norm2d_16 = torch.nn.BatchNorm2d(96, affine=False) + self.relu6 = torch.nn.ReLU6() + + # 2. 3x3 DepthwiseConv2d + ReLu6 + self.depthwise_conv2d = torch.nn.Conv2d( + in_channels=96, + out_channels=96, + kernel_size=3, + padding=1, + stride=1, + groups=96, + ) ## Example output shape (1, 96, H, W) + + # 3. Linear 1x1 Conv2d + self.pointwise_conv2d_linear = torch.nn.Conv2d( + in_channels=96, out_channels=16, kernel_size=1, stride=1, groups=1 + ) ## Example output shape (1, 16, 33, 33) + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 16, 33, 33),) + + def forward(self, x): + input = x + # 1x1 CONV2d + ReLU6 (Pointwise) + x = self.pointwise_conv2d(x) + x = self.batch_norm2d_16(x) + x = self.relu6(x) + + # 3x3 DepthwiseConv2d + ReLu6 + x = self.depthwise_conv2d(x) + x = self.batch_norm2d_16(x) + x = self.relu6(x) + + # Linear 1x1 Conv2d + x = self.pointwise_conv2d_linear(x) + + # Final Residual Connection + x = x + input + + return x + + +class ComboConv2dMeandim(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten_mean_dim", + ] + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=10, kernel_size=5, stride=1, bias=False + ) + # will be specialized to aten.mean.dim + self.adaptive_avg_pool2d = torch.nn.AdaptiveAvgPool2d((1, 1)) + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 3, 48, 48),) + + def forward(self, x): + x = self.conv2d(x) + return self.adaptive_avg_pool2d(x) + + +class ComboConvBatchnormRelu6(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default", + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + ] + + test_data_FP = { + "affine=True": True, + "affine=False": False, + } + + test_data_INT = { + "affine=True,per_channel_quant=True": (True, True), + "affine=True,per_channel_quant=False": (True, False), + "affine=False,per_channel_quant=True": (False, True), + "affine=False,per_channel_quant=False": (False, False), + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + self.batch_norm2d.weight = Parameter(torch.rand(3)) + self.batch_norm2d.bias = Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 3, 64, 64),) + + def forward(self, x): + x = self.conv2d(x) + x = self.batch_norm2d(x) + x = self.relu6(x) + return x + + +class ComboConvRelu6(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + ] + + test_data_FP = { + "combo_conv_relu_2_x_4d": lambda: (2 * torch.randn(1, 3, 64, 64),), + "combo_conv_relu_0_5_x_4d": lambda: (0.5 * torch.randn(1, 3, 64, 64),), + "combo_conv_relu_4d": lambda: (torch.randn(1, 3, 64, 64),), + "combo_conv_relu_neg_0_5_x_4d": lambda: (-0.5 * torch.randn(1, 3, 64, 64),), + "combo_conv_relu_neg_2_x_4d": lambda: (-2 * torch.randn(1, 3, 64, 64),), + } + + # Generate a new test set paired with per_channel_quant=True/False. + test_data_INT = { + # test_name: (input, per_channel_quant) + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] + } + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.relu6 = torch.nn.ReLU6() + + def forward(self, x): + x = self.conv2d(x) + x = self.relu6(x) + return x + + +class ComboConvAvgPool2d(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default", + ] + + test_data_FP = { + "combo_conv_avgpool_20_x_4d": lambda: (20 * torch.randn(1, 3, 48, 24),), + "combo_conv_avgpool_4d": lambda: (torch.randn(1, 3, 60, 120),), + "combo_conv_avgpool_5_x_4d_randn": lambda: (5 * torch.randn(1, 3, 64, 64),), + "combo_conv_avgpool_2_x_4d": lambda: (torch.rand(1, 3, 96, 32),), + } + + # Generate a new test set paired with per_channel_quant=True/False. + test_data_INT = { + # test_name: (input, per_channel_quant) + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] + } + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.avg_pool2d = torch.nn.AvgPool2d(kernel_size=(2, 2)) + + def forward(self, x): + x = self.conv2d(x) + x = self.avg_pool2d(x) + return x + + +#################### +## Conv + meandim ## +#################### + + +def test_convolution_2d_tosa_FP_meandim(): + model = ComboConv2dMeandim() + pipeline = TosaPipelineFP[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +def test_convolution_2d_tosa_INT_meandim(): + model = ComboConv2dMeandim() + pipeline = TosaPipelineINT[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_meandim(): + model = ComboConv2dMeandim() + pipeline = EthosU55PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_meandim(): + model = ComboConv2dMeandim() + pipeline = EthosU85PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_meandim(): + model = ComboConv2dMeandim() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_meandim(): + model = ComboConv2dMeandim() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + quantize=True, + ) + pipeline.run() + + +############################## +## Conv + batch norm + relu ## +############################## + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_FP) +def test_convolution_2d_tosa_FP_batchnorm_relu6(test_data): + affine = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = TosaPipelineFP[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +def test_convolution_2d_tosa_INT_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = TosaPipelineINT[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = EthosU55PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = EthosU85PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_batchnorm_relu6(test_data): + affine = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +################## +## Conv + ReLU6 ## +################## + + +@common.parametrize("test_data", ComboConvRelu6.test_data_FP) +def test_convolution_2d_tosa_FP_relu6(test_data): + model = ComboConvRelu6() + pipeline = TosaPipelineFP[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +def test_convolution_2d_tosa_INT_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = TosaPipelineINT[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = EthosU55PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = EthosU85PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_relu6(test_data): + model = ComboConvRelu6() + pipeline = VgfPipeline[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = VgfPipeline[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +############################### +## Block bottleneck residual ## +############################### +def test_convolution_2d_tosa_FP_block_bottleneck(): + model = ComboBlockBottleneckResidual() + pipeline = TosaPipelineFP[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +def test_convolution_2d_tosa_INT_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = TosaPipelineINT[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.change_args("run_method_and_compare_outputs", model.get_inputs(), qtol=1) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = EthosU55PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = EthosU85PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_block_bottleneck(): + model = ComboBlockBottleneckResidual() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +###################### +## Conv + AvgPool2d ## +###################### + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_FP) +def test_convolution_2d_tosa_FP_avgpool2d(test_data): + model = ComboConvAvgPool2d() + pipeline = TosaPipelineFP[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +def test_convolution_2d_tosa_INT_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = TosaPipelineINT[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = EthosU55PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = EthosU85PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_avgpool2d(test_data): + model = ComboConvAvgPool2d() + pipeline = VgfPipeline[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = VgfPipeline[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_constant_pad_nd.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_constant_pad_nd.py new file mode 100644 index 0000000..aecce1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_conv_constant_pad_nd.py @@ -0,0 +1,145 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Test the pad_constant_nd op which pads the input tensor at specific dimension(s). +# + +from typing import Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.pad.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_pad_default" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + "4dim_last1dim": (torch.rand(1, 1, 16, 16), (1, 1, 0, 0, 0, 0, 0, 0), 1), + "4dim_last2dim": (torch.rand(1, 1, 16, 16), (1, 0, 1, 0, 0, 0, 0, 0), 2), + "4dim_last3dim": (torch.rand(1, 1, 16, 16), (1, 1, 0, 2, 0, 2, 0, 0), 3), + "4dim_last4dim": (torch.rand(1, 1, 16, 16), (1, 0, 1, 1, 0, 2, 0, 2), 4), + "3dim_last1dim": (torch.rand(1, 1, 16), (1, 1, 0, 0, 0, 0), 1), + "3dim_last2dim": (torch.rand(1, 1, 16), (1, 0, 1, 1, 0, 0), 2), + "3dim_last3dim": (torch.rand(1, 1, 16), (1, 0, 1, 0, 1, 1), 3), + "2dim_last1dim": (torch.rand(1, 1, 16), (1, 1, 0, 0), 1), + "2dim_last2dim": (torch.rand(1, 1, 16), (1, 0, 1, 1), 2), +} + + +"""Tests conv + pad.""" + + +class ConstantPadND(torch.nn.Module): + def __init__(self, pad: Tuple, value: float | None = None): + super().__init__() + self.dim = len(pad) // 2 + self.value = value + in_channels = 1 + # Only apply conv2d when the input dim = 4. + if self.dim == 4: + in_channels += pad[-3] + pad[-4] + + self.conv2d = nn.Conv2d( + in_channels=in_channels, + out_channels=3, + kernel_size=3, + bias=True, + stride=(2, 2), + padding=0, + ) + + in_channels = 3 + in_channels += pad[-3] + pad[-4] + self.conv2d_1 = nn.Conv2d( + in_channels=in_channels, + out_channels=3, + kernel_size=3, + bias=True, + padding="same", + ) + + nonzero_idx = len(pad) + for i in range(0, len(pad), 2): + if pad[i] + pad[i + 1] == 0: + nonzero_idx = i + break + self.pad = pad[:nonzero_idx] + self.relu = nn.ReLU() + self.sigmoid = nn.Sigmoid() + + def forward(self, x: torch.Tensor): + x = F.pad(x, pad=self.pad, mode="constant", value=self.value) + if self.dim == 4: + x = self.conv2d(x) + x = self.relu(x) + + x = F.pad(x, pad=self.pad, mode="constant", value=self.value) + if self.dim == 4: + x = self.conv2d_1(x) + x = self.sigmoid(x) + return x + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_FP(test_data: Tuple): + test_data, padding, value = test_data + pipeline = TosaPipelineFP[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_INT(test_data: Tuple): + test_data, padding, value = test_data + pipeline = TosaPipelineINT[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + atol=0.005, # TODO: Investigate flakyness (MLETORCH-989) + rtol=0.01, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_no_quant(test_data: Tuple): + test_data, padding, value = test_data + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_quant(test_data: Tuple): + test_data, padding, value = test_data + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_copy.py new file mode 100644 index 0000000..556e952 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_copy.py @@ -0,0 +1,171 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class CopyOutput(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return y.copy_(x / x) + x + + +class CopyFirstArg(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return y.copy_(x) + x + + +class CopySecondArg(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return x * y.copy_(x) + + +class CopyBothArgs(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return y.copy_(x) + y.copy_(x) + + +class CopyAfterOtherOp(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + x = x * 2 + return y.copy_(x) + x + + +class CopyParallelToOtherOp(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return x * 2 + y.copy_(x) + + +test_suite = { + "copy_output": lambda: ( + CopyOutput, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_first_arg": lambda: ( + CopyFirstArg, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_second_arg": lambda: ( + CopySecondArg, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_both_args": lambda: ( + CopyBothArgs, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_after_other_op": lambda: ( + CopyAfterOtherOp, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_parallel_to_other_op": lambda: ( + CopyParallelToOtherOp, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), +} + + +aten_op = "torch.ops.aten.copy_.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_copy_default" + +input_t = Tuple[torch.Tensor] + + +@common.parametrize("input_data", test_suite) +def test_copy_tosa_FP(input_data): + module, input_tensor = input_data() + pipeline = TosaPipelineFP[input_t]( + module(), + input_tensor, + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", test_suite) +def test_copy_tosa_INT(input_data): + module, input_tensor = input_data() + + pipeline = TosaPipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", test_suite) +@common.XfailIfNoCorstone300 +def test_copy_u55_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU55PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", test_suite) +@common.XfailIfNoCorstone320 +def test_copy_u85_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU85PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_suite) +@common.SkipIfNoModelConverter +def test_copy_vgf_no_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_suite) +@common.SkipIfNoModelConverter +def test_copy_vgf_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cos.py new file mode 100644 index 0000000..4268611 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cos.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.cos.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10, 10), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Cos(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.cos(x) + + +@common.parametrize("test_data", test_data_suite) +@pytest.mark.tosa_ref_model +def test_cos_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + if conftest.get_option("tosa_version") == "1.0": + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@pytest.mark.tosa_ref_model +def test_cos_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_cos_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_cos_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cos_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cos_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cosh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cosh.py new file mode 100644 index 0000000..a07b3ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cosh.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.cosh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__cosh_default" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10), + "zeros_4D": torch.zeros(1, 10, 32, 7), + "zeros_alt_shape": torch.zeros(10, 3, 5), + "ones": torch.ones(15, 10, 7), + "ones_4D": torch.ones(1, 3, 32, 16), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(10, 3, 5) - 0.5, + "rand_4D": torch.rand(1, 6, 5, 7) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), + "large": 100 * torch.ones(1, 1), + "small": 0.000001 * torch.ones(1, 1), + "small_rand": torch.rand(100) * 0.01, + "biggest": torch.tensor([700.0, 710.0, 750.0]), +} + + +class Cosh(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.cosh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_cosh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Cosh(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_cosh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Cosh(), (test_data,), aten_op=aten_op, exir_op=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_cosh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Cosh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize( + "test_data", + test_data_suite, + strict=False, +) +def test_cosh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Cosh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cosh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cosh(), + (test_data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cosh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cosh(), + (test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cumsum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cumsum.py new file mode 100644 index 0000000..09afd57 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_cumsum.py @@ -0,0 +1,122 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, int] +aten_op = "torch.ops.aten.cumsum.default" + +""" +Tests the aten.cumsum operator by decomposing it into a convolution and +verifying results across various dims and pipelines. +""" + + +class CumsumModule(torch.nn.Module): + test_parameters = { + "1d_dim0": lambda: (torch.rand(10), 0), + "1d_dim_neg1": lambda: (torch.rand(10), -1), + "2d_dim1": lambda: (torch.rand(5, 6), 1), + "3d_dim2": lambda: (torch.rand(2, 3, 4), 2), + "3d_dim0": lambda: (torch.rand(2, 3, 4), 0), + "4d_dim3": lambda: (torch.rand(1, 2, 3, 4), 3), + "4d_dim1": lambda: (torch.rand(1, 2, 3, 4), 1), + } + + def forward(self, x: torch.Tensor, dim: int) -> torch.Tensor: + return torch.cumsum(x, dim) + + +@common.parametrize("test_data", CumsumModule.test_parameters) +def test_cumsum_tosa_FP(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + args, + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +def test_cumsum_tosa_INT(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + args, + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.SkipIfNoModelConverter +def test_cumsum_vgf_no_quant(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.SkipIfNoModelConverter +def test_cumsum_vgf_quant(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.XfailIfNoCorstone300 +def test_cumsum_u55_INT(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + args, + aten_ops=aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.XfailIfNoCorstone320 +def test_cumsum_u85_INT(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + args, + aten_ops=aten_op, + exir_ops=[], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_depthwise_conv.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_depthwise_conv.py new file mode 100644 index 0000000..b4289f9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_depthwise_conv.py @@ -0,0 +1,404 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a8w4_quantization_config, +) +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x + +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + +from executorch.backends.arm.test.ops.test_conv1d import Conv1d +from executorch.backends.arm.test.ops.test_conv2d import Conv2d + + +""" +The configuration when + groups == in_channels and + out_channels = K * in_channels + where K is a positive integer +is termed in literature as depthwise convolution. +""" + +dw_conv1d_3_1x3x14_gp3_st1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=7, + stride=1, + groups=3, + length=14, + batches=1, + padding=3, +) + +dw_conv1d_2_1x6x4_gp6_st1 = Conv1d( + in_channels=6, + out_channels=12, + kernel_size=2, + stride=1, + groups=6, + padding=0, + length=4, + batches=1, +) + +dw_conv2d_2x2_1x6x4x4_gp6_st1 = Conv2d( + in_channels=6, + out_channels=12, + kernel_size=(2, 2), + stride=(1, 1), + groups=6, + padding=0, + width=4, + height=4, + batches=1, +) + +dw_conv1d_3_1x3x32_gp3_st1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=3, + stride=1, + groups=3, + padding=0, + length=32, + batches=1, +) + +dw_conv2d_3x3_1x3x24x24_gp3_st1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3), + stride=(1, 1), + groups=3, + padding=0, + width=24, + height=24, + batches=1, +) + +dw_conv2d_3x3_1x4x24x24_gp4_st1 = Conv2d( + in_channels=4, + out_channels=8, + kernel_size=(3, 3), + stride=(1, 1), + groups=4, + padding=0, + width=24, + height=24, + batches=1, +) + +dw_conv2d_3x3_2x8x27x27_gp8_st3 = Conv2d( + in_channels=8, + out_channels=16, + kernel_size=(3, 3), + stride=3, + groups=8, + padding=0, + width=27, + height=27, + batches=2, +) + +dw_conv2d_3x3_1x4x24x24_gp4_nobias = Conv2d( + in_channels=4, + out_channels=8, + kernel_size=(3, 3), + stride=1, + groups=4, + bias=False, + width=24, + height=24, + batches=1, +) + +two_dw_conv1d = Conv1d( + nbr_conv=2, + length=16, + in_channels=[4, 8], + out_channels=[8, 24], + kernel_size=[3, 3], + stride=[1, 1], + padding=[0, 0], + groups=[4, 8], + bias=[True, True], + batches=1, +) + +two_dw_conv2d = Conv2d( + nbr_conv=2, + width=24, + height=24, + in_channels=[4, 8], + out_channels=[8, 24], + kernel_size=[(3, 3), (3, 3)], + stride=[1, 1], + padding=[0, 0], + groups=[4, 8], + bias=[True, True], + batches=2, +) + +# Shenanigan to get a nicer output when test fails. +test_data_conv2d_FP = { + "2x2_1x6x4x4_gp6_st1": lambda: dw_conv2d_2x2_1x6x4x4_gp6_st1, + "3x3_1x3x24x24_gp3_st1": lambda: dw_conv2d_3x3_1x3x24x24_gp3_st1, + "3x3_1x4x24x24_gp4_nobias": lambda: dw_conv2d_3x3_1x4x24x24_gp4_nobias, + "3x3_1x4x24x24_gp4_st1": lambda: dw_conv2d_3x3_1x4x24x24_gp4_st1, + "3x3_2x8x27x27_gp8_st3": lambda: dw_conv2d_3x3_2x8x27x27_gp8_st3, + "two_dw_conv2d": lambda: two_dw_conv2d, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_conv2d_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_conv2d_FP.items() + for q in [True, False] +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_conv2d_u85 = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in { + "2x2_1x6x4x4_gp6_st1": lambda: dw_conv2d_2x2_1x6x4x4_gp6_st1, + "3x3_1x3x24x24_gp3_st1": lambda: dw_conv2d_3x3_1x3x24x24_gp3_st1, + "3x3_1x4x24x24_gp4_st1": lambda: dw_conv2d_3x3_1x4x24x24_gp4_st1, + "3x3_1x4x24x24_gp4_nobias": lambda: dw_conv2d_3x3_1x4x24x24_gp4_nobias, + }.items() + for q in [True, False] +} + +test_data_conv1d_FP = { + "2_1x6x4_gp6_st1": lambda: dw_conv1d_2_1x6x4_gp6_st1, + "two_dw_conv1d": lambda: two_dw_conv1d, + "3_1x3x32_gp3_st1": lambda: dw_conv1d_3_1x3x32_gp3_st1, + "3_1x3x14_gp3_st1": lambda: dw_conv1d_3_1x3x14_gp3_st1, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_conv1d_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_conv1d_FP.items() + for q in [True, False] +} + + +def _get_dtype_count(model: torch.nn.Module): + nbr_convs: int = model.nbr_convs # noqa + return { + "CONST": {"INT4": nbr_convs * 2}, + "DEPTHWISE_CONV2D": {"INT32": nbr_convs}, + "RESCALE": {"INT8": nbr_convs}, + } + + +@common.parametrize("test_data", test_data_conv1d_FP | test_data_conv2d_FP) +def test_convolution_2d_tosa_FP_depthwise(test_data: torch.nn.Module): + pipeline = TosaPipelineFP[input_t]( + test_data(), + test_data().get_inputs(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", test_data_conv1d_INT | test_data_conv2d_INT) +def test_convolution_2d_tosa_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_conv1d_INT | test_data_conv2d_INT) +def test_convolution_2d_tosa_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + tosa_extensions=["int4"], + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + _get_dtype_count(model), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_conv1d_FP | test_data_conv2d_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_depthwise(test_data: torch.nn.Module): + model = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_conv1d_INT | test_data_conv2d_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u55_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u55_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u55_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u55_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u85_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u85_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u85_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u85_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div.py new file mode 100644 index 0000000..9e932b1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div.py @@ -0,0 +1,151 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Optional, Tuple, Union + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.div.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_div_Tensor" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, input, other, rounding_mode) See torch.div() for info + "op_div_rank1_ones": lambda: (torch.ones(5), torch.ones(5), None), + "op_div_rank1_negative_ones": lambda: ( + torch.ones(5) * (-1), + torch.ones(5) * (-1), + None, + ), + "op_div_rank1_rand": lambda: ( + torch.rand(5) * 5, + torch.rand(5) * 5, + None, + ), + "op_div_rank4_ones": lambda: ( + torch.ones(5, 10, 25, 20), + torch.ones(5, 10, 25, 20), + None, + ), + "op_div_rank4_negative_ones": lambda: ( + (-1) * torch.ones(5, 10, 25, 20), + torch.ones(5, 10, 25, 20), + None, + ), + "op_div_rank4_ones_div_negative": lambda: ( + torch.ones(5, 10, 25, 20), + (-1) * torch.ones(5, 10, 25, 20), + None, + ), + "op_div_rank4_large_rand": lambda: ( + 200 * torch.rand(5, 10, 25, 20), + torch.rand(5, 10, 25, 20), + None, + ), + "op_div_rank4_negative_large_rand": lambda: ( + (-200) * torch.rand(5, 10, 25, 20), + torch.rand(5, 10, 25, 20), + None, + ), + "op_div_rank4_large_randn": lambda: ( + 200 * torch.randn(5, 10, 25, 20) + 1, + torch.rand(5, 10, 25, 20) + 1, + None, + ), + "op_div_rank4_randn_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + None, + ), +} + + +class Div(torch.nn.Module): + + def forward( + self, + input_: Union[torch.Tensor, torch.types.Number], + other_: Union[torch.Tensor, torch.types.Number], + rounding_mode: Optional[str] = None, + ): + if rounding_mode is None: + return torch.div(input=input_, other=other_) + else: + return torch.div(input=input_, other=other_, rounding_mode=rounding_mode) + + +@common.parametrize("test_data", test_data_suite) +def test_div_tensor_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1](Div(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_div_tensor_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1](Div(), test_data(), aten_op=[], exir_op=[]) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_div_tensor_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Div(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_div_tensor_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Div(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_div_tensor_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Div(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_div_tensor_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Div(), + test_data(), + aten_op=[], + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div_tensor_mode.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div_tensor_mode.py new file mode 100644 index 0000000..866805a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_div_tensor_mode.py @@ -0,0 +1,151 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_tt = Tuple[torch.Tensor, torch.Tensor] + + +class DivTensorModeFloat(torch.nn.Module): + """ + torch.div(x, y, rounding_mode=mode) with + mode from {None, "floor", "trunc"}. + """ + + aten_ops = ["aten.div.Tensor_mode"] + aten_ops_int = ["aten.mul.Tensor", "aten.reciprocal.default"] + + def __init__(self, mode=None): + super().__init__() + assert mode in (None, "floor", "trunc") + self.mode = mode + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return torch.div(x, y, rounding_mode=self.mode) + + +test_data = { + "mode_none": lambda: (None, (torch.randn(4, 8), torch.randn(4, 8).abs() + 1e-3)), + "mode_floor": lambda: ( + "floor", + (torch.randn(4, 8), torch.randn(4, 8).abs() + 1e-3), + ), + "mode_trunc": lambda: ( + "trunc", + (torch.randn(4, 8), torch.randn(4, 8).abs() + 1e-3), + ), + "int_denominator": lambda: (None, (torch.randn(4, 8), 2)), +} + + +@common.parametrize("data", test_data) +def test_div_tensor_mode_tosa_FP(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = TosaPipelineFP[input_tt]( + model, + inputs, + aten_op=model.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize("data", test_data) +def test_div_tensor_mode_tosa_INT(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = TosaPipelineINT[input_tt]( + model, + inputs, + aten_op=model.aten_ops_int, + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize( + "data", test_data, xfails={"mode_trunc": "CPU op missing in unittests"} +) +def test_div_tensor_mode_u55_INT(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = EthosU55PipelineINT[input_tt]( + model, + inputs, + aten_ops=model.aten_ops_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("data", test_data) +def test_div_tensor_mode_u85_INT(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = EthosU85PipelineINT[input_tt]( + model, + inputs, + aten_ops=model.aten_ops_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("data", test_data) +def test_div_tensor_mode_vgf_quant(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = VgfPipeline[input_tt]( + model, + inputs, + aten_op=model.aten_ops_int, + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("data", test_data) +def test_div_tensor_mode_vgf_no_quant(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = VgfPipeline[input_tt]( + model, + inputs, + aten_op=model.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_elu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_elu.py new file mode 100644 index 0000000..c748f83 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_elu.py @@ -0,0 +1,133 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +import torch.nn as nn + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "zeros_default": lambda: (1.0, torch.zeros(1, 10, 10, 10)), + "ones_default": lambda: (1.0, torch.ones(10, 10, 10)), + "rand_default": lambda: (1.0, torch.rand(10, 10) - 0.5), + "randn_pos_default": lambda: (1.0, torch.randn(1, 2, 3, 3) + 10), + "randn_neg_default": lambda: (1.0, torch.randn(2, 4, 3) - 10), + "ramp_default": lambda: (1.0, torch.arange(-16, 16, 0.2)), + "large_pos_default": lambda: (1.0, torch.randn(3, 3) * 1e6 + 1e7), + "large_neg_default": lambda: (1.0, -torch.empty(5).uniform_(1e5, 1e8)), + "small_pos_default": lambda: (1.0, torch.empty(5).uniform_(1e-8, 1e-5)), + "small_neg_default": lambda: (1.0, -torch.empty(5).uniform_(1e-8, 1e-5)), + "zeros_custom": lambda: (2.0, torch.zeros(1, 10, 10, 10)), + "ones_custom": lambda: (2.0, torch.ones(10, 10, 10)), + "rand_custom": lambda: (2.0, torch.rand(10, 10) - 0.5), + "randn_pos_custom": lambda: (2.0, torch.randn(1, 3, 3) + 10), + "randn_neg_custom": lambda: (2.0, torch.randn(1, 2, 4, 3) - 10), + "ramp_custom": lambda: (2.0, torch.arange(-16, 16, 0.2)), + "large_pos_custom": lambda: (2.0, torch.randn(3, 3) * 1e6 + 1e7), + "large_neg_custom": lambda: (2.0, -torch.empty(5).uniform_(1e5, 1e8)), + "small_pos_custom": lambda: (2.0, torch.empty(5).uniform_(1e-8, 1e-5)), + "small_neg_custom": lambda: (2.0, -torch.empty(5).uniform_(1e-8, 1e-5)), + "zeros_zero": lambda: (0.0, torch.zeros(1, 10, 10, 10)), + "ones_zero": lambda: (0.0, torch.ones(10, 10, 10)), + "rand_zero": lambda: (0.0, torch.rand(10, 10) - 0.5), + "randn_pos_zero": lambda: (0.0, torch.randn(1, 3, 3) + 10), + "randn_neg_zero": lambda: (0.0, torch.randn(1, 2, 4, 3) - 10), + "ramp_zero": lambda: (0.0, torch.arange(-16, 16, 0.2)), + "large_pos_zero": lambda: (0.0, torch.randn(3, 3) * 1e6 + 1e7), + "large_neg_zero": lambda: (0.0, -torch.empty(5).uniform_(1e5, 1e8)), + "small_pos_zero": lambda: (0.0, torch.empty(5).uniform_(1e-8, 1e-5)), + "small_neg_zero": lambda: (0.0, -torch.empty(5).uniform_(1e-8, 1e-5)), +} + + +class Elu(nn.Module): + aten_op = "torch.ops.aten.elu.default" + exir_op = "executorch_exir_dialects_edge__ops_aten__elu_default" + + def __init__(self, input_alpha: float = 1.0): + super().__init__() + self.elu = torch.nn.ELU(alpha=input_alpha) + + def forward(self, input_: torch.Tensor): + return self.elu(input_) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_module", test_data_suite) +def test_elu_tosa_FP(test_module: input_t1): + alpha, test_data = test_module() + pipeline = TosaPipelineFP[input_t1]( + Elu(alpha), (test_data,), aten_op=Elu.aten_op, exir_op=Elu.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_elu_tosa_INT(test_module: input_t1): + alpha, test_data = test_module() + pipeline = TosaPipelineINT[input_t1]( + Elu(alpha), (test_data,), aten_op=Elu.aten_op, exir_op=Elu.exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_module", test_data_suite) +def test_elu_u55_INT(test_module: input_t1): + alpha, test_data = test_module() + pipeline = EthosU55PipelineINT[input_t1]( + Elu(alpha), (test_data,), aten_ops=Elu.aten_op, exir_ops=Elu.exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_module", test_data_suite) +def test_elu_u85_INT(test_module: input_t1): + alpha, test_data = test_module() + pipeline = EthosU85PipelineINT[input_t1]( + Elu(alpha), (test_data,), aten_ops=Elu.aten_op, exir_ops=Elu.exir_op + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_elu_vgf_no_quant(test_module: input_t1): + alpha, test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Elu(alpha), + (test_data,), + aten_op=Elu.aten_op, + exir_op=Elu.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_elu_vgf_quant(test_module: input_t1): + alpha, test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Elu(alpha), + (test_data,), + aten_op=Elu.aten_op, + exir_op=Elu.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_embedding.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_embedding.py new file mode 100644 index 0000000..0030373 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_embedding.py @@ -0,0 +1,146 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm._passes import InsertInt32CastsAfterInt64PlaceholdersPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Embedding(torch.nn.Module): + + aten_op = "torch.ops.aten.embedding.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_embedding_default" + + def forward(self, weights: torch.Tensor, indices: torch.Tensor): + return torch.embedding(weights, indices) + + +class ExpandEmbedding(Embedding): + example_inputs = (torch.randn(10, 3), torch.tensor([[1, 2, 3]], dtype=torch.int32)) + + def forward(self, weights: torch.Tensor, indices: torch.Tensor): + return torch.embedding(weights, indices.expand(2, 3)) + + +input_params = Tuple[torch.Tensor, torch.Tensor] + + +test_input: dict[str, input_params] = { + "test_1": ( + torch.randn(10, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32), + ), + "test_2": ( + torch.randn(10, 4), + torch.tensor([[1, 4, 3], [4, 3, 2]], dtype=torch.int32), + ), + "test_3": ( + torch.randn(9, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int64), + ), + "test_4": ( + torch.randn(11, 5), + torch.randint(low=0, high=10, size=(4, 3), dtype=torch.int64), + ), + "test_5": ( + torch.randn(11, 5), + torch.randint(low=0, high=10, size=(4, 3, 2), dtype=torch.int64), + ), + "test_6": ( + torch.randn(11, 5), + torch.randint(low=0, high=10, size=(4, 3, 2, 5), dtype=torch.int64), + ), +} + + +@pytest.mark.skip(reason="MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize("test_input", test_input) +def test_embedding_tosa_FP(test_input: input_params): + op = Embedding() + pipeline = TosaPipelineFP[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + ) + pipeline.run() + + +@common.parametrize("test_input", test_input) +def test_embedding_tosa_INT(test_input: input_params): + op = Embedding() + pipeline = TosaPipelineINT[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + + pipeline.run() + + +def test_embedding_tosa_INT_expand(): + op = ExpandEmbedding() + pipeline = TosaPipelineINT( + op, + ExpandEmbedding.example_inputs, + ExpandEmbedding.aten_op, + ExpandEmbedding.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + + pipeline.run() + + +@pytest.mark.skip("reason=MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize("test_input", test_input) +@common.SkipIfNoModelConverter +def test_embedding_vgf_no_quant(test_input: input_params): + op = Embedding() + pipeline = VgfPipeline[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_input", test_input) +@common.SkipIfNoModelConverter +def test_embedding_vgf_quant(test_input: input_params): + op = Embedding() + pipeline = VgfPipeline[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eq.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eq.py new file mode 100644 index 0000000..c4e7258 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eq.py @@ -0,0 +1,286 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + + +class Equal(torch.nn.Module): + aten_op_Tensor = "torch.ops.aten.eq.Tensor" + aten_op_Scalar = "torch.ops.aten.eq.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_eq_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ == other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_eq_tensor_rank1_ones = Equal( + torch.ones(5), + torch.ones(5), +) +op_eq_tensor_rank2_rand = Equal( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_eq_tensor_rank3_randn = Equal( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_eq_tensor_rank4_randn = Equal( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_eq_scalar_rank1_ones = Equal(torch.ones(5), 1.0) +op_eq_scalar_rank2_rand = Equal(torch.rand(4, 5), 0.2) +op_eq_scalar_rank3_randn = Equal(torch.randn(10, 5, 2), -0.1) +op_eq_scalar_rank4_randn = Equal(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "eq_tensor_rank1_ones": lambda: op_eq_tensor_rank1_ones, + "eq_tensor_rank2_rand": lambda: op_eq_tensor_rank2_rand, + "eq_tensor_rank3_randn": lambda: op_eq_tensor_rank3_randn, + "eq_tensor_rank4_randn": lambda: op_eq_tensor_rank4_randn, +} + +test_data_scalar = { + "eq_scalar_rank1_ones": lambda: op_eq_scalar_rank1_ones, + "eq_scalar_rank2_rand": lambda: op_eq_scalar_rank2_rand, + "eq_scalar_rank3_randn": lambda: op_eq_scalar_rank3_randn, + "eq_scalar_rank4_randn": lambda: op_eq_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_eq_scalar_tosa_FP_tensor(test_module): + pipeline = TosaPipelineFP[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_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Scalar, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_eq_scalar_tosa_INT_tensor(test_module): + pipeline = TosaPipelineINT[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_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_eq_scalar_tosa_INT_tensor_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_eq_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_eq_scalar_u55_INT_tensor(test_module): + # EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Equal.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_eq_scalar_u55_INT(test_module): + # EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Equal.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT_tensor(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT_tensor_16a8w(test_module): + """Test eq operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT_16a8w(test_module): + """Test eq operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_no_quant_tensor(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Scalar, + Equal.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_quant_tensor(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_erf.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_erf.py new file mode 100644 index 0000000..6ad9f64 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_erf.py @@ -0,0 +1,96 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.erf.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_erf_default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Erf(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.erf(x) + + test_data: dict[str, input_t1] = { + "zeros": lambda: (torch.zeros(1, 10, 10, 10),), + "ones": lambda: (torch.ones(10, 10, 10),), + "rand": lambda: ((torch.rand(10, 10) - 0.5),), + "randn_pos": lambda: ((torch.randn(1, 4, 4, 4) + 10),), + "randn_neg": lambda: ((torch.randn(1, 4, 4, 4) - 10),), + "ramp": lambda: (torch.arange(-16, 16, 0.2),), + } + + +@common.parametrize("test_data", Erf.test_data) +def test_erf_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Erf(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +def test_erf_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Erf(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.XfailIfNoCorstone300 +def test_erf_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.XfailIfNoCorstone320 +def test_erf_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.SkipIfNoModelConverter +def test_erf_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.SkipIfNoModelConverter +def test_erf_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_exp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_exp.py new file mode 100644 index 0000000..71d5f49 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_exp.py @@ -0,0 +1,110 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(1, 4, 4, 4) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + +aten_op = "torch.ops.aten.exp.default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Exp(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.exp(x) + + +@common.parametrize("test_data", test_data_suite) +def test_exp_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_exp_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_exp_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_exp_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_exp_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_exp_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expand.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expand.py new file mode 100644 index 0000000..bddf7b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expand.py @@ -0,0 +1,153 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the expand op which copies the data of the input tensor (possibly with new data format) +# + + +from typing import Sequence, Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.expand.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_expand_copy_default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, Input y + + +class Expand(torch.nn.Module): + # (input tensor, multiples) + base_test_set = { + "rand_1d_both": lambda: (torch.rand(1), (2,)), + "rand_1d": lambda: (torch.randn(1), (2, 2, 4)), + "rand_4d": lambda: (torch.randn(1, 1, 1, 5), (1, 4, -1, -1)), + "rand_batch_1": lambda: (torch.randn(1, 1), (1, 2, 2, 4)), + "rand_batch_2": lambda: (torch.randn(1, 1), (2, 2, 2, 4)), + "rand_mix_neg": lambda: (torch.randn(10, 1, 1, 97), (-1, 4, -1, -1)), + "rand_small_neg": lambda: (torch.rand(1, 1, 2, 2), (4, 3, -1, 2)), + } + + test_u55_reject_set = { + "randbool_1d": lambda: (torch.randint(0, 2, (1,), dtype=torch.bool), (5,)), + } + test_reject_set = { + "rand_2d": lambda: (torch.randn(1, 4), (1, -1)), + "rand_neg_mul": lambda: (torch.randn(1, 1, 192), (1, -1, -1)), + } + test_parameters = base_test_set | test_u55_reject_set + + def forward(self, x: torch.Tensor, m: Sequence): + return x.expand(m) + + +@common.parametrize("test_data", Expand.test_parameters) +def test_expand_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +def test_expand_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize( + "test_data", + Expand.base_test_set, +) +@common.XfailIfNoCorstone300 +def test_expand_u55_INT(test_data: Tuple): + inputs = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + Expand(), + inputs, + aten_op, + exir_ops=[], + ) + if inputs[0].dtype == torch.bool: + pipeline.pop_stage("check_count.exir") + pipeline.tester.use_portable_ops = True + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +@common.XfailIfNoCorstone320 +def test_expand_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Expand(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +@common.SkipIfNoModelConverter +def test_expand_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +@common.SkipIfNoModelConverter +def test_expand_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_reject_set) +def test_expand_tosa_INT_not_delegated(test_data: Tuple): + pipeline = OpNotSupportedPipeline[input_t1]( + Expand(), test_data(), {exir_op: 1}, n_expected_delegates=0, quantize=True + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_u55_reject_set) +def test_expand_u55_INT_not_delegated(test_data: Tuple): + pipeline = OpNotSupportedPipeline[input_t1]( + Expand(), + test_data(), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expm1.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expm1.py new file mode 100644 index 0000000..7556d1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_expm1.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.expm1.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_expm1_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeroes": torch.zeros(1, 10, 10, 10), + "ones": torch.ones(10, 2, 3), + "rand": torch.rand(10, 10) - 0.5, + "near_zero": torch.randn(100) * 0.01, + "taylor_small": torch.empty(5).uniform_( + -0.35, 0.35 + ), # test cases for taylor series expansion + "randn_large_pos": torch.randn(10) + 10, + "randn_large_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Expm1(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.expm1(x) + + +@common.parametrize("test_data", test_data_suite) +def test_expm1_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Expm1(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_expm1_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Expm1(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_expm1_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Expm1(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_expm1_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Expm1(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_expm1_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expm1(), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_expm1_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expm1(), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eye.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eye.py new file mode 100644 index 0000000..c004b7c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_eye.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class EyeAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.eye.default" + + def __init__(self, n: int, dtype: torch.dtype): + super().__init__() + self.args = (n,) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.eye(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)), + "10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (10, torch.int32), + ), + } + + # Mixed dtypes - the eye op is delegated, but it leads to a non-delegated add op. + test_data_mixed_dtypes: dict[str, test_data_t] = { + "fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)), + "fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)), + } + + +# skip test since int32 isn't support on FP profile +# "int32_int32": "view/RESHAPE of integer tensor is not supported for +FP profile" +@pytest.mark.skip(reason="MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize("test_data", EyeAdd.test_data) +def test_eye_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", EyeAdd.test_data | EyeAdd.test_data_mixed_dtypes) +def test_eye_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", EyeAdd.test_data) +@common.XfailIfNoCorstone300 +def test_eye_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", EyeAdd.test_data) +@common.XfailIfNoCorstone320 +def test_eye_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +# skip since int32 isn't support on FP profile +# "int32_int32": "view/RESHAPE of integer tensor is not supported for +FP profile" +@pytest.mark.skip(reason="MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize( + "test_data", + EyeAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_eye_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + EyeAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_eye_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + quantize=True, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize( + "test_data", + EyeAdd.test_data_mixed_dtypes, +) +def test_eye_tosa_INT_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + EyeAdd(*init_data), + input_data(), + non_delegated_ops={"executorch_exir_dialects_edge__ops_aten_add_Tensor": 1}, + n_expected_delegates=1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_fill_scalar.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_fill_scalar.py new file mode 100644 index 0000000..5ca209f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_fill_scalar.py @@ -0,0 +1,108 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.fill_.Scalar" +exir_op = "executorch_exir_dialects_edge__ops_aten_full_like_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "ones_float": [torch.ones(2, 3), 5.0], + "ones_int": [torch.ones(2, 3), -3], +} + + +class FillScalar(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, y: torch.Tensor, fill_value: int | float): + mask = torch.full_like(y, 0) + mask.fill_(fill_value) + return mask * y + + +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + FillScalar(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + FillScalar(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + FillScalar(), + (*test_data,), + aten_ops=[aten_op], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + FillScalar(), + (*test_data,), + aten_ops=[aten_op], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_fill_scalar_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FillScalar(), + (*test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_fill_scalar_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FillScalar(), + (*test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor.py new file mode 100644 index 0000000..d308db1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Floor(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.floor(x) + + aten_op = "torch.ops.aten.floor.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_floor_default" + + +zeros = torch.zeros(1, 10, 10, 10) +ones = torch.ones(10, 10, 10) +rand = torch.rand(10, 10) - 0.5 +randn_pos = torch.randn(1, 4, 4, 4) + 10 +randn_neg = torch.randn(1, 4, 4, 4) - 10 +ramp = torch.arange(-16, 16, 0.2) + +test_data = { + "floor_zeros": lambda: (Floor(), zeros), + "floor_ones": lambda: (Floor(), ones), + "floor_rand": lambda: (Floor(), rand), + "floor_randn_pos": lambda: (Floor(), randn_pos), + "floor_randn_neg": lambda: (Floor(), randn_neg), + "floor_ramp": lambda: (Floor(), ramp), +} + + +@common.parametrize("test_data", test_data) +def test_floor_tosa_FP(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_floor_tosa_INT(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone300 +def test_floor_u55_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone320 +def test_floor_u85_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_floor_vgf_no_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_floor_vgf_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor_div.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor_div.py new file mode 100644 index 0000000..d2b4bc4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_floor_div.py @@ -0,0 +1,156 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple, Union + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, input, other) + "op_floor_div_rank1_ones": lambda: ( + torch.ones(5), + torch.ones(5), + ), + "op_floor_div_rank1_rand": lambda: ( + torch.rand(5) * 5, + torch.rand(5) * 5, + ), + "op_floor_div_rank4_negative_ones": lambda: ( + (-1) * torch.ones(5, 10, 25, 20), + torch.ones(5, 10, 25, 20), + ), + "op_floor_div_rank4_ones_div_negative": lambda: ( + torch.ones(5, 10, 25, 20), + (-1) * torch.ones(5, 10, 25, 20), + ), + "op_floor_div_rank4_randn_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + ), + "op_floor_div_rank4_randn_scalar": lambda: ( + torch.randn(1, 4, 4, 1), + 2, + ), + "op_floor_div_rank4_large_rand": lambda: ( + 200 * torch.rand(5, 10, 25, 20), + torch.rand(5, 10, 25, 20), + ), +} + + +class FloorDivide(torch.nn.Module): + aten_op = "torch.ops.aten.floor_divide.default" + aten_ops_int = ["aten.mul.Tensor", "aten.reciprocal.default", "aten.floor.default"] + exir_op = "executorch_exir_dialects_edge__ops_aten_div_Tensor_mode" + exir_ops_int = [ + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_floor_default", + ] + + def forward( + self, + input_: Union[torch.Tensor, torch.types.Number], + other_: Union[torch.Tensor, torch.types.Number], + ): + return torch.floor_divide(input=input_, other=other_) + + +input_t1 = Tuple[torch.Tensor, Union[torch.Tensor, int]] + + +@common.parametrize("test_data", test_data_suite) +def test_floor_divide_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + FloorDivide(), + test_data(), + FloorDivide.aten_op, + FloorDivide.exir_op, + use_to_edge_transform_and_lower=False, + rtol=0.06, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_floor_divide_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + FloorDivide(), + test_data(), + aten_op=FloorDivide.aten_ops_int, + exir_op=FloorDivide.exir_ops_int, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_floor_divide_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + FloorDivide(), + test_data(), + aten_ops=FloorDivide.aten_ops_int, + exir_ops=[], + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.pop_stage("check_not.exir") + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_floor_divide_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + FloorDivide(), + test_data(), + aten_ops=FloorDivide.aten_ops_int, + exir_ops=FloorDivide.exir_ops_int, + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_floor_divide_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FloorDivide(), + test_data(), + FloorDivide.aten_op, + FloorDivide.exir_op, + use_to_edge_transform_and_lower=False, + rtol=0.06, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_floor_divide_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FloorDivide(), + test_data(), + aten_op=FloorDivide.aten_ops_int, + exir_op=FloorDivide.exir_ops_int, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_full.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_full.py new file mode 100644 index 0000000..9ee607e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_full.py @@ -0,0 +1,255 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the full op which creates a tensor of a given shape filled with a given value. +# The shape and value are set at compile time, i.e. can't be set by a tensor input. +# + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, int] + +exir_op = "executorch_exir_dialects_edge__ops_aten_full_default" + + +class Full(torch.nn.Module): + # A single full op + def forward(self): + return torch.full((3, 3), 4.5) + + +class AddConstFull(torch.nn.Module): + # Input + a full with constant value. + def forward(self, x: torch.Tensor): + return torch.full((2, 2, 3, 3), 4.5, dtype=torch.float32) + x + + +class AddVariableFull(torch.nn.Module): + sizes: list[tuple[int, ...]] = [ + (5,), + (5, 5), + (5, 5, 5), + (1, 5, 5, 5), + ] + test_parameters = {} + for i, n in enumerate(sizes): + test_parameters[f"slice_randn_{i}"] = (torch.randn(n) * 10 - 5, 3.2) + + def forward(self, x: torch.Tensor, y): + # Input + a full with the shape from the input and a given value 'y'. + return x + torch.full(x.shape, y) + + +class FullLike(torch.nn.Module): + """Since full_like is replaced with full, we only need to test on reference model, not FVP.""" + + test_parameters = { + "full_like_value_3_2": lambda: (torch.randn(2, 2, 2, 2) * 50, 3.2), + "full_like_value_3": lambda: (torch.randn(2, 2, 2, 2) * 50, 3), + "full_like_value_3_2_int32": lambda: ( + (torch.randn(2, 2, 2, 2) * 50).to(torch.int32), + 3.2, + ), + "full_like_value_3_int32": lambda: ( + (torch.randn(2, 2, 2, 2) * 50).to(torch.int32), + 3, + ), + } + + def forward(self, input_tensor: torch.Tensor, value): + # Our backend can't handle tensors without users, which input_tensor doesn't have + # when the full_like is converted to a full. Therefore involve it in the output. + return input_tensor + torch.full_like(input_tensor, value) + + +def test_full_tosa_FP_only(): + pipeline = TosaPipelineFP[input_t1]( + Full(), + (), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +def test_full_tosa_FP_const(): + test_data = (torch.rand((2, 2, 3, 3)) * 10,) + pipeline = TosaPipelineFP[input_t1]( + AddConstFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", FullLike.test_parameters) +def test_full_like_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + FullLike(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", FullLike.test_parameters) +def test_full_like_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + FullLike(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +def test_full_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +def test_full_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_full_vgf_no_quant_only(): + pipeline = VgfPipeline[input_t1]( + Full(), + (), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_full_vgf_no_quant_const(): + test_data = (torch.rand((2, 2, 3, 3)) * 10,) + pipeline = VgfPipeline[input_t1]( + AddConstFull(), + test_data, + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.SkipIfNoModelConverter +def test_full_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.SkipIfNoModelConverter +def test_full_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.XfailIfNoCorstone320 +def test_full_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + AddVariableFull(), + test_data, + aten_ops=[], + exir_ops=exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.XfailIfNoCorstone300 +def test_full_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + AddVariableFull(), + test_data, + aten_ops=[], + exir_ops=exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +# This fails since full outputs int64 by default if 'fill_value' is integer, which our backend doesn't support. +@pytest.mark.skip( + "This fails since full outputs int64 by default if 'fill_value' is integer, which our backend doesn't support." +) +def test_full_tosa_FP_integer_value(): + test_data = (torch.ones((2, 2)), 1.0) + pipeline = TosaPipelineFP[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +# This fails since the fill value in the full tensor is set at compile time by the example data (1.). +# Test data tries to set it again at runtime (to 2.) but it doesn't do anything. +# In eager mode, the fill value can be set at runtime, causing the outputs to not match. +@pytest.mark.skip( + "This fails since the fill value in the full tensor is set at compile time by the example data (1.)." +) +def test_full_tosa_FP_set_value_at_runtime(tosa_version: str): + test_data = (torch.ones((2, 2)), 1.0) + pipeline = TosaPipelineFP[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.add_stage( + pipeline.tester.run_method_and_compare_outputs, inputs=(torch.ones((2, 2)), 2.0) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ge.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ge.py new file mode 100644 index 0000000..4674806 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ge.py @@ -0,0 +1,292 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + + +class GreaterEqual(torch.nn.Module): + aten_op_tensor = "torch.ops.aten.ge.Tensor" + aten_op_scalar = "torch.ops.aten.ge.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_ge_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ >= other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_ge_tensor_rank1_ones = GreaterEqual( + torch.ones(5), + torch.ones(5), +) +op_ge_tensor_rank2_rand = GreaterEqual( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_ge_tensor_rank3_randn = GreaterEqual( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_ge_tensor_rank4_randn = GreaterEqual( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_ge_scalar_rank1_ones = GreaterEqual(torch.ones(5), 1.0) +op_ge_scalar_rank2_rand = GreaterEqual(torch.rand(4, 5), 0.2) +op_ge_scalar_rank3_randn = GreaterEqual(torch.randn(10, 5, 2), -0.1) +op_ge_scalar_rank4_randn = GreaterEqual(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "ge_tensor_rank1_ones": lambda: op_ge_tensor_rank1_ones, + "ge_tensor_rank2_rand": lambda: op_ge_tensor_rank2_rand, + "ge_tensor_rank3_randn": lambda: op_ge_tensor_rank3_randn, + "ge_tensor_rank4_randn": lambda: op_ge_tensor_rank4_randn, +} + +test_data_scalar = { + "ge_scalar_rank1_ones": lambda: op_ge_scalar_rank1_ones, + "ge_scalar_rank2_rand": lambda: op_ge_scalar_rank2_rand, + "ge_scalar_rank3_randn": lambda: op_ge_scalar_rank3_randn, + "ge_scalar_rank4_randn": lambda: op_ge_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_ge_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ge_scalar_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_scalar, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_ge_tensor_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ge_scalar_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_ge_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ge_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_ge_tensor_u55_INT(test_module): + # GREATER_EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {GreaterEqual.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_ge_scalar_u55_INT(test_module): + # GREATER_EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {GreaterEqual.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_ge_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_ge_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_ge_tensor_16a8w_u85_INT(test_module): + """Test ge operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_ge_scalar_16a8w_u85_INT(test_module): + """Test ge operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ge_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ge_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ge_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_scalar, + GreaterEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ge_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gelu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gelu.py new file mode 100644 index 0000000..0936aa1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gelu.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Gelu(torch.nn.Module): + aten_op = "torch.ops.aten.gelu.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_gelu_default" + + test_data: dict[str, Tuple[str, input_t1]] = { + "zeros_none": lambda: ( + "none", + torch.zeros(1, 10, 10, 10), + ), + "ones_none": lambda: ( + "none", + torch.ones(10, 10, 10), + ), + "rand_none": lambda: ( + "none", + (torch.rand(10, 10) - 0.5), + ), + "randn_pos_none": lambda: ( + "none", + (torch.randn(1, 4, 4, 4) + 10), + ), + "randn_neg_none": lambda: ( + "none", + (torch.randn(1, 4, 4, 4) - 10), + ), + "ramp_none": lambda: ( + "none", + torch.arange(-16, 16, 0.2), + ), + "zeros_tanh": lambda: ( + "tanh", + torch.zeros(1, 10, 10, 10), + ), + "ones_tanh": lambda: ( + "tanh", + torch.ones(10, 10, 10), + ), + "rand_tanh": lambda: ( + "tanh", + (torch.rand(10, 10) - 0.5), + ), + "randn_pos_tanh": lambda: ( + "tanh", + (torch.randn(1, 4, 4, 4) + 10), + ), + "randn_neg_tanh": lambda: ( + "tanh", + (torch.randn(1, 4, 4, 4) - 10), + ), + "ramp_tanh": lambda: ( + "tanh", + torch.arange(-16, 16, 0.2), + ), + } + + def __init__(self, approximate: str = "none"): + super().__init__() + self.gelu = torch.nn.GELU(approximate) + + def forward(self, x: torch.Tensor): + return self.gelu(x) + + +@common.parametrize("test_data", Gelu.test_data) +def test_gelu_tosa_FP(test_data: input_t1): + approximate, test_data = test_data() + TosaPipelineFP[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + use_to_edge_transform_and_lower=False, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +def test_gelu_tosa_INT(test_data: input_t1): + approximate, test_data = test_data() + TosaPipelineINT[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.XfailIfNoCorstone300 +def test_gelu_u55_INT(test_data: input_t1): + approximate, test_data = test_data() + EthosU55PipelineINT[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.XfailIfNoCorstone320 +def test_gelu_u85_INT(test_data: input_t1): + approximate, test_data = test_data() + EthosU85PipelineINT[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.SkipIfNoModelConverter +def test_gelu_vgf_no_quant(test_data: input_t1): + approximate, data = test_data() + pipeline = VgfPipeline[input_t1]( + Gelu(approximate), + (data,), + Gelu.aten_op, + Gelu.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.SkipIfNoModelConverter +def test_gelu_vgf_quant(test_data: input_t1): + approximate, data = test_data() + pipeline = VgfPipeline[input_t1]( + Gelu(approximate), + (data,), + Gelu.aten_op, + Gelu.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_glu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_glu.py new file mode 100644 index 0000000..c7426c0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_glu.py @@ -0,0 +1,130 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +import torch.nn.functional as F +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.glu.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__glu_default" + + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": [torch.zeros(10, 10, 2), -1], + "ones": [torch.ones(10, 10, 2), -1], + "rand": [torch.rand(10, 10, 2) - 0.5, -1], + "randn_pos": [torch.randn(10, 2) + 10, -1], + "randn_neg": [torch.randn(10, 2) - 10, -1], + "ramp": [torch.linspace(-16, 15.8, 160).reshape(-1, 2), -1], + "zeros_custom_dim": [torch.zeros(7, 10, 5), 1], + "rand_custom_dim": [torch.rand(10, 3, 3) - 0.5, 0], +} + + +class Glu(torch.nn.Module): + + def forward(self, a: torch.Tensor, dim: int) -> torch.Tensor: + return F.glu(a, dim=dim) + + +@common.parametrize( + "test_data", + test_data_suite, +) +def test_glu_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Glu(), + (*test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +def test_glu_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Glu(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.XfailIfNoCorstone300 +def test_glu_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Glu(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.XfailIfNoCorstone320 +def test_glu_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Glu(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_glu_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Glu(), + (*test_data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_glu_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Glu(), + (*test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_group_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_group_norm.py new file mode 100644 index 0000000..d80b94c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_group_norm.py @@ -0,0 +1,200 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class GroupNorm(torch.nn.Module): + + def __init__( + self, + num_groups: int, + num_channels: int, + eps: float = 1e-5, + affine: bool = True, + ): + super().__init__() + self.group_norm = torch.nn.GroupNorm( + num_groups, + num_channels, + eps=eps, + affine=affine, + ) + + def forward( + self, + x: torch.Tensor, + ): + return self.group_norm(x) + + +input_t = tuple[torch.Tensor] +test_data_suite = { + "rand_4_6_groups_1": ((torch.rand(4, 6),), GroupNorm(1, 6)), + "rand_4_6_groups_2": ((torch.rand(4, 6),), GroupNorm(2, 6)), + "rand_4_6_groups_6": ((torch.rand(4, 6),), GroupNorm(6, 6)), + "rand_4_6_8_groups_2_eps_no_affine": ( + (torch.rand(4, 6, 8),), + GroupNorm(2, 6, eps=1e-3, affine=False), + ), + "randn_1_12_8_6_groups_6_eps": ( + (torch.randn(1, 12, 8, 6),), + GroupNorm(6, 12, eps=1e-2), + ), + "randn_1_12_8_6_groups_12": ((torch.randn(1, 12, 8, 6),), GroupNorm(12, 12)), + "rand_6_8_10_12_groups_1": ((torch.rand(6, 8, 10, 12),), GroupNorm(1, 8)), + "rand_6_8_10_12_groups_4_no_affine": ( + (torch.rand(6, 8, 10, 12),), + GroupNorm(4, 8, affine=False), + ), + "rand_6_8_10_12_groups_8": ((torch.rand(6, 8, 10, 12),), GroupNorm(8, 8)), +} + + +@common.parametrize("test_data", test_data_suite) +def test_native_group_norm_tosa_FP(test_data): + aten_op = "torch.ops.aten.group_norm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + pipeline = TosaPipelineFP[input_t]( + test_data[1], + test_data[0], + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + }, + strict=False, +) +def test_native_group_norm_tosa_INT(test_data): + aten_op = "torch.ops.aten.sub.Tensor" # 'sub' op arbitrarily chosen to confirm groupnorm was decomposed + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + pipeline = TosaPipelineINT[input_t]( + test_data[1], + test_data[0], + aten_op=aten_op, + exir_op=exir_op, + atol=0.1, # TODO: "MLETORCH-925: Fix numerical issue for aten.native_group_norm" + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "rand_4_6_8_groups_2_eps_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_4_6_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_4_6_groups_2": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + }, + strict=False, +) +@common.XfailIfNoCorstone300 +def test_native_group_norm_u55_INT(test_data): + pipeline = EthosU55PipelineINT[input_t]( + test_data[1], + test_data[0], + "torch.ops.aten.sub.Tensor", # 'sub' op arbitrarily chosen to confirm groupnorm was decomposed + atol=0.1, # TODO: "MLETORCH-925: Fix numerical issue for aten.native_group_norm" + ) + pipeline.change_args("run_method_and_compare_outputs", atol=1, qtol=1) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + }, + strict=False, +) +@common.XfailIfNoCorstone320 +def test_native_group_norm_u85_INT(test_data): + pipeline = EthosU85PipelineINT[input_t]( + test_data[1], + test_data[0], + "torch.ops.aten.sub.Tensor", # 'sub' op arbitrarily chosen to confirm groupnorm was decomposed + atol=0.1, # TODO: "MLETORCH-925: Fix numerical issue for aten.native_group_norm" + ) + pipeline.change_args("run_method_and_compare_outputs", atol=1, qtol=1) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue", + }, + strict=False, +) +@common.SkipIfNoModelConverter +def test_native_group_norm_vgf_no_quant(test_data): + aten_op = "torch.ops.aten.group_norm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + model, inp = test_data + pipeline = VgfPipeline[input_t]( + inp, + model, + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue", + }, + strict=False, +) +@common.SkipIfNoModelConverter +def test_native_group_norm_vgf_quant(test_data): + aten_op = "torch.ops.aten.sub.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + model, inp = test_data + pipeline = VgfPipeline[input_t]( + inp, + model, + aten_op=aten_op, + exir_op=exir_op, + atol=0.1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gt.py new file mode 100644 index 0000000..1fd1ec8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_gt.py @@ -0,0 +1,293 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +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 + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ > other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_gt_tensor_rank1_ones = Greater( + torch.ones(5), + torch.ones(5), +) +op_gt_tensor_rank2_rand = Greater( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_gt_tensor_rank3_randn = Greater( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_gt_tensor_rank4_randn = Greater( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +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": lambda: op_gt_tensor_rank1_ones, + "gt_tensor_rank2_rand": lambda: op_gt_tensor_rank2_rand, + "gt_tensor_rank3_randn": lambda: op_gt_tensor_rank3_randn, + "gt_tensor_rank4_randn": lambda: op_gt_tensor_rank4_randn, +} + +test_data_scalar = { + "gt_scalar_rank1_ones": lambda: op_gt_scalar_rank1_ones, + "gt_scalar_rank2_rand": lambda: op_gt_scalar_rank2_rand, + "gt_scalar_rank3_randn": lambda: op_gt_scalar_rank3_randn, + "gt_scalar_rank4_randn": lambda: op_gt_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_gt_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[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_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + 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_INT(test_module): + pipeline = TosaPipelineINT[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_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_gt_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_gt_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_gt_tensor_u55_INT(test_module): + # Greater is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Greater.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_gt_scalar_u55_INT(test_module): + # Greater is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Greater.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_gt_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_gt_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_gt_tensor_16a8w_u85_INT(test_module): + """Test gt operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_gt_scalar_16a8w_u85_INT(test_module): + """Test gt operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_gt_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_gt_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_scalar, + Greater.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_gt_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_gt_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardsigmoid.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardsigmoid.py new file mode 100644 index 0000000..eb10e5a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardsigmoid.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.hardsigmoid.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Hardsigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.hardsigmoid = torch.nn.Hardsigmoid() + + def forward(self, x): + return self.hardsigmoid(x) + + +@common.parametrize("test_data", test_data_suite) +def test_hardsigmoid_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_hardsigmoid_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_hardsigmoid_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_hardsigmoid_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardsigmoid_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardsigmoid_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardswish.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardswish.py new file mode 100644 index 0000000..68cd249 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardswish.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.hardswish.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_clamp_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: (torch.zeros(1, 10, 10, 10)), + "ones": lambda: (torch.ones(10, 10, 10)), + "rand": lambda: (torch.rand(10, 10) - 0.5), + "randn_pos": lambda: (torch.randn(10) + 10), + "randn_neg": lambda: (torch.randn(10) - 10), + "ramp": lambda: (torch.arange(-16, 16, 0.2)), +} + + +class Hardswish(torch.nn.Module): + def __init__(self): + super().__init__() + self.hardswish = torch.nn.Hardswish() + + def forward(self, x): + return self.hardswish(x) + + +@common.parametrize("test_data", test_data_suite) +def test_hardswish_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t1](Hardswish(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_hardswish_tosa_INT(test_data): + pipeline = TosaPipelineINT[input_t1](Hardswish(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_hardswish_u55_INT(test_data): + EthosU55PipelineINT[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_hardswish_u85_INT(test_data): + EthosU85PipelineINT[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardswish_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardswish_vgf_quant(test_data): + pipeline = VgfPipeline[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardtanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardtanh.py new file mode 100644 index 0000000..a13e70d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_hardtanh.py @@ -0,0 +1,113 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: (torch.zeros(1, 10, 10, 10)), + "ones": lambda: (torch.ones(10, 10, 10)), + "rand": lambda: (torch.rand(10, 10) - 0.5), + "randn_pos": lambda: (torch.randn(10) + 10), + "randn_neg": lambda: (torch.randn(10) - 10), + "ramp": lambda: (torch.arange(-16, 16, 0.2)), +} + +aten_op = "torch.ops.aten.hardtanh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_hardtanh_default" + +input_t = Tuple[torch.Tensor] + + +class HardTanh(torch.nn.Module): + + def __init__(self): + super().__init__() + + self.hardTanh = torch.nn.Hardtanh() + + def forward(self, x): + return self.hardTanh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_hardtanh_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t](HardTanh(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_hardtanh_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_hardtanh_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_hardtanh_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardtanh_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardtanh_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_select.py new file mode 100644 index 0000000..239c27a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_select.py @@ -0,0 +1,177 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class IndexSelect(torch.nn.Module): + aten_op = "torch.ops.aten.index_select.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_index_select_default" + + def forward(self, input_: torch.Tensor, dim, index_: torch.Tensor): + return torch.index_select(input_, dim=dim, index=index_) + + +input_params = Tuple[torch.Tensor, int, torch.Tensor] + + +test_input: dict[input_params] = { + "test_1": ( + torch.tensor( + [[[0.1, 0.2, 0.3], [1.1, 1.2, 1.3], [2.1, 2.2, 2.3], [3.1, 3.2, 3.3]]], + dtype=torch.float32, + ), # Shape: [N=1, K=4, C=3] + 1, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), + "test_2": ( + torch.tensor( + [[0.1, 0.2, 0.3], [1.1, 1.2, 1.3], [2.1, 2.2, 2.3], [3.1, 3.2, 3.3]], + dtype=torch.float32, + ), # Shape: [K=4, C=3] + 0, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), + "test_3_mult_batches": ( + torch.randn(2, 4, 3), # Batches > 1 not supported + 1, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), + "test_4_rand": ( + torch.randn(1, 4, 3), + 1, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), +} + + +test_data = { + "index_select_test_1": (IndexSelect(), test_input["test_1"]), + "index_select_test_2": (IndexSelect(), test_input["test_2"]), + "index_select_test_3": pytest.param( + (IndexSelect(), test_input["test_3_mult_batches"]), + marks=pytest.mark.xfail( + reason="Rank3 weights with first dim larger than 1 is currently not supported" + ), + ), + "index_select_test_4": (IndexSelect(), test_input["test_4_rand"]), +} + + +@pytest.mark.parametrize("test_data", list(test_data.values())) +def test_index_select_tosa_FP(test_data: input_params): + op, test_input = test_data + pipeline = TosaPipelineFP[input_params]( + op, test_input, op.aten_op, op.exir_op, use_to_edge_transform_and_lower=True + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[:-1]) +def test_index_select_tosa_INT(test_data: input_params): + op, test_input = test_data + + pipeline = TosaPipelineINT[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[-1:]) +def test_index_select_tosa_INT_rand(test_data: input_params): + op, test_input = test_data + + pipeline = TosaPipelineINT[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", inputs=test_input, atol=0.9, rtol=0.2, qtol=1 + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[-1:]) +def test_index_select_u55_INT_not_delegated(test_data: input_params): + op, test_input = test_data + + pipeline = OpNotSupportedPipeline[input_params]( + op, + test_input, + {op.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())) +@common.SkipIfNoModelConverter +def test_index_select_vgf_no_quant(test_data: input_params): + op, inp = test_data + pipeline = VgfPipeline[input_params]( + op, + inp, + op.aten_op, + op.exir_op, + quantize=False, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[:-1]) +@common.SkipIfNoModelConverter +def test_index_select_vgf_quant(test_data: input_params): + op, inp = test_data + pipeline = VgfPipeline[input_params]( + op, + inp, + op.aten_op, + op.exir_op, + quantize=True, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[-1:]) +@common.SkipIfNoModelConverter +def test_index_select_vgf_quant_rand(test_data: input_params): + op, inp = test_data + pipeline = VgfPipeline[input_params]( + op, + inp, + op.aten_op, + op.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_tensor.py new file mode 100644 index 0000000..bc19634 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_index_tensor.py @@ -0,0 +1,467 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, +) + + +class IndexTensorTestCommon: + """Class containing constants common between the tests""" + + aten_op = "torch.ops.aten.index.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_index_Tensor" + + # Gathers and reshapes should result in no inaccuracies + rtol = 0.0 + atol = 0.0 + BEFORE = "BEFORE" + MIDDLE = "MIDDLE" + AFTER = "AFTER" + + +input_params_slice = Tuple[torch.Tensor, int, int, str, Tuple[torch.Tensor]] +input_params = Tuple[torch.Tensor, Tuple[torch.Tensor]] + + +class IndexTensor_Ellipsis(torch.nn.Module): + """ + There are technical limitations with torch/export as it does not support + the ellipsis class and as such the forward function has been crafted + to circumvent that limitation. + """ + + # xfail - ellipsis unsupported + test_data_ellipsis: dict[input_params] = { + "test_4d_ellipsis_before": ( + torch.rand(size=(25, 5, 13, 7)), + IndexTensorTestCommon.BEFORE, + (torch.arange(2, dtype=torch.int32),), + ), + "test_4d_ellipsis_middle": ( + torch.rand(size=(25, 5, 13, 7)), + IndexTensorTestCommon.MIDDLE, + ( + torch.arange(2, dtype=torch.int32), + torch.arange(2, dtype=torch.int32), + ), + ), + "test_4d_ellipsis_after": ( + # Due to the information passed to the NodeVisitor and + # preceding passes, detecting this and rejecting it for + # partitioning is difficult and unreliable, as such + # it is not xfail as the existing logic can handle it. + torch.rand(size=(25, 5, 13, 7)), + IndexTensorTestCommon.AFTER, + (torch.arange(2, dtype=torch.int32),), + ), + } + + def forward( + self, + input_: torch.Tensor, + position: str, + indices: Tuple[None | torch.Tensor], + ): + match position: + case IndexTensorTestCommon.BEFORE: + return input_[..., indices[0]] + case IndexTensorTestCommon.MIDDLE: + return input_[indices[0], ..., indices[1]] + case IndexTensorTestCommon.AFTER: + return input_[indices[0], ...] + + return input_[indices] + + +@common.parametrize( + "test_data", + IndexTensor_Ellipsis.test_data_ellipsis, + xfails={ + # More info in index_tensor_support.py + "test_4d_ellipsis_before": "Ellipsis before index unsupported", + "test_4d_ellipsis_middle": "Ellipsis before index unsupported", + }, +) +def test_index_tensor_tosa_FP_ellipsis(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params]( + IndexTensor_Ellipsis(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor_Ellipsis.test_data_ellipsis, + xfails={ + # More info in index_tensor_support.py + "test_4d_ellipsis_before": "Ellipsis before index unsupported", + "test_4d_ellipsis_middle": "Ellipsis before index unsupported", + }, +) +def test_index_tensor_tosa_INT_ellipsis(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params]( + IndexTensor_Ellipsis(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +class IndexTensor_Slice(torch.nn.Module): + """ + There are technical limitations with Dynamo as it does not support the + slice class and as such the forward function has been crafted + to circumvent that limitation. + """ + + # xfail - None unsupported + test_data: dict[input_params_slice] = { + "test_4d_slice_before_1d_idx": ( + # Value tens is 3D because with the + torch.rand(size=(5, 3, 4, 5)), + 0, + 2, + IndexTensorTestCommon.BEFORE, + (torch.arange(2, dtype=torch.int32),), + ), + "test_3d_slice_before_2d_idx": ( + # TODO: MLETORCH-859 - Testing framework does not support output rank > 4 + # With the bellow configuration a 4D value tensor and 2D index tensor + # results in a 5D output. + torch.arange(5 * 3 * 4, dtype=torch.float32).reshape(5, 3, 4), + 0, + 2, + IndexTensorTestCommon.BEFORE, + (torch.arange(2, dtype=torch.int32).unsqueeze(0).tile(2, 1),), + ), + "test_4d_slice_middle": ( + torch.arange(5 * 3 * 2, dtype=torch.int32).reshape(5, 3, 2), + 0, + 2, + IndexTensorTestCommon.MIDDLE, + ( + torch.arange(2, dtype=torch.int32), + torch.arange(2, dtype=torch.int32), + ), + ), + "test_4d_slice_after": ( + # Due to the information passed to the NodeVisitor and + # preceding passes, detecting this and rejecting it for + # partitioning is difficult and unreliable, as such + # it is not xfail as the existing logic can handle it. + torch.rand(size=(25, 5, 13, 7)), + 0, + 2, + IndexTensorTestCommon.AFTER, + (torch.arange(2, dtype=torch.int32),), + ), + } + + def forward( + self, + input_: torch.Tensor, + slice_start: int, + slice_end: int, + position: str, + indices: Tuple[None | torch.Tensor], + ): + match position: + case IndexTensorTestCommon.BEFORE: + return input_[slice_start:slice_end, indices[0]] + case IndexTensorTestCommon.MIDDLE: + return input_[indices[0], slice_start:slice_end, indices[1]] + case IndexTensorTestCommon.AFTER: + return input_[indices[0], slice_start:slice_end] + + +@common.parametrize( + "test_data", + IndexTensor_Slice.test_data, + xfails={ + # More info in index_tensor_support.py + "test_4d_slice_before_1d_idx": "Slice before index unsupported", + "test_3d_slice_before_2d_idx": "Slice before index unsupported", + "test_4d_slice_middle": "Slice before index unsupported", + }, +) +def test_index_tensor_tosa_FP_slice(test_data: input_params_slice): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params_slice]( + IndexTensor_Slice(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor_Slice.test_data, + xfails={ + # More info in index_tensor_support.py + "test_4d_slice_before_1d_idx": "Slice before index unsupported", + "test_3d_slice_before_2d_idx": "Slice before index unsupported", + "test_4d_slice_middle": "Slice before index unsupported", + }, +) +def test_index_tensor_tosa_INT_slice(test_data: input_params_slice): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params_slice]( + IndexTensor_Slice(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +class IndexTensor(torch.nn.Module): + test_data: dict[input_params] = { + "test_2d_1_idx": (torch.rand(5, 2), (torch.arange(5, dtype=torch.int32),)), + "test_2d_1_less_than_max_idx": ( + torch.rand(5, 2), + (torch.arange(3, dtype=torch.int32),), + ), + "test_2d_1_2d_idx": ( + torch.rand(5, 2), + (torch.randint(5, size=(4, 3), dtype=torch.int32)), + ), + "test_2d_2_idx": ( + torch.rand(5, 2), + ( + torch.randint(5, size=(5,), dtype=torch.int32), + torch.randint(2, size=(5,), dtype=torch.int32), + ), + ), + "test_2d_2_2d_idx_broadcastable": ( + torch.rand(5, 2), + ( + torch.randint(5, size=(5, 3), dtype=torch.int32), + torch.randint(2, size=(1, 3), dtype=torch.int32), + ), + ), + "test_2d_2_2d_idx_broadcastable_2": ( + torch.rand(5, 2), + ( + torch.randint(5, size=(5, 1), dtype=torch.int32), + torch.randint(2, size=(3,), dtype=torch.int32), + ), + ), + "test_3d_1_idx": (torch.rand(12, 3, 7), (torch.arange(12, dtype=torch.int32),)), + "test_3d_2_idx": ( + torch.rand(12, 3, 7), + ( + torch.arange(12, dtype=torch.int32), + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + "test_3d_3_idx": ( + torch.rand(12, 3, 7), + ( + torch.arange(12, dtype=torch.int32), + torch.randint(3, size=(12,), dtype=torch.int32), + torch.randint(7, size=(12,), dtype=torch.int32), + ), + ), + "test_4d_1_idx": ( + torch.rand(15, 3, 7, 2), + (torch.arange(15, dtype=torch.int32),), + ), + "test_4d_2_idx": ( + torch.rand(15, 3, 7, 2), + ( + torch.randint(15, size=(15,), dtype=torch.int32), + torch.randint(3, size=(1,), dtype=torch.int32), + ), + ), + "test_4d_3_idx": ( + torch.rand(15, 3, 7, 2), + ( + torch.arange(15, dtype=torch.int32), + torch.randint(3, size=(15,), dtype=torch.int32), + torch.randint(7, size=(15,), dtype=torch.int32), + ), + ), + "test_4d_4_id_broadcastable": ( + torch.rand(15, 3, 7, 2), + ( + torch.arange(15, dtype=torch.int32), + torch.randint(3, size=(3, 1), dtype=torch.int32), + torch.randint(6, size=(6, 1, 1), dtype=torch.int32), + torch.randint(2, size=(15,), dtype=torch.int32), + ), + ), + } + + # xfail - None (unsqueeze) unsupported + test_data_none: dict[input_params] = { + "test_3d_3_idx_with_none_before": ( + torch.rand(12, 3, 7), + ( + None, + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + "test_3d_3_idx_with_2_none_before": ( + torch.rand(12, 3, 7), + ( + None, + None, + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + "test_3d_3_idx_with_none_around": ( + torch.rand(12, 3, 7), + ( + None, + torch.randint(3, size=(12,), dtype=torch.int32), + None, + ), + ), + "test_3d_3_idx_with_none_after": ( + # Due to the information passed to the NodeVisitor and + # preceding passes, detecting this and rejecting it for + # partitioning is difficult and unreliable, as such + # it is not xfail as the existing logic can handle it. + torch.rand(12, 3, 7), + ( + torch.randint(3, size=(12,), dtype=torch.int32), + None, + ), + ), + "test_3d_3_idx_with_none_middle": ( + torch.rand(12, 3, 7), + ( + torch.randint(3, size=(12,), dtype=torch.int32), + None, + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + } + + def forward(self, input_: torch.Tensor, indices: Tuple[None | torch.Tensor]): + return input_[indices] + + +@common.parametrize("test_data", IndexTensor.test_data) +def test_index_tensor_tosa_FP(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize("test_data", IndexTensor.test_data) +def test_index_tensor_tosa_INT(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor.test_data_none, + xfails={ + # More info in index_tensor_support.py + "test_3d_3_idx_with_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_2_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_around": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_middle": "None (Unsqueeze) unsupported", + }, +) +def test_index_tensor_tosa_FP_none(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor.test_data_none, + xfails={ + # More info in index_tensor_support.py + "test_3d_3_idx_with_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_2_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_around": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_middle": "None (Unsqueeze) unsupported", + }, +) +def test_index_tensor_tosa_INT_none(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +@common.parametrize("test_data", IndexTensor.test_data) +@common.XfailIfNoCorstone300 +def test_index_tensor_u55_INT_not_delegated(test_data: input_params): + """Ethos-U55 backend BI pipeline test for index.Tensor""" + test_input = test_data + with torch.no_grad(): + OpNotSupportedPipeline[input_params]( + IndexTensor(), + test_input, + {IndexTensorTestCommon.exir_op: 1}, + quantize=True, + u55_subset=True, + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_layer_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_layer_norm.py new file mode 100644 index 0000000..232fa0c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_layer_norm.py @@ -0,0 +1,186 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List, Union + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class LayerNorm(torch.nn.Module): + + def __init__( + self, + normalized_shape: Union[int, List[int]], + eps: float = 1e-5, + elementwise_affine: bool = True, + has_bias: bool = True, + ): + super().__init__() + self.layer_norm = torch.nn.LayerNorm( + normalized_shape, + eps=eps, + elementwise_affine=elementwise_affine, + bias=has_bias, + ) + if elementwise_affine: + self.layer_norm.weight = torch.nn.Parameter(torch.ones(normalized_shape)) + if has_bias: + self.layer_norm.bias = torch.nn.Parameter(torch.rand(normalized_shape)) + + def forward(self, x): + return self.layer_norm(x) + + +input_t = tuple[torch.Tensor] +test_data_suite = { + "randn_last_dim": lambda: ((torch.randn(1, 5, 5, 5),), LayerNorm([5])), + "rand_last_two_dims": lambda: ((torch.rand(1, 5, 5, 5),), LayerNorm([5, 5])), + "rand_last_two_dims_not_elementwise_affine": lambda: ( + (torch.rand(1, 5, 5, 5),), + LayerNorm([5, 5], 1e-5, False), + ), + "rand_last_two_dims_not_elementwise_affine_no_bias": lambda: ( + (torch.rand(1, 5, 5, 5),), + LayerNorm([5, 5], 1e-5, False, False), + ), + "randn_last_three_dims": lambda: ( + (torch.randn(1, 15, 10, 5),), + LayerNorm([15, 10, 5]), + ), + "randn_last_three_dims_no_bias": lambda: ( + (torch.randn(1, 15, 10, 5),), + LayerNorm([15, 10, 5], 1e-2, False, False), + ), +} + + +@common.parametrize("test_data", test_data_suite) +def test_native_layer_norm_tosa_FP(test_data): + test_data, model = test_data() + pipeline = TosaPipelineFP[input_t]( + model, + test_data, + "torch.ops.aten.layer_norm.default", + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_native_layer_norm_tosa_INT(test_data): + test_data, model = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + test_data, + "torch.ops.aten.sub.Tensor", # Just check for sub op included in the layernorm decomposition + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_layer_norm_u55_INT(test_data): + test_data, model = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + test_data, + "torch.ops.aten.sub.Tensor", # Just check for sub op included in the layernorm decomposition + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_layer_norm_u85_INT(test_data): + test_data, model = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + test_data, + "torch.ops.aten.sub.Tensor", # Just check for sub op included in the layernorm decomposition + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_layer_norm_vgf_no_quant(test_data): + test_input, model = test_data() + pipeline = VgfPipeline[input_t]( + model, + test_input, + "torch.ops.aten.layer_norm.default", + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_layer_norm_vgf_quant(test_data): + test_input, model = test_data() + pipeline = VgfPipeline[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_native_layer_norm_tosa_INT_a16w8(test_data): + """Test layer_norm with int16 I/O quantization for TOSA INT.""" + test_input, model = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", # check for sub op in decomposition + symmetric_io_quantization=True, + tosa_extensions=["int16"], + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_layer_norm_16a8w_u55_INT(test_data): + """Test layer_norm with int16 I/O quantization for U55""" + test_input, model = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", + symmetric_io_quantization=True, + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_layer_norm_16a8w_u85_INT(test_data): + """Test layer_norm with int16 I/O quantization for U85""" + test_input, model = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", + symmetric_io_quantization=True, + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_le.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_le.py new file mode 100644 index 0000000..6ed49c9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_le.py @@ -0,0 +1,296 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t = Tuple[torch.Tensor] + + +class LessEqual(torch.nn.Module): + aten_op_tensor = "torch.ops.aten.le.Tensor" + aten_op_scalar = "torch.ops.aten.le.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_le_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor, + ): + return input_ <= other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_le_tensor_rank1_ones = LessEqual( + torch.ones(5), + torch.ones(5), +) +op_le_tensor_rank2_rand = LessEqual( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_le_tensor_rank3_randn = LessEqual( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_le_tensor_rank4_randn = LessEqual( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_le_scalar_rank1_ones = LessEqual(torch.ones(5), 1.0) +op_le_scalar_rank2_rand = LessEqual(torch.rand(4, 5), 0.2) +op_le_scalar_rank3_randn = LessEqual(torch.randn(10, 5, 2), -0.1) +op_le_scalar_rank4_randn = LessEqual(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "le_tensor_rank1_ones": lambda: op_le_tensor_rank1_ones, + "le_tensor_rank2_rand": lambda: op_le_tensor_rank2_rand, + "le_tensor_rank3_randn": lambda: op_le_tensor_rank3_randn, + "le_tensor_rank4_randn": lambda: op_le_tensor_rank4_randn, +} + +test_data_scalar = { + "le_scalar_rank1_ones": lambda: op_le_scalar_rank1_ones, + "le_scalar_rank2_rand": lambda: op_le_scalar_rank2_rand, + "le_scalar_rank3_randn": lambda: op_le_scalar_rank3_randn, + "le_scalar_rank4_randn": lambda: op_le_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_le_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_le_scalar_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_scalar, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_le_tensor_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_le_scalar_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_le_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_le_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_le_tensor_u55_INT_not_delegated(test_module): + # GREATER_EQUAL is not supported on U55. LE uses the GREATER_EQUAL Tosa operator. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessEqual.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_le_scalar_u55_INT_not_delegated(test_module): + # GREATER_EQUAL is not supported on U55. LE uses the GREATER_EQUAL Tosa operator. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessEqual.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.dump_operator_distribution("export") + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_le_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_le_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_le_tensor_16a8w_u85_INT(test_module): + """Test le operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_le_scalar_16a8w_u85_INT(test_module): + """Test le operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_le_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_le_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_le_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_scalar, + LessEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_le_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_leaky_relu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_leaky_relu.py new file mode 100644 index 0000000..9be2485 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_leaky_relu.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.leaky_relu.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_leaky_relu_default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class LeakyReLU(torch.nn.Module): + def __init__(self, slope: float = 0.01): + super().__init__() + self.activation = torch.nn.LeakyReLU(slope) + + def forward(self, x: torch.Tensor): + return self.activation(x) + + test_data: dict[str, input_t1] = { + "zeros": lambda: ((torch.zeros(1, 1, 5, 5),), 0.01), + "ones": lambda: ((torch.ones(1, 16, 96, 96),), 0.01), + "rand": lambda: ((torch.rand(1, 64, 56, 56),), 0.2), + "3Dtensor": lambda: ((torch.rand(5, 5, 5),), 0.001), + "negative_slope": lambda: ((torch.rand(1, 16, 96, 96),), -0.002), + } + + +@common.parametrize("test_data", LeakyReLU.test_data) +def test_leaky_relu_tosa_FP(test_data): + data, slope = test_data() + pipeline = TosaPipelineFP[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +def test_leaky_relu_tosa_INT(test_data): + data, slope = test_data() + pipeline = TosaPipelineINT[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.XfailIfNoCorstone300 +def test_leaky_relu_u55_INT(test_data): + data, slope = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.XfailIfNoCorstone320 +def test_leaky_relu_u85_INT(test_data): + data, slope = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.SkipIfNoModelConverter +def test_leaky_relu_vgf_no_quant(test_data): + data, slope = test_data() + pipeline = VgfPipeline[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [aten_op] + ) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.SkipIfNoModelConverter +def test_leaky_relu_vgf_quant(test_data): + data, slope = test_data() + pipeline = VgfPipeline[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linalg_vector_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linalg_vector_norm.py new file mode 100644 index 0000000..2723479 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linalg_vector_norm.py @@ -0,0 +1,160 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + +aten_op_q_decomposed_q = "torch.ops.quantized_decomposed.quantize_per_tensor.default" +exir_op_q_decomposed = "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default" + + +class VectorNormModel(torch.nn.Module): + def __init__( + self, + ord=None, + dim=1, + keepdim=False, + ): + """ + A simple module that applies torch.linalg.vector_norm to its input. + Ord is 2 by default. + """ + super().__init__() + self.ord = ord + self.dim = dim + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + if self.ord is None and self.dim is None: + return torch.linalg.vector_norm(x, keepdim=self.keepdim) + elif self.ord is None: + return torch.linalg.vector_norm(x, dim=self.dim, keepdim=self.keepdim) + elif self.dim is None: + return torch.linalg.vector_norm(x, ord=self.ord, keepdim=self.keepdim) + else: + return torch.linalg.vector_norm( + x, ord=self.ord, dim=self.dim, keepdim=self.keepdim + ) + + +test_modules = { + "default": (VectorNormModel(dim=1), (torch.rand(10, 4),)), + "ord1": (VectorNormModel(ord=1, dim=1), (torch.rand(10, 4),)), + "ord2": (VectorNormModel(ord=2, dim=1), (torch.rand(10, 20),)), + # Norm computed along a specific dimension of a 3D tensor + "dim_3d": (VectorNormModel(dim=2), (torch.rand(4, 5, 6),)), +} + + +@common.parametrize("test_module", test_modules) +def test_vector_norm_tosa_FP(test_module): + model, input_tensor = test_module + + # We decompose LinalgVectorNorm before quantize stage to have annotations + # with q/dq nodes. In case of FP, this operator will be decomposed + # by global decompositions. + aten_op = "torch.ops.aten.linalg_vector_norm.default" + # Should not found this op + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + + pipeline = TosaPipelineFP[input_t](model, input_tensor, aten_op, exir_op) + + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_vector_norm_tosa_INT(test_module): + model, input_tensor = test_module + + # Should not found this op + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op, + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_vector_norm_u55_INT_fvp(test_module): + model, input_tensor = test_module + + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op_q_decomposed, + symmetric_io_quantization=True, + ) + pipeline.pop_stage("check_not.exir") + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_vector_norm_u85_INT_fvp(test_module): + model, input_tensor = test_module + + # The should be decomposed and annotated in DecomposeLinalgVectorNorm pass. + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op_q_decomposed, + symmetric_io_quantization=True, + ) + pipeline.pop_stage("check_not.exir") + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_vector_norm_vgf_no_quant(test_module): + model, input_tensor = test_module + # FP VGF + aten_op = "torch.ops.aten.linalg_vector_norm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_vector_norm_vgf_quant(test_module): + model, input_tensor = test_module + # Should not found this op + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linear.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linear.py new file mode 100644 index 0000000..7e22ad3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_linear.py @@ -0,0 +1,389 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_a8w4_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.linear.default" + +input_t1 = Tuple[torch.Tensor] + +test_data_rank1_FP = { + # test_name: (test_data, out_features, has_bias) + "model_linear_rank1_zeros": lambda: ( + torch.zeros(10), + 15, + True, + ), + "model_linear_rank1_ones": lambda: ( + torch.ones(10), + 15, + False, + ), + "model_linear_rank1_negative_ones": lambda: ( + torch.ones(10) * (-1), + 20, + True, + ), + "model_linear_rank1_rand": lambda: ( + torch.rand(10), + 10, + True, + ), + "model_linear_rank1_negative_large_rand": lambda: ( + torch.rand(10) * (-100), + 30, + False, + ), + "model_linear_rank1_large_randn": lambda: ( + torch.randn(15) * 100, + 20, + True, + ), +} + +test_data_rank4_FP = { + # test_name: (test_data, out_features, has_bias) + "model_linear_rank4_zeros": lambda: ( + torch.zeros(5, 10, 25, 20), + 30, + True, + ), + "model_linear_rank4_ones": lambda: ( + torch.ones(5, 10, 25, 20), + 30, + False, + ), + "model_linear_rank4_negative_ones": lambda: ( + torch.ones(5, 10, 25, 20) * (-1), + 30, + True, + ), + "model_linear_rank4_rand": lambda: ( + torch.rand(5, 10, 25, 20), + 30, + False, + ), + "model_linear_rank4_negative_large_rand": lambda: ( + torch.rand(5, 10, 25, 20) * (-100), + 30, + True, + ), + "model_linear_rank4_large_randn": lambda: ( + torch.randn(5, 10, 25, 20) * 100, + 30, + False, + ), +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_rank1_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (*v(), q)) + for (k, v) in test_data_rank1_FP.items() + for q in [True, False] +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_rank4_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (*v(), q)) + for (k, v) in test_data_rank4_FP.items() + for q in [True, False] +} + + +class Linear(torch.nn.Module): + def __init__( + self, + in_features: int, + out_features: int = 3, + bias: bool = True, + ): + super().__init__() + self.fc = torch.nn.Linear( + in_features=in_features, + out_features=out_features, + bias=bias, + ) + + def forward(self, x): + return self.fc(x) + + +@common.parametrize("test_data", test_data_rank1_FP | test_data_rank4_FP) +def test_linear_tosa_FP(test_data: torch.Tensor): + test_data, out_features, has_bias = test_data() + in_features = test_data.shape[-1] + pipeline = TosaPipelineFP[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT | test_data_rank4_INT) +def test_linear_tosa_INT(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + pipeline = TosaPipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT | test_data_rank4_INT) +def test_linear_tosa_INT_a8w4(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + pipeline = TosaPipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + tosa_extensions=["int4"], + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + { + "CONST": {"INT4": 2}, + "CONV2D": {"INT32": 1}, + "RESCALE": {"INT8": 1}, + }, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT) +@common.XfailIfNoCorstone300 +def test_linear_u55_INT(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + EthosU55PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize( + "test_data", + test_data_rank1_INT | test_data_rank4_INT, +) +@common.XfailIfNoCorstone320 +def test_linear_u85_INT(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + EthosU85PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize("test_data", test_data_rank1_FP | test_data_rank4_FP) +@common.SkipIfNoModelConverter +def test_linear_vgf_no_quant(test_data: torch.Tensor): + test_data, out_features, has_bias = test_data() + in_features = test_data.shape[-1] + pipeline = VgfPipeline[input_t1]( + Linear(in_features=in_features, out_features=out_features, bias=has_bias), + (test_data,), + aten_op=aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT | test_data_rank4_INT) +@common.SkipIfNoModelConverter +def test_linear_vgf_quant(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + pipeline = VgfPipeline[input_t1]( + Linear(in_features=in_features, out_features=out_features, bias=has_bias), + (test_data,), + aten_op=aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_linear_quantizer( + u55_config=False, per_channel_quantization=False +): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + quantizer.set_module_type( + torch.nn.Linear, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +test_data_all_16a8w = test_data_rank1_INT | test_data_rank4_INT + + +@common.parametrize("test_data", test_data_all_16a8w) +def test_linear_16a8w_tosa_INT(test_data: torch.Tensor): + """Test linear operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + + # Create pipeline with custom 16A8W quantization config + pipeline = TosaPipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_linear_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + # Run the pipeline + pipeline.run() + + +@common.parametrize("test_data", test_data_all_16a8w) +@common.XfailIfNoCorstone300 +def test_linear_16a8w_u55_INT(test_data: torch.Tensor): + """Test linear operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + + pipeline = EthosU55PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_linear_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_all_16a8w) +@common.XfailIfNoCorstone320 +def test_linear_16a8w_u85_INT(test_data: torch.Tensor): + """Test linear operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + + pipeline = EthosU85PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_linear_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log.py new file mode 100644 index 0000000..3f4bfcd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log.py @@ -0,0 +1,100 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.log.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_log_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + # (test_name, test_data) + "ones_rank4": lambda: (torch.ones(1, 10, 10, 10)), + "ones_rank3": lambda: (torch.ones(10, 10, 10)), + "rand": lambda: (torch.rand(10, 10) + 0.001), + "randn_pos": lambda: (torch.randn(10) + 10), + "randn_spread": lambda: (torch.max(torch.Tensor([0.0]), torch.randn(10) * 100)), + "ramp": lambda: (torch.arange(0.01, 20, 0.2)), +} + + +class Log(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.log(x) + + +@common.parametrize("test_data", test_data_suite) +def test_log_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Log(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_log_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Log(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_log_u55_INT(test_data: input_t1): + EthosU55PipelineINT[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_log_u85_INT(test_data: input_t1): + EthosU85PipelineINT[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log1p.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log1p.py new file mode 100644 index 0000000..a8ca4a9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_log1p.py @@ -0,0 +1,78 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.log1p.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_log1p_default" + +input_t1 = Tuple[torch.Tensor] + + +def _tensor(values): + return torch.tensor(values, dtype=torch.float32) + + +test_data_suite = { + "tiny_positive": lambda: (_tensor([5e-4, 8e-4, 9e-4, 1e-3, 1.2e-3]),), + "straddle_eps": lambda: (_tensor([5e-4, 1e-3, 2e-3, -5e-4, -1e-3]),), + "mixed_range": lambda: (_tensor([1e-4, 5e-4, 2e-3, 1e-2, 5e-2]),), +} + + +class Log1p(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.log1p(x) + + +@common.parametrize("test_data", test_data_suite) +def test_log1p_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Log1p(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_log1p_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + Log1p(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log1p_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Log1p(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log1p_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Log1p(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logical.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logical.py new file mode 100644 index 0000000..a2a8279 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logical.py @@ -0,0 +1,429 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y +input_t1 = Tuple[torch.Tensor] # Input x + + +class LogicalBinary(torch.nn.Module): + test_data: dict[input_t2] = { + "rank1": lambda: ( + torch.tensor([True, True, False, False], dtype=torch.bool), + torch.tensor([True, False, True, False], dtype=torch.bool), + ), + "rand_rank2": lambda: ( + torch.randint(0, 2, (10, 10), dtype=torch.bool), + torch.randint(0, 2, (10, 10), dtype=torch.bool), + ), + "rand_rank3": lambda: ( + torch.randint(0, 2, (10, 10, 10), dtype=torch.bool), + torch.randint(0, 2, (10, 10, 10), dtype=torch.bool), + ), + "rand_rank4": lambda: ( + torch.randint(0, 2, (1, 10, 10, 10), dtype=torch.bool), + torch.randint(0, 2, (1, 10, 10, 10), dtype=torch.bool), + ), + } + + +class And(LogicalBinary): + aten_op = "torch.ops.aten.logical_and.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_and_default" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.logical_and(tensor2) + + +class Xor(LogicalBinary): + aten_op = "torch.ops.aten.logical_xor.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_xor_default" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.logical_xor(tensor2) + + +class Or(LogicalBinary): + aten_op = "torch.ops.aten.logical_or.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_or_default" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.logical_or(tensor2) + + +class Not(torch.nn.Module): + test_data: dict[input_t1] = { + "rank1": lambda: (torch.tensor([True, True, False, False], dtype=torch.bool),), + "rand_rank2": lambda: (torch.randint(0, 2, (10, 10), dtype=torch.bool),), + "rand_rank3": lambda: (torch.randint(0, 2, (10, 10, 10), dtype=torch.bool),), + "rand_rank4": lambda: (torch.randint(0, 2, (1, 10, 10, 10), dtype=torch.bool),), + } + + aten_op = "torch.ops.aten.logical_not.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_not_default" + + def forward(self, tensor: torch.Tensor): + return torch.logical_not(tensor) + + +################# +## logical_and ## +################# + + +@common.parametrize("test_data", And().test_data) +def test_logical_and_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_logical_and_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_logical_and_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.XfailIfNoCorstone320 +def test_logical_and_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_logical_and_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_logical_and_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + quantize=True, + ) + pipeline.run() + + +################# +## logical_xor ## +################# + + +@common.parametrize("test_data", Xor().test_data) +def test_logical_xor_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_logical_xor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_logical_xor_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.XfailIfNoCorstone320 +def test_logical_xor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_logical_xor_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_logical_xor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + quantize=True, + ) + pipeline.run() + + +################ +## logical_or ## +################ + + +@common.parametrize("test_data", Or().test_data) +def test_logical_or_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_logical_or_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_logical_or_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.XfailIfNoCorstone320 +def test_logical_or_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_logical_or_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_logical_or_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + quantize=True, + ) + pipeline.run() + + +################# +## logical_not ## +################# + + +@common.parametrize("test_data", Not().test_data) +def test_logical_not_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +def test_logical_not_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +def test_logical_not_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Not(), + test_data(), + {Not().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +@common.XfailIfNoCorstone320 +def test_logical_not_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +@common.SkipIfNoModelConverter +def test_logical_not_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +@common.SkipIfNoModelConverter +def test_logical_not_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logit.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logit.py new file mode 100644 index 0000000..b628504 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logit.py @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.logit.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__logit_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": [torch.zeros((10, 10, 10)), None], + "ones": [torch.ones((10, 10, 10)), None], + "uniform_valid": [torch.rand((10, 10, 10)), None], + "near_zero": [torch.full((10, 10), 1e-8), None], + "near_one": [torch.full((10, 10), 1 - 1e-8), None], + "mixed": [torch.tensor([0.0, 1e-5, 0.5, 1 - 1e-5, 1.0]), None], + "multi_dim": [torch.rand((2, 3, 4)), None], + "eps": [torch.zeros((10, 10, 10)), 1e-6], + "invalid_neg": [torch.full((5,), -0.1), 1e-6], + "invalid_gt1": [torch.full((5,), 1.1), 1e-6], +} + + +class Logit(torch.nn.Module): + + def forward(self, x: torch.Tensor, eps: torch.float32): + return torch.logit(x, eps=eps) + + +@common.parametrize("test_data", test_data_suite) +def test_logit_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Logit(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_logit_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Logit(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_logit_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Logit(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_logit_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Logit(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_logit_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Logit(), + (*test_data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_logit_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Logit(), + (*test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logsoftmax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logsoftmax.py new file mode 100644 index 0000000..8d090b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_logsoftmax.py @@ -0,0 +1,124 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.log_softmax.default" # Used for checking that we do not have log_softmax in the graph +exir_op = "executorch_exir_dialects_edge__ops_aten__log_softmax_tensor" + +input_t1 = Tuple[torch.Tensor] # Input x + + +class LogSoftmax(torch.nn.Module): + def __init__(self, dim: int = -1): + super().__init__() + self.log_softmax = torch.nn.LogSoftmax(dim=dim) + + def forward(self, x): + return self.log_softmax(x) + + test_data = { + "ones": lambda: ((torch.ones(10, 10),), 1), + "ones_neg_dim": lambda: ((torch.ones(1, 3, 4),), -1), + "randn_neg_dim": lambda: ((torch.randn(1, 5, 8, 7),), -3), + "zeros": lambda: ((torch.zeros(1, 8, 5, 2),), 0), + "zeros_neg_dim": lambda: ((torch.zeros(1, 7, 8, 9),), -4), + "rand": lambda: ((torch.rand(1, 2, 5, 8),), 2), + "rand_neg_dim": lambda: ((torch.rand(1, 10, 8, 10),), -2), + "randn_mult_batches": lambda: ((torch.randn(2, 10, 10, 10),), 3), + } + + +@common.parametrize("test_data", LogSoftmax.test_data) +def test_log_softmax_tosa_FP(test_data): + data, dim = test_data() + pipeline = TosaPipelineFP[input_t1](LogSoftmax(dim), data, []) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + + pipeline.run() + + +@pytest.mark.flaky(reruns=5) +@common.parametrize("test_data", LogSoftmax.test_data) +def test_log_softmax_tosa_INT(test_data): + data, dim = test_data() + pipeline = TosaPipelineINT[input_t1](LogSoftmax(dim), data, []) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.XfailIfNoCorstone300() +def test_log_softmax_u55_INT(test_data): + data, dim = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + LogSoftmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.XfailIfNoCorstone320 +def test_log_softmax_u85_INT(test_data): + data, dim = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + LogSoftmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.SkipIfNoModelConverter +def test_log_softmax_vgf_no_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + LogSoftmax(dim), + data, + [], + [], + quantize=False, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [aten_op] + ) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.SkipIfNoModelConverter +def test_log_softmax_vgf_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + LogSoftmax(dim), + data, + [], + [], + quantize=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lshift.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lshift.py new file mode 100644 index 0000000..573b0ec --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lshift.py @@ -0,0 +1,220 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.common import ( + XfailIfNoCorstone300, + XfailIfNoCorstone320, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +scalar_input_t = tuple[torch.Tensor, int] + + +class LshiftScalar(torch.nn.Module): + torch_op_FP = "torch.ops.aten.__lshift__.Scalar" + torch_op_INT = "torch.ops.aten.bitwise_left_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_left_shift_Tensor" + test_data = { + "randint_neg_8_int8": ( + torch.randint(-8, 8, (1, 12, 3, 4), dtype=torch.int8), + 1, + ), + "randint_neg_100_int16": ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int16), + 5, + ), + "randint_neg_100_int32": ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int32), + 2, + ), + } + + def forward(self, x: torch.Tensor, shift: int): + return x << shift + + +tensor_input_t = tuple[torch.Tensor, torch.Tensor] + + +class LshiftTensor(torch.nn.Module): + torch_op = "torch.ops.aten.bitwise_left_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_left_shift_Tensor" + test_data = { + "randint_neg_8_tensor_int8": ( + torch.randint(-8, 8, (3, 3), dtype=torch.int8), + torch.randint(0, 4, (3, 3), dtype=torch.int8), + ), + "randint_neg_1024_tensor_int16": ( + torch.randint(-1024, 1024, (3, 3, 3), dtype=torch.int16), + torch.randint(0, 5, (3, 3, 3), dtype=torch.int16), + ), + "randint_0_tensor_int16": ( + torch.randint(0, 127, (1, 2, 3, 3), dtype=torch.int32), + torch.randint(0, 5, (1, 2, 3, 3), dtype=torch.int32), + ), + } + + def forward(self, x: torch.Tensor, shift: torch.Tensor): + return x.bitwise_left_shift(shift) + + +################## +## LshiftScalar ## +################## + + +@common.parametrize("test_data", LshiftScalar.test_data) +def test_bitwise_left_shift_scalar_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_FP, + LshiftScalar.exir_op, + ).run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +def test_bitwise_left_shift_scalar_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@XfailIfNoCorstone300 +def test_bitwise_left_shift_scalar_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@XfailIfNoCorstone320 +def test_bitwise_left_shift_scalar_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_scalar_vgf_no_quant(test_data: scalar_input_t): + pipeline = VgfPipeline[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_FP, + LshiftScalar.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_scalar_vgf_quant(test_data: scalar_input_t): + pipeline = VgfPipeline[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + quantize=True, + ) + pipeline.run() + + +################## +## LshiftTensor ## +################## + + +@common.parametrize("test_data", LshiftTensor.test_data) +def test_bitwise_left_shift_tensor_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ).run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +def test_bitwise_left_shift_tensor_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.XfailIfNoCorstone300 +def test_bitwise_left_shift_tensor_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.XfailIfNoCorstone320 +def test_bitwise_left_shift_tensor_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_tensor_vgf_no_quant(test_data: tensor_input_t): + pipeline = VgfPipeline[tensor_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_tensor_vgf_quant(test_data: tensor_input_t): + pipeline = VgfPipeline[tensor_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lt.py new file mode 100644 index 0000000..8b5b5c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_lt.py @@ -0,0 +1,293 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +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 + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ < other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_lt_tensor_rank1_ones = LessThan( + torch.ones(5), + torch.ones(5), +) +op_lt_tensor_rank2_rand = LessThan( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_lt_tensor_rank3_randn = LessThan( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_lt_tensor_rank4_randn = LessThan( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +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": lambda: op_lt_tensor_rank1_ones, + "lt_tensor_rank2_rand": lambda: op_lt_tensor_rank2_rand, + "lt_tensor_rank3_randn": lambda: op_lt_tensor_rank3_randn, + "lt_tensor_rank4_randn": lambda: op_lt_tensor_rank4_randn, +} + +test_data_scalar = { + "lt_scalar_rank1_ones": lambda: op_lt_scalar_rank1_ones, + "lt_scalar_rank2_rand": lambda: op_lt_scalar_rank2_rand, + "lt_scalar_rank3_randn": lambda: op_lt_scalar_rank3_randn, + "lt_scalar_rank4_randn": lambda: op_lt_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_lt_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[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_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + 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_INT(test_module): + pipeline = TosaPipelineINT[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_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_lt_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_lt_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_lt_tensor_u55_INT_not_delegated(test_module): + # LessThan is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessThan.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_lt_scalar_u55_INT_not_delegated(test_module): + # LessThan is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessThan.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_lt_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_lt_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_lt_tensor_16a8w_u85_INT(test_module): + """Test lt operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_lt_scalar_16a8w_u85_INT(test_module): + """Test lt operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_lt_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_lt_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_scalar, + LessThan.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_lt_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_lt_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_masked_fill.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_masked_fill.py new file mode 100644 index 0000000..2704fa5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_masked_fill.py @@ -0,0 +1,171 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +aten_op = "torch.aten.ops.masked_fill.Scalar" +exir_op = "executorch_exir_dialects_edge__ops_aten_masked_fill_scalar" + +input_t = Tuple[torch.Tensor, torch.Tensor, float] + + +class MaskedFill(torch.nn.Module): + def forward( + self, x: torch.Tensor, mask: torch.Tensor, value: float + ) -> torch.Tensor: + return torch.masked_fill(x, mask, value) + + +test_modules = { + "masked_fill_1": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + (torch.rand(1, 3, 4, 5) < 0.5), # boolean mask + -1.0, + ), + ), + "masked_fill_2": lambda: ( + MaskedFill(), + ( + torch.rand(1, 10, 10, 10), + (torch.rand(1, 10, 10, 10) > 0.75), + 3.14, + ), + ), + "masked_fill_3_zero_fill": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + torch.rand(1, 3, 4, 5) < 0.2, + 0.0, + ), + ), + "masked_fill_4_full_mask": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + torch.ones(1, 3, 4, 5, dtype=torch.bool), + 7.0, + ), + ), + "masked_fill_5_no_mask": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + torch.zeros(1, 3, 4, 5, dtype=torch.bool), + -3.0, + ), + ), + "masked_fill_6_scalar_broadcast": lambda: ( + MaskedFill(), + ( + torch.rand(1, 1, 1, 1), + torch.tensor([[[[True]]]]), + 42.0, + ), + ), + "masked_fill_7_large_tensor": lambda: ( + MaskedFill(), + ( + torch.rand(1, 8, 8, 8), + torch.rand(1, 8, 8, 8) > 0.5, + -127.0, + ), + ), + "masked_fill_8_extreme_scalar_inf": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 7, 5), + torch.rand(1, 3, 7, 5) > 0.5, + float("inf"), + ), + ), +} + + +@common.parametrize("test_module", test_modules) +def test_masked_fill_scalar_tosa_FP(test_module): + module, inputs = test_module() + pipeline = TosaPipelineFP[input_t](module, inputs, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_masked_fill_scalar_tosa_INT(test_module): + module, inputs = test_module() + pipeline = TosaPipelineINT[input_t]( + module, + inputs, + aten_op=[], + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_masked_fill_scalar_u55_INT(test_module): + module, inputs = test_module() + pipeline = OpNotSupportedPipeline[input_t]( + module, + inputs, + {exir_op: 0, "executorch_exir_dialects_edge__ops_aten_where_self": 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_masked_fill_scalar_u85_INT(test_module): + module, inputs = test_module() + pipeline = EthosU85PipelineINT[input_t]( + module, + inputs, + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_masked_fill_scalar_vgf_no_quant(test_module): + module, inputs = test_module() + pipeline = VgfPipeline[input_t]( + module, + inputs, + aten_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_masked_fill_scalar_vgf_quant(test_module): + module, inputs = test_module() + pipeline = VgfPipeline[input_t]( + module, + inputs, + aten_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_matmul.py new file mode 100644 index 0000000..c9d5665 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_matmul.py @@ -0,0 +1,289 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op_mm = "torch.ops.aten.matmul.default" +exir_op_mm = "executorch_exir_dialects_edge__ops_aten_matmul_default" +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class MatMul(torch.nn.Module): + test_data_generators = { + "rand_rand_2d": lambda: (torch.rand(5, 5), torch.rand(5, 2)), + "rand_rand_3d": lambda: (torch.rand(2, 3, 5), torch.rand(2, 5, 2)), + "rand_rand_4d": lambda: (torch.rand(1, 2, 3, 5), torch.rand(1, 2, 5, 2)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return torch.matmul(x, y) + + +class MatMulSingleInput(torch.nn.Module): + test_data_generators = { + "rand_2d": lambda: (torch.rand(5, 5),), + "rand_3d": lambda: (torch.rand(2, 5, 5),), + "rand_4d": lambda: (torch.rand(1, 2, 5, 5),), + } + + def forward(self, x: torch.Tensor): + return torch.matmul(x, x) + + +class MatMulCombo(torch.nn.Module): + test_data_generators = { + "rand_rand_rand_2d": lambda: ( + torch.rand(5, 5), + torch.rand(5, 2), + torch.rand(2, 5), + ), + "rand_rand_rand_3d": lambda: ( + torch.rand(2, 5, 5), + torch.rand(2, 5, 2), + torch.rand(2, 2, 5), + ), + "rand_rand_rand_4d": lambda: ( + torch.rand(1, 2, 5, 5), + torch.rand(1, 2, 5, 2), + torch.rand(1, 2, 2, 5), + ), + } + + def forward(self, x1: torch.Tensor, x2: torch.Tensor, x3: torch.Tensor): + y1 = torch.matmul(x1, x1) + y2 = torch.matmul(x2, x3) + return y1 + y2 + + +@common.parametrize("test_data", MatMul.test_data_generators) +def test_matmul_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](MatMul(), test_data(), aten_op_mm, exir_op_mm) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +def test_matmul_tosa_FP_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + MatMulSingleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +def test_matmul_tosa_FP_combo(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + MatMulCombo(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +def test_matmul_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + MatMul(), test_data(), aten_op_mm, exir_op_mm, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +def test_matmul_tosa_INT_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +def test_matmul_tosa_INT_combo(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.XfailIfNoCorstone300 +def test_matmul_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulSingleInput.test_data_generators, +) +@common.XfailIfNoCorstone300 +def test_matmul_u55_INT_single_input(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulCombo.test_data_generators, +) +@common.XfailIfNoCorstone300 +def test_matmul_u55_INT_combo(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.XfailIfNoCorstone320 +def test_matmul_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulSingleInput.test_data_generators, +) +@common.XfailIfNoCorstone320 +def test_matmul_u85_INT_single_input(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulCombo.test_data_generators, +) +@common.XfailIfNoCorstone320 +def test_matmul_u85_INT_combo(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_combo(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_combo(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_max_pool.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_max_pool.py new file mode 100644 index 0000000..b2cd807 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_max_pool.py @@ -0,0 +1,329 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data, [kernel_size, stride, padding]) + "zeros": lambda: (torch.zeros(1, 1, 4, 8), [(4, 6), 2, (2, 0)]), + "ones": lambda: (torch.ones(1, 16, 50, 32), [4, 2, 0]), + "rand": lambda: (torch.rand(1, 16, 52, 16), [4, 3, 0]), + "non_divisible": lambda: (torch.rand(1, 16, 112, 112), [3, 2, 1]), + "non_divisible_window_height": lambda: (torch.rand(1, 16, 56, 56), [3, (2, 1), 1]), + "non_divisible_window_width": lambda: (torch.rand(1, 16, 56, 56), [3, (1, 2), 1]), + "non_divisible_ceil_mode": lambda: ( + torch.rand(1, 16, 112, 112), + [3, 2, 1, 1, True], + ), + "non_divisible_window_height_ceil_mode": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (2, 1), 1, 1, True], + ), + "non_divisible_window_width_ceil_mode": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (1, 2), 1, 1, True], + ), + "non_divisible_window_adjust_padding": lambda: ( + torch.rand(1, 16, 112, 112), + [3, 2, 1], + ), + "non_divisible_window_height_adjust_padding": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (2, 1), 1], + ), + "non_divisible_window_width_adjust_padding": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (1, 2), 1], + ), + "non_divisble_no_padding": lambda: (torch.rand(1, 16, 56, 56), [3, 2, 0]), + "non_divisible_window_adjust_padding+input": lambda: ( + torch.rand(1, 16, 54, 54), + [3, 3, 1], + ), + "non_divisible_window_height_adjust_padding+input": lambda: ( + torch.rand(1, 16, 54, 54), + [3, (3, 1), 1], + ), + "non_divisible_window_width_adjust_padding+input": lambda: ( + torch.rand(1, 16, 54, 54), + [3, (1, 3), 1], + ), + "randn": lambda: (torch.randn(5, 16, 50, 32), [4, 2, 0]), +} + + +test_data_suite_dilation = [ + # Simple dilation=2 on 8x8 input, kernel=3, stride=1, no padding + ("dilation2", torch.rand(1, 1, 8, 8), [3, 1, 0, 2]), + # Input is 6x6, kernel=3, stride=1, dilation=2. + # Padding=1 expands the effective input to 8x8. + ("pad_then_dil2", torch.rand(1, 1, 6, 6), [3, 1, 1, 2]), + # Input is 16x16, kernel=2x2, stride=2x2, dilation=1 (no dilation). + # Padding of 1 ensures the input size remains divisible by stride + # after padding. + ("even_kernel_fast", torch.rand(1, 3, 16, 16), [(2, 2), (2, 2), (1, 1), 1]), + # Multi-batch, multi-channel input (N=4, C=3), kernel=3x3, + # stride=3x3, no padding, dilation=1. + ("mb_ch_dil1", torch.rand(4, 3, 12, 12), [(3, 3), (3, 3), 0, 1]), +] + +aten_op = "torch.ops.aten.max_pool2d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_max_pool2d_default" + +input_t1 = Tuple[torch.Tensor] + + +class MaxPool2d(torch.nn.Module): + def __init__( + self, + kernel_size: int | Tuple[int, int], + stride: int | Tuple[int, int], + padding: int | Tuple[int, int], + dilation: int | Tuple[int, int] = 1, + ceil_mode: bool = False, + ): + super().__init__() + self.max_pool_2d = torch.nn.MaxPool2d( + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + ceil_mode=ceil_mode, + ) + + def forward(self, x): + return self.max_pool_2d(x) + + +@common.parametrize("test_data", test_data_suite) +def test_max_pool2d_tosa_FP(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + MaxPool2d(*model_params), (test_data,), aten_op, exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_max_pool2d_tosa_INT(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_max_pool2d_tosa_INT_a16w8(test_data: torch.Tensor): + """Test max_pool2d operation with int16 I/O quantization for TOSA INT.""" + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_max_pool2d_u55_INT(test_data: torch.Tensor): + test_data, model_params = test_data() + EthosU55PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_max_pool2d_16a8w_u55_INT(test_data: torch.Tensor): + """Test max_pool2d with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + test_data, model_params = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_max_pool2d_u85_INT(test_data: torch.Tensor): + test_data, model_params = test_data() + EthosU85PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_max_pool2d_16a8w_u85_INT(test_data: torch.Tensor): + """Test max_pool2d with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + test_data, model_params = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +reject_data_suite = { + "reject_1": lambda: (MaxPool2d(1, 4, 0), torch.rand(1, 10, 10, 10)), + "reject_2": lambda: (MaxPool2d((1, 257), 1, 0), torch.rand(1, 16, 5, 300)), + "reject_3": lambda: (MaxPool2d((800, 90), 1, 0), torch.rand(1, 16, 850, 100)), +} + + +@common.parametrize("test_data", reject_data_suite) +@common.XfailIfNoCorstone300 +def test_max_pool2d_u55_INT_failure_set(test_data: Tuple): + module, test_data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + (test_data,), + aten_op, + exir_op, + run_on_fvp=False, + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +# Convert the list of (name, tensor, params) into the dict-of-lambdas shape +dilation_test_data = { + name: (lambda data=data, params=params: (data, params)) + for name, data, params in test_data_suite_dilation +} + + +@common.parametrize("test_data", dilation_test_data) +def test_max_pool2d_tosa_FP_dilation(test_data): + """ + TOSA FP pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + MaxPool2d(*model_params), + (data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", dilation_test_data) +def test_max_pool2d_tosa_INT_dilation(test_data): + """ + TOSA INT pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + MaxPool2d(*model_params), + (data,), + aten_op, + exir_op, + symmetric_io_quantization=True, + ) + pipeline.run() + + +# VGF tests +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_no_quant(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_quant(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", dilation_test_data) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_no_quant_dilation(test_data: torch.Tensor): + """ + VGF FP pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", dilation_test_data) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_quant_dilation(test_data: torch.Tensor): + """ + VGF INT pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_maximum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_maximum.py new file mode 100644 index 0000000..e213842 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_maximum.py @@ -0,0 +1,98 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_t = tuple[torch.Tensor, torch.Tensor] +aten_op = "torch.ops.aten.maximum.default" + + +class Maximum(torch.nn.Module): + test_parameters = { + "float_tensor": lambda: ( + torch.FloatTensor([1, 2, 3, 5, 7]), + (torch.FloatTensor([2, 1, 2, 1, 10])), + ), + "ones": lambda: (torch.ones(1, 10, 4, 6), 2 * torch.ones(1, 10, 4, 6)), + "rand_diff": lambda: (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "rand_same": lambda: (torch.randn(1, 3, 4, 4), torch.randn(1, 3, 4, 4)), + "rand_large": lambda: ( + 10000 * torch.randn(1, 1, 4, 4), + torch.randn(1, 1, 4, 1), + ), + } + + def __init__(self): + super().__init__() + + def forward(self, x, y): + return torch.maximum(x, y) + + +@common.parametrize("test_data", Maximum.test_parameters) +def test_maximum_tosa_FP(test_data: Tuple): + TosaPipelineFP[test_t](Maximum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +def test_maximum_tosa_INT(test_data: Tuple): + TosaPipelineINT[test_t](Maximum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.XfailIfNoCorstone300 +def test_maximum_u55_INT(test_data: Tuple): + EthosU55PipelineINT[test_t]( + Maximum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.XfailIfNoCorstone320 +def test_maximum_u85_INT(test_data: Tuple): + EthosU85PipelineINT[test_t]( + Maximum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.SkipIfNoModelConverter +def test_maximum_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + Maximum(), + test_data(), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.SkipIfNoModelConverter +def test_maximum_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + Maximum(), + test_data(), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mean_dim.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mean_dim.py new file mode 100644 index 0000000..5195d95 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mean_dim.py @@ -0,0 +1,388 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Callable + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] + + +class AdaptiveAveragePool2d(torch.nn.Module): + test_data_suite = { + # (test_name, test_data) + "zeros": lambda: (torch.zeros(1, 1280, 7, 7),), + "ones": lambda: (torch.ones(1, 1280, 7, 7),), + "rand": lambda: (torch.rand(1, 1280, 7, 7),), + "randn": lambda: (torch.randn(1, 1280, 7, 7),), + } + aten_op = "torch.ops.aten.adaptive_avg_pool2d.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_mean_dim" + + def __init__(self): + super().__init__() + self.adaptive_avg_pool2d = torch.nn.AdaptiveAvgPool2d(output_size=(1, 1)) + + def forward(self, x): + return self.adaptive_avg_pool2d(x) + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +def test_adaptive_avg_pool2d_tosa_FP(test_data): + TosaPipelineFP[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +def test_adaptive_avg_pool2d_tosa_INT(test_data): + TosaPipelineINT[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.XfailIfNoCorstone300 +def test_adaptive_avg_pool2d_u55_INT(test_data): + EthosU55PipelineINT[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.XfailIfNoCorstone320 +def test_adaptive_avg_pool2d_u85_INT(test_data): + EthosU85PipelineINT[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_quant(test_data): + pipeline = VgfPipeline[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + quantize=True, + ) + pipeline.run() + + +class MeanDim(torch.nn.Module): + test_data_suite: dict[str, tuple] = { + "rank_1_keepdim": lambda: ( + torch.rand(7), + 0, + True, + ), + "rank_2_keepdim": lambda: ( + torch.rand(7, 3), + (0, 1), + True, + ), + "rank_3_keepdim": lambda: ( + torch.rand(5, 7, 3), + (0, 1, 2), + True, + ), + "rand_1_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1), + True, + ), + "rand_2_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (2), + True, + ), + "rand_3_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (3), + True, + ), + "rand_12_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1, 2), + True, + ), + "rand_13_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1, 3), + True, + ), + "rand_23_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (2, 3), + True, + ), + "rand_123_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1, 2, 3), + True, + ), + "rand_0123_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (0, 1, 2, 3), + True, + ), + "rand_none_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + None, + True, + ), + "rank_1": lambda: ( + torch.rand(7), + (-1), + False, + ), + "rank_2": lambda: ( + torch.rand(5, 7), + (-2, -1), + False, + ), + "rank_3": lambda: ( + torch.rand(5, 7, 3), + (-3, -2, -1), + False, + ), + "rand_1": lambda: ( + torch.rand(1, 5, 7, 3), + (-3), + False, + ), + "rand_2": lambda: ( + torch.rand(1, 5, 7, 3), + (-2), + False, + ), + "rand_3": lambda: ( + torch.rand(1, 5, 7, 3), + (-1), + False, + ), + "rand_12": lambda: ( + torch.rand(1, 5, 7, 3), + (-3, -2), + False, + ), + "rand_13": lambda: ( + torch.rand(1, 5, 7, 3), + (-3, -1), + False, + ), + "rand_23": lambda: ( + torch.rand(1, 5, 7, 3), + (-2, -1), + False, + ), + "rand_123": lambda: ( + torch.rand(1, 5, 7, 3), + (-3, -2, -1), + False, + ), + "rand_0123": lambda: ( + torch.rand(1, 5, 7, 3), + (-4, -3, -2, -1), + False, + ), + "rank5_01234": lambda: ( + torch.rand(1, 1, 7, 3, 2), + (-5, -4, -3, -2, -1), + False, + ), + "rank5_234": lambda: ( + torch.rand(1, 1, 7, 3, 2), + (-3, -2, -1), + False, + ), + "rank5_12": lambda: ( + torch.rand(1, 1, 7, 3, 2), + (1, 2), + False, + ), + "rank5_2": lambda: ( + torch.rand(1, 4, 7, 3, 2), + (2), + False, + ), + "u55_avg_pool_not_supported": lambda: ( + torch.rand(1, 1, 1, 257), + (0, 1, 2, 3), + True, + ), + } + torch_op = "torch.ops.aten.mean.dim" + exir_op = "executorch_exir_dialects_edge__ops_aten_mean_dim" + + def __init__(self, dim: int | list[int] = -1, keepdim: bool = True): + super().__init__() + self.dim = dim + self.keepdim = keepdim + + def forward(self, x: torch.Tensor): + return x.mean(dim=self.dim, keepdim=self.keepdim) + + +@common.parametrize("test_data", MeanDim.test_data_suite) +def test_mean_dim_tosa_FP(test_data): + test_data, dim, keep_dim = test_data() + TosaPipelineFP[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + MeanDim.torch_op, + MeanDim.exir_op, + ).run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +def test_mean_dim_tosa_INT(test_data): + test_data, dim, keep_dim = test_data() + pipeline = TosaPipelineINT[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.XfailIfNoCorstone300 +def test_mean_dim_u55_INT(test_data): + test_data, dim, keep_dim = test_data() + pipeline = EthosU55PipelineINT[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.add_stage_after( + "export", + pipeline.tester.check_not, + ["torch.ops.aten.adaptive_avg_pool2d.default"], + suffix="avg_pool", + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.XfailIfNoCorstone320 +def test_mean_dim_u85_INT(test_data): + test_data, dim, keep_dim = test_data() + pipeline = EthosU85PipelineINT[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.SkipIfNoModelConverter +def test_mean_dim_vgf_no_quant(test_data): + test_data_val, dim, keep_dim = test_data() + pipeline = VgfPipeline[input_t]( + MeanDim(dim, keep_dim), + (test_data_val,), + MeanDim.torch_op, + MeanDim.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.SkipIfNoModelConverter +def test_mean_dim_vgf_quant(test_data): + test_data_val, dim, keep_dim = test_data() + pipeline = VgfPipeline[input_t]( + MeanDim(dim, keep_dim), + (test_data_val,), + [], + symmetric_io_quantization=True, + quantize=True, + ) + pipeline.run() + + +mean_input_t = tuple[torch.Tensor, bool] + + +class MeanDefault(torch.nn.Module): + def forward(self, tensor: torch.Tensor, keepdim: bool): + return tensor.mean() + + test_data_suite: dict[str, Callable[[], mean_input_t]] = { + "rank1": lambda: ( + torch.rand( + 1, + ), + False, + ), + "rank2": lambda: (torch.rand(5, 5), True), + "rank4": lambda: (torch.rand(5, 1, 10, 1), False), + } + + +@common.parametrize("test_data", MeanDefault.test_data_suite) +def test_mean_tosa_FP(test_data): + pipeline = TosaPipelineFP[mean_input_t]( + MeanDefault(), + test_data(), + [], # Might be sum, avgpool, or both + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDefault.test_data_suite) +def test_mean_tosa_INT(test_data): + pipeline = TosaPipelineINT[mean_input_t]( + MeanDefault(), + test_data(), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_minimum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_minimum.py new file mode 100644 index 0000000..ff706f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_minimum.py @@ -0,0 +1,98 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_t = tuple[torch.Tensor, torch.Tensor] +aten_op = "torch.ops.aten.minimum.default" + + +class Minimum(torch.nn.Module): + test_parameters = { + "float_tensor": lambda: ( + torch.FloatTensor([1, 2, 3, 5, 7]), + (torch.FloatTensor([2, 1, 2, 1, 10])), + ), + "ones": lambda: (torch.ones(1, 10, 4, 6), 2 * torch.ones(1, 10, 4, 6)), + "rand_diff": lambda: (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "rand_same": lambda: (torch.randn(1, 3, 4, 4), torch.randn(1, 3, 4, 4)), + "rand_large": lambda: ( + 10000 * torch.randn(1, 1, 4, 4), + torch.randn(1, 1, 4, 1), + ), + } + + def __init__(self): + super().__init__() + + def forward(self, x, y): + return torch.minimum(x, y) + + +@common.parametrize("test_data", Minimum.test_parameters) +def test_minimum_tosa_FP(test_data: Tuple): + TosaPipelineFP[test_t](Minimum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +def test_minimum_tosa_INT(test_data: Tuple): + TosaPipelineINT[test_t](Minimum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.XfailIfNoCorstone300 +def test_minimum_u55_INT(test_data: Tuple): + EthosU55PipelineINT[test_t]( + Minimum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.XfailIfNoCorstone320 +def test_minimum_u85_INT(test_data: Tuple): + EthosU85PipelineINT[test_t]( + Minimum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.SkipIfNoModelConverter +def test_minimum_vgf_no_quant(test_data: test_t): + pipeline = VgfPipeline[test_t]( + Minimum(), + test_data(), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.SkipIfNoModelConverter +def test_minimum_vgf_quant(test_data: test_t): + pipeline = VgfPipeline[test_t]( + Minimum(), + test_data(), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mm.py new file mode 100644 index 0000000..6d02688 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mm.py @@ -0,0 +1,93 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_t = tuple[torch.Tensor, torch.Tensor] + + +class MM(torch.nn.Module): + test_data_generators = { + "rand_2d": lambda: (torch.rand(3, 5), torch.rand(5, 2)), + "rand_same": lambda: (torch.rand(1, 1), torch.rand(1, 1)), + "ones": lambda: (torch.ones(55, 3), torch.ones(3, 44)), + "randn_large": lambda: (10000 * torch.randn(1, 10), torch.randn(10, 5)), + "rand_neg": lambda: (-10 * torch.randn(32, 64), 5 + 5 * torch.randn(64, 32)), + } + aten_op = "torch.ops.aten.mm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_mm_default" + + def forward(self, x, y): + return torch.mm(x, y) + + +@common.parametrize("test_data", MM.test_data_generators) +def test_mm_tosa_FP(test_data: Tuple): + TosaPipelineFP[test_t](MM(), test_data(), MM.aten_op).run() + + +@common.parametrize("test_data", MM.test_data_generators) +def test_mm_tosa_INT(test_data: Tuple): + TosaPipelineINT[test_t](MM(), test_data(), MM.aten_op, MM.exir_op, qtol=1).run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.XfailIfNoCorstone300 +@pytest.mark.flaky # Investigate flakiness (MLETORCH-870) +def test_mm_u55_INT(test_data: Tuple): + EthosU55PipelineINT[test_t]( + MM(), + test_data(), + MM.aten_op, + ).run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.XfailIfNoCorstone320 +def test_mm_u85_INT(test_data: Tuple): + EthosU85PipelineINT[test_t]( + MM(), + test_data(), + MM.aten_op, + MM.exir_op, + ).run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.SkipIfNoModelConverter +def test_mm_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + MM(), + test_data(), + MM.aten_op, + MM.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.SkipIfNoModelConverter +def test_mm_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + MM(), + test_data(), + MM.aten_op, + MM.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mul.py new file mode 100644 index 0000000..a938b4c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_mul.py @@ -0,0 +1,376 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification + +from executorch.backends.xnnpack.test.tester import Quantize + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x +aten_op = "torch.ops.aten.mul.Tensor" + +test_data_suite = { + # (test_name, input, other,) See torch.mul() for info + "op_mul_rank1_rand": lambda: ( + torch.rand(5) * 3.7, + torch.rand(5) * 1.5, + ), + "op_mul_rank2_rand": lambda: ( + torch.rand(4, 5), + torch.rand(1, 5), + ), + "op_mul_rank3_randn": lambda: ( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), + ), + "op_mul_rank4_randn": lambda: ( + torch.randn(1, 10, 25, 20), + torch.randn(1, 10, 25, 20), + ), + "op_mul_rank4_ones_mul_negative": lambda: ( + torch.ones(1, 10, 25, 20), + (-1) * torch.ones(1, 10, 25, 20), + ), + "op_mul_rank4_negative_large_rand": lambda: ( + (-200) * torch.rand(1, 10, 25, 20), + torch.rand(1, 1, 1, 20), + ), + "op_mul_rank4_large_randn": lambda: ( + 200 * torch.randn(1, 10, 25, 20), + torch.rand(1, 10, 25, 1), + ), + "op_mul_rank4_randn_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + ), +} + + +test_data_suite_2 = { + # (test_name, input, other,) See torch.mul() for info + "op_mul_rank2_rand": lambda: ( + torch.rand(4, 5), + torch.rand(5), + ), + "op_mul_rank3_randn": lambda: ( + torch.randn(10, 5, 2), + torch.randn(5, 2), + ), + "op_mul_rank4_randn": lambda: ( + torch.randn(1, 10, 25, 20), + torch.randn(1, 25, 20), + ), + "op_mul_rank4_randn_2": lambda: ( + torch.randn(1, 25, 1), + torch.randn(1, 3, 25, 10), + ), +} + + +test_data_suite_int32 = { + # (test_name, input, other,) See torch.mul() for info + "op_mul_rank4_randn_int32": lambda: ( + torch.randint(0, 10, (1, 10, 25, 20), dtype=torch.int32), + torch.randint(0, 10, (1, 10, 25, 20), dtype=torch.int32), + ), + "op_mul_rank4_randn_mutltiple_broadcasts_int32": lambda: ( + torch.randint(0, 10, (1, 4, 4, 1), dtype=torch.int32), + torch.randint(0, 10, (1, 1, 4, 4), dtype=torch.int32), + ), + "op_mul_rank4_randn_broadcast_int32": lambda: ( + torch.randint(0, 10, (1, 10, 25, 20), dtype=torch.int32), + torch.randint(0, 10, (1, 25, 20), dtype=torch.int32), + ), +} + + +class Mul(torch.nn.Module): + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor, + ): + return input_ * other_ + + +@common.parametrize("test_data", test_data_suite) +def test_mul_tensor_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_2) +def test_mul_tensor_tosa_FP_diff_input_ranks(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +# MLETORCH-1274 Improve data type checks during partitioning +# view/RESHAPE of integer tensor is not supported for +FP profile which causes issues +# with view_copy (RESHAPE) which isn't supported in FP so removing the int32 tests +# to allow for the dtype validation patches to land. +# filter out the 'op_mul_rank4_randn_int32' only +test_data_int32_without_broadcasting = { + k: v for k, v in test_data_suite_int32.items() if k != "op_mul_rank4_randn_int32" +} + + +@common.parametrize("test_data", test_data_int32_without_broadcasting) +def test_mul_tensor_tosa_FP_int32(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_2) +def test_mul_tensor_tosa_INT_diff_input_ranks(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_mul_tensor_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +def test_mul_tensor_tosa_INT_int32(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_mul_tensor_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_mul_tensor_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +@common.XfailIfNoCorstone300 +def test_mul_tensor_u55_INT_int32(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +@common.XfailIfNoCorstone320 +def test_mul_tensor_u85_INT_int32(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +# view/RESHAPE of integer tensor is not supported for +FP profile which causes issues +# with view_copy (RESHAPE) which isn't supported in FP so removing the int32 tests +# to allow for the dtype validation patches to land. + + +@common.parametrize( + "test_data", + test_data_suite | test_data_suite_2 | test_data_int32_without_broadcasting, +) +@common.SkipIfNoModelConverter +def test_mul_tensor_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite | test_data_suite_2) +@common.SkipIfNoModelConverter +def test_mul_tensor_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +@common.SkipIfNoModelConverter +def test_mul_tensor_vgf_quant_int32(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_mul_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_mul_tensor_16a8w_tosa_INT(test_data: input_t1): + """Test mul operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_mul_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_mul_tensor_16a8w_u55_INT(test_data: input_t1): + """Test mul operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_mul_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_mul_tensor_16a8w_u85_INT(test_data: input_t1): + """Test mul operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_mul_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_multihead_attention.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_multihead_attention.py new file mode 100644 index 0000000..50dcaae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_multihead_attention.py @@ -0,0 +1,138 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class MultiheadAttention(torch.nn.MultiheadAttention): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs) + + +input_t1 = tuple[torch.Tensor, torch.nn.Module] +test_suite = { + # test_name, (x,), embed_dim, num_heads, batch_first + "rand_2d": lambda: ( + (torch.rand(6, 3),), + MultiheadAttention(embed_dim=3, num_heads=3, batch_first=True), + ), + "randn_2d": lambda: ( + (torch.randn(2, 4),), + MultiheadAttention(embed_dim=4, num_heads=2, batch_first=True), + ), + "randn_3d": lambda: ( + (torch.randn(3, 2, 4),), + MultiheadAttention(embed_dim=4, num_heads=2, batch_first=False), + ), +} + + +@common.parametrize( + "test_data", + test_suite, +) +def test_multihead_attention_tosa_FP(test_data: input_t1): + test_data, module = test_data() + pipeline = TosaPipelineFP(module, (*test_data, *test_data, *test_data), [], []) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +def test_multihead_attention_tosa_INT(test_data): + test_data, module = test_data() + pipeline = TosaPipelineINT( + module, + (*test_data, *test_data, *test_data), + [], + [], + # TODO: Per-channel quantization is broken (MLETORCH-1144) + per_channel_quantization=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.XfailIfNoCorstone300 +def test_multihead_attention_u55_INT(test_data: input_t1): + test_data, module = test_data() + pipeline = EthosU55PipelineINT( + module, + (*test_data, *test_data, *test_data), + [], + [], + use_to_edge_transform_and_lower=True, + # TODO: Per-channel quantization is broken (MLETORCH-1144) + per_channel_quantization=False, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.XfailIfNoCorstone320 +def test_multihead_attention_u85_INT(test_data: input_t1): + test_data, module = test_data() + pipeline = EthosU85PipelineINT( + module, + (*test_data, *test_data, *test_data), + [], + [], + use_to_edge_transform_and_lower=True, + # TODO: Per-channel quantization is broken (MLETORCH-1144) + per_channel_quantization=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.SkipIfNoModelConverter +def test_multihead_attention_vgf_no_quant(test_data: input_t1): + test_data_vals, module = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (*test_data_vals, *test_data_vals, *test_data_vals), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.SkipIfNoModelConverter +def test_multihead_attention_vgf_quant(test_data: input_t1): + test_data_vals, module = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (*test_data_vals, *test_data_vals, *test_data_vals), + [], + [], + per_channel_quantization=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ne.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ne.py new file mode 100644 index 0000000..9fa1b1d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ne.py @@ -0,0 +1,243 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t = Tuple[torch.Tensor] + + +class NotEqual(torch.nn.Module): + aten_op_Tensor = "torch.ops.aten.ne.Tensor" + aten_op_Scalar = "torch.ops.aten.ne.Scalar" + decomposed_ops = ["torch.ops.aten.eq.Tensor", "torch.ops.aten.logical_not.default"] + decomposed_exir_ops = [ + "executorch_exir_dialects_edge__ops_aten_eq_Tensor", + "executorch_exir_dialects_edge__ops_aten_logical_not_default", + ] + exir_op = "executorch_exir_dialects_edge__ops_aten_ne_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ != other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_ne_tensor_rank1_ones = NotEqual( + torch.ones(5), + torch.ones(5), +) +op_ne_tensor_rank2_rand = NotEqual( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_ne_tensor_rank3_randn = NotEqual( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_ne_tensor_rank4_randn = NotEqual( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_ne_scalar_rank1_ones = NotEqual(torch.ones(5), 1.0) +op_ne_scalar_rank2_rand = NotEqual(torch.rand(4, 5), 0.2) +op_ne_scalar_rank3_randn = NotEqual(torch.randn(10, 5, 2), -0.1) +op_ne_scalar_rank4_randn = NotEqual(torch.randn(3, 2, 2, 2), 0.3) +op_ne_scalar_rank4_randn_1batch = NotEqual(torch.randn(1, 2, 2, 2), 0.3) + +test_data_tensor = { + "ne_tensor_rank1_ones": op_ne_tensor_rank1_ones, + "ne_tensor_rank2_rand": op_ne_tensor_rank2_rand, + "ne_tensor_rank3_randn": op_ne_tensor_rank3_randn, + "ne_tensor_rank4_randn": op_ne_tensor_rank4_randn, +} + +test_data_scalar = { + "ne_scalar_rank1_ones": op_ne_scalar_rank1_ones, + "ne_scalar_rank2_rand": op_ne_scalar_rank2_rand, + "ne_scalar_rank3_randn": op_ne_scalar_rank3_randn, + "ne_scalar_rank4_randn": op_ne_scalar_rank4_randn, + "ne_scalar_rank4_randn_1batch": op_ne_scalar_rank4_randn_1batch, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_ne_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module, test_module.get_inputs(), NotEqual.aten_op_Tensor, NotEqual.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ne_scalar_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.aten_op_Scalar, + NotEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_ne_tensor_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module, test_module.get_inputs(), NotEqual.decomposed_ops, NotEqual.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ne_scalar_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module, test_module.get_inputs(), NotEqual.decomposed_ops, NotEqual.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_ne_tensor_u55_INT(test_module): + # EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module, + test_module.get_inputs(), + { + NotEqual.decomposed_exir_ops[0]: 1, + NotEqual.decomposed_exir_ops[1]: 1, + }, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_ne_scalar_u55_INT(test_module): + # Not equal (ne) is decomposed into the TOSA ops EQUAL and LOGICAL_NOT, both of + # which are unsupported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module, + test_module.get_inputs(), + { + NotEqual.decomposed_exir_ops[0]: 1, + NotEqual.decomposed_exir_ops[1]: 1, + }, + quantize=True, + u55_subset=True, + n_expected_delegates=1, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, + strict=False, +) +@common.XfailIfNoCorstone320 +def test_ne_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.decomposed_exir_ops, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, + xfails={ + "ne_scalar_rank4_randn_1batch": "MLETORCH-847: Boolean ne result unstable on U85", + }, + strict=False, +) +@common.XfailIfNoCorstone320 +def test_ne_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.decomposed_exir_ops, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ne_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.aten_op_Tensor, + NotEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ne_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ne_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.aten_op_Scalar, + NotEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ne_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_neg.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_neg.py new file mode 100644 index 0000000..11d1153 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_neg.py @@ -0,0 +1,99 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Neg(torch.nn.Module): + + aten_op = "torch.ops.aten.neg.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_neg_default" + + test_data: Dict[str, input_t1] = { + "rank_1_ramp": (torch.arange(-16, 16, 0.2),), + "rank_2_rand_uniform": (torch.rand(10, 10) - 0.5,), + "rank_3_all_ones": (torch.ones(10, 10, 10),), + "rank_4_all_zeros": (torch.zeros(1, 10, 10, 10),), + "rank_4_randn_pos": (torch.randn(1, 4, 4, 4) + 10,), + "rank_4_randn_neg": (torch.randn(1, 4, 4, 4) - 10,), + } + + def forward(self, x: torch.Tensor): + return torch.neg(x) + + +@common.parametrize("test_data", Neg.test_data) +def test_neg_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Neg(), test_data, Neg.aten_op, Neg.exir_op) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +def test_neg_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Neg(), test_data, Neg.aten_op, Neg.exir_op) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.XfailIfNoCorstone300 +def test_neg_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.XfailIfNoCorstone320 +def test_neg_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.SkipIfNoModelConverter +def test_neg_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.SkipIfNoModelConverter +def test_neg_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ones.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ones.py new file mode 100644 index 0000000..48c7590 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_ones.py @@ -0,0 +1,152 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class OnesAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.ones.default" + + def __init__(self, n: int, dtype: torch.dtype): + super().__init__() + self.args = (n,) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.ones(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)), + "10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (10, torch.int32), + ), + } + + # Mixed dtypes - the ones op is delegated, but it leads to a non-delegated add op. + test_data_mixed_dtypes: dict[str, test_data_t] = { + "fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)), + "fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)), + } + + +@common.parametrize("test_data", OnesAdd.test_data | OnesAdd.test_data_mixed_dtypes) +def test_ones_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data | OnesAdd.test_data_mixed_dtypes) +def test_ones_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.XfailIfNoCorstone300 +def test_ones_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.XfailIfNoCorstone320 +def test_ones_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize( + "test_data", + OnesAdd.test_data_mixed_dtypes, +) +def test_ones_tosa_INT_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + OnesAdd(*init_data), + input_data(), + non_delegated_ops={"executorch_exir_dialects_edge__ops_aten_add_Tensor": 1}, + n_expected_delegates=1, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.SkipIfNoModelConverter +def test_ones_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.SkipIfNoModelConverter +def test_ones_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + quantize=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_permute.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_permute.py new file mode 100644 index 0000000..f6c6aeb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_permute.py @@ -0,0 +1,256 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.permute.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_permute_copy_default" + +test_data_suite_u55 = { + # (test_name,test_data,dims) + "rank_2": lambda: (torch.rand(10, 10), [1, 0]), + "rank_3": lambda: (torch.rand(10, 10, 10), [2, 0, 1]), + "rank_3_2": lambda: (torch.rand(10, 10, 10), [1, 2, 0]), + "rank_4": lambda: (torch.rand(1, 5, 1, 10), [0, 2, 3, 1]), + "rank_4_2": lambda: (torch.rand(1, 2, 5, 10), [1, 0, 2, 3]), + "rank_4_3": lambda: (torch.rand(1, 10, 10, 5), [2, 0, 1, 3]), + "rank_4_large": lambda: (torch.rand(2, 8, 64, 65), [0, 2, 3, 1]), + "rank_3_large": lambda: (torch.rand(16, 64, 65), [1, 2, 0]), + "reshape_large_1": lambda: (torch.rand(1, 1, 65537), [0, 2, 1]), + "reshape_large_2": lambda: (torch.rand(65537, 1, 1), [1, 2, 0]), +} + +test_data_suite_u55_reject = { + "rank2_bool": lambda: (torch.randint(0, 2, (5, 5), dtype=torch.bool), [1, 0]), +} +test_data_suite = test_data_suite_u55.copy() | test_data_suite_u55_reject.copy() + + +class SimplePermute(torch.nn.Module): + + def __init__(self, dims: list[int]): + super().__init__() + + self.dims = dims + + def forward(self, x): + return torch.permute(x, self.dims) + + +@common.parametrize("test_data", test_data_suite) +def test_permute_tosa_FP(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = TosaPipelineFP[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_permute_tosa_INT(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = TosaPipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55) +@common.XfailIfNoCorstone300 +def test_permute_u55_INT(test_data): + test_data, dims = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops="executorch_exir_dialects_edge__ops_aten_permute_copy_default", + ) + if test_data[0].dtype == torch.bool: + pipeline.pop_stage("check_count.exir") + pipeline.tester.use_portable_ops = True + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55_reject) +def test_permute_u55_INT_not_delegated(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + SimplePermute(dims=dims), + (test_data,), + non_delegated_ops={exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_permute_u85_INT(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops="executorch_exir_dialects_edge__ops_aten_permute_copy_default", + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_permute_vgf_no_quant(test_data): + test_data, dims = test_data() + pipeline = VgfPipeline[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_permute_vgf_quant(test_data): + test_data, dims = test_data() + pipeline = VgfPipeline[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_permute_quantizer( + u55_config=False, per_channel_quantization=False +): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_permute_16a8w_tosa_INT(test_data: torch.Tensor): + """Test permute operation with int16 quantization""" + test_data, dims = test_data() + pipeline = TosaPipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op=[], + per_channel_quantization=False, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_permute_quantizer(per_channel_quantization=False), + ) + # Run the pipeline + pipeline.run() + + +test_data_suite_exact = { + x: test_data_suite[x] + for x in test_data_suite + if x not in ("rank_4_3", "rank2_bool") +} + + +@common.parametrize( + "test_data", + test_data_suite_exact, +) +@common.XfailIfNoCorstone300 +def test_permute_16a8w_u55_INT(test_data: torch.Tensor): + """Test permute operation with int16 quantization on U55""" + test_data, dims = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=True, + use_to_edge_transform_and_lower=True, + atol=1e-02, + rtol=1e-02, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_permute_quantizer(per_channel_quantization=False), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_permute_16a8w_u85_INT(test_data: torch.Tensor): + """Test permute operation with int16 quantization on U85""" + test_data, dims = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=1e-03, + rtol=1e-03, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_permute_quantizer(per_channel_quantization=False), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pixel_shuffling.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pixel_shuffling.py new file mode 100644 index 0000000..0c3436d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pixel_shuffling.py @@ -0,0 +1,237 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.constants import MAX_RANK + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from torch import nn + +aten_op_pixel_unshuffle = "torch.ops.aten.pixel_unshuffle.default" +exir_op_pixel_unshuffle = ( + "executorch_exir_dialects_edge__ops_aten_pixel_unshuffle_default" +) + +aten_op_pixel_shuffle = "torch.ops.aten.pixel_shuffle.default" +exir_op_pixel_shuffle = "executorch_exir_dialects_edge__ops_aten_pixel_shuffle_default" + +input_t1 = Tuple[torch.Tensor] # single positional input (1-tuple) + +max_rank_input_supported = MAX_RANK - 2 + + +class PixelUnShuffle(nn.Module): + + upscale_factor = 2 + test_data_generators = { + "rand_4d": lambda: (torch.randn(1, 12, 64, 64),), + "test_4d": lambda: (torch.tensor([[[[10.0, 20.0], [30.0, 40.0]]]]),), + "test_3d": lambda: (torch.tensor([[[10.0, 20.0], [30.0, 40.0]]]),), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.space_to_depth = nn.PixelUnshuffle(self.upscale_factor) + + def forward(self, inputs: torch.Tensor) -> torch.Tensor: + if inputs.dim() > max_rank_input_supported: + raise RuntimeError( + f"Max rank of input for pixel_unshuffle is currently {max_rank_input_supported}, got {inputs.dim()}" + ) + return self.space_to_depth(inputs) + + +class PixelShuffle(nn.Module): + + upscale_factor = 2 + test_data_generators = { + "rand_4d": lambda: (torch.randn(1, 12, 64, 64),), + "test_4d": lambda: (torch.tensor([[[[10.0]], [[20.0]], [[30.0]], [[40.0]]]]),), + "test_3d": lambda: (torch.tensor([[[10.0]], [[20.0]], [[30.0]], [[40.0]]]),), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.depth_to_space = nn.PixelShuffle(self.upscale_factor) + + def forward(self, inputs: torch.Tensor) -> torch.Tensor: + if inputs.dim() > max_rank_input_supported: + raise RuntimeError( + f"Max rank of input for pixel_shuffle is currently {max_rank_input_supported}, got {inputs.dim()}" + ) + return self.depth_to_space(inputs) + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +def test_pixel_unshuffle_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +def test_pixel_unshuffle_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +def test_pixel_shuffle_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +def test_pixel_shuffle_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_unshuffle_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_unshuffle_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_shuffle_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_shuffle_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +@common.XfailIfNoCorstone300 +def test_pixel_unshuffle_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_fvp=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + PixelUnShuffle.test_data_generators, + xfails={"rand_4d": "MLETORCH-1424: rand test fails"}, +) +@common.XfailIfNoCorstone320 +def test_pixel_unshuffle_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_fvp=True, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +@common.XfailIfNoCorstone300 +def test_pixel_shuffle_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_fvp=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + PixelShuffle.test_data_generators, + xfails={"rand_4d": "MLETORCH-1424: rand test fails"}, +) +@common.XfailIfNoCorstone320 +def test_pixel_shuffle_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_fvp=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pow.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pow.py new file mode 100644 index 0000000..1955ff4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_pow.py @@ -0,0 +1,204 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Pow_TensorTensor(torch.nn.Module): + aten_op = "torch.ops.aten.pow.Tensor_Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Tensor" + + input_t = Tuple[torch.Tensor | float, torch.Tensor | float] + + # The sign of the operands are important w.r.t. TOSA's spec of pow + test_data = { + "zero_base_pos_exp": lambda: ( + torch.zeros(1, 8, 3, 7), + torch.abs(torch.randn((1, 8, 1, 7))) + 1e5, + ), + "pos_base": lambda: ( + torch.abs(torch.randn((3, 2, 4, 2))) + 1e5, + torch.randn((1, 2, 4, 1)), + ), + "zero_base_zero_exp": lambda: (torch.zeros(2, 3), torch.zeros(2, 3)), + "pos_base_zero_exp": lambda: ( + torch.abs(torch.randn((1, 7, 2, 3))) + 1e5, + torch.zeros(1, 1, 2, 3), + ), + "neg_base_zero_exp": lambda: ( + -torch.abs(torch.randn((1, 2, 3, 4))) - 1e5, + torch.zeros(1, 2, 3, 4), + ), + "base_has_lower_rank": lambda: (torch.ones(3, 4), torch.ones(1, 2, 3, 4)), + "exp_has_lower_rank": lambda: (torch.ones(1, 2, 3, 4), torch.ones(3, 4)), + "f16_tensors": lambda: ( + torch.HalfTensor([[1.0, 2.0, 3.0], [0.5, 1.5, 2.5]]), + torch.HalfTensor([[1.0, 2.0, 0.0]]), + ), + } + + def forward(self, x: torch.Tensor | float, y: torch.Tensor | float): + return torch.pow(x, y) + + +class Pow_TensorScalar(torch.nn.Module): + aten_op = "torch.ops.aten.pow.Tensor_Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar" + + input_t = Tuple[torch.Tensor] + + test_data = { + # Test whole number exponents + "exp_minus_three": lambda: (torch.randn((10, 5)).relu() + 0.1, -3.0), + "exp_minus_one": lambda: (torch.randn((42,)).relu() + 0.1, -1.0), + "exp_zero": lambda: (torch.randn((1, 2, 3, 7)).relu(), 0.0), + "exp_one": lambda: (torch.randn((1, 4, 6, 2)).relu(), 1.0), + "exp_two": lambda: (torch.randn((1, 2, 3, 6)), 2.0), + # Test decimal exponent (base must be non-negative) + "non_neg_base_exp_pos_decimal": lambda: ( + torch.abs(torch.randn((1, 2, 3, 6))), + 6.789, + ), + "neg_base_exp_pos_integer": lambda: ( + -torch.abs(torch.randn((1, 2, 3, 6))) - 10, + 3, + ), + } + + def __init__(self, exp): + super().__init__() + self.exp = exp + + def forward(self, x: torch.Tensor): + return torch.pow(x, self.exp) + + +x_fail = { + "zero_base_zero_exp": "TOSA constraints: If x == 0 and y ⇐ 0, the result is undefined.", + "neg_base_zero_exp": "TOSA constraints: If x == 0 and y ⇐ 0, the result is undefined.", +} + + +@common.parametrize("test_data", Pow_TensorTensor.test_data, x_fail, strict=False) +def test_pow_tensor_tensor_tosa_FP(test_data: Pow_TensorTensor.input_t): + pipeline = TosaPipelineFP[Pow_TensorTensor.input_t]( + Pow_TensorTensor(), + test_data(), + Pow_TensorTensor.aten_op, + Pow_TensorTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorTensor.test_data, x_fail, strict=False) +@common.SkipIfNoModelConverter +def test_pow_tensor_tensor_vgf_no_quant(test_data: Pow_TensorTensor.input_t): + pipeline = VgfPipeline[Pow_TensorTensor.input_t]( + Pow_TensorTensor(), + test_data(), + Pow_TensorTensor.aten_op, + Pow_TensorTensor.exir_op, + quantize=False, + ) + pipeline.run() + + +x_fail = { + "exp_two": "TOSA constraints: If x <0 .", +} + + +@common.parametrize( + "test_data", Pow_TensorScalar.test_data, xfails=x_fail, strict=False +) +def test_pow_tensor_scalar_tosa_FP(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = TosaPipelineFP[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data, strict=False) +def test_pow_tensor_scalar_tosa_INT(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = TosaPipelineINT[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data) +@common.XfailIfNoCorstone300 +def test_pow_tensor_scalar_u55_INT(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = EthosU55PipelineINT[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data) +@common.XfailIfNoCorstone320 +def test_pow_tensor_scalar_u85_INT(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = EthosU85PipelineINT[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data, x_fail, strict=False) +@common.SkipIfNoModelConverter +def test_pow_tensor_scalar_vgf_no_quant(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = VgfPipeline[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + Pow_TensorScalar.test_data, +) +@common.SkipIfNoModelConverter +def test_pow_tensor_scalar_vgf_quant(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = VgfPipeline[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_reciprocal.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_reciprocal.py new file mode 100644 index 0000000..5d09dfd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_reciprocal.py @@ -0,0 +1,112 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x, Input y +aten_op = "torch.ops.aten.reciprocal.default" + +test_data_suite = { + "op_reciprocal_rank1_ones": lambda: torch.ones(5), + "op_reciprocal_rank1_rand": lambda: torch.rand(5) * 5, + "op_reciprocal_rank1_negative_ones": lambda: torch.ones(5) * (-1), + "op_reciprocal_rank4_ones": lambda: torch.ones(1, 10, 25, 20), + "op_reciprocal_rank4_negative_ones": lambda: (-1) * torch.ones(1, 10, 25, 20), + "op_reciprocal_rank4_ones_reciprocal_negative": lambda: torch.ones(1, 10, 25, 20), + "op_reciprocal_rank4_large_rand": lambda: 200 * torch.rand(1, 10, 25, 20), + "op_reciprocal_rank4_negative_large_rand": lambda: (-200) + * torch.rand(1, 10, 25, 20), + "op_reciprocal_rank4_large_randn": lambda: 200 * torch.randn(1, 10, 25, 20) + 1, +} + + +class Reciprocal(torch.nn.Module): + + def forward(self, input_: torch.Tensor): + return input_.reciprocal() + + +@common.parametrize("test_data", test_data_suite) +def test_reciprocal_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_reciprocal_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_reciprocal_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_reciprocal_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_ops=[], + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_reciprocal_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_reciprocal_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_relu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_relu.py new file mode 100644 index 0000000..4044cb2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_relu.py @@ -0,0 +1,166 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.relu.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_relu_default" + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Relu(torch.nn.Module): + def __init__(self): + super().__init__() + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.relu(x) + + +test_data_conv_relu = { + # (test_name, test_data) + "4d_randn_inplace=True": (lambda: (torch.randn(1, 64, 96, 96) * 1000, True)), + "4d_randn_inplace=False": (lambda: (torch.randn(1, 64, 96, 96) * 1000, False)), +} + + +class Conv2d_Relu_Add(torch.nn.Module): + def __init__(self, inplace: bool = True): + super().__init__() + self.conv1 = torch.nn.Conv2d( + in_channels=64, out_channels=64, kernel_size=7, padding="same" + ) + self.relu = torch.nn.ReLU(inplace=inplace) + + def forward(self, x: torch.Tensor): + y = self.conv1(x) + z = self.relu(y) + out = x + z + return out + + +@common.parametrize("test_data", test_data_suite) +def test_relu_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +# Test the folding of Conv2D with ReLU +@common.parametrize("test_data", test_data_conv_relu) +def test_relu_tosa_INT_conv_folding(test_data: torch.Tensor): + input_data, inplace = test_data() + pipeline = TosaPipelineINT[input_t1]( + Conv2d_Relu_Add(inplace=inplace), + (input_data,), + [], + [], + ) + # We should have : + # 3 quantize_per_tensor nodes: input activation , output of the conv-relu sequence, out of the add + # 4 dequantize_per_tensor nodes: into the conv2d input, into the add, output of the conv-relu sequence, before returning + # 2 dequantize_per_channel nodes: one for the weights and another one for the bias + # In case of incorrect annotation of the ReLU, we get separate Q/DR around both the conv2d and the ReLU and + # therefore more quantize_per_tensor and dequantize_per_tensor nodes + pipeline.add_stage_after( + "quantize", + pipeline.tester.check_count, + { + "quantized_decomposed.quantize_per_tensor.default": 3, + "torch.ops.quantized_decomposed.dequantize_per_tensor.default": 4, + "quantized_decomposed.dequantize_per_channel.default": 2, + }, + suffix="quant_nodes", + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_relu_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_relu_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_relu_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_relu_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_relu_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_remainder.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_remainder.py new file mode 100644 index 0000000..d1874d1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_remainder.py @@ -0,0 +1,199 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +def _nonzero_float_tensor(*shape: int) -> torch.Tensor: + return torch.rand(*shape, dtype=torch.float32) * 5 + 0.1 + + +class Remainder(torch.nn.Module): + input_t = Tuple[torch.Tensor | float, torch.Tensor | float] + + aten_op_tensor = "torch.ops.aten.remainder.Tensor" + exir_op_tensor = "executorch_exir_dialects_edge__ops_aten_remainder_Tensor" + aten_op_scalar = "torch.ops.aten.remainder.Scalar" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_remainder_Scalar" + + test_cases_tensor = { + "rank2_tensors": lambda: ( + torch.randn(2, 3) * 7, + _nonzero_float_tensor(2, 3), + ), + "rank4_tensors": lambda: ( + torch.randn(1, 4, 2, 3) * 7, + _nonzero_float_tensor(1, 4, 2, 3), + ), + "broadcast": lambda: ( + torch.randn(4, 5, 1), + _nonzero_float_tensor(1, 5, 6), + ), + } + + test_cases_scalar = { + "scalar_pos": lambda: ( + torch.randn(1, 2, 3, 4), + 0.25, + ), + "scalar_neg": lambda: ( + torch.randn(3, 4), + -0.25, + ), + } + + def forward(self, x: torch.Tensor | float, y: torch.Tensor | float) -> torch.Tensor: + return torch.remainder(x, y) + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +def test_remainder_tensor_tosa_FP(test_data): + data = test_data() + pipeline = TosaPipelineFP[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_tensor, + Remainder.exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +def test_remainder_scalar_tosa_FP(test_data): + data = test_data() + pipeline = TosaPipelineFP[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_scalar, + Remainder.exir_op_scalar, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +def test_remainder_tensor_tosa_INT(test_data): + pipeline = TosaPipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +def test_remainder_scalar_tosa_INT(test_data): + pipeline = TosaPipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.XfailIfNoCorstone300 +def test_remainder_tensor_u55_INT(test_data): + pipeline = EthosU55PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.XfailIfNoCorstone300 +def test_remainder_scalar_u55_INT(test_data): + pipeline = EthosU55PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.XfailIfNoCorstone320 +def test_remainder_tensor_u85_INT(test_data): + pipeline = EthosU85PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.XfailIfNoCorstone320 +def test_remainder_scalar_u85_INT(test_data): + pipeline = EthosU85PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.SkipIfNoModelConverter +def test_remainder_tensor_vgf_no_quant(test_data): + data = test_data() + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_tensor, + Remainder.exir_op_tensor, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.SkipIfNoModelConverter +def test_remainder_scalar_vgf_no_quant(test_data): + data = test_data() + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_scalar, + Remainder.exir_op_scalar, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.SkipIfNoModelConverter +def test_remainder_tensor_vgf_quant(test_data): + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + test_data(), + [], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.SkipIfNoModelConverter +def test_remainder_scalar_vgf_quant(test_data): + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + test_data(), + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_repeat.py new file mode 100644 index 0000000..0b3de3b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_repeat.py @@ -0,0 +1,162 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the repeat op which copies the data of the input tensor (possibly with new data format) +# + + +from typing import Sequence, Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, Input y + + +"""Tests Tensor.repeat for different ranks and dimensions.""" + + +class Repeat(torch.nn.Module): + aten_op = "torch.ops.aten.repeat.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_repeat_default" + + def __init__(self, multiples: Sequence[int]): + super().__init__() + self.multiples = multiples + + def forward(self, x: torch.Tensor): + return x.repeat(self.multiples) + + +class RepeatInterleaveInt(torch.nn.Module): + aten_op = "torch.ops.aten.repeat_interleave.self_int" + + def __init__(self, repeats: int, dim: int): + super().__init__() + self.repeats = repeats + self.dim = dim + + def forward(self, x: torch.Tensor): + return x.repeat_interleave(self.repeats, self.dim) + + +test_data_suite_u55 = { + # test_name : lambda: (module, test_data) + "1_x_1": lambda: (Repeat((2,)), (torch.randn(3),)), + "2_x_2": lambda: (Repeat((2, 1)), (torch.randn(3, 4),)), + "4_x_4": lambda: (Repeat((1, 2, 3, 4)), (torch.randn(1, 1, 2, 2),)), + "1_x_2": lambda: (Repeat((2, 2)), (torch.randn(3),)), + "1_x_3": lambda: (Repeat((1, 2, 3)), (torch.randn(3),)), + "2_x_3": lambda: (Repeat((2, 2, 2)), (torch.randn((3, 3)),)), + "1_x_4": lambda: (Repeat((2, 1, 2, 4)), (torch.randn((3, 3, 3)),)), + "interleave_int_3_x_1": lambda: (RepeatInterleaveInt(3, 1), (torch.randn(3, 4),)), +} +test_data_suite_u55_reject = { + "1_x_1_bool": lambda: ( + Repeat((2,)), + (torch.randint(0, 2, (3,), dtype=torch.bool),), + ), +} +test_data_suite = test_data_suite_u55 | test_data_suite_u55_reject + + +@common.parametrize("test_data", test_data_suite) +def test_repeat_tosa_FP(test_data: Tuple): + module, test_data = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + module.aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_repeat_tosa_INT(test_data: Tuple): + module, test_data = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + module.aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55) +@common.XfailIfNoCorstone300 +def test_repeat_u55_INT(test_data: Tuple): + module, test_data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + test_data, + module.aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55_reject) +@common.XfailIfNoCorstone300 +def test_repeat_u55_INT_not_delegated(test_data: Tuple): + module, test_data = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + module, + test_data, + non_delegated_ops={module.exir_op: 1}, + u55_subset=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_repeat_u85_INT(test_data: Tuple): + module, test_data = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + test_data, + module.aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_repeat_vgf_no_quant(test_data: Tuple): + module, args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + module.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_repeat_vgf_quant(test_data: Tuple): + module, args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + module.aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_round.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_round.py new file mode 100644 index 0000000..572163c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_round.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.round.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_round_default" + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Round(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x.round() + + +@common.parametrize("test_data", test_data_suite) +def test_round_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Round(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_round_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +@pytest.mark.xfail(reason="where.self not supported on U55") +def test_round_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_round_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_round_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Round(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_round_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rshift.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rshift.py new file mode 100644 index 0000000..ff3f78f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rshift.py @@ -0,0 +1,226 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.common import ( + XfailIfNoCorstone300, + XfailIfNoCorstone320, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +scalar_input_t = tuple[torch.Tensor, int] + + +class RshiftScalar(torch.nn.Module): + torch_op_FP = "torch.ops.aten.__rshift__.Scalar" + torch_op_INT = "torch.ops.aten.bitwise_right_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_right_shift_Tensor" + test_data = { + "randint_neg_100_int8": lambda: ( + torch.randint(-100, 100, (1, 12, 3, 4), dtype=torch.int8), + 1, + ), + "randint_neg_100_int16": lambda: ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int16), + 5, + ), + "randint_neg_100_int32": lambda: ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int32), + 2, + ), + } + + def forward(self, x: torch.Tensor, shift: int): + return x >> shift + + +tensor_input_t = tuple[torch.Tensor, torch.Tensor] + + +class RshiftTensor(torch.nn.Module): + torch_op = "torch.ops.aten.bitwise_right_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_right_shift_Tensor" + test_data = { + "randint_neg_128_int8": lambda: ( + torch.randint(-128, 127, (3, 3), dtype=torch.int8), + torch.randint(0, 5, (3, 3), dtype=torch.int8), + ), + "randint_neg_1024_int16": lambda: ( + torch.randint(-1024, 1024, (3, 3, 3), dtype=torch.int16), + torch.randint(0, 5, (3, 3, 3), dtype=torch.int16), + ), + "randint_0_127_int32": lambda: ( + torch.randint(0, 127, (1, 2, 3, 3), dtype=torch.int32), + torch.randint(0, 5, (1, 2, 3, 3), dtype=torch.int32), + ), + } + + def forward(self, x: torch.Tensor, shift: torch.Tensor): + return x.bitwise_right_shift(shift) + + +################## +## RshiftScalar ## +################## + + +@common.parametrize("test_data", RshiftScalar.test_data) +def test_bitwise_right_shift_scalar_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_FP, + RshiftScalar.exir_op, + ).run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +def test_bitwise_right_shift_scalar_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.XfailIfNoCorstone300 +def test_bitwise_right_shift_scalar_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + ) + + # Forced rounding in U55 HW causes off-by-one errors. + pipeline.change_args("run_method_and_compare_outputs", inputs=test_data(), atol=1) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.XfailIfNoCorstone320 +def test_bitwise_right_shift_scalar_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_scalar_vgf_no_quant(test_data): + pipeline = VgfPipeline[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_FP, + RshiftScalar.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_scalar_vgf_quant(test_data): + pipeline = VgfPipeline[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + quantize=True, + ) + pipeline.run() + + +################## +## RshiftTensor ## +################## + + +@common.parametrize("test_data", RshiftTensor.test_data) +def test_bitwise_right_shift_tensor_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ).run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +def test_bitwise_right_shift_tensor_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@XfailIfNoCorstone300 +def test_bitwise_right_shift_tensor_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ) + + # Forced rounding in U55 HW causes off-by-one errors. + pipeline.change_args("run_method_and_compare_outputs", inputs=test_data(), atol=1) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@XfailIfNoCorstone320 +def test_bitwise_right_shift_tensor_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_tensor_vgf_no_quant(test_data): + pipeline = VgfPipeline[tensor_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_tensor_vgf_quant(test_data): + pipeline = VgfPipeline[tensor_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsqrt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsqrt.py new file mode 100644 index 0000000..d2e805f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsqrt.py @@ -0,0 +1,153 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +# Tests the rsqrt op. +# + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.rsqrt.default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Rsqrt(torch.nn.Module): + test_parameters = { + "ones_4d": lambda: (torch.ones(1, 10, 10, 10),), + "rand_4d_1": lambda: (torch.rand(1, 10, 10, 10),), + "rand_4d_2": lambda: (torch.rand(1, 5, 10, 20),), + "rand_3d": lambda: (torch.rand(5, 10, 20),), + } + + def forward(self, x: torch.Tensor): + return x.rsqrt() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +def test_rsqrt_tosa_FP(test_tensor: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +def test_rsqrt_tosa_INT(test_tensor: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone300 +def test_rsqrt_u55_INT(test_tensor: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone320 +def test_rsqrt_u85_INT(test_tensor: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.SkipIfNoModelConverter +def test_rsqrt_vgf_no_quant(test_tensor: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.SkipIfNoModelConverter +def test_rsqrt_vgf_quant(test_tensor: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +def test_rsqrt_tosa_INT_a16w8(test_tensor: torch.Tensor): + """Test rsqrt operation with int16 I/O quantization for TOSA INT.""" + # Use wider tolerances for int16 I/O quantization + pipeline = TosaPipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_op=[], + tosa_extensions=["int16"], + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone300 +def test_rsqrt_16a8w_u55_INT16(test_tensor: torch.Tensor): + """Test rsqrt operation with int16 I/O quantization for U55""" + # Use wider tolerances for int16 I/O quantization on U55 + pipeline = EthosU55PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone320 +def test_rsqrt_16a8w_u85_INT(test_tensor: torch.Tensor): + """Test rsqrt operation with int16 I/O quantization for U85""" + # Use wider tolerances for int16 I/O quantization on U85 + pipeline = EthosU85PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsub.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsub.py new file mode 100644 index 0000000..1872521 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_rsub.py @@ -0,0 +1,126 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +rsub_test_data = { + "rand_2D_4x4": lambda: (torch.rand(4, 4), 2), + "rand_3D_4x4x4": lambda: (torch.rand(4, 2, 2), 1.5), + "rand_4D_2x2x4x4": lambda: (torch.rand(2, 2, 4, 4), -1.1), + "rand_4D_big_small": lambda: ( + (10e30) * torch.randn(1, 20, 30, 40), + -0.25, + ), + "zero": lambda: (torch.rand(4, 4), 0), + # "swapped": lambda: (2, torch.rand(4, 4)), # torch.rsub(Scalar, Tensor) is not supported as it is not supported in eager mode. +} + + +class Rsub(torch.nn.Module): + aten_op = "torch.ops.aten.rsub.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_sub_Tensor" + + def forward(self, x: torch.Tensor, y: int): + return torch.rsub(x, y) + + +input_t1 = Tuple[torch.Tensor, torch.Tensor] + + +@common.parametrize("test_data", rsub_test_data) +def test_rsub_scalar_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t1]( + Rsub(), + test_data(), + aten_op=Rsub.aten_op, + exir_op=Rsub.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +def test_rsub_scalar_tosa_INT(test_data): + """Test Subtraction (TOSA INT)""" + pipeline = TosaPipelineINT[input_t1]( + Rsub(), + test_data(), + aten_op="torch.ops.aten.sub.Tensor", + exir_op=Rsub.exir_op, + use_to_edge_transform_and_lower=False, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.XfailIfNoCorstone300 +def test_rsub_scalar_u55_INT(test_data): + """Test Subtraction on Ethos-U55 (FVP Mode)""" + pipeline = EthosU55PipelineINT[input_t1]( + Rsub(), + test_data(), + aten_ops="torch.ops.aten.sub.Tensor", + exir_ops=Rsub.exir_op, + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.XfailIfNoCorstone320 +def test_rsub_scalar_u85_INT(test_data): + """Test Subtraction on Ethos-U85 (FVP Mode)""" + pipeline = EthosU85PipelineINT[input_t1]( + Rsub(), + test_data(), + aten_ops="torch.ops.aten.sub.Tensor", + exir_ops=Rsub.exir_op, + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.SkipIfNoModelConverter +def test_rsub_scalar_vgf_no_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF FP)""" + pipeline = VgfPipeline[input_t1]( + Rsub(), + test_data(), + Rsub.aten_op, + Rsub.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.SkipIfNoModelConverter +def test_rsub_scalar_vgf_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF INT)""" + pipeline = VgfPipeline[input_t1]( + Rsub(), + test_data(), + aten_op="torch.ops.aten.sub.Tensor", + exir_op=Rsub.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalar_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalar_tensor.py new file mode 100644 index 0000000..bc26507 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalar_tensor.py @@ -0,0 +1,135 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +float_test_data_suite = { + "scalar_tensor_float_1": lambda: (3.7, torch.float32, torch.rand((1, 2, 3, 4))), + "scalar_tensor_float_2": lambda: (66, torch.float32, torch.rand((1, 2, 3))), +} + +int_test_data_suite = { + "scalar_tensor_int32": lambda: ( + 33, + torch.int32, + torch.randint(0, 10, (1, 2), dtype=torch.int32), + ), + "scalar_tensor_int8": lambda: ( + 8, + torch.int8, + torch.rand(1, 2, 3), + ), + "scalar_tensor_int16": lambda: ( + 16 * 16 * 16, + torch.int16, + torch.rand((1,)).unsqueeze(0), # Rank 0 inputs not supported + ), +} + + +class ScalarTensor(torch.nn.Module): + aten_op = "torch.ops.aten.scalar_tensor.default" + + def __init__(self, scalar, dtype=torch.float32): + super().__init__() + self.scalar = scalar + self.dtype = dtype + + def forward(self, x: torch.Tensor): + return torch.scalar_tensor(self.scalar, dtype=self.dtype) + x + + +@common.parametrize( + "test_data", + int_test_data_suite | float_test_data_suite, +) +def test_scalar_tensor_tosa_FP(test_data): # Note TOSA FP supports all types + scalar, dtype, data = test_data() + TosaPipelineFP( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ).run() + + +@common.parametrize( + "test_data", + int_test_data_suite | float_test_data_suite, +) +def test_scalar_tensor_tosa_INT(test_data): + scalar, dtype, data = test_data() + pipeline: TosaPipelineINT = TosaPipelineINT( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", float_test_data_suite) +@common.XfailIfNoCorstone300 +def test_scalar_tensor_u55_INT(test_data): + scalar, dtype, data = test_data() + EthosU55PipelineINT( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ).run() + + +@common.parametrize("test_data", float_test_data_suite) +@common.XfailIfNoCorstone320 +def test_scalar_tensor_u85_INT(test_data): + scalar, dtype, data = test_data() + EthosU85PipelineINT( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ).run() + + +@common.parametrize("test_data", float_test_data_suite) +@common.SkipIfNoModelConverter +def test_scalar_tensor_vgf_no_quant(test_data): + scalar, dtype, data = test_data() + pipeline = VgfPipeline( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + int_test_data_suite, +) +@common.SkipIfNoModelConverter +def test_scalar_tensor_vgf_quant(test_data): + scalar, dtype, data = test_data() + pipeline = VgfPipeline( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + quantize=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalars.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalars.py new file mode 100644 index 0000000..b3704c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_scalars.py @@ -0,0 +1,438 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +""" +Summary of non-working cases. +FP: + Op(scalar, tensor): + One issue is that lift_constant_tensor_pass looks for a fake_tensor in the meta of the first + node which does not work the first node is a scalar. + Fixing that, the lowering fails since edge_program.graph_signatures.inputs_to_buffers is changed from + {"_lifted_tensor_constant0":"_lifted_tensor_constant0"} to {"x":"_lifted_tensor_constant0"} + somewhere in _transform in the to_edge step. This makes ArmPartitioner miss tagging the + data in tag_constant_data. + # MLETORCH-408 + Sub or inplace-sub with an integer input. +""" +input_t1 = Tuple[torch.Tensor, torch.scalar_tensor] # Input x, Input y + + +"""Tests various scalar cases""" + + +class Add(torch.nn.Module): + aten_op = "torch.ops.aten.add.Tensor" + + def forward(self, x, y): + return x + y + + +class Sub(torch.nn.Module): + aten_op = "torch.ops.aten.sub.Tensor" + + def forward(self, x, y): + return x - y + + +class Div(torch.nn.Module): + aten_op = "torch.ops.aten.div.Tensor" + + def forward(self, x, y): + return x / y + + +class Mul(torch.nn.Module): + aten_op = "torch.ops.aten.mul.Tensor" + + def forward(self, x, y): + return x * y + + +class MulScalar(torch.nn.Module): + aten_op = "torch.ops.aten.mul.Scalar" + + def forward(self, x, y): + return torch.ops.aten.mul.Scalar(x, y) + + +class DivScalar(torch.nn.Module): + aten_op = "torch.ops.aten.div.Scalar" + + def forward(self, x, y): + return torch.ops.aten.div.Scalar(x, y) + + +class AddScalar(torch.nn.Module): + aten_op = "torch.ops.aten.add.Scalar" + + def forward(self, x, y): + return torch.ops.aten.add.Scalar(x, y) + + +class SubScalar(torch.nn.Module): + aten_op = "torch.ops.aten.sub.Scalar" + + def forward(self, x, y): + return torch.ops.aten.sub.Scalar(x, y) + + +class AddInplace(torch.nn.Module): + aten_op = "torch.ops.aten.add_.Tensor" + + def forward(self, x, y): + x += y + return x + + +class SubInplace(torch.nn.Module): + aten_op = "torch.ops.aten.sub_.Tensor" + + def forward(self, x, y): + x -= y + return x + + +class DivInplace(torch.nn.Module): + aten_op = "torch.ops.aten.div_.Tensor" + + def forward(self, x, y): + x /= y + return x + + +class MulInplace(torch.nn.Module): + aten_op = "torch.ops.aten.mul_.Tensor" + + def forward(self, x, y): + x *= y + return x + + +class AddConst(torch.nn.Module): + aten_op = "torch.ops.aten.add.Tensor" + + def forward(self, x): + x = 1.0 + x + return x + + +class ShiftInplaceSub(torch.nn.Module): + + def forward(self, x): + x = x >> 4 + x -= 10 + return x + + +dtypes = [("int", 3), ("float", 3.0)] +sizes = [("r1", (1)), ("r4", (2, 4, 5, 3))] + +# Create combinations of tests +tensor_scalar_tests = {} +for dtype in dtypes: + for size in sizes: + test_name = f"{dtype[0]}_{size[0]}" + tensor = torch.rand(size[1]) + scalar = dtype[1] + tensor_scalar_tests[test_name + "_ts"] = (tensor, scalar) + # # Don't add (scalar, tensor) test case for .Scalar ops. + # if op[0][-6:] == "Scalar": + # continue + + tensor_scalar_tests[test_name + "_st"] = (scalar, tensor) + +tensor_const_tests = {} +for size in sizes: + test_name = f"{size[0]}" + tensor = torch.rand(size[1]) + tensor_const_tests[test_name] = (tensor,) + +xfails = { + "int_r1_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", + "int_r4_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", + "float_r1_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", + "float_r4_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", +} + + +# ADD FP ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_tensor_tosa_FP_scalar(test_data): + """Tests regular add with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Add(), test_data, aten_op=Add.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_tensor_tosa_FP_inplace(test_data): + """Tests inplace add with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](AddInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_const_tests, xfails=xfails) +def test_add_tensor_tosa_FP_const(test_data): + """Tests regular add with one scalar input, with one of inputs constant.""" + pipeline = TosaPipelineFP[input_t1](AddConst(), test_data, aten_op=AddConst.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_scalar_tosa_FP(test_data): + """Tests a scalar add with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + AddScalar(), test_data, aten_op=AddScalar.aten_op + ) + pipeline.run() + + +# ADD INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_add_tensor_tosa_INT_scalar(test_data): + """Tests regular add with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Add(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_add_tensor_tosa_INT_inplace(test_data): + """Tests inplace add with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](AddInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_const_tests) +def test_add_tensor_tosa_INT_const(test_data): + """Tests regular add with one scalar input, with one of inputs constant.""" + pipeline = TosaPipelineINT[input_t1]( + AddConst(), test_data, aten_op=AddConst.aten_op + ) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_scalar_tosa_INT(test_data): + """Tests a scalar add with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](AddScalar(), test_data, aten_op=Add.aten_op) + pipeline.run() + + +# ADD ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_add_scalar_tosa_INT") +def test_add_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_add_scalar_tosa_INT") +def test_add_scalar_u85_INT(): + pass + + +# SUB FP ------------------------------------------------------ + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_tensor_tosa_FP_scalar(test_data): + """Tests regular sub with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Sub(), test_data, aten_op=Sub.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_tensor_tosa_FP_inplace(test_data): + """Tests inplace sub with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](SubInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_scalar_tosa_FP(test_data): + """Tests a scalar sub with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + SubScalar(), test_data, aten_op=SubScalar.aten_op + ) + pipeline.run() + + +# SUB INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_sub_tensor_tosa_INT_scalar(test_data): + """Tests regular sub with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Sub(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_sub_tensor_tosa_INT_inplace(test_data): + """Tests inplace sub with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](SubInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_scalar_tosa_INT(test_data): + """Tests a scalar sub with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](SubScalar(), test_data, aten_op=Sub.aten_op) + pipeline.run() + + +# SUB ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_sub_scalar_tosa_INT") +def test_sub_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_sub_scalar_tosa_INT") +def test_sub_scalar_u85_INT(): + pass + + +# MUL FP ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_tensor_tosa_FP_scalar(test_data): + """Tests regular mul with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Mul(), test_data, aten_op=Mul.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_tensor_tosa_FP_inplace(test_data): + """Tests inplace mul with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](MulInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_scalar_tosa_FP(test_data): + """Tests a scalar mul with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + MulScalar(), test_data, aten_op=MulScalar.aten_op + ) + pipeline.run() + + +# MUL INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_mul_tensor_tosa_INT_scalar(test_data): + """Tests regular mul with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Mul(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_mul_tensor_tosa_INT_inplace(test_data): + """Tests inplace mul with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](MulInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_scalar_tosa_INT(test_data): + """Tests a scalar mul with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](MulScalar(), test_data, aten_op=Mul.aten_op) + pipeline.run() + + +# MUL ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_mul_scalar_tosa_INT") +def test_mul_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_mul_scalar_tosa_INT") +def test_mul_scalar_u85_INT(): + pass + + +# DIV FP ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_tensor_tosa_FP_scalar(test_data): + """Tests regular div with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Div(), test_data, aten_op=Div.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_tensor_tosa_FP_inplace(test_data): + """Tests inplace div with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](DivInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_scalar_tosa_FP(test_data): + """Tests a scalar div with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + DivScalar(), test_data, aten_op=DivScalar.aten_op + ) + pipeline.run() + + +# DIV INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_div_tensor_tosa_INT_scalar(test_data): + """Tests regular div with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Div(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_div_tensor_tosa_INT_inplace(test_data): + """Tests inplace div with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](DivInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_scalar_tosa_INT(test_data): + """Tests a scalar div with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](DivScalar(), test_data, aten_op=[]) + pipeline.run() + + +# DIV ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_div_scalar_tosa_INT") +def test_div_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_div_scalar_tosa_INT") +def test_div_scalar_u85_INT(): + pass + + +# SHIFT ETHOS-U ------------------------------------------------------ +@pytest.mark.skip( + reason="integer operations (shift and sub) are not supported on FP profile" +) +def test_bitwise_right_shift_tensor_tosa_FP_inplace(): + pipeline = TosaPipelineFP[input_t1]( + ShiftInplaceSub(), + (torch.IntTensor(5),), + aten_op="torch.ops.aten.__rshift__.Scalar", + ) + pipeline.run() + + +def test_bitwise_right_shift_tensor_tosa_INT_inplace(): + pipeline = TosaPipelineINT[input_t1]( + ShiftInplaceSub(), + (torch.IntTensor(5),), + aten_op="torch.ops.aten.bitwise_right_shift.Tensor", + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sdpa.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sdpa.py new file mode 100644 index 0000000..201d80a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sdpa.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class SDPA(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, query, key, value): + return torch.nn.functional.scaled_dot_product_attention( + query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False + ) + + +input_t = Tuple[torch.Tensor, torch.Tensor, torch.Tensor] + + +def test_sdpa_tosa_FP(): + test_input = tuple(torch.randn(1, 3, 197, 64) for x in range(3)) + pipeline = TosaPipelineFP[input_t](SDPA(), test_input, [], []) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +def test_sdpa_tosa_INT(): + test_input = tuple(torch.randn(1, 3, 197, 64) for x in range(3)) + pipeline = TosaPipelineINT[input_t](SDPA(), test_input, [], []) + pipeline.pop_stage("check.quant_nodes") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage( + "run_method_and_compare_outputs" + ) # TODO: reference is not quantized + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sdpa_vgf_no_quant(): + test_input = tuple(torch.randn(1, 3, 197, 64) for _ in range(3)) + pipeline = VgfPipeline[input_t]( + SDPA(), + test_input, + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sdpa_vgf_quant(): + test_input = tuple(torch.randn(1, 3, 197, 64) for _ in range(3)) + pipeline = VgfPipeline[input_t]( + SDPA(), + test_input, + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select.py new file mode 100644 index 0000000..91c1e14 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select.py @@ -0,0 +1,219 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, int, int] + +test_data_suite = { + # (test_data, dim, index) + "select3d_neg_1_dim_0_index": lambda: (torch.zeros(5, 3, 20), -1, 0), + "select3d_0_dim_neg_1_index": lambda: (torch.rand(5, 3, 20), 0, -1), + "select3d_0_dim_4_index": lambda: (torch.zeros(5, 3, 20), 0, 4), + "select3d_0_dim_2_index": lambda: (torch.ones(10, 10, 10), 0, 2), + "select4d_0_dim_2_index": lambda: (torch.rand(5, 3, 20, 2), 0, 2), + "select2d_0_dim_0_index": lambda: (torch.rand(10, 10) - 0.5, 0, 0), + "select1d_0_dim_1_index": lambda: (torch.randn(10) + 10, 0, 1), + "select1d_0_dim_0_index": lambda: (torch.randn(10) - 10, 0, 2), + "select3d_0_dim_1_index": lambda: (torch.arange(-16, 16, 0.2), 0, 1), +} + +test_data_not_delegated = { + "select3d_large_after_squeeze": lambda: (torch.rand(3, 64, 3, 49, 32), 0, 0), +} + +aten_op_copy = "torch.ops.aten.select_copy.int" +aten_op_int = "torch.ops.aten.select.int" + + +class SelectCopy(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, x, dim: int, index: int): + return torch.select_copy(x, dim=dim, index=index) + + +class SelectInt(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, x, dim: int, index: int): + return torch.select(x, dim=dim, index=index) + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_FP_copy(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SelectCopy(), + test_data(), + aten_op=aten_op_copy, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SelectInt(), + test_data(), + aten_op=aten_op_int, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_INT_copy(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SelectCopy(), + test_data(), + aten_op=aten_op_copy, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SelectInt(), + test_data(), + aten_op=aten_op_int, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_select_int_u55_INT_copy(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_select_int_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_not_delegated) +def test_select_int_u55_INT_not_delegated(test_data: Tuple): + pipeline = OpNotSupportedPipeline[input_t1]( + SelectInt(), + test_data(), + {aten_op_copy: 0}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_select_int_u85_INT_copy(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_select_int_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_no_quant_copy(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_quant_copy(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + [], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select_scatter.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select_scatter.py new file mode 100644 index 0000000..b4df8d4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_select_scatter.py @@ -0,0 +1,173 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + "rank2_rand": lambda: ( + torch.randint(-30, 30, (5, 9), dtype=torch.float32), + torch.randint(0, 9, (9,), dtype=torch.float32), + 0, + 2, + ), + "rank2_zeros": lambda: ( + torch.rand((3, 2), dtype=torch.float32), + torch.randint(0, 4, (2,), dtype=torch.float32), + 0, + 0, + ), + "rank3_rand": lambda: ( + torch.rand((2, 4, 5), dtype=torch.float32), + torch.randint(-5, 5, (2, 5), dtype=torch.float32), + 1, + 0, + ), + "rank3_ones": lambda: ( + torch.ones((2, 3, 3), dtype=torch.float32), + torch.rand((2, 3), dtype=torch.float32), + 2, + 2, + ), + "rank4_rand": lambda: ( + torch.rand((1, 2, 4, 5), dtype=torch.float32), + torch.rand((2, 4, 5), dtype=torch.float32), + 0, + 0, + ), + "rank4_ones": lambda: ( + torch.ones((2, 3, 3, 2), dtype=torch.float32), + torch.randint(-5, 5, (2, 3, 2), dtype=torch.float32), + 2, + -1, + ), + "rank5_ones": lambda: ( + torch.ones((3, 4, 20, 9, 5), dtype=torch.float32), + torch.randn((3, 4, 20, 9), dtype=torch.float32), + 4, + 1, + ), + "rank6_rand": lambda: ( + torch.rand((1, 2, 3, 4, 2, 1), dtype=torch.float32), + torch.randn((2, 3, 4, 2, 1), dtype=torch.float32), + 0, + 0, + ), +} + + +class SelectScatter(torch.nn.Module): + fp_aten_op = "torch.ops.aten.select_scatter.default" + int_aten_ops = [ + "torch.ops.aten.arange.start_step", + "torch.ops.aten.view_copy.default", + "torch.ops.aten.unsqueeze_copy.default", + "torch.ops.aten.expand_copy.default", + "torch.ops.aten.where.self", + "torch.ops.aten.eq.Tensor", + ] + fp_exir_op = ["executorch_exir_dialects_edge__ops_aten_select_scatter_default"] + int_exir_ops = [ + "executorch_exir_dialects_edge__ops_aten_eq_Tensor", + "executorch_exir_dialects_edge__ops_aten_where_self", + "executorch_exir_dialects_edge__ops_aten_arange_start_step", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default", + "executorch_exir_dialects_edge__ops_aten_expand_copy_default", + ] + u55_not_supported = { + "executorch_exir_dialects_edge__ops_aten_eq_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_where_self": 1, + } + + def forward(self, x: torch.Tensor, y: torch.Tensor, dim: int, index: int): + return x.select_scatter(y, dim, index) + + +input_t = Tuple[torch.Tensor, torch.Tensor, int, int] + + +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_tosa_FP(test_module: input_t): + pipeline = TosaPipelineFP[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.fp_aten_op, + exir_op=SelectScatter.fp_exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_tosa_INT(test_module: input_t): + pipeline = TosaPipelineINT[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.int_aten_ops, + exir_op=SelectScatter.int_exir_ops, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_u55_INT(test_module: input_t): + # select_scatter is not supported on U55 + pipeline = OpNotSupportedPipeline[input_t]( + SelectScatter(), + test_module(), + SelectScatter.u55_not_supported, + quantize=True, + u55_subset=True, + n_expected_delegates=1, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_u85_INT(test_module: input_t): + pipeline = EthosU85PipelineINT[input_t]( + SelectScatter(), + test_module(), + aten_ops=SelectScatter.int_aten_ops, + exir_ops=SelectScatter.int_exir_ops, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_vgf_no_quant(test_module: input_t): + pipeline = VgfPipeline[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.fp_aten_op, + exir_op=SelectScatter.fp_exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_vgf_quant(test_module: input_t): + pipeline = VgfPipeline[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.int_aten_ops, + exir_op=SelectScatter.int_exir_ops, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid.py new file mode 100644 index 0000000..29bf037 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid.py @@ -0,0 +1,357 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.sigmoid.default" # Used for checking that we do not have softmax in the graph after decompose +exir_op = "executorch_exir_dialects_edge__ops_aten_sigmoid_default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(10, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "rand_4d": lambda: torch.rand(1, 1, 5, 10), + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Sigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid(x) + + +class AddSigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid(x + x) + + +class SigmoidAdd(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return x + self.sigmoid(x) + + +class SigmoidAddSigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x, y): + return self.sigmoid((self.sigmoid(y) + self.sigmoid(x))) + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_FP(test_data: torch.Tensor): + TosaPipelineFP[input_t1](Sigmoid(), (test_data(),), aten_op, exir_op).run() + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_INT(test_data: torch.Tensor): + TosaPipelineINT[input_t1](Sigmoid(), (test_data(),), aten_op, exir_op).run() + + +def test_sigmoid_tosa_FP_add(): + TosaPipelineFP[input_t1]( + AddSigmoid(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_INT_add(): + TosaPipelineINT[input_t1]( + AddSigmoid(), + (test_data_suite["ramp"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_FP_add_2(): + TosaPipelineFP[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_INT_add_2(): + TosaPipelineINT[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_FP_add_3(): + TosaPipelineFP[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_INT_3(): + TosaPipelineINT[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sigmoid_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant_add(): + pipeline = VgfPipeline[input_t1]( + AddSigmoid(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant_add(): + pipeline = VgfPipeline[input_t1]( + AddSigmoid(), + (test_data_suite["ramp"](),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant_add_2(): + pipeline = VgfPipeline[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant_add_2(): + pipeline = VgfPipeline[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant_add_3(): + pipeline = VgfPipeline[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant_add_3(): + pipeline = VgfPipeline[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_sigmoid_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + + # Use a smaller episilon value to not greatly inflate [qmin, qmax] + quantizer.set_global( + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=2**-16 + ) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=2**-16 + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_16a8w_tosa_INT(test_data: torch.Tensor): + """Test sigmoid operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sigmoid_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_16a8w_u55_INT16(test_data: torch.Tensor): + """Test sigmoid operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sigmoid_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sigmoid_16a8w_u85_INT(test_data: torch.Tensor): + """Test sigmoid operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sigmoid_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid_32bit.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid_32bit.py new file mode 100644 index 0000000..29fc90b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sigmoid_32bit.py @@ -0,0 +1,177 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineINT, +) +from torchao.quantization.pt2e import HistogramObserver +from torchao.quantization.pt2e.quantizer import QuantizationSpec + + +def _get_16_bit_quant_config(): + int16_spec = QuantizationSpec( + dtype=torch.int16, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_symmetric, + ) + int32_spec = QuantizationSpec( + dtype=torch.int32, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_symmetric, + ) + qconfig = QuantizationConfig( + input_activation=int16_spec, + output_activation=int32_spec, + weight=None, + bias=None, + ) + return qconfig + + +def _get_32_bit_quant_config(): + int32_spec = QuantizationSpec( + dtype=torch.int32, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_symmetric, + ) + qconfig = QuantizationConfig( + input_activation=int32_spec, + output_activation=int32_spec, + weight=None, + bias=None, + ) + return qconfig + + +def configure_32bit_sigmoid_quantizer(pipeline): + pipeline.quantizer.set_global(_get_32_bit_quant_config()) + pipeline.quantizer.set_module_type( + torch.nn.modules.activation.Sigmoid, _get_16_bit_quant_config() + ) + + +input_t = tuple[torch.Tensor] +test_data_suite = { + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "rand_4d": lambda: torch.rand(1, 10, 10, 10), + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Sigmoid(torch.nn.Module): + aten_op = "torch.ops.aten.sigmoid.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_sigmoid_default" + + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid(x) + + +class SigmoidAddSigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid((self.sigmoid(x) + self.sigmoid(x))) + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_INT(test_data): + pipeline = TosaPipelineINT( + Sigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + qtol=1, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_INT_add_sigmoid(test_data): + pipeline = TosaPipelineINT( + SigmoidAddSigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + qtol=1, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_u55_INT(test_data): + pipeline = OpNotSupportedPipeline( + Sigmoid(), + (test_data(),), + {Sigmoid.exir_op: 1}, + quantize=True, + u55_subset=True, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_u55_INT_add_sigmoid(test_data): + pipeline = OpNotSupportedPipeline( + SigmoidAddSigmoid(), + (test_data(),), + {Sigmoid.exir_op: 3}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sigmoid_u85_INT(test_data): + pipeline = EthosU85PipelineINT( + Sigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.XfailIfNoCorstone320 +def test_sigmoid_u85_INT_add_sigmoid(test_data): + pipeline = EthosU85PipelineINT( + SigmoidAddSigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sign.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sign.py new file mode 100644 index 0000000..dd4f289 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sign.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sign.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__sign_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": torch.zeros(3, 5), + "ones": torch.ones(4, 4), + "neg_ones": -torch.ones(4, 4), + "mixed_signs": torch.tensor([[-2.0, -1.0, 0.0, 1.0, 2.0]]), + "positive_ramp": torch.arange(0.1, 1.1, 0.2), + "negative_ramp": torch.arange(-1.0, -0.1, 0.2), + "small_values": torch.tensor([-1e-7, 0.0, 1e-7]), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(10, 3, 5) - 0.5, + "high_magnitude": torch.tensor([-1e6, -10.0, 0.0, 10.0, 1e6]), +} + + +class Sign(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.sign(x) + + +@common.parametrize("test_data", test_data_suite) +def test_sign_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Sign(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sign_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Sign(), + (test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +@pytest.mark.xfail(reason="where.self not supported on U55") +def test_sign_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sign(), + (test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_sign_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sign(), + (test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sign_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sign(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sign_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sign(), + (test_data,), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_silu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_silu.py new file mode 100644 index 0000000..03dea73 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_silu.py @@ -0,0 +1,174 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t = Tuple[torch.Tensor] + + +class Silu(torch.nn.Module): + def forward( + self, + _input: torch.Tensor, + _inplace: Optional[bool] = False, + ): + return torch.nn.SiLU(inplace=_inplace)(_input) + + test_data: list[input_t] = { + "op_silu_rank1_ones": lambda: torch.ones(5), + "op_silu_rank1_negative_ones": lambda: torch.ones(5) * (-1), + "op_silu_rank1_rand": lambda: torch.rand(5) * 5, + "op_silu_rank4_ones": lambda: torch.ones(1, 10, 25, 20), + "op_silu_rank4_negative_ones": lambda: (-1) * torch.ones(1, 10, 25, 20), + "op_silu_rank4_large_rand": lambda: 200 * torch.rand(1, 10, 25, 20), + "op_silu_rank4_negative_large_rand": lambda: (-200) * torch.rand(1, 10, 25, 20), + "op_silu_rank4_large_randn": lambda: 200 * torch.randn(1, 10, 25, 20) + 1, + } + + aten_op_FP = "torch.ops.aten.silu.default" + aten_op_inplace_FP = "torch.ops.aten.silu_.default" + aten_op_INT = ["torch.ops.aten.sigmoid.default", "torch.ops.aten.mul.Tensor"] + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_FP(test_data: input_t): + silu_data = (test_data(), False) + pipeline = TosaPipelineFP[input_t](Silu(), silu_data, Silu.aten_op_FP) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_FP_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = TosaPipelineFP[input_t](Silu(), silu_data, Silu.aten_op_inplace_FP) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_INT(test_data: input_t): + silu_data = (test_data(), False) + pipeline = TosaPipelineINT[input_t](Silu(), silu_data, Silu.aten_op_INT) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_INT_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = TosaPipelineINT[input_t](Silu(), silu_data, Silu.aten_op_INT) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone300 +def test_silu_u55_INT(test_data: input_t): + silu_data = (test_data(), False) + pipeline = EthosU55PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone300 +def test_silu_u55_INT_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = EthosU55PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone320 +def test_silu_u85_INT(test_data: input_t): + silu_data = (test_data(), False) + pipeline = EthosU85PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone320 +def test_silu_u85_INT_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = EthosU85PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_no_quant(test_data: input_t): + silu_data = (test_data(), False) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_FP, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_no_quant_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_inplace_FP, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_quant(test_data: input_t): + silu_data = (test_data(), False) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_quant_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sin.py new file mode 100644 index 0000000..05cc8f5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sin.py @@ -0,0 +1,108 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sin.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10, 10), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Sin(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.sin(x) + + +@common.parametrize("test_data", test_data_suite) +def test_sin_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_op=[], + ) + if conftest.get_option("tosa_version") == "1.0": + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sin_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sin_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sin_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sin_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sin(), + (test_data,), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sin_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sin(), + (test_data,), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sinh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sinh.py new file mode 100644 index 0000000..703d3e5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sinh.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sinh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__sinh_default" + + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10), + "zeros_alt_shape": torch.zeros(10, 3, 5), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(10, 3, 5) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), + "large": 100 * torch.ones(1, 1), + "small": 0.000001 * torch.ones(1, 1), +} + + +class Sinh(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.sinh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_sinh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Sinh(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sinh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Sinh(), (test_data,), aten_op=aten_op, exir_op=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_sinh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sinh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_sinh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sinh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sinh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sinh(), + (test_data,), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sinh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sinh(), + (test_data,), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_slice.py new file mode 100644 index 0000000..f98efe1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_slice.py @@ -0,0 +1,217 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.slice.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_slice_copy" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + "ones_neg_3": lambda: (torch.ones(10), [(3, -3)]), + "ones_neg_8": lambda: (torch.ones(10), [(-8, 3)]), + "ones_slice_2": lambda: (torch.ones(10, 10), [(1, 3), (3, 10)]), + "ones_slice_3": lambda: (torch.ones(10, 10, 10), [(0, 7), (0, 10), (0, 8)]), + "ones_slice_4": lambda: ( + torch.ones((1, 12, 10, 10)), + [(0, 1), (0, 5), (3, 5), (4, 10)], + ), +} + + +class Slice(torch.nn.Module): + def forward(self, x: torch.Tensor, s: list[tuple[int, int]]): + slices = [slice(*i) for i in s] + return x[slices] + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1](Slice(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_tosa_INT_nchw(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_tosa_INT_nhwc(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_slice_tensor_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_slice_tensor_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_slice_tensor_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_slice_tensor_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_slice_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_16a8w_tosa_INT(test_data: torch.Tensor): + """Test slice operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_slice_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_slice_tensor_16a8w_u55_INT(test_data: torch.Tensor): + """Test slice operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_slice_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_slice_tensor_16a8w_u85_INT(test_data: torch.Tensor): + """Test slice operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_slice_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_softmax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_softmax.py new file mode 100644 index 0000000..0b2af23 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_softmax.py @@ -0,0 +1,121 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.softmax.default" # Used for checking that we do not have softmax in the graph after decompose +exir_op = "executorch_exir_dialects_edge__ops_aten__softmax_tensor" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Softmax(torch.nn.Module): + def __init__(self, dim: int = -1): + super().__init__() + self.softmax = torch.nn.Softmax(dim=dim) + + def forward(self, x): + return self.softmax(x) + + test_data = { + "ones": lambda: ((torch.ones(10, 10),), 1), + "ones_neg_dim": lambda: ((torch.ones(1, 3, 4),), -1), + "randn_neg_dim": lambda: ((torch.randn(1, 5, 8, 7),), -3), + "zeros": lambda: ((torch.zeros(1, 8, 5, 2),), 0), + "zeros_neg_dim": lambda: ((torch.zeros(1, 7, 8, 9),), -4), + "rand": lambda: ((torch.rand(1, 2, 5, 8),), 2), + "rand_neg_dim": lambda: ((torch.rand(1, 10, 8, 10),), -2), + "randn_mult_batches": lambda: ((torch.randn(2, 10, 10, 10),), 3), + } + + +@common.parametrize("test_data", Softmax.test_data) +def test_softmax_tosa_FP(test_data): + data, dim = test_data() + pipeline = TosaPipelineFP[input_t1](Softmax(dim), data, []) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +def test_softmax_tosa_INT(test_data): + data, dim = test_data() + pipeline = TosaPipelineINT[input_t1](Softmax(dim), data, []) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.XfailIfNoCorstone300 +def test_softmax_u55_INT(test_data): + data, dim = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + Softmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.XfailIfNoCorstone320 +def test_softmax_u85_INT(test_data): + data, dim = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + Softmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.SkipIfNoModelConverter +def test_softmax_vgf_no_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + Softmax(dim), + data, + [], + quantize=False, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.SkipIfNoModelConverter +def test_softmax_vgf_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + Softmax(dim), + data, + [], + quantize=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + # TODO: MLETORCH-1136 Change args of run_method_and_compare_outputs of the vgf tests + # pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_split.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_split.py new file mode 100644 index 0000000..6af3362 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_split.py @@ -0,0 +1,312 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +exir_op = "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Split(torch.nn.Module): + test_data = { + "split_1d_2_size_0_dim": lambda: (torch.rand(10), 2, 0), + "split_2d_3_size_1_dim": lambda: (torch.rand(10, 10), 3, 1), + "split_2d_2_size_4_dim": lambda: (torch.rand(10, 10), 4, -1), + "split_4d_2_size_2_dim": lambda: (torch.rand(4, 4, 4, 4), 2, 0), + } + + test_data_list = { + "split_3d_2_sizes_dim": lambda: (torch.rand(10, 15, 10), [2, 2, 11], 1), + "split_4d_2_sizes_dim_neg": lambda: (torch.rand(4, 4, 4, 4), [1, 1, 1, 1], -2), + } + + def forward( + self, x: torch.Tensor, split_size_or_sections: int | list[int], dim: int + ): + return x.split(split_size=split_size_or_sections, dim=dim) + + +class SplitWithSizes(torch.nn.Module): + def forward(self, x: torch.Tensor, split_sizes: list[int], dim: int): + return x.split_with_sizes(split_sizes=split_sizes, dim=dim) + + +class SplitSingleOut(torch.nn.Module): + def forward( + self, x: torch.Tensor, split_size_or_sections: int | list[int], dim: int + ): + return x.split(split_size=split_size_or_sections, dim=dim)[1] + + +class SplitTwoOut(torch.nn.Module): + def forward( + self, x: torch.Tensor, split_size_or_sections: int | list[int], dim: int + ): + return x.split(split_size=split_size_or_sections, dim=dim)[1:3] + + +class SplitCopy(torch.nn.Module): + aten_op = "torch.ops.aten.split_copy.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_split_copy_Tensor" + + def forward( + self, + x: torch.Tensor, + split_size: int, + dim: int, + ): + return torch.split_copy(x, split_size=split_size, dim=dim) + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data_list) +def test_split_with_sizes_tosa_FP_2(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SplitWithSizes(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_FP_one_out(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SplitSingleOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_FP_two_out(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SplitTwoOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", (Split.test_data | Split.test_data_list)) +@common.XfailIfNoCorstone300 +def test_split_with_sizes_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Split(), + test_data(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", (Split.test_data | Split.test_data_list)) +@common.XfailIfNoCorstone320 +def test_split_with_sizes_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Split(), + test_data(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data_list) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant_2(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + SplitWithSizes(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant_one_out(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + SplitSingleOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant_two_out(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + SplitTwoOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SplitCopy(), + test_data(), + aten_ops=SplitCopy.aten_op, + exir_ops=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SplitCopy(), + test_data(), + aten_ops=SplitCopy.aten_op, + exir_ops=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +@common.SkipIfNoModelConverter +def test_split_tensor_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +@common.SkipIfNoModelConverter +def test_split_tensor_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sqrt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sqrt.py new file mode 100644 index 0000000..c3d1aae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sqrt.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Sqrt(torch.nn.Module): + input_t = Tuple[torch.Tensor] + aten_op_FP = "torch.ops.aten.sqrt.default" + exir_op_FP = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Tensor" + + aten_op_INT = "torch.ops.aten.pow.Tensor_Scalar" + exir_op_INT = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar" + + def __init__(self): + super().__init__() + + def forward(self, x): + return torch.sqrt(x) + + test_data: Dict[str, input_t] = { + "sqrt_tensor_rank1_ones": lambda: (torch.ones(10),), + "sqrt_tensor_rank2_random": lambda: (torch.rand(5, 10),), + "sqrt_tensor_rank3_ones": lambda: (torch.ones(2, 3, 4),), + "sqrt_tensor_rank4_random": lambda: (torch.rand(1, 3, 8, 8),), + "sqrt_tensor_rank4_multibatch": lambda: (torch.rand(2, 3, 4, 4),), + } + + +@common.parametrize("test_data", Sqrt.test_data) +def test_sqrt_tosa_FP(test_data: Sqrt.input_t): + pipeline = TosaPipelineFP[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_FP, + Sqrt.exir_op_FP, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +def test_sqrt_tosa_INT(test_data: Sqrt.input_t): + pipeline = TosaPipelineINT[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.XfailIfNoCorstone300 +def test_sqrt_u55_INT(test_data: Sqrt.input_t): + pipeline = EthosU55PipelineINT[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.XfailIfNoCorstone320 +def test_sqrt_u85_INT(test_data: Sqrt.input_t): + pipeline = EthosU85PipelineINT[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.SkipIfNoModelConverter +def test_sqrt_vgf_no_quant(test_data: Sqrt.input_t): + pipeline = VgfPipeline[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_FP, + Sqrt.exir_op_FP, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.SkipIfNoModelConverter +def test_sqrt_vgf_quant(test_data: Sqrt.input_t): + pipeline = VgfPipeline[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_squeeze.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_squeeze.py new file mode 100644 index 0000000..fcef851 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_squeeze.py @@ -0,0 +1,291 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the squeeze op which squeezes a given dimension with size 1 into a lower ranked tensor. +# + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class SqueezeDim(torch.nn.Module): + test_parameters = { + "squeeze3d_dim_neg_2": lambda: (torch.randn(1, 1, 5), -2), + "squeeze4d_dim_pos_3": lambda: (torch.randn(1, 2, 3, 1), 3), + "squeeze4d_dim_neg_2": lambda: (torch.randn(1, 5, 1, 5), -2), + "squeeze5d_dim_neg_2": lambda: (torch.randn(1, 1, 5, 1, 5), -2), + } + + def forward(self, x: torch.Tensor, dim: int): + return x.squeeze(dim) + + +class SqueezeDims(torch.nn.Module): + test_parameters = { + "squeeze3d_dims_0_1": lambda: (torch.randn(1, 1, 5), (0, 1)), + "squeeze4d_dims_0_neg_1": lambda: (torch.randn(1, 5, 5, 1), (0, -1)), + "squeeze4d_dims_0_neg_2": lambda: (torch.randn(1, 5, 1, 5), (0, -2)), + "squeeze5d_dims_0_neg_2": lambda: (torch.randn(1, 1, 5, 1, 5), (0, -2)), + } + + def forward(self, x: torch.Tensor, dims: tuple[int]): + return x.squeeze(dims) + + +class Squeeze(torch.nn.Module): + test_parameters = { + "squeeze3d": lambda: (torch.randn(1, 1, 5),), + "squeeze4d_dims": lambda: (torch.randn(1, 5, 5, 1),), + "squeeze3d_dims_mix": lambda: (torch.randn(1, 5, 1, 5),), + "squeeze4d_dims_mix": lambda: (torch.randn(1, 1, 5, 1, 5),), + } + + def forward(self, x: torch.Tensor): + return x.squeeze() + + +############## +## Squeeze ### +############## + + +@common.parametrize("test_data", Squeeze.test_parameters) +def test_squeeze_dim_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Squeeze(), + test_data(), + aten_op="torch.ops.aten.squeeze.default", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +def test_squeeze_dim_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Squeeze(), + test_data(), + aten_op="torch.ops.aten.squeeze.default", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.XfailIfNoCorstone300 +def test_squeeze_dim_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Squeeze(), + test_data(), + aten_ops="torch.ops.aten.squeeze.default", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.XfailIfNoCorstone320 +def test_squeeze_dim_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Squeeze(), + test_data(), + aten_ops="torch.ops.aten.squeeze.default", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Squeeze(), + test_data(), + "torch.ops.aten.squeeze.default", + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Squeeze(), + test_data(), + "torch.ops.aten.squeeze.default", + [], + quantize=True, + ) + pipeline.run() + + +################# +## SqueezeDim ### +################# + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +def test_squeeze_dim_tosa_FP_2(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SqueezeDim(), + test_data(), + aten_op="torch.ops.aten.squeeze.dim", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +def test_squeeze_dim_tosa_INT_2(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SqueezeDim(), + test_data(), + aten_op="torch.ops.aten.squeeze.dim", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.XfailIfNoCorstone300 +def test_squeeze_dim_u55_INT_2(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SqueezeDim(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dim", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.XfailIfNoCorstone320 +def test_squeeze_dim_u85_INT_2(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SqueezeDim(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dim", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_no_quant_2(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDim(), + test_data(), + "torch.ops.aten.squeeze.dim", + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_quant_2(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDim(), + test_data(), + "torch.ops.aten.squeeze.dim", + [], + quantize=True, + ) + pipeline.run() + + +################## +## SqueezeDims ### +################## + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +def test_squeeze_dims_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SqueezeDims(), + test_data(), + aten_op="torch.ops.aten.squeeze.dims", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +def test_squeeze_dims_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SqueezeDims(), + test_data(), + aten_op="torch.ops.aten.squeeze.dims", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.XfailIfNoCorstone300 +def test_squeeze_dims_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SqueezeDims(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dims", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.XfailIfNoCorstone320 +def test_squeeze_dims_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SqueezeDims(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dims", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dims_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDims(), + test_data(), + "torch.ops.aten.squeeze.dims", + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dims_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDims(), + test_data(), + "torch.ops.aten.squeeze.dims", + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_stack.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_stack.py new file mode 100644 index 0000000..a3911a6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_stack.py @@ -0,0 +1,150 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +import torch.nn as nn + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "ones_two_tensors": lambda: ((torch.ones(1), torch.ones(1)), 0), + "ones_and_rand_three_tensors": lambda: ( + (torch.ones(1, 2), torch.randn(1, 2), torch.randn(1, 2)), + 1, + ), + "ones_and_rand_four_tensors": lambda: ( + ( + torch.ones(1, 2, 5), + torch.randn(1, 2, 5), + torch.randn(1, 2, 5), + torch.randn(1, 2, 5), + ), + -1, + ), + "rand_two_tensors": lambda: ( + (torch.randn(2, 2, 4), torch.randn(2, 2, 4)), + 2, + ), + "rand_two_tensors_dim_0": lambda: ( + (torch.randn(1, 2, 4, 4), torch.randn(1, 2, 4, 4)), + ), + "rand_two_tensors_dim_2": lambda: ( + (torch.randn(2, 2, 3, 5), torch.randn(2, 2, 3, 5)), + 2, + ), + "rand_large": lambda: ( + ( + 10000 * torch.randn(2, 3, 1, 4), + torch.randn(2, 3, 1, 4), + torch.randn(2, 3, 1, 4), + ), + -3, + ), +} + + +class Stack(nn.Module): + aten_op = "torch.ops.aten.stack.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_cat_default" + + def forward(self, n: tuple[torch.Tensor, ...], dim: int = 0): + return torch.stack(n, dim) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_module", test_data_suite) +def test_stack_tosa_FP(test_module: input_t1): + test_data = test_module() + pipeline = TosaPipelineFP[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_stack_tosa_INT(test_module: input_t1): + test_data = test_module() + pipeline = TosaPipelineINT[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_module", test_data_suite) +def test_stack_u55_INT(test_module: input_t1): + test_data = test_module() + pipeline = EthosU55PipelineINT[input_t1]( + Stack(), + test_data, + aten_ops=Stack.aten_op, + exir_ops=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_module", test_data_suite) +def test_stack_u85_INT(test_module: input_t1): + test_data = test_module() + pipeline = EthosU85PipelineINT[input_t1]( + Stack(), + test_data, + aten_ops=Stack.aten_op, + exir_ops=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_stack_vgf_no_quant(test_module: input_t1): + test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_stack_vgf_quant(test_module: input_t1): + test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sub.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sub.py new file mode 100644 index 0000000..1db6f7b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sub.py @@ -0,0 +1,366 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.sub.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_sub_Tensor" + +# Single-input subtraction (x - x) +sub_test_data = { + "ones_1D_5": lambda: (torch.ones(5),), + "ones_1D_50": lambda: (torch.ones(50),), + "rand_1D_10": lambda: (torch.rand(10),), + "rand_2D_5x5": lambda: (torch.rand(5, 5),), + "rand_3D_5x5x5": lambda: (torch.rand(5, 5, 5),), + "rand_4D_2x3x4x5": lambda: (torch.rand(2, 3, 4, 5),), + "zeros": lambda: (torch.zeros(10),), +} + +# Two-input subtraction (x - y) +sub2_test_data = { + "rand_2D_4x4": lambda: (torch.rand(4, 4), torch.rand(4, 4)), + "rand_3D_4x4x4": lambda: (torch.rand(4, 2, 2), torch.rand(4, 2, 2)), + "rand_4D_2x2x4x4": lambda: (torch.rand(2, 2, 4, 4), torch.rand(2, 2, 4, 4)), + "rand_4D_big_small": lambda: ( + (10e30) * torch.randn(1, 20, 30, 40), + torch.randn(1, 20, 30, 40), + ), + "zeros": lambda: (torch.rand(4, 4), torch.zeros(4, 4)), + "randn_4D_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + ), + "rand_3d_rand_Scalar": lambda: (torch.rand(1, 6, 2), torch.rand(1)), + "rand_3d_Scalar": lambda: (torch.rand(1, 6, 2), 1), +} + +# Sub and tan - the tan has a really steep curve just before Pi/2 and a point of discontinuity at Pi/2 +# so if the sub result is inaccurate, the error will be amplified by the tan +sub_tan_test_data = { + "rand_4D_pi": lambda: ( + torch.randn(1, 10, 20, 30) * math.pi / 2, + torch.randn(1, 10, 20, 30) * math.pi / 2, + ), + "rand_3D_pi": lambda: (torch.randn(1, 30, 40) * math.pi / 2, torch.rand(1, 30, 40)), +} + + +class Sub(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x - x + + +class Sub2(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x - y + + +class SubAlpha(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return torch.sub(x, y, alpha=5) + + +class SubTan(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor): + z = x - y + t = torch.tan(z) + return t + + +input_t1 = Tuple[torch.Tensor] # Input x +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +@common.parametrize("test_data", sub_test_data) +def test_sub_tensor_tosa_FP(test_data): + """Test Subtraction (TOSA FP)""" + pipeline = TosaPipelineFP[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +def test_sub_tensor_tosa_FP_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (TOSA FP)""" + pipeline = TosaPipelineFP[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_tan_test_data) +def test_sub_tensor_tosa_FP_alpha(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction with alpha (TOSA FP)""" + pipeline = TosaPipelineFP[input_t2]( + SubAlpha(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +def test_sub_tensor_tosa_INT(test_data): + """Test Subtraction (TOSA INT)""" + pipeline = TosaPipelineINT[input_t1](Sub(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +def test_sub_tensor_tosa_INT_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (TOSA INT)""" + pipeline = TosaPipelineINT[input_t2](Sub2(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", sub_tan_test_data) +def test_sub_tensor_tosa_INT_3(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (TOSA INT)""" + # This test has only been added to the tosa INT profile in order to catch quantization-induced errors. + pipeline = TosaPipelineINT[input_t2]( + SubTan(), test_data(), aten_op, exir_op, qtol=0 + ) + pipeline.run() + + +@common.parametrize("test_data", sub_tan_test_data) +def test_sub_tensor_tosa_INT_alpha(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction with alpha (TOSA INT)""" + pipeline = TosaPipelineINT[input_t2]( + SubAlpha(), test_data(), aten_op, exir_op, qtol=0 + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone300 +def test_sub_tensor_u55_INT(test_data): + """Test Subtraction on Ethos-U55 (FVP Mode)""" + pipeline = EthosU55PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.XfailIfNoCorstone300 +def test_sub_tensor_u55_INT_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction on Ethos-U55 (FVP Mode)""" + pipeline = EthosU55PipelineINT[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone320 +def test_sub_tensor_u85_INT_2(test_data): + """Test Subtraction on Ethos-U85 (FVP Mode)""" + pipeline = EthosU85PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.XfailIfNoCorstone320 +def test_sub_tensor_u85_INT(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction on Ethos-U85 (FVP Mode)""" + pipeline = EthosU85PipelineINT[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_no_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF FP)""" + pipeline = VgfPipeline[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_no_quant_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (VGF FP)""" + pipeline = VgfPipeline[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF INT)""" + pipeline = VgfPipeline[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_quant_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (VGF INT)""" + pipeline = VgfPipeline[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_sub_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", sub_test_data) +def test_sub_tensor_16a8w_tosa_INT(test_data: input_t1): + """Test sub operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sub_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone300 +def test_sub_tensor_16a8w_u55_INT(test_data: input_t1): + """Test sub operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sub_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone320 +def test_sub_tensor_16a8w_u85_INT(test_data: input_t1): + """Test sub operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sub_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sum.py new file mode 100644 index 0000000..14a6eee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_sum.py @@ -0,0 +1,161 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sum.dim_IntList" +input_t1 = Tuple[torch.Tensor] # Input x + + +"""Tests sum which sums all elements along some specified dimensions. +keepdim specifies whether the dimension that is summed should +be squeezed or not. +""" + + +class Sum(torch.nn.Module): + test_parameters = { + "1d_dim_0_keep": lambda: (torch.rand(10), 0, True), + "2d_dim_1_no_keep": lambda: (torch.rand(10, 10), 1, False), + "3d_dims_keep": lambda: (torch.rand(10, 10, 10), [-3, 1], True), + "4d_dims_no_keep": lambda: (torch.rand(1, 1, 5, 8), 1, False), + "4d_dim_3_keep": lambda: (torch.rand(1, 2, 3, 4), 3, True), + "4d_dims_keep": lambda: (torch.rand(1, 2, 8, 8), [2, 3, 0], True), + "dim_None": lambda: (torch.rand(10), None, True), + "dim_None_4d_tensor": lambda: (torch.rand(10, 3, 2, 1), None, True), + } + + def forward(self, x: torch.Tensor, dim: int, keepdim: bool): + return x.sum(dim=dim, keepdim=keepdim) + + +@common.parametrize("test_data", Sum.test_parameters) +def test_sum_dim_intlist_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + Sum(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +def test_sum_dim_intlist_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.XfailIfNoCorstone300 +def test_view_u55_INT_1_0(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.XfailIfNoCorstone320 +def test_view_u85_INT_1_0(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.SkipIfNoModelConverter +def test_sum_dim_intlist_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Sum(), + test_data(), + aten_op, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.SkipIfNoModelConverter +def test_sum_dim_intlist_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Sum(), + test_data(), + aten_op, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +reject_inputs = { + "reject_large_0_dim": lambda: (torch.rand((65537, 1, 1)), 0, False), + "reject_large_2_dim": lambda: (torch.rand((800, 90, 1)), 2, False), + "reject_large_1_dim": lambda: (torch.rand((3, 2, 800, 90)), 1, False), +} + + +@common.parametrize("test_data", reject_inputs) +def test_view_u55_INT_failure_set(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_ops=[], + run_on_fvp=False, # Run fails since we are missing a non partitioned sum op + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +input_t2 = tuple[torch.Tensor] + + +class SumDefault(torch.nn.Module): + test_parameters = { + "rank1": lambda: (torch.rand(10),), + "rank2": lambda: (torch.rand(10, 1, 10),), + "rank4": lambda: (torch.rand(1, 1, 5, 8),), + } + aten_op = "torch.ops.aten.sum.default" + + def forward(self, x: torch.Tensor): + return x.sum() + + +@common.parametrize("test_data", SumDefault.test_parameters) +def test_sum_tosa_FP(test_data: Callable[[], input_t2]): + pipeline = TosaPipelineFP[input_t2](SumDefault(), test_data(), SumDefault.aten_op) + pipeline.run() + + +@common.parametrize("test_data", SumDefault.test_parameters) +def test_sum_tosa_INT(test_data: Callable[[], input_t2]): + pipeline = TosaPipelineINT[input_t1](SumDefault(), test_data(), SumDefault.aten_op) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_t_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_t_copy.py new file mode 100644 index 0000000..705e812 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_t_copy.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # test_name: (test_data, min, max) + "rand": lambda: (torch.rand(2, 3),), + "rand_multiplied": lambda: (torch.rand(3, 4) * 10,), + "ones": lambda: (torch.ones(5, 10),), + "randn": lambda: (torch.randn(1, 10) * 2,), +} + + +class TCopy(torch.nn.Module): + aten_op = "torch.ops.aten.t_copy.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_permute_copy_default" + + def forward(self, x: torch.Tensor): + return torch.t_copy(x) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_data", test_data_suite) +def test_t_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_t_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_t_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + TCopy(), + test_data(), + aten_ops=TCopy.aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_t_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + TCopy(), + test_data(), + aten_ops=TCopy.aten_op, + exir_ops=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_t_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_t_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tan.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tan.py new file mode 100644 index 0000000..cf711bf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tan.py @@ -0,0 +1,146 @@ +# Copyright 2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + +aten_op = "torch.ops.aten.tan.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__tan_default" + +eps32 = torch.finfo(torch.float32).eps +tiny32 = torch.finfo(torch.float32).tiny + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10), + "zeros_alt_shape": torch.zeros(1, 10, 3, 5), + "ones": torch.ones(10, 15, 25), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(1, 10, 3, 5) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), + "pi_multiples": (torch.arange(-5, 6, dtype=torch.float32) * math.pi), + "common_angles": torch.tensor( + [ + -math.pi, + -2 * math.pi / 3, + -math.pi / 2 + 1e-3, + -math.pi / 3, + -math.pi / 4, + -math.pi / 6, + 0.0, + math.pi / 6, + math.pi / 4, + math.pi / 3, + math.pi / 2 - 1e-3, + 2 * math.pi / 3, + math.pi, + ], + dtype=torch.float32, + ), + "near_asymptote_pos": torch.tensor( + [ + math.pi / 2 - 1e-7, + math.pi / 2 - 1e-6, + math.pi / 2 - 1e-4, + math.pi / 2 + 1e-7, + math.pi / 2 + 1e-6, + math.pi / 2 + 1e-4, + ], + dtype=torch.float32, + ), + "high_rank": torch.randn(1, 3, 7, 4, 5), + "very_small": torch.tensor( + [-tiny32, -eps32, -1e-10, 0.0, 1e-10, eps32, tiny32], dtype=torch.float32 + ), + "large_values": torch.linspace(-1e6, 1e6, steps=257, dtype=torch.float32), + "undefined": torch.tensor([math.pi / 2, -math.pi / 2, 3 * math.pi / 2]), +} + + +class Tan(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.tan(x) + + +@common.parametrize("test_data", test_data_suite) +def test_tan_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Tan(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_tan_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Tan(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_tan_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Tan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_tan_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Tan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tan_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t](Tan(), (test_data,), [], [], quantize=False) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tan_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Tan(), + (test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tanh.py new file mode 100644 index 0000000..c2b5e88 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_tanh.py @@ -0,0 +1,169 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.tanh.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(10, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Tanh(torch.nn.Module): + def __init__(self): + super().__init__() + self.tanh = torch.nn.Tanh() + + def forward(self, x): + return self.tanh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_tanh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_tanh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_tanh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_tanh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tanh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Tanh(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tanh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Tanh(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_tanh_16a8w_tosa_INT(test_data: torch.Tensor): + """Test tanh operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + epsilon=2**-16, + rtol=2e-03, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_tanh_16a8w_u55_INT16(test_data: torch.Tensor): + """Test tanh operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + a16w8_quantization=True, + epsilon=2**-16, + rtol=2e-03, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_tanh_16a8w_u85_INT(test_data: torch.Tensor): + """Test tanh operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + a16w8_quantization=True, + epsilon=2**-16, + rtol=2e-03, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_to_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_to_copy.py new file mode 100644 index 0000000..114051d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_to_copy.py @@ -0,0 +1,296 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the _to_copy op which is interpreted as a cast for our purposes. +# + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Cast(torch.nn.Module): + def __init__(self, target_dtype): + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor): + return x.to(dtype=self.target_dtype) + + +class CastAdd(torch.nn.Module): + def __init__(self, target_dtype): + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor): + return x.to(dtype=self.target_dtype) + x.to(dtype=self.target_dtype) + + +""" +Tests the _to_copy operation. + +Only test unquantized graphs as explicit casting of dtypes messes with the +quantization. +However, the model being exported may have some explicit casting to floating +point dtypes. The casting or their decomposition should be rejected during +partition. This test will be coveraged by class TestToCopy_INT. + +Note: This is also covered by test_scalars.py. +""" + +_TO_COPY_TEST_DATA_FP = { + "rand_fp16": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float16), torch.float32), + "rand_fp32": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float32), torch.float16), + "rand_int8": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.float32, + ), + "rand_int8_int32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.int32, + ), + "rand_int32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.int8, + ), +} + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_FP) +def test_to_tosa_FP(test_data: Tuple): + test_tensor, new_dtype = test_data() + + pipeline = TosaPipelineFP[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + ) + # int to int cast is not supported in TOSA+FP profile + if not new_dtype.is_floating_point and not torch.is_floating_point(test_tensor): + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 0, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + }, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_FP) +@common.SkipIfNoModelConverter +def test_to_vgf_no_quant(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = VgfPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + quantize=False, + ) + pipeline.run() + + +""" +Casting operations that output floating-point dtypes should be rejected under INT profile, +rather than introducing an invalid dtype into the tosa graph. +For example, x.to(dtype=torch.float32) will be eventually lowered to +exir_ops.edge.dim_order_ops._to_dim_order_copy.default. We should reject this operation +in ToCopySupported::is_node_tosa_supported() before it goes into the delegated graph. +""" +_TO_COPY_TEST_DATA_INT = { + "rand_int8_fp32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.float32, + ), + "rand_int16_fp32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int16), + torch.float32, + ), + "rand_int32_fp32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.float32, + ), + "rand_int32_fp16": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.float16, + ), + "rand_int32_bf16": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.bfloat16, + ), +} + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT) +def test_to_tosa_INT_not_delegated(test_data: Tuple): + test_tensor, new_dtype = test_data() + + pipeline = OpNotSupportedPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1 + }, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT) +@common.SkipIfNoModelConverter +def test_to_vgf_quant(test_data: Tuple): + # Op not supported + pass + + +_TO_COPY_TEST_DATA_REDUNDANT_CAST = { + "rand_fp16_fp16": lambda: ( + torch.rand((1, 2, 3, 4), dtype=torch.float16), + torch.float16, + ), + "rand_fp32_fp32": lambda: ( + torch.rand((1, 2, 3, 4), dtype=torch.float32), + torch.float32, + ), + "rand_int8_int8": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.int8, + ), + "rand_int16_int16": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int16), + torch.int16, + ), + "rand_int32_int32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.int32, + ), +} + +redundant_xfails = { + "rand_fp16_fp16": "FP16 is not supported", + "rand_int8_int8": "Tracing graph with quantized input is not supported.", + "rand_int16_int16": "Tracing graph with quantized input is not supported.", +} + + +@common.parametrize( + "test_data", _TO_COPY_TEST_DATA_REDUNDANT_CAST, xfails=redundant_xfails +) +def test_to_tosa_FP_REDUNDANT_CAST(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = TosaPipelineFP[input_t1]( + CastAdd(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize( + "test_data", _TO_COPY_TEST_DATA_REDUNDANT_CAST, xfails=redundant_xfails +) +def test_to_tosa_INT_REDUNDANT_CAST(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = TosaPipelineINT[input_t1]( + CastAdd(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_REDUNDANT_CAST) +def test_to_tosa_INT_not_delegated_REDUNDANT_CAST(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + non_delegated_ops={}, # These are removed outside of the Arm backend so the graph is empty + ) + pipeline.run() + + +_TO_COPY_DATA_INT_U55_REJECT = { + "rand_bool_int8": lambda: ( + torch.randint(0, 2, (1, 2, 3, 4), dtype=torch.bool), + torch.int8, + ), + "rand_int16_bool": lambda: ( + torch.randint(-1000, 1000, (1, 2, 3, 4), dtype=torch.int16), + torch.bool, + ), + "rand_int32_int8": lambda: ( + torch.randint(-1000, 1000, (1, 2, 3, 4), dtype=torch.int32), + torch.int8, + ), +} + + +@common.parametrize("test_data", _TO_COPY_DATA_INT_U55_REJECT) +def test_to_u55_INT(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + u55_subset=True, + quantize=True, + non_delegated_ops={}, # These are removed outside of the Arm backend so the graph is empty + ) + pipeline.run() + + +_TO_COPY_TEST_DATA_INT_FP = { + "bool_fp32": lambda: ( + torch.tensor([True, False], dtype=torch.bool), + torch.float32, + ), +} + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT_FP) +@common.SkipIfNoModelConverter +def test_to_vgf_no_quant_bool_fp32(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = VgfPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT_FP) +@common.SkipIfNoModelConverter +def test_to_vgf_quant_bool_fp32(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = VgfPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_transpose_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_transpose_copy.py new file mode 100644 index 0000000..fb521ed --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_transpose_copy.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # test_name: (test_data, min, max) + "rank_2": lambda: (torch.rand(2, 3), 0, 1), + "rank_2_swapped": lambda: (torch.rand(3, 4), 1, 0), + "rank_3": lambda: (torch.ones(5, 10, 10), 1, 2), + "rank_4": lambda: (torch.rand(1, 10, 4, 2) * 2, 2, 0), +} + + +class TransposeCopy(torch.nn.Module): + aten_op = "torch.ops.aten.transpose_copy.int" + exir_op = "executorch_exir_dialects_edge__ops_aten_permute_copy_default" + + def forward(self, x: torch.Tensor, dim0: int, dim1: int): + return torch.transpose_copy(x, dim0=dim0, dim1=dim1) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + TransposeCopy(), + test_data(), + aten_ops=TransposeCopy.aten_op, + exir_ops=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + TransposeCopy(), + test_data(), + aten_ops=TransposeCopy.aten_op, + exir_ops=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_transpose_int_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_transpose_int_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unary_combos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unary_combos.py new file mode 100644 index 0000000..f938e1d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unary_combos.py @@ -0,0 +1,144 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +Tensor1 = Tuple[torch.Tensor] + + +class NegAdd(torch.nn.Module): + # neg(x) + 1 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_neg_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10),) + + def forward(self, x): + return torch.neg(x) + 1.0 + + +class MinAddZero(torch.nn.Module): + # min(x, 0) + 1 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_full_like_default", + "executorch_exir_dialects_edge__ops_aten_minimum_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + # range [-1, 1] + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10) * 2 - 1,) + + def forward(self, x): + # We want Tensor-Tensor minimum + z = torch.full_like(x, 0.0) + return torch.minimum(x, z) + 1.0 + + +class MaxAddZero(torch.nn.Module): + # max(x, 0) + 1.0 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_full_like_default", + "executorch_exir_dialects_edge__ops_aten_maximum_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + # range [-1, 1] + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10) * 2 - 1,) + + def forward(self, x): + z = torch.full_like(x, 0.0) + return torch.maximum(x, z) + 1.0 + + +class AbsAdd(torch.nn.Module): + # abs(x) + 1.0 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_abs_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10),) + + def forward(self, x): + return torch.abs(x) + 1.0 + + +MODELS = [NegAdd, AbsAdd, MaxAddZero, MinAddZero] + + +def _build(model_cls): + m = model_cls() + return m, m.get_inputs(), model_cls.edge_op_list + + +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_tosa_FP_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = TosaPipelineFP[Tensor1](m, inputs, aten_op=[], exir_op=exir) + p.run() + + +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_tosa_INT_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = TosaPipelineINT[Tensor1](m, inputs, aten_op=[], exir_op=exir, qtol=1) + p.run() + + +@common.XfailIfNoCorstone300 +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_u55_INT_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = EthosU55PipelineINT[Tensor1]( + m, + inputs, + aten_ops=[], + exir_ops=exir, + ) + p.run() + + +@common.XfailIfNoCorstone320 +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_u85_INT_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = EthosU85PipelineINT[Tensor1]( + m, + inputs, + aten_ops=[], + exir_ops=exir, + ) + p.run() + + +@common.SkipIfNoModelConverter +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_vgf_quant_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = VgfPipeline[Tensor1]( + m, + inputs, + aten_op=[], + exir_op=exir, + quantize=True, + ) + p.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unbind.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unbind.py new file mode 100644 index 0000000..ce3f769 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unbind.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class Unbind(torch.nn.Module): + aten_op: str = "torch.ops.aten.unbind.int" + + def __init__(self, dim: int): + super().__init__() + self.dim = dim + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor]: + return torch.unbind(x, self.dim) + + test_data: dict[str, test_data_t] = { + "randn_4d": (lambda: (torch.randn(1, 5, 4, 3),), (2,)), + "randn_3d": (lambda: (torch.randn(5, 4, 3),), (0,)), + } + + +@common.parametrize("test_data", Unbind.test_data) +def test_unbind_int_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unbind.test_data) +def test_unbind_int_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unbind.test_data) +@common.SkipIfNoModelConverter +def test_unbind_int_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Unbind.test_data) +@common.SkipIfNoModelConverter +def test_unbind_int_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unflatten.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unflatten.py new file mode 100644 index 0000000..d4730ac --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unflatten.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[torch.nn.Module, input_t] + + +class Unflatten(torch.nn.Module): + aten_op: str = "torch.ops.aten.unflatten.int" + + def __init__(self, dim: int, sizes: Tuple[int, ...]): + super().__init__() + self.dim = dim + self.sizes = sizes + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.unflatten(x, self.dim, self.sizes) + + test_data: dict[str, test_data_t] = { + "rand_3d_batch3": (lambda: (Unflatten(1, (-1, 2)), (torch.rand(3, 4, 4),))), + "rand_3d_batch1": (lambda: (Unflatten(1, (-1, 2)), (torch.rand(1, 4, 4),))), + "randn_4d_dim1": (lambda: (Unflatten(1, (2, 2)), (torch.randn(3, 4, 5, 1),))), + "randn_4d_dim3": (lambda: (Unflatten(3, (2, 2)), (torch.randn(1, 1, 5, 4),))), + } + + +@common.parametrize("test_data", Unflatten.test_data) +def test_unflatten_int_tosa_FP(test_data: test_data_t): + module, inputs = test_data() + pipeline = TosaPipelineFP[input_t]( + module, + inputs, + Unflatten.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data) +def test_unflatten_int_tosa_INT(test_data: test_data_t): + module, inputs = test_data() + pipeline = TosaPipelineINT[input_t](module, inputs, Unflatten.aten_op) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data, strict=False) +@common.XfailIfNoCorstone300 +def test_unflatten_int_u55_INT(test_data: test_data_t): + module, inputs = test_data() + pipeline = EthosU55PipelineINT[input_t]( + module, + inputs, + Unflatten.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data, strict=False) +@common.XfailIfNoCorstone320 +def test_unflatten_int_u85_INT(test_data: test_data_t): + module, inputs = test_data() + pipeline = EthosU85PipelineINT[input_t]( + module, + inputs, + Unflatten.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data) +@common.SkipIfNoModelConverter +def test_unflatten_int_vgf_no_quant(test_data: test_data_t): + module, inputs = test_data() + pipeline = VgfPipeline[input_t]( + module, + inputs, + Unflatten.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data) +@common.SkipIfNoModelConverter +def test_unflatten_int_vgf_quant(test_data: test_data_t): + module, inputs = test_data() + pipeline = VgfPipeline[input_t]( + module, + inputs, + Unflatten.aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unsqueeze.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unsqueeze.py new file mode 100644 index 0000000..0c29d3b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_unsqueeze.py @@ -0,0 +1,107 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the unsqueeze op which copies the data of the input tensor (possibly with new data format) +# + +from typing import Sequence, Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.unsqueeze.default" +input_t1 = Tuple[torch.Tensor, torch.scalar_tensor] # Input x, Input y + + +class Unsqueeze(torch.nn.Module): + shapes: list[int | Sequence[int]] = [5, (5, 5), (5, 4), (5, 4, 3), (1, 5, 4, 3)] + test_parameters = {} + for n in shapes: + test_parameters[f"rand_{n}"] = (torch.randn(n),) + + def forward(self, x: torch.Tensor, dim): + return x.unsqueeze(dim) + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +def test_unsqueeze_tosa_FP(test_tensor: torch.Tensor): + for i in range(-test_tensor[0].dim() - 1, test_tensor[0].dim() + 1): + pipeline = TosaPipelineFP[input_t1]( + Unsqueeze(), + (*test_tensor, i), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +def test_unsqueeze_tosa_INT(test_tensor: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Unsqueeze(), + (*test_tensor, 0), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.XfailIfNoCorstone300 +def test_unsqueeze_u55_INT(test_tensor: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Unsqueeze(), + (*test_tensor, 0), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.XfailIfNoCorstone320 +def test_unsqueeze_u85_INT(test_tensor: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Unsqueeze(), + (*test_tensor, 0), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.SkipIfNoModelConverter +def test_unsqueeze_vgf_no_quant(test_tensor: torch.Tensor): + for i in range(-test_tensor[0].dim() - 1, test_tensor[0].dim() + 1): + pipeline = VgfPipeline[input_t1]( + Unsqueeze(), + (*test_tensor, i), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.SkipIfNoModelConverter +def test_unsqueeze_vgf_quant(test_tensor: torch.Tensor): + for i in range(-test_tensor[0].dim() - 1, test_tensor[0].dim() + 1): + pipeline = VgfPipeline[input_t1]( + Unsqueeze(), + (*test_tensor, i), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_bilinear2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_bilinear2d.py new file mode 100644 index 0000000..11ac351 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_bilinear2d.py @@ -0,0 +1,443 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.upsample_bilinear2d.vec" +exir_op = "executorch_exir_dialects_edge__ops_aten_upsample_bilinear2d_vec" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite_tosa = { + # (test_name, test_data, size, scale_factor, compare_outputs) + "rand_double_scale": (torch.rand(2, 4, 8, 3), None, 2.0, True), + "rand_double_scale_one_dim": (torch.rand(2, 4, 8, 3), None, (1.0, 2.0), True), + "rand_double_size": (torch.rand(2, 4, 8, 3), (16, 6), None, True), + "rand_one_double_scale": (torch.rand(2, 4, 1, 1), None, 2.0, True), + "rand_one_double_size": (torch.rand(2, 4, 1, 1), (2, 2), None, True), + "rand_one_same_scale": (torch.rand(2, 4, 1, 1), None, 1.0, True), + "rand_one_same_size": (torch.rand(2, 4, 1, 1), (1, 1), None, True), + # Can't compare outputs as the rounding when selecting the nearest pixel is + # different between PyTorch and TOSA. Just check the legalization went well. + # TODO Improve the test infrastructure to support more in depth verification + # of the TOSA legalization results. + "rand_half_scale": (torch.rand(2, 4, 8, 6), None, 0.5, False), + "rand_half_size": (torch.rand(2, 4, 8, 6), (4, 3), None, False), + "rand_one_and_half_scale": (torch.rand(2, 4, 8, 3), None, 1.5, False), + "rand_one_and_half_size": (torch.rand(2, 4, 8, 3), (12, 4), None, False), + # Use randn for a bunch of tests to get random numbers from the + # normal distribution where negative is also a possibilty + "randn_double_scale_negative": (torch.randn(2, 4, 8, 3), None, 2.0, True), + "randn_double_scale_one_dim_negative": ( + torch.randn(2, 4, 8, 3), + None, + (1.0, 2.0), + True, + ), + "randn_double_size_negative": (torch.randn(2, 4, 8, 3), (16, 6), None, True), + "randn_one_double_scale_negative": (torch.randn(2, 4, 1, 1), None, 2.0, True), + "randn_one_double_size_negative": (torch.randn(2, 4, 1, 1), (2, 2), None, True), + "randn_one_same_scale_negative": (torch.randn(2, 4, 1, 1), None, 1.0, True), + "randn_one_same_size_negative": (torch.randn(2, 4, 1, 1), (1, 1), None, True), +} + +test_data_suite_Uxx = { + "rand_half_scale": (torch.rand(2, 4, 8, 6), None, 0.5, False), + "rand_half_size": (torch.rand(2, 4, 8, 6), (4, 3), None, False), + "rand_one_and_half_scale": (torch.rand(2, 4, 8, 3), None, 1.5, False), + "rand_one_and_half_size": (torch.rand(2, 4, 8, 3), (12, 4), None, False), +} + +test_data_u55 = { + "rand_double_size": (torch.rand(2, 4, 8, 3), (16, 6), None, True), +} + + +class UpsamplingBilinear2d(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.UpsamplingBilinear2d( # noqa: TOR101 + size=size, scale_factor=scale_factor + ) + + def forward(self, x): + return self.upsample(x) + + +class Upsample(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.Upsample( + size=size, scale_factor=scale_factor, mode="bilinear", align_corners=True + ) + + def forward(self, x): + return self.upsample(x) + + +class Interpolate(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = lambda x: torch.nn.functional.interpolate( + x, size=size, scale_factor=scale_factor, mode="bilinear", align_corners=True + ) + + def forward(self, x): + return self.upsample(x) + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_FP_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineFP[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_FP_Upsample( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineFP[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_FP_Interpolate( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineFP[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_INT_intropolate( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineINT[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_INT_Upsample( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_INT_a16w8( + test_data: torch.Tensor, +): + """Test upsample_bilinear2d vector op with int16 I/O quantization for TOSA INT.""" + test_data, size, scale_factor, compare_outputs = test_data + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + tosa_extensions=["int16"], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_bilinear2d_vec_u55_INT_Upsample_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + pipeline = OpNotSupportedPipeline[input_t1]( + Upsample(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_bilinear2d_vec_u55_INT_Interpolate_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + pipeline = OpNotSupportedPipeline[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_bilinear2d_vec_u55_INT_UpsamplingBilinear2d_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + pipeline = OpNotSupportedPipeline[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_Upsample(test_data: input_t1): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + qtol=1, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_Interpolate( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + qtol=1, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + aten_op, + qtol=1, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_a16w8( + test_data: input_t1, +): + """Test upsample_bilinear2d vec op with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (data,), + aten_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_no_quant_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_no_quant_Upsample(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_no_quant_Interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_quant_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_quant_Upsample(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_quant_Interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_nearest2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_nearest2d.py new file mode 100644 index 0000000..cb7d487 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_upsample_nearest2d.py @@ -0,0 +1,520 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.upsample_nearest2d.vec" +exir_op = "executorch_exir_dialects_edge__ops_aten_upsample_nearest2d_vec" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data, size, scale_factor, compare_outputs) + "rand_double_scale": lambda: (torch.rand(2, 4, 8, 3), None, 2.0, True), + "rand_double_scale_one_dim": lambda: ( + torch.rand(2, 4, 8, 3), + None, + (1.0, 2.0), + True, + ), + "rand_double_size": lambda: (torch.rand(2, 4, 8, 3), (16, 6), None, True), + "rand_one_double_scale": lambda: (torch.rand(2, 4, 1, 1), None, 2.0, True), + "rand_one_double_size": lambda: (torch.rand(2, 4, 1, 1), (2, 2), None, True), + "rand_one_same_scale": lambda: (torch.rand(2, 4, 1, 1), None, 1.0, True), + "rand_one_same_size": lambda: (torch.rand(2, 4, 1, 1), (1, 1), None, True), + # Can't compare outputs as the rounding when selecting the nearest pixel is + # different between PyTorch and TOSA. Just check the legalization went well. + # TODO Improve the test infrastructure to support more in depth verification + # of the TOSA legalization results. + "rand_half_scale": lambda: (torch.rand(2, 4, 8, 6), None, 0.5, False), + "rand_half_size": lambda: (torch.rand(2, 4, 8, 6), (4, 3), None, False), + "rand_one_and_half_scale": lambda: (torch.rand(2, 4, 8, 3), None, 1.5, False), + "rand_one_and_half_size": lambda: (torch.rand(2, 4, 8, 3), (12, 4), None, False), +} + +test_data_u55 = { + "rand_double_size": lambda: (torch.rand(2, 4, 8, 3), (16, 6), None, True), +} + +test_data_suite_dynamic = { + # (test_name, test_data, size, scale_factor, compare_outputs) + "rand_double_scale": lambda: (torch.rand(2, 4, 8, 3), None, 2.0, False), + "rand_double_scale_one_dim": lambda: ( + torch.rand(2, 4, 8, 3), + None, + (1.0, 2.0), + False, + ), +} + + +class UpsamplingNearest2d(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.UpsamplingNearest2d( # noqa: TOR101 + size=size, scale_factor=scale_factor + ) + + def forward(self, x): + return self.upsample(x) + + +class Upsample(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.Upsample( + size=size, scale_factor=scale_factor, mode="nearest" + ) + + def forward(self, x): + return self.upsample(x) + + +class Interpolate(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = lambda x: torch.nn.functional.interpolate( + x, size=size, scale_factor=scale_factor, mode="nearest" + ) + + def forward(self, x): + return self.upsample(x) + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_FP(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineFP[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_FP_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = TosaPipelineFP[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_FP_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineFP[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineINT[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineINT[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT_a16w8(test_data: torch.Tensor): + """Test upsample_nearest2d vector op with int16 I/O quantization for TOSA INT.""" + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + tosa_extensions=["int16"], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_no_quant(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_no_quant_nearest(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_no_quant_interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + # Override tosa version to test FP-only path + tosa_version="TOSA-1.0+FP", + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_quant(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_quant_nearest(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_INT_interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + # Override tosa version to test INT-only path + tosa_version="TOSA-1.0+INT", + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_nearest2d_vec_u55_INT_Upsample_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Upsample(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_nearest2d_vec_u55_INT_Interpolate_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_nearest2d_vec_u55_INT_UpsamplingBilinear2d_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_FP_dynamic_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=1000) + input_height = torch.export.Dim("input_height", min=0, max=1000) + input_width = torch.export.Dim("input_width", min=0, max=1000) + + dynamic_shapes = {"x": {0: batch_size, 2: input_height, 3: input_width}} + + pipeline = TosaPipelineFP[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_INT_dynamic_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=0, max=8) + input_width = torch.export.Dim("input_width", min=0, max=8) + + dynamic_shapes = {"x": {0: batch_size, 2: input_height, 3: input_width}} + + pipeline = TosaPipelineINT[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_FP_dynamic_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=4, max=8) + input_width = torch.export.Dim("input_width", min=3, max=8) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineFP[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_INT_dynamic_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=4, max=8) + input_width = torch.export.Dim("input_width", min=3, max=8) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineINT[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_FP_dynamic_upsample(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=1000) + input_height = torch.export.Dim("input_height", min=0, max=1000) + input_width = torch.export.Dim("input_width", min=0, max=1000) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineFP[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_INT_dynamic_upsample(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=0, max=8) + input_width = torch.export.Dim("input_width", min=0, max=8) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_var.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_var.py new file mode 100644 index 0000000..a7943bf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_var.py @@ -0,0 +1,394 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Var(torch.nn.Module): + test_parameters = { + "var_4d_keep_dim_0_correction": lambda: (torch.randn(1, 50, 10, 20), True, 0), + "var_3d_no_keep_dim_0_correction": lambda: (torch.rand(1, 50, 10), False, 0), + "var_4d_keep_dim_1_correction": lambda: (torch.randn(1, 30, 15, 20), True, 1), + "var_4d_no_keep_dim_0_5_correction": lambda: ( + torch.rand(1, 50, 10, 20), + False, + 0.5, + ), + } + + def __init__(self, keepdim: bool = True, correction: int = 0): + super().__init__() + self.keepdim = keepdim + self.correction = correction + + def forward( + self, + x: torch.Tensor, + ): + return x.var(keepdim=self.keepdim, correction=self.correction) + + +class VarDim(torch.nn.Module): + test_parameters = { + "var_4d_dim_1_keep_dim_unbiased": lambda: ( + torch.randn(1, 50, 10, 20), + 1, + True, + False, + ), + "var_3d_dim_neg_2_no_keep_dim_unbiased": lambda: ( + torch.rand(1, 50, 10), + -2, + False, + False, + ), + "var_3d_dim_neg_3_keep_dim_biased": lambda: ( + torch.randn(1, 30, 15, 20), + -3, + True, + True, + ), + "var_3d_dim_neg_1_no_keep_dim_biased": lambda: ( + torch.rand(1, 50, 10, 20), + -1, + False, + True, + ), + } + + test_parameters_u55 = { + "var_4d_dim_1_keep_dim_unbiased": lambda: ( + torch.randn(1, 50, 10, 20), + 1, + True, + False, + ), + "var_4d_dim_neg_3_keep_dim_biased": lambda: ( + torch.randn(1, 30, 15, 20), + -3, + True, + True, + ), + } + + def __init__(self, dim: int = -1, keepdim: bool = True, unbiased: bool = False): + super().__init__() + self.dim = dim + self.keepdim = keepdim + self.unbiased = unbiased + + def forward( + self, + x: torch.Tensor, + ): + return x.var(dim=self.dim, keepdim=self.keepdim, unbiased=self.unbiased) + + +class VarCorrection(torch.nn.Module): + test_parameters = { + "var_4d_dims_keep_dim_0_correction": lambda: ( + torch.randn(1, 50, 10, 20), + (-1, -2), + True, + 0, + ), + "var_3d_dims_keep_dim_0_correction": lambda: ( + torch.rand(1, 50, 10), + (-2), + True, + 0, + ), + "var_4d_dims_keep_dim_1_correction": lambda: ( + torch.randn(1, 30, 15, 20), + (-1, -2, -3), + True, + 1, + ), + "var_4d_dims_keep_dim_0_5_correction": lambda: ( + torch.rand(1, 50, 10, 20), + (-1, -2), + True, + 0.5, + ), + } + + def __init__(self, dim: int = -1, keepdim: bool = True, correction: bool = False): + super().__init__() + self.dim = dim + self.keepdim = keepdim + self.correction = correction + + def forward( + self, + x: torch.Tensor, + ): + return x.var(dim=self.dim, keepdim=self.keepdim, correction=self.correction) + + +########## +## Var ### +########## + + +@common.parametrize("test_data", Var.test_parameters) +def test_var_dim_tosa_FP_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = TosaPipelineFP[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +def test_var_dim_tosa_INT_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = TosaPipelineINT[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.XfailIfNoCorstone300 +def test_var_dim_u55_INT_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.XfailIfNoCorstone320 +def test_var_dim_u85_INT_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_no_quant_no_dim(test_data: Tuple): + data, keepdim, correction = test_data() + pipeline = VgfPipeline[input_t1]( + Var(keepdim, correction), + (data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_quant_no_dim(test_data: Tuple): + data, keepdim, correction = test_data() + pipeline = VgfPipeline[input_t1]( + Var(keepdim, correction), + (data,), + [], + [], + quantize=True, + ) + pipeline.run() + + +############# +## VarDim ### +############# + + +@common.parametrize("test_data", VarDim.test_parameters) +def test_var_dim_tosa_FP(test_data: Tuple): + test_data, dim, keepdim, unbiased = test_data() + pipeline = TosaPipelineFP[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +def test_var_dim_tosa_INT(test_data: Tuple): + + test_data, dim, keepdim, unbiased = test_data() + pipeline = TosaPipelineINT[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters_u55) +@common.XfailIfNoCorstone300 +def test_var_dim_u55_INT(test_data: Tuple): + test_data, dim, keepdim, unbiased = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +@common.XfailIfNoCorstone320 +def test_var_dim_u85_INT(test_data: Tuple): + test_data, dim, keepdim, unbiased = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_no_quant(test_data: Tuple): + data, dim, keepdim, unbiased = test_data() + pipeline = VgfPipeline[input_t1]( + VarDim(dim, keepdim, unbiased), + (data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_quant(test_data: Tuple): + data, dim, keepdim, unbiased = test_data() + pipeline = VgfPipeline[input_t1]( + VarDim(dim, keepdim, unbiased), + (data,), + [], + [], + quantize=True, + ) + pipeline.run() + + +#################### +## VarCorrection ### +#################### + + +@common.parametrize("test_data", VarCorrection.test_parameters) +def test_var_dim_tosa_FP_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = TosaPipelineFP[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +def test_var_dim_tosa_INT_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = TosaPipelineINT[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize( + "test_data", + VarCorrection.test_parameters, +) +@common.XfailIfNoCorstone300 +def test_var_dim_u55_INT_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +@common.XfailIfNoCorstone320 +def test_var_dim_u85_INT_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_no_quant_correction(test_data: Tuple): + data, dim, keepdim, corr = test_data() + pipeline = VgfPipeline[input_t1]( + VarCorrection(dim, keepdim, corr), + (data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_quant_correction(test_data: Tuple): + data, dim, keepdim, corr = test_data() + pipeline = VgfPipeline[input_t1]( + VarCorrection(dim, keepdim, corr), + (data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_view.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_view.py new file mode 100644 index 0000000..fb0445a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_view.py @@ -0,0 +1,253 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the view op which changes the size of a Tensor without changing the underlying data. +# + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.view.default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, Input y + + +class View(torch.nn.Module): + + needs_transpose_tests = { + "rand_1d_neg": lambda: (torch.rand(100), (1, -1, 5, 2)), + "rand_4d_neg": lambda: (torch.rand(10, 2, 1, 5), (1, -1, 5, 2)), + "rand_4d_4d_small": lambda: (torch.rand(1, 2, 1, 9), (3, 1, 3, 2)), + "rand_4d_4d": lambda: (torch.rand(2, 1, 1, 9), (3, 2, 3, 1)), + "rand_4d_2d": lambda: (torch.rand(2, 50, 2, 1), (1, 200)), + "rand_4d_3d": lambda: (torch.rand(2, 5, 2, 3), (1, 15, 4)), + "rand_4d_1": lambda: (torch.rand(2, 1, 1, 9), (3, 1, 3, 2)), + "rand_4d_2": lambda: (torch.rand(5, 10, 1, 1), (25, 2, 1, 1)), + "rand_4d_2_4": lambda: (torch.rand(10, 2), (1, 1, 5, 4)), + "rand_4d_2_4_big": lambda: (torch.rand(10, 10), (5, 1, 5, 4)), + "rand_4d_4_4": lambda: (torch.rand(1, 1, 1, 10), (1, 1, 10, 1)), + "rand_4d_4_4_big": lambda: (torch.rand(1, 1, 5, 10), (1, 1, 50, 1)), + "rand_4d_4_3": lambda: (torch.rand(5, 10, 1, 1), (1, 25, 2)), + "rand_4d_4_2": lambda: (torch.rand(2, 50, 1, 1), (1, 100)), + "rand_4d_2_4_same": lambda: (torch.rand(2, 3, 2, 3), (2, 3, 3, 2)), + "rand_4d_5d": lambda: (torch.rand(1, 3, 4, 5), (1, 1, 4, 5, -1)), + "rand_5d_5d": lambda: (torch.rand(1, 1, 4, 5, 6), (1, 1, 4, -1, 6)), + "rand_5d_3d": lambda: (torch.rand(1, 1, 4, 5, 6), (2, 3, -1)), + "rand_3d_5d": lambda: (torch.rand(4, 5, 6), (1, 1, 2, -1, 3)), + } + + rank_product_too_large = { + "rand_4d_large": lambda: (torch.rand(1, 49, 16, 128), (1, 16, 49, 128)), + } + + def __init__(self, new_shape): + super().__init__() + self.new_shape = new_shape + + def forward(self, x: torch.Tensor): + return x.view(self.new_shape) + + +@common.parametrize("test_data", View.needs_transpose_tests) +def test_view_tosa_FP(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = TosaPipelineFP[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +def test_view_tosa_INT(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = TosaPipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone300 +def test_view_u55_INT(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.SkipIfNoModelConverter +def test_view_vgf_no_quant(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = VgfPipeline[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.SkipIfNoModelConverter +def test_view_vgf_quant(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = VgfPipeline[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", View.rank_product_too_large) +@common.XfailIfNoCorstone300 +def test_view_u55_INT_not_delegated(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + View(new_shape), + (test_tensor,), + {"executorch_exir_dialects_edge__ops_aten_view_copy": 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone320 +def test_view_u85_INT(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +def get_symmetric_a16w8_view_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", View.needs_transpose_tests) +def test_view_16a8w_tosa_INT(test_data: Tuple): + """Test view operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + test_tensor, new_shape = test_data() + + pipeline = TosaPipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_view_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone300 +def test_view_16a8w_u55_INT(test_data: Tuple): + """Test view operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + test_tensor, new_shape = test_data() + + pipeline = EthosU55PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_view_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone320 +def test_view_16a8w_u85_INT(test_data: Tuple): + """Test view operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + test_tensor, new_shape = test_data() + + pipeline = EthosU85PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_view_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_where.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_where.py new file mode 100644 index 0000000..50a7aef --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_where.py @@ -0,0 +1,285 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List, Tuple + +import torch +from executorch.backends.arm.quantizer import ( + EthosUQuantizer, + get_symmetric_quantization_config, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.xnnpack.test.tester.tester import Quantize + +aten_op = "torch.ops.aten.where.self" +exir_op = "executorch_exir_dialects_edge__ops_aten_where_self" + + +class Where(torch.nn.Module): + def __init__( + self, shape: tuple | int, dtype: torch.dtype | Tuple[torch.dtype], condition + ): + super().__init__() + self.shape = shape if isinstance(shape, tuple) else (shape,) * shape + self.dtype = (dtype, dtype) if isinstance(dtype, torch.dtype) else dtype + self.condition = condition + + def get_inputs(self): + inputs: List = [0, 0] + for i in range(2): + if self.dtype[i] in [torch.int8, torch.int16, torch.int32]: + inputs[i] = torch.randint( + torch.iinfo(self.dtype[i]).min, + torch.iinfo(self.dtype[i]).max, + self.shape, + dtype=self.dtype[i], + ) + elif self.dtype[i] in [torch.float32]: + inputs[i] = torch.randn(*self.shape).to(self.dtype[i]) + elif self.dtype[i] is torch.bool: + inputs[i] = torch.randint(0, 1, self.shape, dtype=torch.bool) + else: + raise TypeError( + f"Input generation for dtype {self.dtype[i]} not implemented in " + "Where()" + ) + + return tuple(inputs) + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor, + ): + return torch.where(self.condition(input_), input_, other_) + + +class ConstWhere(torch.nn.Module): + + def __init__(self, buffer: torch.Tensor, dtype: torch.dtype): + super().__init__() + self.buffer = buffer + self.dtype = dtype + self.min = torch.nn.Buffer(torch.tensor(0.0, dtype=self.dtype)) + self.input_1 = torch.nn.Buffer(torch.tensor(-1.0, dtype=self.dtype)) + self.input_2 = torch.nn.Buffer(torch.tensor(1.0, dtype=self.dtype)) + + def get_inputs(self): + return (torch.rand(self.buffer.size(), dtype=self.dtype),) + + def forward(self, input: torch.Tensor): + return ( + torch.where( + self.buffer > self.min, + self.input_1, + self.input_2, + ) + + input + ) + + +def tensor_condition(input: torch.Tensor): + return input > torch.zeros_like(input) + + +def scalar_condition(input: torch.Tensor): + return input > 0 + + +two_dim_tensor_cond = Where( + 2, + torch.float32, + tensor_condition, +) + +three_dim_tensor_cond = Where( + 3, + torch.float32, + tensor_condition, +) + +float32_tensor_cond = Where( + 1, + torch.float32, + tensor_condition, +) + +float32_tensor_cond_tuple_dtype = Where( + 1, + (torch.float32, torch.int8), + tensor_condition, +) + +float32_tensor_cond_tuple_dtype_bool = Where( + 1, + (torch.float32, torch.bool), + tensor_condition, +) + +# Scalar tests +two_dim_scalar_cond = Where( + 2, + torch.float32, + scalar_condition, +) + +three_dim_scalar_cond = Where( + 3, + torch.float32, + scalar_condition, +) + +float32_scalar_cond = Where( + 1, + torch.float32, + scalar_condition, +) + +int32_scalar_cond = Where( + 1, + torch.int32, + scalar_condition, +) + +const_float32 = ConstWhere( + buffer=torch.tensor([[1.0, -1.0], [-1.0, 1.0]]), + dtype=torch.float32, +) + +test_modules_common = { + "two_dim_tensor_cond": lambda: two_dim_tensor_cond, + "three_dim_tensor_cond": lambda: three_dim_tensor_cond, + "float32_tensor_cond": lambda: float32_tensor_cond, + "two_dim_scalar_cond": lambda: two_dim_scalar_cond, + "three_dim_scalar_cond": lambda: three_dim_scalar_cond, + "float32_scalar_cond": lambda: float32_scalar_cond, + "const_float32": lambda: const_float32, +} + +test_modules_FP = { + **test_modules_common, + "float32_tensor_cond_tuple_dtype_bool": lambda: float32_tensor_cond_tuple_dtype_bool, +} + +test_modules_FP_unsupported_dtype = { + "float32_tensor_cond_tuple_dtype": lambda: float32_tensor_cond_tuple_dtype, + "int32_scalar_cond": lambda: int32_scalar_cond, +} + +test_modules_INT = { + **test_modules_common, +} + +input_t = Tuple[torch.Tensor] + + +@common.parametrize("test_module", test_modules_FP) +def test_where_self_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_FP_unsupported_dtype) +def test_where_self_tosa_FP_unsupported_dtype(test_module): + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {exir_op: 1}, + n_expected_delegates=1, # condition can be delegated + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +def test_where_self_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +@common.XfailIfNoCorstone300 +def test_where_self_u55_INT_not_delegated(test_module): + # There will be one full_like op which will be delegated. + num_delegates = 1 + num_exir = 0 + + compile_spec = common.get_u55_compile_spec() + quantizer = EthosUQuantizer(compile_spec).set_io( + get_symmetric_quantization_config() + ) + + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + { + exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.change_args( + "quantize", Quantize(quantizer, get_symmetric_quantization_config()) + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +@common.XfailIfNoCorstone320 +def test_where_self_u85_INT(test_module): + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_FP) +@common.SkipIfNoModelConverter +def test_where_self_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +@common.SkipIfNoModelConverter +def test_where_self_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_while.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_while.py new file mode 100644 index 0000000..64870ee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_while.py @@ -0,0 +1,264 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Tuple + +import torch +import torch.fx + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.arm_tester import ArmTester +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from pytest import mark + +input_single = Tuple[torch.Tensor] +input_double = Tuple[torch.Tensor, torch.Tensor] + + +class WhileTwoInputsTwoOutputs(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + + def forward( + self, lhs: torch.Tensor, rhs: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + def cond_fn(lhs_val: torch.Tensor, rhs_val: torch.Tensor) -> torch.Tensor: + total = torch.sum(rhs_val) + zero = torch.zeros_like(total) + return torch.gt(total, zero).squeeze() + + def body_fn( + lhs_val: torch.Tensor, rhs_val: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + next_lhs = torch.add(lhs_val, rhs_val) + next_rhs = torch.sub(rhs_val, torch.full((1,), 1.0)) + return (next_lhs, next_rhs) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (lhs, rhs), + (), + ) + return result # type: ignore + + +class WhileOneInputOneBufferTwoOutputs(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer("threshold", torch.tensor((30.0,))) + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor, limit: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.lt(total, limit).squeeze() + + def body_fn( + value: torch.Tensor, limit: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + return (torch.add(value, value), limit.clone()) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value, self.threshold), + (), + ) + return result # type: ignore + + +class DecreasingOutput(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.gt(total, torch.full((1,), 60.0)).squeeze() + + def body_fn(value: torch.Tensor) -> Tuple[torch.Tensor]: + return (torch.div(value, torch.full((1,), 2.0)),) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value,), + (), + ) + return result[0] # type: ignore + + +class WhileAdditionalArg(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer("threshold", torch.tensor((300.0,))) + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor, limit: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.lt(total, limit).squeeze() + + def body_fn(value: torch.Tensor, limit: torch.Tensor) -> tuple[torch.Tensor]: + return (torch.add(value, value),) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value,), + (self.threshold,), + ) + return result # type: ignore + + +class WhileSingleCapturedOutput(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer("threshold", torch.tensor((200.0,))) + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor, limit: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.lt(total, limit).squeeze() + + def body_fn( + value: torch.Tensor, limit: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + return (torch.add(value, value), limit.clone()) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value, self.threshold), + (), + ) + return result[0] # type: ignore + + +def _single_input_case( + module_factory: Callable[[], torch.nn.Module], +) -> Callable[[], Tuple[torch.nn.Module, input_single]]: + def _create() -> Tuple[torch.nn.Module, input_single]: + return module_factory(), (torch.ones(2, 3, 4, 6),) + + return _create + + +def _dual_input_case( + module_factory: Callable[[], torch.nn.Module], +) -> Callable[[], Tuple[torch.nn.Module, input_double]]: + def _create() -> Tuple[torch.nn.Module, input_double]: + return module_factory(), (torch.zeros(2, 3), torch.full((2, 3), -2.0)) + + return _create + + +test_cases: dict[str, Callable[[], Tuple[torch.nn.Module, Tuple]]] = { + "two_in_two_out": _dual_input_case(WhileTwoInputsTwoOutputs), + "one_in_one_buffer_two_out": _single_input_case(WhileOneInputOneBufferTwoOutputs), + "decreasing_output": _single_input_case(DecreasingOutput), + "additional_arg": _single_input_case(WhileAdditionalArg), + "two_in_one_captured_out": _single_input_case(WhileSingleCapturedOutput), +} + + +@common.parametrize( + "case", + test_cases, +) +def test_while_loop_tosa_FP(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineFP[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + tosa_extensions=["cf"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, +) +def test_while_loop_tosa_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineINT[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + tosa_extensions=["cf"], + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + ArmTester.check_not, + pipeline.tester, + ["torch.ops.higher_order.while_loop"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, +) +def test_while_loop_u55_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + OpNotSupportedPipeline[tuple]( + module, + example_inputs, + non_delegated_ops={"torch.ops.higher_order.while_loop": 1}, + u55_subset=True, + ).run() + + +@common.parametrize( + "case", + test_cases, +) +@common.XfailIfNoCorstone320 +def test_while_loop_u85_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + EthosU85PipelineINT[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + ).run() + + +@mark.skip("While not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_while_loop_vgf_FP(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + VgfPipeline[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + tosa_version="TOSA-1.0+FP", + ).run() + + +@mark.skip("While not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_while_loop_vgf_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + VgfPipeline[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_zeros.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_zeros.py new file mode 100644 index 0000000..7e1609e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/ops/test_zeros.py @@ -0,0 +1,158 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class ZerosAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.zeros.default" + + def __init__(self, n: int, dtype: torch.dtype): + super().__init__() + self.args = (n,) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.zeros(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)), + "10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (10, torch.int32), + ), + } + + # Mixed dtypes - the zeros op is delegated, but it leads to a non-delegated add op. + test_data_mixed_dtypes: dict[str, test_data_t] = { + "fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)), + "fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)), + } + + +@common.parametrize("test_data", ZerosAdd.test_data | ZerosAdd.test_data_mixed_dtypes) +def test_zeros_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ZerosAdd.test_data | ZerosAdd.test_data_mixed_dtypes) +def test_zeros_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", ZerosAdd.test_data) +@common.XfailIfNoCorstone300 +def test_zeros_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", ZerosAdd.test_data) +@common.XfailIfNoCorstone320 +def test_zeros_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize( + "test_data", + ZerosAdd.test_data_mixed_dtypes, +) +def test_zeros_tosa_INT_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + ZerosAdd(*init_data), + input_data(), + non_delegated_ops={"executorch_exir_dialects_edge__ops_aten_add_Tensor": 1}, + n_expected_delegates=1, + quantize=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + ZerosAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_zeros_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + ZerosAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_zeros_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + quantize=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_broadcast_args_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_broadcast_args_pass.py new file mode 100644 index 0000000..eab4f20 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_broadcast_args_pass.py @@ -0,0 +1,57 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import operator +from typing import Callable, Tuple + +import torch +from executorch.backends.arm._passes import BroadcastArgsPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class NeedsMultipleBroadcastsModel(torch.nn.Module): + test_data = (torch.rand(1, 10), torch.rand(10, 1)) + + def __init__( + self, op: Callable[[torch.Tensor, torch.Tensor], torch.Tensor] + ) -> None: + self.op = op + super().__init__() + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return self.op(x, y) + + +modules = { + "add": NeedsMultipleBroadcastsModel(operator.add), + "sub": NeedsMultipleBroadcastsModel(operator.sub), + "mul": NeedsMultipleBroadcastsModel(operator.mul), + "div": NeedsMultipleBroadcastsModel(operator.truediv), +} + + +@common.parametrize("module", modules) +def test_broadcast_args_tosa_INT_multiple(module: NeedsMultipleBroadcastsModel): + test_data = module.test_data + ops_not_before_pass = [ + "executorch_exir_dialects_edge__ops_aten_repeat_default", + ] + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_repeat_default": 1, + } + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=True, + ops_not_before_pass=ops_not_before_pass, + ops_after_pass=ops_after_pass, + pass_list=[BroadcastArgsPass], + tosa_extensions=["u55"], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_cast_int64_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_cast_int64_pass.py new file mode 100644 index 0000000..dac4922 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_cast_int64_pass.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import CastInt64BuffersToInt32Pass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +from executorch.backends.test.harness.stages import StageType + +input_t = Tuple[torch.Tensor] # Input x + + +class Int64Model(torch.nn.Module): + test_data = { + "rand": (torch.rand(4),), + } + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x + 3 + + +@common.parametrize("test_data", Int64Model.test_data) +def test_cast_int64_buffers_to_int32_tosa_FP(test_data: input_t): + module = Int64Model() + op_checks = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + } + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass=op_checks, + ops_after_pass=op_checks, + passes_with_exported_program=[CastInt64BuffersToInt32Pass], + ) + pipeline.run() + + exported_program = pipeline.tester.get_artifact( + StageType.RUN_PASSES + ).exported_program() + for state in exported_program.state_dict: + assert exported_program.state_dict[state].dtype == torch.int32 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py new file mode 100644 index 0000000..8217d4e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py @@ -0,0 +1,51 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.convert_expand_copy_to_repeat import ( + ConvertExpandCopyToRepeatPass, +) + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Expand(torch.nn.Module): + """ + Basic expand model using torch.Tensor.expand function + """ + + def __init__(self) -> None: + super().__init__() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.expand(3, 4) + + def get_inputs(self) -> input_t: + return (torch.rand(3, 1),) + + +def test_convert_expand_copy_to_repeat_tosa_INT() -> None: + module = Expand() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_expand_copy_default": 1, + }, + ops_not_before_pass=["executorch_exir_dialects_edge__ops_aten_repeat_default"], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_repeat_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_expand_copy_default" + ], + pass_list=[ConvertExpandCopyToRepeatPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py new file mode 100644 index 0000000..0dbc9d9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py @@ -0,0 +1,529 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, ClassVar, Dict, Tuple, Union + +import pytest + +import torch +from executorch.backends.arm._passes import ( + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +input_t1 = Tuple[torch.Tensor] # Input x +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + +Scalar = Union[bool, float, int] +ArangeNoneParam = Tuple[Callable[[], input_t1], Tuple[Scalar, Scalar, Scalar]] +FullNoneParam = Tuple[Callable[[], input_t1], Tuple[Tuple[int, ...], Scalar]] + + +##################################################### +## Test arange(dtype=int64) -> arange(dtype=int32) ## +##################################################### + + +class ArangeDefaultIncrementViewLessThan(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (torch.arange(10, dtype=torch.int64) + 1).view(-1, 1) < x + + test_data: ClassVar[Dict[str, input_t1]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", ArangeDefaultIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_default( + test_data: input_t1, +) -> None: + module = ArangeDefaultIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ConvertInt64ConstOpsToInt32Pass()], + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeDefaultIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_default( + test_data: input_t1, +) -> None: + module = ArangeDefaultIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +class ArangeStartIncrementViewLessThan(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (torch.arange(0, 10, dtype=torch.int64) + 1).view(-1, 1) < x + + test_data: ClassVar[Dict[str, input_t1]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", ArangeStartIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_start( + test_data: input_t1, +) -> None: + module = ArangeStartIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ConvertInt64ConstOpsToInt32Pass()], + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeStartIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_start( + test_data: input_t1, +) -> None: + module = ArangeStartIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +class ArangeStartStepIncrementViewLessThan(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (torch.arange(0, 10, 2, dtype=torch.int64) + 1).view(-1, 1) < x + + test_data: ClassVar[Dict[str, input_t1]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", ArangeStartStepIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_start_step( + test_data: input_t1, +) -> None: + module = ArangeStartStepIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ConvertInt64ConstOpsToInt32Pass()], + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeStartStepIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_start_step( + test_data: input_t1, +) -> None: + module = ArangeStartStepIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +######################################################### +## Test arange(dtype=None) -> arange(dtype=None/int32) ## +######################################################### + + +class ArangeAddDtypeNone(torch.nn.Module): + aten_op: str = "torch.ops.aten.arange.start_step" + exir_op: str = "executorch_exir_dialects_edge__ops_aten_arange_start_step" + + def __init__(self, start: float, stop: float, step: float): + super().__init__() + self.args = (start, stop, step) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.arange(*self.args) + x + + test_data: ClassVar[Dict[str, ArangeNoneParam]] = { + "int64": (lambda: (torch.randn(10, 1),), (0, 10, 1)), + "float32_start": (lambda: (torch.randn(10, 1),), (0.0, 10, 1)), + "float32_stop": (lambda: (torch.randn(10, 1),), (0, 10.0, 1)), + "float32_step": (lambda: (torch.randn(10, 1),), (0, 10, 1.0)), + "int64_bool_0": (lambda: (torch.randn(10, 1),), (False, True, True)), + "int64_bool_1": (lambda: (torch.randn(10, 1),), (False, True, True * 10)), + "float32_bool_0": (lambda: (torch.randn(10, 1),), (0.0, True, True)), + "float32_bool_1": (lambda: (torch.randn(10, 1),), (False, True, True * 10.0)), + } + + +@common.parametrize("test_data", ArangeAddDtypeNone.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_none( + test_data: ArangeNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineFP[input_t1]( + ArangeAddDtypeNone(*init_data), + input_factory(), + ArangeAddDtypeNone.aten_op, + ArangeAddDtypeNone.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAddDtypeNone.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_none( + test_data: ArangeNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineINT[input_t1]( + ArangeAddDtypeNone(*init_data), + input_factory(), + ArangeAddDtypeNone.aten_op, + ArangeAddDtypeNone.exir_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +################################################# +## Test full(dtype=int64) -> full(dtype=int32) ## +################################################# + + +class FullIncrementViewMulXLessThanY(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return ( + ( + torch.full( + ( + 1, + 3, + 5, + ), + 10, + dtype=torch.int64, + ) + + 1 + ).view(-1, 1) + * x + ) < y + + test_data: ClassVar[Dict[str, input_t2]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", FullIncrementViewMulXLessThanY.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_full( + test_data: input_t2, +) -> None: + """ + There are four int64 placeholders in the original graph: + 1. _lifted_tensor_constant0: 1 + 2. x + 3. y + Ideally, after applying ConvertInt64ConstOpsToInt32Pass to convert the aten.full from int64 to int32, + the int32 type should propagate throughout the graph, and no int64 values should remain. + However, due to unexpected retracing behavior, a cast from int32 → int64 for x was reintroducedh. + + Applying ConvertInt64OutputOpsToInt32Pass afterward resolves this issue, + removing the int64 cast and producing a fully delegated int32 graph. + """ + module = FullIncrementViewMulXLessThanY() + aten_ops_checks = [ + "torch.ops.aten.full.default", + "torch.ops.aten.add.Tensor", + "torch.ops.aten.view.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.lt.Tensor", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + ] + pipeline = TosaPipelineFP[input_t2]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + ], + ) + pipeline.run() + + +@common.parametrize("test_data", FullIncrementViewMulXLessThanY.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_full( + test_data: input_t2, +) -> None: + """ + For INT profile, _lifted_tensor_constant0 is still int64 after applying ConvertInt64ConstOpsToInt32Pass(). + And an int64->int32 cast is inserted at the beginning of the graph. + TODO: Explore why _lifted_tensor_constant0 is handled in different ways in FP and INT profile. + Find a way to optimize out the int64->int32 cast. + """ + module = FullIncrementViewMulXLessThanY() + aten_ops_checks = [ + "torch.ops.aten.full.default", + "torch.ops.aten.add.Tensor", + "torch.ops.aten.view.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.lt.Tensor", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + ] + pipeline = TosaPipelineINT[input_t2]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +class RejectFullIncrementViewMulXLessThanY(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return ( + ( + torch.full( + ( + 1, + 3, + 5, + ), + torch.iinfo(torch.int32).max + 1, + dtype=torch.int64, + ) + + 1 + ).view(-1, 1) + * x + ) < y + + test_data: ClassVar[Dict[str, input_t2]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", RejectFullIncrementViewMulXLessThanY.test_data) +@pytest.mark.xfail( + reason="MLETORCH-1254: Add operator support check for aten.arange and aten.full" +) +def test_convert_int64_const_ops_to_int32_tosa_FP_reject_full( + test_data: input_t2, +) -> None: + module = RejectFullIncrementViewMulXLessThanY() + aten_ops_checks = [ + "torch.ops.aten.full.default", + "torch.ops.aten.add.Tensor", + "torch.ops.aten.view.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.lt.Tensor", + ] + pipeline = TosaPipelineFP[input_t2]( + module, + test_data, + aten_ops_checks, + exir_op=[], + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + ], + ) + pipeline.run() + + +##################################################### +## Test full(dtype=None) -> full(dtype=None/int32) ## +##################################################### + + +class AddConstFullDtypeNone(torch.nn.Module): + # Input + a full with constant value. + exir_op = "executorch_exir_dialects_edge__ops_aten_full_default" + + def __init__(self, size: tuple, fill_value: Union[bool, float, int]): + super().__init__() + self.args = (size, fill_value) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.full(*self.args) + x + + test_data = { + "int64": (lambda: (torch.randn(1),), ((1, 2, 3), 10)), + "float32": (lambda: (torch.randn(1),), ((1, 2, 3), 10.0)), + } + + test_data_bool = { + "bool": (lambda: (torch.randn(1),), ((1, 2, 3), True)), + } + + +@common.parametrize("test_data", AddConstFullDtypeNone.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_full_none( + test_data: FullNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineFP[input_t1]( + AddConstFullDtypeNone(*init_data), + input_factory(), + aten_op=[], + exir_op=AddConstFullDtypeNone.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", AddConstFullDtypeNone.test_data_bool) +def test_convert_int64_const_ops_to_int32_tosa_FP_full_none_bool( + test_data: FullNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineFP[input_t1]( + AddConstFullDtypeNone(*init_data), + input_factory(), + aten_op=[], + exir_op=AddConstFullDtypeNone.exir_op, + ) + pipeline.change_args( + "check_count.exir", + {"torch.ops.higher_order.executorch_call_delegate": 2}, + ) + pipeline.run() + + +@common.parametrize( + "test_data", AddConstFullDtypeNone.test_data | AddConstFullDtypeNone.test_data_bool +) +def test_convert_int64_const_ops_to_int32_tosa_INT_full_none(test_data): + input_data, init_data = test_data + input_factory, init_data = test_data + pipeline = TosaPipelineINT[input_t1]( + AddConstFullDtypeNone(*init_data), + input_factory(), + aten_op=[], + exir_op=AddConstFullDtypeNone.exir_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py new file mode 100644 index 0000000..4e15f4a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py @@ -0,0 +1,129 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Dict, Tuple + +import torch +from executorch.backends.arm._passes import ConvertInt64OutputOpsToInt32Pass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineFP + +input_t1 = Tuple[torch.Tensor] # Input x + + +######################################### +## Test [int32 | other types] -> int64 ## +######################################### + + +class CastingToInt64Model(torch.nn.Module): + def __init__(self, target_dtype: torch.dtype) -> None: + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.to(dtype=self.target_dtype) + + +test_data_suite_convert: Dict[str, Callable[[], Tuple[torch.Tensor, torch.dtype]]] = { + "fp32_input": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float32), torch.int64), + "fp16_input": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float16), torch.int64), +} + +test_data_suite_remove: Dict[str, Callable[[], Tuple[torch.Tensor, torch.dtype]]] = { + "int32_input": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.int64, + ), +} + + +TestDataFactory = Callable[[], Tuple[torch.Tensor, torch.dtype]] + + +@common.parametrize("test_data", test_data_suite_convert) +def test_convert_int64_output_ops_to_int32_tosa_FP_convert_casting( + test_data: TestDataFactory, +) -> None: + test_tensor, target_dtype = test_data() + module = CastingToInt64Model(target_dtype) + + pipeline = TosaPipelineFP[input_t1]( + module, + (test_tensor,), + aten_op="torch.ops.aten.to.dtype", + exir_op=[], + transform_passes=[ConvertInt64OutputOpsToInt32Pass()], + ) + pipeline.pop_stage( + "run_method_and_compare_outputs" + ) # As expected: RuntimeError: Int did not match Long + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_remove) +def test_convert_int64_output_ops_to_int32_tosa_FP_remove_casting( + test_data: TestDataFactory, +) -> None: + test_tensor, target_dtype = test_data() + module = CastingToInt64Model(target_dtype) + + pipeline = TosaPipelineFP[input_t1]( + module, + (test_tensor,), + aten_op=[], + exir_op=[], + transform_passes=[ConvertInt64OutputOpsToInt32Pass()], + ) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 0} + ) # Empty graph without nodes + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +##################################################### +## Test arange(dtype=int64) -> arange(dtype=int32) ## +##################################################### + + +class Int64OutputModel(torch.nn.Module): + + def forward(self, x: torch.Tensor) -> torch.Tensor: + # return torch.argmax(x) # RuntimeError: Int did not match Long; But this is expected as we expect _argmax_i32 to generate int32 output + # return (10 * torch.argmax(x) + 10).to(dtype=torch.int32) # [1]. This behavior is deprecated, and in a future PyTorch release outputs will not be resized unless they have zero elements. You can explicitly reuse an out tensor t by resizing it, inplace, to zero elements with t.resize_(0). (function _resize_output_check) + return (10 * torch.argmax(x, dim=-1) + 10) + 1.5 + + def get_inputs(self) -> input_t1: + return ( + torch.randint( + 0, + 10, + (2, 4, 6, 8), + ), + ) + + +def test_convert_int64_output_ops_to_int32_tosa_FP_insert_cast(): + module = Int64OutputModel() + aten_ops_checks = [ + "torch.ops.aten.argmax.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.add.Tensor", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + module.get_inputs(), + aten_op=aten_ops_checks, + exir_op=exir_ops_checks, + transform_passes=[ConvertInt64OutputOpsToInt32Pass()], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py new file mode 100644 index 0000000..8478cff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py @@ -0,0 +1,100 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm._passes import ConvertPermuteSingletonToViewPass +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] + + +class PermuteSingletonAxesModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.permute(0, 2, 3, 1) + + @staticmethod + def input() -> input_t: + return (torch.randn(2, 1, 3, 4),) + + +def test_convert_permute_singleton_to_view_tosa_FP_applies(): + module = PermuteSingletonAxesModule() + pipeline = PassPipeline[input_t]( + module, + PermuteSingletonAxesModule.input(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default", + ], + pass_list=[ConvertPermuteSingletonToViewPass], + ) + pipeline.run() + + +class PermuteNonSingletonModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.permute(0, 2, 1) + + @staticmethod + def input() -> input_t: + return (torch.randn(2, 3, 4),) + + +def test_convert_permute_singleton_to_view_tosa_FP_skip_non_singleton(): + module = PermuteNonSingletonModule() + pipeline = PassPipeline[input_t]( + module, + PermuteNonSingletonModule.input(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ], + pass_list=[ConvertPermuteSingletonToViewPass], + ) + pipeline.run() + + +class PermuteSameSizedNonSingletonModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.permute(2, 1, 0) + + @staticmethod + def input() -> input_t: + return (torch.randn(2, 1, 2),) + + +def test_convert_permute_singleton_to_view_tosa_FP_skip_same_size_non_singleton(): + module = PermuteSameSizedNonSingletonModule() + pipeline = PassPipeline[input_t]( + module, + PermuteSameSizedNonSingletonModule.input(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ], + pass_list=[ConvertPermuteSingletonToViewPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_split_to_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_split_to_slice.py new file mode 100644 index 0000000..ee70b7b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_split_to_slice.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.convert_split_to_slice import ( + ConvertSplitToSlicePass, +) + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class Split(torch.nn.Module): + """ + Basic split model using torch.split function + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, ...]: + return torch.split(x, 2) + + +class SplitTensor(torch.nn.Module): + """ + Basic split model using torch.Tensor.split function + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, ...]: + return x.split(2) + + +modules: Dict[str, ModuleWithInputs] = { + "split_basic": Split(), + "split_tensor": SplitTensor(), +} + + +@common.parametrize("module", modules) +def test_convert_split_to_slice_tosa_INT(module: ModuleWithInputs) -> None: + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor" + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor": 5, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default" + ], + pass_list=[ConvertSplitToSlicePass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_to_clamp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_to_clamp.py new file mode 100644 index 0000000..24f575b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_convert_to_clamp.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes.convert_to_clamp_pass import ConvertToClampPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class HardTanh(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = {"rand": (torch.rand(1, 64, 64, 3),)} + + def __init__(self): + super().__init__() + + self.hardtanh = torch.nn.Hardtanh() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.hardtanh(x) + + +class ReLU(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = {"rand": (torch.rand(1, 64, 64, 3),)} + + def __init__(self): + super().__init__() + + self.relu = torch.nn.ReLU() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.relu(x) + + +""" +Tests the ConvertToClampPass which converts hardtanh.default and relu.default to clamp.default +""" + + +@common.parametrize("test_data", HardTanh.test_data) +def test_convert_to_clamp_tosa_FP_hardtahn(test_data: input_t) -> None: + module = HardTanh() + op_checks_before_pass = { + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + } + op_checks_after_pass = { + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + } + op_checks_not_after_pass = [ + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + ] + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass=op_checks_before_pass, + ops_after_pass=op_checks_after_pass, + ops_not_after_pass=op_checks_not_after_pass, + pass_list=[ConvertToClampPass], + ) + pipeline.run() + + +@common.parametrize("test_data", ReLU.test_data) +def test_convert_to_clamp_tosa_FP_relu(test_data: input_t) -> None: + module = ReLU() + op_checks_before_pass = { + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + } + op_checks_after_pass = { + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + } + op_checks_not_after_pass = [ + "executorch_exir_dialects_edge__ops_aten_relu_default", + ] + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass=op_checks_before_pass, + ops_after_pass=op_checks_after_pass, + ops_not_after_pass=op_checks_not_after_pass, + pass_list=[ConvertToClampPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py new file mode 100644 index 0000000..093b563 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.decompose_avg_pool2d_pass import ( + DecomposeAvgPool2dPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class AvgPool2dWithStride(torch.nn.Module): + """ + avg_pool2d model with explicit stride parameter + """ + + def get_inputs(self) -> input_t: + return (torch.rand(1, 3, 8, 8),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.avg_pool2d(x, kernel_size=2, stride=2) + + +class AvgPool2dWithoutStride(torch.nn.Module): + """ + avg_pool2d model without stride parameter (should default to kernel_size) + """ + + def get_inputs(self) -> input_t: + return (torch.rand(1, 3, 8, 8),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.avg_pool2d(x, kernel_size=3) + + +class AvgPool2dListKernel(torch.nn.Module): + """ + avg_pool2d model with list kernel_size and no stride + """ + + def get_inputs(self) -> input_t: + return (torch.rand(1, 3, 8, 8),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.avg_pool2d(x, kernel_size=[2, 3]) + + +modules: Dict[str, ModuleWithInputs] = { + "avg_pool2d_with_stride": AvgPool2dWithStride(), + "avg_pool2d_without_stride": AvgPool2dWithoutStride(), + "avg_pool2d_list_kernel": AvgPool2dListKernel(), +} + + +@common.parametrize("module", modules) +def test_decompose_avg_pool2d_tosa_FP(module: ModuleWithInputs) -> None: + """Test that DecomposeAvgPool2d pass works correctly with and without stride parameters.""" + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1, + }, + ops_after_pass={ + # After decomposition, we should still see avg_pool2d (transformed) + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1, + }, + pass_list=[DecomposeAvgPool2dPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py new file mode 100644 index 0000000..8dec840 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch + +from executorch.backends.arm._passes.decompose_cosine_similarity_pass import ( + DecomposeCosineSimilarityPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class CosineSimilarityModel(torch.nn.Module): + def get_inputs(self) -> input_t: + return (torch.rand(2, 3, 4), torch.rand(2, 3, 4)) + + def forward(self, x1: torch.Tensor, x2: torch.Tensor) -> torch.Tensor: + return torch.cosine_similarity(x1, x2, dim=1, eps=1e-6) + + +modules: Dict[str, ModuleWithInputs] = {"cosine_basic": CosineSimilarityModel()} + + +@common.parametrize("module", modules) +def test_decompose_cosine_similarity_tosa_INT(module: ModuleWithInputs) -> None: + + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 5, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 3, + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 2, + # TODO(masnesral): uncomment after https://github.com/pytorch/pytorch/pull/144765 + # "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 2, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + } + + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + ops_before_pass=None, + ops_not_before_pass=None, + ops_after_pass=ops_after_pass, + ops_not_after_pass=None, + pass_list=[DecomposeCosineSimilarityPass], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_div_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_div_pass.py new file mode 100644 index 0000000..3d6293b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_div_pass.py @@ -0,0 +1,70 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class Div(torch.nn.Module): + """ + Basic div model using torch.div + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.div(x, 2) + + +class DivTensor(torch.nn.Module): + """ + Basic div model using torch.Tensor.div + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.div(2) + + +modules: Dict[str, ModuleWithInputs] = {"div_basic": Div(), "div_tensor": DivTensor()} + + +@common.parametrize("module", modules) +def test_decompose_div_tosa_FP(module: ModuleWithInputs) -> None: + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_div_Tensor": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten_div_Tensor"], + pass_list=[DecomposeDivPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_int_pow_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_int_pow_pass.py new file mode 100644 index 0000000..e12fc21 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_int_pow_pass.py @@ -0,0 +1,80 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes import DecomposeIntPowPass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Inputs to the module + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +TestParam = Tuple[ModuleWithInputs, int] + + +class Square(torch.nn.Module): + """ + Basic squaring + """ + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.square() + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +class Pow(torch.nn.Module): + """ + Basic squaring + """ + + def __init__(self, exponent: int) -> None: + super().__init__() + self.exponent = exponent + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.pow(self.exponent) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +test_data: Dict[str, TestParam] = { + "square": (Square(), 1), + "pow_2": (Pow(2), 1), + "pow_3": (Pow(3), 2), + "pow_0": (Pow(0), 0), + "pow_neg_2": (Pow(-2), 1), +} + + +@common.parametrize("data", test_data) +def test_decompose_int_pow_tosa_FP(data: TestParam) -> None: + module_with_inputs, nbr_muls = data + module = cast(torch.nn.Module, module_with_inputs) + pipeline = PassPipeline[input_t]( + module, + module_with_inputs.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 1, + }, + ops_not_before_pass=[], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": nbr_muls, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_pow_Tensor_Scalar"], + pass_list=[DecomposeIntPowPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_layernorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_layernorm_pass.py new file mode 100644 index 0000000..018d108 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_layernorm_pass.py @@ -0,0 +1,69 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.decompose_layernorm_pass import ( + DecomposeLayerNormPass, +) + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class LayerNorm(torch.nn.Module): + """ + Basic layer_norm model using torch.nn.layer_norm layer + """ + + def __init__(self): + super(LayerNorm, self).__init__() + self.layer_norm = torch.nn.LayerNorm(10) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.layer_norm(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + +def test_decompose_layer_norm_tosa_FP(): + module = LayerNorm() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_native_layer_norm_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_rsqrt_default", + "executorch_exir_dialects_edge__ops_aten_var_correction", + "executorch_exir_dialects_edge__ops_aten_sub_Tensor", + "executorch_exir_dialects_edge__ops_aten_mean_dim", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_rsqrt_default": 1, + "executorch_exir_dialects_edge__ops_aten_var_correction": 1, + "executorch_exir_dialects_edge__ops_aten_sub_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_expand_copy_default" + ], + pass_list=[DecomposeLayerNormPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py new file mode 100644 index 0000000..73b9008 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch + +from executorch.backends.arm._passes.decompose_linalg_vector_norm_pass import ( + DecomposeLinalgVectorNormPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] + + +class ModuleWithInputs(Protocol): + ord: float | None + + def get_inputs(self) -> input_t: ... + + +class VectorNormModel(torch.nn.Module): + """ + A test module with torch.linalg.vector_norm. + https://pytorch.org/docs/stable/generated/torch.linalg.vector_norm.html + + We support only order 1 or 2. + """ + + def __init__( + self, ord: float | None = None, dim=None, keepdim: bool = False + ) -> None: + super().__init__() + self.ord = ord + self.dim = dim + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + if self.ord is None and self.dim is None: + return torch.linalg.vector_norm(x, keepdim=self.keepdim) + elif self.ord is None: + return torch.linalg.vector_norm(x, dim=self.dim, keepdim=self.keepdim) + elif self.dim is None: + return torch.linalg.vector_norm(x, ord=self.ord, keepdim=self.keepdim) + else: + return torch.linalg.vector_norm( + x, ord=self.ord, dim=self.dim, keepdim=self.keepdim + ) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +modules = { + # Default uses p=2 (l2 vector norm) + "default_p2": VectorNormModel(dim=1), + # p = 1: L1 norm over all elements + "p1": VectorNormModel(ord=1, dim=1), +} + + +@common.parametrize("module", modules) +def test_decompose_linalg_vector_norm_tosa_INT(module: ModuleWithInputs) -> None: + """ + This test creates a PassPipeline that applies the DecomposeLinalgVectorNormPass. + The expected primitive ops vary depending on the norm order: + - p == 1: should decompose to ABS and SUM. + - p == 2 (default): should decompose to MUL, SUM, and SQRT. + - Other p: should decompose to ABS, two instances of POW, and SUM. + """ + ord_val = module.ord if module.ord is not None else 2.0 + + ops_after_pass: Dict[str, int] + if ord_val == 1: + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_abs_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + } + elif ord_val == 2: + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 2, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + } + else: + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_abs_default": 1, + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 2, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + } + + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + # The op is decomposed in legalization aten -> edge, so we are not able to check ops before + ops_before_pass=None, + ops_not_before_pass=None, + ops_after_pass=ops_after_pass, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_linarg_vector_norm_default", + ], + pass_list=[DecomposeLinalgVectorNormPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_meandim_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_meandim_pass.py new file mode 100644 index 0000000..d696485 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_meandim_pass.py @@ -0,0 +1,137 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithMeanAttrs(Protocol): + ops_after_pass: Dict[str, int] + ops_not_after_pass: list[str] + u55_ops_after_pass: Dict[str, int] + u55_ops_not_after_pass: list[str] + + def get_inputs(self) -> input_t: ... + + +class MeanDim(torch.nn.Module): + """ + Basic mean model using torch.mean with keepdim = True + """ + + ops_after_pass = u55_ops_after_pass = { + "torch.ops.aten.sum.dim_IntList": 2, + "torch.ops.aten.mul.Tensor": 1, + } + + ops_not_after_pass = u55_ops_not_after_pass = [ + "torch.ops.aten.reshape.default", + "torch.ops.aten.avg_pool2d.default", + "torch.ops.aten.mean.dim", + ] + + def __init__(self): + super(MeanDim, self).__init__() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.mean(x, (0, 1), True) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4, 4, 4),) + + +class MeanDimTensor(torch.nn.Module): + """ + Basic mean model using torch.Tensor.mean with keepdim = False + """ + + ops_after_pass = { + "torch.ops.aten.sum.dim_IntList": 2, + "torch.ops.aten.mul.Tensor": 1, + "torch.ops.aten.avg_pool2d.default": 1, + "torch.ops.aten.reshape.default": 1, + } + + ops_not_after_pass = [ + "torch.ops.aten.mean.dim", + ] + + u55_ops_after_pass = { + "torch.ops.aten.sum.dim_IntList": 2, + "torch.ops.aten.mul.Tensor": 1, + "torch.ops.aten.reshape.default": 1, + } + + u55_ops_not_after_pass = [ + "torch.ops.aten.avg_pool2d.default", + "torch.ops.aten.mean.dim", + ] + + def __init__(self): + super(MeanDimTensor, self).__init__() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.mean((0, 2), False) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4, 4, 4),) + + +modules: Dict[str, ModuleWithMeanAttrs] = { + "meandim_basic": MeanDim(), + "meandim_tensor": MeanDimTensor(), +} + + +@common.parametrize("module", modules) +def test_decompose_mean_dim_tosa_INT(module: ModuleWithMeanAttrs) -> None: + # Decompose meandim_pass requires initiating the pas with args, which is not supported + # by RunPasses in the arm_tester -> PassPipeline cannot be used. + nn_module = cast(torch.nn.Module, module) + pipeline = TosaPipelineINT[input_t](nn_module, module.get_inputs(), []) + pipeline.pop_stage("check_not.exir") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("to_executorch") + pipeline.pop_stage("check.aten") + pipeline.add_stage_after("quantize", pipeline.tester.check, module.ops_after_pass) + pipeline.add_stage_after( + "quantize", pipeline.tester.check_not, module.ops_not_after_pass + ) + + pipeline.dump_artifact("quantize") + pipeline.run() + + +@common.parametrize("module", modules) +def test_decompose_mean_dim_u55_INT(module: ModuleWithMeanAttrs) -> None: + # Decompose meandim_pass requires initiating the pas with args, which is not supported + # by RunPasses in the arm_tester -> PassPipeline cannot be used. + nn_module = cast(torch.nn.Module, module) + pipeline = EthosU55PipelineINT[input_t]( + nn_module, module.get_inputs(), [], run_on_fvp=False + ) + pipeline.pop_stage("check_not.exir") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("to_executorch") + pipeline.pop_stage("check.aten") + pipeline.add_stage_after( + "quantize", pipeline.tester.check, module.u55_ops_after_pass + ) + pipeline.add_stage_after( + "quantize", pipeline.tester.check_not, module.u55_ops_not_after_pass + ) + + pipeline.dump_artifact("quantize") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_quant_nodes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_quant_nodes.py new file mode 100644 index 0000000..b25dffd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_quant_nodes.py @@ -0,0 +1,44 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import DecomposeQuantNodesPass +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +class Mul(torch.nn.Module): + test_data = { + "randn": (torch.randn(1, 3, 16, 16), torch.randn(1, 3, 16, 16)), + "large_randn": (10e10 * torch.randn(1, 3, 16, 16), torch.randn(1, 3, 16, 16)), + } + + def forward(self, x, y): + return x * y + + +@parametrize("test_data", Mul.test_data) +def test_decompose_quant_nodes_tosa_INT(test_data: Tuple[torch.Tensor]): + module = Mul() + q_dq_ops = { + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + # Verify that DecomposeQuantNodesPass removes quantize/dequantize nodes + # and that the output is correct. + pipeline = PassPipeline( + module, + test_data, + quantize=True, + pass_list=[ + DecomposeQuantNodesPass, + ], + ops_before_pass=q_dq_ops, + ops_not_after_pass=list(q_dq_ops.keys()), + tosa_extensions=["FP"], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_softmax_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_softmax_pass.py new file mode 100644 index 0000000..1212593 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_softmax_pass.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.decompose_softmax_pass import DecomposeSoftmaxPass + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Softmax(torch.nn.Module): + """ + Basic torch.nn.softmax layer model + """ + + def __init__(self): + super(Softmax, self).__init__() + self.softmax = torch.nn.Softmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.softmax(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(2, 3),) + + +class SoftmaxLog(torch.nn.Module): + """ + Basic torch.nn.log_softmax layer model + """ + + def __init__(self): + super(SoftmaxLog, self).__init__() + self.softmax = torch.nn.LogSoftmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.softmax(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(2, 3),) + + +def test_decompose_softmax_tosa_FP_basic(): + module = Softmax() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten__softmax_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList", + "executorch_exir_dialects_edge__ops_aten_exp_default", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_exp_default": 1, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten__softmax_default"], + pass_list=[DecomposeSoftmaxPass], + ) + pipeline.run() + + +def test_decompose_softmax_tosa_FP_log(): + module = SoftmaxLog() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten__log_softmax_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList", + "executorch_exir_dialects_edge__ops_aten_exp_default", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_exp_default": 1, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten__log_softmax_default" + ], + pass_list=[DecomposeSoftmaxPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py new file mode 100644 index 0000000..756685c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.decompose_tosa_unsupported_clamp_pass import ( + DecomposeTOSAUnsupportedClampPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] + + +class ClampInt32(torch.nn.Module): + test_data = {"rand": (torch.randint(-50, 50, (2, 3), dtype=torch.int32),)} + + def forward(self, x: torch.Tensor): + return torch.clamp(x, -10, 5) + + +@common.parametrize("test_data", ClampInt32.test_data) +def test_decompose_tosa_unsupported_clamp_tosa_FP_int32(test_data: input_t): + module = ClampInt32() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_clamp_default", + ], + pass_list=[DecomposeTOSAUnsupportedClampPass], + ) + pipeline.run() + + +class ClampTensorInt32(torch.nn.Module): + test_data = {"rand": (torch.randint(-50, 50, (2, 3), dtype=torch.int32),)} + + def forward(self, x: torch.Tensor): + return torch.clamp(x, torch.tensor(-10), torch.tensor(5)) + + +@common.parametrize("test_data", ClampTensorInt32.test_data) +def test_decompose_tosa_unsupported_clamp_tosa_FP_int32_tensor(test_data: input_t): + module = ClampTensorInt32() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_clamp_Tensor": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_clamp_Tensor", + ], + pass_list=[DecomposeTOSAUnsupportedClampPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_var_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_var_pass.py new file mode 100644 index 0000000..2e31c9d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decompose_var_pass.py @@ -0,0 +1,89 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.decompose_var_pass import DecomposeVarPass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class VarDim(torch.nn.Module): + """ + Basic variance model using torch.Tensor.var function. + """ + + def __init__(self, keepdim): + super(VarDim, self).__init__() + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.var(dim=-1, keepdim=self.keepdim) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +class VarCorrection(torch.nn.Module): + """ + Basic variance model using torch.var function. + """ + + def __init__(self, keepdim): + super(VarCorrection, self).__init__() + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.var(x, -1, keepdim=self.keepdim) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +modules: Dict[str, ModuleWithInputs] = { + "vardim_keepdim": VarDim(True), + "vardim_no_keepdim": VarDim(False), + "varcorrection_keepdim": VarCorrection(True), + "varcorrection_no_keepdim": VarCorrection(False), +} + + +@common.parametrize("module", modules) +def test_decompose_var_tosa_FP(module: ModuleWithInputs) -> None: + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_var_correction": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList", + "executorch_exir_dialects_edge__ops_aten_mean_dim", + "executorch_exir_dialects_edge__ops_aten_sub_Tensor", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 1, + "executorch_exir_dialects_edge__ops_aten_sub_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten_var_correction"], + pass_list=[DecomposeVarPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py new file mode 100644 index 0000000..588428a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py @@ -0,0 +1,85 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Dict, Tuple + +import torch +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class FP32ToINT32Casting(torch.nn.Module): + def __init__(self, target_dtype: torch.dtype) -> None: + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.to(self.target_dtype) + + +test_data_fp32_input: Dict[str, Callable[[], Tuple[torch.Tensor, torch.dtype]]] = { + "fp32_input_rank1": lambda: ( + torch.rand((4), dtype=torch.float32), + torch.int32, + ), + "fp32_input_rank2": lambda: ( + torch.rand((3, 4), dtype=torch.float32), + torch.int32, + ), + "fp32_input_rank3": lambda: ( + torch.rand((2, 3, 4), dtype=torch.float32), + torch.int32, + ), + "fp32_input_rank4": lambda: ( + torch.rand((1, 2, 3, 4), dtype=torch.float32), + torch.int32, + ), +} + + +@common.parametrize("test_data", test_data_fp32_input) +def test_decorate_fp32_to_int32_casting_tosa_FP( + test_data: Callable[[], Tuple[torch.Tensor, torch.dtype]] +) -> None: + test_tensor, target_dtype = test_data() + module = FP32ToINT32Casting(target_dtype) + + pipeline = TosaPipelineFP[input_t1]( + module, + (test_tensor,), + aten_op=[], + exir_op=[], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_fp32_input) +def test_decorate_fp32_to_int32_casting_tosa_INT( + test_data: Callable[[], Tuple[torch.Tensor, torch.dtype]] +) -> None: + """ + Casting operation involving floating-point dtypes will be rejected in INT/INT profile. + Therefore, the DecorateFp32toInt32CastingPass is not required in this profile. + Add a INT test to ensure that such casting is rejected as expected. + """ + test_tensor, target_dtype = test_data() + module = FP32ToINT32Casting(target_dtype) + + pipeline = OpNotSupportedPipeline[input_t1]( + module, + (test_tensor,), + { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1 + }, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fold_qdq_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fold_qdq_pass.py new file mode 100644 index 0000000..d76384a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fold_qdq_pass.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes import FoldAndAnnotateQParamsPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +input_t = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class SimpleQuantizeModel(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = { + "rand": (torch.rand(1, 1280, 7, 7), torch.rand(1, 1280, 7, 7)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return x + torch.maximum((x + x), (y + y)) + + +@common.parametrize("test_data", SimpleQuantizeModel.test_data) +def test_fold_and_annotate_q_params_tosa_INT(test_data: input_t) -> None: + """ + Tests the FoldAndAnnotateQParamsPass which folds dq/q nodes into + the node and stores the quantization parameters in meta. + + Check that the pass runs for add operation and that one q node and one dq node + is removed from the representation. + """ + module = SimpleQuantizeModel() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 7, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 6, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + }, + pass_list=[FoldAndAnnotateQParamsPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_batchnorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_batchnorm_pass.py new file mode 100644 index 0000000..5e461f9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_batchnorm_pass.py @@ -0,0 +1,164 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, ClassVar, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.fuse_batch_norm2d_pass import FuseBatchNorm2dPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithBatchNormAttrs(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + + def get_inputs(self) -> input_t: ... + + +class MergeOneOfTwoBN(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 2, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 0, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 2, + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + if affine: + self.batch_norm2d.weight = torch.nn.Parameter(torch.rand(3)) + self.batch_norm2d.bias = torch.nn.Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> input_t: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.conv2d(x) + x = self.batch_norm2d(x) + x = self.relu6(x) + x = self.batch_norm2d(x) + return x + + +class MergeTwosOfTwoBN(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 2, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 2, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 0, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 2, + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.conv2d2 = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + if affine: + self.batch_norm2d.weight = torch.nn.Parameter(torch.rand(3)) + self.batch_norm2d.bias = torch.nn.Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> input_t: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.conv2d(x) + x = self.batch_norm2d(x) + x = self.relu6(x) + x = self.conv2d2(x) + x = self.batch_norm2d(x) + return x + + +class MergeMultipleUsersBN(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 2, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 3, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 0, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 4, + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.conv2d2 = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + if affine: + self.batch_norm2d.weight = torch.nn.Parameter(torch.rand(3)) + self.batch_norm2d.bias = torch.nn.Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> input_t: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + x1 = self.conv2d(x) + x = self.batch_norm2d( + x1 + ) # Replaces bn wih a new conv since x1 has multiple users + x = self.relu6(x) + y = self.conv2d2(x1) + z = self.conv2d2(x) + a = self.batch_norm2d( + y + ) # Can be fused despite paramters of conv2d2 having multiple users. + + return z, a + + +modules: Dict[str, ModuleWithBatchNormAttrs] = { + "merge_one_of_two_bn_affine": cast(ModuleWithBatchNormAttrs, MergeOneOfTwoBN(True)), + "merge_one_of_two_bn": cast(ModuleWithBatchNormAttrs, MergeOneOfTwoBN(False)), + "merge_two_of_two_bn_affine": cast( + ModuleWithBatchNormAttrs, MergeTwosOfTwoBN(True) + ), + "merge_multiple_users_bn_affine": cast( + ModuleWithBatchNormAttrs, MergeMultipleUsersBN(True) + ), +} + + +@common.parametrize("module", modules) +def test_fuse_batch_norm2d_tosa_FP(module: ModuleWithBatchNormAttrs) -> None: + """Test various cases where the batchnorm should either be fused with a previous + conv, or converted to a new conv.""" + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[FuseBatchNorm2dPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_constant_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_constant_ops_pass.py new file mode 100644 index 0000000..19888f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_constant_ops_pass.py @@ -0,0 +1,177 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import operator +from typing import cast, ClassVar, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x +input_t2 = Tuple[torch.Tensor, torch.Tensor] + + +class ModuleWithFuseAttrs(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + ops_not_after_pass: list[str] + + def get_inputs(self) -> input_t: ... + + +class FuseParameter(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 1, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1 + } + ops_not_after_pass: ClassVar[list[str]] = [ + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_permute_copy_default", + "executorch_exir_dialects_edge__ops_aten_addmm_default", + ] + + def __init__( + self, + in_features: int = 1, + out_features: int = 1, + bias: bool = True, + ): + super().__init__() + self.fc = torch.nn.Linear( + in_features=in_features, + out_features=out_features, + bias=bias, + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.fc(torch.ones(1)) + x + + +class FuseBuffer(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + } + ops_not_after_pass: ClassVar[list[str]] = [ + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default" + ] + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (x + 1) * 2 + + +class FuseLiftedTensor(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_select_copy_int": 1, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1 + } + ops_not_after_pass: ClassVar[list[str]] = [ + "executorch_exir_dialects_edge__ops_aten_select_copy_int" + ] + + def __init__( + self, + ): + super().__init__() + self.lifted_tensor = torch.rand(2) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + sliced = self.lifted_tensor[0] + return operator.add(sliced, x) + + +class CatConst(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + } + ops_not_after_pass: ClassVar[list[str]] = [] + + def __init__(self): + super().__init__() + + def forward(self, a: torch.Tensor, b: torch.Tensor) -> torch.Tensor: + return torch.cat((a, b), dim=0) + + +modules: Dict[str, ModuleWithFuseAttrs] = { + "fuse_parameter": cast(ModuleWithFuseAttrs, FuseParameter()), + "fuse_buffer": cast(ModuleWithFuseAttrs, FuseBuffer()), + "fuse_const_tensor": cast(ModuleWithFuseAttrs, FuseLiftedTensor()), +} + +cat_module: Dict[str, ModuleWithFuseAttrs] = { + "fuse_cat": cast(ModuleWithFuseAttrs, CatConst()), +} + + +@common.parametrize("module", modules) +def test_fuse_constant_args_tosa_FP(module: ModuleWithFuseAttrs) -> None: + pipeline = PassPipeline[input_t]( + module=cast(torch.nn.Module, module), + test_data=(torch.rand(1),), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + ops_not_after_pass=module.ops_not_after_pass, + passes_with_exported_program=[ + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, + ], + ) + pipeline.run() + + +@common.parametrize("module", modules) +def test_fuse_constant_args_tosa_INT(module: ModuleWithFuseAttrs) -> None: + pipeline = PassPipeline[input_t]( + cast(torch.nn.Module, module), + (torch.rand(10, 10),), + quantize=True, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[ + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, + ], + ) + pipeline.run() + + +@common.parametrize("module", cat_module) +def test_fuse_constant_args_tosa_INT_cat(module: ModuleWithFuseAttrs) -> None: + pipeline = PassPipeline[input_t2]( + cast(torch.nn.Module, module), + (torch.rand(3), torch.rand(2)), + quantize=True, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[ + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, + ], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_duplicate_users_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_duplicate_users_pass.py new file mode 100644 index 0000000..d94e01f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_duplicate_users_pass.py @@ -0,0 +1,70 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, Tuple + +import torch +from executorch.backends.arm._passes import FuseDuplicateUsersPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithOps(torch.nn.Module): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + + +class FuseaAvgPool(ModuleWithOps): + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 3, + } + ops_after_pass = {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1} + + def __init__(self): + super().__init__() + self.avg = torch.nn.AvgPool2d(1) + + def forward(self, x): + return self.avg(x) + self.avg(x) + self.avg(x) + + +class FuseAvgPoolChain(ModuleWithOps): + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 6, + } + ops_after_pass = {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 2} + + def __init__(self): + super().__init__() + self.avg = torch.nn.AvgPool2d(1) + + def forward(self, x): + first = self.avg(self.avg(x)) + second = self.avg(self.avg(x)) + third = self.avg(self.avg(x)) + return first + second + third + + +modules: Dict[str, ModuleWithOps] = { + "fuse_avg_pool": FuseaAvgPool(), + "fuse_avg_pool_chain": FuseAvgPoolChain(), +} + + +@common.parametrize("module", modules) +def test_fuse_duplicate_users_tosa_FP(module: ModuleWithOps): + pipeline = PassPipeline[input_t]( + module=module, + test_data=(torch.ones(1, 1, 1, 1),), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + pass_list=[ + FuseDuplicateUsersPass, + ], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py new file mode 100644 index 0000000..b29bb67 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py @@ -0,0 +1,170 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from copy import deepcopy +from typing import Callable, cast, ClassVar, Dict, Protocol, Tuple, TypeVar + +import torch +from executorch.backends.arm._passes.fuse_equal_placeholders_pass import ( + FuseEqualPlaceholdersPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + PassPipeline, + TosaPipelineFP, +) + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithEqualPlaceholderAttrs(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + ops_not_after_pass: list[str] + + def get_inputs(self) -> input_t: ... + + +T = TypeVar("T") +TestDecorator = Callable[[Callable[[T], None]], Callable[[T], None]] + + +def _typed_parametrize(test_data: Dict[str, T]) -> TestDecorator: + return cast(TestDecorator, common.parametrize("module", test_data)) + + +class FuseWeightsConstants(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = {} + ops_after_pass: ClassVar[Dict[str, int]] = {} + ops_not_after_pass: ClassVar[list[str]] = [] + + def __init__( + self, + ): + super().__init__() + self.weights1 = torch.rand(1, 2, 1) + self.weights2 = deepcopy(self.weights1) + self.bias1 = torch.rand(1) + self.bias2 = deepcopy(self.bias1) + self.bias3 = deepcopy(self.bias1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return ( + torch.conv1d(x, self.weights1, self.bias1) + + torch.conv1d(x, self.weights2, self.bias2) + + self.bias3 + ) + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 8),) + + +class FuseWeightsStateDict(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = {} + ops_after_pass: ClassVar[Dict[str, int]] = {} + ops_not_after_pass: ClassVar[list[str]] = [] + + def __init__( + self, + ): + super().__init__() + self.fc1 = torch.nn.Linear(in_features=8, out_features=2, bias=True) + self.fc2 = deepcopy(self.fc1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.fc1(x) + self.fc2(x) + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 8),) + + +class NotFuseTensorWithDifferentType(torch.nn.Module): + + ops_before_pass: ClassVar[Dict[str, int]] = {} + ops_after_pass: ClassVar[Dict[str, int]] = {} + ops_not_after_pass: ClassVar[list[str]] = [] + + def forward(self, x: torch.Tensor, y: torch.Tensor): + """ + Args: + x: A float tensor (dtype=torch.float32) + y: An int tensor (dtype=torch.int32) + """ + a = torch.tensor(1.0, dtype=torch.float32) + b = torch.tensor(1, dtype=torch.int32) + m = x < a + n = y > b + return m, n + + +constants_modules: Dict[str, ModuleWithEqualPlaceholderAttrs] = { + "fuse_constants": cast(ModuleWithEqualPlaceholderAttrs, FuseWeightsConstants()), +} + +parametrize_constants = _typed_parametrize(constants_modules) + + +@parametrize_constants +def test_fuse_equal_placeholders_tosa_FP_constants( + module: ModuleWithEqualPlaceholderAttrs, +) -> None: + pipeline = PassPipeline[input_t]( + cast(torch.nn.Module, module), + module.get_inputs(), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[FuseEqualPlaceholdersPass], + ) + pipeline.run() + + # Check that weights and bias has been merged. + exp_program = pipeline.tester.get_artifact().exported_program() + constant_keys = list(exp_program.constants.keys()) + assert len(constant_keys) == 2, "FuseEqualPlaceholders constants failed" + assert "_common" in constant_keys[0], "FuseEqualPlaceholders constants failed" + assert "_common" in constant_keys[1], "FuseEqualPlaceholders constants failed" + + +def test_fuse_equal_placeholders_tosa_FP_state_dict() -> None: + module = FuseWeightsStateDict() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[FuseEqualPlaceholdersPass], + ) + pipeline.run() + + # Check that weights and bias has been merged. + exp_program = pipeline.tester.get_artifact().exported_program() + state_dict_keys = list(exp_program.state_dict.keys()) + assert len(state_dict_keys) == 2, "FuseEqualPlaceholders state_dict failed" + assert "_common" in state_dict_keys[0], "FuseEqualPlaceholders state_dict failed" + assert "_common" in state_dict_keys[1], "FuseEqualPlaceholders state_dict failed" + + +def test_fuse_equal_placeholders_tosa_FP_no_fuse_type_diff(): + module = NotFuseTensorWithDifferentType() + data = ( + torch.rand( + 1, + ), + torch.randint( + 0, + 10, + (1,), + dtype=torch.int, + ), + ) + pipeline = TosaPipelineFP[input_t]( + module, + data, + aten_op=[], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_view_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_view_copy.py new file mode 100644 index 0000000..6901ca9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_fuse_view_copy.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline +from executorch.backends.transforms.fuse_view_copy import FuseViewCopyTransform + + +class FuseSequentialViews(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x.view((1, 2, 3, 4)).view((2, 3, 4, 1)).view((2, 3, 4)) + + data = (torch.randn(2, 3, 1, 4),) + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 3, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 1, + } + + +class FuseSequentialWithNoopsViews(torch.nn.Module): + def forward(self, x: torch.Tensor): + return ( + x.view((1, 2, 3, 4)) + .clone() + .view((2, 3, 4, 1)) + .to(dtype=torch.int32) + .view((2, 3, 4)) + .abs() + .reciprocal() + .sqrt() + .view((12, 2)) + ) + + data = (torch.randn(2, 3, 1, 4),) + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 4, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 1, + } + + +class DontFuseBranchingViews(torch.nn.Module): + def forward(self, x: torch.Tensor): + x = x.view((1, 2, 3, 4)) + x1 = x.abs().view((2, 3, 4, 1)) + x2 = x.ceil().view((2, 3, 4, 1)) + return x1 + x2 + + data = (torch.randn(2, 3, 1, 4),) + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 3, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 3, + } + + +tests = { + "fuse_sequential_views": FuseSequentialViews(), + "fuse_sequential_with_noops_views": FuseSequentialWithNoopsViews(), + "dont_fuse_branching_views": DontFuseBranchingViews(), +} + + +@common.parametrize("model", tests) +def test_fuse_view_copy_transform_tosa_FP(model): + pipeline = PassPipeline( + model, + model.data, + quantize=False, + ops_before_pass=model.ops_before_pass, + ops_after_pass=model.ops_after_pass, + pass_list=[FuseViewCopyTransform], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py new file mode 100644 index 0000000..8cae159 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import InsertInt32CastsAfterInt64PlaceholdersPass + +from executorch.backends.arm.test.tester.test_pipeline import ( + PassPipeline, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor, torch.Tensor] # weights, indices +input_t3 = Tuple[torch.Tensor, torch.LongTensor, torch.Tensor] + + +class Int64InputModel(torch.nn.Module): + + def forward(self, weights: torch.Tensor, indices: torch.Tensor): + return torch.embedding(weights, indices) + + def get_inputs(self) -> input_t: + return ( + torch.randn(9, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int64), + ) + + +def test_insert_int32_casts_after_int64_placeholders_tosa_FP(): + module = Int64InputModel() + op_checks_before = { + "executorch_exir_dialects_edge__ops_aten_embedding_default": 1, + } + op_checks_after = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_embedding_default": 1, + } + + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + ops_before_pass=op_checks_before, + ops_after_pass=op_checks_after, + pass_list=[InsertInt32CastsAfterInt64PlaceholdersPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() + + +class UpcastToInt64ForIndexCopyInplaceModel(torch.nn.Module): + aten_op = "torch.ops.aten.index_copy_.default" + + def forward(self, x: torch.Tensor, index: torch.LongTensor, y: torch.Tensor): + return x.index_copy_(0, index, y) + + def get_inputs(self) -> input_t3: + return ( + torch.zeros(5, 3), + torch.LongTensor([0, 4, 2]), + torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=torch.float), + ) + + +def test_insert_int32_casts_after_int64_placeholders_tosa_INT_upcast_for_index_copy_inplace(): + module = UpcastToInt64ForIndexCopyInplaceModel() + pipeline = TosaPipelineINT[input_t3]( + module, + module.get_inputs(), + aten_op=module.aten_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 0, + }, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +class UpcastToInt64ForIndexCopyModel(torch.nn.Module): + aten_op = "torch.ops.aten.index_copy.default" + + def forward(self, x: torch.Tensor, index: torch.LongTensor, y: torch.Tensor): + return x.index_copy(0, index, y) + + def get_inputs(self) -> input_t3: + return ( + torch.zeros(5, 3), + torch.LongTensor([0, 4, 2]), + torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=torch.float), + ) + + +def test_insert_int32_casts_after_int64_placeholders_tosa_INT_upcast_for_index_copy(): + module = UpcastToInt64ForIndexCopyModel() + pipeline = TosaPipelineINT[input_t3]( + module, + module.get_inputs(), + aten_op=module.aten_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 0, + }, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_rescale_i32_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_rescale_i32_pass.py new file mode 100644 index 0000000..e685da1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_rescale_i32_pass.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import ( + FoldAndAnnotateQParamsPass, + InsertRescaleInt32Pass, +) +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +class MultipleOpsModel(torch.nn.Module): + """A module containing ops that require INT32 inputs/outputs.""" + + input_t = Tuple[torch.Tensor, torch.Tensor] + + def forward(self, x, y): + a = x - y + b = x * a + c = torch.maximum(a, b) + d = torch.abs(b) + e = c + d + f = e > a + return f + + def get_inputs(self, dtype) -> input_t: + if dtype == torch.float32: + return (torch.rand(1, 3, 5, 6), torch.rand(1, 3, 5, 6)) + elif dtype == torch.int32: + return ( + torch.randint(3, 5, (3,), dtype=torch.int32), + torch.randint(3, 5, (3,), dtype=torch.int32), + ) + else: + raise ValueError("Not a valid input dtype for model") + + def get_num_expected_rescales(self): + # "number of op nodes with i8 output" + "number of i8 node inputs" + return 5 + 11 + + +class SumModel(torch.nn.Module): + input_t = Tuple[torch.Tensor] + + def forward(self, x): + a = torch.sum(x, 2, keepdim=True) # (1, 2, 1, 4) + b = torch.sum(a, [1, 3], keepdim=True) # (1, 1, 1, 1) + c = torch.sum(b, [0, 2], keepdim=False) # (1, 1) + return c + + def get_inputs(self, dtype) -> input_t: + if dtype == torch.float32: + return (torch.rand(1, 2, 3, 4),) + elif dtype == torch.int32: + return (torch.randint(0, 10, (1, 2, 3, 4), dtype=torch.int32),) + else: + raise ValueError("Not a valid input dtype for model") + + def get_num_expected_rescales(self): + # Two RESCALE nodes per SUM node + return 6 + + +def _test_model_with_f32_data(model): + ops_not_before = {"executorch_exir_dialects_backend__ops_tosa_RESCALE_default"} + ops_after = { + "executorch_exir_dialects_backend__ops_tosa_RESCALE_default": model.get_num_expected_rescales(), + } + pipeline = PassPipeline[model.input_t]( + model, + model.get_inputs(torch.float32), + quantize=True, + ops_not_before_pass=ops_not_before, + ops_after_pass=ops_after, + pass_list=[FoldAndAnnotateQParamsPass, InsertRescaleInt32Pass], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +def test_insert_rescale_int32_tosa_INT_sum(): + _test_model_with_f32_data(SumModel()) + + +def test_insert_rescale_int32_tosa_INT_multiple_ops(): + _test_model_with_f32_data(MultipleOpsModel()) + + +def test_insert_rescale_int32_tosa_FP_dont_insert_rescales(): + module = MultipleOpsModel() + input_t = Tuple[torch.Tensor, torch.Tensor] + ops_not_before = {"executorch_exir_dialects_backend__ops_tosa_RESCALE_default"} + # All inputs are already i32. Rescales should not be added. + ops_not_after = {"executorch_exir_dialects_backend__ops_tosa_RESCALE_default"} + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(torch.int32), + ops_not_before_pass=ops_not_before, + ops_not_after_pass=ops_not_after, + pass_list=[FoldAndAnnotateQParamsPass, InsertRescaleInt32Pass], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_table_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_table_ops_pass.py new file mode 100644 index 0000000..693bd19 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_insert_table_ops_pass.py @@ -0,0 +1,47 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + FoldAndAnnotateQParamsPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Sigmoid(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = { + "rand": (torch.rand(4),), + } + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.sigmoid() + + +@common.parametrize("test_data", Sigmoid.test_data) +def test_insert_table_ops_tosa_INT(test_data: input_t) -> None: + module = Sigmoid() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=True, + ops_before_pass={"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 1, + "backend__ops_tosa_TABLE_default": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten_sigmoid_default"], + pass_list=[FoldAndAnnotateQParamsPass], + passes_with_exported_program=[InsertTableOpsPass], + ) + pipeline.pop_stage(-1) # Do not compare output + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_int32_cast_embedding_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_int32_cast_embedding_pass.py new file mode 100644 index 0000000..dbe4d1b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_int32_cast_embedding_pass.py @@ -0,0 +1,46 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import DecomposeEmbeddingPass + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class Int32Embedding(torch.nn.Module): + + def forward(self, weights: torch.Tensor, indices: torch.Tensor) -> torch.Tensor: + return torch.embedding(weights, indices) + + def get_inputs(self) -> input_t: + return ( + torch.randn(9, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32), + ) + + +def test_decompose_embedding_tosa_FP_int32(): + module = Int32Embedding() + op_checks_before = { + "executorch_exir_dialects_edge__ops_aten_embedding_default": 1, + } + op_checks_after = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 2, + "executorch_exir_dialects_edge__ops_aten_index_select": 1, + } + + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + ops_before_pass=op_checks_before, + ops_after_pass=op_checks_after, + pass_list=[DecomposeEmbeddingPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_ioquantization_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_ioquantization_pass.py new file mode 100644 index 0000000..3fe89a7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_ioquantization_pass.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import EthosU55PipelineINT +from executorch.exir.passes.quantize_io_pass import QuantizeInputs, QuantizeOutputs + + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class SimpleModel(torch.nn.Module): + test_data = { + "rand_rand": (torch.rand(1, 2, 2, 1), torch.rand(1, 2, 2, 1)), + } + + def forward(self, x, y): + return x + y + + +@common.parametrize("test_data", SimpleModel.test_data) +def test_quantize_io_u55_INT(test_data: input_t): + """ + Test the executorch/exir/passes/quantize_io_pass pass works(meaning we don't get Q/DQ nodes) on a simple model + """ + model = SimpleModel() + pipeline = EthosU55PipelineINT( + model, + test_data, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=False, + run_on_fvp=False, + ) + pipeline.pop_stage(-1) + pipeline.run() + edge = pipeline.tester.get_artifact() + edge.transform(passes=[QuantizeInputs(edge, [0, 1]), QuantizeOutputs(edge, [0])]) + pipeline.tester.check_not(["edge__ops_quantized_decomposed_quantize_per_tensor"]) + pipeline.tester.check_not(["edge__ops_quantized_decomposed_dequantize_per_tensor"]) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_promote_bool_operands_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_promote_bool_operands_pass.py new file mode 100644 index 0000000..61be6d4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_promote_bool_operands_pass.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes import PromoteBoolOperandsPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline +from executorch.backends.test.harness.stages import StageType +from executorch.exir.dialects._ops import ops as exir_ops + +tensor_pair_t = Tuple[torch.Tensor, torch.Tensor] + + +def _collect_cast_dtypes(pipeline: PassPipeline[tensor_pair_t]) -> list[torch.dtype]: + exported_program = pipeline.tester.get_artifact( + StageType.RUN_PASSES + ).exported_program() + graph_module = exported_program.graph_module + cast_dtypes: list[torch.dtype] = [] + for node in graph_module.graph.nodes: + if ( + node.op == "call_function" + and node.target == exir_ops.edge.dim_order_ops._to_dim_order_copy.default + and "dtype" in node.kwargs + ): + cast_dtypes.append(node.kwargs["dtype"]) + return cast_dtypes + + +class BoolBitwiseAndModule(torch.nn.Module): + test_data: ClassVar[Dict[str, tensor_pair_t]] = { + "bool_tensors": ( + torch.tensor([[True, False], [False, True]], dtype=torch.bool), + torch.tensor([[False, True], [True, False]], dtype=torch.bool), + ) + } + + def forward(self, lhs: torch.Tensor, rhs: torch.Tensor) -> torch.Tensor: + return torch.bitwise_and(lhs, rhs) + + +class MixedMulModule(torch.nn.Module): + test_data: ClassVar[Dict[str, tensor_pair_t]] = { + "mixed_tensors": ( + torch.tensor([True, False, True, False], dtype=torch.bool), + torch.tensor([1, 2, 3, 4], dtype=torch.int32), + ) + } + + def forward(self, lhs: torch.Tensor, rhs: torch.Tensor) -> torch.Tensor: + return torch.mul(lhs, rhs) + + +@common.parametrize("test_data", BoolBitwiseAndModule.test_data) +def test_promote_bool_operands_tosa_FP_all_bool(test_data: tensor_pair_t) -> None: + module = BoolBitwiseAndModule() + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor": 1, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 3, + } + pipeline = PassPipeline[tensor_pair_t]( + module, + test_data, + quantize=False, + ops_before_pass=ops_before_pass, + ops_after_pass=ops_after_pass, + pass_list=[PromoteBoolOperandsPass], + ) + pipeline.run() + cast_dtypes = _collect_cast_dtypes(pipeline) + assert cast_dtypes.count(torch.int8) == 2 + assert cast_dtypes.count(torch.bool) == 1 + + +@common.parametrize("test_data", MixedMulModule.test_data) +def test_promote_bool_operands_tosa_FP_mixed_types(test_data: tensor_pair_t) -> None: + module = MixedMulModule() + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + } + pipeline = PassPipeline[tensor_pair_t]( + module, + test_data, + quantize=False, + ops_before_pass=ops_before_pass, + ops_after_pass=ops_after_pass, + pass_list=[PromoteBoolOperandsPass], + ) + pipeline.run() + cast_dtypes = _collect_cast_dtypes(pipeline) + assert cast_dtypes.count(torch.int32) == 1 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_remove_clone_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_remove_clone_pass.py new file mode 100755 index 0000000..c0182b2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_remove_clone_pass.py @@ -0,0 +1,45 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.remove_noop_pass import RemoveNoopPass + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Clone(torch.nn.Module): + """ + Basic remove layer model to test RemoveNoopePass + """ + + def __init__(self): + super(Clone, self).__init__() + + def forward(self, x): + return torch.clone(x) + + def get_inputs(self) -> input_t: + return (torch.rand(3, 1),) + + +def test_remove_noop_tosa_INT_clone(): + module = Clone() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default" + ], + pass_list=[RemoveNoopPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_replace_inf_values_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_replace_inf_values_pass.py new file mode 100644 index 0000000..d079058 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_replace_inf_values_pass.py @@ -0,0 +1,96 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm._passes.replace_inf_and_limit_values_pass import ( + ReplaceInfAndLimitValuesPass, +) + +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from torch import fx + + +class ModuleWithInf(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer( + "mask", torch.tensor([float("inf"), float("-inf")], dtype=torch.float32) + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = x + self.mask # type: ignore[operator] + x = torch.ops.aten.add.Tensor(x, float("-inf")) + x = torch.ops.aten.add.Tensor(x, float("inf")) + return x + + +def _get_add_constants(module_with_infinf: fx.GraphModule) -> list[float]: + """ + Return the scalar literals passed to `aten.add.Tensor`, skipping tensor inputs. + """ + return [ + node.args[1] + for node in module_with_infinf.graph.nodes + if node.op == "call_function" + and node.target == torch.ops.aten.add.Tensor + and len(node.args) > 1 + and not isinstance(node.args[1], fx.Node) + ] + + +def _get_mask_buffer(graph_module: fx.GraphModule) -> torch.Tensor: + """ + Fetch the `mask` buffer tensor from the traced module. + """ + buffers = dict(graph_module.named_buffers()) + assert "mask" in buffers, "Mask buffer not found" + return buffers["mask"] + + +def test_replace_inf_values_pass_clamps_inf_constants(): + """ + Trace a module with infinities, run ReplaceInfAndLimitValuesPass, and expect the buffer and scalar + literals to be clamped to ±255 with no infinities left. + """ + gm = fx.symbolic_trace(ModuleWithInf()) + + result = ReplaceInfAndLimitValuesPass().call(gm) + mask_after_pass = _get_mask_buffer(result.graph_module) + + assert result.modified + expected = torch.tensor([255.0, -255.0], dtype=mask_after_pass.dtype) + assert torch.equal(mask_after_pass, expected) + assert not torch.isinf(mask_after_pass).any() + assert sorted(_get_add_constants(result.graph_module)) == [-255, 255] + + +def test_replace_inf_values_respects_disallowed_nodes(): + """ + When nodes opt out of transforms, running the pass in TFA mode should leave the mask buffer + untouched while still clamping scalar literals to ±255. + """ + gm = fx.symbolic_trace(ModuleWithInf()) + mask_before = _get_mask_buffer(gm).clone() + + for node in gm.graph.nodes: + if node.op != "call_function": + continue + + if any( + isinstance(arg, fx.Node) and arg.op == "get_attr" and arg.target == "mask" + for arg in node.args + ): + node.meta[DISALLOW_TFA_META_KEY] = True + + replace_inf = ReplaceInfAndLimitValuesPass() + replace_inf.is_tfa_pass = True + + result = replace_inf.call(gm) + assert result.modified + + mask_after = _get_mask_buffer(result.graph_module) + assert torch.equal(mask_after, mask_before) + assert torch.isinf(mask_after).tolist() == [True, True] + assert sorted(_get_add_constants(result.graph_module)) == [-255, 255] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rescale_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rescale_pass.py new file mode 100644 index 0000000..7d2e596 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rescale_pass.py @@ -0,0 +1,81 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class RescaleNetwork(torch.nn.Module): + test_data = { + "rand": (torch.rand(5), torch.rand(5)), + "randn": (torch.randn(5, 2), torch.randn(5, 1)), + "ones": (torch.ones(1, 10, 4, 6), torch.ones(1, 10, 4, 6)), + "randn_ones": (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "randn_large": (10000 * torch.randn(1, 1, 4, 4), torch.randn(1, 1, 4, 1)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + a = y.exp() + g = (a + 5).log() + c = a + x + d = c - g + e = c * d + f = e.sigmoid() + + return f + + +@common.parametrize("test_data", RescaleNetwork.test_data) +def test_insert_rescale_tosa_INT(test_data: tuple[torch.Tensor, torch.Tensor]): + """Tests a model with many ops that requires rescales. As more ops are quantized to int32 and + need the InsertRescalesPass, make sure that they play nicely together.""" + module = RescaleNetwork() + pipeline = TosaPipelineINT( + module=module, + test_data=test_data, + aten_op=[], + exir_op=[], + ) + if not conftest.is_option_enabled("tosa_ref_model"): + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize("test_data", RescaleNetwork.test_data) +@common.XfailIfNoCorstone300 +def test_insert_rescale_u55_INT(test_data: input_t): + """Tests a model with many ops that requires rescales. As more ops are quantized to int32 and + need the InsertRescalesPass, make sure that they play nicely together.""" + module = RescaleNetwork() + pipeline = EthosU55PipelineINT( + module=module, + test_data=test_data, + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", RescaleNetwork.test_data) +@common.XfailIfNoCorstone320 +def test_insert_rescale_u85_INT(test_data: input_t): + """Tests a model with many ops that requires rescales. As more ops are quantized to int32 and + need the InsertRescalesPass, make sure that they play nicely together.""" + module = RescaleNetwork() + pipeline = EthosU85PipelineINT( + module=module, + test_data=test_data, + aten_ops=[], + exir_ops=[], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rewrite_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rewrite_conv_pass.py new file mode 100644 index 0000000..d59dbc9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_rewrite_conv_pass.py @@ -0,0 +1,20 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass +from executorch.backends.arm.test.misc.test_dw_convs_with_shared_weights import ( + DWConvsModule, +) +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +def test_rewrite_conv_tosa_FP(): + module = DWConvsModule() + pipeline = PassPipeline( + module, module.get_inputs(), passes_with_exported_program=[RewriteConvPass] + ) + # We can't run TOSA backend dialect operators in eager mode + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_to_tosa_memory_format.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_to_tosa_memory_format.py new file mode 100644 index 0000000..486a906 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_to_tosa_memory_format.py @@ -0,0 +1,213 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, List, Protocol, Tuple + +import torch +from executorch.backends.arm._passes import ( + AnnotateOutputDimOrderPass, + ToTosaMemoryFormatPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + PassPipeline, + TosaPipelineINT, +) +from executorch.backends.transforms.remove_getitem_op import RemoveGetItemPass + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleMetadata(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + ops_not_after_pass: List[str] + + def get_inputs(self) -> input_t: ... + + +class NoNHWC(torch.nn.Module): + """ + Test-module with no ops requiring NHWC mermory format. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 2 + } + ops_not_after_pass: List[str] = [] + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = x + x + return x + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 2, 2),) + + +class ParallelClusters(torch.nn.Module): + """ + Test-module with multiple parallel clusters of nodes requiring different memory formats. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 2 + } + ops_not_after_pass: List[str] = [] + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d( + in_channels=2, + out_channels=2, + kernel_size=1, + bias=True, + ) + self.maxpool = torch.nn.MaxPool2d(1, 1) + self.avgpool = torch.nn.AvgPool2d(1, 1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x1 = self.conv(x) + x2 = self.maxpool(x) + x3 = self.avgpool(x) + x4 = x * x + return x1 + x2 + x3 + x4 + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 2, 2),) + + +class SerialClusters(torch.nn.Module): + """ + Test-module with multiple serial clusters of nodes requring different memory formats. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 4 + } + ops_not_after_pass: List[str] = [] + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d( + in_channels=2, + out_channels=2, + kernel_size=1, + bias=True, + ) + self.fc = torch.nn.Linear( + in_features=2, + out_features=2, + bias=True, + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.conv(x) + x = x * x + x = self.conv(x) + x = x.view((2, 1, 2, 4)) + x = x * 2 + x = x.view((2, 2, 2, 2)) + x = self.conv(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(2, 2, 2, 2),) + + +class Reshapes(torch.nn.Module): + """ + Test-module with different configurations of views requiring different memory formats. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 16 + } + ops_not_after_pass: List[str] = [] + + def __init__(self): + super().__init__() + self.maxpool = torch.nn.MaxPool2d(1, 1) # Use maxpool to force NHWC format + + def forward(self, x: torch.Tensor) -> torch.Tensor: + + x = self.maxpool(x) + x = x.view((2, 2, 4, 16, 1)) # N-C-HW-invariant intact, no transposes needed + x = x * 2 # Add op to avoid views merging + x = x.view((4, 4, 4, 4)) + x = x / 2 # Add op to avoid views merging + x = self.maxpool(x) + + x = x.view((256)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((16, 16)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((16, 4, 4)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((2, 4, 4, 8)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((8, 1, 2, 4, 4)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = self.maxpool(x) + + return x + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4, 4, 4),) + + +modules: Dict[str, ModuleMetadata] = { + "no_nhwc": NoNHWC(), + "parallel_clusters": ParallelClusters(), + "serial_clusters": SerialClusters(), + "reshapes": Reshapes(), +} + + +@common.parametrize("module", modules) +def test_to_tosa_memory_format_tosa_INT(module: ModuleMetadata) -> None: + # We cannot check op counts after a specific pass with the full pipeline + module_nn = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + module_nn, + module.get_inputs(), + ops_after_pass=module.ops_after_pass, + ops_not_after_pass=module.ops_not_after_pass, + pass_list=[RemoveGetItemPass, AnnotateOutputDimOrderPass], + passes_with_exported_program=[ToTosaMemoryFormatPass], + ) + pipeline.pop_stage( + "run_method_and_compare_outputs" + ) # Eager execution is not possible after introducing tosa.TRANSPOSE + pipeline.run() + + +@common.parametrize("module", modules) +def test_to_tosa_memory_format_tosa_INT_functional(module: ModuleMetadata) -> None: + # Also run the actual pass pipeline to ensure functional correctness. + module_nn = cast(torch.nn.Module, module) + pipeline = TosaPipelineINT[input_t](module_nn, module.get_inputs(), []) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py new file mode 100644 index 0000000..f6ff8b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py @@ -0,0 +1,62 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Tuple + +import torch +from executorch.backends.arm._passes import UnsqueezeBeforeRepeatPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +pipeline_input_t = Tuple[torch.Tensor, ...] +test_case_t = Tuple[ + pipeline_input_t, + Dict[str, int], + List[str], +] + + +class Repeat(torch.nn.Module): + """ + Basic repeat model. + """ + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.repeat(2, 2, 2, 2) + + test_data: Dict[str, test_case_t] = { + "insert_view": ( + (torch.rand((2, 3, 4)),), + {"aten_repeat_default": 3, "aten_view_copy_default": 4}, + [], + ), + "dont_insert_view": ( + (torch.rand((2, 3, 4, 1)),), + {"aten_repeat_default": 3}, + ["aten_view_copy_default"], + ), + } + + +@common.parametrize("test_data", Repeat.test_data) +def test_unsqueeze_before_repeat_tosa_FP(test_data: test_case_t): + """ + When rank(input) != number of repeated dimensions (=4 in Repeat module), + insert view. + """ + module = Repeat() + data, ops_after_pass, ops_not_after_pass = test_data + pipeline = PassPipeline[pipeline_input_t]( + module, + data, + quantize=False, + ops_before_pass={"aten_repeat_default": 3}, + ops_not_before_pass=["aten_view_copy_default"], + ops_after_pass=ops_after_pass, + ops_not_after_pass=ops_not_after_pass, + pass_list=[UnsqueezeBeforeRepeatPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/pytest.ini b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/pytest.ini new file mode 100644 index 0000000..8d25e4c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +addopts = --strict-markers +markers = + slow: Tests that take long time + tosa_ref_model: Tests that use TOSA reference model # Temporary! diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_conv_relu_fusing.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_conv_relu_fusing.py new file mode 100644 index 0000000..83179c1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_conv_relu_fusing.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.quantizer.quantization_config import ( + QuantizationConfig, + QuantizationSpec, +) +from executorch.backends.arm.test.tester.test_pipeline import QuantizationPipeline +from executorch.backends.arm.tosa import TosaSpecification + + +def get_symmetric_a8w8_quantization_config(): + affine_quant_config = get_symmetric_quantization_config() + output_activation = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=affine_quant_config.get_output_act_qspec().observer_or_fake_quant_ctr, + quant_min=-127, + quant_max=127, + qscheme=torch.per_tensor_symmetric, + ch_axis=None, + is_dynamic=False, + ) + input_activation = output_activation + symmetric_quant_config = QuantizationConfig( + input_activation=input_activation, + output_activation=output_activation, + weight=affine_quant_config.get_weight_qspec(), + bias=None, + ) + return symmetric_quant_config + + +class ConvBNRelu(torch.nn.Module): + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d( + in_channels=3, + out_channels=4, + kernel_size=2, + ) + self.bn = torch.nn.BatchNorm2d(num_features=4) + self.relu = torch.nn.ReLU() + + def forward(self, x): + conv = self.conv(x) + bn = self.bn(conv) + relu = self.relu(bn) + return relu + + def get_example_inputs(self): + return (torch.randn(1, 3, 8, 8),) + + +def test_conv_relu_fusing_8a8w_tosa_INT_affine(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + quant_config = get_symmetric_quantization_config() + quantizer.set_global(quant_config) + expected_annotations = { + "aten.conv2d.default": {None: 1}, + "aten.relu.default": {quant_config.get_output_act_qspec(): 1}, + } + pipeline = QuantizationPipeline[Tuple[torch.Tensor]]( + ConvBNRelu(), + ConvBNRelu().get_example_inputs(), + quantizer=quantizer, + qspecs=expected_annotations, + ) + pipeline.run() + + +def test_conv_relu_fusing_8a8w_tosa_INT_symmetric(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + symmetric_quant_config = get_symmetric_a8w8_quantization_config() + + quantizer.set_global(symmetric_quant_config) + expected_annotations = { + "aten.conv2d.default": {symmetric_quant_config.get_output_act_qspec(): 1}, + "aten.relu.default": {symmetric_quant_config.get_output_act_qspec(): 1}, + } + pipeline = QuantizationPipeline[Tuple[torch.Tensor]]( + ConvBNRelu(), + ConvBNRelu().get_example_inputs(), + quantizer=quantizer, + qspecs=expected_annotations, + ) + pipeline.run() + + +def test_conv_relu_fusing_16a8w_tosa_INT_symmetric(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT+int16") + quantizer = TOSAQuantizer(tosa_spec) + quant_config = get_symmetric_a16w8_quantization_config() + + quantizer.set_global(quant_config) + expected_annotations = { + "aten.conv2d.default": {quant_config.get_output_act_qspec(): 1}, + "aten.relu.default": {quant_config.get_output_act_qspec(): 1}, + } + pipeline = QuantizationPipeline[Tuple[torch.Tensor]]( + ConvBNRelu(), + ConvBNRelu().get_example_inputs(), + quantizer=quantizer, + qspecs=expected_annotations, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_generic_annotater.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_generic_annotater.py new file mode 100644 index 0000000..dd883e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_generic_annotater.py @@ -0,0 +1,109 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +import itertools + +from typing import Any, Callable, Tuple + +import torch +from executorch.backends.arm.quantizer import is_annotated +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT +from executorch.backends.test.harness.stages import StageType + +from torch.fx.passes.utils.source_matcher_utils import get_source_partitions + + +input_t1 = Tuple[torch.Tensor] # Input x + + +class SingleOpModel(torch.nn.Module): + def __init__( + self, + op: Callable[..., torch.Tensor], + example_input: Tuple[Any, ...], + **op_kwargs: Any, + ) -> None: + super().__init__() + self.op: Callable[..., torch.Tensor] = op + self._example_input: Tuple[Any, ...] = example_input + self.op_kwargs: dict[str, Any] = dict(op_kwargs) + + def forward(self, x: Any) -> torch.Tensor: + return self.op(x, **self.op_kwargs) + + def example_inputs(self) -> Tuple[Any, ...]: + return self._example_input + + +def check_annotation(model: SingleOpModel) -> None: + pipeline = TosaPipelineINT[input_t1](model, model.example_inputs(), [], []) + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + artifact = pipeline.tester.get_artifact(StageType.QUANTIZE) + + partitions = get_source_partitions(artifact.graph, [model.op]) + partitions = list(itertools.chain.from_iterable(partitions.values())) + + assert len(partitions) == 1 + partition = partitions[0] + assert all(is_annotated(node) for node in partition.nodes) + + +def test_squeeze_tosa_INT(): + check_annotation(SingleOpModel(torch.squeeze, (torch.rand(8, 8, 1),))) + check_annotation(SingleOpModel(torch.squeeze_copy, (torch.rand(8, 8, 1),))) + + +def test_unsqueeze_tosa_INT(): + check_annotation(SingleOpModel(torch.unsqueeze, (torch.rand(8, 8),), dim=0)) + check_annotation(SingleOpModel(torch.unsqueeze_copy, (torch.rand(8, 8),), dim=0)) + + +def test_reshape_tosa_INT(): + check_annotation( + SingleOpModel(torch.reshape, (torch.randn(8, 8),), shape=(64,)), + ) + + +def test_view_tosa_INT(): + check_annotation( + SingleOpModel(torch.view_copy, (torch.randn(4, 4),), size=(2, 8)), + ) + + +def test_slice_tosa_INT(): + check_annotation( + SingleOpModel(torch.slice_copy, (torch.randn(3, 4),)), + ) + + +def test_transpose_tosa_INT(): + check_annotation( + SingleOpModel(torch.transpose, (torch.randn(2, 3),), dim0=0, dim1=1), + ) + check_annotation( + SingleOpModel(torch.transpose_copy, (torch.randn(2, 3),), dim0=0, dim1=1), + ) + + +def test_tile_tosa_INT(): + check_annotation( + SingleOpModel(torch.tile, (torch.randn(4, 4),), dims=(2,)), + ) + + +def test_flip_tosa_INT(): + check_annotation( + SingleOpModel(torch.flip, (torch.randn(2, 4),), dims=(0, 1)), + ) + + +def test_concat_tosa_INT(): + check_annotation( + SingleOpModel( + torch.concatenate, ((torch.randn(2, 3), torch.randn(2, 3)),), dim=0 + ), + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_partial_quantization.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_partial_quantization.py new file mode 100644 index 0000000..43393c9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_partial_quantization.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from collections.abc import Iterable + +import torch +import torch.fx + +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT +from executorch.backends.test.harness.stages import StageType + + +def _collect_disallow_flags(graph: torch.fx.Graph) -> dict[str, bool | None]: + flags: dict[str, bool | None] = {} + for node in graph.nodes: + if DISALLOW_TFA_META_KEY in node.meta: + flags[node.name] = node.meta[DISALLOW_TFA_META_KEY] + return flags + + +def _run_quantization_pipeline( + module: torch.nn.Module, + unquantized_submodules: Iterable[type[torch.nn.Module]], +) -> torch.fx.Graph: + """Run the Arm TOSA quantization pipeline for ``module`` while keeping the + specified submodules in floating-point. + """ + pipeline = TosaPipelineINT[tuple[torch.Tensor]]( + module, + module.example_inputs(), # type: ignore[operator] + [], + [], + ) + + quant_stage = pipeline._stages[0].args[0] + for mod in unquantized_submodules: + quant_stage.quantizer.set_module_type(mod, None) + + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + return pipeline.tester.get_artifact(StageType.QUANTIZE).graph + + +def test_disallow_tfa_for_skipped_module(): + """Ensure a softmax skipped for quantization is not decomposed and that its + node has `disallow_tfa` set.""" + + class TwoOpModel(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.softmax = torch.nn.Softmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.softmax(x) + 1 + + def example_inputs(self) -> tuple[torch.Tensor, ...]: + return (torch.randn(2, 3),) + + graph_after_quant_stage = _run_quantization_pipeline( + TwoOpModel(), [torch.nn.Softmax] + ) + + flags = _collect_disallow_flags(graph_after_quant_stage) + + assert flags.get("x") is False, "'x' should not be disallowed for TFA" + assert flags.get("softmax") is True, "'softmax' should be disallowed for TFA" + assert flags.get("add") is False, "'add' should not be disallowed for TFA" + assert flags.get("output") is False, "'output' should not be disallowed for TFA" + + +def test_disallow_tfa_for_two_skipped_modules(): + class LinearSoftmaxModel(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.linear = torch.nn.Linear(10, 10) + self.softmax = torch.nn.Softmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.linear(x) + x = torch.abs(x) + x = self.softmax(x) + return x + 1 + + def example_inputs(self) -> tuple[torch.Tensor, ...]: + return (torch.randn(1, 10),) + + graph_after_quant_stage = _run_quantization_pipeline( + LinearSoftmaxModel(), + [torch.nn.Linear, torch.nn.Softmax], + ) + + flags = _collect_disallow_flags(graph_after_quant_stage) + + assert flags.get("x") is False, "'x' should not be disallowed for TFA" + assert flags.get("linear") is True, "'linear' should be disallowed for TFA" + assert flags.get("softmax") is True, "'softmax' should be disallowed for TFA" + assert flags.get("add") is False, "'add' should not be disallowed for TFA" + assert flags.get("abs_1") is False, "'abs_1' should not be disallowed for TFA" + assert flags.get("output") is False, "'output' should not be disallowed for TFA" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_selective_quantization.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_selective_quantization.py new file mode 100644 index 0000000..ae8892f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_selective_quantization.py @@ -0,0 +1,212 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import QuantizationPipeline +from executorch.backends.arm.tosa import TosaSpecification +from torchvision import models, transforms # type: ignore[import-untyped] +from torchvision.ops.misc import Conv2dNormActivation # type: ignore[import-untyped] + + +def get_quantizer(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + quantizer.set_global(get_symmetric_quantization_config()) + return quantizer + + +def get_selective_quantizer_by_module( + module_types: Dict[torch.nn.Module, QuantizationConfig] +): + quantizer = get_quantizer() + quantizer.set_global(get_symmetric_quantization_config()) + for module_type, config in module_types.items(): + quantizer.set_module_type(module_type, config) + + return quantizer + + +def get_selective_quantizer_by_module_name(module_names: Dict[str, QuantizationConfig]): + quantizer = get_quantizer() + quantizer.set_global(get_symmetric_quantization_config()) + for module_name, config in module_names.items(): + quantizer.set_module_name(module_name, config) + + return quantizer + + +class Add(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return x + y + + +class AddSoftmaxAdd(torch.nn.Module): + module_names = {"add_0": None, "add_1": None} + module_types = { + Add: None, + } + quantized_aten_targets = {"aten.relu.default": 1} + non_quantized_aten_targets = {"aten.add.Tensor": 2} + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.softmax = torch.nn.Softmax(dim=-1) + self.relu = torch.nn.ReLU() + self.add_0 = Add() + self.add_1 = Add() + + def get_inputs(self): + return (torch.randn(1, 10), torch.randn(1, 10)) + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + z = self.add_0(x, y) + z = self.relu(z) + z = self.softmax(z) + return self.add_1(z, y) + + +test_models = { + "add_softmax_add": AddSoftmaxAdd, +} + + +@common.parametrize("model", test_models) +def test_selective_quant_module_name_tosa_INT(model): + model = model() + inputs = model.get_inputs() + quantzed_aten_targets = model.quantized_aten_targets + non_quantized_aten_targets = model.non_quantized_aten_targets + quantization_annotations = {} + for target, count in quantzed_aten_targets.items(): + quantization_annotations[target] = { + get_symmetric_quantization_config().output_activation: count + } + for target, count in non_quantized_aten_targets.items(): + quantization_annotations[target] = {None: count} + + pipeline = QuantizationPipeline[tuple[torch.Tensor, torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module_name(model.module_names), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +@common.parametrize("model", test_models) +def test_selective_quant_module_type_tosa_INT(model): + model = model() + inputs = model.get_inputs() + quantzed_aten_targets = model.quantized_aten_targets + non_quantized_aten_targets = model.non_quantized_aten_targets + quantization_annotations = {} + for target, count in quantzed_aten_targets.items(): + quantization_annotations[target] = { + get_symmetric_quantization_config().output_activation: count + } + for target, count in non_quantized_aten_targets.items(): + quantization_annotations[target] = {None: count} + + pipeline = QuantizationPipeline[tuple[torch.Tensor, torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module(model.module_types), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +mv3 = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights) +mv3.eval() +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + + +def test_mv3_selective_quant_int16_tosa_INT(): + model = mv3 + inputs = (normalize(torch.randn(1, 3, 224, 224)),) + + a16w8_config = get_symmetric_a16w8_quantization_config() + quantization_annotations = { + "aten.conv2d.default": { + a16w8_config.output_activation: 34, + }, + "aten.hardswish_.default": { + a16w8_config.output_activation: 18, + }, + "aten.relu_.default": { + a16w8_config.output_activation: 5, + }, + } + + pipeline = QuantizationPipeline[tuple[torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module( + { + Conv2dNormActivation: a16w8_config, + } + ), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +def test_mv3_selective_quant_float32_tosa_INT(): + model = mv3 + inputs = (normalize(torch.randn(1, 3, 224, 224)),) + + quantization_annotations = { + "aten.adaptive_avg_pool2d.default": { + None: 1, + }, + } + + pipeline = QuantizationPipeline[tuple[torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module_name( + { + "features.11.block.2.avgpool": None, + } + ), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +def test_mv3_io_quant_tosa_INT(): + model = mv3 + inputs = (normalize(torch.randn(1, 3, 224, 224)),) + + quantizer = get_quantizer() + # Workaround to disable quantization for all modules + quantizer.set_module_type(torch.nn.Module, None) + # Only quantize IO + quantizer.set_io(get_symmetric_quantization_config()) + + pipeline = QuantizationPipeline[tuple[torch.Tensor]]( + model, + inputs, + quantizer=quantizer, + input_qspecs={get_symmetric_quantization_config().input_activation: 1}, + output_qspecs={get_symmetric_quantization_config().output_activation: 1}, + ) + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_set_module_name.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_set_module_name.py new file mode 100644 index 0000000..d0ca781 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_set_module_name.py @@ -0,0 +1,158 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + is_annotated, + QuantizationConfig, + TOSAQuantizer, +) +from executorch.backends.arm.quantizer.quantization_config import QuantizationSpec +from executorch.backends.arm.tosa import TosaSpecification +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + +DQ_PER_CHANNEL = torch.ops.quantized_decomposed.dequantize_per_channel.default +DQ_PER_TENSOR = torch.ops.quantized_decomposed.dequantize_per_tensor.default +Q_PER_TENSOR = torch.ops.quantized_decomposed.quantize_per_tensor.default + + +class ConvModel(torch.nn.Module): + def __init__(self): + super().__init__() + self.conv0 = torch.nn.Conv2d( + 3, + 16, + kernel_size=4, + ) + self.conv1 = torch.nn.Conv2d(16, 32, kernel_size=3, bias=False) + self.conv2 = torch.nn.Conv2d(32, 64, kernel_size=3) + + def forward(self, x): + x = self.conv0(x) + x = torch.sigmoid(x) + x = self.conv1(x) + x = torch.tanh(x) + x = self.conv2(x) + return x + + +test_inputs = (torch.randn(1, 3, 64, 64),) + + +def validate_per_tensor_quant(node: torch.fx.Node, qspec: QuantizationSpec): + _, _, zero_point, qmin, qmax, dtype = node.args + if qspec.qscheme == torch.per_tensor_symmetric: + assert ( + zero_point == 0 + ), f"Zero point {zero_point} is not zero for symmetric quantization" + assert ( + qmin == qspec.quant_min + ), f"Quant min {qmin} does not match expected {qspec.quant_min}" + assert ( + qmax == qspec.quant_max + ), f"Quant max {qmax} does not match expected {qspec.quant_max}" + assert dtype == qspec.dtype, f"Dtype {dtype} does not match expected {qspec.dtype}" + + +def validate_per_channel_quant(node: torch.fx.Node, qspec: QuantizationSpec): + _, _, _, channel_axis, qmin, qmax, dtype = node.args + assert ( + channel_axis == qspec.ch_axis + ), f"Channel axis {channel_axis} does not match expected {qspec.ch_axis}" + assert ( + qmin == qspec.quant_min + ), f"Quant min {qmin} does not match expected {qspec.quant_min}" + assert ( + qmax == qspec.quant_max + ), f"Quant max {qmax} does not match expected {qspec.quant_max}" + assert dtype == qspec.dtype, f"Dtype {dtype} does not match expected {qspec.dtype}" + + +def validate_input(input_node: torch.fx.Node, qspec: QuantizationSpec | None): + if qspec is None: + return + + per_channel = qspec.qscheme == torch.per_channel_symmetric + expected_dequant_op = DQ_PER_CHANNEL if per_channel else DQ_PER_TENSOR + assert ( + input_node.target == expected_dequant_op + ), f"Input node {input_node} is not quantized as expected" + if per_channel: + validate_per_channel_quant(input_node, qspec) + else: + validate_per_tensor_quant(input_node, qspec) + + +def validate_output(node: torch.fx.Node, qspec: QuantizationSpec | None): + if qspec is None: + return + users = list(node.users) + assert len(users) == 1, f"Node {node} should have exactly one user" + assert ( + users[0].target == Q_PER_TENSOR + ), f"Output node {users[0]} is not quantized as expected" + validate_per_tensor_quant(users[0], qspec) + + +def validate_node( + node: torch.fx.Node, quantization_config: QuantizationConfig | None +) -> None: + if quantization_config is None: + assert not is_annotated(node), f"Node {node} is unexpectedly annotated" + return + + assert is_annotated(node), f"Node {node} is not annotated" + input_qspec = quantization_config.get_input_act_qspec() + output_qspec = quantization_config.get_output_act_qspec() + weight_qspec = quantization_config.get_weight_qspec() + + if len(node.all_input_nodes) == 3: + input_node, weight_node, bias_node = node.all_input_nodes + bias_qspec = quantization_config.get_bias_qspec(node) + validate_input(bias_node, bias_qspec) + else: + input_node, weight_node = node.all_input_nodes + + validate_input(input_node, input_qspec) + validate_input(weight_node, weight_qspec) + validate_output(node, output_qspec) + + +def test_set_module_name_tosa_INT() -> None: + model = ConvModel() + model.eval() + + # Set up quantizer with different configs for different modules + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + int8_config = get_symmetric_quantization_config(is_per_channel=False) + a16w8_config = get_symmetric_a16w8_quantization_config() + # Set module-specific configurations but don't set global config to test that + # only specified modules are quantized + quantizer.set_module_name("conv0", int8_config) + quantizer.set_module_name("conv1", a16w8_config) + + # Export model + exported_model = torch.export.export(model, test_inputs) + + # Prepare, calibrate and convert model + prepared_model = prepare_pt2e(exported_model.module(), quantizer) + prepared_model(*test_inputs) + converted_model = convert_pt2e(prepared_model) + + validate_node( + [node for node in converted_model.graph.nodes if node.name == "conv2d"][0], + int8_config, + ) + validate_node( + [node for node in converted_model.graph.nodes if node.name == "conv2d_1"][0], + a16w8_config, + ) + validate_node( + [node for node in converted_model.graph.nodes if node.name == "conv2d_2"][0], + None, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_tosa_quantizer_validate.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_tosa_quantizer_validate.py new file mode 100644 index 0000000..081e9ec --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/quantizer/test_tosa_quantizer_validate.py @@ -0,0 +1,55 @@ +# Copyright 2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch + +from executorch.backends.arm.quantizer import TOSAQuantizer +from executorch.backends.arm.tosa import TosaSpecification +from torch.fx import symbolic_trace + + +def _annotate_placeholders_with_devices(gm, device_map): + for node in gm.graph.nodes: + if node.op == "placeholder": + device = device_map[node.target] + node.meta["val"] = torch.empty(1, device=device) + + +def _get_quantizer(): + return TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + +class TwoIndependentAdds(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x + 1, y + 1 + + +class CrossDeviceAdd(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x + y + + +def test_validate_allows_different_devices_across_operators(): + gm = symbolic_trace(TwoIndependentAdds()) + _annotate_placeholders_with_devices( + gm, {"x": torch.device("cpu"), "y": torch.device("meta")} + ) + + quantizer = _get_quantizer() + quantizer.validate(gm) + + +def test_validate_rejects_mixed_devices_within_operator(): + gm = symbolic_trace(CrossDeviceAdd()) + _annotate_placeholders_with_devices( + gm, {"x": torch.device("cpu"), "y": torch.device("meta")} + ) + + quantizer = _get_quantizer() + with pytest.raises(ValueError, match="Quantizer detected operator"): + quantizer.validate(gm) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/runner_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/runner_utils.py new file mode 100644 index 0000000..44e9e75 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/runner_utils.py @@ -0,0 +1,840 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import importlib.resources as _resources +import json +import logging +import os +import re +import shutil +import subprocess # nosec B404 - invoked only for trusted toolchain binaries +import tempfile +from pathlib import Path + +from types import NoneType +from typing import Any, cast, Dict, List, Optional, Tuple + +import executorch.backends.arm.test as arm_test_package +import executorch.backends.arm.tosa.schemas as tosa_schemas_package + +import numpy as np +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.constants import ( + NHWC_INVERSE_ORDER, + NHWC_ORDER, + NNHWC_INVERSE_ORDER, + NNHWC_ORDER, +) + +from executorch.backends.arm.ethosu import EthosUCompileSpec +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.specification import Tosa_1_00, TosaSpecification +from executorch.backends.arm.vgf import VgfCompileSpec +from executorch.backends.arm.vgf.model_converter import find_model_converter_binary +from executorch.exir import ExecutorchProgramManager, ExportedProgram +from executorch.exir.lowered_backend_module import LoweredBackendModule +from torch.fx.node import Node + +from torch.overrides import TorchFunctionMode +from tosa.TosaGraph import TosaGraph # type: ignore[import-not-found, import-untyped] + +logger = logging.getLogger(__name__) + +# Copied from PyTorch. +# From torch/testing/_internal/common_utils.py:torch_to_numpy_dtype_dict +# To avoid a dependency on _internal stuff. +_torch_to_numpy_dtype_dict = { + torch.bool: np.bool_, + torch.uint8: np.uint8, + torch.uint16: np.uint16, + torch.uint32: np.uint32, + torch.uint64: np.uint64, + torch.int8: np.int8, + torch.int16: np.int16, + torch.int32: np.int32, + torch.int64: np.int64, + torch.float16: np.float16, + torch.float32: np.float32, + torch.float64: np.float64, + torch.bfloat16: np.float32, + torch.complex32: np.complex64, + torch.complex64: np.complex64, + torch.complex128: np.complex128, +} + +VALID_TARGET = {"corstone-300", "corstone-320", "vkml_emulation_layer"} + + +class QuantizationParams: + __slots__ = ["node_name", "zp", "scale", "qmin", "qmax", "dtype"] + + # todo: zps and scales can be per tensors or per channel => a list?? + def __init__( + self, + node_name: str, + zp: int, + scale: float, + qmin: int, + qmax: int, + dtype: torch.dtype, + ): + self.node_name = node_name # not need I think, but good for error check + self.zp = zp + self.scale = scale + self.qmin = qmin + self.qmax = qmax + self.dtype = dtype + + +def get_input_names(program: ExportedProgram) -> list[str]: + """ + Get a list[str] with the names of the inputs to this model. + + Args: + program (ExportedProgram): The program to get input names from. + Returns: + A list of strings with the names of the model input. + """ + return [spec.arg.name for spec in program.graph_signature.input_specs] + + +def get_input_quantization_params( + program: ExportedProgram, +) -> list[QuantizationParams]: + """ + Get input QuantizationParams in a program, maximum one per input to the program. + Args: + program (ExportedProgram): The program to get input quantization parameters from. + Returns: + list[QuantizationParams]: The found quantization parameters. + """ + + quant_params = [] + input_names = get_input_names(program) + num_inputs = len(input_names) + for node in program.graph.nodes: + if ( + node.target == torch.ops.quantized_decomposed.quantize_per_tensor.default + and node.args[0].name in input_names + ): + qp = QuantizationParams( + node_name=node.args[0].name, + scale=node.args[1], + zp=node.args[2], + qmin=node.args[3], + qmax=node.args[4], + dtype=node.args[5], + ) + quant_params.append(qp) + if ( + len(quant_params) == num_inputs + ): # break early if we have all the inputs quantized parameters + break + if len(quant_params) == 0: + logger.warning("No input quantization parameters found in exported model.") + return quant_params + + +def get_output_quantization_params( + output_node: Node, +) -> dict[Node, QuantizationParams | None]: + """ + Get output QuantizationParams from a program. + Args: + output_nodes (list(Node)): A list of output nodes to get output quantization parameters from. + Returns: + dictionary mapping the output nodes to the found quantization parameters. + If no quantization parameters were found, the entry is None. + Raises: + RuntimeError if no output quantization parameters are found. + """ + quant_params: dict[Node, QuantizationParams | None] = {} + for node in output_node.args[0]: # type: ignore[union-attr] + if ( + node.target # type: ignore[union-attr] + == torch.ops.quantized_decomposed.dequantize_per_tensor.default + ): + quant_params[node] = QuantizationParams( # type: ignore[index] + node_name=node.args[0].name, # type: ignore[arg-type, union-attr] + scale=node.args[1], # type: ignore[arg-type, union-attr] + zp=node.args[2], # type: ignore[arg-type, union-attr] + qmin=node.args[3], # type: ignore[arg-type, union-attr] + qmax=node.args[4], # type: ignore[arg-type, union-attr] + dtype=node.args[5], # type: ignore[arg-type, union-attr] + ) + else: + quant_params[node] = None # type: ignore[index] + return quant_params + + +def torch_tensor_to_numpy(tensor: torch.Tensor) -> np.ndarray: + dtype = _torch_to_numpy_dtype_dict[tensor.dtype] + array = tensor.detach().numpy().astype(dtype) # type: ignore[var-annotated] + dim_order = tensor.dim_order() + if dim_order == NHWC_ORDER: + a = array.transpose(NHWC_ORDER) + return a + elif dim_order == NNHWC_ORDER: + return array.transpose(NNHWC_ORDER) + else: + return array + + +def numpy_to_torch_tensor(array: np.ndarray, output_node: Node) -> torch.Tensor: + output_tensor = get_first_fake_tensor(output_node) + shape = output_tensor.shape + dim_order = output_tensor.dim_order() + if dim_order == NHWC_ORDER: + shape_with_dim_order = [shape[i] for i in NHWC_ORDER] + tensor = torch.from_numpy(array).reshape(shape_with_dim_order) + return tensor.permute(NHWC_INVERSE_ORDER).to(memory_format=torch.channels_last) + elif dim_order == NNHWC_ORDER: + shape_with_dim_order = [shape[i] for i in NNHWC_ORDER] + tensor = torch.from_numpy(array).reshape(shape_with_dim_order) + return tensor.permute(NNHWC_INVERSE_ORDER).to(memory_format=torch.channels_last) + else: + tensor = torch.from_numpy(array).reshape(shape) + return tensor + + +class TosaReferenceModelDispatch(TorchFunctionMode): + """A context manager for executing call_delegate nodes using the reference model""" + + def __init__(self): + self.ran_tosa_dispatch = False + super().__init__() + + def _tosa_dispatch(self, lowered_backend_module: LoweredBackendModule, inputs): + tosa_buffer = lowered_backend_module.processed_bytes + compile_spec = TosaCompileSpec.from_list(lowered_backend_module.compile_specs) + + output_node = lowered_backend_module.original_module.graph.output_node() + return run_tosa_graph(tosa_buffer, compile_spec.tosa_spec, inputs, output_node) + + def __exit__(self, exc_type, exc_val, exc_tb): + super().__exit__(exc_type, exc_val, exc_tb) + # Only raise this error if we ran the model without errors. + if not self.ran_tosa_dispatch and exc_type is None: + raise RuntimeError( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + ) + + def __torch_function__(self, func, types, args=..., kwargs=None): + if func is torch._higher_order_ops.executorch_call_delegate: + lowered_backend_module = cast(LoweredBackendModule, args[0]) + if lowered_backend_module.backend_id == "TOSABackend": + self.ran_tosa_dispatch = True + return self._tosa_dispatch(lowered_backend_module, args[1:]) + else: + raise RuntimeError( + f"Ran model with TosaReferenceModelDispatch but call_delegate with {lowered_backend_module.backend_id=} != 'TOSABackend'." + ) + + kwargs = kwargs or {} + + # This is a hack since Q/DQ ops does not handle channels last input correctly: the simplest and most robust + # workaround is to simply run them in channels first format and then convert back to channels last. + if func in ( + torch.ops.quantized_decomposed.quantize_per_tensor.out, + torch.ops.quantized_decomposed.dequantize_per_tensor.out, + torch.ops.quantized_decomposed.quantize_per_channel.out, + torch.ops.quantized_decomposed.dequantize_per_channel.out, + ): + + input_dim_order = args[0].dim_order() + if input_dim_order in (NHWC_ORDER, NNHWC_ORDER): + args = [args[0].to(memory_format=torch.contiguous_format), *args[1:]] + res = func(*args, **kwargs) + return res.to(memory_format=torch.channels_last) + + return func(*args, **kwargs) + + +def run_target( + executorch_program_manager: ExecutorchProgramManager, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, + target_board: str, + elf_path: str | Path, + timeout: int = 120, # s +): + if target_board not in VALID_TARGET: + raise ValueError(f"Unsupported target: {target_board}") + + if target_board == "vkml_emulation_layer": + return run_vkml_emulation_layer( + executorch_program_manager, + inputs, + intermediate_path, + elf_path, + ) + return run_corstone( + executorch_program_manager, + inputs, + intermediate_path, + target_board, + elf_path, + timeout, + ) + + +def save_inputs_to_file( + exported_program: ExportedProgram, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, +): + input_file_paths: list[str] = [] + input_names = get_input_names(exported_program) + for input_name, input_ in zip(input_names, inputs): + input_path = save_bytes(intermediate_path, input_, input_name) # type: ignore[arg-type] + input_file_paths.append(input_path) + + return input_file_paths + + +def get_output_from_file( + exported_program: ExportedProgram, + intermediate_path: str | Path, + output_base_name: str, +): + output_np = [] + output_node = exported_program.graph_module.graph.output_node() + for i, node in enumerate(output_node.args[0]): # type: ignore[union-attr] + output_dtype = node.meta["val"].dtype + tosa_ref_output = np.fromfile( # type: ignore[var-annotated] + os.path.join(intermediate_path, f"{output_base_name}-{i}.bin"), + _torch_to_numpy_dtype_dict[output_dtype], + ) + + output_np.append(numpy_to_torch_tensor(tosa_ref_output, node)) + return tuple(output_np) + + +def run_vkml_emulation_layer( + executorch_program_manager: ExecutorchProgramManager, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, + elf_path: str | Path, +): + """Executes an inference of the exported_program on ML Emulation Layer for Vulkan + Args: + `executorch_program_manager`: The executorch program to run. + `intermediate_path`: Directory to save the .pte and capture outputs. + `elf_path`: Path to the Vulkan-capable executor_runner binary. + """ + exported_program = executorch_program_manager.exported_program() + intermediate_path = Path(intermediate_path) + intermediate_path.mkdir(exist_ok=True) + elf_path = Path(elf_path) + if not elf_path.exists(): + raise FileNotFoundError(f"Did not find elf file {elf_path}") + + # Save pte to file + pte_path = os.path.join(intermediate_path, "program.pte") + with open(pte_path, "wb") as f: + f.write(executorch_program_manager.buffer) + + output_base_name = "out" + out_path = os.path.join(intermediate_path, output_base_name) + + cmd_line = f"{elf_path} -model_path {pte_path} -output_file {out_path}" + + input_string = None + input_paths = save_inputs_to_file(exported_program, inputs, intermediate_path) + for input_path in input_paths: + if input_string is None: + input_string = f" -inputs={input_path}" + else: + input_string += f",{input_path}" + if input_string is not None: + cmd_line += input_string + cmd_line = cmd_line.split() + + result = _run_cmd(cmd_line) + + # TODO: MLETORCH-1234: Support VGF e2e tests in VgfPipeline + # TODO: Add regex to check for error or fault messages in stdout from Emulation Layer + result_stdout = result.stdout.decode() # noqa: F841 + + return get_output_from_file(exported_program, intermediate_path, output_base_name) + + +def run_corstone( + executorch_program_manager: ExecutorchProgramManager, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, + target_board: str, + elf_path: str | Path, + timeout: int = 120, # s +) -> list[torch.Tensor]: + """Executes an inference of the exported_program on FVP. + Returns a list of tensors with the output. + Args: + `executorch_program_manager`: The executorch program to run. + The output of a EdgeProgramManager.to_executorch() call. + `inputs`: A list of tensors with the inputs of the inference. + `dump_path`: A directory where the .pte and inputs are saved to file. + The output tensors are saved in `dump_path`/out. + `target_board`: Whether to run the corstone-300 FVP or the corstone-320 FVP + `elf_path`: The path to the runtime elf. Needs to have semihosting enabled + and match the target_board. + `timeout`: The timeout until the FVP terminates the elf, in seconds. + A runtime with semihosting needs + Limitations: + Relies on the output tensors from the exported program + to figure out the shape and dtype of the buffer that was + output from the FVP. + """ + exported_program = executorch_program_manager.exported_program() + intermediate_path = Path(intermediate_path) + intermediate_path.mkdir(exist_ok=True) + elf_path = Path(elf_path) + if not elf_path.exists(): + raise FileNotFoundError(f"Did not find elf file {elf_path}") + + # Save pte to file + pte_path = os.path.join(intermediate_path, "program.pte") + with open(pte_path, "wb") as f: + f.write(executorch_program_manager.buffer) + + input_paths = save_inputs_to_file(exported_program, inputs, intermediate_path) + + output_base_name = "out" + + cmd_line = "executor_runner -m program.pte -o out" + for input_path in input_paths: + relative_path = os.path.relpath( + Path(input_path).resolve(), start=intermediate_path + ) + cmd_line += f" -i {relative_path}" + + if len(cmd_line) > 256: + raise ValueError( + "The argument passed to the FVP should be less than 256 characters long, otherwise it gets truncated" + ) + + match target_board: + case "corstone-300": + command_args = [ + "FVP_Corstone_SSE-300_Ethos-U55", + "-C", + "ethosu.num_macs=128", + "-C", + "mps3_board.visualisation.disable-visualisation=1", + "-C", + "mps3_board.telnetterminal0.start_telnet=0", + "-C", + "mps3_board.uart0.out_file='-'", + "-C", + "cpu0.semihosting-enable=1", + "-C", + "cpu0.semihosting-stack_base=0", + "-C", + "cpu0.semihosting-heap_limit=0", + "-C", + f"cpu0.semihosting-cwd={intermediate_path}", + "-C", + "ethosu.extra_args='--fast'", + "-C", + f"cpu0.semihosting-cmd_line='{cmd_line}'", + "-a", + str(elf_path), + "--timelimit", + f"{timeout}", + ] + case "corstone-320": + command_args = [ + "FVP_Corstone_SSE-320", + "-C", + "mps4_board.subsystem.ethosu.num_macs=128", + "-C", + "mps4_board.visualisation.disable-visualisation=1", + "-C", + "vis_hdlcd.disable_visualisation=1", + "-C", + "mps4_board.telnetterminal0.start_telnet=0", + "-C", + "mps4_board.uart0.out_file='-'", + "-C", + "mps4_board.uart0.unbuffered_output=1", + "-C", + "mps4_board.uart0.shutdown_on_eot=1", + "-C", + "mps4_board.subsystem.cpu0.semihosting-enable=1", + "-C", + "mps4_board.subsystem.cpu0.semihosting-stack_base=0", + "-C", + "mps4_board.subsystem.cpu0.semihosting-heap_limit=0", + "-C", + f"mps4_board.subsystem.cpu0.semihosting-cwd={intermediate_path}", + "-C", + "mps4_board.subsystem.ethosu.extra_args='--fast'", + "-C", + f"mps4_board.subsystem.cpu0.semihosting-cmd_line='{cmd_line}'", + "-a", + str(elf_path), + "--timelimit", + f"{timeout}", + ] + case _: + raise ValueError(f"Unknown target board {target_board}") + + result = _run_cmd(command_args) + + # Regex to check for error or fault messages in stdout from FVP + result_stdout = result.stdout.decode() + error_regex = r"(^[EF][: ].*$)|(^.*Hard fault.*$)|(^.*Assertion.*$)" + pattern = re.compile(error_regex, re.MULTILINE) + regex_matches = [m.group(0) for m in pattern.finditer(result_stdout)] + + if regex_matches: + logger.error( + f"Corstone simulation failed:\ncmd: {' '.join(command_args)}\nlog: \n {result_stdout}\n{result.stderr.decode()}" + ) + # Pretty-print regex matches + pretty_matches = "\n".join(f"{m.strip()}" for i, m in enumerate(regex_matches)) + logger.error( + f"Corstone simulation failed. Problems: {len(regex_matches)} found:\n{pretty_matches}" + ) + raise RuntimeError( + f"Corstone simulation failed. Problems: {len(regex_matches)} found:\n{pretty_matches}" + ) + else: + logger.info( + f"Corstone simulation:\ncmd: {' '.join(command_args)}\nlog: \n {result_stdout}\n{result.stderr.decode()}" + ) + + return get_output_from_file(exported_program, intermediate_path, output_base_name) + + +def prep_data_for_save( + data, + input_name: str, + quant_param: Optional[QuantizationParams] = None, +): + if isinstance(data, torch.Tensor): + data_np = torch_tensor_to_numpy(data) + elif isinstance(data, (int, float, bool, NoneType)): + return np.array(data) + else: + raise RuntimeError( + f"Input dtype {type(data)} could not be converted to numpy array." + ) + + if quant_param is not None: + assert quant_param.node_name in input_name, ( + f"The quantization params name '{quant_param.node_name}' does not " + f"match the input tensor name '{input_name}'." + ) + data_np = ( + ((data_np / np.float32(quant_param.scale)) + quant_param.zp) + .round() + .clip(quant_param.qmin, quant_param.qmax) + .astype( + f"{quant_param.dtype}".replace("torch.", "") + ) # Use string format of dtype to convert to numpy dtype + ) + + return data_np + + +def save_bytes( + path: str, + data, + input_name: str, + quant_param: Optional[QuantizationParams] = None, +) -> str: + """Serializes and saves 'data' in byte format, possibly quantizing it before. + + Parameters: + path: the directory where to save the data. + data: the data to save. + input_name: the name of the file, without file-ending. + quant_param: the parameters to use for quantization. + Returns: + the full file path of the output. + """ + data_np = prep_data_for_save(data, input_name, quant_param) + file_path = os.path.join(path, input_name + ".bin") + with open(file_path, "w+b") as f: + data_np_bytes = data_np.tobytes() + f.write(data_np_bytes) + + return file_path + + +def _run_cmd(cmd: List[str], check=True) -> subprocess.CompletedProcess[bytes]: + """ + Run a command and check for errors. + + Args: + cmd (List[str]): The command to run as a list. + """ + try: + result = subprocess.run( # nosec B603 - cmd constructed from trusted inputs + cmd, check=check, capture_output=True + ) + return result + except subprocess.CalledProcessError as e: + arg_string = " ".join(cmd) + raise RuntimeError( + f"Failed running command {arg_string}\nStderr: {e.stderr.decode()}\nStdout: {e.stdout.decode()}" + ) + + +# Name of an optional resource containing the `flatc` executable. +_FLATC_RESOURCE_NAME: str = "flatbuffers-flatc" + + +def _run_flatc(args: List[str]) -> None: + """Runs the `flatc` command with the provided args. + + If a resource matching _FLATC_RESOURCE_NAME exists, uses that executable. + Otherwise, expects the `flatc` tool to be available on the system path. + """ + flatc_resource = _resources.files(arm_test_package).joinpath(_FLATC_RESOURCE_NAME) + if flatc_resource.is_file(): + # Use the provided flatc binary from resources. + with _resources.as_file(flatc_resource) as flatc_path: + subprocess.run( # nosec B603 - cmd constructed from trusted inputs + [str(flatc_path)] + args, check=True + ) + else: + # Expect the `flatc` tool to be on the system path or set as an env var. + flatc_executable: str | None = os.getenv("FLATC_EXECUTABLE") + if not flatc_executable: + flatc_executable = shutil.which("flatc") + if not flatc_executable: + raise RuntimeError( + "flatc not found. Either add it to PATH, set FLATC_EXECUTABLE env var, " + "or ensure the flatbuffers-flatc resource is available." + ) + subprocess.run( # nosec B603 - cmd constructed from trusted inputs + [flatc_executable] + args, check=True + ) + + +def dbg_tosa_fb_to_json(tosa_fb: bytes) -> Dict: + """ + This function is used to dump the TOSA flatbuffer to a human readable + format, using flatc. It is used for debugging purposes. + """ + + tmp = tempfile.mkdtemp() + tosa_input_file = os.path.join(tmp, "output.tosa") + with open(tosa_input_file, "wb") as f: + f.write(tosa_fb) + tosa_graph = TosaGraph.GetRootAsTosaGraph(tosa_fb) + version = tosa_graph.Version() + major = version._Major() + minor = version._Minor() + patch = version._Patch() + if not ((major == 1 and minor == 0)): + raise RuntimeError( + f"Unsupported version in TOSA flatbuffer: version={major}.{minor}.{patch}" + ) + + # Write schema file to temp directory using importlib.resources + tosa_schema_file = os.path.join(tmp, f"tosa_{major}.{minor}.fbs") + with open(tosa_schema_file, "wb") as schema_file: + schema_file.write( + _resources.read_binary(tosa_schemas_package, f"tosa_{major}.{minor}.fbs") + ) + + flatc_args = [ + "--json", + "--strict-json", + "-o", + tmp, + "--raw-binary", + "-t", + tosa_schema_file, + "--", + tosa_input_file, + ] + _run_flatc(flatc_args) + with open(os.path.join(tmp, "output.json"), "r") as f: + json_out = json.load(f) + + # Cast float tensors to proper dtype. + try: + for region in json_out["regions"]: + for block in region["blocks"]: + for tensor in block["tensors"]: + if "data" in tensor: + if tensor["type"] == "FP32": + data = np.array(tensor["data"]) + data = data.astype(np.int8) + data = np.frombuffer(data, dtype=np.float32) + data = data.reshape(tensor["shape"]) + tensor["data"] = data + except Exception: # nosec B110 - best-effort casting for debug output only + pass + + return json_out + + +def _tosa_refmodel_loglevel(loglevel: int) -> str: + """Converts a logging loglevel to tosa_reference_model logginglevel, + returned as string. + """ + loglevel_map = { + logging.INFO: "INFO", + logging.CRITICAL: "LOW", + logging.ERROR: "LOW", + logging.WARNING: "MED", + logging.DEBUG: "HIGH", + logging.NOTSET: "MED", + } + clamped_logging_level = max(min(loglevel // 10 * 10, 50), 0) + return loglevel_map[clamped_logging_level] + + +def corstone300_installed() -> bool: + cmd = ["FVP_Corstone_SSE-300_Ethos-U55", "--version"] + try: + _run_cmd(cmd, check=True) + except: + return False + return True + + +def corstone320_installed() -> bool: + cmd = ["FVP_Corstone_SSE-320", "--version"] + try: + _run_cmd(cmd, check=True) + except: + return False + return True + + +def model_converter_installed() -> bool: + model_converter = find_model_converter_binary() + if model_converter is None: + return False + + try: + _run_cmd([model_converter, "--version"], check=True) + except Exception: + return False + + return True + + +def vkml_emulation_layer_installed() -> bool: + # Check VK_INSTANCE_LAYERS + vk_instance_layers = os.environ.get("VK_INSTANCE_LAYERS", "") + required_layers = { + "VK_LAYER_ML_Graph_Emulation", + "VK_LAYER_ML_Tensor_Emulation", + } + existing_layers = set(vk_instance_layers.split(":")) + layers_exists = required_layers.issubset(existing_layers) + + # Check LD_LIBRARY_PATH for "emulation-layer/deploy" + ld_library_path = os.environ.get("LD_LIBRARY_PATH", "") + deploy_exists = False + for path in ld_library_path.split(os.path.pathsep): + if "emulation-layer/deploy" in path and os.path.isdir(path): + deploy_exists = True + + return layers_exists and deploy_exists + + +def assert_elf_path_exists(elf_path): + if not os.path.exists(elf_path): + raise FileNotFoundError( + f"Did not find build arm_executor_runner or executor_runner in path {elf_path}, \ + run setup_testing.sh or setup_testing_vkml.sh?" + ) + + +def get_elf_path(target_board: str, use_portable_ops: bool = False) -> str: + elf_path = "" + + if target_board not in VALID_TARGET: + raise ValueError(f"Unsupported target: {target_board}") + + if use_portable_ops: + portable_ops_str = "portable-ops_" + else: + portable_ops_str = "" + + if target_board in ("corstone-300", "corstone-320"): + elf_path = os.path.join( + "arm_test", + f"arm_semihosting_executor_runner_{portable_ops_str}{target_board}", + "arm_executor_runner", + ) + elif target_board == "vkml_emulation_layer": + elf_path = os.path.join( + f"arm_test/arm_executor_runner_{portable_ops_str}vkml", + "executor_runner", + ) + + assert_elf_path_exists(elf_path) + return elf_path + + +def arm_executor_runner_exists(target_board: str, use_portable_ops: bool = False): + try: + get_elf_path(target_board, use_portable_ops=use_portable_ops) + except: + return False + else: + return True + + +def run_tosa_graph( + graph: Any, + tosa_version: TosaSpecification, + inputs: list[torch.Tensor], + output_node: Node, +) -> list[torch.Tensor]: + """Runs the TOSA reference model with inputs and returns the result.""" + + # Convert tensors to numpy arrays with correct dim_order + inputs_np = [torch_tensor_to_numpy(input_tensor) for input_tensor in inputs] + + if isinstance(tosa_version, Tosa_1_00): + import tosa_reference_model as reference_model # type: ignore[import-not-found, import-untyped] + + debug_mode = "ALL" if logger.getEffectiveLevel() <= logging.DEBUG else None + outputs_np, status = reference_model.run( + graph, + inputs_np, + verbosity=_tosa_refmodel_loglevel(logger.getEffectiveLevel()), + initialize_variable_tensor_from_numpy=True, + debug_mode=debug_mode, + ) + else: + raise ValueError( + f"Unknown TOSA specification: {tosa_version}. No refererence model available to run for this specification version" + ) + + assert ( + status == reference_model.GraphStatus.TOSA_VALID + ), "Non-valid TOSA given to reference model." + + # Convert output numpy arrays to tensors with same dim_order as the output nodes + result = [ + numpy_to_torch_tensor(output_array, node) + for output_array, node in zip(outputs_np, output_node.args[0]) # type: ignore[arg-type] + ] + + return result + + +def get_target_board(compile_spec: ArmCompileSpec) -> str | None: + if isinstance(compile_spec, VgfCompileSpec): + return "vkml_emulation_layer" + if isinstance(compile_spec, EthosUCompileSpec): + if "u55" in compile_spec.target: + return "corstone-300" + if "u85" in compile_spec.target: + return "corstone-320" + return None diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing.sh new file mode 100755 index 0000000..bb68361 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +et_root_dir=$(realpath "${script_dir}/../../..") +build_executor_runner=${et_root_dir}/backends/arm/scripts/build_executor_runner.sh +build_root_test_dir=${et_root_dir}/arm_test/arm_semihosting_executor_runner +extraflags="-DET_ARM_BAREMETAL_METHOD_ALLOCATOR_POOL_SIZE=83886080" + +# By default tests with an elf without any portable_ops +# If you supply use_portable_ops=True when creating the ArmTester() +# you will instead test with some portable ops compiled in, see list below. + +#--target --system_config --memory_mode should match the ArmTester used setup see backends/arm/test/common.py + +${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --system_config=Ethos_U55_High_End_Embedded --memory_mode=Shared_Sram --output="${build_root_test_dir}_corstone-300" --extra_build_flags=${extraflags} +${build_executor_runner} --pte=semihosting --target=ethos-u85-128 --system_config=Ethos_U85_SYS_DRAM_Mid --memory_mode=Dedicated_Sram_384KB --output="${build_root_test_dir}_corstone-320" --extra_build_flags=${extraflags} + +# List of portable ops used by testing, this is mainly used to test models in the flow +# test setup to make sure models that are not fully delegated can still be tested and run OK +# To use this you can set use_portable_ops=True when creating ArmTester() + +portable_ops_list_u55="aten::permute_copy.out,aten::convolution.out,aten::relu.out,aten::_native_batch_norm_legit_no_training.out,aten::as_strided_copy.out,aten::mean.out,aten::squeeze_copy.dims,dim_order_ops::_clone_dim_order.out" +portable_ops_list_u85="aten::permute_copy.out,aten::convolution.out,aten::relu.out,aten::_native_batch_norm_legit_no_training.out,aten::as_strided_copy.out,aten::mean.out,aten::full_like.out,aten::bmm.out,aten::scalar_tensor.out,aten::index.Tensor_out,aten::where.self_out" + +${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --system_config=Ethos_U55_High_End_Embedded --memory_mode=Shared_Sram --select_ops_list="${portable_ops_list_u55}" --output="${build_root_test_dir}_portable-ops_corstone-300" --extra_build_flags=${extraflags} +${build_executor_runner} --pte=semihosting --target=ethos-u85-128 --system_config=Ethos_U85_SYS_DRAM_Mid --memory_mode=Dedicated_Sram_384KB --select_ops_list="${portable_ops_list_u85}" --output="${build_root_test_dir}_portable-ops_corstone-320" --extra_build_flags=${extraflags} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing_vkml.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing_vkml.sh new file mode 100755 index 0000000..6edb2dc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/setup_testing_vkml.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +et_root_dir=$(realpath "${script_dir}/../../..") +build_executor_runner=${et_root_dir}/backends/arm/scripts/build_executor_runner_vkml.sh +build_root_test_dir=${et_root_dir}/arm_test/arm_executor_runner_vkml + +${build_executor_runner} --output="${build_root_test_dir}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/targets.bzl new file mode 100644 index 0000000..14b4a37 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/targets.bzl @@ -0,0 +1,79 @@ +# load("//caffe2/test/fb:defs.bzl", "define_tests") +load("@fbsource//tools/build_defs:fbsource_utils.bzl", "is_fbcode") +load("@fbcode_macros//build_defs:python_pytest.bzl", "python_pytest") +load("@bazel_skylib//lib:paths.bzl", "paths") + +def define_arm_tests(): + # TODO [fbonly] Add more tests + test_files = [] + + # Passes + test_files += native.glob(["passes/test_*.py"]) + # https://github.com/pytorch/executorch/issues/8606 + test_files.remove("passes/test_ioquantization_pass.py") + + # Operators + test_files += [ + "ops/test_add.py", + "ops/test_addmm.py", + "ops/test_avg_pool2d.py", + "ops/test_cat.py", + "ops/test_conv2d.py", + "ops/test_linear.py", + "ops/test_mul.py", + "ops/test_permute.py", + "ops/test_rsqrt.py", + "ops/test_slice.py", + "ops/test_sigmoid.py", + "ops/test_sub.py", + "ops/test_tanh.py", + "ops/test_view.py", + "ops/test_cos.py", + "ops/test_to_copy.py", + ] + + # Quantization + test_files += [ + "quantizer/test_generic_annotater.py", + ] + + # Misc tests + test_files += [ + "misc/test_compile_spec.py", + "misc/test_tosa_spec.py", + "misc/test_bn_relu_folding_qat.py", + "misc/test_custom_partition.py", + "misc/test_debug_hook.py", + # "misc/test_dim_order.py", (TODO - T238390249) + "misc/test_outputs_order.py", + ] + + TESTS = {} + + for test_file in test_files: + test_file_name = paths.basename(test_file) + test_name = test_file_name.replace("test_", "").replace(".py", "") + + python_pytest( + name = test_name, + srcs = [test_file], + pytest_config = "pytest.ini", + resources = ["conftest.py"], + compile = "with-source", + typing = False, + preload_deps = [ + "//executorch/kernels/quantized:custom_ops_generated_lib", + ], + deps = [ + "//executorch/backends/arm/test/tester/fb:arm_tester_fb" if is_fbcode else "//executorch/backends/arm/test:arm_tester", + "//executorch/backends/arm/test:conftest", + "//executorch/backends/arm/test/misc:dw_convs_shared_weights_module", + "//executorch/backends/arm:ethosu", + "//executorch/backends/arm/tosa:compile_spec", + "//executorch/backends/arm/tosa:partitioner", + "//executorch/backends/arm:vgf", + "//executorch/exir:lib", + "fbsource//third-party/pypi/pytest:pytest", + "fbsource//third-party/pypi/parameterized:parameterized", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_baremetal.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_baremetal.sh new file mode 100755 index 0000000..4561e05 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_baremetal.sh @@ -0,0 +1,347 @@ +#!/bin/bash +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# TODO: Rename this script + +set -e + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) + +# Executorch root +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +cd "${et_root_dir}" +pwd +scratch_dir=${et_root_dir}/examples/arm/arm-scratch +setup_path_script=${scratch_dir}/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + + +TEST_SUITE=$1 + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } +source ${setup_path_script} + +help() { + echo "Usage:" + echo " $0 " + echo " where can be any of:" + # This will list all lines in this file that is starting with test_ remove () { and print it as a list. + # e,g, "test_pytest() { # Test ops and other things" -> test_pytest # Test ops and other things + echo "all # run all tests" + grep "^test_" $0 | sed 's/([^)]*)[[:space:]]*{*//g' + exit +} + +if [[ -z "${TEST_SUITE:-}" ]]; then + echo "Missing test suite name, exiting..." + help +else + echo "Run Arm baremetal test suite ${TEST_SUITE}" +fi + +TEST_SUITE_NAME="$(basename "$0") ${TEST_SUITE}" + +all() { # Run all tests + # This will list all lines in this file that is starting with test_ remove () { and add this script name in + # front of it and execute it in a sub shell + # e.g. from this file: + # + # test_pytest() { # Test ops and other things + # bla bla bla + # } + # test_pytest_ethosu_fvp() { # Same as test_pytest but ... + # bla bla bla + # } + #... + # become a small script: + # ---- + # backends/arm/test/test_arm_baremetal.sh test_pytest # Test ops and other things + # backends/arm/test/test_arm_baremetal.sh test_pytest_ethosu_fvp # Same as test_pytest but ... + # ... + # ---- + # That is executed + echo "${TEST_SUITE_NAME}: Run all tests" + grep "^test_" backends/arm/test/test_arm_baremetal.sh | sed 's/([^)]*)[[:space:]]*{*//g' | sed "s|^|$0 |" | sh + echo "${TEST_SUITE_NAME}: PASS" +} + +# ------------------------------------------- +# -------- Non target-specific tests -------- +# ------------------------------------------- +test_pytest_ops_no_target() { + echo "${TEST_SUITE_NAME}: Run pytest ops for target-less tests" + + # Run arm baremetal pytest tests without target + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k no_target + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_no_target() { + echo "${TEST_SUITE_NAME}: Run pytest models for target-less tests" + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + # Run arm baremetal pytest tests without FVP + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k no_target + echo "${TEST_SUITE_NAME}: PASS" +} + +# ------------------------------------- +# -------- TOSA specific tests -------- +# ------------------------------------- +test_pytest_ops_tosa() { + echo "${TEST_SUITE_NAME}: Run pytest ops for TOSA" + + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k tosa + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_tosa() { + echo "${TEST_SUITE_NAME}: Run pytest models for TOSA" + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k tosa + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_tosa() { + echo "${TEST_SUITE_NAME}: Test TOSA delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test target TOSA" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=TOSA-1.0+INT --model_name=add + examples/arm/run.sh --et_build_root=arm_test/test_run --target=TOSA-1.0+INT --model_name=mul + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ---------------------------------------------- +# -------- Arm Ethos-U55 specific tests -------- +# ---------------------------------------------- +test_pytest_ops_ethos_u55() { + echo "${TEST_SUITE_NAME}: Run pytest ops for Arm Ethos-U55" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k u55 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_ethos_u55() { + echo "${TEST_SUITE_NAME}: Run pytest models for Arm Ethos-U55" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k u55 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_ethos_u55() { + echo "${TEST_SUITE_NAME}: Test ethos-u55 delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test target Ethos-U55" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-64 --model_name=add + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-256 --model_name=add --bundleio --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=mul + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-256 --model_name=add --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=mul --bundleio --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=mul --bundleio --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --bundleio --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=examples/arm/example_modules/add.py + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=examples/arm/example_modules/add.py --bundleio + + # Cortex-M op tests + echo "${TEST_SUITE_NAME}: Test target Cortex-M55 (on Ethos-U55)" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --bundleio --no_delegate --select_ops_list="aten::add.out" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=qadd --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=qops --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=qops --bundleio --no_delegate --select_ops_list="aten::sub.out,aten::add.out,aten::mul.out" + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ---------------------------------------------- +# -------- Arm Ethos-U85 specific tests -------- +# ---------------------------------------------- +test_pytest_ops_ethos_u85() { + echo "${TEST_SUITE_NAME}: Run pytest ops for Arm Ethos-U85" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + # Run arm baremetal pytest tests with FVP + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k u85 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_ethos_u85() { + echo "${TEST_SUITE_NAME}: Run pytest models for Arm Ethos-U85" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k u85 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_ethos_u85() { + echo "${TEST_SUITE_NAME}: Test ethos-u85 delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=add + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-256 --model_name=add --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-512 --model_name=add --bundleio --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-1024 --model_name=add --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-2048 --model_name=mul --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=mul --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=mul --bundleio --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-256 --model_name=mul --bundleio --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-1024 --model_name=examples/arm/example_modules/add.py --bundleio + + # Cortex-M op tests + echo "${TEST_SUITE_NAME}: Test target Cortex-M55 (on Ethos-U85)" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=qops --bundleio + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ---------------------------------------------------------- +# -------- Vulkan Graph Format (VGF) specific tests -------- +# ---------------------------------------------------------- +test_pytest_ops_vkml() { + echo "${TEST_SUITE_NAME}: Run pytest operator tests with VKML runtime" + + source backends/arm/test/setup_testing_vkml.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ \ + --ignore=backends/arm/test/models -k _vgf_ + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_vkml() { + echo "${TEST_SUITE_NAME}: Run pytest model tests with VKML runtime" + + source backends/arm/test/setup_testing_vkml.sh + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k _vgf_ + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_vkml() { + echo "${TEST_SUITE_NAME}: Test VKML delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test VKML" + out_folder="arm_test/test_run" + + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=add --output=${out_folder}/runner + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=mul --output=${out_folder}/runner + + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=qadd --output=${out_folder}/runner + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=qops --output=${out_folder}/runner + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ------------------------------------ +# -------- Miscelaneous tests -------- +# ------------------------------------ +test_model_smollm2-135M() { + echo "${TEST_SUITE_NAME}: Test SmolLM2-135M on Ethos-U85" + + # Build common libs once + python3 backends/arm/test/test_model.py --test_output=arm_test/test_model --build_libs + + python3 backends/arm/test/test_model.py --test_output=arm_test/test_model --target=ethos-u85-128 --model=smollm2 --extra_flags="-DEXECUTORCH_SELECT_OPS_LIST=dim_order_ops::_to_dim_order_copy.out" + + echo "${TEST_SUITE_NAME}: PASS" + + +} + +test_smaller_stories_llama() { + echo "${TEST_SUITE_NAME}: Test smaller_stories_llama" + + backends/arm/scripts/build_executorch.sh + + mkdir -p stories110M + pushd stories110M + wget -N https://huggingface.co/karpathy/tinyllamas/resolve/main/stories110M.pt + echo '{"dim": 768, "multiple_of": 32, "n_heads": 12, "n_layers": 12, "norm_eps": 1e-05, "vocab_size": 32000}' > params.json + popd + + # Get path to source directory + pytest \ + -c /dev/null \ + --verbose \ + --color=yes \ + --numprocesses=auto \ + --log-level=DEBUG \ + --junit-xml=stories110M/test-reports/unittest.xml \ + -s \ + backends/arm/test/models/test_llama.py \ + --llama_inputs stories110M/stories110M.pt stories110M/params.json stories110m + + echo "${TEST_SUITE_NAME}: PASS" +} + +test_memory_allocation() { + echo "${TEST_SUITE_NAME}: Test ethos-u memory allocation with run.sh" + + mkdir -p arm_test/test_run + # Ethos-U85 + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py &> arm_test/test_run/full.log + python3 backends/arm/test/test_memory_allocator_log.py --log arm_test/test_run/full.log \ + --require "model_pte_program_size" "<= 3100 B" \ + --require "method_allocator_planned" "<= 64 B" \ + --require "method_allocator_loaded" "<= 1024 B" \ + --require "method_allocator_input" "<= 16 B" \ + --require "Total DRAM used" "<= 0.06 KiB" + echo "${TEST_SUITE_NAME}: PASS" +} + +test_undefinedbehavior_sanitizer() { + echo "${TEST_SUITE_NAME}: Test ethos-u executor_runner with UBSAN" + + mkdir -p arm_test/test_run + # Ethos-U85 + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py --build_type=UndefinedSanitizer + echo "${TEST_SUITE_NAME}: PASS" +} + +test_address_sanitizer() { + echo "${TEST_SUITE_NAME}: Test ethos-u executor_runner with ASAN" + + mkdir -p arm_test/test_run + # Ethos-U85 + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py --build_type=AddressSanitizer + echo "${TEST_SUITE_NAME}: PASS" +} + + +${TEST_SUITE} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_ootb.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_ootb.sh new file mode 100755 index 0000000..43a1bff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_arm_ootb.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash + +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eo pipefail + +help() { + echo "Usage:" + echo " $0 [TESTNAME]" + echo "Without TESTNAME all tests will run; otherwise choose one of:" + # This will list all lines in this file that is starting with test_ remove () { and print it as a list. + # e,g, "test_pytest() { # Test ops and other things" -> test_pytest # Test ops and other things + grep "^run_" $0 | sed 's/([^)]*)[[:space:]]*{*//g' + exit +} + +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + help +fi + +if [[ $# -eq 0 ]]; then + TEST_SUITES=(run_ootb_tests_ethos_u run_ootb_tests_tosa run_deit_e2e_ethos_u) +else + TEST_SUITES=("$1") +fi + + +run_ootb_tests_ethos_u() { + echo "$FUNCNAME: Running out-of-the-box tests for Arm Ethos-U" + jupyter nbconvert \ + --to notebook \ + --execute examples/arm/ethos_u_minimal_example.ipynb + echo "${FUNCNAME}: PASS" +} + +run_ootb_tests_tosa() { + echo "$FUNCNAME: Running out-of-the-box tests for TOSA" + jupyter nbconvert \ + --to notebook \ + --execute backends/arm/scripts/TOSA_minimal_example.ipynb + echo "${FUNCNAME}: PASS" +} + +run_deit_e2e_ethos_u() { + echo "$FUNCNAME: Fine-tune, export, build, and run the DEiT e2e test" + + local script_dir + script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) + et_root_dir=$(cd "${script_dir}/../../.." && pwd) + local example_dir="${et_root_dir}/examples/arm/image_classification_example" + local work_root="${et_root_dir}/arm_test/deit_tiny_ootb_smoke" + local model_dir="${work_root}/deit_tiny_finetuned" + local export_dir="${work_root}/export" + local build_dir="${work_root}/simple_app_deit_tiny" + local image_path="${work_root}/dog.bmp" + local pte_path="${export_dir}/deit_tiny_smoke.pte" + local toolchain_file="${et_root_dir}/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake" + echo "${FUNCNAME}: Work root is ${work_root}; existing artifacts will be reused if present" + + mkdir -p "${model_dir}" "${export_dir}" "${build_dir}" + + setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh + source ${setup_path_script} + + source ${et_root_dir}/backends/arm/scripts/utils.sh + local n_proc="$(get_parallel_jobs)" + + # Build ExecuTorch + echo "${FUNCNAME}: Building ExecuTorch (if needed)" + cmake --preset arm-baremetal -B "${et_root_dir}/cmake-out-arm" + cmake --build "${et_root_dir}/cmake-out-arm" --target install -j"$n_proc" + + # Install requirements + pip install -r examples/arm/image_classification_example/requirements.txt + + # Get and finetune model + echo "${FUNCNAME}: Running DeiT fine-tuning script" + python3 "${example_dir}/model_export/train_deit.py" \ + --output-dir "${model_dir}" \ + --num-epochs 1 + + # Export model to pte + local final_model_dir="${model_dir}/final_model" + echo "${FUNCNAME}: Exporting quantized PTE from ${final_model_dir}" + python3 "${example_dir}/model_export/export_deit.py" \ + --model-path "${final_model_dir}" \ + --output-path "${pte_path}" \ + --num-calibration-samples 100 + + [[ -f "${pte_path}" ]] || { + echo "${FUNCNAME}: Missing PTE at ${pte_path}" + return 1 + } + + # Download demo image for inference + local image_url="https://gitlab.arm.com/artificial-intelligence/ethos-u/ml-embedded-evaluation-kit/-/raw/main/resources/img_class/samples/dog.bmp?ref_type=heads" + if [[ ! -f "${image_path}" ]]; then + echo "${FUNCNAME}: Downloading sample image from ${image_url}" + wget -O "${image_path}" "${image_url}" + else + echo "${FUNCNAME}: Reusing sample image at ${image_path}" + fi + + # Build application + echo "${FUNCNAME}: Configuring the minimal application" + cmake \ + -S "${example_dir}/runtime" \ + -B "${build_dir}" \ + -DCMAKE_TOOLCHAIN_FILE="${toolchain_file}" \ + -DET_PTE_FILE_PATH="${pte_path}" \ + -DIMAGE_PATH="${image_path}" \ + -DET_BUILD_DIR_PATH="${et_root_dir}/cmake-out-arm" + + echo "${FUNCNAME}: Building img_class_example" + cmake --build "${build_dir}" -j"$n_proc" --target img_class_example + + # Run application on FVP + local fvp_bin="${FVP_BINARY:-FVP_Corstone_SSE-320}" + local elf="${build_dir}/img_class_example" + + echo "${FUNCNAME}: Running on ${fvp_bin}" + "${fvp_bin}" \ + -C mps4_board.subsystem.ethosu.num_macs=256 \ + -C mps4_board.visualisation.disable-visualisation=1 \ + -C vis_hdlcd.disable_visualisation=1 \ + -C mps4_board.telnetterminal0.start_telnet=0 \ + -C mps4_board.uart0.out_file="-" \ + -C mps4_board.uart0.shutdown_on_eot=1 \ + -a "${elf}" \ + -C mps4_board.subsystem.ethosu.extra_args="--fast" + + echo "${FUNCNAME}: PASS" +} + +for suite in "${TEST_SUITES[@]}"; do + "${suite}" +done diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_memory_allocator_log.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_memory_allocator_log.py new file mode 100644 index 0000000..3853b60 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_memory_allocator_log.py @@ -0,0 +1,170 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +""" +Check log files for memory metrics and compare them against thresholds. + +Usage example: + python3 test_memory_allocator_log.py \ + --log path/to/log.txt \ + --require "Total SRAM used" "<= 310 KiB" \ + --require "method_allocator_input" "<= 4 B" +""" + +import argparse +import re +import sys +from typing import List, Optional, Tuple + + +def unit_factor(u: str) -> float: + if not u: + return 1.0 + ul = u.strip().lower() + table = { + "b": 1, + "byte": 1, + "bytes": 1, + "kb": 1000, + "mb": 1000**2, + "gb": 1000**3, + "kib": 1024, + "mib": 1024**2, + "gib": 1024**3, + } + if ul in table: + return float(table[ul]) + return 1.0 + + +def parse_value(text_num: str, text_unit: Optional[str]) -> float: + return float(text_num) * unit_factor(text_unit or "") + + +def parse_cond(cond: str) -> Tuple[str, float, str]: + # Regexp explained. Example of things it will parse: + # "< 310 KiB", ">=10MB", "== 42", "!=3 bytes", "<=0.5 MiB" + + # The regexp explained in detail: + # ^: anchor the match to the start and end of the string (no extra chars allowed). + # \s*: optional whitespace (spaces, tabs, etc.). + # (<=|>=|==|!=|<|>): capturing group 1. One of the comparison operators: <=, >=, ==, !=, <, >. + # \s*: optional whitespace. + # ([0-9]+(?:\.[0-9]+)?): capturing group 2. A number: + # [0-9]+: one or more digits (the integer part). + # (?:\.[0-9]+)?: optional non-capturing group for a fractional part like .25. + # \s*: optional whitespace between number and unit + # ([A-Za-z]+)?: capturing group 3, optional. A unit made of letters only (e.g., B, KB, KiB, MB, MiB). Case# insensitive by class choice. + # \s*: optional trailing whitespace. + m = re.match( + r"^\s*(<=|>=|==|!=|<|>)\s*([0-9]+(?:\.[0-9]+)?)\s*([A-Za-z]+)?\s*$", cond + ) + if not m: + raise ValueError(f"Invalid condition: {cond}") + op, num, unit = m.groups() + return op, float(num), (unit or "") + + +def compare(a: float, b: float, op: str) -> bool: + return { + "<": a < b, + "<=": a <= b, + ">": a > b, + ">=": a >= b, + "==": abs(a - b) < 1e-9, + "!=": abs(a - b) >= 1e-9, + }[op] + + +def find_metric_value(line: str, label: str) -> Tuple[Optional[str], Optional[str]]: + # Same regexp as parse_cond() but without the first group of matching comparison operators + # First go, search for the pattern but escape and ignore cases + # The regexp: + # ([0-9]+(?:\.[0-9]+)?) — capturing group 1: a decimal number + # [0-9]+ — one or more digits (integer part) + # (?:\.[0-9]+)? — optional fractional part like .25 (non-capturing) + # \s* — optional whitespace between number and unit + # ([A-Za-z]+)? — capturing group 2 (optional): a unit made only of letters (e.g., B, KB, KiB, MB) + m = re.search( + re.escape(label) + r".*?([0-9]+(?:\.[0-9]+)?)\s*([A-Za-z]+)?", + line, + flags=re.IGNORECASE, + ) + if m: + return m.group(1), m.group(2) + # Second go, same regexp as above but not caring about label. If + # no number was tied to a label be happy just salvaging it from + # the line + m = re.search(r"([0-9]+(?:\.[0-9]+)?)\s*([A-Za-z]+)?", line) + if m: + return m.group(1), m.group(2) + return None, None + + +def first_line_with_label(lines: List[str], label: str) -> Optional[str]: + label_lc = label.lower() + return next((ln for ln in lines if label_lc in ln.lower()), None) + + +def check_requirement(label: str, cond: str, lines: List[str]) -> Optional[str]: + op, thr_num, thr_unit = parse_cond(cond) + matched = first_line_with_label(lines, label) + if matched is None: + return f"{label}: not found in log" + + num_str, unit_str = find_metric_value(matched, label) + if num_str is None: + return f"{label}: value not found on line: {matched.strip()}" + + left_bytes = parse_value(num_str, unit_str) + right_bytes = parse_value(str(thr_num), thr_unit or (unit_str or "")) + ok = compare(left_bytes, right_bytes, op) + + human_left = f"{num_str} {unit_str or 'B'}" + human_right = f"{thr_num:g} {thr_unit or (unit_str or 'B')}" + print( + f"[check] {label}: {human_left} {op} {human_right} -> {'OK' if ok else 'FAIL'}" + ) + + if ok: + return None + return f"{label}: {human_left} not {op} {human_right}" + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--log", required=True, help="Path to log file") + parser.add_argument( + "--require", + action="append", + nargs=2, + metavar=("LABEL", "COND"), + default=[], + help="""Required label and condition consisting + of a number and unit. Example: \"Total DRAM + used\" \"<= 0.06 KiB\"""", + ) + args = parser.parse_args() + + with open(args.log, "r", encoding="utf-8", errors="ignore") as f: + lines = f.readlines() + + failures: List[str] = [] + for label, cond in args.require: + msg = check_requirement(label, cond, lines) + if msg: + failures.append(msg) + + if failures: + print("Failures:") + for msg in failures: + print(" - " + msg) + return 1 + + print("All checks passed.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_model.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_model.py new file mode 100755 index 0000000..87a92c2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/test_model.py @@ -0,0 +1,345 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os +import subprocess # nosec B404 - launches trusted build/test scripts +import sys +import time +from typing import Sequence + + +def get_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--build_libs", + action="store_true", + required=False, + default=False, + help="Flag for building executorch libs needed for this testing", + ) + parser.add_argument( + "--model", + required=False, + default=None, + help="Model to use that aot_arm_compiler.py can handle, can be a builtin, examples/models or a filename.", + ) + parser.add_argument( + "--target", + required=False, + default=None, + help="Target name", + ) + parser.add_argument( + "--test_output", + required=False, + default="arm_test", + help="Output folder used for build and test defults to arm_test", + ) + parser.add_argument( + "--system_config", + required=False, + default=None, + help="Target specific system_config (See Vela compiler)", + ) + parser.add_argument( + "--memory_mode", + required=False, + default=None, + help="Target specific memory_mode (See Vela compiler)", + ) + parser.add_argument( + "--no_intermediate", + action="store_true", + required=False, + default=False, + help="Don't save temporary files during compilation", + ) + parser.add_argument( + "--no_quantize", + action="store_true", + required=False, + default=False, + help="Don't quantize model", + ) + parser.add_argument( + "--extra_flags", + required=False, + default="", + help="Extra cmake flags to pass the when building the executor_runner", + ) + parser.add_argument( + "--extra_runtime_flags", + required=False, + default="", + help="Extra runtime flags to pass the final runner/executable", + ) + parser.add_argument( + "--timeout", + required=False, + default=60 * 20, + help="Timeout in seconds used when running the model", + ) + args = parser.parse_args() + + if args.model and "ethos-u" in args.target and args.system_config is None: + if "u55" in args.target: + args.system_config = "Ethos_U55_High_End_Embedded" + elif "u85" in args.target: + args.system_config = "Ethos_U85_SYS_DRAM_Mid" + else: + raise RuntimeError(f"Invalid target name {args.target}") + + if args.model and "ethos-u" in args.target and args.memory_mode is None: + if "u55" in args.target: + args.memory_mode = "Shared_Sram" + elif "u85" in args.target: + args.memory_mode = "Dedicated_Sram_384KB" + else: + raise RuntimeError(f"Invalid target name {args.target}") + + return args + + +def run_external_cmd(cmd: Sequence[str]) -> None: + print("CALL:", *cmd, sep=" ") + try: + subprocess.check_call( + cmd + ) # nosec B603 - cmd assembled from vetted scripts/flags + except subprocess.CalledProcessError as err: + print("ERROR called: ", *cmd, sep=" ") + print(f"Failed with: {err.returncode}") + sys.exit(err.returncode) + + +def build_libs(et_build_root: str, script_path: str): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "build_executorch.sh"), + f"--et_build_root={et_build_root}", + "--build_type=Release", + "--devtools", + "--etdump", + ] + ) + + +def build_pte( + et_build_root: str, + model_name: str, + target: str, + system_config: str, + memory_mode: str, + build_output: str, + no_intermediate: bool, + no_quantize: bool, +): + command_list = [ + "python3", + "-m", + "examples.arm.aot_arm_compiler", + "--delegate", + "--bundleio", + f"--model_name={model_name}", + f"--target={target}", + f"--output={build_output}", + ] + + if "vgf" != target: + command_list.append(f"--system_config={system_config}") + command_list.append(f"--memory_mode={memory_mode}") + + if not no_quantize: + command_list.append("--quantize") + + if not no_intermediate: + command_list.append(f"--intermediate={output}") + + run_external_cmd(command_list) + + pte_file_ending = "bpte" + pte_file = os.path.join( + output, f"{model_name}_arm_delegate_{args.target}.{pte_file_ending}" + ) + + return pte_file + + +def build_ethosu_runtime( + et_build_root: str, + script_path: str, + pte_file: str, + target: str, + system_config: str, + memory_mode: str, + extra_flags: str, + elf_build_path: str, +): + elf_build_path = os.path.join(elf_build_path, "cmake-out") + run_external_cmd( + [ + "bash", + os.path.join(script_path, "build_executor_runner.sh"), + f"--et_build_root={et_build_root}", + f"--pte={pte_file}", + "--bundleio", + "--etdump", + f"--target={target}", + "--build_type=Release", + f"--system_config={system_config}", + f"--memory_mode={memory_mode}", + f"--extra_build_flags=-DET_LOG_DUMP_OUTPUT=OFF {extra_flags}", + f"--output={elf_build_path}", + ] + ) + + elf_file = os.path.join(elf_build_path, "arm_executor_runner") + return elf_file + + +def run_elf_with_fvp(script_path: str, elf_file: str, target: str, timeout: int): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "run_fvp.sh"), + f"--elf={elf_file}", + f"--target={target}", + f"--timeout={timeout}", + ] + ) + + +def build_vkml_runtime( + et_build_root: str, + script_path: str, + extra_flags: str, + build_path: str, +): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "build_executor_runner_vkml.sh"), + f"--et_build_root={et_build_root}", + "--etdump", + "--bundleio", + "--build_type=Release", + f"--extra_build_flags=-DET_DUMP_OUTPUT=OFF {extra_flags}", + f"--output={build_path}", + ] + ) + + runner = os.path.join(build_path, "executor_runner") + return runner + + +def run_vkml(script_path: str, pte_file: str, runner_build_path: str, extra_flags: str): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "run_vkml.sh"), + f"--model={pte_file}", + f"--build_path={runner_build_path}", + f"--optional_flags={extra_flags}", + ] + ) + + +if __name__ == "__main__": + total_start_time = time.perf_counter() + args = get_args() + script_path = os.path.join("backends", "arm", "scripts") + + if args.build_libs: + start_time = time.perf_counter() + build_libs(args.test_output, script_path) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] Build needed executorch libs" + ) + + if args.model: + model_name = args.model.split(" ")[0].split(";")[0] + if not model_name: + print("ERROR: Bad --model specified") + if not args.target: + print("ERROR: --model need --target to also be set") + + output = os.path.join( + args.test_output, f"{model_name}_arm_delegate_{args.target}" + ) + + start_time = time.perf_counter() + pte_file = build_pte( + args.test_output, + model_name, + args.target, + args.system_config, + args.memory_mode, + output, + args.no_intermediate, + args.no_quantize, + ) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] PTE file created: {pte_file}" + ) + + if "vgf" == args.target: + build_path = os.path.join( + output, f"{model_name}_arm_delegate_{args.target}" + ) + + start_time = time.perf_counter() + vkml_runner = build_vkml_runtime( + args.test_output, + script_path, + args.extra_flags, + build_path, + ) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] ELF file created: {vkml_runner}" + ) + + start_time = time.perf_counter() + run_vkml(script_path, pte_file, build_path, args.extra_runtime_flags) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] Tested VKML runner: {vkml_runner}" + ) + + elif "ethos-u" in args.target: + elf_build_path = os.path.join( + output, f"{model_name}_arm_delegate_{args.target}" + ) + + start_time = time.perf_counter() + elf_file = build_ethosu_runtime( + args.test_output, + script_path, + pte_file, + args.target, + args.system_config, + args.memory_mode, + args.extra_flags, + elf_build_path, + ) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] ELF file created: {elf_file}" + ) + + start_time = time.perf_counter() + run_elf_with_fvp(script_path, elf_file, args.target, args.timeout) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] Tested elf on FVP {elf_file}" + ) + total_end_time = time.perf_counter() + print( + f"[Test model: {total_end_time - total_start_time:.2f} s total] Model: {model_name} on {args.target} -> PASS" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/__init__.py new file mode 100644 index 0000000..caafcc4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2024 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/analyze_output_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/analyze_output_utils.py new file mode 100644 index 0000000..527413e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/analyze_output_utils.py @@ -0,0 +1,346 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import tempfile +from typing import Any, cast, Sequence + +import torch +from executorch.backends.arm.test.runner_utils import ( + get_input_quantization_params, + get_output_quantization_params, +) + +from executorch.backends.test.harness.stages import StageType + +logger = logging.getLogger(__name__) + + +TensorLike = torch.Tensor | tuple[torch.Tensor, ...] + + +def _ensure_tensor(value: TensorLike) -> torch.Tensor: + if isinstance(value, torch.Tensor): + return value + if value and isinstance(value[0], torch.Tensor): + return value[0] + raise TypeError("Expected a Tensor or a non-empty tuple of Tensors") + + +def _print_channels( + result: torch.Tensor, + reference: torch.Tensor, + channels_close: Sequence[bool], + C: int, + H: int, + W: int, + rtol: float, + atol: float, +) -> str: + output_str = "" + exp = "000" + booldata = False + if reference.dtype == torch.bool or result.dtype == torch.bool: + booldata = True + + for c in range(C): + if channels_close[c]: + continue + if not booldata: + max_diff = torch.max(torch.abs(reference - result)) + exp = f"{max_diff:2e}"[-3:] + output_str += f"channel {c} (e{exp})\n" + else: + max_diff = torch.max(reference ^ result) + output_str += f"channel {c} (bool)\n" + + for y in range(H): + res = "[" + for x in range(W): + if torch.allclose(reference[c, y, x], result[c, y, x], rtol, atol): + if not booldata: + res += " . " + else: + res += " . " + else: + if not booldata: + diff = (reference[c, y, x] - result[c, y, x]) / 10 ** (int(exp)) + res += f"{diff: .2f} " + else: + diff = reference[c, y, x] ^ result[c, y, x] + res += " X " + + # Break early for large widths + if x == 16: + res += "..." + break + + res += "]\n" + output_str += res + + return output_str + + +def _print_elements( + result: torch.Tensor, + reference: torch.Tensor, + C: int, + H: int, + W: int, + rtol: float, + atol: float, +) -> str: + output_str = "" + for y in range(H): + res = "[" + for x in range(W): + result_channels = result[:, y, x] + reference_channels = reference[:, y, x] + + n_errors = 0 + for a, b in zip(result_channels, reference_channels): + if not torch.allclose(a, b, rtol, atol): + n_errors = n_errors + 1 + + if n_errors == 0: + res += ". " + else: + res += f"{n_errors} " + + # Break early for large widths + if x == 16: + res += "..." + break + + res += "]\n" + output_str += res + + return output_str + + +def print_error_diffs( # noqa: C901 + tester_or_result: Any, + result_or_reference: TensorLike, + reference: TensorLike | None = None, + # Force remaining args to be keyword-only to keep the two positional call patterns unambiguous. + *, + quantization_scale: float | None = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: float = 0, +) -> None: + """ + Prints the error difference between a result tensor and a reference tensor in NCHW format. + Certain formatting rules are applied to clarify errors: + + - Batches are only expanded if they contain errors. + -> Shows if errors are related to batch handling + - If errors appear in all channels, only the number of errors in each HW element are printed. + -> Shows if errors are related to HW handling + - If at least one channel is free from errors, or if C==1, errors are printed channel by channel + -> Shows if errors are related to channel handling or single errors such as rounding/quantization errors + + Example output of shape (3,3,2,2): + + ############################ ERROR DIFFERENCE ############################# + BATCH 0 + . + BATCH 1 + [. . ] + [. 3 ] + BATCH 2 + channel 1 (e-03) + [ 1.85 . ] + [ . 9.32 ] + + MEAN MEDIAN MAX MIN (error as % of reference output range) + 60.02% 55.73% 100.17% 19.91% + ########################################################################### + + + """ + if reference is None: + result = _ensure_tensor(cast(TensorLike, tester_or_result)) + reference_tensor = _ensure_tensor(result_or_reference) + else: + result = _ensure_tensor(result_or_reference) + reference_tensor = _ensure_tensor(reference) + + if result.shape != reference_tensor.shape: + raise ValueError( + f"Output needs to be of same shape: {result.shape} != {reference_tensor.shape}" + ) + shape = result.shape + rank = len(shape) + + if rank == 5: + N, C, D, H, W = shape + elif rank == 4: + N, C, H, W = shape + D = 1 + elif rank == 3: + C, H, W = shape + N, D = 1, 1 + elif rank == 2: + H, W = shape + N, C, D = 1, 1, 1 + elif rank == 1: + W = shape[0] + N, C, D, H = 1, 1, 1, 1 + elif rank == 0: + N = C = D = H = W = 1 + else: + raise ValueError("Invalid tensor rank") + + if rank < 3: + C = 1 + if rank < 2: + H = 1 + if rank < 1: + W = 1 + + if quantization_scale is not None: + atol += quantization_scale * qtol + + # Reshape tensors to 4D NCHW format, optionally folding depth into batch. + total_batches = N * D + result = torch.reshape(result, (total_batches, C, H, W)) + reference_tensor = torch.reshape(reference_tensor, (total_batches, C, H, W)) + + output_str = "" + for idx in range(total_batches): + batch_idx = idx // D if D > 0 else idx + depth_idx = idx % D if D > 0 else 0 + if D > 1: + output_str += f"BATCH {batch_idx} DEPTH {depth_idx}\n" + else: + output_str += f"BATCH {batch_idx}\n" + + result_batch = result[idx, :, :, :] + reference_batch = reference_tensor[idx, :, :, :] + + is_close = torch.allclose(result_batch, reference_batch, rtol, atol) + if is_close: + output_str += ".\n" + else: + channels_close: list[bool] = [False] * C + for c in range(C): + result_hw = result[idx, c, :, :] + reference_hw = reference_tensor[idx, c, :, :] + + channels_close[c] = torch.allclose(result_hw, reference_hw, rtol, atol) + + if any(channels_close) or len(channels_close) == 1: + output_str += _print_channels( + result[idx, :, :, :], + reference_tensor[idx, :, :, :], + channels_close, + C, + H, + W, + rtol, + atol, + ) + else: + output_str += _print_elements( + result[idx, :, :, :], + reference_tensor[idx, :, :, :], + C, + H, + W, + rtol, + atol, + ) + if reference_batch.dtype == torch.bool or result_batch.dtype == torch.bool: + mismatches = (reference_batch != result_batch).sum().item() + total = reference_batch.numel() + output_str += f"(BOOLEAN tensor) {mismatches} / {total} elements differ ({mismatches / total:.2%})\n" + + # Only compute numeric error metrics if tensor is not boolean + if reference_tensor.dtype != torch.bool and result.dtype != torch.bool: + reference_range = torch.max(reference_tensor) - torch.min(reference_tensor) + diff = torch.abs(reference_tensor - result).flatten() + diff = diff[diff.nonzero()] + if not len(diff) == 0: + diff_percent = diff / reference_range + output_str += "\nMEAN MEDIAN MAX MIN (error as % of reference output range)\n" + output_str += f"{torch.mean(diff_percent):<8.2%} {torch.median(diff_percent):<8.2%} {torch.max(diff_percent):<8.2%} {torch.min(diff_percent):<8.2%}\n" + + # Over-engineer separators to match output width + lines = output_str.split("\n") + line_length = [len(line) for line in lines] + longest_line = max(line_length) + title = "# ERROR DIFFERENCE #" + separator_length = max(longest_line, len(title)) + + pre_title_length = max(0, ((separator_length - len(title)) // 2)) + post_title_length = max(0, ((separator_length - len(title) + 1) // 2)) + start_separator = ( + "\n" + "#" * pre_title_length + title + "#" * post_title_length + "\n" + ) + output_str = start_separator + output_str + end_separator = "#" * separator_length + "\n" + output_str += end_separator + + logger.error(output_str) + + +def dump_error_output( + tester: Any, + reference_output: TensorLike, + stage_output: TensorLike, + quantization_scale: float | None = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: float = 0, +) -> None: + """ + Prints Quantization info and error tolerances, and saves the differing tensors to disc. + """ + # Capture assertion error and print more info + banner = "=" * 40 + "TOSA debug info" + "=" * 40 + logger.error(banner) + path_to_tosa_files = tester.compile_spec.get_intermediate_path() + + if path_to_tosa_files is None: + path_to_tosa_files = tempfile.mkdtemp(prefix="executorch_result_dump_") + + export_stage = tester.stages.get(StageType.EXPORT, None) + quantize_stage = tester.stages.get(StageType.QUANTIZE, None) + if export_stage is not None and quantize_stage is not None: + output_node = export_stage.artifact.graph_module.graph.output_node() + qp_input = get_input_quantization_params(export_stage.artifact) + qp_output = get_output_quantization_params(output_node) + logger.error(f"Input QuantArgs: {qp_input}") + logger.error(f"Output QuantArgs: {qp_output}") + + logger.error(f"{path_to_tosa_files=}") + import os + + torch.save( + stage_output, + os.path.join(path_to_tosa_files, "torch_tosa_output.pt"), + ) + torch.save( + reference_output, + os.path.join(path_to_tosa_files, "torch_ref_output.pt"), + ) + logger.error(f"{atol=}, {rtol=}, {qtol=}") + + +if __name__ == "__main__": + """This is expected to produce the example output of print_diff""" + torch.manual_seed(0) + a = torch.rand(3, 3, 2, 2) * 0.01 + b = a.clone().detach() + logger.info(b) + + # Errors in all channels in element (1,1) + a[1, :, 1, 1] = 0 + # Errors in (0,0) and (1,1) in channel 1 + a[2, 1, 1, 1] = 0 + a[2, 1, 0, 0] = 0 + + print_error_diffs(a, b) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/arm_tester.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/arm_tester.py new file mode 100644 index 0000000..66f90ea --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/arm_tester.py @@ -0,0 +1,1149 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import copy + +import logging +import shutil +import tempfile + +from collections import Counter, defaultdict +from pprint import pformat +from typing import ( + Any, + Callable, + cast, + Dict, + Iterable, + List, + no_type_check, + Optional, + Sequence, + Tuple, + Type, + Union, +) + +import executorch.backends.xnnpack.test.tester.tester as tester + +import torch.fx +import torch.utils._pytree as pytree + +import tosa_serializer as ts + +from executorch.backends.arm._passes.arm_pass_manager import ArmPassManager + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.ethosu import EthosUCompileSpec +from executorch.backends.arm.quantizer import get_symmetric_quantization_config +from executorch.backends.arm.test.runner_utils import ( + dbg_tosa_fb_to_json, + get_output_quantization_params, + TosaReferenceModelDispatch, +) + +from executorch.backends.arm.test.tester.analyze_output_utils import ( + dump_error_output, + print_error_diffs, +) +from executorch.backends.arm.test.tester.quantize import ArmQuantize as Quantize +from executorch.backends.arm.test.tester.serialize import Serialize + +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.mapping import extract_tensor_meta + +from executorch.backends.arm.util._factory import ( + create_partitioner, + create_quantizer, + parse_compile_spec, +) +from executorch.backends.arm.vgf import VgfCompileSpec + +from executorch.backends.test.harness.error_statistics import ErrorStatistics +from executorch.backends.test.harness.stages import Stage, StageType +from executorch.backends.xnnpack.test.tester import ( + Partition as XnnpackPartitionStage, + Quantize as XnnpackQuantize, + Tester, + ToEdge as XnnpackToEdge, + ToEdgeTransformAndLower as XnnpackToEdgeTransformAndLower, + ToExecutorch as XnnpackToExecutorch, +) +from executorch.devtools.backend_debug import get_delegation_info + +from executorch.exir import ( + EdgeCompileConfig, + EdgeProgramManager, + ExecutorchProgramManager, + ExportedProgram, + to_edge_transform_and_lower, +) +from executorch.exir.backend.backend_api import validation_disabled +from executorch.exir.backend.operator_support import OperatorSupportBase +from executorch.exir.backend.partitioner import Partitioner +from executorch.exir.lowered_backend_module import LoweredBackendModule +from executorch.exir.pass_base import ExportPass +from executorch.exir.pass_manager import PassType +from executorch.exir.program._program import ( + _copy_module, + _update_exported_program_graph_module, +) +from tabulate import tabulate # type: ignore[import-untyped] + +from torch.export.graph_signature import ExportGraphSignature, InputSpec, OutputSpec +from torch.fx import Graph + +from torchao.quantization.pt2e.quantizer import QuantizationSpec, SharedQuantizationSpec +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + +logger = logging.getLogger(__name__) + + +def _dump_lowered_modules_artifact( + path_to_dump: Optional[str], + artifact: Union[EdgeProgramManager, ExecutorchProgramManager], + graph_module: torch.fx.GraphModule | None, +) -> None: + if graph_module is None: + logger.warning("No graph module available to dump lowered modules.") + return + + output = "Formated Graph Signature:\n" + output += _format_export_graph_signature( + artifact.exported_program().graph_signature + ) + + for node in graph_module.graph.nodes: + if node.op == "get_attr" and node.name.startswith("lowered_module_"): + lowered_module = getattr(graph_module, node.name) + assert isinstance( + lowered_module, LoweredBackendModule + ), f"Attribute {node.name} must be of type LoweredBackendModule." + + compile_spec = parse_compile_spec(lowered_module.compile_specs) + if isinstance(compile_spec, TosaCompileSpec): + tosa_fb = lowered_module.processed_bytes + to_print = dbg_tosa_fb_to_json(tosa_fb) + to_print = pformat(to_print, compact=True, indent=1) + output += f"\nTOSA deserialized {node.name}: \n{to_print}\n" + elif isinstance(compile_spec, EthosUCompileSpec): + vela_cmd_stream = lowered_module.processed_bytes + output += f"\nVela command stream {node.name}: \n{vela_cmd_stream!r}\n" + else: + logger.warning( + f"No TOSA nor Vela compile spec found in compile specs of {node.name}." + ) + continue + + if not output: + logger.warning("No output to print generated from artifact.") + return + + _dump_str(output, path_to_dump) + + +class Partition(tester.Partition): + def dump_artifact(self, path_to_dump: Optional[str]): + super().dump_artifact(path_to_dump) + artifact = cast(Optional[EdgeProgramManager], self.artifact) + graph_module = cast(Optional[torch.fx.GraphModule], self.graph_module) + if artifact is None: + logger.warning( + "Partition stage artifact missing; skipping lowered module dump." + ) + return + _dump_lowered_modules_artifact(path_to_dump, artifact, graph_module) + + +class ToEdgeTransformAndLower(tester.ToEdgeTransformAndLower): + def __init__( + self, + partitioners: Optional[List[Partitioner]] = None, + edge_compile_config: Optional[EdgeCompileConfig] = None, + constant_methods: Optional[Dict[str, Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + ): + super().__init__(partitioners, edge_compile_config) + self.constant_methods = constant_methods + self.transform_passes = transform_passes + + def dump_artifact(self, path_to_dump: Optional[str]): + super().dump_artifact(path_to_dump) + artifact = cast(Optional[EdgeProgramManager], self.artifact) + graph_module = cast(Optional[torch.fx.GraphModule], self.graph_module) + if artifact is None: + logger.warning( + "ToEdgeTransformAndLower stage artifact missing; skipping lowered module dump." + ) + return + _dump_lowered_modules_artifact(path_to_dump, artifact, graph_module) + + def run( + self, artifact: ExportedProgram, inputs=None, generate_etrecord: bool = False + ) -> None: + artifact_to_run = copy.deepcopy(artifact) + self.edge_dialect_program = to_edge_transform_and_lower( + artifact_to_run, + transform_passes=self.transform_passes, + compile_config=self.edge_compile_conf, + partitioner=self.partitioners, + constant_methods=self.constant_methods, + generate_etrecord=generate_etrecord, + ) + + +class ToExecutorch(tester.ToExecutorch): + def run_artifact(self, inputs): + with TosaReferenceModelDispatch(): + return super().run_artifact(inputs) + + +class RunPasses(tester.RunPasses): + @no_type_check + def __init__( + self, + pass_list: Optional[List[Type[PassType]]] = None, + pass_functions: Optional[List[Callable]] = None, + passes_with_exported_program: Optional[List[Type[ExportPass]]] = None, + ): + """Passes are run in the order they are passed: first pass_list, second pass_functions, + and lastly passes_with_exported_program.""" + self.pass_with_exported_program: Optional[List[Type[ExportPass]]] = ( + passes_with_exported_program + ) + + super().__init__(pass_list, pass_functions) + + def run( + self, artifact: Union[EdgeProgramManager, ExportedProgram], inputs=None + ) -> None: + if self.pass_with_exported_program is not None: + pass_functions = list(self.pass_functions or []) # type: ignore[has-type] + + # pass_function list from superclass expects functions that take in + # and return ExportedPrograms. + # Create a wrapper to fit pass_with_exported_program into this. + def wrap_ep_pass(ep_pass: Type[ExportPass]): + def wrapped_ep_pass(ep: ExportedProgram) -> ExportedProgram: + pass_instance = ep_pass(ep) # type: ignore[call-arg] + pass_result = pass_instance.call(ep.graph_module) + with validation_disabled(): + return _update_exported_program_graph_module( + ep, pass_result.graph_module + ) + + return wrapped_ep_pass + + pass_functions.extend( + [wrap_ep_pass(ep_pass) for ep_pass in self.pass_with_exported_program] + ) + self.pass_functions = pass_functions + super().run(artifact, inputs) + + +class InitialModel(Stage): + def __init__(self, model: torch.nn.Module): + self.model = model + + def stage_type(self) -> StageType: + return StageType.INITIAL_MODEL + + def run(self, artifact, inputs=None) -> None: + pass + + @property + def artifact(self) -> torch.nn.Module: + return self.model + + @property + def graph_module(self) -> None: + return None + + def artifact_str(self) -> str: + return str(self.model) + + def run_artifact(self, inputs): + return self.model.forward(*inputs) + + +class ArmTester(Tester): + def __init__( + self, + model: torch.nn.Module, + example_inputs: Tuple[Any, ...], + compile_spec: ArmCompileSpec, + tosa_ref_model_path: str | None = None, + dynamic_shapes: Optional[Tuple[Any]] = None, + constant_methods: Optional[Dict[str, Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + use_portable_ops: bool = False, + timeout: int = 600, + ): + """ + Args: + model (torch.nn.Module): The model to test + example_inputs (Tuple[torch.Tensor]): Example inputs to the model + compile_spec (ArmCompileSpec): The compile spec to use + """ + + self.transform_passes = transform_passes + self.constant_methods = constant_methods + self.compile_spec = compile_spec + super().__init__(model, example_inputs, dynamic_shapes) + self.pipeline[StageType.INITIAL_MODEL] = [ + StageType.QUANTIZE, + StageType.EXPORT, + ] + self.original_module.requires_grad_(False) + + # Initial model needs to be set as a *possible* but not yet added Stage, therefore add None entry. + self.stages[StageType.INITIAL_MODEL] = cast(Stage, None) + self._run_stage(InitialModel(self.original_module)) + self.use_portable_ops = use_portable_ops + self.timeout = timeout + + @no_type_check + def quantize( + self, + quantize_stage: Optional[XnnpackQuantize] = None, + ): + # Same stage type as parent but exposed via module alias + if quantize_stage is None: + quantizer = create_quantizer(self.compile_spec) + quantize_stage = Quantize( + quantizer, + get_symmetric_quantization_config(), + ) + return super().quantize(quantize_stage) + + @no_type_check + def to_edge( + self, + to_edge_stage: Optional[XnnpackToEdge] = None, + # Keep config keyword-only to avoid positional clashes with legacy calls. + *, + config: Optional[EdgeCompileConfig] = None, + ): + # Allow optional config override beyond base signature + if to_edge_stage is None: + to_edge_stage = tester.ToEdge(config) + else: + if config is not None: + to_edge_stage.edge_compile_conf = config + + return super().to_edge(to_edge_stage) + + @no_type_check + def partition(self, partition_stage: Optional[XnnpackPartitionStage] = None): + # Accept Arm-specific partition stage subclass + if partition_stage is None: + arm_partitioner = create_partitioner(self.compile_spec) + partition_stage = Partition(arm_partitioner) + return super().partition(partition_stage) + + @no_type_check + def to_edge_transform_and_lower( + self, + to_edge_and_lower_stage: Optional[XnnpackToEdgeTransformAndLower] = None, + generate_etrecord: bool = False, + # Force the optional tuning knobs to be keyword-only for readability/back-compat. + *, + partitioners: Optional[List[Partitioner]] = None, + edge_compile_config: Optional[EdgeCompileConfig] = None, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + ): + # Arm flow exposes extra stage wiring knobs + if transform_passes is not None: + raise RuntimeError( + "transform passes are given to ArmTester at construction." + ) + + if to_edge_and_lower_stage is None: + if partitioners is None: + operator_checks = ( + list(additional_checks) if additional_checks is not None else None + ) + arm_partitioner = create_partitioner(self.compile_spec, operator_checks) + partitioners = [arm_partitioner] + to_edge_and_lower_stage = ToEdgeTransformAndLower( + partitioners, + edge_compile_config, + constant_methods=self.constant_methods, + transform_passes=self.transform_passes, + ) + else: + if partitioners is not None: + to_edge_and_lower_stage.partitioners = partitioners + if edge_compile_config is not None: + to_edge_and_lower_stage.edge_compile_conf = edge_compile_config + return super().to_edge_transform_and_lower( + to_edge_and_lower_stage, generate_etrecord=generate_etrecord + ) + + @no_type_check + def to_executorch(self, to_executorch_stage: Optional[XnnpackToExecutorch] = None): + # Allow custom ExecuTorch stage subclass + if to_executorch_stage is None: + to_executorch_stage = ToExecutorch() + return super().to_executorch(to_executorch_stage) + + @no_type_check + def serialize( + self, + serialize_stage: Optional[Serialize] = None, + # Keep timeout keyword-only so positional usage matches the base class. + *, + timeout: int = 480, + ): + if serialize_stage is None: + serialize_stage = Serialize( + compile_spec=self.compile_spec, + module=self.original_module, + use_portable_ops=self.use_portable_ops, + timeout=self.timeout, + ) + assert ( + self.compile_spec.get_intermediate_path() is not None + ), "Can't dump serialized file when compile specs do not contain an artifact path." + + return super().serialize(serialize_stage) + + def is_quantized(self) -> bool: + return self.stages[StageType.QUANTIZE] is not None + + def run_method_and_compare_outputs( + self, + stage: Optional[StageType] = None, + inputs: Optional[Tuple[torch.Tensor, ...]] = None, + num_runs: int = 1, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 0, + statistics_callback: Callable[[ErrorStatistics], None] | None = None, + # Preserve positional compatibility while keeping new flags keyword-only. + *, + error_callbacks: Optional[Sequence[Callable[..., None]]] = None, + run_eager_mode: bool = False, + ): + """ + Compares the run_artifact output of 'stage' with the output of a reference stage. + If the model is quantized, the reference stage is the Quantize stage output. + Otherwise, the reference stage is the initial pytorch module. + + Asserts that the outputs are equal (within tolerances). + Returns self to allow the function to be run in a test chain. + + Args: + stage: (Optional[str]): The name of the stage to compare. + The default is the latest run stage. + inputs (Optional[Tuple[torch.Tensor]]): Allows you to input custom input data. + The default is random data. + """ + + # backward-compatible ordering (accept inputs as the first positional argument) + if inputs is None and isinstance(stage, tuple): + if all(isinstance(arg, torch.Tensor) for arg in stage): + inputs = cast(Tuple[torch.Tensor, ...], stage) + stage = None + + if not run_eager_mode: + edge_stage = self.stages[StageType.TO_EDGE] + if edge_stage is None: + edge_stage = self.stages[StageType.TO_EDGE_TRANSFORM_AND_LOWER] + assert ( + edge_stage is not None + ), "To compare outputs, at least the ToEdge or ToEdgeTransformAndLower stage needs to be run." + else: + # Run models in eager mode. We do this when we want to check that the passes + # are numerically accurate and the exported graph is correct. + export_stage = self.stages[StageType.EXPORT] + assert ( + export_stage is not None + ), "To compare outputs in eager mode, the model must be at Export stage" + + stage = stage or self.cur + if stage is None: + raise RuntimeError("No stage has been executed yet.") + test_stage = self.stages[stage] + is_quantized = self.is_quantized() + + if is_quantized: + reference_stage = self.stages[StageType.QUANTIZE] + else: + reference_stage = self.stages[StageType.INITIAL_MODEL] + + exported_stage = self.stages[StageType.EXPORT] + exported_program = cast(ExportedProgram, exported_stage.artifact) + output_node = exported_program.graph_module.graph.output_node() + output_qparams = get_output_quantization_params(output_node) + + quantization_scales = [] + for node in output_qparams: + quantization_scales.append(getattr(output_qparams[node], "scale", None)) + + logger.info( + f"Comparing Stage '{test_stage.stage_type()}' with Stage '{reference_stage.stage_type()}'" + ) + + # Loop inputs and compare reference stage with the compared stage. + number_of_runs = 1 if inputs is not None else num_runs + + for run_iteration in range(number_of_runs): + reference_input = inputs if inputs else next(self.generate_random_inputs()) + + # Avoid issues with inplace operators + test_input = copy.deepcopy(reference_input) + original_input = copy.deepcopy(reference_input) + + input_shapes = [ + generated_input.shape if hasattr(generated_input, "shape") else (1,) + for generated_input in reference_input + ] + input_shape_str = ", ".join([str(list(i)) for i in input_shapes]) + logger.info(f"Run #{run_iteration}, input shapes: {input_shape_str}") + + reference_outputs, _ = pytree.tree_flatten( + reference_stage.run_artifact(reference_input) + ) + if run_eager_mode: + # Run exported module directly + eager_output, _ = self._calculate_reference_output( + exported_program, test_input + ) + test_outputs, _ = pytree.tree_flatten(eager_output) + else: + # Run lowered model with target + test_outputs, _ = pytree.tree_flatten( + test_stage.run_artifact(test_input) + ) + + logger.info(f"\n Input: {original_input}") + logger.info(f"\n Ref output: {reference_outputs}") + logger.info(f"\nTest output: {test_outputs}") + + for reference_output, test_output, quantization_scale in zip( + reference_outputs, test_outputs, quantization_scales + ): + self._compare_outputs( + reference_output, + test_output, + quantization_scale, + atol, + rtol, + qtol, + statistics_callback=statistics_callback, + error_callbacks=error_callbacks, + ) + + return self + + def _get_output_qspec_from_node( + self, node: torch.fx.Node + ) -> QuantizationSpec | None: + if Q_ANNOTATION_KEY not in node.meta: + return None + annotation = node.meta[Q_ANNOTATION_KEY] + # If annotation.output_qspec is a SharedQuantizationSpec, we need to find + # the actual QuantizationSpec from one of the inputs. + if isinstance(annotation.output_qspec, SharedQuantizationSpec): + # First try to find a non-shared qspec from the inputs. + annotation_qspec = [ + qspec + for qspec in annotation.input_qspec_map.values() + if not isinstance(qspec, SharedQuantizationSpec) + ] + # If none of the inputs have a non-shared qspec, we need to + # find the source node of the shared qspec. + if len(annotation_qspec) == 0: + edge_or_node = annotation.output_qspec.edge_or_node + if isinstance(edge_or_node, tuple): + source_node = edge_or_node[0] + else: + source_node = edge_or_node + annotation_qspec = [source_node.meta[Q_ANNOTATION_KEY].output_qspec] + annotation_qspec = annotation_qspec[0] + else: + annotation_qspec = annotation.output_qspec + + return annotation_qspec + + def _get_input_qspecs_from_node( + self, node: torch.fx.Node + ) -> List[QuantizationSpec | None]: + if Q_ANNOTATION_KEY not in node.meta: + return [None] + annotation = node.meta[Q_ANNOTATION_KEY] + input_qspec_map = annotation.input_qspec_map + found_qspecs = [] + if len(input_qspec_map) == 0: + return [None] + for spec in input_qspec_map.values(): + # If spec is a SharedQuantizationSpec, we need to find + # the actual QuantizationSpec. + if isinstance(spec, SharedQuantizationSpec): + # First try to find a non-shared qspec from the inputs. + annotation_qspec = [ + qspec + for qspec in input_qspec_map.values() + if not isinstance(qspec, SharedQuantizationSpec) + ] + # If none of the inputs have a non-shared qspec, we need to + # find the source node of the shared qspec. + if len(annotation_qspec) == 0: + edge_or_node = annotation.output_qspec.edge_or_node + if isinstance(edge_or_node, tuple): + source_node = edge_or_node[0] + else: + source_node = edge_or_node + annotation_qspec = [source_node.meta[Q_ANNOTATION_KEY].output_qspec] + found_qspecs.append(annotation_qspec[0]) + else: + found_qspecs.append(spec) + + return found_qspecs + + def _check_input_qspecs(self, graph: Graph, input_qspecs): + if input_qspecs is None: + return + found_qspecs = [] + for node in graph.nodes: + if node.op != "placeholder": + continue + annotation_qspec = self._get_output_qspec_from_node(node) + found_qspecs.append(annotation_qspec) + found_qspecs_counter = Counter(found_qspecs) + for qspec in input_qspecs: + # check that each expected qspec is found + if qspec not in found_qspecs_counter: + raise AssertionError( + f"Expected to find input quantization annotation {qspec}, but it was not found. " + f"Found annotations: {found_qspecs_counter}" + ) + # check that number of occurrences of each qspec matches expected + if found_qspecs_counter[qspec] != input_qspecs[qspec]: + raise AssertionError( + f"Expected to find {input_qspecs[qspec]} instances of input quantization annotation {qspec}, but " + f"found {found_qspecs_counter[qspec]} instances." + ) + + def _check_output_qspecs(self, graph: Graph, output_qspecs): + if output_qspecs is None: + return + found_qspecs = [] + output_node = graph.output_node() + annotation_qspec = self._get_input_qspecs_from_node(output_node) + found_qspecs.extend(annotation_qspec) + found_qspecs_counter = Counter(found_qspecs) + for qspec in output_qspecs: + # check that each expected qspec is found + if qspec not in found_qspecs_counter: + raise AssertionError( + f"Expected to find output quantization annotation {qspec}, but it was not found. " + f"Found annotations: {found_qspecs_counter}" + ) + # check that number of occurrences of each qspec matches expected + if found_qspecs_counter[qspec] != output_qspecs[qspec]: + raise AssertionError( + f"Expected to find {output_qspecs[qspec]} instances of output quantization annotation {qspec}, but " + f"found {found_qspecs_counter[qspec]} instances." + ) + + def _check_qspecs(self, graph: Graph, quantization_annotations): + if quantization_annotations is None: + return self + + quantization_annotations_found: List[Tuple[str, QuantizationSpec | None]] = [] + for node in graph.nodes: + if node.op != "call_function": + continue + quantization_annotations_found.append( + (str(node.target), self._get_output_qspec_from_node(node)) + ) + + # Counter: (target, qspec) -> count + quantization_annotations_found_counter = Counter(quantization_annotations_found) + # Convert counter to Dict[target, Dict[qspec, count]] + quantization_annotations_found_dict: Dict[ + str, Dict[QuantizationSpec | None, int] + ] = defaultdict(dict) + for (target, qspec), count in quantization_annotations_found_counter.items(): + quantization_annotations_found_dict[target][qspec] = count + + for target, qspecs in quantization_annotations.items(): + # check if target is in found annotations + if target not in quantization_annotations_found_dict: + raise AssertionError( + f"Expected to find quantization annotation for operator {target}, but it was not found." + ) + for qspec in qspecs: + # check if qspec is in found annotations for target + if qspec not in quantization_annotations_found_dict[target]: + raise AssertionError( + f"Expected to find quantization annotation {qspec} for operator {target}, but it was not found. " + f"Found annotations: {quantization_annotations_found_dict[target]}" + ) + # check that number of occurrences of each qspec matches expected + if quantization_annotations_found_dict[target][qspec] != qspecs[qspec]: + raise AssertionError( + f"Expected to find {qspecs[qspec]} instances of quantization annotation {qspec} for operator " + f"{target}, but found {quantization_annotations_found_dict[target][qspec]} instances." + ) + + def check_quantization_annotation( + self, + quantization_annotations: Optional[ + Dict[str, Dict[QuantizationSpec | None, int]] + ] = None, + input_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + output_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + ): + """ + Check the quantization annotations in the graph of a quantized model. + + Args: + quantization_annotations: A dictionary mapping operator names to a dictionary of + QuantizationSpecs and their expected counts. + If None, the check is skipped. + input_qspecs: A dictionary of expected input QuantizationSpecs and their counts. + If None, the check is skipped. + output_qspecs: A dictionary of expected output QuantizationSpecs and their counts. + If None, the check is skipped. + + Returns self for daisy-chaining. + """ + if not self.is_quantized(): + raise RuntimeError( + f"{self.check_quantization_annotation.__name__} should be called after quantization stage." + ) + + graph = self.get_graph(StageType.QUANTIZE) + + self._check_input_qspecs(graph, input_qspecs) + self._check_output_qspecs(graph, output_qspecs) + self._check_qspecs(graph, quantization_annotations) + return self + + def get_graph(self, stage: StageType | None = None) -> Graph: + if stage is None: + stage = self.cur + if stage is None: + raise RuntimeError("No stage has been executed yet.") + artifact = self.get_artifact(stage) + if ( + self.cur == StageType.TO_EDGE + or self.cur == StageType.PARTITION + or self.cur == StageType.TO_EDGE_TRANSFORM_AND_LOWER + ): + graph = artifact.exported_program().graph + elif self.cur == StageType.EXPORT or self.cur == StageType.QUANTIZE: + graph = artifact.graph + else: + raise RuntimeError( + "Can only get a graph from Quantize, ToEdge, Export, and Partition stages." + ) + + return graph + + def dump_operator_distribution( + self, + path_to_dump: Optional[str] = None, + print_table: bool = True, + include_dtypes: bool = True, + ): + """Dump the distribution of operators in the current stage. + In the partition stage, additional information is included such as the number of + delegates and the distribution of TOSA operators. + Set parameter print_table to False to dump in a parseable format. + + + Returns self for daisy-chaining. + """ + line = "#" * 10 + to_print = f"\n{line} {self.cur} Operator Distribution {line}\n" + + if self.cur in ( + StageType.PARTITION, + StageType.TO_EDGE_TRANSFORM_AND_LOWER, + ): + graph_module = self.get_artifact().exported_program().graph_module + delegation_info = get_delegation_info(graph_module) + op_dist = _get_tosa_operator_distribution(graph_module, include_dtypes) + if print_table: + aten_op_dist = delegation_info.get_operator_delegation_dataframe() + to_print += "Aten operators:\n" + _format_dict( + dict(aten_op_dist), print_table + ) + + if include_dtypes: + op_dist_dict = { + "Operator": [op_type[0] for op_type, _ in op_dist], + "Dtype": [op_type[1] for op_type, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + op_dist_dict = { + "Operator": [op for op, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + if include_dtypes: + op_dtype_dist_dict: Dict[str, Dict[str, int]] = defaultdict(dict) + for op_dtype, count in op_dist: + op = op_dtype[0] + dtype = op_dtype[1] + op_dtype_dist_dict[op].update({dtype: count}) + op_dist_dict = dict(op_dtype_dist_dict) + else: + op_dist_dict = dict(op_dist) # type: ignore[arg-type] + to_print += "\nTOSA operators:\n" + _format_dict(op_dist_dict, print_table) + to_print += "\n" + delegation_info.get_summary() + else: + graph = self.get_graph(self.cur) + if include_dtypes: + op_dist = _get_operator_dtype_distribution(graph) + else: + op_dist = _get_operator_distribution(graph) + if print_table: + if include_dtypes: + op_dist_dict = { + "Operator": [op_dtype[0] for op_dtype, _ in op_dist], + "Dtype": [op_dtype[1] for op_dtype, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + op_dist_dict = { + "Operator": [op for op, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + if include_dtypes: + op_dtype_dist_dict = defaultdict(dict) + for op_dtype, count in op_dist: + op = op_dtype[0] + dtype = op_dtype[1] + op_dtype_dist_dict[op].update({dtype: count}) + op_dist_dict = dict(op_dtype_dist_dict) + else: + op_dist_dict = dict(op_dist) # type: ignore[arg-type] + + to_print += _format_dict(op_dist_dict, print_table) + "\n" + + _dump_str(to_print, path_to_dump) + + return self + + def dump_dtype_distribution( + self, path_to_dump: Optional[str] = None, print_table: bool = True + ): + """Dump a the distributions of dtypes of nodes and placeholders in the current stage. + Set parameter print_table to False to dump in a parseable format. + + Returns self for daisy-chaining. + """ + + line = "#" * 10 + to_print = f"{line} {self.cur} Placeholder Dtype Distribution {line}\n" + + graph = self.get_graph(self.cur) + tosa_spec = self.compile_spec.tosa_spec + dtype_dist_placeholders, dtype_dirst_tensors = _get_dtype_distribution( + graph, tosa_spec + ) + all_dtypes = set(dtype_dist_placeholders.keys()) | set( + dtype_dirst_tensors.keys() + ) + dtype_dist: dict[str, Any] + if print_table: + dtype_dist = { + "Dtype": all_dtypes, + "Placeholder Count": [ + ( + dtype_dist_placeholders[key] + if key in dtype_dist_placeholders + else 0 + ) + for key in all_dtypes + ], + "Tensor Count": [ + (dtype_dirst_tensors[key] if key in dtype_dirst_tensors else 0) + for key in all_dtypes + ], + } + else: + combined_counts = dtype_dist_placeholders + dtype_dirst_tensors + dtype_dist = {key: combined_counts[key] for key in combined_counts} + to_print += _format_dict(dtype_dist, print_table) + "\n" + _dump_str(to_print, path_to_dump) + return self + + def run_transform_for_annotation_pipeline( + self, stage: StageType | None = None + ) -> torch.fx.GraphModule: + """Run transform_for_annotation_pipeline on exported program to ensure + passes do not break the initial model before quantization. + + There are caveats to this however. As we register buffers to the graph modules + the resulting exported graph can fail. Use this only to compare numerical correctness + in eager mode. + + Returns exported program with passes applied. + """ + + if stage is None: + stage = self.cur + if stage is None: + raise RuntimeError("No stage has been executed yet.") + # We need to clone the artifact in order to ensure that the state_dict is preserved after passes are run. + artifact = self.get_artifact(stage) + if self.cur == StageType.EXPORT: + new_gm = ArmPassManager( + self.compile_spec + ).transform_for_annotation_pipeline(graph_module=artifact.graph_module) + else: + raise RuntimeError("Can only run passes on Export stage.") + _copy_module(artifact.graph_module, new_gm) + return artifact + + @staticmethod + def _calculate_reference_output( + program: ExportedProgram, inputs: Tuple[Any, ...] + ) -> Tuple[torch.Tensor, Optional[float]]: + """ + Note: I'd prefer to use the base class method here, but since it use the + exported program, I can't. The partitioner stage clears the state_dict + of the exported program, which causes an issue when evaluating the + module. + """ + + module = program.module() + return module.forward(*inputs), None + + @no_type_check + def _compare_outputs( + self, + reference_output, + stage_output, + quantization_scale=None, + atol=1e-03, + rtol=1e-03, + qtol=0, + statistics_callback: Callable[[ErrorStatistics], None] | None = None, + # Extra debugging hooks are keyword-only to keep the signature stable. + *, + error_callbacks: Optional[Sequence[Callable[..., None]]] = None, + ): + # Accept extra error callback hook for debugging + try: + super()._compare_outputs( + reference_output, + stage_output, + quantization_scale, + atol, + rtol, + qtol, + statistics_callback=statistics_callback, + ) + except AssertionError as e: + callbacks = ( + list(error_callbacks) + if error_callbacks is not None + else [print_error_diffs, dump_error_output] + ) + for callback in callbacks: + callback( + self, + stage_output, + reference_output, + quantization_scale=quantization_scale, + atol=1e-03, + rtol=1e-03, + qtol=0, + ) + raise e + + def __del__(self): + intermediate_path = self.compile_spec.get_intermediate_path() + if not intermediate_path: + return + if len(tempdir := tempfile.gettempdir()) > 0: + if intermediate_path.startswith(tempdir): + shutil.rmtree(intermediate_path, ignore_errors=True) + + def check_dtype_count(self, dtype_dict: Dict[str, Dict[str, int]]): + if self.cur in ( + StageType.PARTITION, + StageType.TO_EDGE_TRANSFORM_AND_LOWER, + ): + graph_module = self.get_artifact().exported_program().graph_module + op_dist = _get_tosa_operator_distribution(graph_module, include_dtypes=True) + op_dist_dict: Dict[str, Dict[str, int]] = defaultdict(dict) + for op_dtype, count in op_dist: + if isinstance(op_dtype, str): + raise ValueError( + f"Expected {_get_tosa_operator_distribution.__name__} to return " + "Tuple[Tuple[str, str], int]." + ) + else: + op, dtype = op_dtype + + op_dist_dict[op].update({dtype: count}) + for op in dtype_dict.keys(): + if op not in op_dist_dict: + raise RuntimeError(f"Could not find op {op}.") + for dtype, count in dtype_dict[op].items(): + dtype_count = op_dist_dict[op].setdefault(dtype, 0) + if dtype_count != count: + raise RuntimeError( + f"Expected {count} occurencies of {op=}, {dtype=} but found {dtype_count}." + ) + + else: + + raise NotImplementedError(f"Cannot check dtypes for stage {self.cur}") + + +def _get_dtype_distribution( + graph: Graph, tosa_spec: TosaSpecification +) -> tuple[Counter[str], Counter[str]]: + """Counts the occurences of placeholder and call_function dtypes in a graph. + The result is a tuple of Counters (placeholder_distribution, call_function_distribution) + """ + placeholder_dtypes: list[str] = [] + call_function_dtypes: list[str] = [] + for node in graph.nodes: + if node.op == "placeholder": + placeholder_dtypes.append(str(node.meta["val"].dtype)) + if node.op == "call_function": + if "val" in node.meta and isinstance(node.meta["val"], torch.Tensor): + dtype, _, _ = extract_tensor_meta(node.meta, tosa_spec) + call_function_dtypes.append(ts.DTypeNames[dtype]) + return Counter(placeholder_dtypes), Counter(call_function_dtypes) + + +def _get_operator_distribution(graph: Graph) -> List[Tuple[str, int]]: + """Counts the occurences of operator names in a graph. + The result is a sorted list [('operator name':'number of nodes')] + """ + return sorted( + Counter( + [ + str(node.target) + for node in list(graph.nodes) + if node.op == "call_function" + ] + ).items() + ) + + +def _get_operator_dtype_distribution(graph: Graph) -> List[Tuple[Tuple[str, str], int]]: + """Counts the occurences of operator names and dtype pairs in a graph. + The result is a sorted list[(('operator name','dtype'),'number of nodes')] + """ + target_dtype_pairs = [] + for node in graph.nodes: + if node.op != "call_function": + continue + if "val" in node.meta and isinstance(node.meta["val"], torch.Tensor): + dtype = str(node.meta["val"].dtype) + else: + dtype = "UNKNOWN" + target_dtype_pairs.append((str(node.target), dtype)) + return sorted(Counter(target_dtype_pairs).items()) + + +def _format_export_graph_signature(signature: ExportGraphSignature) -> str: + def specs_dict(specs: Sequence[InputSpec | OutputSpec], title: str): + _dict: dict[str, list] = {title: [], "arg": [], "kind": [], "target": []} + for i, spec in enumerate(specs): + _dict[title].append(i) + _dict["arg"].append(spec.arg) + _dict["kind"].append(spec.kind) + _dict["target"].append(spec.target if spec.target else "-") + return _dict + + input_dict = specs_dict(signature.input_specs, "Inputs") + output_dict = specs_dict(signature.output_specs, "Outputs") + + return f"{_format_dict(input_dict)}\n{_format_dict(output_dict)}" + + +def _get_tosa_operator_distribution( + graph_module: torch.fx.GraphModule, include_dtypes=False +) -> list[Tuple[str, int]] | list[Tuple[Tuple[str, str], int]]: + """Counts the occurences of operator names of all lowered modules containing + a TOSA flatbuffer. + The result is a string with the operator distribution or an error message. + """ + id = 0 + unknown_dtype_str = "UNKNOWN" + op_list = [] + while lowered_module := getattr(graph_module, f"lowered_module_{id}", None): + compile_spec = parse_compile_spec(lowered_module.compile_specs) + if isinstance(compile_spec, TosaCompileSpec): + tosa_fb = lowered_module.processed_bytes + tosa_json = dbg_tosa_fb_to_json(tosa_fb) + for region in tosa_json["regions"]: + for block in region["blocks"]: + for operator in block["operators"]: + op = operator["op"] + if include_dtypes: + outputs = operator.get("outputs", []) + if outputs == []: + op_list.append((op, unknown_dtype_str)) + continue + tensor_block = block.get("tensors", {}) + tensors_with_matching_name = [ + t for t in tensor_block if t["name"] == outputs[0] + ] + dtype = ( + tensors_with_matching_name[0]["type"] + if len(tensors_with_matching_name) > 0 + else unknown_dtype_str + ) + op_list.append((op, dtype)) + else: + op_list.append(op) + + elif isinstance(compile_spec, EthosUCompileSpec): + raise NotImplementedError( + "Can not get operator distribution for Vela command stream." + ) + elif isinstance(compile_spec, VgfCompileSpec): + raise NotImplementedError("Can not get operator distribution for VGF.") + else: + raise NotImplementedError( + f"Unknown output format '{compile_spec.get_output_format()}'." + ) + id += 1 + if id == 0: + raise ValueError( + "No delegate with name 'lowered_module_0 found in graph module." + ) + return sorted(Counter(op_list).items()) + + +def _dump_str(to_print: str, path_to_dump: Optional[str] = None): + if path_to_dump: + with open(path_to_dump, "a") as fp: + fp.write(to_print) + else: + print(to_print) + + +def _format_dict(to_print: dict, print_table: bool = True) -> str: + if isinstance(list(to_print.items())[0], Iterable) and print_table: + return tabulate( + to_print, headers="keys", tablefmt="fancy_grid", maxcolwidths=35 + ) + else: + return pformat(to_print, compact=True, indent=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/quantize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/quantize.py new file mode 100644 index 0000000..18ecd40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/quantize.py @@ -0,0 +1,43 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.quantizer import TOSAQuantizer +from executorch.backends.test.harness.stages.quantize import Quantize + +from executorch.backends.transforms.duplicate_dynamic_quant_chain import ( + DuplicateDynamicQuantChainPass, +) + +from torch.export import export + + +class ArmQuantize(Quantize): + + def run( + self, artifact: torch.nn.Module, inputs: Optional[Tuple[torch.Tensor]] + ) -> None: + assert inputs is not None + if self.is_qat: + artifact.train() + captured_graph = export(artifact, inputs, strict=True).module() + + if not isinstance(self.quantizer, TOSAQuantizer): + raise ValueError("ArmQuantizer can only run with TOSAQuantizer.") + + if self.calibration_samples is not None: + converted = self.quantizer.quantize_with_submodules( + captured_graph, self.calibration_samples, bool(self.is_qat) # type: ignore + ) + else: + converted = self.quantizer.quantize_with_submodules( + captured_graph, [inputs], bool(self.is_qat) + ) + + DuplicateDynamicQuantChainPass()(converted) + + self.converted_graph = converted diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/serialize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/serialize.py new file mode 100644 index 0000000..33e57cc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/serialize.py @@ -0,0 +1,78 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from typing import Optional + +import executorch.backends.xnnpack.test.tester.tester as tester + +import torch.fx + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec + +from executorch.backends.arm.test.runner_utils import ( + get_elf_path, + get_target_board, + run_target, +) + +from executorch.exir import ExecutorchProgramManager +from torch.utils._pytree import tree_flatten + + +logger = logging.getLogger(__name__) + + +class Serialize(tester.Serialize): + def __init__( + self, + compile_spec: ArmCompileSpec, + module: Optional[torch.nn.Module], + use_portable_ops: bool = False, + timeout: int = 120, + ): + """ + Args: + compile_spec: CompileSpecs to be used for serialization. + module: Original Module to be used for serialization. Optional - can be used for reference output generation. + portable_ops: If True tests with compiled in portable ops, default is to test without this to get error if not fully delegated + timeout: Timeout for fvp. Default is 120 seconds. + """ + super().__init__() + self.module = module + self.timeout = timeout + self.executorch_program_manager: ExecutorchProgramManager | None + self.compile_spec = compile_spec + self.use_portable_ops = use_portable_ops + + def run(self, artifact: ExecutorchProgramManager, inputs=None) -> None: + super().run(artifact, inputs) + # Keep the entire ExecutorchProgramManager for execution. + self.executorch_program_manager = artifact + + def run_artifact(self, inputs): + if self.executorch_program_manager is None: + raise RuntimeError( + "Tried running artifact from Serialize stage without running the stage." + ) + inputs_flattened, _ = tree_flatten(inputs) + intermediate_path = self.compile_spec.get_intermediate_path() + target_board = get_target_board(self.compile_spec) + elf_path = get_elf_path(target_board, self.use_portable_ops) + + if not os.path.exists(elf_path): + raise FileNotFoundError( + f"Did not find build arm_executor_runner in path {elf_path}, run setup_testing.sh?" + ) + + return run_target( + self.executorch_program_manager, + inputs_flattened, + intermediate_path, + target_board, + elf_path, + self.timeout, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/test_pipeline.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/test_pipeline.py new file mode 100644 index 0000000..3285d54 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/test/tester/test_pipeline.py @@ -0,0 +1,1190 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import warnings as _warnings + +from typing import ( + Any, + Callable, + Dict, + Generic, + List, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, +) + +import torch +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.ethosu import EthosUCompileSpec + +from executorch.backends.arm.quantizer import ( + EthosUQuantizer, + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, + VgfQuantizer, +) +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.arm_tester import ArmTester, RunPasses + +from executorch.backends.arm.test.tester.quantize import ArmQuantize as Quantize +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) + +from executorch.backends.arm.util._factory import create_quantizer +from executorch.exir.pass_base import ExportPass +from torch._export.pass_base import PassType +from torchao.quantization.pt2e.quantizer import QuantizationSpec + +logger = logging.getLogger(__name__) +T = TypeVar("T", bound=Tuple[Any, ...]) +""" Generic type used for test data in the pipeline. Depends on which type the operator expects.""" + + +def _require_tosa_version() -> str: + version = conftest.get_option("tosa_version") + if not isinstance(version, str): + raise TypeError(f"TOSA version option must be a string, got {type(version)}.") + return version + + +def _has_quantizable_inputs(test_data: T) -> bool: + for data in test_data: + if isinstance(data, torch.Tensor) and data.is_floating_point(): + return True + return False + + +class PipelineStage: + """Container for a pipeline stage (callable plus arguments).""" + + def __init__(self, func: Callable, id: str, *args, **kwargs): + self.id: str = id + self.func: Callable = func + self.args = args + self.kwargs = kwargs + self.is_called = False + + def __call__(self): + if not self.is_called: + self.func(*self.args, **self.kwargs) + else: + raise RuntimeError(f"{self.id} called twice.") + self.is_called = True + + def update(self, *args, **kwargs): + if not self.is_called: + self.args = args + self.kwargs = kwargs + else: + raise RuntimeError(f"{self.id} args updated after being called.") + + +class BasePipeline(Generic[T]): + """ + The BasePipeline defines a list of stages to be applied to a torch.nn.module for lowering it + in the Arm backend. To be inherited and adjusted for particular targets. Importantly, the + pipeline list can be modified before running the pipeline to support various pipeline extensions + and debugging usecases. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + aten_ops: Aten dialect ops expected to be found in the graph after export. + compile_spec: The compile spec used in the lowering process. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge if not using + use_edge_to_transform_and_lower. + use_edge_to_transform_and_lower: Selects betweeen two possible routes for lowering: + tester.to_edge_transform_and_lower() + or + tester.to_edge().check(exir_ops).partition() + """ + + @staticmethod + def _normalize_ops(ops: str | Sequence[str] | None) -> list[str]: + if ops is None: + return [] + if isinstance(ops, str): + return [ops] + return list(ops) + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_ops: str | Sequence[str] | None, + compile_spec: ArmCompileSpec, + exir_ops: str | Sequence[str] | None = None, + use_to_edge_transform_and_lower: bool = True, + dynamic_shapes: Optional[Tuple[Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + ): + self.tester = ArmTester( + module, + example_inputs=test_data, + compile_spec=compile_spec, + dynamic_shapes=dynamic_shapes, + transform_passes=transform_passes, + ) + + self.aten_ops = self._normalize_ops(aten_ops) + self.exir_ops = self._normalize_ops(exir_ops) + self.test_data = test_data + self._stages: list[PipelineStage] = [] + + self.add_stage(self.tester.export) + self.add_stage(self.tester.check, self.aten_ops, suffix="aten") + if use_to_edge_transform_and_lower: + self.add_stage(self.tester.to_edge_transform_and_lower) + else: + self.add_stage(self.tester.to_edge) + self.add_stage(self.tester.check, self.exir_ops, suffix="exir") + self.add_stage(self.tester.partition) + self.add_stage(self.tester.check_not, self.exir_ops, suffix="exir") + self.add_stage( + self.tester.check_count, + {"torch.ops.higher_order.executorch_call_delegate": 1}, + suffix="exir", + ) + self.add_stage(self.tester.to_executorch) + + def add_stage(self, func: Callable, *args, **kwargs): + """ + Adds a stage defined by a function with args and kwargs. By default appends to the pipeline. + For stages which may be added multiple times to a pipeline, s.a. checks and debug stages, + a suffix is appended with a dot to make sure every id is unique, e.g. check becomes check.0 + + Special kwargs: + pos : specifies position in pipeline to add stage at. + suffix : specifies a custom suffix to identify non unique stages, instead of a number. + """ + pipeline_length = len(self._stages) + + pos = -1 + if "pos" in kwargs: + pos = kwargs.pop("pos") + + if pos < 0: + pos = pipeline_length + (pos + 1) + if not -pipeline_length <= pos <= pipeline_length: + raise ValueError( + f"Pos must be between [-{pipeline_length}, {pipeline_length}]" + ) + + stage_id = func.__name__ + suffix = None + if "suffix" in kwargs: + suffix = kwargs.pop("suffix") + if stage_id == "dump_artifact": + args = (*args, suffix) + + unique_stages = [ + "quantize", + "export", + "to_edge_transform_and_lower", + "to_edge", + "partition", + "to_executorch", + "serialize", + ] + id_list = [stage.id for stage in self._stages] + if stage_id in unique_stages: + if stage_id in id_list: + raise RuntimeError(f"Tried adding {stage_id} to pipeline twice.") + else: + if suffix is None: + stages_containing_stage_id = [ + id for id in id_list if stage_id == id.split(".")[0] + ] + + suffix = str(len(stages_containing_stage_id)) + + if not suffix == "0": + stage_id = stage_id + "." + suffix + + if stage_id in id_list: + raise ValueError("Suffix must be unique in pipeline") + + pipeline_stage = PipelineStage(func, stage_id, *args, **kwargs) + self._stages.insert(pos, pipeline_stage) + + logger.debug(f"Added stage {stage_id} to {type(self).__name__}") + + return self + + @property + def quantizer(self) -> TOSAQuantizer: + quantize_pipeline_stage = self._stages[self.find_pos("quantize")] + quantize_stage = quantize_pipeline_stage.args[0] + if isinstance(quantize_stage, Quantize): + quantizer = quantize_stage.quantizer + if isinstance(quantizer, TOSAQuantizer): + return quantizer + else: + raise RuntimeError( + f"Quantizer in pipeline was {type(quantizer).__name__}, not TOSAQuantizer as expected." + ) + else: + raise RuntimeError( + f"First argument of quantize stage was {type(quantize_stage).__name__}, not Quantize as expected." + ) + + def pop_stage(self, identifier: int | str): + """Removes and returns the stage at postion pos""" + if isinstance(identifier, int): + stage = self._stages.pop(identifier) + elif isinstance(identifier, str): + pos = self.find_pos(identifier) + stage = self._stages.pop(pos) + else: + raise TypeError("identifier must be an int or str") + + logger.debug(f"Removed stage {stage.id} from {type(self).__name__}") + + return stage + + def find_pos(self, stage_id: str): + """Returns the position of the stage id.""" + for i, stage in enumerate(self._stages): + if stage.id == stage_id: + return i + + raise Exception(f"Stage id {stage_id} not found in pipeline") + + def has_stage(self, stage_id: str): + try: + return self.find_pos(stage_id) >= 0 + except: + return False + + def add_stage_after(self, stage_id: str, func: Callable, *args, **kwargs): + """Adds a stage after the given stage id.""" + pos = self.find_pos(stage_id) + 1 + kwargs["pos"] = pos + + self.add_stage(func, *args, **kwargs) + return self + + def dump_artifact(self, stage_id: str, suffix: str | None = None): + """Adds a dump_artifact stage after the given stage id.""" + self.add_stage_after(stage_id, self.tester.dump_artifact, suffix=suffix) + return self + + def dump_operator_distribution( + self, stage_id: str, suffix: str | None = None, include_dtypes: bool = False + ): + """Adds a dump_operator_distribution stage after the given stage id.""" + self.add_stage_after( + stage_id, + self.tester.dump_operator_distribution, + suffix=suffix, + include_dtypes=include_dtypes, + ) + return self + + def visualize(self, stage_id: str, suffix: str | None = None): + """Adds a dump_operator_distribution stage after the given stage id.""" + self.add_stage_after(stage_id, self.tester.visualize, suffix=suffix) + return self + + def change_args(self, stage_id: str, *args, **kwargs): + """Updates the args to the given stage id.""" + pos = self.find_pos(stage_id) + pipeline_stage = self._stages[pos] + pipeline_stage.update(*args, **kwargs) + return self + + def run(self): + """Calls each stage in order.""" + stage_list = [stage.id for stage in self._stages] + logger.info(f"Running pipeline with stages:\n {stage_list}.") + + for stage in self._stages: + try: + stage() + except Exception as e: + logger.error(f"\nFailure in stage <{stage.id}>: \n {str(e)}") + raise e + + +class TOSAPipeline(BasePipeline, Generic[T]): + @staticmethod + def is_tosa_ref_model_available(): + """Checks if the TOSA reference model is available.""" + # Not all deployments of ET have the TOSA reference model available. + # Make sure we don't try to use it if it's not available. + try: + import tosa_reference_model # type: ignore[import-not-found, import-untyped] + + # Check if the module has content + return bool(dir(tosa_reference_model)) + except ImportError: + return False + + def run(self): + if ( + self.has_stage("run_method_and_compare_outputs") + and not self.is_tosa_ref_model_available() + ): + _warnings.warn( + "Warning: Skipping run_method_and_compare_outputs stage. TOSA reference model is not available." + ) + self.pop_stage("run_method_and_compare_outputs") + super().run() + + +class TosaPipelineINT(TOSAPipeline, Generic[T]): + """ + Lowers a graph to INT TOSA spec (with quantization) and tests it with the TOSA reference model. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + + aten_ops: Aten dialect ops expected to be found in the graph after export. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + + run_on_tosa_ref_model: Set to true to test the tosa file on the TOSA reference model. + + tosa_version: A string for identifying the TOSA version, see common.get_tosa_compile_spec for + options. + use_edge_to_transform_and_lower: Selects betweeen two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_op: str | List[str], + exir_op: Optional[str | List[str]] = None, + run_on_tosa_ref_model: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + dynamic_shapes: Optional[Tuple[Any]] = None, + tosa_extensions: Optional[List[str]] = None, + epsilon: float = 2**-12, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+INT" + "".join([f"+{ext}" for ext in tosa_extensions]) + ), + } + tosa_version = _require_tosa_version() + tosa_spec: TosaSpecification = tosa_profiles[tosa_version] + + compile_spec = common.get_tosa_compile_spec( + tosa_spec, + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + + quantizer = TOSAQuantizer(tosa_spec) + # choose 16A8W quantization config when int16 extension is requested + if "int16" in tosa_extensions: + quantization_config = get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=epsilon + ) + else: + quantization_config = get_symmetric_quantization_config( + is_per_channel=per_channel_quantization + ) + if symmetric_io_quantization: + quantizer.set_io(quantization_config) + quant_stage = Quantize(quantizer, quantization_config) + + super().__init__( + module, + test_data, + aten_op, + compile_spec, + exir_op, + use_to_edge_transform_and_lower, + dynamic_shapes, + ) + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + remove_torch_quant_nodes_stage = ( + "to_edge_transform_and_lower" + if use_to_edge_transform_and_lower + else "partition" + ) + + if _has_quantizable_inputs(test_data): + # only add stages if we have quantizable input + self.add_stage_after( + "quantize", + self.tester.check, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + # For pure INT lowering, outer exir Q/DQ nodes remain in the graph because we can't partition them. + # In INT+FP lowering, we partition these nodes, so a check is added to verify that. + if tosa_spec.support_integer() and tosa_spec.support_float(): + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_channel_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default", + ], + suffix="exir_quant_nodes", + ) + + if run_on_tosa_ref_model: + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + + +class TosaPipelineFP(TOSAPipeline, Generic[T]): + """ + Lowers a graph to FP TOSA spec and tests it with the TOSA reference model. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + + aten_ops: Aten dialect ops expected to be found in the graph after export. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + + run_on_tosa_ref_model: Set to true to test the tosa file on the TOSA reference model. + + tosa_version: A string for identifying the TOSA version, see common.get_tosa_compile_spec for + options. + use_edge_to_transform_and_lower: Selects betweeen two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_op: str | List[str], + exir_op: Optional[str | List[str]] = None, + run_on_tosa_ref_model: bool = True, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 0, + dynamic_shapes: Optional[Tuple[Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+FP" + "".join([f"+{ext}" for ext in tosa_extensions]) + ), + } + tosa_version = _require_tosa_version() + + compile_spec = common.get_tosa_compile_spec( + tosa_profiles[tosa_version], + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + super().__init__( + module, + test_data, + aten_op, + compile_spec, + exir_op, + use_to_edge_transform_and_lower, + dynamic_shapes=dynamic_shapes, + transform_passes=transform_passes, + ) + self.add_stage_after( + "export", + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + if run_on_tosa_ref_model: + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + + +class EthosUPipelineINTBase(BasePipeline, Generic[T]): + """Base class that encapsulates shared Ethos-U INT pipeline setup.""" + + def __init__( + self, + compile_spec: EthosUCompileSpec, + module: torch.nn.Module, + test_data: T, + aten_ops: str | List[str], + exir_ops: str | Sequence[str] | None, + run_on_fvp: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + a16w8_quantization: bool = False, + use_to_edge_transform_and_lower: bool = True, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + epsilon: float = 2**-12, + ): + super().__init__( + module, + test_data, + aten_ops, + compile_spec, + exir_ops, + use_to_edge_transform_and_lower, + ) + + quantizer = EthosUQuantizer(compile_spec) + # choose int8 or int16 activation quantization + if a16w8_quantization: + quantization_config = get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=epsilon + ) + else: + quantization_config = get_symmetric_quantization_config( + is_per_channel=per_channel_quantization + ) + if symmetric_io_quantization: + quantizer.set_io(quantization_config) + quant_stage = Quantize(quantizer, quantization_config) + + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + remove_quant_nodes_stage = ( + "to_edge_transform_and_lower" + if use_to_edge_transform_and_lower + else "partition" + ) + + if _has_quantizable_inputs(test_data): + # only add stages if we have quantizable input + self.add_stage_after( + "quantize", + self.tester.check, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + self.add_stage_after( + remove_quant_nodes_stage, + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + if run_on_fvp: + self.add_stage(self.tester.serialize) + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + + +class EthosU55PipelineINT(EthosUPipelineINTBase, Generic[T]): + """ + Lowers a graph to u55 INT TOSA spec and tests it on the Corstone300 FVP, if run_on_fvp is true. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + aten_ops: Aten dialect ops expected to be found in the graph after export. + + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + run_on_fvp: Set to true to test the pte file on a fvp simulator. + use_edge_to_transform_and_lower: Selects between two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_ops: str | List[str], + exir_ops: str | Sequence[str] | None = None, + run_on_fvp: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + a16w8_quantization: bool = False, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + epsilon: float = 2**-12, + ): + compile_spec = common.get_u55_compile_spec( + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + super().__init__( + compile_spec, + module, + test_data, + aten_ops, + exir_ops, + run_on_fvp=run_on_fvp, + symmetric_io_quantization=symmetric_io_quantization, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=a16w8_quantization, + use_to_edge_transform_and_lower=use_to_edge_transform_and_lower, + atol=atol, + rtol=rtol, + qtol=qtol, + epsilon=epsilon, + ) + + +class EthosU85PipelineINT(EthosUPipelineINTBase, Generic[T]): + """ + Lowers a graph to u85 INT TOSA spec and tests it on the Corstone320 FVP, if run_on_fvp is true. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + aten_ops: Aten dialect ops expected to be found in the graph after export. + + exir_ops: Exir dialect ops expected to be found in the graph after to_edge if not using + use_edge_to_transform_and_lower. + run_on_fvp: Set to true to test the pte file on a fvp simulator. + use_edge_to_transform_and_lower: Selects between two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_ops: str | List[str], + exir_ops: str | Sequence[str] | None = None, + run_on_fvp: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + a16w8_quantization: bool = False, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + epsilon: float = 2**-12, + ): + compile_spec = common.get_u85_compile_spec( + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + super().__init__( + compile_spec, + module, + test_data, + aten_ops, + exir_ops, + run_on_fvp=run_on_fvp, + symmetric_io_quantization=symmetric_io_quantization, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=a16w8_quantization, + use_to_edge_transform_and_lower=use_to_edge_transform_and_lower, + atol=atol, + rtol=rtol, + qtol=qtol, + epsilon=epsilon, + ) + + +class PassPipeline(TOSAPipeline, Generic[T]): + """ + Runs single passes directly on an edge_program and checks operators before/after. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + tosa_version: The TOSA-version which to test for. + + ops_before_pass : Ops expected to be found in the graph before passes. + ops_not_before_pass : Ops expected not to be found in the graph before passes. + ops_after_pass : Ops expected to be found in the graph after passes. + ops_notafter_pass : Ops expected not to be found in the graph after passes. + + pass_list: List of regular passes. + pass_functions: List of functions applied directly to the exported program. + passes_with_exported_program: List of passes initiated with an exported_program. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + + Passes are run in order pass_list -> pass_functions -> passes_with_exported_program. + See arm_tester.RunPasses() for more information. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + quantize: Optional[bool] = False, + ops_before_pass: Optional[Dict[str, int]] = None, + ops_not_before_pass: Optional[list[str]] = None, + ops_after_pass: Optional[Dict[str, int]] = None, + ops_not_after_pass: Optional[list[str]] = None, + pass_list: Optional[List[Type[PassType]]] = None, + pass_functions: Optional[List[Callable]] = None, + passes_with_exported_program: Optional[List[Type[ExportPass]]] = None, + custom_path: str | None = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+" + + ("INT" if quantize else "FP") + + "".join([f"+{ext}" for ext in tosa_extensions]), + ), + } + tosa_version = _require_tosa_version() + self.tosa_spec: TosaSpecification = tosa_profiles[tosa_version] + + compile_spec = common.get_tosa_compile_spec( + self.tosa_spec, custom_path=custom_path + ) + super().__init__( + module, + test_data, + None, + compile_spec, + None, + use_to_edge_transform_and_lower=False, + ) + + # Delete most of the pipeline + self.pop_stage("check.exir") + self.pop_stage("partition") + self.pop_stage("check_not.exir") + self.pop_stage("check_count.exir") + self.pop_stage("to_executorch") + self.pop_stage("check.aten") + + if quantize: + self.add_stage(self.tester.quantize, pos=0) + + # Add checks/check_not's if given + if ops_before_pass: + self.add_stage(self.tester.check_count, ops_before_pass, suffix="before") + if ops_not_before_pass: + self.add_stage(self.tester.check_not, ops_not_before_pass, suffix="before") + test_pass_stage = RunPasses( # type: ignore[arg-type] + pass_list, pass_functions, passes_with_exported_program # type: ignore[arg-type] + ) # Legacy pass APIs expose callable classes rather than ExportPass subclasses + + self.add_stage(self.tester.run_passes, test_pass_stage) + + if ops_after_pass: + self.add_stage(self.tester.check_count, ops_after_pass, suffix="after") + if ops_not_after_pass: + self.add_stage(self.tester.check_not, ops_not_after_pass, suffix="after") + self.add_stage( + self.tester.run_method_and_compare_outputs, + inputs=self.test_data, + ) + + def run(self): + with TosaLoweringContext(self.tosa_spec): + super().run() + + +class TransformAnnotationPassPipeline(TOSAPipeline, Generic[T]): + """ + Runs transform_for_annotation_pipeline passes directly on an exported program and checks output. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for testing the module. + + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + custom_path: str | None = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+INT" + "".join([f"+{ext}" for ext in tosa_extensions]), + ), + } + tosa_version = _require_tosa_version() + + compile_spec = common.get_tosa_compile_spec( + tosa_profiles[tosa_version], custom_path=custom_path + ) + super().__init__( + module, + test_data, + None, + compile_spec, + None, + use_to_edge_transform_and_lower=True, + ) + self.add_stage_after( + "export", self.tester.run_transform_for_annotation_pipeline + ) + + # Delete most of the pipeline + self.pop_stage("check_not.exir") + self.pop_stage("check_count.exir") + self.pop_stage("to_executorch") + self.pop_stage("to_edge_transform_and_lower") + self.pop_stage("check.aten") + self.add_stage( + self.tester.run_method_and_compare_outputs, + inputs=test_data, + run_eager_mode=True, + ) + + +class QuantizationPipeline(TOSAPipeline, Generic[T]): + """ + Runs quantization and checks that appropriate nodes are annotated with an expected + quantization-spec. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for testing the module. + quantizer: The quantizer to use for quantization. + qspecs: Annotations to check for after quantization. A dict mapping + operator names to a dict mapping QuantizationSpec (or None) to the number of times + that spec should appear in the graph. A None QuantizationSpec indicates that the + operator should not be quantized. + input_qspecs: Annotations to check for after quantization on inputs. + output_qspecs: Annotations to check for after quantization on outputs. + custom_path : Path to dump intermediate artifacts to. + + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + quantizer: TOSAQuantizer, + qspecs: Optional[Dict[str, Dict[QuantizationSpec | None, int]]] = None, + input_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + output_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + custom_path: Optional[str] = None, + ): + tosa_spec = quantizer.tosa_spec + compile_spec = common.get_tosa_compile_spec(tosa_spec, custom_path=custom_path) + super().__init__( + module, + test_data, + None, + compile_spec, + None, + use_to_edge_transform_and_lower=True, + ) + # TODO sort out typing + quant_stage = Quantize(quantizer, quantization_config=quantizer.global_config) # type: ignore[arg-type] + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + # Delete most of the pipeline + self.pop_stage("check_count.exir") + self.pop_stage("to_executorch") + self.pop_stage("to_edge_transform_and_lower") + self.pop_stage("check.aten") + self.add_stage_after( + "export", + self.tester.check_quantization_annotation, + qspecs, + input_qspecs, + output_qspecs, + ) + + +class OpNotSupportedPipeline(TOSAPipeline, Generic[T]): + """ + Runs the partitioner on a module and checks that ops are not delegated to test + SupportedTOSAOperatorChecks. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data with a representative shape which the operator_check is performed on. + tosa_version: The TOSA-version which to test for. + + non_delegated_ops : Exir ops expected not to be delegated. + n_expected_delegates : Number of delegate calls (0 in the usual case). + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + non_delegated_ops: Dict[str, int], + n_expected_delegates: int = 0, + custom_path: str | None = None, + quantize: Optional[bool] = False, + u55_subset: Optional[bool] = False, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+" + + ("INT" if quantize else "FP") + + ("+u55" if u55_subset and quantize else "") + + "".join([f"+{ext}" for ext in tosa_extensions]), + ), + } + tosa_version = _require_tosa_version() + + tosa_spec = tosa_profiles[tosa_version] + + compile_spec: ArmCompileSpec = common.get_tosa_compile_spec( + tosa_spec, + custom_path=custom_path, + ) + super().__init__( + module, + test_data, + [], + compile_spec, + [], + ) + + if tosa_spec.support_integer(): + quantizer = create_quantizer(compile_spec) + quantizer.set_global(get_symmetric_quantization_config()) + quant_stage = Quantize(quantizer) + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + self.change_args("check_not.exir", []) + self.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": n_expected_delegates, + **non_delegated_ops, + }, + ) + self.pop_stage("to_executorch") + + +class VgfPipeline(BasePipeline, Generic[T]): + """ + Lowers a graph based on TOSA spec (with or without quantization) and converts TOSA to VFG. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + + aten_ops: Aten dialect ops expected to be found in the graph after export. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + + run_on_vulkan_runtime: Whether to test VGF output on VKML runtime. + + vgf_compiler_flags: Optional compiler flags. + + tosa_version: A string for identifying the TOSA version. + + use_edge_to_transform_and_lower: Selects betweeen two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_op: str | List[str], + exir_op: Optional[str | List[str]] = None, + run_on_vulkan_runtime: bool = True, + vgf_compiler_flags: Optional[str] = "", + tosa_version: str = "TOSA-1.0+INT+FP", + quantize: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + dynamic_shapes: Optional[Tuple[Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_spec = TosaSpecification.create_from_string( + tosa_version + "".join([f"+{ext}" for ext in tosa_extensions]) + ) + compile_spec = common.get_vgf_compile_spec( + tosa_spec, + compiler_flags=vgf_compiler_flags, + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + + super().__init__( + module, + test_data, + aten_op, + compile_spec, + exir_op, + use_to_edge_transform_and_lower, + dynamic_shapes, + transform_passes=transform_passes, + ) + + remove_torch_quant_nodes_stage = ( + "to_edge_transform_and_lower" + if use_to_edge_transform_and_lower + else "partition" + ) + + if quantize: + quantizer = VgfQuantizer(compile_spec) + quantization_config = get_symmetric_quantization_config( + is_per_channel=per_channel_quantization + ) + if symmetric_io_quantization: + quantizer.set_io(quantization_config) + quant_stage = Quantize(quantizer, quantization_config) + + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + if _has_quantizable_inputs(test_data): + # only add stages if we have quantizable input + self.add_stage_after( + "quantize", + self.tester.check, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + else: + self.add_stage_after( + "export", + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + # For pure INT lowering, outer exir Q/DQ nodes remain in the graph because we can't partition them. + # In INT+FP lowering, we partition these these nodes, so a check is added to verify that. + if tosa_spec.support_integer() and tosa_spec.support_float(): + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_channel_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default", + ], + suffix="exir_quant_nodes", + ) + + if run_on_vulkan_runtime: + self.add_stage(self.tester.serialize) + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + self.run_on_vulkan_runtime = run_on_vulkan_runtime + + # TODO: Remove once CI fully working + def run(self): + import pytest + + if self.run_on_vulkan_runtime: + try: + super().run() + except FileNotFoundError as e: + pytest.skip(f"VKML executor_runner not found - not built - skip {e}") + else: + super().run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.clang-format b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.clang-format new file mode 100644 index 0000000..9a7ae82 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.clang-format @@ -0,0 +1,144 @@ +# +# Copyright (c) 2019-2020 Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the License); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: true +BreakInheritanceList: AfterColon +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: AfterColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000000 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +... + diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.gitignore b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/.gitignore @@ -0,0 +1 @@ +/build diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt new file mode 100644 index 0000000..aeec47a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt @@ -0,0 +1,114 @@ +# +# SPDX-FileCopyrightText: Copyright 2019-2021, 2023-2024 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the License); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required(VERSION 3.15.6) + +project(ethosu_core_driver VERSION 0.0.1) + +# +# Compile options +# + +add_compile_options(-Werror) + +# +# Build options +# + +set(CMSIS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmsis" CACHE PATH "Path to CMSIS.") + +set(LOG_NAMES err warning info debug) +set(ETHOSU_LOG_ENABLE ON CACHE BOOL "Toggle driver logs on/off (Defaults to ON)") +set(ETHOSU_LOG_SEVERITY "warning" CACHE STRING "Driver log severity level ${LOG_NAMES} (Defaults to 'warning')") +set(ETHOSU_TARGET_NPU_CONFIG "ethos-u55-128" CACHE STRING "Default NPU configuration") +set(ETHOSU_INFERENCE_TIMEOUT "" CACHE STRING "Inference timeout (unit is implementation defined)") +set_property(CACHE ETHOSU_LOG_SEVERITY PROPERTY STRINGS ${LOG_NAMES}) + +# +# Global settings +# + +# Check that ETHOSU_LOG_SEVERITY has one of the supported levels +list(FIND LOG_NAMES ${ETHOSU_LOG_SEVERITY} LOG_SEVERITY) +if (${LOG_SEVERITY} EQUAL -1) + message(FATAL_ERROR "Unsupported log level ${ETHOSU_LOG_SEVERITY}") +endif() + +# Make include directories available for current- and sub projects +include_directories(include src) +include_directories(${CMSIS_PATH}/CMSIS/Core/Include) + +# +# Build libraries +# + +# Build driver library +add_library(ethosu_core_driver STATIC) +target_include_directories(ethosu_core_driver PUBLIC include) +target_sources(ethosu_core_driver PRIVATE src/ethosu_driver.c src/ethosu_pmu.c) + +string(TOLOWER ${ETHOSU_TARGET_NPU_CONFIG} ETHOSU_TARGET_NPU_CONFIG) +if(ETHOSU_TARGET_NPU_CONFIG MATCHES "^ethos-(u[0-9]+)-([0-9]+$)") + set(ETHOSU_ARCH ${CMAKE_MATCH_1}) + set(ETHOSU_MACS ${CMAKE_MATCH_2}) +else() + message(FATAL_ERROR "Invalid Ethos-U target configuration '${ETHOSU_TARGET_NPU_CONFIG}") +endif() + +target_compile_definitions(ethosu_core_driver PUBLIC + ETHOSU_ARCH=${ETHOSU_ARCH} + ETHOSU_MACS=${ETHOSU_MACS} + ETHOS$) + +if (ETHOSU_ARCH STREQUAL "u55" OR ETHOSU_ARCH STREQUAL "u65") + target_sources(ethosu_core_driver PRIVATE src/ethosu_device_u55_u65.c) +elseif (ETHOSU_ARCH STREQUAL "u85") + target_sources(ethosu_core_driver PRIVATE src/ethosu_device_u85.c) +else() + message(FATAL_ERROR "Invalid NPU configuration") +endif() + +if(NOT "${ETHOSU_INFERENCE_TIMEOUT}" STREQUAL "") + target_compile_definitions(ethosu_core_driver PRIVATE + ETHOSU_SEMAPHORE_WAIT_INFERENCE=${ETHOSU_INFERENCE_TIMEOUT}) + set(ETHOSU_INFERENCE_TIMEOUT_TEXT ${ETHOSU_INFERENCE_TIMEOUT}) +else() + set(ETHOSU_INFERENCE_TIMEOUT_TEXT "Default (no timeout)") +endif() +# Set the log level for the target +target_compile_definitions(ethosu_core_driver PRIVATE + ETHOSU_LOG_SEVERITY=${LOG_SEVERITY} + ETHOSU_LOG_ENABLE=$) + +# Install library and include files +install(TARGETS ethosu_core_driver LIBRARY DESTINATION "lib") +install(FILES include/ethosu_device.h include/ethosu_driver.h include/pmu_ethosu.h + DESTINATION "include") + +# Define ETHOSU macro +target_compile_definitions(ethosu_core_driver PUBLIC ETHOSU) + +# Print build status +message(STATUS "*******************************************************") +message(STATUS "PROJECT_NAME : ${PROJECT_NAME}") +message(STATUS "ETHOSU_TARGET_NPU_CONFIG : ${ETHOSU_TARGET_NPU_CONFIG}") +message(STATUS "CMAKE_SYSTEM_PROCESSOR : ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS "CMSIS_PATH : ${CMSIS_PATH}") +message(STATUS "ETHOSU_LOG_ENABLE : ${ETHOSU_LOG_ENABLE}") +message(STATUS "ETHOSU_LOG_SEVERITY : ${ETHOSU_LOG_SEVERITY}") +message(STATUS "ETHOSU_INFERENCE_TIMEOUT : ${ETHOSU_INFERENCE_TIMEOUT_TEXT}") +message(STATUS "*******************************************************") diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/LICENSE b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt similarity index 99% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/LICENSE rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt index d645695..8dada3e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/LICENSE +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -179,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -187,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/README.md new file mode 100644 index 0000000..327a897 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/README.md @@ -0,0 +1,330 @@ +# Arm(R) Ethos(TM)-U core driver + +This repository contains a device driver for the Arm(R) Ethos(TM)-U NPU. + +## Building + +The source code comes with a CMake based build system. The driver is expected to +be cross compiled for any of the supported Arm Cortex(R)-M CPUs, which requires +the user to configure the build to match their system configuration. + + +One such requirement is to define the target CPU, normally by setting +`CMAKE_SYSTEM_PROCESSOR`. **Note** that when using the toolchain files provided +in [core_platform](https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-platform), +the variable `TARGET_CPU` must be used instead of `CMAKE_SYSTEM_PROCESSOR`. + +Target CPU is specified on the form "cortex-m", for example: +"cortex-m55+nodsp+nofp". + +Similarly the target NPU configuration is +controlled by setting `ETHOSU_TARGET_NPU_CONFIG`, for example "ethos-u55-128". + +The build configuration can be defined either in the toolchain file or +by passing options on the command line. + +```[bash] +$ cmake -B build \ + -DCMAKE_TOOLCHAIN_FILE= \ + -DCMAKE_SYSTEM_PROCESSOR=cortex-m \ + -DETHOSU_TARGET_NPU_CONFIG=ethos-u- +$ cmake --build build +``` + +or when using toolchain files from [core_platform](https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-platform) + +```[bash] +$ cmake -B build \ + -DCMAKE_TOOLCHAIN_FILE= \ + -DTARGET_CPU=cortex-m \ + -DETHOSU_TARGET_NPU_CONFIG=ethos-u- +$ cmake --build build +``` +## Compiler flags used + +The Arm Ethos-U core driver component adds the -Werror flag in addition +to the compiler flags specified in the toolchain file, or options passed +on the command line. + +## Driver APIs + +The driver APIs are defined in `include/ethosu_driver.h` and the related types +in `include/ethosu_types.h`. Inferences can be invoked in two manners: +synchronously or asynchronously. The two types of invocation can be freely mixed +in a single application. + +### Synchronous invocation + +A typical usage of the driver can be the following: + +```[C] +// reserve a driver to be used (this call could block until a driver is available) +struct ethosu_driver *drv = ethosu_reserve_driver(); +... +// run one or more inferences +int result = ethosu_invoke(drv, + custom_data_ptr, + custom_data_size, + base_addr, + base_addr_size, + num_base_addr); +... +// release the driver for others to use +ethosu_release_driver(drv); +``` + +### Asynchronous invocation + +A typical usage of the driver can be the following: + +```[C] +// reserve a driver to be used (this call could block until a driver is available) +struct ethosu_driver *drv = ethosu_reserve_driver(); +... +// run one or more inferences +int result = ethosu_invoke_async(drv, + custom_data_ptr, + custom_data_size, + base_addr, + base_addr_size, + num_base_addr, + user_arg); +... +// do some other work +... +int ret; +do { + // true = blocking, false = non-blocking + // ret > 0 means inference not completed (only for non-blocking mode) + ret = ethosu_wait(drv, ); +} while(ret > 0); +... +// release the driver for others to use +ethosu_release_driver(drv); +``` + +Note that if `ethosu_wait` is invoked from a different thread and concurrently +with `ethosu_invoke_async`, the user is responsible to guarantee that +`ethosu_wait` is called after a successful completion of `ethosu_invoke_async`. +Otherwise `ethosu_wait` might fail and not actually wait for the inference +completion. + +### Driver initialization + +In order to use a driver it first needs to be initialized by calling the `init` +function, which will also register the handle in the list of available drivers. +A driver can be torn down by using the `deinit` function, which also removes the +driver from the list. + +The correct mapping is one driver per NPU device. Note that the NPUs must have +the same configuration, indeed the NPU configuration can be only one, which is +defined at compile time. + +## Implementation design + +The driver is structured in two main parts: the driver, which is responsible to +provide an unified API to the user; and the device part, which deals with the +details at the hardware level. + +In order to do its task the driver needs a device implementation. There could be +multiple device implementation for different hardware model and/or +configurations. Note that the driver can be compiled to target only one NPU +configuration by specializing the device part at compile time. + +## Data caching + +For running the driver on Arm CPUs which are configured with data cache, certain +caution must be taken to ensure cache coherency. The driver expects that cache +clean/flush has been done by the user application before being invoked. The +driver does provide a deprecated weakly linked function `ethosu_flush_dcache` +that could be overriden, causing the driver to cache flush/clean base pointers +marked in the flush mask before each inference. By default the flush mask is set +to only clean the scratch base pointer containing RW data (IFM in particular). +It is recommended to not implement this function but have the user application +make sure that IFM data has been written to memory before invoking an inference +on the NPU. + +The driver also exposes a weakly linked symbol for cache invalidation called +`ethosu_invalidate_dcache`, that must be overriden when the data cache is used. +After starting an inference on the NPU, the driver will call this function to +invalidate the base pointers marked in the invalidation mask. By defaults it +invalidates the scratch base pointer keeping RW data, to ensure cache coherency +after the inference is done. The invalidation call is done before waiting for +the NPU to finish the inference so that depending on the network, the cycles +for invalidating the cache may be completely hidden (the CPU performs cache +invalidation before yielding while waiting for the NPU to finish). + +Make sure that any base pointers marked for flush/invalidation is aligned to the +cache line size of your CPU, typically 32 bytes. While not implemented, to the +really advanced user aiming for maximum performance, it is theoretically +possible to tell the network compiler to align the IFM/OFM to cache line size, +and modify the driver so that only OFM data is invalidated (and if left to the +driver, only IFM data is cache cleaned/flushed). Due to the uncertainty of +tensor alignment, the driver only flushes/invalidates on base pointer level. + +By default the cache flush- and invalidation mask is set to only mark the +default scratch base pointer (base pointer 1). For maximum flexibility, the +driver provides a function to modify the cache flush/invalidate masks called +`ethosu_set_basep_cache_mask`. This function sets the two 8 bit masks, one for +flush and one for invalidate, where bit 0 corresponds to base pointer 0, bit 1 +corresponds to base pointer 1 etc. See `include/ethosu_driver.h` for more +information. + +An example implementation for the weak functions, using CMSIS primitives could +look like below: + +```[C++] +extern "C" { +// Deprecated - recommended to flush/clean in application code +// p must be 32 byte aligned +void ethosu_flush_dcache(uint32_t *p, size_t bytes) { + SCB_CleanDCache_by_Addr(p, bytes); +} + +// p must be 32 byte aligned +void ethosu_invalidate_dcache(uint32_t *p, size_t bytes) { + SCB_InvalidateDCache_by_Addr(p, bytes); +} +} +``` +The NPU contain memory attributes that should be set to match the settings used +in the MPU configuration for the memories used. See `NPU_MEM_ATTR_[0-3]` for +Ethos-U85 and the `AXI_LIMIT[0-3]_MEM_TYPE` for Ethos-U55/Ethos-U65 in +corresponding `src/ethosu_config_uX5.h` files. + +## Mutex and semaphores + +To ensure the correct functionality of the driver mutexes and semaphores are +used internally. The default implementations of mutexes and semaphores are +designed for a single-threaded baremetal environment. Hence for integration in +environemnts where multi-threading is possible, e.g., RTOS, the user is +responsible to provide implementation for mutexes and semaphores to be used by +the driver. + +The mutex and semaphores are used as synchronisation mechanisms and unless +specified, the timeout is required to be 'forever'. + +The driver allows for an RTOS to set a timeout for the NPU interrupt semaphore. +The timeout can be set with the CMake variable `ETHOSU_INFERENCE_TIMEOUT`, which +is then used as `timeout` argument for the interrupt semaphore take call. Note +that the unit is implementation defined, the value is shipped as is to the +`ethosu_semaphore_take()` function and an override implementation should cast it +to the appropriate type and/or convert it to the unit desired. + +A macro `ETHOSU_SEMAPHORE_WAIT_FOREVER` is defined in the driver header file, +and should be made sure to map to the RTOS' equivalent of +'no timeout/wait forever'. Inference timeout value defaults to this if left +unset. The macro is used internally in the driver for the available NPU's, thus +the driver does NOT support setting a timeout other than forever when waiting +for an NPU to become available (global ethosu_semaphore). + +The mutex and semaphore APIs are defined as weak linked functions that can be +overridden by the user. The APIs are the usual ones and described below: + +```[C] +// create a mutex by returning back a handle +void *ethosu_mutex_create(void); +// lock the given mutex +int ethosu_mutex_lock(void *mutex); +// unlock the given mutex +int ethosu_mutex_unlock(void *mutex); + +// create a (binary) semaphore by returning back a handle +void *ethosu_semaphore_create(void); +// take from the given semaphore, accepting a timeout (unit impl. defined) +int ethosu_semaphore_take(void *sem, uint64_t timeout); +// give from the given semaphore +int ethosu_semaphore_give(void *sem); +``` + +## Begin/End inference callbacks + +The driver provide weak linked functions as hooks to receive callbacks whenever +an inference begins and ends. The user can override such functions when needed. +To avoid memory leaks, any allocations done in the ethosu_inference_begin() must +be balanced by a corresponding free of the memory in the ethosu_inference_end() +callback. + +The end callback will always be called if the begin callback has been called, +including in the event of an interrupt semaphore take timeout. + +```[C] +void ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg); +void ethosu_inference_end(struct ethosu_driver *drv, void *user_arg); +``` + +Note that the `void *user_arg` pointer passed to invoke() function is the same +pointer passed to the begin() and end() callbacks. For example: + +```[C] +void my_function() { + ... + struct my_data data = {...}; + int result = int ethosu_invoke_v3(drv, + custom_data_ptr, + custom_data_size, + base_addr, + base_addr_size, + num_base_addr, + (void *)&data); + .... +} + +void ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg) { + struct my_data *data = (struct my_data*) user_arg; + // use drv and data here +} + +void ethosu_inference_end(struct ethosu_driver *drv, void *user_arg) { + struct my_data *data = (struct my_data*) user_arg; + // use drv and data here +} +``` + +## License + +The Arm Ethos-U core driver is provided under an Apache-2.0 license. Please see +[LICENSE.txt](LICENSE.txt) for more information. + +## Contributions + +The Arm Ethos-U project welcomes contributions under the Apache-2.0 license. + +Before we can accept your contribution, you need to certify its origin and give +us your permission. For this process we use the Developer Certificate of Origin +(DCO) V1.1 (https://developercertificate.org). + +To indicate that you agree to the terms of the DCO, you "sign off" your +contribution by adding a line with your name and e-mail address to every git +commit message. You must use your real name, no pseudonyms or anonymous +contributions are accepted. If there are more than one contributor, everyone +adds their name and e-mail to the commit message. + +```[] +Author: John Doe \ +Date: Mon Feb 29 12:12:12 2016 +0000 + +Title of the commit + +Short description of the change. + +Signed-off-by: John Doe john.doe@example.org +Signed-off-by: Foo Bar foo.bar@example.org +``` + +The contributions will be code reviewed by Arm before they can be accepted into +the repository. + +In order to submit a contribution, submit a merge request to the +[core_driver](https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-driver) +repository. To do this you will need to sign-up at [gitlab.arm.com](https://gitlab.arm.com) +and add your SSH key under your settings. + +## Security + +Please see [Security](SECURITY.md). + +## Trademark notice + +Arm, Cortex and Ethos are registered trademarks of Arm Limited (or its +subsidiaries) in the US and/or elsewhere. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/SECURITY.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/SECURITY.md new file mode 100644 index 0000000..29c6ce4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/SECURITY.md @@ -0,0 +1,85 @@ +# Security + +If you believe you have identified a security related issue or vulnerability, +then we encourage you to responsibly disclose it to us as soon as possible. + +## Reporting vulnerabilities + +Arm takes security issues seriously and welcomes feedback from researchers and +the security community in order to improve the security of its products and +services. We operate a coordinated disclosure policy for disclosing +vulnerabilities and other security issues. + +Security issues can be complex and one single timescale doesn't fit all +circumstances. We will make best endeavours to inform you when we expect +security notifications and fixes to be available and facilitate coordinated +disclosure when notifications and patches/mitigations are available. + +### Report + +For all security issues, contact Arm by email at +[arm-security@arm.com](mailto:arm-security@arm.com). In the body of the email +include as much information as possible about the issue or vulnerability and any +additional contact details. + +### Secure submission using PGP + +We support and encourage secure submission of vulnerability reports using PGP, +using the key below. If you would like replies to be encrypted, please provide +your own public key through a secure mechanism. + +~~~none +-----BEGIN PGP PUBLIC KEY BLOCK----- +mQINBFr7/RMBEACjHR5QZL/z1t2aLCRNXLE4KJiQmCo7edU5Be+7MTjIJDzZNu68 +lNEUYRoLexeayif8eC4T19bUsSbGpxHiYsFFjV8ewLXDyDJRRuaBGPfQ5rn/mE6X +Nvu+9Pputr+mB1R3CXcvrNkhmzPkK7zVM15oeyBMhogqPssuT4OeMduQdip8smfK +xTMk91RrJTLb+G3eE1tf+81kXBYvzp2e24Sn0/VeYe0IWnBobjVBZk3TmcYxDvz5 +Y47fU9V6cNj3Zq4VYrgxuLoFCA2VtetyiFQm5IYa3Bt3SWcAwihr8nbR2HoNdWyA +u8wJYYVzSq3hvT5l/IjTHxEcY+6RBq8poDSsftzvX386u9hmw7sJQFlTw6/pUjdr +gbsZ2ZzRBzKtU17ercpn4kU6VgVP3WRB5HiTFFkEpZuqAznOYaHbMq4dfd/g7Quq +C0VTbWiJnhku2i+g4BdHHRDtIF6U3aVQAfbrDb1LjVTa65p5ULOeY3HRAWtMNtu/ +Cj8cD98JDanzXtcnisds8vMQ8LZ6iMFChEnF8K4V0eLw9Ju6CMNiFYY7SEBndD/H +M4KcU4li7mROSbJcshgEbe1SYkxdMuI9eY4DNYxl3VjxoPUGzeqXo/ADFKE9bHsi +GTyEoij4ku0HspLVKnYHXn/LqHGwEcwjF8zphS+w5cn/e01akYwz5EVSQwARAQAB +tB1Bcm0gU3VwcG9ydCA8c3VwcG9ydEBhcm0uY29tPokCTgQTAQgAOBYhBN9zqDwZ +RL/vF0ihcdfNKdz4bBRiBQJa+/0TAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA +AAoJENfNKdz4bBRibK0P/jLlJR/QYypcjb+8BnHT9tCDgcV2KFYXS15VpbSNviN9 +Xs/UOnSadoGUMGCXDyb1PRNn98yUn7JlNR9rtsqPRmkpbo5cuw46ehgxjVlfcHnk +CttaE8Davx6zo0fyrBib2+oVVW8usi9+uRK4vhhPUicO3oXwzldsVFz+RbpubZxc +Bg/CZ+dQ2jMKOv1zDtInOG6OBnbQZRAeiWXgGhcIoPZ4zBQOi8nr0+bLcfvMeZi2 +uz6uKnylpXwZbl4ijcG8MKV/ei+7du+SzA9NY0WOT2g3FXDREWUhjKs8bmEZgIx4 +QgvDNpxAUThF+TqQ7zrsA8nT8POvDD0MhN/Z+A3QdPTdcaZFaXzIdxbDg+0FKmzu +OgtQBH4C01RWrkmZlhO5w7/Qjt0vLlhfyQIL9BW/HeEPtjnH2Hnq8xYnZhlVqJEh +FJU7F9sMvyiJiKviobFTd6AmpVkhxhcJ3k2L2C03imTsmUwAoejQCXwiYcOhyQ2t +Z9Nk8YIZTEw2urGFi4HSQPwPq2j/2j7ABJ4rlzJvO6vs5ppGkumvzIIP9JnpVXbp +wcbK6Ev6KdkX4s14Mzd6Hsd8LpL8t5nHhxUey6G0xKe2eSlHVm5Mlfhoete9UmIZ +dzIOZkgTgWXlYXRIxwGQ2Pss7pURtofykvLklq4jcobQuHxurl9cteodETfbWk/J +uQINBFr7/RMBEADWZG8eqt5D22g3T7ehnH/T3fuTX8LPUBnODMWGAEUY8uv64To8 +46odvrXFgWBgCf0sROEyJchc3SGLyR9S4lJsVJRde3QLN3WZkHlB4pSn4IQHFyQd +wsLQi+S9uggHMPlQ6MNvc5n0P3k5bT9fLUmtJWJ3QVjW7k963ZXpzf1zbQJqs30w +rlqGUZllfRoYQTfcYxFEaUFhwRJ//skNImWH8Vz+PTnqg2zRtFn3usrBV4GpNvsM +6jy+YEsSvUa7IY8k4wpPzEhIfqDjGbZxFSQ1H1G+mLUL+DD7oGffej/ZoC86TIdM +p6ew1rGhJdQBLh9nx+1ADOLWjNo2R0h60u7VR5q/K6V4fwWmeGFipPXZCD92I+nR +t/cjznwNyD/6J9YrBMF7mbGrS1TyfLaLt4tpdcBnsgqDTodd5OmG65mroXsg/lNO +7YZdecLZ34krfaLrWTtKkqULXbppB+uQvbVj8p8ONRImn6bZ+iAhnNaH9wJ06ico +b1F0imJ2SJWnFr6PzPRr0gPStLgu9wrRKheaORwF/H/HxSyPZxNVxFqu81q518A/ +plhub9INQLaxHf/TTjXpqZCcfdNTYUAW8rwbQfW9doSIT4lHY8bJXktb6BsVjkFj +PzDeYpXeOoTWetQqsEuTdg/F+qg041QBLtNj9Lr3Vy3StgMciRUIP8m0XwARAQAB +iQI2BBgBCAAgFiEE33OoPBlEv+8XSKFx180p3PhsFGIFAlr7/RMCGwwACgkQ180p +3PhsFGLWMA//V/XKrnI2YBh/SptUrgg7knPXva45bb7tGSH1fJg8f/wqycOSFFCY +ES45boA5jlQ3z8uw6BYCz5KeOucGhxAMw+x5EDdxZ33ksY5zqXB35WaMXzEwGYYb +E113/yhOsTbzu4bBKABSXbJO98MdAWvWpyCpp2MHIR3S9+ycM7/FMZ5xi3czZNRg +9+WZP+7W4qWhJptQ0kBh5C3N/tiltju5WQ2Y7XIn+5dMOJdtseFS7CNerxXZGAtH +nfRxaD/4ENdbWOwaVJiVW7+ioUJz09OWgy0gLYSDW+hciDnW1QAaJLpdAbniGZ0S +JsTmaZla8JnUKqZPgbFfA2OcnH9H+DWc0pHv17c5tJzTMP7rgirgGRX/U2LOzmFZ +1UxjQj5nn3Oa5frXbIAzb8xKiR0VDaquCM/3sti1AesYiS0Gw0Sqnw8qpFypgFXN +CKVgYXppIT+TmbDbNJDOB2UycxeI4vbiBwU8fI4qSpW12WsGdAJt/rx3UsyhZ+02 +4aSqDHzhJmtDPQ6lnaKe1fUkC90tgp8loVGmriWQx82jAQMqATVjIklTpE4vm00f +ocQIWOKEE90mKNEoV6rNbfl5QevmapTVdV/pmrRBzhbsa1uAUS4HZdH0Nf/OXEyv +yYCr2gCFPymkkRYhPr2w5EgbWyzLaBIwqjyIbXaveuB3DYi2Lhbf64I= +=EaN7 +-----END PGP PUBLIC KEY BLOCK----- +~~~ + +For more information visit + \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h new file mode 100644 index 0000000..1e71791 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h @@ -0,0 +1,399 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_DRIVER_H +#define ETHOSU_DRIVER_H + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "ethosu_types.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define ETHOSU_DRIVER_VERSION_MAJOR 0 ///< Driver major version +#define ETHOSU_DRIVER_VERSION_MINOR 16 ///< Driver minor version +#define ETHOSU_DRIVER_VERSION_PATCH 0 ///< Driver patch version + +#define ETHOSU_SEMAPHORE_WAIT_FOREVER (UINT64_MAX) + +#ifndef ETHOSU_SEMAPHORE_WAIT_INFERENCE +#define ETHOSU_SEMAPHORE_WAIT_INFERENCE ETHOSU_SEMAPHORE_WAIT_FOREVER +#endif + +/****************************************************************************** + * Types + ******************************************************************************/ + +enum ethosu_job_state +{ + ETHOSU_JOB_IDLE = 0, + ETHOSU_JOB_RUNNING, + ETHOSU_JOB_DONE +}; + +enum ethosu_job_result +{ + ETHOSU_JOB_RESULT_OK = 0, + ETHOSU_JOB_RESULT_TIMEOUT, + ETHOSU_JOB_RESULT_ERROR +}; + +struct ethosu_job +{ + volatile enum ethosu_job_state state; + volatile enum ethosu_job_result result; + const void *custom_data_ptr; + int custom_data_size; + const uint64_t *base_addr; + const size_t *base_addr_size; + int num_base_addr; + void *user_arg; +}; + +struct ethosu_driver +{ + struct ethosu_device dev; + struct ethosu_driver *next; + struct ethosu_job job; + void *semaphore; + uint64_t fast_memory; + size_t fast_memory_size; + uint32_t power_request_counter; + bool reserved; + uint8_t basep_flush_mask; + uint8_t basep_invalidate_mask; +}; + +struct ethosu_driver_version +{ + uint8_t major; + uint8_t minor; + uint8_t patch; +}; + +enum ethosu_request_clients +{ + ETHOSU_PMU_REQUEST = 0, + ETHOSU_INFERENCE_REQUEST = 1, +}; + +/****************************************************************************** + * Prototypes (weak functions in driver) + ******************************************************************************/ + +/** + * Interrupt handler to be called on IRQ from Ethos-U + * + * @param drv Pointer to driver handle + */ +void ethosu_irq_handler(struct ethosu_driver *drv); + +/** + * Flush/clean the data cache by address and size. + * NOTE: It is not recommended to implement this, but let the application code + * make sure that any data needed by the NPU is flushed before invoking + * an inference. + * + * Addresses passed to this function must be 32 byte aligned. + * + * @param p 32 byte aligned address + * @param bytes Size of memory block in bytes + */ +void ethosu_flush_dcache(uint32_t *p, size_t bytes); + +/** + * Invalidate the data cache by address and size. + * NOTE: The driver will only call this for the scratch/tensor arena base + * pointer. + * + * Addresses passed to this function must be 32 byte aligned. + * + * @param p 32 byte aligned address + * @param bytes Size in bytes + */ +void ethosu_invalidate_dcache(uint32_t *p, size_t bytes); + +/** + * Minimal mutex implementation for baremetal applications. See + * ethosu_driver.c. + * + * @return Pointer to mutex handle + */ +void *ethosu_mutex_create(void); + +/** + * Destroy mutex. + * + * @param mutex Pointer to mutex handle + */ +void ethosu_mutex_destroy(void *mutex); + +/** + * Minimal sempahore implementation for baremetal applications. See + * ethosu_driver.c. + * + * @return Pointer to semaphore handle + */ +void *ethosu_semaphore_create(void); + +/** + * Destroy semaphore. + * + * @param sem Pointer to semaphore handle + */ +void ethosu_semaphore_destroy(void *sem); + +/** + * Lock mutex. + * + * @param mutex Pointer to mutex handle + * @returns 0 on success, else negative error code + */ +int ethosu_mutex_lock(void *mutex); + +/** + * Unlock mutex. + * + * @param mutex Pointer to mutex handle + * @returns 0 on success, else negative error code + */ +int ethosu_mutex_unlock(void *mutex); + +/** + * Take semaphore. + * + * @param sem Pointer to semaphore handle + * @param timeout Timeout value (unit impl. defined) + * @returns 0 on success else negative error code + */ +int ethosu_semaphore_take(void *sem, uint64_t timeout); + +/** + * Give semaphore. + * + * @param sem Pointer to semaphore handle + * @returns 0 on success, else negative error code + */ +int ethosu_semaphore_give(void *sem); + +/** + * Callback invoked just before the inference is started. + * + * @param drv Pointer to driver handle + * @param user_arg User argument provided to ethosu_invoke_*() + */ +void ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg); + +/** + * Callback invoked just after the inference has completed. + * + * @param drv Pointer to driver handle + * @param user_arg User argument provided to ethosu_invoke_*() + */ +void ethosu_inference_end(struct ethosu_driver *drv, void *user_arg); + +/** + * Remapping command stream and base pointer addresses. + * + * @param address Address to be remapped. + * @param index -1 command stream, 0-n base address index + * + * @return Remapped address + */ +uint64_t ethosu_address_remap(uint64_t address, int index); + +/****************************************************************************** + * Prototypes + ******************************************************************************/ + +/** + * Set cache mask for cache flush/clean and invalidation per base pointer. + * + * @param drv Pointer to driver handle + * @param flush_mask Base pointer cache flush mask (bit 0 == basep 0) + * @param invalidate_mask Base pointer cache invalidation mask (bit 0 == basep 0) + */ +void ethosu_set_basep_cache_mask(struct ethosu_driver *drv, uint8_t flush_mask, uint8_t invalidate_mask); + +/** + * Initialize the Ethos-U driver. + * + * @param drv Pointer to driver handle + * @param base_address NPU register base address + * @param fast_memory Fast memory area, used for Ethos-U65 with spilling + * @param fast_memory_size Size in bytes of fast memory area + * @param secure_enable Configure NPU in secure- or non-secure mode + * @param privilege_enable Configure NPU in privileged- or non-privileged mode + * @return 0 on success, else negative error code + */ +int ethosu_init(struct ethosu_driver *drv, + void *const base_address, + const void *fast_memory, + const size_t fast_memory_size, + uint32_t secure_enable, + uint32_t privilege_enable); + +/** + * Deinitialize the Ethos-U driver. + * + * @param drv Pointer to driver handle + */ +void ethosu_deinit(struct ethosu_driver *drv); + +/** + * Soft resets the Ethos-U device. + * + * @param drv Pointer to driver handle + * @return 0 on success, else negative error code + */ +int ethosu_soft_reset(struct ethosu_driver *drv); + +/** + * Request to disable Q-channel power gating of the Ethos-U device. + * Power requests are ref.counted. Increases count. + * (Note: clock gating is made to follow power gating) + * + * @param drv Pointer to driver handle + * @return 0 on success, else negative error code + */ +int ethosu_request_power(struct ethosu_driver *drv); + +/** + * Release disable request for Q-channel power gating of the Ethos-U device. + * Power requests are ref.counted. Decreases count. + * + * @param drv Pointer to driver handle + */ +void ethosu_release_power(struct ethosu_driver *drv); + +/** + * Get Ethos-U driver version. + * + * @param ver Driver version struct + */ +void ethosu_get_driver_version(struct ethosu_driver_version *ver); + +/** + * Get Ethos-U hardware information. + * + * @param drv Pointer to driver handle + * @param hw Hardware information struct + */ +void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw); + +/** + * Invoke command stream. + * + * @param drv Pointer to driver handle + * @param custom_data_ptr Custom data payload + * @param custom_data_size Size in bytes of custom data + * @param base_addr Array of base address pointers + * @param base_addr_size Size in bytes of each address in base_addr + * @param num_base_addr Number of elements in base_addr array + * @param user_arg User argument, will be passed to + * ethosu_inference_begin() and ethosu_inference_end() + * @return 0 on success, else negative error code + */ +int ethosu_invoke_v3(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg); + +#define ethosu_invoke(drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr) \ + ethosu_invoke_v3(drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr, 0) + +/** + * Invoke command stream using async interface. + * Must be followed by call(s) to ethosu_wait() upon successful return. + * + * @see ethosu_invoke_v3 for documentation. + */ +int ethosu_invoke_async(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg); + +/** + * Wait for inference to complete (block=true) + * Poll status or finish up if inference is complete (block=false) + * (This function is only intended to be used in conjuction with ethosu_invoke_async) + * + * @param drv Pointer to driver handle + * @param block If call should block if inference is running + * @return -2 on inference not invoked, -1 on inference error, 0 on success, 1 on inference running + */ +int ethosu_wait(struct ethosu_driver *drv, bool block); + +/** + * Reserves a driver to execute inference with. Call will block until a driver + * is available. + * + * @return Pointer to driver handle. + */ +struct ethosu_driver *ethosu_reserve_driver(void); + +/** + * Release driver that was previously reserved with @see ethosu_reserve_driver. + * + * @param drv Pointer to driver handle + */ +void ethosu_release_driver(struct ethosu_driver *drv); + +/** + * Static inline for backwards-compatibility. + * + * @see ethosu_invoke_v3 for documentation. + */ +static inline int ethosu_invoke_v2(const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr) +{ + struct ethosu_driver *drv = ethosu_reserve_driver(); + if (!drv) + { + return -1; + } + int result = ethosu_invoke_v3(drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr, 0); + ethosu_release_driver(drv); + return result; +} + +#ifdef __cplusplus +} +#endif + +#endif // ETHOSU_DRIVER_H diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h new file mode 100644 index 0000000..9d14a60 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2021, 2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_TYPES_H +#define ETHOSU_TYPES_H + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include + +/****************************************************************************** + * Types + ******************************************************************************/ + +struct NPU_REG; // Forward declare, to be implemented by each device + +struct ethosu_device +{ + volatile struct NPU_REG *reg; // Register map + uint32_t secure; + uint32_t privileged; +}; + +enum ethosu_error_codes +{ + ETHOSU_SUCCESS = 0, ///< Success + ETHOSU_GENERIC_FAILURE = -1, ///< Generic failure + ETHOSU_INVALID_PARAM = -2 ///< Invalid parameter +}; + +enum ethosu_clock_q_request +{ + ETHOSU_CLOCK_Q_DISABLE = 0, ///< Disable NPU signal ready for clock off. + ETHOSU_CLOCK_Q_ENABLE = 1, ///< Enable NPU signal ready for clock off when stop+idle state reached. + ETHOSU_CLOCK_Q_UNCHANGED = 2 ///< Keep current clock q setting +}; + +enum ethosu_power_q_request +{ + ETHOSU_POWER_Q_DISABLE = 0, ///< Disable NPU signal ready for power off. + ETHOSU_POWER_Q_ENABLE = 1, ///< Enable NPU signal ready for power off when stop+idle state reached. + ETHOSU_POWER_Q_UNCHANGED = 2 ///< Keep current power q setting +}; + +struct ethosu_id +{ + uint32_t version_status; ///< Version status + uint32_t version_minor; ///< Version minor + uint32_t version_major; ///< Version major + uint32_t product_major; ///< Product major + uint32_t arch_patch_rev; ///< Architecture version patch + uint32_t arch_minor_rev; ///< Architecture version minor + uint32_t arch_major_rev; ///< Architecture version major +}; + +struct ethosu_config +{ + uint32_t macs_per_cc; ///< MACs per clock cycle + uint32_t cmd_stream_version; ///< NPU command stream version + uint32_t custom_dma; ///< Custom DMA enabled +}; + +struct ethosu_hw_info +{ + struct ethosu_id version; + struct ethosu_config cfg; +}; +#endif // ETHOSU_TYPES_H diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h new file mode 100644 index 0000000..76abc61 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h @@ -0,0 +1,515 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PMU_ETHOSU_H +#define PMU_ETHOSU_H + +/***************************************************************************** + * Includes + *****************************************************************************/ +#include + +#include "ethosu_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************** + * Defines + *****************************************************************************/ +#ifdef ETHOSU85 +#define ETHOSU_PMU_NCOUNTERS 8 +#else +#define ETHOSU_PMU_NCOUNTERS 4 +#endif + +#define ETHOSU_PMU_CNT1_Msk (1UL << 0) +#define ETHOSU_PMU_CNT2_Msk (1UL << 1) +#define ETHOSU_PMU_CNT3_Msk (1UL << 2) +#define ETHOSU_PMU_CNT4_Msk (1UL << 3) +#ifdef ETHOSU85 +#define ETHOSU_PMU_CNT5_Msk (1UL << 4) +#define ETHOSU_PMU_CNT6_Msk (1UL << 5) +#define ETHOSU_PMU_CNT7_Msk (1UL << 6) +#define ETHOSU_PMU_CNT8_Msk (1UL << 7) +#endif + +#define ETHOSU_PMU_CCNT_Msk (1UL << 31) + +/***************************************************************************** + * Types + *****************************************************************************/ + +/** \brief HW Supported ETHOSU PMU Events + * + * Note: These values are symbolic. Actual HW-values may change. I.e. always use API + * to set/get actual event-type value. + * */ +#if defined(ETHOSU55) || defined(ETHOSU65) +enum ethosu_pmu_event_type +{ + ETHOSU_PMU_NO_EVENT = 0, + ETHOSU_PMU_CYCLE, + ETHOSU_PMU_NPU_IDLE, + ETHOSU_PMU_CC_STALLED_ON_BLOCKDEP, + ETHOSU_PMU_CC_STALLED_ON_SHRAM_RECONFIG, + ETHOSU_PMU_NPU_ACTIVE, + ETHOSU_PMU_MAC_ACTIVE, + ETHOSU_PMU_MAC_ACTIVE_8BIT, + ETHOSU_PMU_MAC_ACTIVE_16BIT, + ETHOSU_PMU_MAC_DPU_ACTIVE, + ETHOSU_PMU_MAC_STALLED_BY_WD_ACC, + ETHOSU_PMU_MAC_STALLED_BY_WD, + ETHOSU_PMU_MAC_STALLED_BY_ACC, + ETHOSU_PMU_MAC_STALLED_BY_IB, + ETHOSU_PMU_MAC_ACTIVE_32BIT, + ETHOSU_PMU_MAC_STALLED_BY_INT_W, + ETHOSU_PMU_MAC_STALLED_BY_INT_ACC, + ETHOSU_PMU_AO_ACTIVE, + ETHOSU_PMU_AO_ACTIVE_8BIT, + ETHOSU_PMU_AO_ACTIVE_16BIT, + ETHOSU_PMU_AO_STALLED_BY_OFMP_OB, + ETHOSU_PMU_AO_STALLED_BY_OFMP, + ETHOSU_PMU_AO_STALLED_BY_OB, + ETHOSU_PMU_AO_STALLED_BY_ACC_IB, + ETHOSU_PMU_AO_STALLED_BY_ACC, + ETHOSU_PMU_AO_STALLED_BY_IB, + ETHOSU_PMU_WD_ACTIVE, + ETHOSU_PMU_WD_STALLED, + ETHOSU_PMU_WD_STALLED_BY_WS, + ETHOSU_PMU_WD_STALLED_BY_WD_BUF, + ETHOSU_PMU_WD_PARSE_ACTIVE, + ETHOSU_PMU_WD_PARSE_STALLED, + ETHOSU_PMU_WD_PARSE_STALLED_IN, + ETHOSU_PMU_WD_PARSE_STALLED_OUT, + ETHOSU_PMU_WD_TRANS_WS, + ETHOSU_PMU_WD_TRANS_WB, + ETHOSU_PMU_WD_TRANS_DW0, + ETHOSU_PMU_WD_TRANS_DW1, + ETHOSU_PMU_AXI0_RD_TRANS_ACCEPTED, + ETHOSU_PMU_AXI0_RD_TRANS_COMPLETED, + ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_AXI0_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI0_WR_TRANS_ACCEPTED, + ETHOSU_PMU_AXI0_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_AXI0_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_AXI0_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI0_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_AXI0_ENABLED_CYCLES, + ETHOSU_PMU_AXI0_RD_STALL_LIMIT, + ETHOSU_PMU_AXI0_WR_STALL_LIMIT, + ETHOSU_PMU_AXI_LATENCY_ANY, + ETHOSU_PMU_AXI_LATENCY_32, + ETHOSU_PMU_AXI_LATENCY_64, + ETHOSU_PMU_AXI_LATENCY_128, + ETHOSU_PMU_AXI_LATENCY_256, + ETHOSU_PMU_AXI_LATENCY_512, + ETHOSU_PMU_AXI_LATENCY_1024, + ETHOSU_PMU_ECC_DMA, + ETHOSU_PMU_ECC_SB0, + ETHOSU_PMU_AXI1_RD_TRANS_ACCEPTED, + ETHOSU_PMU_AXI1_RD_TRANS_COMPLETED, + ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_AXI1_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI1_WR_TRANS_ACCEPTED, + ETHOSU_PMU_AXI1_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_AXI1_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_AXI1_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_AXI1_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI1_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_AXI1_ENABLED_CYCLES, + ETHOSU_PMU_AXI1_RD_STALL_LIMIT, + ETHOSU_PMU_AXI1_WR_STALL_LIMIT, + ETHOSU_PMU_ECC_SB1, + + ETHOSU_PMU_SENTINEL // End-marker (not event) +}; +#elif defined(ETHOSU85) +enum ethosu_pmu_event_type +{ + ETHOSU_PMU_NO_EVENT = 0, + ETHOSU_PMU_CYCLE, + ETHOSU_PMU_NPU_IDLE, + ETHOSU_PMU_CC_STALLED_ON_BLOCKDEP, + ETHOSU_PMU_NPU_ACTIVE, + ETHOSU_PMU_MAC_ACTIVE, + ETHOSU_PMU_MAC_DPU_ACTIVE, + ETHOSU_PMU_MAC_STALLED_BY_W_OR_ACC, + ETHOSU_PMU_MAC_STALLED_BY_W, + ETHOSU_PMU_MAC_STALLED_BY_ACC, + ETHOSU_PMU_MAC_STALLED_BY_IB, + ETHOSU_PMU_AO_ACTIVE, + ETHOSU_PMU_AO_STALLED_BY_BS_OR_OB, + ETHOSU_PMU_AO_STALLED_BY_BS, + ETHOSU_PMU_AO_STALLED_BY_OB, + ETHOSU_PMU_AO_STALLED_BY_AB_OR_CB, + ETHOSU_PMU_AO_STALLED_BY_AB, + ETHOSU_PMU_AO_STALLED_BY_CB, + ETHOSU_PMU_WD_ACTIVE, + ETHOSU_PMU_WD_STALLED, + ETHOSU_PMU_WD_STALLED_BY_WD_BUF, + ETHOSU_PMU_WD_STALLED_BY_WS_FC, + ETHOSU_PMU_WD_STALLED_BY_WS_TC, + ETHOSU_PMU_WD_TRANS_WBLK, + ETHOSU_PMU_WD_TRANS_WS_FC, + ETHOSU_PMU_WD_TRANS_WS_TC, + ETHOSU_PMU_WD_STALLED_BY_WS_SC0, + ETHOSU_PMU_WD_STALLED_BY_WS_SC1, + ETHOSU_PMU_WD_STALLED_BY_WS_SC2, + ETHOSU_PMU_WD_STALLED_BY_WS_SC3, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC0, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC1, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC2, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC3, + ETHOSU_PMU_WD_PARSE_STALL_SC0, + ETHOSU_PMU_WD_PARSE_STALL_SC1, + ETHOSU_PMU_WD_PARSE_STALL_SC2, + ETHOSU_PMU_WD_PARSE_STALL_SC3, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC0, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC1, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC2, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC3, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC0, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC1, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC2, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC3, + ETHOSU_PMU_WD_TRANS_WS_SC0, + ETHOSU_PMU_WD_TRANS_WS_SC1, + ETHOSU_PMU_WD_TRANS_WS_SC2, + ETHOSU_PMU_WD_TRANS_WS_SC3, + ETHOSU_PMU_WD_TRANS_WB0, + ETHOSU_PMU_WD_TRANS_WB1, + ETHOSU_PMU_WD_TRANS_WB2, + ETHOSU_PMU_WD_TRANS_WB3, + ETHOSU_PMU_SRAM_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM_ENABLED_CYCLES, + ETHOSU_PMU_SRAM_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM_WR_STALL_LIMIT, + ETHOSU_PMU_AXI_LATENCY_ANY, + ETHOSU_PMU_AXI_LATENCY_32, + ETHOSU_PMU_AXI_LATENCY_64, + ETHOSU_PMU_AXI_LATENCY_128, + ETHOSU_PMU_AXI_LATENCY_256, + ETHOSU_PMU_AXI_LATENCY_512, + ETHOSU_PMU_AXI_LATENCY_1024, + ETHOSU_PMU_ECC_DMA, + ETHOSU_PMU_ECC_MAC_IB, + ETHOSU_PMU_ECC_MAC_AB, + ETHOSU_PMU_ECC_AO_CB, + ETHOSU_PMU_ECC_AO_OB, + ETHOSU_PMU_ECC_AO_LUT, + ETHOSU_PMU_EXT_RD_TRANS_ACCEPTED, + ETHOSU_PMU_EXT_RD_TRANS_COMPLETED, + ETHOSU_PMU_EXT_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_EXT_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT_WR_TRANS_ACCEPTED, + ETHOSU_PMU_EXT_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_EXT_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_EXT_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_EXT_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_EXT_ENABLED_CYCLES, + ETHOSU_PMU_EXT_RD_STALL_LIMIT, + ETHOSU_PMU_EXT_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM0_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM0_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM0_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM0_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM0_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM0_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM0_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM0_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM0_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM0_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM0_ENABLED_CYCLES, + ETHOSU_PMU_SRAM0_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM0_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM1_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM1_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM1_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM1_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM1_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM1_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM1_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM1_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM1_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM1_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM1_ENABLED_CYCLES, + ETHOSU_PMU_SRAM1_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM1_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM2_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM2_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM2_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM2_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM2_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM2_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM2_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM2_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM2_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM2_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM2_ENABLED_CYCLES, + ETHOSU_PMU_SRAM2_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM2_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM3_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM3_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM3_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM3_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM3_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM3_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM3_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM3_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM3_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM3_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM3_ENABLED_CYCLES, + ETHOSU_PMU_SRAM3_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM3_WR_STALL_LIMIT, + ETHOSU_PMU_EXT0_RD_TRANS_ACCEPTED, + ETHOSU_PMU_EXT0_RD_TRANS_COMPLETED, + ETHOSU_PMU_EXT0_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_EXT0_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT0_WR_TRANS_ACCEPTED, + ETHOSU_PMU_EXT0_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_EXT0_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_EXT0_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_EXT0_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT0_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_EXT0_ENABLED_CYCLES, + ETHOSU_PMU_EXT0_RD_STALL_LIMIT, + ETHOSU_PMU_EXT0_WR_STALL_LIMIT, + ETHOSU_PMU_EXT1_RD_TRANS_ACCEPTED, + ETHOSU_PMU_EXT1_RD_TRANS_COMPLETED, + ETHOSU_PMU_EXT1_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_EXT1_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT1_WR_TRANS_ACCEPTED, + ETHOSU_PMU_EXT1_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_EXT1_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_EXT1_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_EXT1_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT1_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_EXT1_ENABLED_CYCLES, + ETHOSU_PMU_EXT1_RD_STALL_LIMIT, + ETHOSU_PMU_EXT1_WR_STALL_LIMIT, + + ETHOSU_PMU_SENTINEL // End-marker (not event) +}; +#else +#error No NPU target defined +#endif + +/***************************************************************************** + * Functions + *****************************************************************************/ + +/** + * \brief Enable the PMU + */ +void ETHOSU_PMU_Enable(struct ethosu_driver *drv); + +/** + * \brief Disable the PMU + */ +void ETHOSU_PMU_Disable(struct ethosu_driver *drv); + +/** + * \brief Set event to count for PMU eventer counter + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) to configure + * \param [in] type Event to count + */ +void ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type); + +/** + * \brief Get number of PMU event counters + * \return Number of event counters + */ +uint32_t ETHOSU_PMU_Get_NumEventCounters(void); + +/** + * \brief Get event to count for PMU eventer counter + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) to configure + * \return type Event to count + */ +enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(struct ethosu_driver *drv, uint32_t num); + +/** + * \brief Reset cycle counter + */ +void ETHOSU_PMU_CYCCNT_Reset(struct ethosu_driver *drv); + +/** + * \brief Reset all event counters + */ +void ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver *drv); + +/** + * \brief Enable counters + * \param [in] mask Counters to enable + * \note Enables one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_CNTR_Enable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Disable counters + * \param [in] mask Counters to disable + * \note Disables one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_CNTR_Disable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Determine counters activation + * + * \return Event count + * \param [in] mask Counters to enable + * \return a bitmask where bit-set means: + * - event counters activated (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter activate (bit 31) + * \note ETHOSU specific. Usage breaks CMSIS complience + */ +uint32_t ETHOSU_PMU_CNTR_Status(struct ethosu_driver *drv); + +/** + * \brief Read cycle counter (64 bit) + * \return Cycle count + * \note Two HW 32-bit registers that can increment independently in-between reads. + * To work-around raciness yet still avoid turning + * off the event both are read as one value twice. If the latter read + * is not greater than the former, it means overflow of LSW without + * incrementing MSW has occurred, in which case the former value is used. + */ +uint64_t ETHOSU_PMU_Get_CCNTR(struct ethosu_driver *drv); + +/** + * \brief Set cycle counter (64 bit) + * \param [in] val Conter value + * \note Two HW 32-bit registers that can increment independently in-between reads. + * To work-around raciness, counter is temporary disabled if enabled. + * \note ETHOSU specific. Usage breaks CMSIS complience + */ +void ETHOSU_PMU_Set_CCNTR(struct ethosu_driver *drv, uint64_t val); + +/** + * \brief Read event counter + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) + * \return Event count + */ +uint32_t ETHOSU_PMU_Get_EVCNTR(struct ethosu_driver *drv, uint32_t num); + +/** + * \brief Set event counter value + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) + * \param [in] val Conter value + * \note ETHOSU specific. Usage breaks CMSIS complience + */ +void ETHOSU_PMU_Set_EVCNTR(struct ethosu_driver *drv, uint32_t num, uint32_t val); + +/** + * \brief Read counter overflow status + * \return Counter overflow status bits for the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS)) + * - cycle counter (bit 31) + */ +uint32_t ETHOSU_PMU_Get_CNTR_OVS(struct ethosu_driver *drv); + +/** + * \brief Clear counter overflow status + * \param [in] mask Counter overflow status bits to clear + * \note Clears overflow status bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_Set_CNTR_OVS(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Enable counter overflow interrupt request + * \param [in] mask Counter overflow interrupt request bits to set + * \note Sets overflow interrupt request bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_Set_CNTR_IRQ_Enable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Disable counter overflow interrupt request + * \param [in] mask Counter overflow interrupt request bits to clear + * \note Clears overflow interrupt request bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_Set_CNTR_IRQ_Disable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Get counters overflow interrupt request stiinings + * \return mask Counter overflow interrupt request bits + * \note Sets overflow interrupt request bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + * \note ETHOSU specific. Usage breaks CMSIS compliance + */ +uint32_t ETHOSU_PMU_Get_IRQ_Enable(struct ethosu_driver *drv); + +/** + * \brief Software increment event counter + * \param [in] mask Counters to increment + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + * \note Software increment bits for one or more event counters. + */ +void ETHOSU_PMU_CNTR_Increment(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Set start event number for the cycle counter + * \param [in] start_event Event to trigger start of the cycle counter + * \note Sets the event number that starts the cycle counter. + */ +void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type start_event); + +/** + * \brief Set stop event number for the cycle counter + * \param [in] stop_event Event number + * \note Sets the event number that stops the cycle counter. + */ +void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type stop_event); + +/** + * \brief Read qread register + */ +uint32_t ETHOSU_PMU_Get_QREAD(struct ethosu_driver *drv); + +/** + * \brief Read status register + */ +uint32_t ETHOSU_PMU_Get_STATUS(struct ethosu_driver *drv); + +#ifdef __cplusplus +} +#endif + +#endif /* PMU_ETHOSU_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h new file mode 100644 index 0000000..37472b9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h @@ -0,0 +1,26197 @@ +/* + * Copyright (c) 2020-2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU55_INTERFACE_H +#define ETHOSU55_INTERFACE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#if !defined(__cplusplus) || __cplusplus < 201402L +#define CONSTEXPR +#else +#define CONSTEXPR constexpr +#endif + +#ifndef __cplusplus +#define STRUCT struct +#else +#define STRUCT +#endif + +#if defined(__cplusplus) && defined(NPU_DISASSEMBLE) +#include +#include +#include +#endif + +#if defined(__cplusplus) && !defined(NPU_NAMESPACE) +#define NPU_NAMESPACE npu +#endif + +#ifdef __cplusplus +#include +#include +#endif + +#ifdef __cplusplus +namespace NPU_NAMESPACE +{ +#endif +#define NNX_ARCH_VERSION_MAJOR 1 +#define NNX_ARCH_VERSION_MINOR 1 +#define NNX_ARCH_VERSION_PATCH 0 + +// Register offsets +// +// Register subpage BASE +// +#define NPU_REG_ID 0x0000 +#define NPU_REG_STATUS 0x0004 +#define NPU_REG_CMD 0x0008 +#define NPU_REG_RESET 0x000C +#define NPU_REG_QBASE 0x0010 +#define NPU_REG_QBASE_HI 0x0014 +#define NPU_REG_QREAD 0x0018 +#define NPU_REG_QCONFIG 0x001C +#define NPU_REG_QSIZE 0x0020 +#define NPU_REG_PROT 0x0024 +#define NPU_REG_CONFIG 0x0028 +#define NPU_REG_LOCK 0x002C +#define NPU_REG_REGIONCFG 0x003C +#define NPU_REG_AXI_LIMIT0 0x0040 +#define NPU_REG_AXI_LIMIT1 0x0044 +#define NPU_REG_AXI_LIMIT2 0x0048 +#define NPU_REG_AXI_LIMIT3 0x004C +#define BASE_REGISTERS_SIZE 0x0080 + +// +// Register subpage BASE_POINTERS +// +#define NPU_REG_BASEP_BASE 0x0080 +#define NPU_REG_BASEP_ARRLEN 0x0008 +#define BASE_POINTERS_REGISTERS_SIZE 0x0100 + +// +// Register subpage DEBUG +// +#define NPU_REG_WD_STATUS 0x0100 +#define NPU_REG_MAC_STATUS 0x0104 +#define NPU_REG_AO_STATUS 0x0108 +#define NPU_REG_DMA_STATUS0 0x0110 +#define NPU_REG_DMA_STATUS1 0x0114 +#define NPU_REG_CLKFORCE 0x0140 +#define NPU_REG_DEBUG_ADDRESS 0x0144 +#define NPU_REG_DEBUG_MISC 0x0148 +#define NPU_REG_DEBUG_BLOCK 0x0150 +#define DEBUG_REGISTERS_SIZE 0x0180 + +// +// Register subpage PMU +// +#define NPU_REG_PMCR 0x0180 +#define NPU_REG_PMCNTENSET 0x0184 +#define NPU_REG_PMCNTENCLR 0x0188 +#define NPU_REG_PMOVSSET 0x018C +#define NPU_REG_PMOVSCLR 0x0190 +#define NPU_REG_PMINTSET 0x0194 +#define NPU_REG_PMINTCLR 0x0198 +#define NPU_REG_PMCCNTR 0x01A0 +#define NPU_REG_PMCCNTR_HI 0x01A4 +#define NPU_REG_PMCCNTR_CFG 0x01A8 +#define NPU_REG_PMCAXI_CHAN 0x01AC +#define PMU_REGISTERS_SIZE 0x0200 + +// +// Register subpage TSU_DEBUG +// +#define NPU_REG_KERNEL_X 0x0200 +#define NPU_REG_KERNEL_Y 0x0204 +#define NPU_REG_KERNEL_W_M1 0x0208 +#define NPU_REG_KERNEL_H_M1 0x020C +#define NPU_REG_OFM_CBLK_WIDTH_M1 0x0210 +#define NPU_REG_OFM_CBLK_HEIGHT_M1 0x0214 +#define NPU_REG_OFM_CBLK_DEPTH_M1 0x0218 +#define NPU_REG_IFM_CBLK_DEPTH_M1 0x021C +#define NPU_REG_OFM_X 0x0220 +#define NPU_REG_OFM_Y 0x0224 +#define NPU_REG_OFM_Z 0x0228 +#define NPU_REG_IFM_Z 0x022C +#define NPU_REG_PAD_TOP 0x0230 +#define NPU_REG_PAD_LEFT 0x0234 +#define NPU_REG_IFM_CBLK_WIDTH 0x0238 +#define NPU_REG_IFM_CBLK_HEIGHT 0x023C +#define NPU_REG_DMA_IFM_SRC 0x0240 +#define NPU_REG_DMA_IFM_SRC_HI 0x0244 +#define NPU_REG_DMA_IFM_DST 0x0248 +#define NPU_REG_DMA_OFM_SRC 0x024C +#define NPU_REG_DMA_OFM_DST 0x0250 +#define NPU_REG_DMA_OFM_DST_HI 0x0254 +#define NPU_REG_DMA_WEIGHT_SRC 0x0258 +#define NPU_REG_DMA_WEIGHT_SRC_HI 0x025C +#define NPU_REG_DMA_CMD_SRC 0x0260 +#define NPU_REG_DMA_CMD_SRC_HI 0x0264 +#define NPU_REG_DMA_CMD_SIZE 0x0268 +#define NPU_REG_DMA_M2M_SRC 0x026C +#define NPU_REG_DMA_M2M_SRC_HI 0x0270 +#define NPU_REG_DMA_M2M_DST 0x0274 +#define NPU_REG_DMA_M2M_DST_HI 0x0278 +#define NPU_REG_CURRENT_QREAD 0x027C +#define NPU_REG_DMA_SCALE_SRC 0x0280 +#define NPU_REG_DMA_SCALE_SRC_HI 0x0284 +#define NPU_REG_CURRENT_BLOCK 0x02B4 +#define NPU_REG_CURRENT_OP 0x02B8 +#define NPU_REG_CURRENT_CMD 0x02BC +#define TSU_DEBUG_REGISTERS_SIZE 0x02C0 + +// +// Register subpage PMU_COUNTERS +// +#define NPU_REG_PMEVCNTR_BASE 0x0300 +#define NPU_REG_PMEVCNTR_ARRLEN 0x0004 +#define NPU_REG_PMEVTYPER_BASE 0x0380 +#define NPU_REG_PMEVTYPER_ARRLEN 0x0004 +#define PMU_COUNTERS_REGISTERS_SIZE 0x0400 + +// +// Register subpage SHARED_BUFFER +// +#define NPU_REG_SHARED_BUFFER_BASE 0x0400 +#define NPU_REG_SHARED_BUFFER_ARRLEN 0x0100 +#define SHARED_BUFFER_REGISTERS_SIZE 0x0800 + +// +// Register subpage TSU_IFM +// +#define NPU_REG_IFM_PAD_TOP 0x0800 +#define NPU_REG_IFM_PAD_LEFT 0x0804 +#define NPU_REG_IFM_PAD_RIGHT 0x0808 +#define NPU_REG_IFM_PAD_BOTTOM 0x080C +#define NPU_REG_IFM_DEPTH_M1 0x0810 +#define NPU_REG_IFM_PRECISION 0x0814 +#define NPU_REG_IFM_UPSCALE 0x081C +#define NPU_REG_IFM_ZERO_POINT 0x0824 +#define NPU_REG_IFM_WIDTH0_M1 0x0828 +#define NPU_REG_IFM_HEIGHT0_M1 0x082C +#define NPU_REG_IFM_HEIGHT1_M1 0x0830 +#define NPU_REG_IFM_IB_END 0x0834 +#define NPU_REG_IFM_REGION 0x083C +#define TSU_IFM_REGISTERS_SIZE 0x0840 + +// +// Register subpage TSU_OFM +// +#define NPU_REG_OFM_WIDTH_M1 0x0844 +#define NPU_REG_OFM_HEIGHT_M1 0x0848 +#define NPU_REG_OFM_DEPTH_M1 0x084C +#define NPU_REG_OFM_PRECISION 0x0850 +#define NPU_REG_OFM_BLK_WIDTH_M1 0x0854 +#define NPU_REG_OFM_BLK_HEIGHT_M1 0x0858 +#define NPU_REG_OFM_BLK_DEPTH_M1 0x085C +#define NPU_REG_OFM_ZERO_POINT 0x0860 +#define NPU_REG_OFM_WIDTH0_M1 0x0868 +#define NPU_REG_OFM_HEIGHT0_M1 0x086C +#define NPU_REG_OFM_HEIGHT1_M1 0x0870 +#define NPU_REG_OFM_REGION 0x087C +#define TSU_OFM_REGISTERS_SIZE 0x0880 + +// +// Register subpage TSU_KERNEL +// +#define NPU_REG_KERNEL_WIDTH_M1 0x0880 +#define NPU_REG_KERNEL_HEIGHT_M1 0x0884 +#define NPU_REG_KERNEL_STRIDE 0x0888 +#define NPU_REG_ACC_FORMAT 0x0890 +#define NPU_REG_ACTIVATION 0x0894 +#define NPU_REG_ACTIVATION_MIN 0x0898 +#define NPU_REG_ACTIVATION_MAX 0x089C +#define NPU_REG_WEIGHT_REGION 0x08A0 +#define NPU_REG_SCALE_REGION 0x08A4 +#define NPU_REG_AB_START 0x08B4 +#define NPU_REG_BLOCKDEP 0x08BC +#define TSU_KERNEL_REGISTERS_SIZE 0x08C0 + +// +// Register subpage TSU_DMA +// +#define NPU_REG_DMA0_SRC_REGION 0x08C0 +#define NPU_REG_DMA0_DST_REGION 0x08C4 +#define NPU_REG_DMA0_SIZE0 0x08C8 +#define NPU_REG_DMA0_SIZE1 0x08CC +#define TSU_DMA_REGISTERS_SIZE 0x0900 + +// +// Register subpage TSU_IFM2 +// +#define NPU_REG_IFM2_BROADCAST 0x0900 +#define NPU_REG_IFM2_SCALAR 0x0904 +#define NPU_REG_IFM2_PRECISION 0x0914 +#define NPU_REG_IFM2_ZERO_POINT 0x0924 +#define NPU_REG_IFM2_WIDTH0_M1 0x0928 +#define NPU_REG_IFM2_HEIGHT0_M1 0x092C +#define NPU_REG_IFM2_HEIGHT1_M1 0x0930 +#define NPU_REG_IFM2_IB_START 0x0934 +#define NPU_REG_IFM2_REGION 0x093C +#define TSU_IFM2_REGISTERS_SIZE 0x0940 + +// +// Register subpage TSU_IFM_BASE +// +#define NPU_REG_IFM_BASE0 0x0A00 +#define NPU_REG_IFM_BASE0_HI 0x0A04 +#define NPU_REG_IFM_BASE1 0x0A08 +#define NPU_REG_IFM_BASE1_HI 0x0A0C +#define NPU_REG_IFM_BASE2 0x0A10 +#define NPU_REG_IFM_BASE2_HI 0x0A14 +#define NPU_REG_IFM_BASE3 0x0A18 +#define NPU_REG_IFM_BASE3_HI 0x0A1C +#define NPU_REG_IFM_STRIDE_X 0x0A20 +#define NPU_REG_IFM_STRIDE_X_HI 0x0A24 +#define NPU_REG_IFM_STRIDE_Y 0x0A28 +#define NPU_REG_IFM_STRIDE_Y_HI 0x0A2C +#define NPU_REG_IFM_STRIDE_C 0x0A30 +#define NPU_REG_IFM_STRIDE_C_HI 0x0A34 +#define TSU_IFM_BASE_REGISTERS_SIZE 0x0A40 + +// +// Register subpage TSU_OFM_BASE +// +#define NPU_REG_OFM_BASE0 0x0A40 +#define NPU_REG_OFM_BASE0_HI 0x0A44 +#define NPU_REG_OFM_BASE1 0x0A48 +#define NPU_REG_OFM_BASE1_HI 0x0A4C +#define NPU_REG_OFM_BASE2 0x0A50 +#define NPU_REG_OFM_BASE2_HI 0x0A54 +#define NPU_REG_OFM_BASE3 0x0A58 +#define NPU_REG_OFM_BASE3_HI 0x0A5C +#define NPU_REG_OFM_STRIDE_X 0x0A60 +#define NPU_REG_OFM_STRIDE_X_HI 0x0A64 +#define NPU_REG_OFM_STRIDE_Y 0x0A68 +#define NPU_REG_OFM_STRIDE_Y_HI 0x0A6C +#define NPU_REG_OFM_STRIDE_C 0x0A70 +#define NPU_REG_OFM_STRIDE_C_HI 0x0A74 +#define TSU_OFM_BASE_REGISTERS_SIZE 0x0A80 + +// +// Register subpage TSU_WS_BASE +// +#define NPU_REG_WEIGHT_BASE 0x0A80 +#define NPU_REG_WEIGHT_BASE_HI 0x0A84 +#define NPU_REG_WEIGHT_LENGTH 0x0A88 +#define NPU_REG_WEIGHT_LENGTH_HI 0x0A8C +#define NPU_REG_SCALE_BASE 0x0A90 +#define NPU_REG_SCALE_BASE_HI 0x0A94 +#define NPU_REG_SCALE_LENGTH 0x0A98 +#define NPU_REG_SCALE_LENGTH_HI 0x0A9C +#define NPU_REG_OFM_SCALE 0x0AA0 +#define NPU_REG_OFM_SCALE_SHIFT 0x0AA4 +#define NPU_REG_OPA_SCALE 0x0AA8 +#define NPU_REG_OPA_SCALE_SHIFT 0x0AAC +#define NPU_REG_OPB_SCALE 0x0AB0 +#define TSU_WS_BASE_REGISTERS_SIZE 0x0AC0 + +// +// Register subpage TSU_DMA_BASE +// +#define NPU_REG_DMA0_SRC 0x0AC0 +#define NPU_REG_DMA0_SRC_HI 0x0AC4 +#define NPU_REG_DMA0_DST 0x0AC8 +#define NPU_REG_DMA0_DST_HI 0x0ACC +#define NPU_REG_DMA0_LEN 0x0AD0 +#define NPU_REG_DMA0_LEN_HI 0x0AD4 +#define TSU_DMA_BASE_REGISTERS_SIZE 0x0B00 + +// +// Register subpage TSU_IFM2_BASE +// +#define NPU_REG_IFM2_BASE0 0x0B00 +#define NPU_REG_IFM2_BASE0_HI 0x0B04 +#define NPU_REG_IFM2_BASE1 0x0B08 +#define NPU_REG_IFM2_BASE1_HI 0x0B0C +#define NPU_REG_IFM2_BASE2 0x0B10 +#define NPU_REG_IFM2_BASE2_HI 0x0B14 +#define NPU_REG_IFM2_BASE3 0x0B18 +#define NPU_REG_IFM2_BASE3_HI 0x0B1C +#define NPU_REG_IFM2_STRIDE_X 0x0B20 +#define NPU_REG_IFM2_STRIDE_X_HI 0x0B24 +#define NPU_REG_IFM2_STRIDE_Y 0x0B28 +#define NPU_REG_IFM2_STRIDE_Y_HI 0x0B2C +#define NPU_REG_IFM2_STRIDE_C 0x0B30 +#define NPU_REG_IFM2_STRIDE_C_HI 0x0B34 +#define TSU_IFM2_BASE_REGISTERS_SIZE 0x0B40 + +// +// Register subpage TSU_WS1_BASE +// +#define TSU_WS1_BASE_REGISTERS_SIZE 0x0B80 + +// +// Register subpage TSU_USER_BASE +// +#define NPU_REG_USER_DEFINED_BASE 0x0B80 +#define NPU_REG_USER_DEFINED_ARRLEN 0x0008 +#define TSU_USER_BASE_REGISTERS_SIZE 0x0BC0 + +// +// Register subpage TSU_DMA_EBASE +// +#define TSU_DMA_EBASE_REGISTERS_SIZE 0x0C00 + +// +// Register subpage ID +// +#define NPU_REG_REVISION 0x0FC0 +#define NPU_REG_PID4 0x0FD0 +#define NPU_REG_PID5 0x0FD4 +#define NPU_REG_PID6 0x0FD8 +#define NPU_REG_PID7 0x0FDC +#define NPU_REG_PID0 0x0FE0 +#define NPU_REG_PID1 0x0FE4 +#define NPU_REG_PID2 0x0FE8 +#define NPU_REG_PID3 0x0FEC +#define NPU_REG_CID0 0x0FF0 +#define NPU_REG_CID1 0x0FF4 +#define NPU_REG_CID2 0x0FF8 +#define NPU_REG_CID3 0x0FFC +#define ID_REGISTERS_SIZE 0x1000 + +#ifdef __cplusplus +// Enum types +enum class acc_format : uint8_t +{ + I32 = 0, + I40 = 1, + F16 = 2, +}; + +enum class activation_clip_range : uint8_t +{ + OFM_PRECISION = 0, + FORCE_UINT8 = 2, + FORCE_INT8 = 3, + FORCE_INT16 = 5, +}; + +enum class activation_format : uint8_t +{ + NHWC = 0, + NHCWB16 = 1, +}; + +enum class activation_function : uint8_t +{ + RELU = 0, + TANH = 3, + SIGMOID = 4, + TABLE_0 = 16, + TABLE_1 = 17, + TABLE_2 = 18, + TABLE_3 = 19, + TABLE_4 = 20, + TABLE_5 = 21, + TABLE_6 = 22, + TABLE_7 = 23, +}; + +enum class activation_precision : uint8_t +{ + B8 = 0, + B16 = 1, + B32 = 2, + B64 = 3, +}; + +enum class activation_type : uint8_t +{ + UNSIGNED = 0, + SIGNED = 1, +}; + +enum class axi_mem_encoding : uint8_t +{ + DEVICE_NON_BUFFERABLE = 0, + DEVICE_BUFFERABLE = 1, + NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + WRITE_THROUGH_NO_ALLOCATE = 4, + WRITE_THROUGH_READ_ALLOCATE = 5, + WRITE_THROUGH_WRITE_ALLOCATE = 6, + WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + WRITE_BACK_NO_ALLOCATE = 8, + WRITE_BACK_READ_ALLOCATE = 9, + WRITE_BACK_WRITE_ALLOCATE = 10, + WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum class broadcast_mode : uint8_t +{ + DISABLE = 0, + ENABLE = 1, +}; + +enum class cmd0_opcode : uint16_t +{ + NPU_OP_STOP = 0, + NPU_OP_IRQ = 1, + NPU_OP_CONV = 2, + NPU_OP_DEPTHWISE = 3, + NPU_OP_POOL = 5, + NPU_OP_ELEMENTWISE = 6, + NPU_OP_DMA_START = 16, + NPU_OP_DMA_WAIT = 17, + NPU_OP_KERNEL_WAIT = 18, + NPU_OP_PMU_MASK = 19, + NPU_SET_IFM_PAD_TOP = 256, + NPU_SET_IFM_PAD_LEFT = 257, + NPU_SET_IFM_PAD_RIGHT = 258, + NPU_SET_IFM_PAD_BOTTOM = 259, + NPU_SET_IFM_DEPTH_M1 = 260, + NPU_SET_IFM_PRECISION = 261, + NPU_SET_IFM_UPSCALE = 263, + NPU_SET_IFM_ZERO_POINT = 265, + NPU_SET_IFM_WIDTH0_M1 = 266, + NPU_SET_IFM_HEIGHT0_M1 = 267, + NPU_SET_IFM_HEIGHT1_M1 = 268, + NPU_SET_IFM_IB_END = 269, + NPU_SET_IFM_REGION = 271, + NPU_SET_OFM_WIDTH_M1 = 273, + NPU_SET_OFM_HEIGHT_M1 = 274, + NPU_SET_OFM_DEPTH_M1 = 275, + NPU_SET_OFM_PRECISION = 276, + NPU_SET_OFM_BLK_WIDTH_M1 = 277, + NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + NPU_SET_OFM_BLK_DEPTH_M1 = 279, + NPU_SET_OFM_ZERO_POINT = 280, + NPU_SET_OFM_WIDTH0_M1 = 282, + NPU_SET_OFM_HEIGHT0_M1 = 283, + NPU_SET_OFM_HEIGHT1_M1 = 284, + NPU_SET_OFM_REGION = 287, + NPU_SET_KERNEL_WIDTH_M1 = 288, + NPU_SET_KERNEL_HEIGHT_M1 = 289, + NPU_SET_KERNEL_STRIDE = 290, + NPU_SET_ACC_FORMAT = 292, + NPU_SET_ACTIVATION = 293, + NPU_SET_ACTIVATION_MIN = 294, + NPU_SET_ACTIVATION_MAX = 295, + NPU_SET_WEIGHT_REGION = 296, + NPU_SET_SCALE_REGION = 297, + NPU_SET_AB_START = 301, + NPU_SET_BLOCKDEP = 303, + NPU_SET_DMA0_SRC_REGION = 304, + NPU_SET_DMA0_DST_REGION = 305, + NPU_SET_DMA0_SIZE0 = 306, + NPU_SET_DMA0_SIZE1 = 307, + NPU_SET_IFM2_BROADCAST = 384, + NPU_SET_IFM2_SCALAR = 385, + NPU_SET_IFM2_PRECISION = 389, + NPU_SET_IFM2_ZERO_POINT = 393, + NPU_SET_IFM2_WIDTH0_M1 = 394, + NPU_SET_IFM2_HEIGHT0_M1 = 395, + NPU_SET_IFM2_HEIGHT1_M1 = 396, + NPU_SET_IFM2_IB_START = 397, + NPU_SET_IFM2_REGION = 399, +}; + +enum class cmd1_opcode : uint16_t +{ + NPU_SET_IFM_BASE0 = 0, + NPU_SET_IFM_BASE1 = 1, + NPU_SET_IFM_BASE2 = 2, + NPU_SET_IFM_BASE3 = 3, + NPU_SET_IFM_STRIDE_X = 4, + NPU_SET_IFM_STRIDE_Y = 5, + NPU_SET_IFM_STRIDE_C = 6, + NPU_SET_OFM_BASE0 = 16, + NPU_SET_OFM_BASE1 = 17, + NPU_SET_OFM_BASE2 = 18, + NPU_SET_OFM_BASE3 = 19, + NPU_SET_OFM_STRIDE_X = 20, + NPU_SET_OFM_STRIDE_Y = 21, + NPU_SET_OFM_STRIDE_C = 22, + NPU_SET_WEIGHT_BASE = 32, + NPU_SET_WEIGHT_LENGTH = 33, + NPU_SET_SCALE_BASE = 34, + NPU_SET_SCALE_LENGTH = 35, + NPU_SET_OFM_SCALE = 36, + NPU_SET_OPA_SCALE = 37, + NPU_SET_OPB_SCALE = 38, + NPU_SET_DMA0_SRC = 48, + NPU_SET_DMA0_DST = 49, + NPU_SET_DMA0_LEN = 50, + NPU_SET_IFM2_BASE0 = 128, + NPU_SET_IFM2_BASE1 = 129, + NPU_SET_IFM2_BASE2 = 130, + NPU_SET_IFM2_BASE3 = 131, + NPU_SET_IFM2_STRIDE_X = 132, + NPU_SET_IFM2_STRIDE_Y = 133, + NPU_SET_IFM2_STRIDE_C = 134, + NPU_SET_USER_DEFINED0 = 160, + NPU_SET_USER_DEFINED1 = 161, + NPU_SET_USER_DEFINED2 = 162, + NPU_SET_USER_DEFINED3 = 163, + NPU_SET_USER_DEFINED4 = 164, + NPU_SET_USER_DEFINED5 = 165, + NPU_SET_USER_DEFINED6 = 166, + NPU_SET_USER_DEFINED7 = 167, +}; + +enum class cmd_ctrl : uint8_t +{ + CMD0_CTRL = 0, + CMD1_CTRL = 1, +}; + +enum class custom_dma_cs : uint8_t +{ + DISABLE = 0, + ENABLE = 1, +}; + +enum class custom_dma : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class dma_fault_src : uint8_t +{ + AXI_M0 = 0, + AXI_M1 = 1, +}; + +enum class dma_region_mode : uint8_t +{ + EXTERNAL = 0, + INTERNAL = 1, +}; + +enum class dma_stride_mode : uint8_t +{ + D1 = 0, +}; + +enum class elementwise_mode : uint8_t +{ + MUL = 0, + ADD = 1, + SUB = 2, + MIN = 3, + MAX = 4, + LRELU = 5, + ABS = 6, + CLZ = 7, + SHR = 8, + SHL = 9, +}; + +enum class functional_safety : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class ifm2_operand_order : uint8_t +{ + ORDER_B = 0, + ORDER_A = 1, +}; + +enum class ifm_scale_mode : uint8_t +{ + OPA_OPB_16 = 0, + OPA_32 = 1, + OPB_32 = 2, +}; + +enum class ifm_upscale_mode : uint8_t +{ + NONE = 0, + NEAREST = 1, + ZEROS = 2, +}; + +enum class kernel_decomposition : uint8_t +{ + D8X8 = 0, + D4X4 = 1, +}; + +enum class kernel_dilation : uint8_t +{ + NONE = 0, + X2 = 1, +}; + +enum class max_beats : uint8_t +{ + B64 = 0, + B128 = 1, + B256 = 2, +}; + +enum class mem_attr : uint8_t +{ + AXI0_OUTSTANDING_COUNTER0 = 0, + AXI0_OUTSTANDING_COUNTER1 = 1, + AXI1_OUTSTANDING_COUNTER2 = 2, + AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum class ofm_scale_mode : uint8_t +{ + PER_CHANNEL = 0, + GLOBAL = 1, +}; + +enum class pmu_axi_channel : uint8_t +{ + RD_CMD = 0, + RD_IFM = 1, + RD_WEIGHTS = 2, + RD_SCALE_BIAS = 3, + RD_MEM2MEM = 4, + WR_OFM = 8, + WR_MEM2MEM = 9, +}; + +enum class pmu_event : uint16_t +{ + NO_EVENT = 0, + CYCLE = 17, + NPU_IDLE = 32, + CC_STALLED_ON_BLOCKDEP = 33, + CC_STALLED_ON_SHRAM_RECONFIG = 34, + NPU_ACTIVE = 35, + MAC_ACTIVE = 48, + MAC_ACTIVE_8BIT = 49, + MAC_ACTIVE_16BIT = 50, + MAC_DPU_ACTIVE = 51, + MAC_STALLED_BY_WD_ACC = 52, + MAC_STALLED_BY_WD = 53, + MAC_STALLED_BY_ACC = 54, + MAC_STALLED_BY_IB = 55, + MAC_ACTIVE_32BIT = 56, + MAC_STALLED_BY_INT_W = 57, + MAC_STALLED_BY_INT_ACC = 58, + AO_ACTIVE = 64, + AO_ACTIVE_8BIT = 65, + AO_ACTIVE_16BIT = 66, + AO_STALLED_BY_OFMP_OB = 67, + AO_STALLED_BY_OFMP = 68, + AO_STALLED_BY_OB = 69, + AO_STALLED_BY_ACC_IB = 70, + AO_STALLED_BY_ACC = 71, + AO_STALLED_BY_IB = 72, + WD_ACTIVE = 80, + WD_STALLED = 81, + WD_STALLED_BY_WS = 82, + WD_STALLED_BY_WD_BUF = 83, + WD_PARSE_ACTIVE = 84, + WD_PARSE_STALLED = 85, + WD_PARSE_STALLED_IN = 86, + WD_PARSE_STALLED_OUT = 87, + WD_TRANS_WS = 88, + WD_TRANS_WB = 89, + WD_TRANS_DW0 = 90, + WD_TRANS_DW1 = 91, + AXI0_RD_TRANS_ACCEPTED = 128, + AXI0_RD_TRANS_COMPLETED = 129, + AXI0_RD_DATA_BEAT_RECEIVED = 130, + AXI0_RD_TRAN_REQ_STALLED = 131, + AXI0_WR_TRANS_ACCEPTED = 132, + AXI0_WR_TRANS_COMPLETED_M = 133, + AXI0_WR_TRANS_COMPLETED_S = 134, + AXI0_WR_DATA_BEAT_WRITTEN = 135, + AXI0_WR_TRAN_REQ_STALLED = 136, + AXI0_WR_DATA_BEAT_STALLED = 137, + AXI0_ENABLED_CYCLES = 140, + AXI0_RD_STALL_LIMIT = 142, + AXI0_WR_STALL_LIMIT = 143, + AXI_LATENCY_ANY = 160, + AXI_LATENCY_32 = 161, + AXI_LATENCY_64 = 162, + AXI_LATENCY_128 = 163, + AXI_LATENCY_256 = 164, + AXI_LATENCY_512 = 165, + AXI_LATENCY_1024 = 166, + ECC_DMA = 176, + ECC_SB0 = 177, + AXI1_RD_TRANS_ACCEPTED = 384, + AXI1_RD_TRANS_COMPLETED = 385, + AXI1_RD_DATA_BEAT_RECEIVED = 386, + AXI1_RD_TRAN_REQ_STALLED = 387, + AXI1_WR_TRANS_ACCEPTED = 388, + AXI1_WR_TRANS_COMPLETED_M = 389, + AXI1_WR_TRANS_COMPLETED_S = 390, + AXI1_WR_DATA_BEAT_WRITTEN = 391, + AXI1_WR_TRAN_REQ_STALLED = 392, + AXI1_WR_DATA_BEAT_STALLED = 393, + AXI1_ENABLED_CYCLES = 396, + AXI1_RD_STALL_LIMIT = 398, + AXI1_WR_STALL_LIMIT = 399, + ECC_SB1 = 433, +}; + +enum class pooling_mode : uint8_t +{ + MAX = 0, + AVERAGE = 1, + REDUCE_SUM = 2, +}; + +enum class privilege_level : uint8_t +{ + USER = 0, + PRIVILEGED = 1, +}; + +enum class round_mode : uint8_t +{ + DBL = 0, + TRUNCATE = 1, + NATURAL = 2, +}; + +enum class security_level : uint8_t +{ + SECURE = 0, + NON_SECURE = 1, +}; + +enum class state : uint8_t +{ + STOPPED = 0, + RUNNING = 1, +}; + +enum class wd_core_slice_state : uint8_t +{ + HEADER = 0, + PALETTE = 1, + WEIGHTS = 2, +}; + +enum class wd_ctrl_state : uint8_t +{ + IDLE = 0, + DRAIN = 1, + OFD_INIT = 2, + OFD_RUN = 3, +}; + +enum class weight_order : uint8_t +{ + DEPTH_FIRST = 0, + PART_KERNEL_FIRST = 1, +}; + +#else + +enum acc_format +{ + ACC_FORMAT_I32 = 0, + ACC_FORMAT_I40 = 1, + ACC_FORMAT_F16 = 2, +}; + +enum activation_clip_range +{ + ACTIVATION_CLIP_RANGE_OFM_PRECISION = 0, + ACTIVATION_CLIP_RANGE_FORCE_UINT8 = 2, + ACTIVATION_CLIP_RANGE_FORCE_INT8 = 3, + ACTIVATION_CLIP_RANGE_FORCE_INT16 = 5, +}; + +enum activation_format +{ + ACTIVATION_FORMAT_NHWC = 0, + ACTIVATION_FORMAT_NHCWB16 = 1, +}; + +enum activation_function +{ + ACTIVATION_FUNCTION_RELU = 0, + ACTIVATION_FUNCTION_TANH = 3, + ACTIVATION_FUNCTION_SIGMOID = 4, + ACTIVATION_FUNCTION_TABLE_0 = 16, + ACTIVATION_FUNCTION_TABLE_1 = 17, + ACTIVATION_FUNCTION_TABLE_2 = 18, + ACTIVATION_FUNCTION_TABLE_3 = 19, + ACTIVATION_FUNCTION_TABLE_4 = 20, + ACTIVATION_FUNCTION_TABLE_5 = 21, + ACTIVATION_FUNCTION_TABLE_6 = 22, + ACTIVATION_FUNCTION_TABLE_7 = 23, +}; + +enum activation_precision +{ + ACTIVATION_PRECISION_B8 = 0, + ACTIVATION_PRECISION_B16 = 1, + ACTIVATION_PRECISION_B32 = 2, + ACTIVATION_PRECISION_B64 = 3, +}; + +enum activation_type +{ + ACTIVATION_TYPE_UNSIGNED = 0, + ACTIVATION_TYPE_SIGNED = 1, +}; + +enum axi_mem_encoding +{ + AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE = 0, + AXI_MEM_ENCODING_DEVICE_BUFFERABLE = 1, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE = 4, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE = 5, + AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE = 6, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE = 8, + AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE = 9, + AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE = 10, + AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum broadcast_mode +{ + BROADCAST_MODE_DISABLE = 0, + BROADCAST_MODE_ENABLE = 1, +}; + +enum cmd0_opcode +{ + CMD0_OPCODE_NPU_OP_STOP = 0, + CMD0_OPCODE_NPU_OP_IRQ = 1, + CMD0_OPCODE_NPU_OP_CONV = 2, + CMD0_OPCODE_NPU_OP_DEPTHWISE = 3, + CMD0_OPCODE_NPU_OP_POOL = 5, + CMD0_OPCODE_NPU_OP_ELEMENTWISE = 6, + CMD0_OPCODE_NPU_OP_DMA_START = 16, + CMD0_OPCODE_NPU_OP_DMA_WAIT = 17, + CMD0_OPCODE_NPU_OP_KERNEL_WAIT = 18, + CMD0_OPCODE_NPU_OP_PMU_MASK = 19, + CMD0_OPCODE_NPU_SET_IFM_PAD_TOP = 256, + CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT = 257, + CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT = 258, + CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM = 259, + CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1 = 260, + CMD0_OPCODE_NPU_SET_IFM_PRECISION = 261, + CMD0_OPCODE_NPU_SET_IFM_UPSCALE = 263, + CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT = 265, + CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1 = 266, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1 = 267, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1 = 268, + CMD0_OPCODE_NPU_SET_IFM_IB_END = 269, + CMD0_OPCODE_NPU_SET_IFM_REGION = 271, + CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1 = 273, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1 = 274, + CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1 = 275, + CMD0_OPCODE_NPU_SET_OFM_PRECISION = 276, + CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1 = 277, + CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1 = 279, + CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT = 280, + CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1 = 282, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1 = 283, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1 = 284, + CMD0_OPCODE_NPU_SET_OFM_REGION = 287, + CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1 = 288, + CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1 = 289, + CMD0_OPCODE_NPU_SET_KERNEL_STRIDE = 290, + CMD0_OPCODE_NPU_SET_ACC_FORMAT = 292, + CMD0_OPCODE_NPU_SET_ACTIVATION = 293, + CMD0_OPCODE_NPU_SET_ACTIVATION_MIN = 294, + CMD0_OPCODE_NPU_SET_ACTIVATION_MAX = 295, + CMD0_OPCODE_NPU_SET_WEIGHT_REGION = 296, + CMD0_OPCODE_NPU_SET_SCALE_REGION = 297, + CMD0_OPCODE_NPU_SET_AB_START = 301, + CMD0_OPCODE_NPU_SET_BLOCKDEP = 303, + CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION = 304, + CMD0_OPCODE_NPU_SET_DMA0_DST_REGION = 305, + CMD0_OPCODE_NPU_SET_DMA0_SIZE0 = 306, + CMD0_OPCODE_NPU_SET_DMA0_SIZE1 = 307, + CMD0_OPCODE_NPU_SET_IFM2_BROADCAST = 384, + CMD0_OPCODE_NPU_SET_IFM2_SCALAR = 385, + CMD0_OPCODE_NPU_SET_IFM2_PRECISION = 389, + CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT = 393, + CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1 = 394, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1 = 395, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1 = 396, + CMD0_OPCODE_NPU_SET_IFM2_IB_START = 397, + CMD0_OPCODE_NPU_SET_IFM2_REGION = 399, +}; + +enum cmd1_opcode +{ + CMD1_OPCODE_NPU_SET_IFM_BASE0 = 0, + CMD1_OPCODE_NPU_SET_IFM_BASE1 = 1, + CMD1_OPCODE_NPU_SET_IFM_BASE2 = 2, + CMD1_OPCODE_NPU_SET_IFM_BASE3 = 3, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_X = 4, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y = 5, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_C = 6, + CMD1_OPCODE_NPU_SET_OFM_BASE0 = 16, + CMD1_OPCODE_NPU_SET_OFM_BASE1 = 17, + CMD1_OPCODE_NPU_SET_OFM_BASE2 = 18, + CMD1_OPCODE_NPU_SET_OFM_BASE3 = 19, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_X = 20, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y = 21, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_C = 22, + CMD1_OPCODE_NPU_SET_WEIGHT_BASE = 32, + CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH = 33, + CMD1_OPCODE_NPU_SET_SCALE_BASE = 34, + CMD1_OPCODE_NPU_SET_SCALE_LENGTH = 35, + CMD1_OPCODE_NPU_SET_OFM_SCALE = 36, + CMD1_OPCODE_NPU_SET_OPA_SCALE = 37, + CMD1_OPCODE_NPU_SET_OPB_SCALE = 38, + CMD1_OPCODE_NPU_SET_DMA0_SRC = 48, + CMD1_OPCODE_NPU_SET_DMA0_DST = 49, + CMD1_OPCODE_NPU_SET_DMA0_LEN = 50, + CMD1_OPCODE_NPU_SET_IFM2_BASE0 = 128, + CMD1_OPCODE_NPU_SET_IFM2_BASE1 = 129, + CMD1_OPCODE_NPU_SET_IFM2_BASE2 = 130, + CMD1_OPCODE_NPU_SET_IFM2_BASE3 = 131, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X = 132, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y = 133, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C = 134, + CMD1_OPCODE_NPU_SET_USER_DEFINED0 = 160, + CMD1_OPCODE_NPU_SET_USER_DEFINED1 = 161, + CMD1_OPCODE_NPU_SET_USER_DEFINED2 = 162, + CMD1_OPCODE_NPU_SET_USER_DEFINED3 = 163, + CMD1_OPCODE_NPU_SET_USER_DEFINED4 = 164, + CMD1_OPCODE_NPU_SET_USER_DEFINED5 = 165, + CMD1_OPCODE_NPU_SET_USER_DEFINED6 = 166, + CMD1_OPCODE_NPU_SET_USER_DEFINED7 = 167, +}; + +enum cmd_ctrl +{ + CMD_CTRL_CMD0_CTRL = 0, + CMD_CTRL_CMD1_CTRL = 1, +}; + +enum custom_dma_cs +{ + CUSTOM_DMA_CS_DISABLE = 0, + CUSTOM_DMA_CS_ENABLE = 1, +}; + +enum custom_dma +{ + CUSTOM_DMA_NOT_IMPLEMENTED = 0, + CUSTOM_DMA_IMPLEMENTED = 1, +}; + +enum dma_fault_src +{ + DMA_FAULT_SRC_AXI_M0 = 0, + DMA_FAULT_SRC_AXI_M1 = 1, +}; + +enum dma_region_mode +{ + DMA_REGION_MODE_EXTERNAL = 0, + DMA_REGION_MODE_INTERNAL = 1, +}; + +enum dma_stride_mode +{ + DMA_STRIDE_MODE_D1 = 0, +}; + +enum elementwise_mode +{ + ELEMENTWISE_MODE_MUL = 0, + ELEMENTWISE_MODE_ADD = 1, + ELEMENTWISE_MODE_SUB = 2, + ELEMENTWISE_MODE_MIN = 3, + ELEMENTWISE_MODE_MAX = 4, + ELEMENTWISE_MODE_LRELU = 5, + ELEMENTWISE_MODE_ABS = 6, + ELEMENTWISE_MODE_CLZ = 7, + ELEMENTWISE_MODE_SHR = 8, + ELEMENTWISE_MODE_SHL = 9, +}; + +enum functional_safety +{ + FUNCTIONAL_SAFETY_NOT_IMPLEMENTED = 0, + FUNCTIONAL_SAFETY_IMPLEMENTED = 1, +}; + +enum ifm2_operand_order +{ + IFM2_OPERAND_ORDER_ORDER_B = 0, + IFM2_OPERAND_ORDER_ORDER_A = 1, +}; + +enum ifm_scale_mode +{ + IFM_SCALE_MODE_OPA_OPB_16 = 0, + IFM_SCALE_MODE_OPA_32 = 1, + IFM_SCALE_MODE_OPB_32 = 2, +}; + +enum ifm_upscale_mode +{ + IFM_UPSCALE_MODE_NONE = 0, + IFM_UPSCALE_MODE_NEAREST = 1, + IFM_UPSCALE_MODE_ZEROS = 2, +}; + +enum kernel_decomposition +{ + KERNEL_DECOMPOSITION_D8X8 = 0, + KERNEL_DECOMPOSITION_D4X4 = 1, +}; + +enum kernel_dilation +{ + KERNEL_DILATION_NONE = 0, + KERNEL_DILATION_X2 = 1, +}; + +enum max_beats +{ + MAX_BEATS_B64 = 0, + MAX_BEATS_B128 = 1, + MAX_BEATS_B256 = 2, +}; + +enum mem_attr +{ + MEM_ATTR_AXI0_OUTSTANDING_COUNTER0 = 0, + MEM_ATTR_AXI0_OUTSTANDING_COUNTER1 = 1, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER2 = 2, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum ofm_scale_mode +{ + OFM_SCALE_MODE_PER_CHANNEL = 0, + OFM_SCALE_MODE_GLOBAL = 1, +}; + +enum pmu_axi_channel +{ + PMU_AXI_CHANNEL_RD_CMD = 0, + PMU_AXI_CHANNEL_RD_IFM = 1, + PMU_AXI_CHANNEL_RD_WEIGHTS = 2, + PMU_AXI_CHANNEL_RD_SCALE_BIAS = 3, + PMU_AXI_CHANNEL_RD_MEM2MEM = 4, + PMU_AXI_CHANNEL_WR_OFM = 8, + PMU_AXI_CHANNEL_WR_MEM2MEM = 9, +}; + +enum pmu_event +{ + PMU_EVENT_NO_EVENT = 0, + PMU_EVENT_CYCLE = 17, + PMU_EVENT_NPU_IDLE = 32, + PMU_EVENT_CC_STALLED_ON_BLOCKDEP = 33, + PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG = 34, + PMU_EVENT_NPU_ACTIVE = 35, + PMU_EVENT_MAC_ACTIVE = 48, + PMU_EVENT_MAC_ACTIVE_8BIT = 49, + PMU_EVENT_MAC_ACTIVE_16BIT = 50, + PMU_EVENT_MAC_DPU_ACTIVE = 51, + PMU_EVENT_MAC_STALLED_BY_WD_ACC = 52, + PMU_EVENT_MAC_STALLED_BY_WD = 53, + PMU_EVENT_MAC_STALLED_BY_ACC = 54, + PMU_EVENT_MAC_STALLED_BY_IB = 55, + PMU_EVENT_MAC_ACTIVE_32BIT = 56, + PMU_EVENT_MAC_STALLED_BY_INT_W = 57, + PMU_EVENT_MAC_STALLED_BY_INT_ACC = 58, + PMU_EVENT_AO_ACTIVE = 64, + PMU_EVENT_AO_ACTIVE_8BIT = 65, + PMU_EVENT_AO_ACTIVE_16BIT = 66, + PMU_EVENT_AO_STALLED_BY_OFMP_OB = 67, + PMU_EVENT_AO_STALLED_BY_OFMP = 68, + PMU_EVENT_AO_STALLED_BY_OB = 69, + PMU_EVENT_AO_STALLED_BY_ACC_IB = 70, + PMU_EVENT_AO_STALLED_BY_ACC = 71, + PMU_EVENT_AO_STALLED_BY_IB = 72, + PMU_EVENT_WD_ACTIVE = 80, + PMU_EVENT_WD_STALLED = 81, + PMU_EVENT_WD_STALLED_BY_WS = 82, + PMU_EVENT_WD_STALLED_BY_WD_BUF = 83, + PMU_EVENT_WD_PARSE_ACTIVE = 84, + PMU_EVENT_WD_PARSE_STALLED = 85, + PMU_EVENT_WD_PARSE_STALLED_IN = 86, + PMU_EVENT_WD_PARSE_STALLED_OUT = 87, + PMU_EVENT_WD_TRANS_WS = 88, + PMU_EVENT_WD_TRANS_WB = 89, + PMU_EVENT_WD_TRANS_DW0 = 90, + PMU_EVENT_WD_TRANS_DW1 = 91, + PMU_EVENT_AXI0_RD_TRANS_ACCEPTED = 128, + PMU_EVENT_AXI0_RD_TRANS_COMPLETED = 129, + PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED = 130, + PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED = 131, + PMU_EVENT_AXI0_WR_TRANS_ACCEPTED = 132, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M = 133, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S = 134, + PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN = 135, + PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED = 136, + PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED = 137, + PMU_EVENT_AXI0_ENABLED_CYCLES = 140, + PMU_EVENT_AXI0_RD_STALL_LIMIT = 142, + PMU_EVENT_AXI0_WR_STALL_LIMIT = 143, + PMU_EVENT_AXI_LATENCY_ANY = 160, + PMU_EVENT_AXI_LATENCY_32 = 161, + PMU_EVENT_AXI_LATENCY_64 = 162, + PMU_EVENT_AXI_LATENCY_128 = 163, + PMU_EVENT_AXI_LATENCY_256 = 164, + PMU_EVENT_AXI_LATENCY_512 = 165, + PMU_EVENT_AXI_LATENCY_1024 = 166, + PMU_EVENT_ECC_DMA = 176, + PMU_EVENT_ECC_SB0 = 177, + PMU_EVENT_AXI1_RD_TRANS_ACCEPTED = 384, + PMU_EVENT_AXI1_RD_TRANS_COMPLETED = 385, + PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED = 386, + PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED = 387, + PMU_EVENT_AXI1_WR_TRANS_ACCEPTED = 388, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M = 389, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S = 390, + PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN = 391, + PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED = 392, + PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED = 393, + PMU_EVENT_AXI1_ENABLED_CYCLES = 396, + PMU_EVENT_AXI1_RD_STALL_LIMIT = 398, + PMU_EVENT_AXI1_WR_STALL_LIMIT = 399, + PMU_EVENT_ECC_SB1 = 433, +}; + +enum pooling_mode +{ + POOLING_MODE_MAX = 0, + POOLING_MODE_AVERAGE = 1, + POOLING_MODE_REDUCE_SUM = 2, +}; + +enum privilege_level +{ + PRIVILEGE_LEVEL_USER = 0, + PRIVILEGE_LEVEL_PRIVILEGED = 1, +}; + +enum round_mode +{ + ROUND_MODE_DBL = 0, + ROUND_MODE_TRUNCATE = 1, + ROUND_MODE_NATURAL = 2, +}; + +enum security_level +{ + SECURITY_LEVEL_SECURE = 0, + SECURITY_LEVEL_NON_SECURE = 1, +}; + +enum state +{ + STATE_STOPPED = 0, + STATE_RUNNING = 1, +}; + +enum wd_core_slice_state +{ + WD_CORE_SLICE_STATE_HEADER = 0, + WD_CORE_SLICE_STATE_PALETTE = 1, + WD_CORE_SLICE_STATE_WEIGHTS = 2, +}; + +enum wd_ctrl_state +{ + WD_CTRL_STATE_IDLE = 0, + WD_CTRL_STATE_DRAIN = 1, + WD_CTRL_STATE_OFD_INIT = 2, + WD_CTRL_STATE_OFD_RUN = 3, +}; + +enum weight_order +{ + WEIGHT_ORDER_DEPTH_FIRST = 0, + WEIGHT_ORDER_PART_KERNEL_FIRST = 1, +}; + +#endif + +#ifdef NPU_DISASSEMBLE + +static const char *acc_format_str[] = { + "ACC_FORMAT_I32", + "ACC_FORMAT_I40", + "ACC_FORMAT_F16", +}; + +static const char *activation_clip_range_str[] = { + "ACTIVATION_CLIP_RANGE_OFM_PRECISION", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_UINT8", + "ACTIVATION_CLIP_RANGE_FORCE_INT8", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_INT16", +}; + +static const char *activation_format_str[] = { + "ACTIVATION_FORMAT_NHWC", + "ACTIVATION_FORMAT_NHCWB16", +}; + +static const char *activation_function_str[] = { + "ACTIVATION_FUNCTION_RELU", + "****", + "****", + "ACTIVATION_FUNCTION_TANH", + "ACTIVATION_FUNCTION_SIGMOID", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "ACTIVATION_FUNCTION_TABLE_0", + "ACTIVATION_FUNCTION_TABLE_1", + "ACTIVATION_FUNCTION_TABLE_2", + "ACTIVATION_FUNCTION_TABLE_3", + "ACTIVATION_FUNCTION_TABLE_4", + "ACTIVATION_FUNCTION_TABLE_5", + "ACTIVATION_FUNCTION_TABLE_6", + "ACTIVATION_FUNCTION_TABLE_7", +}; + +static const char *activation_precision_str[] = { + "ACTIVATION_PRECISION_B8", + "ACTIVATION_PRECISION_B16", + "ACTIVATION_PRECISION_B32", + "ACTIVATION_PRECISION_B64", +}; + +static const char *activation_type_str[] = { + "ACTIVATION_TYPE_UNSIGNED", + "ACTIVATION_TYPE_SIGNED", +}; + +static const char *axi_mem_encoding_str[] = { + "AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_DEVICE_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE", + "AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE", +}; + +static const char *broadcast_mode_str[] = { + "BROADCAST_MODE_DISABLE", + "BROADCAST_MODE_ENABLE", +}; + +static const char *cmd0_opcode_str[] = { + "CMD0_OPCODE_NPU_OP_STOP", + "CMD0_OPCODE_NPU_OP_IRQ", + "CMD0_OPCODE_NPU_OP_CONV", + "CMD0_OPCODE_NPU_OP_DEPTHWISE", + "****", + "CMD0_OPCODE_NPU_OP_POOL", + "CMD0_OPCODE_NPU_OP_ELEMENTWISE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_OP_DMA_START", + "CMD0_OPCODE_NPU_OP_DMA_WAIT", + "CMD0_OPCODE_NPU_OP_KERNEL_WAIT", + "CMD0_OPCODE_NPU_OP_PMU_MASK", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_PAD_TOP", + "CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM", + "CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_IFM_PRECISION", + "****", + "CMD0_OPCODE_NPU_SET_IFM_UPSCALE", + "****", + "CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM_IB_END", + "****", + "CMD0_OPCODE_NPU_SET_IFM_REGION", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_PRECISION", + "CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_OFM_REGION", + "CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_STRIDE", + "****", + "CMD0_OPCODE_NPU_SET_ACC_FORMAT", + "CMD0_OPCODE_NPU_SET_ACTIVATION", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MIN", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MAX", + "CMD0_OPCODE_NPU_SET_WEIGHT_REGION", + "CMD0_OPCODE_NPU_SET_SCALE_REGION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_AB_START", + "****", + "CMD0_OPCODE_NPU_SET_BLOCKDEP", + "CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_DST_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE0", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_BROADCAST", + "CMD0_OPCODE_NPU_SET_IFM2_SCALAR", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_PRECISION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM2_IB_START", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_REGION", +}; + +static const char *cmd1_opcode_str[] = { + "CMD1_OPCODE_NPU_SET_IFM_BASE0", + "CMD1_OPCODE_NPU_SET_IFM_BASE1", + "CMD1_OPCODE_NPU_SET_IFM_BASE2", + "CMD1_OPCODE_NPU_SET_IFM_BASE3", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_OFM_BASE0", + "CMD1_OPCODE_NPU_SET_OFM_BASE1", + "CMD1_OPCODE_NPU_SET_OFM_BASE2", + "CMD1_OPCODE_NPU_SET_OFM_BASE3", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE_BASE", + "CMD1_OPCODE_NPU_SET_SCALE_LENGTH", + "CMD1_OPCODE_NPU_SET_OFM_SCALE", + "CMD1_OPCODE_NPU_SET_OPA_SCALE", + "CMD1_OPCODE_NPU_SET_OPB_SCALE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_DMA0_SRC", + "CMD1_OPCODE_NPU_SET_DMA0_DST", + "CMD1_OPCODE_NPU_SET_DMA0_LEN", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_IFM2_BASE0", + "CMD1_OPCODE_NPU_SET_IFM2_BASE1", + "CMD1_OPCODE_NPU_SET_IFM2_BASE2", + "CMD1_OPCODE_NPU_SET_IFM2_BASE3", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_USER_DEFINED0", + "CMD1_OPCODE_NPU_SET_USER_DEFINED1", + "CMD1_OPCODE_NPU_SET_USER_DEFINED2", + "CMD1_OPCODE_NPU_SET_USER_DEFINED3", + "CMD1_OPCODE_NPU_SET_USER_DEFINED4", + "CMD1_OPCODE_NPU_SET_USER_DEFINED5", + "CMD1_OPCODE_NPU_SET_USER_DEFINED6", + "CMD1_OPCODE_NPU_SET_USER_DEFINED7", +}; + +static const char *cmd_ctrl_str[] = { + "CMD_CTRL_CMD0_CTRL", + "CMD_CTRL_CMD1_CTRL", +}; + +static const char *custom_dma_cs_str[] = { + "CUSTOM_DMA_CS_DISABLE", + "CUSTOM_DMA_CS_ENABLE", +}; + +static const char *custom_dma_str[] = { + "CUSTOM_DMA_NOT_IMPLEMENTED", + "CUSTOM_DMA_IMPLEMENTED", +}; + +static const char *dma_fault_src_str[] = { + "DMA_FAULT_SRC_AXI_M0", + "DMA_FAULT_SRC_AXI_M1", +}; + +static const char *dma_region_mode_str[] = { + "DMA_REGION_MODE_EXTERNAL", + "DMA_REGION_MODE_INTERNAL", +}; + +static const char *dma_stride_mode_str[] = { + "DMA_STRIDE_MODE_D1", +}; + +static const char *elementwise_mode_str[] = { + "ELEMENTWISE_MODE_MUL", + "ELEMENTWISE_MODE_ADD", + "ELEMENTWISE_MODE_SUB", + "ELEMENTWISE_MODE_MIN", + "ELEMENTWISE_MODE_MAX", + "ELEMENTWISE_MODE_LRELU", + "ELEMENTWISE_MODE_ABS", + "ELEMENTWISE_MODE_CLZ", + "ELEMENTWISE_MODE_SHR", + "ELEMENTWISE_MODE_SHL", +}; + +static const char *functional_safety_str[] = { + "FUNCTIONAL_SAFETY_NOT_IMPLEMENTED", + "FUNCTIONAL_SAFETY_IMPLEMENTED", +}; + +static const char *ifm2_operand_order_str[] = { + "IFM2_OPERAND_ORDER_ORDER_B", + "IFM2_OPERAND_ORDER_ORDER_A", +}; + +static const char *ifm_scale_mode_str[] = { + "IFM_SCALE_MODE_OPA_OPB_16", + "IFM_SCALE_MODE_OPA_32", + "IFM_SCALE_MODE_OPB_32", +}; + +static const char *ifm_upscale_mode_str[] = { + "IFM_UPSCALE_MODE_NONE", + "IFM_UPSCALE_MODE_NEAREST", + "IFM_UPSCALE_MODE_ZEROS", +}; + +static const char *kernel_decomposition_str[] = { + "KERNEL_DECOMPOSITION_D8X8", + "KERNEL_DECOMPOSITION_D4X4", +}; + +static const char *kernel_dilation_str[] = { + "KERNEL_DILATION_NONE", + "KERNEL_DILATION_X2", +}; + +static const char *max_beats_str[] = { + "MAX_BEATS_B64", + "MAX_BEATS_B128", + "MAX_BEATS_B256", +}; + +static const char *mem_attr_str[] = { + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER0", + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER1", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER2", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER3", +}; + +static const char *ofm_scale_mode_str[] = { + "OFM_SCALE_MODE_PER_CHANNEL", + "OFM_SCALE_MODE_GLOBAL", +}; + +static const char *pmu_axi_channel_str[] = { + "PMU_AXI_CHANNEL_RD_CMD", + "PMU_AXI_CHANNEL_RD_IFM", + "PMU_AXI_CHANNEL_RD_WEIGHTS", + "PMU_AXI_CHANNEL_RD_SCALE_BIAS", + "PMU_AXI_CHANNEL_RD_MEM2MEM", + "****", + "****", + "****", + "PMU_AXI_CHANNEL_WR_OFM", + "PMU_AXI_CHANNEL_WR_MEM2MEM", +}; + +static const char *pmu_event_str[] = { + "PMU_EVENT_NO_EVENT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_CYCLE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_NPU_IDLE", + "PMU_EVENT_CC_STALLED_ON_BLOCKDEP", + "PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG", + "PMU_EVENT_NPU_ACTIVE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_MAC_ACTIVE", + "PMU_EVENT_MAC_ACTIVE_8BIT", + "PMU_EVENT_MAC_ACTIVE_16BIT", + "PMU_EVENT_MAC_DPU_ACTIVE", + "PMU_EVENT_MAC_STALLED_BY_WD_ACC", + "PMU_EVENT_MAC_STALLED_BY_WD", + "PMU_EVENT_MAC_STALLED_BY_ACC", + "PMU_EVENT_MAC_STALLED_BY_IB", + "PMU_EVENT_MAC_ACTIVE_32BIT", + "PMU_EVENT_MAC_STALLED_BY_INT_W", + "PMU_EVENT_MAC_STALLED_BY_INT_ACC", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AO_ACTIVE", + "PMU_EVENT_AO_ACTIVE_8BIT", + "PMU_EVENT_AO_ACTIVE_16BIT", + "PMU_EVENT_AO_STALLED_BY_OFMP_OB", + "PMU_EVENT_AO_STALLED_BY_OFMP", + "PMU_EVENT_AO_STALLED_BY_OB", + "PMU_EVENT_AO_STALLED_BY_ACC_IB", + "PMU_EVENT_AO_STALLED_BY_ACC", + "PMU_EVENT_AO_STALLED_BY_IB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_ACTIVE", + "PMU_EVENT_WD_STALLED", + "PMU_EVENT_WD_STALLED_BY_WS", + "PMU_EVENT_WD_STALLED_BY_WD_BUF", + "PMU_EVENT_WD_PARSE_ACTIVE", + "PMU_EVENT_WD_PARSE_STALLED", + "PMU_EVENT_WD_PARSE_STALLED_IN", + "PMU_EVENT_WD_PARSE_STALLED_OUT", + "PMU_EVENT_WD_TRANS_WS", + "PMU_EVENT_WD_TRANS_WB", + "PMU_EVENT_WD_TRANS_DW0", + "PMU_EVENT_WD_TRANS_DW1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI0_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI0_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI0_RD_STALL_LIMIT", + "PMU_EVENT_AXI0_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI_LATENCY_ANY", + "PMU_EVENT_AXI_LATENCY_32", + "PMU_EVENT_AXI_LATENCY_64", + "PMU_EVENT_AXI_LATENCY_128", + "PMU_EVENT_AXI_LATENCY_256", + "PMU_EVENT_AXI_LATENCY_512", + "PMU_EVENT_AXI_LATENCY_1024", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_DMA", + "PMU_EVENT_ECC_SB0", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI1_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI1_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI1_RD_STALL_LIMIT", + "PMU_EVENT_AXI1_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_SB1", +}; + +static const char *pooling_mode_str[] = { + "POOLING_MODE_MAX", + "POOLING_MODE_AVERAGE", + "POOLING_MODE_REDUCE_SUM", +}; + +static const char *privilege_level_str[] = { + "PRIVILEGE_LEVEL_USER", + "PRIVILEGE_LEVEL_PRIVILEGED", +}; + +static const char *round_mode_str[] = { + "ROUND_MODE_DBL", + "ROUND_MODE_TRUNCATE", + "ROUND_MODE_NATURAL", +}; + +static const char *security_level_str[] = { + "SECURITY_LEVEL_SECURE", + "SECURITY_LEVEL_NON_SECURE", +}; + +static const char *state_str[] = { + "STATE_STOPPED", + "STATE_RUNNING", +}; + +static const char *wd_core_slice_state_str[] = { + "WD_CORE_SLICE_STATE_HEADER", + "WD_CORE_SLICE_STATE_PALETTE", + "WD_CORE_SLICE_STATE_WEIGHTS", +}; + +static const char *wd_ctrl_state_str[] = { + "WD_CTRL_STATE_IDLE", + "WD_CTRL_STATE_DRAIN", + "WD_CTRL_STATE_OFD_INIT", + "WD_CTRL_STATE_OFD_RUN", +}; + +static const char *weight_order_str[] = { + "WEIGHT_ORDER_DEPTH_FIRST", + "WEIGHT_ORDER_PART_KERNEL_FIRST", +}; + +#endif + +// Register type structs +// id_r - ID register +struct id_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t version_status : 4; // This is the version of the product + uint32_t version_minor : 4; // This is the n for the P part of an RnPn release number + uint32_t version_major : 4; // This is the n for the R part of an RnPn release number + uint32_t product_major : 4; // Product major ID number (unique per base product) + uint32_t arch_patch_rev : 4; // This is the patch number of the architecture version a.b + uint32_t + arch_minor_rev : 8; // This is the minor architecture version number, b in the architecture version a.b + uint32_t + arch_major_rev : 4; // This is the major architecture version number, a in the architecture version a.b + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR id_r() : word0(269500929) {} + CONSTEXPR id_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + id_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_version_status() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_version_status() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR id_r &set_version_status(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile id_r &set_version_status(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_version_minor() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_version_minor() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR id_r &set_version_minor(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile id_r &set_version_minor(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_version_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + uint32_t get_version_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR id_r &set_version_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + volatile id_r &set_version_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_product_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_product_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR id_r &set_product_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile id_r &set_product_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_arch_patch_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + uint32_t get_arch_patch_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR id_r &set_arch_patch_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + volatile id_r &set_arch_patch_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_arch_minor_rev() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + uint32_t get_arch_minor_rev() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR id_r &set_arch_minor_rev(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + volatile id_r &set_arch_minor_rev(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_arch_major_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_arch_major_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR id_r &set_arch_major_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile id_r &set_arch_major_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// status_r - Register describes the current operating status of the NPU +struct status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t state : 1; // NPU state, 0 = Stopped, 1 = Running + uint32_t irq_raised : 1; // Raw IRQ status, 0 = IRQ not raised, 1 = IRQ raised. IRQ is cleared using command + // register bit 1 + uint32_t + bus_status : 1; // 0=OK, 1=Bus abort detected and processing halted (NPU will reach IDLE state and not + // to start process any more commands/AXI transactions). Can only be cleared by a reset + uint32_t reset_status : 1; // Reset is ongoing and only this register can be read (other registers read as 0 + // and writes are ignored.) A value of 0 means NPU is not being reset and can be + // accessed as normal + uint32_t + cmd_parse_error : 1; // 0=No error 1=Command stream parsing error detected. Can only be cleared by reset + uint32_t cmd_end_reached : 1; // 0=Not reached, 1=Reached. Cleared by writing QBASE or QSIZE when NPU is in + // stopped state + uint32_t pmu_irq_raised : 1; // 0=No PMU IRQ, 1=PMU IRQ raised. Cleared by using command register bit 1 + uint32_t wd_fault : 1; // Weight decoder state: 0=no fault 1=weight decoder decompression fault. Can only be + // cleared by reset + uint32_t ecc_fault : 1; // ECC state for internal RAMs: 0=no fault 1=ECC fault signalled. Can only be + // cleared by reset + uint32_t reserved0 : 2; + uint32_t faulting_interface : 1; // Faulting interface on bus abort + uint32_t faulting_channel : 4; // Faulting channel on a bus abort. Read: 0=Cmd 1=IFM 2=Weights 3=Scale+Bias + // 4=Mem2Mem; Write: 8=OFM 9=Mem2Mem + uint32_t irq_history_mask : 16; // IRQ History mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR status_r() : word0(8) {} + CONSTEXPR status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::state get_state() const + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::state get_state() const volatile + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR status_r &set_state(NPU_NAMESPACE::state value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile status_r &set_state(NPU_NAMESPACE::state value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR status_r &set_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile status_r &set_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_bus_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_bus_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR status_r &set_bus_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile status_r &set_bus_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_reset_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_reset_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR status_r &set_reset_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile status_r &set_reset_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_parse_error() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_parse_error() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR status_r &set_cmd_parse_error(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile status_r &set_cmd_parse_error(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_end_reached() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_end_reached() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR status_r &set_cmd_end_reached(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile status_r &set_cmd_end_reached(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_pmu_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_pmu_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR status_r &set_pmu_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile status_r &set_pmu_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wd_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wd_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR status_r &set_wd_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile status_r &set_wd_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ecc_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ecc_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR status_r &set_ecc_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile status_r &set_ecc_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_fault_src get_faulting_interface() const + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + NPU_NAMESPACE::dma_fault_src get_faulting_interface() const volatile + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + CONSTEXPR status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + volatile status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + CONSTEXPR uint32_t get_faulting_channel() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_faulting_channel() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR status_r &set_faulting_channel(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile status_r &set_faulting_channel(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_irq_history_mask() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_irq_history_mask() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR status_r &set_irq_history_mask(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile status_r &set_irq_history_mask(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// cmd_r - Command register, reads as last written command +struct cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t transition_to_running_state : 1; // Write 1 to transition the NPU to running state. Writing 0 has + // no effect + uint32_t clear_irq : 1; // Write 1 to clear the IRQ status in the STATUS register. Writing 0 has no effect + uint32_t clock_q_enable : 1; // Write 1 to this bit to enable clock off using clock q-interface and enable + // the requester clock gate + uint32_t power_q_enable : 1; // Write 1 to this bit to enable power off using power q-interface + uint32_t + stop_request : 1; // Write 1 to this bit to request STOP after completing any already-started commands + uint32_t reserved0 : 11; + uint32_t clear_irq_history : 16; // Clears the IRQ history mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cmd_r() : word0(12) {} + CONSTEXPR cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_transition_to_running_state() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_transition_to_running_state() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR cmd_r &set_transition_to_running_state(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile cmd_r &set_transition_to_running_state(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_clear_irq() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_clear_irq() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR cmd_r &set_clear_irq(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile cmd_r &set_clear_irq(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_clock_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_clock_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR cmd_r &set_clock_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile cmd_r &set_clock_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_power_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_power_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR cmd_r &set_power_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile cmd_r &set_power_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_stop_request() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_stop_request() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR cmd_r &set_stop_request(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile cmd_r &set_stop_request(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_clear_irq_history() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_clear_irq_history() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR cmd_r &set_clear_irq_history(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile cmd_r &set_clear_irq_history(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// reset_r - Request Reset and new security mode +struct reset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t pending_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t pending_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR reset_r() : word0(0) {} + CONSTEXPR reset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + reset_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_pending_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_pending_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_pending_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_pending_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// qbase_r - Base address of the command stream in bytes +struct qbase_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR qbase_r() : word0(0), word1(0) {} + CONSTEXPR qbase_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + qbase_r copy() volatile + { + return *this; + } +#endif +}; + +// qread_r - Read offset in the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QREAD : 32; // The read offset of the current command under execution + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qread_r() : word0(0) {} + CONSTEXPR qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QREAD() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QREAD() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qread_r &set_QREAD(uint32_t value) + { + word0 = value; + return *this; + } + volatile qread_r &set_QREAD(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// qconfig_r - AXI configuration for the command stream in the range 0-3. Same encoding as for REGIONCFG +struct qconfig_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_region0 : 2; // Command region configuration + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qconfig_r() : word0(0) {} + CONSTEXPR qconfig_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qconfig_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_cmd_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_cmd_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// qsize_r - Size of the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qsize_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QSIZE : 32; // Size of the next command stream to be executed by the NPU + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qsize_r() : word0(0) {} + CONSTEXPR qsize_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qsize_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QSIZE() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QSIZE() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qsize_r &set_QSIZE(uint32_t value) + { + word0 = value; + return *this; + } + volatile qsize_r &set_QSIZE(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// prot_r - Protection level configured for the NPU when acting as an AXI requester +struct prot_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t active_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t active_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR prot_r() : word0(0) {} + CONSTEXPR prot_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + prot_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_active_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_active_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_active_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_active_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// config_r - RTL configuration +struct config_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t macs_per_cc : 4; // The log2(macs/clock cycle) + uint32_t cmd_stream_version : 4; // command stream version accepted by this NPU + uint32_t shram_size : 8; // Total size in KB of internal SHRAM + uint32_t reserved0 : 10; + uint32_t functional_safety : 1; // Functional safety configuration + uint32_t custom_dma : 1; // Custom DMA configuration + uint32_t product : 4; // Product configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR config_r() : word0(0) {} + CONSTEXPR config_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + config_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_macs_per_cc() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_macs_per_cc() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR config_r &set_macs_per_cc(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile config_r &set_macs_per_cc(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_stream_version() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_stream_version() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR config_r &set_cmd_stream_version(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile config_r &set_cmd_stream_version(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_shram_size() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + uint32_t get_shram_size() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR config_r &set_shram_size(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + volatile config_r &set_shram_size(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::functional_safety get_functional_safety() const + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + NPU_NAMESPACE::functional_safety get_functional_safety() const volatile + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + CONSTEXPR config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + volatile config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma get_custom_dma() const + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + NPU_NAMESPACE::custom_dma get_custom_dma() const volatile + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + CONSTEXPR config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + volatile config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + CONSTEXPR uint32_t get_product() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_product() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR config_r &set_product(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile config_r &set_product(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// lock_r - Lock register. This register is designed for driver use and does not affect NPU functionality +struct lock_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t LOCK : 32; // 32 bit value for LOCK configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR lock_r() : word0(0) {} + CONSTEXPR lock_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + lock_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_LOCK() const + { + uint32_t value = word0; + return value; + } + uint32_t get_LOCK() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR lock_r &set_LOCK(uint32_t value) + { + word0 = value; + return *this; + } + volatile lock_r &set_LOCK(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// regioncfg_r - Region memory type configuration. Bits[2*k+1:2*k] give the memory type for REGION[k] +struct regioncfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t region0 : 2; // Bits for Region0 Configuration + uint32_t region1 : 2; // Bits for Region1 Configuration + uint32_t region2 : 2; // Bits for Region2 Configuration + uint32_t region3 : 2; // Bits for Region3 Configuration + uint32_t region4 : 2; // Bits for Region4 Configuration + uint32_t region5 : 2; // Bits for Region5 Configuration + uint32_t region6 : 2; // Bits for Region6 Configuration + uint32_t region7 : 2; // Bits for Region7 Configuration + uint32_t reserved0 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR regioncfg_r() : word0(0) {} + CONSTEXPR regioncfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + regioncfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region1() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + NPU_NAMESPACE::mem_attr get_region1() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + CONSTEXPR regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + volatile regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region2() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::mem_attr get_region2() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + volatile regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region3() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + NPU_NAMESPACE::mem_attr get_region3() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + CONSTEXPR regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + volatile regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region4() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + NPU_NAMESPACE::mem_attr get_region4() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + CONSTEXPR regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + volatile regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region5() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + NPU_NAMESPACE::mem_attr get_region5() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + CONSTEXPR regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + volatile regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region6() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + NPU_NAMESPACE::mem_attr get_region6() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + CONSTEXPR regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + volatile regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region7() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + NPU_NAMESPACE::mem_attr get_region7() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + CONSTEXPR regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } + volatile regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } +#endif +}; + +// axi_limit0_r - AXI limits for port 0 counter 0 +struct axi_limit0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit0_r() : word0(0) {} + CONSTEXPR axi_limit0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit0_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit1_r - AXI limits for port 0 counter 1 +struct axi_limit1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit1_r() : word0(0) {} + CONSTEXPR axi_limit1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit1_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit2_r - AXI limits for port 1 counter 2 +struct axi_limit2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit2_r() : word0(0) {} + CONSTEXPR axi_limit2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit2_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit3_r - AXI limits for port 1 counter 3 +struct axi_limit3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit3_r() : word0(0) {} + CONSTEXPR axi_limit3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit3_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// basep_r - The driver can use this address to relocate the command stream on region 0. If the region contains data +// requiring A-byte alignment then the base must be a multiple of A +struct basep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR basep_r() : word0(0), word1(0) {} + CONSTEXPR basep_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + basep_r copy() volatile + { + return *this; + } +#endif +}; + +// wd_status_r - WD_STATUS +struct wd_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t core_slice_state : 2; // WD core slice parser state + uint32_t core_idle : 1; // Core idle + uint32_t ctrl_state : 2; // WD control state + uint32_t ctrl_idle : 1; // All stripe jobs idle (all weights consumed) + uint32_t write_buf_index0 : 3; // current write index for next data from core + uint32_t write_buf_valid0 : 1; // write buf valid (full) + uint32_t write_buf_idle0 : 1; // write buf idle (empty) + uint32_t write_buf_index1 : 3; // current write index for next data from core + uint32_t write_buf_valid1 : 1; // write buf valid (full) + uint32_t write_buf_idle1 : 1; // write buf idle (empty) + uint32_t events : 12; // WD events mapped as appendix A + uint32_t reserved0 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR wd_status_r() : word0(0) {} + CONSTEXPR wd_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + wd_status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const volatile + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_core_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_core_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR wd_status_r &set_core_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile wd_status_r &set_core_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const volatile + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + volatile wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + CONSTEXPR uint32_t get_ctrl_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ctrl_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile wd_status_r &set_ctrl_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index0() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + uint32_t get_write_buf_index0() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index0(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + volatile wd_status_r &set_write_buf_index0(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_write_buf_valid0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile wd_status_r &set_write_buf_valid0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_write_buf_idle0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile wd_status_r &set_write_buf_idle0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index1() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + uint32_t get_write_buf_index1() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index1(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + volatile wd_status_r &set_write_buf_index1(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_write_buf_valid1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile wd_status_r &set_write_buf_valid1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_write_buf_idle1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile wd_status_r &set_write_buf_idle1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR wd_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } + volatile wd_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } +#endif +}; + +// mac_status_r - MAC_STATUS +struct mac_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block_cfg_valid : 1; // MAC has a valid block configuration + uint32_t trav_en : 1; // MAC is doing block traversal + uint32_t wait_for_ib : 1; // MAC is waiting for an Input Buffer to become available + uint32_t wait_for_acc_buf : 1; // MAC is waiting for an Accumulator Buffer to become available + uint32_t wait_for_weights : 1; // MAC is waiting for a Weight Block to become available + uint32_t stall_stripe : 1; // MAC is stalling between two stripes + uint32_t dw_sel : 1; // Currently used weight interface in MAC AI + uint32_t wait_for_dw0_ready : 1; // MAC AI is waiting for MAC DPU to send dw0_ready to WD + uint32_t wait_for_dw1_ready : 1; // MAC AI is waiting for MAC DPU to send dw1_ready to WD + uint32_t acc_buf_sel_ai : 1; // Currently used AccBuf interface in MAC AI + uint32_t wait_for_acc0_ready : 1; // MAC AI is waiting for acc0_ready from AO + uint32_t wait_for_acc1_ready : 1; // MAC AI is waiting for acc1_ready from AO + uint32_t acc_buf_sel_aa : 1; // Currently used AccBuf interface in MAC ADDER_ARRAY + uint32_t acc0_valid : 1; // MAC outgoing value of acc0_valid + uint32_t acc1_valid : 1; // MAC outgoing value of acc1_valid + uint32_t reserved0 : 1; + uint32_t events : 11; // Mapped to MAC events described in Appendix A + uint32_t reserved1 : 5; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR mac_status_r() : word0(0) {} + CONSTEXPR mac_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + mac_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block_cfg_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_block_cfg_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR mac_status_r &set_block_cfg_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile mac_status_r &set_block_cfg_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_trav_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_trav_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR mac_status_r &set_trav_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile mac_status_r &set_trav_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wait_for_ib() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wait_for_ib() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_ib(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile mac_status_r &set_wait_for_ib(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc_buf() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_wait_for_acc_buf() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc_buf(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile mac_status_r &set_wait_for_acc_buf(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_wait_for_weights() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_wait_for_weights() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_weights(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile mac_status_r &set_wait_for_weights(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_stall_stripe() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_stall_stripe() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR mac_status_r &set_stall_stripe(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile mac_status_r &set_stall_stripe(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_dw_sel() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_dw_sel() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR mac_status_r &set_dw_sel(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile mac_status_r &set_dw_sel(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wait_for_dw0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile mac_status_r &set_wait_for_dw0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_wait_for_dw1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile mac_status_r &set_wait_for_dw1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_ai() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_acc_buf_sel_ai() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_ai(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_ai(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_wait_for_acc0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile mac_status_r &set_wait_for_acc0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_wait_for_acc1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile mac_status_r &set_wait_for_acc1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_aa() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_acc_buf_sel_aa() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_aa(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_aa(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_acc0_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_acc0_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR mac_status_r &set_acc0_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile mac_status_r &set_acc0_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_acc1_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_acc1_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR mac_status_r &set_acc1_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile mac_status_r &set_acc1_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR mac_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } + volatile mac_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } +#endif +}; + +// ao_status_r - AO_STATUS +struct ao_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_sbw_valid : 1; // Block command to shared buffer write module is valid + uint32_t cmd_act_valid : 1; // Block command to activation function module is valid + uint32_t cmd_ctl_valid : 1; // Block command to control module is valid + uint32_t cmd_scl_valid : 1; // Block command to scale module is valid + uint32_t cmd_sbr_valid : 1; // Block command to shared buffer read module is valid + uint32_t cmd_ofm_valid : 1; // Block command to ofm parameter module is valid + uint32_t blk_cmd_ready : 1; // Ready to accept block command + uint32_t blk_cmd_valid : 1; // Block command from CC is valid + uint32_t reserved0 : 8; + uint32_t events : 8; // Mapped to AO events described in Appendix A + uint32_t reserved1 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ao_status_r() : word0(0) {} + CONSTEXPR ao_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ao_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_sbw_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_sbw_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbw_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile ao_status_r &set_cmd_sbw_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_act_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cmd_act_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR ao_status_r &set_cmd_act_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile ao_status_r &set_cmd_act_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cmd_ctl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cmd_ctl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ctl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile ao_status_r &set_cmd_ctl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_cmd_scl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_cmd_scl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR ao_status_r &set_cmd_scl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile ao_status_r &set_cmd_scl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_sbr_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_sbr_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbr_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile ao_status_r &set_cmd_sbr_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_ofm_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_ofm_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ofm_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile ao_status_r &set_cmd_ofm_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_blk_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile ao_status_r &set_blk_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_blk_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile ao_status_r &set_blk_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR ao_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } + volatile ao_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } +#endif +}; + +// dma_status0_r - DMA_STATUS0 +struct dma_status0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_idle : 1; // When this bit is high means that the CMD block is not busy in generating addresses + // for a CMD job + uint32_t ifm_idle : 1; // When this bit is high means that there are no ongoing IFM jobs + uint32_t wgt_idle_c0 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c0 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t m2m_idle : 1; // When this bit is high means that there are no ongoing M2M jobs + uint32_t ofm_idle : 1; // When this bit is high means that there are no ongoing OFM jobs + uint32_t halt_req : 1; // CPM has requested to HALT AXI bus before soft reset + uint32_t halt_ack : 1; // DMA is in condition to halt the AXI bus since there are no pending transactions + uint32_t pause_req : 1; // CC has requested to pause the AXI + uint32_t pause_ack : 1; // DMA is in condition to pause the AXI bus since there are no pending transactions + uint32_t ib0_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 0 - Core 0 + uint32_t ib1_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 1 - Core 0 + uint32_t ib1_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 1 - Core 0 + uint32_t ib0_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 1 - Core 0 + uint32_t ob0_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 0 + uint32_t ob0_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 0 + uint32_t ob1_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 0 + uint32_t ob1_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 0 + uint32_t cmd_valid : 1; // New command word for CC to be consumed + uint32_t cmd_ready : 1; // command word consumed by CC + uint32_t wd_bitstream_valid_c0 : 1; // New weight word for WD to be consumed - Core 0 + uint32_t wd_bitstream_ready_c0 : 1; // Weight word consumed by WD - Core 0 + uint32_t bs_bitstream_valid_c0 : 1; // New BaS word for AO to be consumed - Core 0 + uint32_t bs_bitstream_ready_c0 : 1; // BaS word consumed by AO - Core 0 + uint32_t axi0_ar_stalled : 1; // Read transfer request stalled on arready low AXI0 (due to memory system) + uint32_t axi0_rd_limit_stall : 1; // Read stalled due to one AXI0 limit counter being reached + uint32_t axi0_aw_stalled : 1; // Write transfer request stalled on awready low AXI0 (due to memory system) + uint32_t axi0_w_stalled : 1; // Write transfer stalled on awready low AXI0 (due to memory system) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status0_r() : word0(0) {} + CONSTEXPR dma_status0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status0_r &set_cmd_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ifm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_ifm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status0_r &set_ifm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status0_r &set_ifm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wgt_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status0_r &set_wgt_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status0_r &set_wgt_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_bas_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status0_r &set_bas_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status0_r &set_bas_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_m2m_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_m2m_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status0_r &set_m2m_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status0_r &set_m2m_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_ofm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ofm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status0_r &set_ofm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status0_r &set_ofm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_halt_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_halt_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status0_r &set_halt_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status0_r &set_halt_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_halt_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_halt_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status0_r &set_halt_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status0_r &set_halt_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_pause_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_pause_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status0_r &set_pause_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status0_r &set_pause_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_pause_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_pause_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status0_r &set_pause_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status0_r &set_pause_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib0_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib0_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib1_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib1_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib0_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib0_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ib1_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ib1_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob0_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status0_r &set_ob0_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob0_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status0_r &set_ob0_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_ob1_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status0_r &set_ob1_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_ob1_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status0_r &set_ob1_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status0_r &set_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status0_r &set_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + uint32_t get_wd_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + uint32_t get_wd_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + uint32_t get_bs_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + uint32_t get_bs_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_axi0_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + uint32_t get_axi0_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + volatile dma_status0_r &set_axi0_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_axi0_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + uint32_t get_axi0_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + volatile dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + CONSTEXPR uint32_t get_axi0_aw_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + uint32_t get_axi0_aw_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_aw_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + volatile dma_status0_r &set_axi0_aw_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + CONSTEXPR uint32_t get_axi0_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_axi0_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile dma_status0_r &set_axi0_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// dma_status1_r - DMA_STATUS1 +struct dma_status1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t axi0_wr_limit_stall : 1; // Write stalled due to one AXI0 limit counter being reached + uint32_t axi1_ar_stalled : 1; // Read transfer request stalled on arready low AXI1 (due to memory system) + uint32_t axi1_rd_limit_stall : 1; // Read stalled due to one AXI1 limit counter being reached + uint32_t axi1_wr_stalled : 1; // Write transfer request stalled on awready low AXI1 (due to memory system) + uint32_t axi1_w_stalled : 1; // Write transfer stalled on wready low AXI1 (due to memory system) + uint32_t axi1_wr_limit_stall : 1; // Write stalled due to one AXI1 limit counter being reached + uint32_t wgt_idle_c1 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c1 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t ib0_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 0 - Core 1 + uint32_t ib1_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 1 - Core 1 + uint32_t ib1_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 1 - Core 1 + uint32_t ib0_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 1 - Core 1 + uint32_t ob0_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 1 + uint32_t ob0_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 1 + uint32_t ob1_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 1 + uint32_t ob1_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 1 + uint32_t wd_bitstream_valid_c1 : 1; // New weight word for WD to be consumed - Core 1 + uint32_t wd_bitstream_ready_c1 : 1; // Weight word consumed by WD - Core 1 + uint32_t bs_bitstream_valid_c1 : 1; // New BaS word for AO to be consumed - Core 1 + uint32_t bs_bitstream_ready_c1 : 1; // BaS word consumed by AO - Core 1 + uint32_t reserved0 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status1_r() : word0(0) {} + CONSTEXPR dma_status1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_axi0_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_axi0_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_axi1_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_axi1_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status1_r &set_axi1_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_axi1_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_axi1_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_axi1_wr_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status1_r &set_axi1_wr_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_axi1_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_axi1_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status1_r &set_axi1_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_axi1_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_wgt_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status1_r &set_wgt_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status1_r &set_wgt_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_bas_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status1_r &set_bas_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status1_r &set_bas_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ib0_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_ib0_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib1_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib1_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib0_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib0_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib1_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib1_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ob0_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status1_r &set_ob0_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ob0_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status1_r &set_ob0_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob1_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status1_r &set_ob1_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob1_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status1_r &set_ob1_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_wd_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_wd_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_bs_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_bs_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } +#endif +}; + +// clkforce_r - Force clocks on for clock gating +struct clkforce_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t top_level_clk : 1; // set to 1 to force on TOP level clock + uint32_t cc_clk : 1; // set to 1 to force on CC clock + uint32_t dma_clk : 1; // set to 1 to force on DMA clock + uint32_t mac_clk : 1; // set to 1 to force on MAC clock + uint32_t ao_clk : 1; // set to 1 to force on AO clock + uint32_t wd_clk : 1; // set to 1 to force on WD clock + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR clkforce_r() : word0(0) {} + CONSTEXPR clkforce_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + clkforce_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_top_level_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_top_level_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR clkforce_r &set_top_level_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile clkforce_r &set_top_level_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cc_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cc_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR clkforce_r &set_cc_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile clkforce_r &set_cc_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_dma_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_dma_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR clkforce_r &set_dma_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile clkforce_r &set_dma_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mac_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mac_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR clkforce_r &set_mac_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile clkforce_r &set_mac_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_ao_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR clkforce_r &set_ao_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile clkforce_r &set_ao_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_wd_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_wd_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR clkforce_r &set_wd_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile clkforce_r &set_wd_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } +#endif +}; + +// debug_address_r - Set debug address for register reads 0x400-0x7FF. The address must be 1KB aligned +struct debug_address_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t addr : 32; // Register address + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_address_r() : word0(0) {} + CONSTEXPR debug_address_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_address_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + uint32_t value = word0; + return value; + } + uint32_t get_addr() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_address_r &set_addr(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_address_r &set_addr(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_misc_r - 32-bit read/write register for driver debug use. This does not affect NPU function +struct debug_misc_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t misc : 32; // Debug misc + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_misc_r() : word0(0) {} + CONSTEXPR debug_misc_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_misc_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_misc() const + { + uint32_t value = word0; + return value; + } + uint32_t get_misc() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_misc_r &set_misc(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_misc_r &set_misc(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_block_r - Set from which of four block banks the TSU registers are read. 0 = read from the current bank 256+n = +// force to read from bank n where n is in the range 0 to 3 +struct debug_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block : 32; // Debug block + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_block_r() : word0(0) {} + CONSTEXPR debug_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block() const + { + uint32_t value = word0; + return value; + } + uint32_t get_block() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_block_r &set_block(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_block_r &set_block(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmcr_r - PMU Register control +struct pmcr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cnt_en : 1; // Enable counter + uint32_t event_cnt_rst : 1; // Reset event counter + uint32_t cycle_cnt_rst : 1; // Reset cycle counter + uint32_t mask_en : 1; // PMU can be enabled/disabled by command stream operation NPU_OP_PMU_MASK + uint32_t reserved0 : 7; + uint32_t num_event_cnt : 5; // Number of event counters + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcr_r() : word0(8192) {} + CONSTEXPR pmcr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cnt_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cnt_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcr_r &set_cnt_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcr_r &set_cnt_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_event_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_event_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcr_r &set_event_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcr_r &set_event_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cycle_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cycle_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcr_r &set_cycle_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcr_r &set_cycle_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mask_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mask_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcr_r &set_mask_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcr_r &set_mask_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_num_event_cnt() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + uint32_t get_num_event_cnt() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR pmcr_r &set_num_event_cnt(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } + volatile pmcr_r &set_num_event_cnt(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } +#endif +}; + +// pmcntenset_r - Count enable set register +struct pmcntenset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenset_r() : word0(0) {} + CONSTEXPR pmcntenset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenset_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenset_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmcntenclr_r - Count enable clear register +struct pmcntenclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenclr_r() : word0(0) {} + CONSTEXPR pmcntenclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenclr_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenclr_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsset_r - Overflow flag status set register +struct pmovsset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow set bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow set bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow set bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow set bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow set bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsset_r() : word0(0) {} + CONSTEXPR pmovsset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsclr_r - Overflow flag status clear register +struct pmovsclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow clear bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow clear bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow clear bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow clear bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow clear bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsclr_r() : word0(0) {} + CONSTEXPR pmovsclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintset_r - Interrupt enable set register +struct pmintset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintset_r() : word0(0) {} + CONSTEXPR pmintset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintset_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintset_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintclr_r - Interrupt enable clear register +struct pmintclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintclr_r() : word0(0) {} + CONSTEXPR pmintclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmccntr_r - Performance monitor cycle count register +struct pmccntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_LO : 32; // Cycle count - LSB + uint32_t CYCLE_CNT_HI : 16; // Cycle count - MSB + uint32_t reserved0 : 16; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR pmccntr_r() : word0(0), word1(0) {} + CONSTEXPR pmccntr_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + pmccntr_r copy() volatile + { + return *this; + } +#endif +}; + +// pmccntr_cfg_r - Set start/stop event on the cycle counter +struct pmccntr_cfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_CFG_START : 10; // Cycle counter start event + uint32_t reserved0 : 6; + uint32_t CYCLE_CNT_CFG_STOP : 10; // Cycle counter stop event + uint32_t reserved1 : 6; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmccntr_cfg_r() : word0(0) {} + CONSTEXPR pmccntr_cfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmccntr_cfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// pmcaxi_chan_r - Set which AXI channel to monitor for latency measurements in PMU +struct pmcaxi_chan_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CH_SEL : 4; // Channel select for latency measurements + uint32_t reserved0 : 4; + uint32_t AXI_CNT_SEL : 2; // AXI counter to monitor for latency measurements + uint32_t BW_CH_SEL_EN : 1; // Bandwidth channel selector + uint32_t reserved1 : 21; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcaxi_chan_r() : word0(0) {} + CONSTEXPR pmcaxi_chan_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcaxi_chan_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const volatile + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_AXI_CNT_SEL() const + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + uint32_t get_AXI_CNT_SEL() const volatile + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + volatile pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_BW_CH_SEL_EN() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_BW_CH_SEL_EN() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } +#endif +}; + +// kernel_x_r - Kernel X offset of in kernel decomposition +struct kernel_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_x_r() : word0(0) {} + CONSTEXPR kernel_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_y_r - Kernel Y offset of in kernel decomposition +struct kernel_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_y_r() : word0(0) {} + CONSTEXPR kernel_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_w_m1_r - Kernel (width-1) of current block +struct kernel_w_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_w_m1_r() : word0(0) {} + CONSTEXPR kernel_w_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_w_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_w_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_w_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_h_m1_r - Kernel (height-1) of current block +struct kernel_h_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_h_m1_r() : word0(0) {} + CONSTEXPR kernel_h_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_h_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_h_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_h_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_width_m1_r - OFM current block (width-1) +struct ofm_cblk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_height_m1_r - OFM current block (height-1) +struct ofm_cblk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_depth_m1_r - OFM current block (depth-1) +struct ofm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_depth_m1_r - IFM current block (depth-1) +struct ifm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_x_r - Block X coordinate in OFM +struct ofm_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_x_r() : word0(0) {} + CONSTEXPR ofm_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_y_r - Block Y coordinate in OFM +struct ofm_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_y_r() : word0(0) {} + CONSTEXPR ofm_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_z_r - Block Z (channel) coordinate in OFM +struct ofm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_z_r() : word0(0) {} + CONSTEXPR ofm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_z_r - Block Z (channel) coordinate in IFM +struct ifm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_z_r() : word0(0) {} + CONSTEXPR ifm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_top_r - Block top pad +struct pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_top_r() : word0(0) {} + CONSTEXPR pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_left_r - Block left pad +struct pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_left_r() : word0(0) {} + CONSTEXPR pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_width_r - IFM current block derived width +struct ifm_cblk_width_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_width_r() : word0(0) {} + CONSTEXPR ifm_cblk_width_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_width_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_width_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_width_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_height_r - IFM current block derived height +struct ifm_cblk_height_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_height_r() : word0(0) {} + CONSTEXPR ifm_cblk_height_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_height_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_height_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_height_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ifm_src_r - DMA IFM channel source position on AXI +struct dma_ifm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ifm_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_ifm_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ifm_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_ifm_dst_r - DMA IFM channel destination position in SHRAM +struct dma_ifm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ifm_dst_r() : word0(0) {} + CONSTEXPR dma_ifm_dst_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ifm_dst_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ifm_dst_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ifm_dst_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_src_r - DMA OFM channel source position in SHRAM +struct dma_ofm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ofm_src_r() : word0(0) {} + CONSTEXPR dma_ofm_src_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ofm_src_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ofm_src_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ofm_src_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_dst_r - DMA OFM channel destination position on AXI +struct dma_ofm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ofm_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_ofm_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ofm_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_weight_src_r - DMA weight channel source position on AXI +struct dma_weight_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_weight_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_weight_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_weight_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_src_r - DMA command channel source position on AXI +struct dma_cmd_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_cmd_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_cmd_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_cmd_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_size_r - DMA command channel number of bytes buffered +struct dma_cmd_size_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_cmd_size_r() : word0(0) {} + CONSTEXPR dma_cmd_size_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_cmd_size_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_cmd_size_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_cmd_size_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_m2m_src_r - DMA memory to memory source position on AXI +struct dma_m2m_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_m2m_dst_r - DMA memory to memory destination position on AXI +struct dma_m2m_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// current_qread_r - QREAD position being issued (rather than completed) +struct current_qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_qread_r() : word0(0) {} + CONSTEXPR current_qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_qread_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_qread_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_scale_src_r - DMA scale and bias channel source position on AXI +struct dma_scale_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_scale_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_scale_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_scale_src_r copy() volatile + { + return *this; + } +#endif +}; + +// current_block_r - 0-3. Current block bank being executed by the TSU or last one executed if TSU is stopped +struct current_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_block_r() : word0(0) {} + CONSTEXPR current_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_block_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_block_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_op_r - Current NPU OP command being executed by the TSU +struct current_op_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_op_r() : word0(0) {} + CONSTEXPR current_op_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_op_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_op_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_op_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_cmd_r - Current 32-bit command being parsed by the command stream parser +struct current_cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_cmd_r() : word0(0) {} + CONSTEXPR current_cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_cmd_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_cmd_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevcntr_r - Performance monitor event 0 count register +struct pmevcntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t count : 32; // Count word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevcntr_r() : word0(0) {} + CONSTEXPR pmevcntr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevcntr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_count() const + { + uint32_t value = word0; + return value; + } + uint32_t get_count() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pmevcntr_r &set_count(uint32_t value) + { + word0 = value; + return *this; + } + volatile pmevcntr_r &set_count(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevtyper_r - Performance monitor event type register 0 +struct pmevtyper_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EV_TYPE : 10; // Event Type + uint32_t reserved0 : 22; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevtyper_r() : word0(0) {} + CONSTEXPR pmevtyper_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevtyper_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_EV_TYPE() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_EV_TYPE() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// shared_buffer_r - Shared buffer debug access. Only valid in STOPPED state +struct shared_buffer_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_word : 32; // Memory word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR shared_buffer_r() : word0(0) {} + CONSTEXPR shared_buffer_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + shared_buffer_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_mem_word() const + { + uint32_t value = word0; + return value; + } + uint32_t get_mem_word() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR shared_buffer_r &set_mem_word(uint32_t value) + { + word0 = value; + return *this; + } + volatile shared_buffer_r &set_mem_word(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_top_r - None +struct ifm_pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_top_r() : word0(0) {} + CONSTEXPR ifm_pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_left_r - None +struct ifm_pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_left_r() : word0(0) {} + CONSTEXPR ifm_pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_right_r - None +struct ifm_pad_right_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_right_r() : word0(0) {} + CONSTEXPR ifm_pad_right_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_right_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_right_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_right_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_bottom_r - None +struct ifm_pad_bottom_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_bottom_r() : word0(0) {} + CONSTEXPR ifm_pad_bottom_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_bottom_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_bottom_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_bottom_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_depth_m1_r - None +struct ifm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_precision_r - None +struct ifm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_precision_r() : word0(0) {} + CONSTEXPR ifm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_upscale_r - None +struct ifm_upscale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_upscale_r() : word0(0) {} + CONSTEXPR ifm_upscale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_upscale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_upscale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_upscale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_zero_point_r - None +struct ifm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_zero_point_r() : word0(0) {} + CONSTEXPR ifm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_width0_m1_r - None +struct ifm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_width0_m1_r() : word0(0) {} + CONSTEXPR ifm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height0_m1_r - None +struct ifm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height0_m1_r() : word0(0) {} + CONSTEXPR ifm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height1_m1_r - None +struct ifm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height1_m1_r() : word0(0) {} + CONSTEXPR ifm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_ib_end_r - None +struct ifm_ib_end_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_ib_end_r() : word0(0) {} + CONSTEXPR ifm_ib_end_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_ib_end_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_ib_end_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_ib_end_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_region_r - None +struct ifm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_region_r() : word0(0) {} + CONSTEXPR ifm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width_m1_r - None +struct ofm_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width_m1_r() : word0(0) {} + CONSTEXPR ofm_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height_m1_r - None +struct ofm_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height_m1_r() : word0(0) {} + CONSTEXPR ofm_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_depth_m1_r - None +struct ofm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_precision_r - None +struct ofm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_precision_r() : word0(0) {} + CONSTEXPR ofm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_width_m1_r - None +struct ofm_blk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_height_m1_r - None +struct ofm_blk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_depth_m1_r - None +struct ofm_blk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_zero_point_r - None +struct ofm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_zero_point_r() : word0(0) {} + CONSTEXPR ofm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width0_m1_r - None +struct ofm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width0_m1_r() : word0(0) {} + CONSTEXPR ofm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height0_m1_r - None +struct ofm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height0_m1_r() : word0(0) {} + CONSTEXPR ofm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height1_m1_r - None +struct ofm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height1_m1_r() : word0(0) {} + CONSTEXPR ofm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_region_r - None +struct ofm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_region_r() : word0(0) {} + CONSTEXPR ofm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_width_m1_r - None +struct kernel_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_width_m1_r() : word0(0) {} + CONSTEXPR kernel_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_height_m1_r - None +struct kernel_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_height_m1_r() : word0(0) {} + CONSTEXPR kernel_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_stride_r - None +struct kernel_stride_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_stride_r() : word0(0) {} + CONSTEXPR kernel_stride_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_stride_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_stride_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_stride_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// acc_format_r - None +struct acc_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR acc_format_r() : word0(0) {} + CONSTEXPR acc_format_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + acc_format_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR acc_format_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile acc_format_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_r - None +struct activation_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_r() : word0(0) {} + CONSTEXPR activation_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_min_r - None +struct activation_min_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_min_r() : word0(0) {} + CONSTEXPR activation_min_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_min_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_min_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_min_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_max_r - None +struct activation_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_max_r() : word0(0) {} + CONSTEXPR activation_max_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_max_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_max_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_max_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// weight_region_r - None +struct weight_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR weight_region_r() : word0(0) {} + CONSTEXPR weight_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + weight_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR weight_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile weight_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// scale_region_r - None +struct scale_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR scale_region_r() : word0(0) {} + CONSTEXPR scale_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + scale_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR scale_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile scale_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ab_start_r - None +struct ab_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ab_start_r() : word0(0) {} + CONSTEXPR ab_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ab_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ab_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ab_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// blockdep_r - None +struct blockdep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR blockdep_r() : word0(0) {} + CONSTEXPR blockdep_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + blockdep_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR blockdep_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile blockdep_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_region_r - None +struct dma0_src_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_src_region_r() : word0(0) {} + CONSTEXPR dma0_src_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_src_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_src_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_src_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_dst_region_r - None +struct dma0_dst_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_dst_region_r() : word0(0) {} + CONSTEXPR dma0_dst_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_dst_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_dst_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_dst_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size0_r - None +struct dma0_size0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size0_r() : word0(0) {} + CONSTEXPR dma0_size0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size0_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size0_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size1_r - None +struct dma0_size1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size1_r() : word0(0) {} + CONSTEXPR dma0_size1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_broadcast_r - None +struct ifm2_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_broadcast_r() : word0(0) {} + CONSTEXPR ifm2_broadcast_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_broadcast_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_broadcast_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_broadcast_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_scalar_r - None +struct ifm2_scalar_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_scalar_r() : word0(0) {} + CONSTEXPR ifm2_scalar_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_scalar_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_scalar_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_scalar_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_precision_r - None +struct ifm2_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_precision_r() : word0(0) {} + CONSTEXPR ifm2_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_zero_point_r - None +struct ifm2_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_zero_point_r() : word0(0) {} + CONSTEXPR ifm2_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_width0_m1_r - None +struct ifm2_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_width0_m1_r() : word0(0) {} + CONSTEXPR ifm2_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height0_m1_r - None +struct ifm2_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height0_m1_r() : word0(0) {} + CONSTEXPR ifm2_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height1_m1_r - None +struct ifm2_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height1_m1_r() : word0(0) {} + CONSTEXPR ifm2_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_ib_start_r - None +struct ifm2_ib_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_ib_start_r() : word0(0) {} + CONSTEXPR ifm2_ib_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_ib_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_ib_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_ib_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_region_r - None +struct ifm2_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_region_r() : word0(0) {} + CONSTEXPR ifm2_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_base0_r - None +struct ifm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base1_r - None +struct ifm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base2_r - None +struct ifm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base3_r - None +struct ifm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_x_r - None +struct ifm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_y_r - None +struct ifm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_c_r - None +struct ifm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base0_r - None +struct ofm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base1_r - None +struct ofm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base2_r - None +struct ofm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base3_r - None +struct ofm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_x_r - None +struct ofm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_y_r - None +struct ofm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_c_r - None +struct ofm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_base_r - None +struct weight_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_base_r() : word0(0), word1(0) {} + CONSTEXPR weight_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_base_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_length_r - None +struct weight_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_length_r() : word0(0), word1(0) {} + CONSTEXPR weight_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_length_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_base_r - None +struct scale_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_base_r() : word0(0), word1(0) {} + CONSTEXPR scale_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_base_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_length_r - None +struct scale_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_length_r() : word0(0), word1(0) {} + CONSTEXPR scale_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_length_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_scale_r - None +struct ofm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_r() : word0(0) {} + CONSTEXPR ofm_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_scale_shift_r - None +struct ofm_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_shift_r() : word0(0) {} + CONSTEXPR ofm_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_r - None +struct opa_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_r() : word0(0) {} + CONSTEXPR opa_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_shift_r - None +struct opa_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_shift_r() : word0(0) {} + CONSTEXPR opa_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opb_scale_r - None +struct opb_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opb_scale_r() : word0(0) {} + CONSTEXPR opb_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opb_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opb_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opb_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_r - None +struct dma0_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_src_r() : word0(0), word1(0) {} + CONSTEXPR dma0_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_dst_r - None +struct dma0_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma0_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_len_r - None +struct dma0_len_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_len_r() : word0(0), word1(0) {} + CONSTEXPR dma0_len_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_len_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base0_r - None +struct ifm2_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base1_r - None +struct ifm2_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base2_r - None +struct ifm2_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base3_r - None +struct ifm2_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_x_r - None +struct ifm2_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_y_r - None +struct ifm2_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_c_r - None +struct ifm2_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// revision_r - Internal FPGA build revision: first 32-bits of the Ultan Git hash used for the build +struct revision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR revision_r() : word0(0) {} + CONSTEXPR revision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + revision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR revision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile revision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid4_r - Peripheral ID byte 4 (Arm=code 4) +struct pid4_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID4 : 32; // Byte 4 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid4_r() : word0(4) {} + CONSTEXPR pid4_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid4_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID4() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID4() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid4_r &set_PID4(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid4_r &set_PID4(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid5_r - Peripheral ID byte 5 (reserved) +struct pid5_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID5 : 32; // Byte 5 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid5_r() : word0(0) {} + CONSTEXPR pid5_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid5_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID5() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID5() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid5_r &set_PID5(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid5_r &set_PID5(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid6_r - Peripheral ID byte 6 (reserved) +struct pid6_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID6 : 32; // Byte 6 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid6_r() : word0(0) {} + CONSTEXPR pid6_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid6_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID6() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID6() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid6_r &set_PID6(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid6_r &set_PID6(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid7_r - Peripheral ID byte 7 (reserved) +struct pid7_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID7 : 32; // Byte 7 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid7_r() : word0(0) {} + CONSTEXPR pid7_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid7_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID7() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID7() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid7_r &set_PID7(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid7_r &set_PID7(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid0_r - Peripheral ID byte 0. This is bits[7:0] of the part number +struct pid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID0 : 32; // Byte 0 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid0_r() : word0(128) {} + CONSTEXPR pid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid0_r &set_PID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid0_r &set_PID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid1_r - Peripheral ID byte 1. This is bits[11:8] of the part number in bits[3:0], and bits[3:0] of the Arm ID in +// bits[7:4] +struct pid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID1 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid1_r() : word0(181) {} + CONSTEXPR pid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid1_r &set_PID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid1_r &set_PID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid2_r - Peripheral ID byte 2. This is bits[6:4] of the Arm ID in bits[2:0], and bit 3 indicates format B +struct pid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID2 : 32; // Byte 2 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid2_r() : word0(11) {} + CONSTEXPR pid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid2_r &set_PID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid2_r &set_PID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid3_r - Peripheral ID byte 3 +struct pid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID3 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid3_r() : word0(0) {} + CONSTEXPR pid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid3_r &set_PID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid3_r &set_PID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid0_r - Component ID byte 0 +struct cid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID0 : 32; // Byte 0 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid0_r() : word0(13) {} + CONSTEXPR cid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid0_r &set_CID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid0_r &set_CID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid1_r - Component ID byte 1 +struct cid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID1 : 32; // Byte 1 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid1_r() : word0(240) {} + CONSTEXPR cid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid1_r &set_CID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid1_r &set_CID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid2_r - Component ID byte 2 +struct cid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID2 : 32; // Byte 2 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid2_r() : word0(5) {} + CONSTEXPR cid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid2_r &set_CID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid2_r &set_CID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid3_r - Component ID byte 3 +struct cid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID3 : 32; // Byte 3 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid3_r() : word0(177) {} + CONSTEXPR cid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid3_r &set_CID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid3_r &set_CID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +struct NPU_REG +{ + STRUCT id_r ID; // 0x0000 + STRUCT status_r STATUS; // 0x0004 + STRUCT cmd_r CMD; // 0x0008 + STRUCT reset_r RESET; // 0x000C + STRUCT qbase_r QBASE; // 0x0010 + STRUCT qread_r QREAD; // 0x0018 + STRUCT qconfig_r QCONFIG; // 0x001C + STRUCT qsize_r QSIZE; // 0x0020 + STRUCT prot_r PROT; // 0x0024 + STRUCT config_r CONFIG; // 0x0028 + STRUCT lock_r LOCK; // 0x002C + uint32_t unused0[3]; + STRUCT regioncfg_r REGIONCFG; // 0x003C + STRUCT axi_limit0_r AXI_LIMIT0; // 0x0040 + STRUCT axi_limit1_r AXI_LIMIT1; // 0x0044 + STRUCT axi_limit2_r AXI_LIMIT2; // 0x0048 + STRUCT axi_limit3_r AXI_LIMIT3; // 0x004C + uint32_t unused1[12]; + STRUCT basep_r BASEP[8]; // 0x0080 + uint32_t unused2[16]; + STRUCT wd_status_r WD_STATUS; // 0x0100 + STRUCT mac_status_r MAC_STATUS; // 0x0104 + STRUCT ao_status_r AO_STATUS; // 0x0108 + uint32_t unused3[1]; + STRUCT dma_status0_r DMA_STATUS0; // 0x0110 + STRUCT dma_status1_r DMA_STATUS1; // 0x0114 + uint32_t unused4[10]; + STRUCT clkforce_r CLKFORCE; // 0x0140 + STRUCT debug_address_r DEBUG_ADDRESS; // 0x0144 + STRUCT debug_misc_r DEBUG_MISC; // 0x0148 + uint32_t unused5[1]; + STRUCT debug_block_r DEBUG_BLOCK; // 0x0150 + uint32_t unused6[11]; + STRUCT pmcr_r PMCR; // 0x0180 + STRUCT pmcntenset_r PMCNTENSET; // 0x0184 + STRUCT pmcntenclr_r PMCNTENCLR; // 0x0188 + STRUCT pmovsset_r PMOVSSET; // 0x018C + STRUCT pmovsclr_r PMOVSCLR; // 0x0190 + STRUCT pmintset_r PMINTSET; // 0x0194 + STRUCT pmintclr_r PMINTCLR; // 0x0198 + uint32_t unused7[1]; + STRUCT pmccntr_r PMCCNTR; // 0x01A0 + STRUCT pmccntr_cfg_r PMCCNTR_CFG; // 0x01A8 + STRUCT pmcaxi_chan_r PMCAXI_CHAN; // 0x01AC + uint32_t unused8[20]; + STRUCT kernel_x_r KERNEL_X; // 0x0200 + STRUCT kernel_y_r KERNEL_Y; // 0x0204 + STRUCT kernel_w_m1_r KERNEL_W_M1; // 0x0208 + STRUCT kernel_h_m1_r KERNEL_H_M1; // 0x020C + STRUCT ofm_cblk_width_m1_r OFM_CBLK_WIDTH_M1; // 0x0210 + STRUCT ofm_cblk_height_m1_r OFM_CBLK_HEIGHT_M1; // 0x0214 + STRUCT ofm_cblk_depth_m1_r OFM_CBLK_DEPTH_M1; // 0x0218 + STRUCT ifm_cblk_depth_m1_r IFM_CBLK_DEPTH_M1; // 0x021C + STRUCT ofm_x_r OFM_X; // 0x0220 + STRUCT ofm_y_r OFM_Y; // 0x0224 + STRUCT ofm_z_r OFM_Z; // 0x0228 + STRUCT ifm_z_r IFM_Z; // 0x022C + STRUCT pad_top_r PAD_TOP; // 0x0230 + STRUCT pad_left_r PAD_LEFT; // 0x0234 + STRUCT ifm_cblk_width_r IFM_CBLK_WIDTH; // 0x0238 + STRUCT ifm_cblk_height_r IFM_CBLK_HEIGHT; // 0x023C + STRUCT dma_ifm_src_r DMA_IFM_SRC; // 0x0240 + STRUCT dma_ifm_dst_r DMA_IFM_DST; // 0x0248 + STRUCT dma_ofm_src_r DMA_OFM_SRC; // 0x024C + STRUCT dma_ofm_dst_r DMA_OFM_DST; // 0x0250 + STRUCT dma_weight_src_r DMA_WEIGHT_SRC; // 0x0258 + STRUCT dma_cmd_src_r DMA_CMD_SRC; // 0x0260 + STRUCT dma_cmd_size_r DMA_CMD_SIZE; // 0x0268 + STRUCT dma_m2m_src_r DMA_M2M_SRC; // 0x026C + STRUCT dma_m2m_dst_r DMA_M2M_DST; // 0x0274 + STRUCT current_qread_r CURRENT_QREAD; // 0x027C + STRUCT dma_scale_src_r DMA_SCALE_SRC; // 0x0280 + uint32_t unused9[11]; + STRUCT current_block_r CURRENT_BLOCK; // 0x02B4 + STRUCT current_op_r CURRENT_OP; // 0x02B8 + STRUCT current_cmd_r CURRENT_CMD; // 0x02BC + uint32_t unused10[16]; + STRUCT pmevcntr_r PMEVCNTR[4]; // 0x0300 + uint32_t unused11[28]; + STRUCT pmevtyper_r PMEVTYPER[4]; // 0x0380 + uint32_t unused12[28]; + STRUCT shared_buffer_r SHARED_BUFFER[256]; // 0x0400 + STRUCT ifm_pad_top_r IFM_PAD_TOP; // 0x0800 + STRUCT ifm_pad_left_r IFM_PAD_LEFT; // 0x0804 + STRUCT ifm_pad_right_r IFM_PAD_RIGHT; // 0x0808 + STRUCT ifm_pad_bottom_r IFM_PAD_BOTTOM; // 0x080C + STRUCT ifm_depth_m1_r IFM_DEPTH_M1; // 0x0810 + STRUCT ifm_precision_r IFM_PRECISION; // 0x0814 + uint32_t unused13[1]; + STRUCT ifm_upscale_r IFM_UPSCALE; // 0x081C + uint32_t unused14[1]; + STRUCT ifm_zero_point_r IFM_ZERO_POINT; // 0x0824 + STRUCT ifm_width0_m1_r IFM_WIDTH0_M1; // 0x0828 + STRUCT ifm_height0_m1_r IFM_HEIGHT0_M1; // 0x082C + STRUCT ifm_height1_m1_r IFM_HEIGHT1_M1; // 0x0830 + STRUCT ifm_ib_end_r IFM_IB_END; // 0x0834 + uint32_t unused15[1]; + STRUCT ifm_region_r IFM_REGION; // 0x083C + uint32_t unused16[1]; + STRUCT ofm_width_m1_r OFM_WIDTH_M1; // 0x0844 + STRUCT ofm_height_m1_r OFM_HEIGHT_M1; // 0x0848 + STRUCT ofm_depth_m1_r OFM_DEPTH_M1; // 0x084C + STRUCT ofm_precision_r OFM_PRECISION; // 0x0850 + STRUCT ofm_blk_width_m1_r OFM_BLK_WIDTH_M1; // 0x0854 + STRUCT ofm_blk_height_m1_r OFM_BLK_HEIGHT_M1; // 0x0858 + STRUCT ofm_blk_depth_m1_r OFM_BLK_DEPTH_M1; // 0x085C + STRUCT ofm_zero_point_r OFM_ZERO_POINT; // 0x0860 + uint32_t unused17[1]; + STRUCT ofm_width0_m1_r OFM_WIDTH0_M1; // 0x0868 + STRUCT ofm_height0_m1_r OFM_HEIGHT0_M1; // 0x086C + STRUCT ofm_height1_m1_r OFM_HEIGHT1_M1; // 0x0870 + uint32_t unused18[2]; + STRUCT ofm_region_r OFM_REGION; // 0x087C + STRUCT kernel_width_m1_r KERNEL_WIDTH_M1; // 0x0880 + STRUCT kernel_height_m1_r KERNEL_HEIGHT_M1; // 0x0884 + STRUCT kernel_stride_r KERNEL_STRIDE; // 0x0888 + uint32_t unused19[1]; + STRUCT acc_format_r ACC_FORMAT; // 0x0890 + STRUCT activation_r ACTIVATION; // 0x0894 + STRUCT activation_min_r ACTIVATION_MIN; // 0x0898 + STRUCT activation_max_r ACTIVATION_MAX; // 0x089C + STRUCT weight_region_r WEIGHT_REGION; // 0x08A0 + STRUCT scale_region_r SCALE_REGION; // 0x08A4 + uint32_t unused20[3]; + STRUCT ab_start_r AB_START; // 0x08B4 + uint32_t unused21[1]; + STRUCT blockdep_r BLOCKDEP; // 0x08BC + STRUCT dma0_src_region_r DMA0_SRC_REGION; // 0x08C0 + STRUCT dma0_dst_region_r DMA0_DST_REGION; // 0x08C4 + STRUCT dma0_size0_r DMA0_SIZE0; // 0x08C8 + STRUCT dma0_size1_r DMA0_SIZE1; // 0x08CC + uint32_t unused22[12]; + STRUCT ifm2_broadcast_r IFM2_BROADCAST; // 0x0900 + STRUCT ifm2_scalar_r IFM2_SCALAR; // 0x0904 + uint32_t unused23[3]; + STRUCT ifm2_precision_r IFM2_PRECISION; // 0x0914 + uint32_t unused24[3]; + STRUCT ifm2_zero_point_r IFM2_ZERO_POINT; // 0x0924 + STRUCT ifm2_width0_m1_r IFM2_WIDTH0_M1; // 0x0928 + STRUCT ifm2_height0_m1_r IFM2_HEIGHT0_M1; // 0x092C + STRUCT ifm2_height1_m1_r IFM2_HEIGHT1_M1; // 0x0930 + STRUCT ifm2_ib_start_r IFM2_IB_START; // 0x0934 + uint32_t unused25[1]; + STRUCT ifm2_region_r IFM2_REGION; // 0x093C + uint32_t unused26[48]; + STRUCT ifm_base0_r IFM_BASE0; // 0x0A00 + STRUCT ifm_base1_r IFM_BASE1; // 0x0A08 + STRUCT ifm_base2_r IFM_BASE2; // 0x0A10 + STRUCT ifm_base3_r IFM_BASE3; // 0x0A18 + STRUCT ifm_stride_x_r IFM_STRIDE_X; // 0x0A20 + STRUCT ifm_stride_y_r IFM_STRIDE_Y; // 0x0A28 + STRUCT ifm_stride_c_r IFM_STRIDE_C; // 0x0A30 + uint32_t unused27[2]; + STRUCT ofm_base0_r OFM_BASE0; // 0x0A40 + STRUCT ofm_base1_r OFM_BASE1; // 0x0A48 + STRUCT ofm_base2_r OFM_BASE2; // 0x0A50 + STRUCT ofm_base3_r OFM_BASE3; // 0x0A58 + STRUCT ofm_stride_x_r OFM_STRIDE_X; // 0x0A60 + STRUCT ofm_stride_y_r OFM_STRIDE_Y; // 0x0A68 + STRUCT ofm_stride_c_r OFM_STRIDE_C; // 0x0A70 + uint32_t unused28[2]; + STRUCT weight_base_r WEIGHT_BASE; // 0x0A80 + STRUCT weight_length_r WEIGHT_LENGTH; // 0x0A88 + STRUCT scale_base_r SCALE_BASE; // 0x0A90 + STRUCT scale_length_r SCALE_LENGTH; // 0x0A98 + STRUCT ofm_scale_r OFM_SCALE; // 0x0AA0 + STRUCT ofm_scale_shift_r OFM_SCALE_SHIFT; // 0x0AA4 + STRUCT opa_scale_r OPA_SCALE; // 0x0AA8 + STRUCT opa_scale_shift_r OPA_SCALE_SHIFT; // 0x0AAC + STRUCT opb_scale_r OPB_SCALE; // 0x0AB0 + uint32_t unused29[3]; + STRUCT dma0_src_r DMA0_SRC; // 0x0AC0 + STRUCT dma0_dst_r DMA0_DST; // 0x0AC8 + STRUCT dma0_len_r DMA0_LEN; // 0x0AD0 + uint32_t unused30[10]; + STRUCT ifm2_base0_r IFM2_BASE0; // 0x0B00 + STRUCT ifm2_base1_r IFM2_BASE1; // 0x0B08 + STRUCT ifm2_base2_r IFM2_BASE2; // 0x0B10 + STRUCT ifm2_base3_r IFM2_BASE3; // 0x0B18 + STRUCT ifm2_stride_x_r IFM2_STRIDE_X; // 0x0B20 + STRUCT ifm2_stride_y_r IFM2_STRIDE_Y; // 0x0B28 + STRUCT ifm2_stride_c_r IFM2_STRIDE_C; // 0x0B30 + uint32_t unused31[18]; + uint32_t USER_DEFINED[16]; // 0x0B80 + uint32_t unused32[256]; + STRUCT revision_r REVISION; // 0x0FC0 + uint32_t unused33[3]; + STRUCT pid4_r PID4; // 0x0FD0 + STRUCT pid5_r PID5; // 0x0FD4 + STRUCT pid6_r PID6; // 0x0FD8 + STRUCT pid7_r PID7; // 0x0FDC + STRUCT pid0_r PID0; // 0x0FE0 + STRUCT pid1_r PID1; // 0x0FE4 + STRUCT pid2_r PID2; // 0x0FE8 + STRUCT pid3_r PID3; // 0x0FEC + STRUCT cid0_r CID0; // 0x0FF0 + STRUCT cid1_r CID1; // 0x0FF4 + STRUCT cid2_r CID2; // 0x0FF8 + STRUCT cid3_r CID3; // 0x0FFC + +#ifdef __cplusplus + enum class access_type_t : uint8_t + { + RW, + RO, + WO + }; + NPU_REG() + { + reset(); + } + void reset() + { + ID = 269500929; + STATUS = 8; + CMD = 12; + RESET = 0; + QBASE = 0; + QREAD = 0; + QCONFIG = 0; + QSIZE = 0; + PROT = 0; + CONFIG = 0; + LOCK = 0; + REGIONCFG = 0; + AXI_LIMIT0 = 0; + AXI_LIMIT1 = 0; + AXI_LIMIT2 = 0; + AXI_LIMIT3 = 0; + for (size_t i = 0; i < (sizeof(BASEP) / sizeof(BASEP[0])); ++i) + BASEP[i] = 0; + WD_STATUS = 0; + MAC_STATUS = 0; + AO_STATUS = 0; + DMA_STATUS0 = 0; + DMA_STATUS1 = 0; + CLKFORCE = 0; + DEBUG_ADDRESS = 0; + DEBUG_MISC = 0; + DEBUG_BLOCK = 0; + PMCR = 8192; + PMCNTENSET = 0; + PMCNTENCLR = 0; + PMOVSSET = 0; + PMOVSCLR = 0; + PMINTSET = 0; + PMINTCLR = 0; + PMCCNTR = 0; + PMCCNTR_CFG = 0; + PMCAXI_CHAN = 0; + KERNEL_X = 0; + KERNEL_Y = 0; + KERNEL_W_M1 = 0; + KERNEL_H_M1 = 0; + OFM_CBLK_WIDTH_M1 = 0; + OFM_CBLK_HEIGHT_M1 = 0; + OFM_CBLK_DEPTH_M1 = 0; + IFM_CBLK_DEPTH_M1 = 0; + OFM_X = 0; + OFM_Y = 0; + OFM_Z = 0; + IFM_Z = 0; + PAD_TOP = 0; + PAD_LEFT = 0; + IFM_CBLK_WIDTH = 0; + IFM_CBLK_HEIGHT = 0; + DMA_IFM_SRC = 0; + DMA_IFM_DST = 0; + DMA_OFM_SRC = 0; + DMA_OFM_DST = 0; + DMA_WEIGHT_SRC = 0; + DMA_CMD_SRC = 0; + DMA_CMD_SIZE = 0; + DMA_M2M_SRC = 0; + DMA_M2M_DST = 0; + CURRENT_QREAD = 0; + DMA_SCALE_SRC = 0; + CURRENT_BLOCK = 0; + CURRENT_OP = 0; + CURRENT_CMD = 0; + for (size_t i = 0; i < (sizeof(PMEVCNTR) / sizeof(PMEVCNTR[0])); ++i) + PMEVCNTR[i] = 0; + for (size_t i = 0; i < (sizeof(PMEVTYPER) / sizeof(PMEVTYPER[0])); ++i) + PMEVTYPER[i] = 0; + for (size_t i = 0; i < (sizeof(SHARED_BUFFER) / sizeof(SHARED_BUFFER[0])); ++i) + SHARED_BUFFER[i] = 0; + IFM_PAD_TOP = 0; + IFM_PAD_LEFT = 0; + IFM_PAD_RIGHT = 0; + IFM_PAD_BOTTOM = 0; + IFM_DEPTH_M1 = 0; + IFM_PRECISION = 0; + IFM_UPSCALE = 0; + IFM_ZERO_POINT = 0; + IFM_WIDTH0_M1 = 0; + IFM_HEIGHT0_M1 = 0; + IFM_HEIGHT1_M1 = 0; + IFM_IB_END = 0; + IFM_REGION = 0; + OFM_WIDTH_M1 = 0; + OFM_HEIGHT_M1 = 0; + OFM_DEPTH_M1 = 0; + OFM_PRECISION = 0; + OFM_BLK_WIDTH_M1 = 0; + OFM_BLK_HEIGHT_M1 = 0; + OFM_BLK_DEPTH_M1 = 0; + OFM_ZERO_POINT = 0; + OFM_WIDTH0_M1 = 0; + OFM_HEIGHT0_M1 = 0; + OFM_HEIGHT1_M1 = 0; + OFM_REGION = 0; + KERNEL_WIDTH_M1 = 0; + KERNEL_HEIGHT_M1 = 0; + KERNEL_STRIDE = 0; + ACC_FORMAT = 0; + ACTIVATION = 0; + ACTIVATION_MIN = 0; + ACTIVATION_MAX = 0; + WEIGHT_REGION = 0; + SCALE_REGION = 0; + AB_START = 0; + BLOCKDEP = 0; + DMA0_SRC_REGION = 0; + DMA0_DST_REGION = 0; + DMA0_SIZE0 = 0; + DMA0_SIZE1 = 0; + IFM2_BROADCAST = 0; + IFM2_SCALAR = 0; + IFM2_PRECISION = 0; + IFM2_ZERO_POINT = 0; + IFM2_WIDTH0_M1 = 0; + IFM2_HEIGHT0_M1 = 0; + IFM2_HEIGHT1_M1 = 0; + IFM2_IB_START = 0; + IFM2_REGION = 0; + IFM_BASE0 = 0; + IFM_BASE1 = 0; + IFM_BASE2 = 0; + IFM_BASE3 = 0; + IFM_STRIDE_X = 0; + IFM_STRIDE_Y = 0; + IFM_STRIDE_C = 0; + OFM_BASE0 = 0; + OFM_BASE1 = 0; + OFM_BASE2 = 0; + OFM_BASE3 = 0; + OFM_STRIDE_X = 0; + OFM_STRIDE_Y = 0; + OFM_STRIDE_C = 0; + WEIGHT_BASE = 0; + WEIGHT_LENGTH = 0; + SCALE_BASE = 0; + SCALE_LENGTH = 0; + OFM_SCALE = 0; + OFM_SCALE_SHIFT = 0; + OPA_SCALE = 0; + OPA_SCALE_SHIFT = 0; + OPB_SCALE = 0; + DMA0_SRC = 0; + DMA0_DST = 0; + DMA0_LEN = 0; + IFM2_BASE0 = 0; + IFM2_BASE1 = 0; + IFM2_BASE2 = 0; + IFM2_BASE3 = 0; + IFM2_STRIDE_X = 0; + IFM2_STRIDE_Y = 0; + IFM2_STRIDE_C = 0; + for (size_t i = 0; i < (sizeof(USER_DEFINED) / sizeof(USER_DEFINED[0])); ++i) + USER_DEFINED[i] = 0; + REVISION = 0; + PID4 = 4; + PID5 = 0; + PID6 = 0; + PID7 = 0; + PID0 = 128; + PID1 = 181; + PID2 = 11; + PID3 = 0; + CID0 = 13; + CID1 = 240; + CID2 = 5; + CID3 = 177; + } + uint32_t &operator[](const int addr_offset) + { + return reinterpret_cast(this)[addr_offset / 4]; + } + access_type_t get_access_type(uint32_t offset) + { + switch (offset) + { + case 0: + return access_type_t::RO; + case 4: + return access_type_t::RO; + case 8: + return access_type_t::RW; + case 12: + return access_type_t::RW; + case 16: + return access_type_t::RW; + case 24: + return access_type_t::RO; + case 28: + return access_type_t::RW; + case 32: + return access_type_t::RW; + case 36: + return access_type_t::RO; + case 40: + return access_type_t::RO; + case 44: + return access_type_t::RW; + case 60: + return access_type_t::RW; + case 64: + return access_type_t::RW; + case 68: + return access_type_t::RW; + case 72: + return access_type_t::RW; + case 76: + return access_type_t::RW; + case 128: + return access_type_t::RW; + case 136: + return access_type_t::RW; + case 144: + return access_type_t::RW; + case 152: + return access_type_t::RW; + case 160: + return access_type_t::RW; + case 168: + return access_type_t::RW; + case 176: + return access_type_t::RW; + case 184: + return access_type_t::RW; + case 256: + return access_type_t::RO; + case 260: + return access_type_t::RO; + case 264: + return access_type_t::RO; + case 272: + return access_type_t::RO; + case 276: + return access_type_t::RO; + case 320: + return access_type_t::RW; + case 324: + return access_type_t::RW; + case 328: + return access_type_t::RW; + case 336: + return access_type_t::RW; + case 384: + return access_type_t::RW; + case 388: + return access_type_t::RW; + case 392: + return access_type_t::RW; + case 396: + return access_type_t::RW; + case 400: + return access_type_t::RW; + case 404: + return access_type_t::RW; + case 408: + return access_type_t::RW; + case 416: + return access_type_t::RW; + case 424: + return access_type_t::RW; + case 428: + return access_type_t::RW; + case 512: + return access_type_t::RO; + case 516: + return access_type_t::RO; + case 520: + return access_type_t::RO; + case 524: + return access_type_t::RO; + case 528: + return access_type_t::RO; + case 532: + return access_type_t::RO; + case 536: + return access_type_t::RO; + case 540: + return access_type_t::RO; + case 544: + return access_type_t::RO; + case 548: + return access_type_t::RO; + case 552: + return access_type_t::RO; + case 556: + return access_type_t::RO; + case 560: + return access_type_t::RO; + case 564: + return access_type_t::RO; + case 568: + return access_type_t::RO; + case 572: + return access_type_t::RO; + case 576: + return access_type_t::RO; + case 584: + return access_type_t::RO; + case 588: + return access_type_t::RO; + case 592: + return access_type_t::RO; + case 600: + return access_type_t::RO; + case 608: + return access_type_t::RO; + case 616: + return access_type_t::RO; + case 620: + return access_type_t::RO; + case 628: + return access_type_t::RO; + case 636: + return access_type_t::RO; + case 640: + return access_type_t::RO; + case 692: + return access_type_t::RO; + case 696: + return access_type_t::RO; + case 700: + return access_type_t::RO; + case 768: + return access_type_t::RW; + case 772: + return access_type_t::RW; + case 776: + return access_type_t::RW; + case 780: + return access_type_t::RW; + case 896: + return access_type_t::RW; + case 900: + return access_type_t::RW; + case 904: + return access_type_t::RW; + case 908: + return access_type_t::RW; + case 1024: + return access_type_t::RW; + case 1028: + return access_type_t::RW; + case 1032: + return access_type_t::RW; + case 1036: + return access_type_t::RW; + case 1040: + return access_type_t::RW; + case 1044: + return access_type_t::RW; + case 1048: + return access_type_t::RW; + case 1052: + return access_type_t::RW; + case 1056: + return access_type_t::RW; + case 1060: + return access_type_t::RW; + case 1064: + return access_type_t::RW; + case 1068: + return access_type_t::RW; + case 1072: + return access_type_t::RW; + case 1076: + return access_type_t::RW; + case 1080: + return access_type_t::RW; + case 1084: + return access_type_t::RW; + case 1088: + return access_type_t::RW; + case 1092: + return access_type_t::RW; + case 1096: + return access_type_t::RW; + case 1100: + return access_type_t::RW; + case 1104: + return access_type_t::RW; + case 1108: + return access_type_t::RW; + case 1112: + return access_type_t::RW; + case 1116: + return access_type_t::RW; + case 1120: + return access_type_t::RW; + case 1124: + return access_type_t::RW; + case 1128: + return access_type_t::RW; + case 1132: + return access_type_t::RW; + case 1136: + return access_type_t::RW; + case 1140: + return access_type_t::RW; + case 1144: + return access_type_t::RW; + case 1148: + return access_type_t::RW; + case 1152: + return access_type_t::RW; + case 1156: + return access_type_t::RW; + case 1160: + return access_type_t::RW; + case 1164: + return access_type_t::RW; + case 1168: + return access_type_t::RW; + case 1172: + return access_type_t::RW; + case 1176: + return access_type_t::RW; + case 1180: + return access_type_t::RW; + case 1184: + return access_type_t::RW; + case 1188: + return access_type_t::RW; + case 1192: + return access_type_t::RW; + case 1196: + return access_type_t::RW; + case 1200: + return access_type_t::RW; + case 1204: + return access_type_t::RW; + case 1208: + return access_type_t::RW; + case 1212: + return access_type_t::RW; + case 1216: + return access_type_t::RW; + case 1220: + return access_type_t::RW; + case 1224: + return access_type_t::RW; + case 1228: + return access_type_t::RW; + case 1232: + return access_type_t::RW; + case 1236: + return access_type_t::RW; + case 1240: + return access_type_t::RW; + case 1244: + return access_type_t::RW; + case 1248: + return access_type_t::RW; + case 1252: + return access_type_t::RW; + case 1256: + return access_type_t::RW; + case 1260: + return access_type_t::RW; + case 1264: + return access_type_t::RW; + case 1268: + return access_type_t::RW; + case 1272: + return access_type_t::RW; + case 1276: + return access_type_t::RW; + case 1280: + return access_type_t::RW; + case 1284: + return access_type_t::RW; + case 1288: + return access_type_t::RW; + case 1292: + return access_type_t::RW; + case 1296: + return access_type_t::RW; + case 1300: + return access_type_t::RW; + case 1304: + return access_type_t::RW; + case 1308: + return access_type_t::RW; + case 1312: + return access_type_t::RW; + case 1316: + return access_type_t::RW; + case 1320: + return access_type_t::RW; + case 1324: + return access_type_t::RW; + case 1328: + return access_type_t::RW; + case 1332: + return access_type_t::RW; + case 1336: + return access_type_t::RW; + case 1340: + return access_type_t::RW; + case 1344: + return access_type_t::RW; + case 1348: + return access_type_t::RW; + case 1352: + return access_type_t::RW; + case 1356: + return access_type_t::RW; + case 1360: + return access_type_t::RW; + case 1364: + return access_type_t::RW; + case 1368: + return access_type_t::RW; + case 1372: + return access_type_t::RW; + case 1376: + return access_type_t::RW; + case 1380: + return access_type_t::RW; + case 1384: + return access_type_t::RW; + case 1388: + return access_type_t::RW; + case 1392: + return access_type_t::RW; + case 1396: + return access_type_t::RW; + case 1400: + return access_type_t::RW; + case 1404: + return access_type_t::RW; + case 1408: + return access_type_t::RW; + case 1412: + return access_type_t::RW; + case 1416: + return access_type_t::RW; + case 1420: + return access_type_t::RW; + case 1424: + return access_type_t::RW; + case 1428: + return access_type_t::RW; + case 1432: + return access_type_t::RW; + case 1436: + return access_type_t::RW; + case 1440: + return access_type_t::RW; + case 1444: + return access_type_t::RW; + case 1448: + return access_type_t::RW; + case 1452: + return access_type_t::RW; + case 1456: + return access_type_t::RW; + case 1460: + return access_type_t::RW; + case 1464: + return access_type_t::RW; + case 1468: + return access_type_t::RW; + case 1472: + return access_type_t::RW; + case 1476: + return access_type_t::RW; + case 1480: + return access_type_t::RW; + case 1484: + return access_type_t::RW; + case 1488: + return access_type_t::RW; + case 1492: + return access_type_t::RW; + case 1496: + return access_type_t::RW; + case 1500: + return access_type_t::RW; + case 1504: + return access_type_t::RW; + case 1508: + return access_type_t::RW; + case 1512: + return access_type_t::RW; + case 1516: + return access_type_t::RW; + case 1520: + return access_type_t::RW; + case 1524: + return access_type_t::RW; + case 1528: + return access_type_t::RW; + case 1532: + return access_type_t::RW; + case 1536: + return access_type_t::RW; + case 1540: + return access_type_t::RW; + case 1544: + return access_type_t::RW; + case 1548: + return access_type_t::RW; + case 1552: + return access_type_t::RW; + case 1556: + return access_type_t::RW; + case 1560: + return access_type_t::RW; + case 1564: + return access_type_t::RW; + case 1568: + return access_type_t::RW; + case 1572: + return access_type_t::RW; + case 1576: + return access_type_t::RW; + case 1580: + return access_type_t::RW; + case 1584: + return access_type_t::RW; + case 1588: + return access_type_t::RW; + case 1592: + return access_type_t::RW; + case 1596: + return access_type_t::RW; + case 1600: + return access_type_t::RW; + case 1604: + return access_type_t::RW; + case 1608: + return access_type_t::RW; + case 1612: + return access_type_t::RW; + case 1616: + return access_type_t::RW; + case 1620: + return access_type_t::RW; + case 1624: + return access_type_t::RW; + case 1628: + return access_type_t::RW; + case 1632: + return access_type_t::RW; + case 1636: + return access_type_t::RW; + case 1640: + return access_type_t::RW; + case 1644: + return access_type_t::RW; + case 1648: + return access_type_t::RW; + case 1652: + return access_type_t::RW; + case 1656: + return access_type_t::RW; + case 1660: + return access_type_t::RW; + case 1664: + return access_type_t::RW; + case 1668: + return access_type_t::RW; + case 1672: + return access_type_t::RW; + case 1676: + return access_type_t::RW; + case 1680: + return access_type_t::RW; + case 1684: + return access_type_t::RW; + case 1688: + return access_type_t::RW; + case 1692: + return access_type_t::RW; + case 1696: + return access_type_t::RW; + case 1700: + return access_type_t::RW; + case 1704: + return access_type_t::RW; + case 1708: + return access_type_t::RW; + case 1712: + return access_type_t::RW; + case 1716: + return access_type_t::RW; + case 1720: + return access_type_t::RW; + case 1724: + return access_type_t::RW; + case 1728: + return access_type_t::RW; + case 1732: + return access_type_t::RW; + case 1736: + return access_type_t::RW; + case 1740: + return access_type_t::RW; + case 1744: + return access_type_t::RW; + case 1748: + return access_type_t::RW; + case 1752: + return access_type_t::RW; + case 1756: + return access_type_t::RW; + case 1760: + return access_type_t::RW; + case 1764: + return access_type_t::RW; + case 1768: + return access_type_t::RW; + case 1772: + return access_type_t::RW; + case 1776: + return access_type_t::RW; + case 1780: + return access_type_t::RW; + case 1784: + return access_type_t::RW; + case 1788: + return access_type_t::RW; + case 1792: + return access_type_t::RW; + case 1796: + return access_type_t::RW; + case 1800: + return access_type_t::RW; + case 1804: + return access_type_t::RW; + case 1808: + return access_type_t::RW; + case 1812: + return access_type_t::RW; + case 1816: + return access_type_t::RW; + case 1820: + return access_type_t::RW; + case 1824: + return access_type_t::RW; + case 1828: + return access_type_t::RW; + case 1832: + return access_type_t::RW; + case 1836: + return access_type_t::RW; + case 1840: + return access_type_t::RW; + case 1844: + return access_type_t::RW; + case 1848: + return access_type_t::RW; + case 1852: + return access_type_t::RW; + case 1856: + return access_type_t::RW; + case 1860: + return access_type_t::RW; + case 1864: + return access_type_t::RW; + case 1868: + return access_type_t::RW; + case 1872: + return access_type_t::RW; + case 1876: + return access_type_t::RW; + case 1880: + return access_type_t::RW; + case 1884: + return access_type_t::RW; + case 1888: + return access_type_t::RW; + case 1892: + return access_type_t::RW; + case 1896: + return access_type_t::RW; + case 1900: + return access_type_t::RW; + case 1904: + return access_type_t::RW; + case 1908: + return access_type_t::RW; + case 1912: + return access_type_t::RW; + case 1916: + return access_type_t::RW; + case 1920: + return access_type_t::RW; + case 1924: + return access_type_t::RW; + case 1928: + return access_type_t::RW; + case 1932: + return access_type_t::RW; + case 1936: + return access_type_t::RW; + case 1940: + return access_type_t::RW; + case 1944: + return access_type_t::RW; + case 1948: + return access_type_t::RW; + case 1952: + return access_type_t::RW; + case 1956: + return access_type_t::RW; + case 1960: + return access_type_t::RW; + case 1964: + return access_type_t::RW; + case 1968: + return access_type_t::RW; + case 1972: + return access_type_t::RW; + case 1976: + return access_type_t::RW; + case 1980: + return access_type_t::RW; + case 1984: + return access_type_t::RW; + case 1988: + return access_type_t::RW; + case 1992: + return access_type_t::RW; + case 1996: + return access_type_t::RW; + case 2000: + return access_type_t::RW; + case 2004: + return access_type_t::RW; + case 2008: + return access_type_t::RW; + case 2012: + return access_type_t::RW; + case 2016: + return access_type_t::RW; + case 2020: + return access_type_t::RW; + case 2024: + return access_type_t::RW; + case 2028: + return access_type_t::RW; + case 2032: + return access_type_t::RW; + case 2036: + return access_type_t::RW; + case 2040: + return access_type_t::RW; + case 2044: + return access_type_t::RW; + case 2048: + return access_type_t::RW; + case 2052: + return access_type_t::RW; + case 2056: + return access_type_t::RW; + case 2060: + return access_type_t::RW; + case 2064: + return access_type_t::RW; + case 2068: + return access_type_t::RW; + case 2076: + return access_type_t::RW; + case 2084: + return access_type_t::RW; + case 2088: + return access_type_t::RW; + case 2092: + return access_type_t::RW; + case 2096: + return access_type_t::RW; + case 2100: + return access_type_t::RW; + case 2108: + return access_type_t::RW; + case 2116: + return access_type_t::RW; + case 2120: + return access_type_t::RW; + case 2124: + return access_type_t::RW; + case 2128: + return access_type_t::RW; + case 2132: + return access_type_t::RW; + case 2136: + return access_type_t::RW; + case 2140: + return access_type_t::RW; + case 2144: + return access_type_t::RW; + case 2152: + return access_type_t::RW; + case 2156: + return access_type_t::RW; + case 2160: + return access_type_t::RW; + case 2172: + return access_type_t::RW; + case 2176: + return access_type_t::RW; + case 2180: + return access_type_t::RW; + case 2184: + return access_type_t::RW; + case 2192: + return access_type_t::RW; + case 2196: + return access_type_t::RW; + case 2200: + return access_type_t::RW; + case 2204: + return access_type_t::RW; + case 2208: + return access_type_t::RW; + case 2212: + return access_type_t::RW; + case 2228: + return access_type_t::RW; + case 2236: + return access_type_t::RW; + case 2240: + return access_type_t::RW; + case 2244: + return access_type_t::RW; + case 2248: + return access_type_t::RW; + case 2252: + return access_type_t::RW; + case 2304: + return access_type_t::RW; + case 2308: + return access_type_t::RW; + case 2324: + return access_type_t::RW; + case 2340: + return access_type_t::RW; + case 2344: + return access_type_t::RW; + case 2348: + return access_type_t::RW; + case 2352: + return access_type_t::RW; + case 2356: + return access_type_t::RW; + case 2364: + return access_type_t::RW; + case 2560: + return access_type_t::RW; + case 2568: + return access_type_t::RW; + case 2576: + return access_type_t::RW; + case 2584: + return access_type_t::RW; + case 2592: + return access_type_t::RW; + case 2600: + return access_type_t::RW; + case 2608: + return access_type_t::RW; + case 2624: + return access_type_t::RW; + case 2632: + return access_type_t::RW; + case 2640: + return access_type_t::RW; + case 2648: + return access_type_t::RW; + case 2656: + return access_type_t::RW; + case 2664: + return access_type_t::RW; + case 2672: + return access_type_t::RW; + case 2688: + return access_type_t::RW; + case 2696: + return access_type_t::RW; + case 2704: + return access_type_t::RW; + case 2712: + return access_type_t::RW; + case 2720: + return access_type_t::RW; + case 2724: + return access_type_t::RW; + case 2728: + return access_type_t::RW; + case 2732: + return access_type_t::RW; + case 2736: + return access_type_t::RW; + case 2752: + return access_type_t::RW; + case 2760: + return access_type_t::RW; + case 2768: + return access_type_t::RW; + case 2816: + return access_type_t::RW; + case 2824: + return access_type_t::RW; + case 2832: + return access_type_t::RW; + case 2840: + return access_type_t::RW; + case 2848: + return access_type_t::RW; + case 2856: + return access_type_t::RW; + case 2864: + return access_type_t::RW; + case 2944: + return access_type_t::RW; + case 2952: + return access_type_t::RW; + case 2960: + return access_type_t::RW; + case 2968: + return access_type_t::RW; + case 2976: + return access_type_t::RW; + case 2984: + return access_type_t::RW; + case 2992: + return access_type_t::RW; + case 3000: + return access_type_t::RW; + case 4032: + return access_type_t::RO; + case 4048: + return access_type_t::RO; + case 4052: + return access_type_t::RO; + case 4056: + return access_type_t::RO; + case 4060: + return access_type_t::RO; + case 4064: + return access_type_t::RO; + case 4068: + return access_type_t::RO; + case 4072: + return access_type_t::RO; + case 4076: + return access_type_t::RO; + case 4080: + return access_type_t::RO; + case 4084: + return access_type_t::RO; + case 4088: + return access_type_t::RO; + case 4092: + return access_type_t::RO; + default: + return access_type_t::RO; + } + } +#endif +}; + +#ifdef __cplusplus +struct isa +{ +#ifdef NPU_DISASSEMBLE + static int disassemble(const uint32_t *in, + std::string &op, + std::vector> &fields) + { + switch (*in & 0xffff) + { + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP): + { + const npu_op_stop_t &v = *reinterpret_cast(in); + op = "NPU_OP_STOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ): + { + const npu_op_irq_t &v = *reinterpret_cast(in); + op = "NPU_OP_IRQ"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV): + { + const npu_op_conv_t &v = *reinterpret_cast(in); + op = "NPU_OP_CONV"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE): + { + const npu_op_depthwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_DEPTHWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL): + { + const npu_op_pool_t &v = *reinterpret_cast(in); + op = "NPU_OP_POOL"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE): + { + const npu_op_elementwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_ELEMENTWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START): + { + const npu_op_dma_start_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT): + { + const npu_op_dma_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT): + { + const npu_op_kernel_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_KERNEL_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK): + { + const npu_op_pmu_mask_t &v = *reinterpret_cast(in); + op = "NPU_OP_PMU_MASK"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP): + { + const npu_set_ifm_pad_top_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_TOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT): + { + const npu_set_ifm_pad_left_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_LEFT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT): + { + const npu_set_ifm_pad_right_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_RIGHT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM): + { + const npu_set_ifm_pad_bottom_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_BOTTOM"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1): + { + const npu_set_ifm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION): + { + const npu_set_ifm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE): + { + const npu_set_ifm_upscale_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_UPSCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT): + { + const npu_set_ifm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1): + { + const npu_set_ifm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1): + { + const npu_set_ifm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1): + { + const npu_set_ifm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END): + { + const npu_set_ifm_ib_end_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_IB_END"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION): + { + const npu_set_ifm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1): + { + const npu_set_ofm_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1): + { + const npu_set_ofm_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1): + { + const npu_set_ofm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION): + { + const npu_set_ofm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1): + { + const npu_set_ofm_blk_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1): + { + const npu_set_ofm_blk_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1): + { + const npu_set_ofm_blk_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT): + { + const npu_set_ofm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1): + { + const npu_set_ofm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1): + { + const npu_set_ofm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1): + { + const npu_set_ofm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION): + { + const npu_set_ofm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1): + { + const npu_set_kernel_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1): + { + const npu_set_kernel_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE): + { + const npu_set_kernel_stride_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_STRIDE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT): + { + const npu_set_acc_format_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACC_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION): + { + const npu_set_activation_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN): + { + const npu_set_activation_min_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MIN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX): + { + const npu_set_activation_max_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION): + { + const npu_set_weight_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION): + { + const npu_set_scale_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START): + { + const npu_set_ab_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_AB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP): + { + const npu_set_blockdep_t &v = *reinterpret_cast(in); + op = "NPU_SET_BLOCKDEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION): + { + const npu_set_dma0_src_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION): + { + const npu_set_dma0_dst_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0): + { + const npu_set_dma0_size0_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1): + { + const npu_set_dma0_size1_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST): + { + const npu_set_ifm2_broadcast_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR): + { + const npu_set_ifm2_scalar_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_SCALAR"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION): + { + const npu_set_ifm2_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT): + { + const npu_set_ifm2_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1): + { + const npu_set_ifm2_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1): + { + const npu_set_ifm2_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1): + { + const npu_set_ifm2_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START): + { + const npu_set_ifm2_ib_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_IB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION): + { + const npu_set_ifm2_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0): + { + const npu_set_ifm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1): + { + const npu_set_ifm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2): + { + const npu_set_ifm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3): + { + const npu_set_ifm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X): + { + const npu_set_ifm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y): + { + const npu_set_ifm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C): + { + const npu_set_ifm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0): + { + const npu_set_ofm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1): + { + const npu_set_ofm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2): + { + const npu_set_ofm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3): + { + const npu_set_ofm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X): + { + const npu_set_ofm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y): + { + const npu_set_ofm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C): + { + const npu_set_ofm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE): + { + const npu_set_weight_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH): + { + const npu_set_weight_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE): + { + const npu_set_scale_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH): + { + const npu_set_scale_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE): + { + const npu_set_ofm_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE): + { + const npu_set_opa_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPA_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE): + { + const npu_set_opb_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPB_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC): + { + const npu_set_dma0_src_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST): + { + const npu_set_dma0_dst_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN): + { + const npu_set_dma0_len_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_LEN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0): + { + const npu_set_ifm2_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1): + { + const npu_set_ifm2_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2): + { + const npu_set_ifm2_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3): + { + const npu_set_ifm2_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X): + { + const npu_set_ifm2_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y): + { + const npu_set_ifm2_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C): + { + const npu_set_ifm2_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0): + { + const npu_set_user_defined0_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1): + { + const npu_set_user_defined1_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2): + { + const npu_set_user_defined2_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3): + { + const npu_set_user_defined3_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4): + { + const npu_set_user_defined4_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED4"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5): + { + const npu_set_user_defined5_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED5"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6): + { + const npu_set_user_defined6_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED6"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7): + { + const npu_set_user_defined7_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED7"; + v.disassemble(fields); + break; + } + } + return (*in & (3 << 14)) != 0 ? 2 : 1; + } +#endif +#endif + // Signal the end of command stream + struct npu_op_stop_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_stop_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_stop_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_stop_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_stop_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_stop_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // Raises an IRQ to the host + struct npu_op_irq_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_irq_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_irq_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_irq_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_irq_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_irq_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // 2D convolution + struct npu_op_conv_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_conv_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_conv_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_conv_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Depth-wise 2D convolution + struct npu_op_depthwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_depthwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_depthwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_depthwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Pooling + struct npu_op_pool_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pooling_mode : 3; // Pooling mode + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_op_pool_t(NPU_NAMESPACE::pooling_mode _pooling_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(static_cast(_pooling_mode) & ((1U << 3) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_pool_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pooling_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pool_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pool_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pooling_mode get_pooling_mode() const + { + return static_cast(pooling_mode); + } + CONSTEXPR npu_op_pool_t &set_pooling_mode(NPU_NAMESPACE::pooling_mode value) + { + pooling_mode = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "pooling_mode", + (pooling_mode < (sizeof(pooling_mode_str) / sizeof(pooling_mode_str[0])) ? + pooling_mode_str[pooling_mode] : + "****"))); + } +#endif +#endif + }; + // Elementwise operation + struct npu_op_elementwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t elementwise_mode : 6; // Elementwise mode + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_op_elementwise_t(NPU_NAMESPACE::elementwise_mode _elementwise_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(static_cast(_elementwise_mode) & ((1U << 6) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_elementwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), elementwise_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_elementwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_elementwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::elementwise_mode get_elementwise_mode() const + { + return static_cast(elementwise_mode); + } + CONSTEXPR npu_op_elementwise_t &set_elementwise_mode(NPU_NAMESPACE::elementwise_mode value) + { + elementwise_mode = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "elementwise_mode", + (elementwise_mode < (sizeof(elementwise_mode_str) / sizeof(elementwise_mode_str[0])) ? + elementwise_mode_str[elementwise_mode] : + "****"))); + } +#endif +#endif + }; + // Queue new DMA for the given channel + struct npu_op_dma_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_dma_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Wait for the DMA channel to have k or fewer active descriptors outstanding + struct npu_op_dma_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t k : 4; // Number of outstanding descriptors + uint32_t reserved1 : 12; +#ifdef __cplusplus + public: + npu_op_dma_wait_t(uint32_t _k) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(_k & ((1U << 4) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_dma_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_k() const + { + return static_cast(k); + } + CONSTEXPR npu_op_dma_wait_t &set_k(uint32_t value) + { + k = static_cast(value) & ((1U << 4) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("k", std::to_string(k))); + } +#endif +#endif + }; + // Wait for n or fewer kernel operations to be remaining + struct npu_op_kernel_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t n : 2; // Number of kernel operations in range 0-3 + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_op_kernel_wait_t(uint32_t _n) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(_n & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_kernel_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_kernel_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_kernel_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_n() const + { + return static_cast(n); + } + CONSTEXPR npu_op_kernel_wait_t &set_n(uint32_t value) + { + n = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("n", std::to_string(n))); + } +#endif +#endif + }; + // Enable or disable PMU counting (debug feature only) + struct npu_op_pmu_mask_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t enable : 1; // Enable or disable PMU mask + uint32_t reserved1 : 15; +#ifdef __cplusplus + public: + npu_op_pmu_mask_t(uint32_t _enable) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(_enable & ((1U << 1) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_op_pmu_mask_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pmu_mask_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pmu_mask_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_enable() const + { + return static_cast(enable); + } + CONSTEXPR npu_op_pmu_mask_t &set_enable(uint32_t value) + { + enable = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("enable", std::to_string(enable))); + } +#endif +#endif + }; + // IFM top pad + struct npu_set_ifm_pad_top_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM top pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_top_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_top_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM left pad + struct npu_set_ifm_pad_left_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM left pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_left_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_left_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM right pad + struct npu_set_ifm_pad_right_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM right pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_right_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_right_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM bottom pad + struct npu_set_ifm_pad_bottom_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM bottom pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_bottom_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_bottom_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // Number of input channels for convolution + struct npu_set_ifm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Number of input channels for convolution +#ifdef __cplusplus + public: + npu_set_ifm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // IFM Precision + struct npu_set_ifm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t scale_mode : 2; // IFM scale mode + uint32_t reserved3 : 4; + uint32_t round_mode : 2; // IFM round mode +#ifdef __cplusplus + public: + npu_set_ifm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ifm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 2) - 1)), reserved3(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ifm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), scale_mode(0), reserved3(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_scale_mode(NPU_NAMESPACE::ifm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ifm_scale_mode_str) / sizeof(ifm_scale_mode_str[0])) ? + ifm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // IFM upscale mode + struct npu_set_ifm_upscale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mode : 2; // IFM upscale mode + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_ifm_upscale_t(NPU_NAMESPACE::ifm_upscale_mode _mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(static_cast(_mode) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_upscale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_upscale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_upscale_mode get_mode() const + { + return static_cast(mode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_mode(NPU_NAMESPACE::ifm_upscale_mode value) + { + mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "mode", + (mode < (sizeof(ifm_upscale_mode_str) / sizeof(ifm_upscale_mode_str[0])) ? ifm_upscale_mode_str[mode] : + "****"))); + } +#endif +#endif + }; + // IFM zero point + struct npu_set_ifm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM Tile 0 and tile 2 width + struct npu_set_ifm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM Tile 0 height + struct npu_set_ifm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM Tile 1 height + struct npu_set_ifm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // End of IB0,IB1 buffers + struct npu_set_ifm_ib_end_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_end : 6; // End of IB0,IB1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm_ib_end_t(uint32_t _ib_end) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(_ib_end & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm_ib_end_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_end() const + { + return static_cast(ib_end); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_ib_end(uint32_t value) + { + ib_end = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_end", std::to_string(ib_end))); + } +#endif +#endif + }; + // Index n for IFM access + struct npu_set_ifm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number n + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_ifm_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_ifm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_ifm_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Output feature map width + struct npu_set_ofm_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Output feature map width +#ifdef __cplusplus + public: + npu_set_ofm_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Output feature map height + struct npu_set_ofm_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Output feature map height +#ifdef __cplusplus + public: + npu_set_ofm_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Output feature map depth + struct npu_set_ofm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Output feature map depth +#ifdef __cplusplus + public: + npu_set_ofm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM Precision + struct npu_set_ofm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // OFM type + uint32_t activation_precision : 2; // OFM precision + uint32_t reserved1 : 3; + uint32_t activation_format : 2; // OFM format + uint32_t scale_mode : 1; // OFM scale mode + uint32_t reserved2 : 5; + uint32_t round_mode : 2; // OFM round mode +#ifdef __cplusplus + public: + npu_set_ofm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ofm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved1(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 1) - 1)), reserved2(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ofm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), + activation_precision(0), reserved1(0), activation_format(0), scale_mode(0), reserved2(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ofm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_scale_mode(NPU_NAMESPACE::ofm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ofm_scale_mode_str) / sizeof(ofm_scale_mode_str[0])) ? + ofm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // OFM block width + struct npu_set_ofm_blk_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 6; // OFM block width + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ofm_blk_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM block height + struct npu_set_ofm_blk_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 5; // OFM block height + uint32_t reserved1 : 11; +#ifdef __cplusplus + public: + npu_set_ofm_blk_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 5) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 5) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM block depth + struct npu_set_ofm_blk_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 7; // OFM block depth + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ofm_blk_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 7) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM zero point + struct npu_set_ofm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ofm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // OFM Tile 0 and tile 2 width + struct npu_set_ofm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // OFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ofm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM Tile 0 height + struct npu_set_ofm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ofm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM Tile 1 height + struct npu_set_ofm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ofm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Index n for OFM access + struct npu_set_ofm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for OFM access + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_ofm_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_ofm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ofm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_ofm_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Kernel width + struct npu_set_kernel_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Kernel width +#ifdef __cplusplus + public: + npu_set_kernel_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Kernel height + struct npu_set_kernel_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Kernel height +#ifdef __cplusplus + public: + npu_set_kernel_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Kernel stride + struct npu_set_kernel_stride_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t stride_x_lsb : 1; // Stride x LSB. (kernel_x_stride - 1)[0] + uint32_t stride_y_lsb : 1; // Stride y LSB. (kernel_y_stride - 1)[0] + uint32_t weight_order : 1; // Weight ordering mode + uint32_t dilation_x : 1; // Kernel x dilation + uint32_t dilation_y : 1; // Kernel y dilation + uint32_t decomposition : 1; // Kernel decomposition + uint32_t stride_x_msb : 1; // Stride x MSB. (kernel_x_stride - 1) >> 1 + uint32_t reserved1 : 2; + uint32_t stride_y_msb : 1; // Stride y MSB. (kernel_y_stride - 1) >> 1 + uint32_t reserved2 : 6; +#ifdef __cplusplus + public: + npu_set_kernel_stride_t(uint32_t _stride_x_lsb, + uint32_t _stride_y_lsb, + NPU_NAMESPACE::weight_order _weight_order, + NPU_NAMESPACE::kernel_dilation _dilation_x, + NPU_NAMESPACE::kernel_dilation _dilation_y, + NPU_NAMESPACE::kernel_decomposition _decomposition, + uint32_t _stride_x_msb, + uint32_t _stride_y_msb) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(_stride_x_lsb & ((1U << 1) - 1)), stride_y_lsb(_stride_y_lsb & ((1U << 1) - 1)), + weight_order(static_cast(_weight_order) & ((1U << 1) - 1)), + dilation_x(static_cast(_dilation_x) & ((1U << 1) - 1)), + dilation_y(static_cast(_dilation_y) & ((1U << 1) - 1)), + decomposition(static_cast(_decomposition) & ((1U << 1) - 1)), + stride_x_msb(_stride_x_msb & ((1U << 1) - 1)), reserved1(0), stride_y_msb(_stride_y_msb & ((1U << 1) - 1)), + reserved2(0) + { + } + CONSTEXPR npu_set_kernel_stride_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), stride_x_lsb(0), stride_y_lsb(0), + weight_order(0), dilation_x(0), dilation_y(0), decomposition(0), stride_x_msb(0), reserved1(0), + stride_y_msb(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_stride_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_stride_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_lsb() const + { + return static_cast(stride_x_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_lsb(uint32_t value) + { + stride_x_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_lsb() const + { + return static_cast(stride_y_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_lsb(uint32_t value) + { + stride_y_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_order get_weight_order() const + { + return static_cast(weight_order); + } + CONSTEXPR npu_set_kernel_stride_t &set_weight_order(NPU_NAMESPACE::weight_order value) + { + weight_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_x() const + { + return static_cast(dilation_x); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_x(NPU_NAMESPACE::kernel_dilation value) + { + dilation_x = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_y() const + { + return static_cast(dilation_y); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_y(NPU_NAMESPACE::kernel_dilation value) + { + dilation_y = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_decomposition get_decomposition() const + { + return static_cast(decomposition); + } + CONSTEXPR npu_set_kernel_stride_t &set_decomposition(NPU_NAMESPACE::kernel_decomposition value) + { + decomposition = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_msb() const + { + return static_cast(stride_x_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_msb(uint32_t value) + { + stride_x_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_msb() const + { + return static_cast(stride_y_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_msb(uint32_t value) + { + stride_y_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("stride_x_lsb", std::to_string(stride_x_lsb))); + fields.push_back(std::make_pair("stride_y_lsb", std::to_string(stride_y_lsb))); + fields.push_back(std::make_pair( + "weight_order", + (weight_order < (sizeof(weight_order_str) / sizeof(weight_order_str[0])) ? + weight_order_str[weight_order] : + "****"))); + fields.push_back(std::make_pair( + "dilation_x", + (dilation_x < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_x] : + "****"))); + fields.push_back(std::make_pair( + "dilation_y", + (dilation_y < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_y] : + "****"))); + fields.push_back(std::make_pair( + "decomposition", + (decomposition < (sizeof(kernel_decomposition_str) / sizeof(kernel_decomposition_str[0])) ? + kernel_decomposition_str[decomposition] : + "****"))); + fields.push_back(std::make_pair("stride_x_msb", std::to_string(stride_x_msb))); + fields.push_back(std::make_pair("stride_y_msb", std::to_string(stride_y_msb))); + } +#endif +#endif + }; + // Accumulator format + struct npu_set_acc_format_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t acc_format : 2; // Accumulator format + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_acc_format_t(NPU_NAMESPACE::acc_format _acc_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(static_cast(_acc_format) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_acc_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), acc_format(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_acc_format_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_acc_format_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_format get_acc_format() const + { + return static_cast(acc_format); + } + CONSTEXPR npu_set_acc_format_t &set_acc_format(NPU_NAMESPACE::acc_format value) + { + acc_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "acc_format", + (acc_format < (sizeof(acc_format_str) / sizeof(acc_format_str[0])) ? acc_format_str[acc_format] : + "****"))); + } +#endif +#endif + }; + // Activation function and clip range + struct npu_set_activation_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_function : 5; // Activation function (before table lookup) + uint32_t reserved1 : 7; + uint32_t activation_clip_range : 3; // Activation clip range. This must be set to 0 if table lookup is not used + uint32_t reserved2 : 1; +#ifdef __cplusplus + public: + npu_set_activation_t(NPU_NAMESPACE::activation_function _activation_function, + NPU_NAMESPACE::activation_clip_range _activation_clip_range) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(static_cast(_activation_function) & ((1U << 5) - 1)), reserved1(0), + activation_clip_range(static_cast(_activation_clip_range) & ((1U << 3) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_activation_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_function(0), reserved1(0), + activation_clip_range(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_function get_activation_function() const + { + return static_cast(activation_function); + } + CONSTEXPR npu_set_activation_t &set_activation_function(NPU_NAMESPACE::activation_function value) + { + activation_function = static_cast(value) & ((1U << 5) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_clip_range get_activation_clip_range() const + { + return static_cast(activation_clip_range); + } + CONSTEXPR npu_set_activation_t &set_activation_clip_range(NPU_NAMESPACE::activation_clip_range value) + { + activation_clip_range = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_function", + (activation_function < (sizeof(activation_function_str) / sizeof(activation_function_str[0])) ? + activation_function_str[activation_function] : + "****"))); + fields.push_back(std::make_pair( + "activation_clip_range", + (activation_clip_range < (sizeof(activation_clip_range_str) / sizeof(activation_clip_range_str[0])) ? + activation_clip_range_str[activation_clip_range] : + "****"))); + } +#endif +#endif + }; + // Lower bound clip + struct npu_set_activation_min_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_min_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_min_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_min_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_min_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_min_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Upper bound clip + struct npu_set_activation_max_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_max_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_max_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_max_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_max_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Index n for weight stream access + struct npu_set_weight_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for weight stream access + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_weight_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_weight_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_weight_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_weight_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Index n for scale stream access + struct npu_set_scale_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for scale stream access + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_scale_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_scale_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_scale_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_scale_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Start of ACC0,ACC1 buffers + struct npu_set_ab_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ab_start : 6; // Start of ACC0,ACC1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ab_start_t(uint32_t _ab_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(_ab_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ab_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ab_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ab_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ab_start() const + { + return static_cast(ab_start); + } + CONSTEXPR npu_set_ab_start_t &set_ab_start(uint32_t value) + { + ab_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ab_start", std::to_string(ab_start))); + } +#endif +#endif + }; + // Block number of blocks dependency + struct npu_set_blockdep_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t blockdep : 2; // Block number of blocks dependency between kernel operations + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_blockdep_t(uint32_t _blockdep) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(_blockdep & ((1U << 2) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_blockdep_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_blockdep_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_blockdep_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_blockdep() const + { + return static_cast(blockdep); + } + CONSTEXPR npu_set_blockdep_t &set_blockdep(uint32_t value) + { + blockdep = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("blockdep", std::to_string(blockdep))); + } +#endif +#endif + }; + // DMA0 source region + struct npu_set_dma0_src_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 4; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_dma0_src_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode, + NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0), + custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_dma0_src_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_dma0_src_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // DMA0 destination region + struct npu_set_dma0_dst_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number if region_mode is region_mode_external. Else core mask to write to (bit k + // set for core k=0,1) + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 4; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_dma0_dst_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode, + NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0), + custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_dma0_dst_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Size of second dimension for 2D/3D transfers + struct npu_set_dma0_size0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of second dimension for 2D/3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size0_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size0_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size0_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // Size of third dimension for 3D transfers + struct npu_set_dma0_size1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of third dimension for 3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size1_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size1_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // IFM2 broadcast configuration + struct npu_set_ifm2_broadcast_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t + broadcast_h : 1; // Broadcast H dimension (if set then any accesses to IFM2 sets y=0 and IFM2 height=1) + uint32_t broadcast_w : 1; // Broadcast W dimension (if set then any accesses to IFM2 sets x=0 and IFM2 width=1) + uint32_t broadcast_c : 1; // Broadcast C dimension (if set then any accesses to IFM2 sets c=0 and IFM2 depth=1) + uint32_t reserved1 : 3; + uint32_t operand_order : 1; // Operand order + uint32_t broadcast_constant : 1; // Broadcast constant given by NPU_SET_IFM2_SCALAR and so ignore BH, BW and BC + uint32_t reserved2 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_h, + NPU_NAMESPACE::broadcast_mode _broadcast_w, + NPU_NAMESPACE::broadcast_mode _broadcast_c, + NPU_NAMESPACE::ifm2_operand_order _operand_order, + NPU_NAMESPACE::broadcast_mode _broadcast_constant) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_h(static_cast(_broadcast_h) & ((1U << 1) - 1)), + broadcast_w(static_cast(_broadcast_w) & ((1U << 1) - 1)), + broadcast_c(static_cast(_broadcast_c) & ((1U << 1) - 1)), reserved1(0), + operand_order(static_cast(_operand_order) & ((1U << 1) - 1)), + broadcast_constant(static_cast(_broadcast_constant) & ((1U << 1) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_ifm2_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), broadcast_h(0), broadcast_w(0), + broadcast_c(0), reserved1(0), operand_order(0), broadcast_constant(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_h() const + { + return static_cast(broadcast_h); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_h(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_h = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_w() const + { + return static_cast(broadcast_w); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_w(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_w = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_c() const + { + return static_cast(broadcast_c); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_c(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_c = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm2_operand_order get_operand_order() const + { + return static_cast(operand_order); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_operand_order(NPU_NAMESPACE::ifm2_operand_order value) + { + operand_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_constant() const + { + return static_cast(broadcast_constant); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_constant(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_constant = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "broadcast_h", + (broadcast_h < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_h] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_w", + (broadcast_w < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_w] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_c", + (broadcast_c < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_c] : + "****"))); + fields.push_back(std::make_pair( + "operand_order", + (operand_order < (sizeof(ifm2_operand_order_str) / sizeof(ifm2_operand_order_str[0])) ? + ifm2_operand_order_str[operand_order] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_constant", + (broadcast_constant < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_constant] : + "****"))); + } +#endif +#endif + }; + // IFM2 scalar value + struct npu_set_ifm2_scalar_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t scalar : 16; // int16 or uint16 depending on ifm2_precision.type +#ifdef __cplusplus + public: + npu_set_ifm2_scalar_t(uint32_t _scalar) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(_scalar & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_scalar_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scalar() const + { + return static_cast(scalar); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_scalar(uint32_t value) + { + scalar = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scalar", std::to_string(scalar))); + } +#endif +#endif + }; + // IFM2 Precision + struct npu_set_ifm2_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type - MUST MATCH IFM + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision - MUST MATCH IFM + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t reserved3 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), reserved3(0) + { + } + CONSTEXPR npu_set_ifm2_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), reserved3(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + } +#endif +#endif + }; + // IFM2 zero point + struct npu_set_ifm2_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm2_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM2 Tile 0 and tile 2 width + struct npu_set_ifm2_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM2 Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm2_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM2 Tile 0 height + struct npu_set_ifm2_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm2_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM2 Tile 1 height + struct npu_set_ifm2_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm2_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Start of IB0,IB1 buffers for IFM2 + struct npu_set_ifm2_ib_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_start : 6; // Start of IB0,IB1 buffers for IFM2 in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm2_ib_start_t(uint32_t _ib_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(_ib_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_ib_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_start() const + { + return static_cast(ib_start); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_ib_start(uint32_t value) + { + ib_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_start", std::to_string(ib_start))); + } +#endif +#endif + }; + // Index n for IFM2 access + struct npu_set_ifm2_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for IFM2 access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ifm2_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm2_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // IFM Tile 0 address + struct npu_set_ifm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base0_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base0_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 1 address + struct npu_set_ifm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base1_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base1_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 2 address + struct npu_set_ifm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base2_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base2_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 3 address + struct npu_set_ifm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base3_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base3_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between horizontal values + struct npu_set_ifm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_x_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_stride_x_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_stride_x_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_stride_x_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between vertical values + struct npu_set_ifm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_y_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_stride_y_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_stride_y_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_stride_y_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_c_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_stride_c_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_stride_c_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_stride_c_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 0 address + struct npu_set_ofm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base0_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base0_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 1 address + struct npu_set_ofm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base1_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base1_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 2 address + struct npu_set_ofm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base2_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base2_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 3 address + struct npu_set_ofm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base3_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base3_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between horizontal values + struct npu_set_ofm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_x_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_stride_x_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_stride_x_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_stride_x_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between vertical values + struct npu_set_ofm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_y_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_stride_y_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_stride_y_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_stride_y_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ofm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_c_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_stride_c_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_stride_c_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_stride_c_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte offset in WEIGHT_REGION + struct npu_set_weight_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_weight_base_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_weight_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_base_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_base_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_weight_base_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte length + struct npu_set_weight_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 32; // Weight stream byte length +#ifdef __cplusplus + public: + npu_set_weight_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(_length) + { + } + CONSTEXPR npu_set_weight_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight_length_t &set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // Scale and bias stream input byte offset from SCALE_REGION + struct npu_set_scale_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_scale_base_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_scale_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_base_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_base_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_scale_base_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Scale and bias stream input byte length + struct npu_set_scale_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 20; // Scale and bias stream byte length + uint32_t reserved2 : 12; +#ifdef __cplusplus + public: + npu_set_scale_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + length(_length & ((1U << 20) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_scale_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale_length_t &set_length(uint32_t value) + { + length = value & ((1U << 20) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // OFM scale + struct npu_set_ofm_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. Not applied for 32-bit operations +#ifdef __cplusplus + public: + npu_set_ofm_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_ofm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ofm_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ofm_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand A scale + struct npu_set_opa_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift. Ignored if IFM scale mode is 0 + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. 16-bit if IFM scale mode is 0 +#ifdef __cplusplus + public: + npu_set_opa_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_opa_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opa_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opa_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_opa_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opa_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand B scale + struct npu_set_opb_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t scale : 16; // Scale. Not used if IFM scale mode is 1 or 2 + uint32_t reserved2 : 16; +#ifdef __cplusplus + public: + npu_set_opb_scale_t(uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + scale(_scale & ((1U << 16) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_opb_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), scale(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opb_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opb_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opb_scale_t &set_scale(uint32_t value) + { + scale = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // DMA user channel 0 source byte offset from DMA0_SRC_REGION + struct npu_set_dma0_src_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_src_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_dma0_src_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_dma0_src_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 destination byte offset from DMA0_DST_REGION + struct npu_set_dma0_dst_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_dst_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_dma0_dst_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_dma0_dst_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 transfer length in bytes for each 1D transfer + struct npu_set_dma0_len_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_len_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_dma0_len_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_len_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_len_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_dma0_len_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 0 address + struct npu_set_ifm2_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base0_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base0_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 1 address + struct npu_set_ifm2_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base1_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base1_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 2 address + struct npu_set_ifm2_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base2_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base2_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 3 address + struct npu_set_ifm2_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base3_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base3_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between horizontal values + struct npu_set_ifm2_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_x_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between vertical values + struct npu_set_ifm2_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_y_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm2_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_c_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // User defined register 0 + struct npu_set_user_defined0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined0_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined0_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 1 + struct npu_set_user_defined1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined1_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined1_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 2 + struct npu_set_user_defined2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined2_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined2_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 3 + struct npu_set_user_defined3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined3_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined3_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 4 + struct npu_set_user_defined4_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined4_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined4_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined4_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined4_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined4_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 5 + struct npu_set_user_defined5_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined5_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined5_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined5_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined5_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined5_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 6 + struct npu_set_user_defined6_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined6_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined6_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined6_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined6_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined6_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 7 + struct npu_set_user_defined7_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined7_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined7_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined7_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined7_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined7_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; +#ifdef __cplusplus +}; +#endif +#define NPU_OP_STRUCTS \ + NPU_OP_(stop) \ + NPU_OP_(irq) \ + NPU_OP_(conv) \ + NPU_OP_(depthwise) \ + NPU_OP_(pool) \ + NPU_OP_(elementwise) \ + NPU_OP_(dma_start) \ + NPU_OP_(dma_wait) \ + NPU_OP_(kernel_wait) \ + NPU_OP_(pmu_mask) + +#define NPU_SET_STRUCTS \ + NPU_SET_(ifm_pad_top) \ + NPU_SET_(ifm_pad_left) \ + NPU_SET_(ifm_pad_right) \ + NPU_SET_(ifm_pad_bottom) \ + NPU_SET_(ifm_depth_m1) \ + NPU_SET_(ifm_precision) \ + NPU_SET_(ifm_upscale) \ + NPU_SET_(ifm_zero_point) \ + NPU_SET_(ifm_width0_m1) \ + NPU_SET_(ifm_height0_m1) \ + NPU_SET_(ifm_height1_m1) \ + NPU_SET_(ifm_ib_end) \ + NPU_SET_(ifm_region) \ + NPU_SET_(ofm_width_m1) \ + NPU_SET_(ofm_height_m1) \ + NPU_SET_(ofm_depth_m1) \ + NPU_SET_(ofm_precision) \ + NPU_SET_(ofm_blk_width_m1) \ + NPU_SET_(ofm_blk_height_m1) \ + NPU_SET_(ofm_blk_depth_m1) \ + NPU_SET_(ofm_zero_point) \ + NPU_SET_(ofm_width0_m1) \ + NPU_SET_(ofm_height0_m1) \ + NPU_SET_(ofm_height1_m1) \ + NPU_SET_(ofm_region) \ + NPU_SET_(kernel_width_m1) \ + NPU_SET_(kernel_height_m1) \ + NPU_SET_(kernel_stride) \ + NPU_SET_(acc_format) \ + NPU_SET_(activation) \ + NPU_SET_(activation_min) \ + NPU_SET_(activation_max) \ + NPU_SET_(weight_region) \ + NPU_SET_(scale_region) \ + NPU_SET_(ab_start) \ + NPU_SET_(blockdep) \ + NPU_SET_(dma0_src_region) \ + NPU_SET_(dma0_dst_region) \ + NPU_SET_(dma0_size0) \ + NPU_SET_(dma0_size1) \ + NPU_SET_(ifm2_broadcast) \ + NPU_SET_(ifm2_scalar) \ + NPU_SET_(ifm2_precision) \ + NPU_SET_(ifm2_zero_point) \ + NPU_SET_(ifm2_width0_m1) \ + NPU_SET_(ifm2_height0_m1) \ + NPU_SET_(ifm2_height1_m1) \ + NPU_SET_(ifm2_ib_start) \ + NPU_SET_(ifm2_region) \ + NPU_SET_(ifm_base0) \ + NPU_SET_(ifm_base1) \ + NPU_SET_(ifm_base2) \ + NPU_SET_(ifm_base3) \ + NPU_SET_(ifm_stride_x) \ + NPU_SET_(ifm_stride_y) \ + NPU_SET_(ifm_stride_c) \ + NPU_SET_(ofm_base0) \ + NPU_SET_(ofm_base1) \ + NPU_SET_(ofm_base2) \ + NPU_SET_(ofm_base3) \ + NPU_SET_(ofm_stride_x) \ + NPU_SET_(ofm_stride_y) \ + NPU_SET_(ofm_stride_c) \ + NPU_SET_(weight_base) \ + NPU_SET_(weight_length) \ + NPU_SET_(scale_base) \ + NPU_SET_(scale_length) \ + NPU_SET_(ofm_scale) \ + NPU_SET_(opa_scale) \ + NPU_SET_(opb_scale) \ + NPU_SET_(dma0_src) \ + NPU_SET_(dma0_dst) \ + NPU_SET_(dma0_len) \ + NPU_SET_(ifm2_base0) \ + NPU_SET_(ifm2_base1) \ + NPU_SET_(ifm2_base2) \ + NPU_SET_(ifm2_base3) \ + NPU_SET_(ifm2_stride_x) \ + NPU_SET_(ifm2_stride_y) \ + NPU_SET_(ifm2_stride_c) \ + NPU_SET_(user_defined0) \ + NPU_SET_(user_defined1) \ + NPU_SET_(user_defined2) \ + NPU_SET_(user_defined3) \ + NPU_SET_(user_defined4) \ + NPU_SET_(user_defined5) \ + NPU_SET_(user_defined6) \ + NPU_SET_(user_defined7) + +#define EXPAND_ACC_FORMAT(FUNC, SEP) FUNC(acc_format, I32) SEP FUNC(acc_format, I40) SEP FUNC(acc_format, F16) + +#define EXPAND_ACTIVATION_CLIP_RANGE(FUNC, SEP) \ + FUNC(activation_clip_range, OFM_PRECISION) \ + SEP FUNC(activation_clip_range, FORCE_UINT8) SEP FUNC(activation_clip_range, FORCE_INT8) \ + SEP FUNC(activation_clip_range, FORCE_INT16) + +#define EXPAND_ACTIVATION_FORMAT(FUNC, SEP) FUNC(activation_format, NHWC) SEP FUNC(activation_format, NHCWB16) + +#define EXPAND_ACTIVATION_FUNCTION(FUNC, SEP) \ + FUNC(activation_function, RELU) \ + SEP FUNC(activation_function, TANH) SEP FUNC(activation_function, SIGMOID) SEP FUNC(activation_function, TABLE_0) \ + SEP FUNC(activation_function, TABLE_1) SEP FUNC(activation_function, TABLE_2) \ + SEP FUNC(activation_function, TABLE_3) SEP FUNC(activation_function, TABLE_4) \ + SEP FUNC(activation_function, TABLE_5) SEP FUNC(activation_function, TABLE_6) \ + SEP FUNC(activation_function, TABLE_7) + +#define EXPAND_ACTIVATION_PRECISION(FUNC, SEP) \ + FUNC(activation_precision, B8) \ + SEP FUNC(activation_precision, B16) SEP FUNC(activation_precision, B32) SEP FUNC(activation_precision, B64) + +#define EXPAND_ACTIVATION_TYPE(FUNC, SEP) FUNC(activation_type, UNSIGNED) SEP FUNC(activation_type, SIGNED) + +#define EXPAND_AXI_MEM_ENCODING(FUNC, SEP) \ + FUNC(axi_mem_encoding, DEVICE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, DEVICE_BUFFERABLE) SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_AND_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_AND_WRITE_ALLOCATE) + +#define EXPAND_BROADCAST_MODE(FUNC, SEP) FUNC(broadcast_mode, DISABLE) SEP FUNC(broadcast_mode, ENABLE) + +#define EXPAND_CMD0_OPCODE(FUNC, SEP) \ + FUNC(cmd0_opcode, NPU_OP_STOP) \ + SEP FUNC(cmd0_opcode, NPU_OP_IRQ) SEP FUNC(cmd0_opcode, NPU_OP_CONV) SEP FUNC( \ + cmd0_opcode, NPU_OP_DEPTHWISE) SEP FUNC(cmd0_opcode, NPU_OP_POOL) SEP FUNC(cmd0_opcode, NPU_OP_ELEMENTWISE) \ + SEP FUNC(cmd0_opcode, NPU_OP_DMA_START) SEP FUNC(cmd0_opcode, NPU_OP_DMA_WAIT) SEP FUNC( \ + cmd0_opcode, NPU_OP_KERNEL_WAIT) SEP FUNC(cmd0_opcode, NPU_OP_PMU_MASK) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PAD_TOP) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_LEFT) SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_RIGHT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_PAD_BOTTOM) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_DEPTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PRECISION) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_UPSCALE) SEP FUNC(cmd0_opcode, NPU_SET_IFM_ZERO_POINT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_WIDTH0_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_IB_END) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_REGION) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_DEPTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_PRECISION) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_BLK_WIDTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_OFM_BLK_HEIGHT_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_BLK_DEPTH_M1) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_ZERO_POINT) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT0_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_OFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_REGION) \ + SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_WIDTH_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_KERNEL_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_STRIDE) \ + SEP FUNC(cmd0_opcode, NPU_SET_ACC_FORMAT) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_ACTIVATION) SEP FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MIN) \ + SEP FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MAX) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_WEIGHT_REGION) SEP FUNC(cmd0_opcode, NPU_SET_SCALE_REGION) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_AB_START) SEP FUNC(cmd0_opcode, NPU_SET_BLOCKDEP) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SRC_REGION) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_DMA0_DST_REGION) SEP FUNC(cmd0_opcode, \ + NPU_SET_DMA0_SIZE0) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_BROADCAST) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM2_SCALAR) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_PRECISION) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM2_ZERO_POINT) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM2_WIDTH0_M1) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT0_M1) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT1_M1) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_IB_START) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_REGION) + +#define EXPAND_CMD1_OPCODE(FUNC, SEP) \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE0) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE1) SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE2) SEP FUNC( \ + cmd1_opcode, NPU_SET_IFM_BASE3) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_Y) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_C) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_BASE0) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE1) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE2) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE3) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_STRIDE_X) SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_C) SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT_BASE) SEP FUNC( \ + cmd1_opcode, NPU_SET_WEIGHT_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_SCALE_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_OFM_SCALE) SEP FUNC( \ + cmd1_opcode, NPU_SET_OPA_SCALE) SEP FUNC(cmd1_opcode, NPU_SET_OPB_SCALE) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SRC) SEP FUNC(cmd1_opcode, NPU_SET_DMA0_DST) SEP FUNC( \ + cmd1_opcode, NPU_SET_DMA0_LEN) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE0) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE1) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE2) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE3) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_C) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED0) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED1) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED2) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED3) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED4) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED5) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED6) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED7) + +#define EXPAND_CMD_CTRL(FUNC, SEP) FUNC(cmd_ctrl, CMD0_CTRL) SEP FUNC(cmd_ctrl, CMD1_CTRL) + +#define EXPAND_CUSTOM_DMA_CS(FUNC, SEP) FUNC(custom_dma_cs, DISABLE) SEP FUNC(custom_dma_cs, ENABLE) + +#define EXPAND_CUSTOM_DMA(FUNC, SEP) FUNC(custom_dma, NOT_IMPLEMENTED) SEP FUNC(custom_dma, IMPLEMENTED) + +#define EXPAND_DMA_FAULT_SRC(FUNC, SEP) FUNC(dma_fault_src, AXI_M0) SEP FUNC(dma_fault_src, AXI_M1) + +#define EXPAND_DMA_REGION_MODE(FUNC, SEP) FUNC(dma_region_mode, EXTERNAL) SEP FUNC(dma_region_mode, INTERNAL) + +#define EXPAND_DMA_STRIDE_MODE(FUNC, SEP) FUNC(dma_stride_mode, D1) + +#define EXPAND_ELEMENTWISE_MODE(FUNC, SEP) \ + FUNC(elementwise_mode, MUL) \ + SEP FUNC(elementwise_mode, ADD) SEP FUNC(elementwise_mode, SUB) SEP FUNC(elementwise_mode, MIN) \ + SEP FUNC(elementwise_mode, MAX) SEP FUNC(elementwise_mode, LRELU) SEP FUNC(elementwise_mode, ABS) \ + SEP FUNC(elementwise_mode, CLZ) SEP FUNC(elementwise_mode, SHR) SEP FUNC(elementwise_mode, SHL) + +#define EXPAND_FUNCTIONAL_SAFETY(FUNC, SEP) \ + FUNC(functional_safety, NOT_IMPLEMENTED) SEP FUNC(functional_safety, IMPLEMENTED) + +#define EXPAND_IFM2_OPERAND_ORDER(FUNC, SEP) FUNC(ifm2_operand_order, ORDER_B) SEP FUNC(ifm2_operand_order, ORDER_A) + +#define EXPAND_IFM_SCALE_MODE(FUNC, SEP) \ + FUNC(ifm_scale_mode, OPA_OPB_16) SEP FUNC(ifm_scale_mode, OPA_32) SEP FUNC(ifm_scale_mode, OPB_32) + +#define EXPAND_IFM_UPSCALE_MODE(FUNC, SEP) \ + FUNC(ifm_upscale_mode, NONE) SEP FUNC(ifm_upscale_mode, NEAREST) SEP FUNC(ifm_upscale_mode, ZEROS) + +#define EXPAND_KERNEL_DECOMPOSITION(FUNC, SEP) FUNC(kernel_decomposition, D8X8) SEP FUNC(kernel_decomposition, D4X4) + +#define EXPAND_KERNEL_DILATION(FUNC, SEP) FUNC(kernel_dilation, NONE) SEP FUNC(kernel_dilation, X2) + +#define EXPAND_MAX_BEATS(FUNC, SEP) FUNC(max_beats, B64) SEP FUNC(max_beats, B128) SEP FUNC(max_beats, B256) + +#define EXPAND_MEM_ATTR(FUNC, SEP) \ + FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER0) \ + SEP FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER1) SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER2) \ + SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER3) + +#define EXPAND_OFM_SCALE_MODE(FUNC, SEP) FUNC(ofm_scale_mode, PER_CHANNEL) SEP FUNC(ofm_scale_mode, GLOBAL) + +#define EXPAND_PMU_AXI_CHANNEL(FUNC, SEP) \ + FUNC(pmu_axi_channel, RD_CMD) \ + SEP FUNC(pmu_axi_channel, RD_IFM) SEP FUNC(pmu_axi_channel, RD_WEIGHTS) SEP FUNC(pmu_axi_channel, RD_SCALE_BIAS) \ + SEP FUNC(pmu_axi_channel, RD_MEM2MEM) SEP FUNC(pmu_axi_channel, WR_OFM) SEP FUNC(pmu_axi_channel, WR_MEM2MEM) + +#define EXPAND_PMU_EVENT(FUNC, SEP) \ + FUNC(pmu_event, NO_EVENT) \ + SEP FUNC(pmu_event, CYCLE) SEP FUNC(pmu_event, NPU_IDLE) SEP FUNC(pmu_event, CC_STALLED_ON_BLOCKDEP) SEP FUNC( \ + pmu_event, CC_STALLED_ON_SHRAM_RECONFIG) SEP FUNC(pmu_event, NPU_ACTIVE) SEP FUNC(pmu_event, MAC_ACTIVE) \ + SEP FUNC(pmu_event, MAC_ACTIVE_8BIT) SEP FUNC(pmu_event, MAC_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, MAC_DPU_ACTIVE) SEP FUNC(pmu_event, MAC_STALLED_BY_WD_ACC) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_WD) \ + SEP FUNC(pmu_event, MAC_STALLED_BY_ACC) SEP FUNC(pmu_event, MAC_STALLED_BY_IB) SEP FUNC( \ + pmu_event, \ + MAC_ACTIVE_32BIT) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_W) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_ACC) SEP FUNC(pmu_event, \ + AO_ACTIVE) \ + SEP FUNC(pmu_event, AO_ACTIVE_8BIT) SEP FUNC(pmu_event, AO_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, AO_STALLED_BY_OFMP_OB) SEP FUNC(pmu_event, AO_STALLED_BY_OFMP) SEP \ + FUNC(pmu_event, AO_STALLED_BY_OB) SEP FUNC(pmu_event, AO_STALLED_BY_ACC_IB) SEP FUNC( \ + pmu_event, AO_STALLED_BY_ACC) SEP FUNC(pmu_event, AO_STALLED_BY_IB) SEP \ + FUNC(pmu_event, WD_ACTIVE) SEP FUNC(pmu_event, WD_STALLED) SEP FUNC(pmu_event, WD_STALLED_BY_WS) SEP FUNC( \ + pmu_event, WD_STALLED_BY_WD_BUF) SEP FUNC(pmu_event, \ + WD_PARSE_ACTIVE) SEP \ + FUNC(pmu_event, WD_PARSE_STALLED) SEP FUNC(pmu_event, WD_PARSE_STALLED_IN) SEP FUNC( \ + pmu_event, WD_PARSE_STALLED_OUT) SEP FUNC(pmu_event, \ + WD_TRANS_WS) SEP \ + FUNC(pmu_event, WD_TRANS_WB) SEP FUNC(pmu_event, WD_TRANS_DW0) SEP FUNC( \ + pmu_event, WD_TRANS_DW1) SEP FUNC(pmu_event, \ + AXI0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_RD_TRANS_COMPLETED) SEP FUNC(pmu_event, AXI0_RD_DATA_BEAT_RECEIVED) SEP FUNC( \ + pmu_event, AXI0_RD_TRAN_REQ_STALLED) SEP FUNC(pmu_event, \ + AXI0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, AXI0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_WRITTEN) SEP FUNC( \ + pmu_event, AXI0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_STALLED) SEP FUNC( \ + pmu_event, \ + AXI0_ENABLED_CYCLES) SEP FUNC(pmu_event, \ + AXI0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, AXI0_WR_STALL_LIMIT) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_ANY) SEP FUNC(pmu_event, \ + AXI_LATENCY_32) SEP \ + FUNC(pmu_event, \ + AXI_LATENCY_64) SEP FUNC(pmu_event, \ + AXI_LATENCY_128) SEP \ + FUNC(pmu_event, AXI_LATENCY_256) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_512) SEP FUNC(pmu_event, \ + AXI_LATENCY_1024) SEP \ + FUNC(pmu_event, ECC_DMA) SEP FUNC( \ + pmu_event, \ + ECC_SB0) SEP FUNC(pmu_event, \ + AXI1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_RD_TRANS_COMPLETED) SEP FUNC( \ + pmu_event, AXI1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, AXI1_RD_TRAN_REQ_STALLED) SEP FUNC( \ + pmu_event, AXI1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, \ + AXI1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, \ + AXI1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, \ + AXI1_WR_TRAN_REQ_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_DATA_BEAT_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_ENABLED_CYCLES) SEP \ + FUNC( \ + pmu_event, \ + AXI1_RD_STALL_LIMIT) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_STALL_LIMIT) \ + SEP FUNC( \ + pmu_event, \ + ECC_SB1) + +#define EXPAND_POOLING_MODE(FUNC, SEP) \ + FUNC(pooling_mode, MAX) SEP FUNC(pooling_mode, AVERAGE) SEP FUNC(pooling_mode, REDUCE_SUM) + +#define EXPAND_PRIVILEGE_LEVEL(FUNC, SEP) FUNC(privilege_level, USER) SEP FUNC(privilege_level, PRIVILEGED) + +#define EXPAND_ROUND_MODE(FUNC, SEP) FUNC(round_mode, DBL) SEP FUNC(round_mode, TRUNCATE) SEP FUNC(round_mode, NATURAL) + +#define EXPAND_SECURITY_LEVEL(FUNC, SEP) FUNC(security_level, SECURE) SEP FUNC(security_level, NON_SECURE) + +#define EXPAND_STATE(FUNC, SEP) FUNC(state, STOPPED) SEP FUNC(state, RUNNING) + +#define EXPAND_WD_CORE_SLICE_STATE(FUNC, SEP) \ + FUNC(wd_core_slice_state, HEADER) SEP FUNC(wd_core_slice_state, PALETTE) SEP FUNC(wd_core_slice_state, WEIGHTS) + +#define EXPAND_WD_CTRL_STATE(FUNC, SEP) \ + FUNC(wd_ctrl_state, IDLE) \ + SEP FUNC(wd_ctrl_state, DRAIN) SEP FUNC(wd_ctrl_state, OFD_INIT) SEP FUNC(wd_ctrl_state, OFD_RUN) + +#define EXPAND_WEIGHT_ORDER(FUNC, SEP) FUNC(weight_order, DEPTH_FIRST) SEP FUNC(weight_order, PART_KERNEL_FIRST) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h new file mode 100644 index 0000000..c4e3d2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h @@ -0,0 +1,26060 @@ +/* + * Copyright (c) 2020-2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU65_INTERFACE_H +#define ETHOSU65_INTERFACE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#if !defined(__cplusplus) || __cplusplus < 201402L +#define CONSTEXPR +#else +#define CONSTEXPR constexpr +#endif + +#ifndef __cplusplus +#define STRUCT struct +#else +#define STRUCT +#endif + +#if defined(__cplusplus) && defined(NPU_DISASSEMBLE) +#include +#include +#include +#endif + +#if defined(__cplusplus) && !defined(NPU_NAMESPACE) +#define NPU_NAMESPACE npu +#endif + +#ifdef __cplusplus +#include +#include +#endif + +#ifdef __cplusplus +namespace NPU_NAMESPACE +{ +#endif +#define NNX_ARCH_VERSION_MAJOR 1 +#define NNX_ARCH_VERSION_MINOR 0 +#define NNX_ARCH_VERSION_PATCH 6 + +// Register offsets +// +// Register subpage BASE +// +#define NPU_REG_ID 0x0000 +#define NPU_REG_STATUS 0x0004 +#define NPU_REG_CMD 0x0008 +#define NPU_REG_RESET 0x000C +#define NPU_REG_QBASE 0x0010 +#define NPU_REG_QBASE_HI 0x0014 +#define NPU_REG_QREAD 0x0018 +#define NPU_REG_QCONFIG 0x001C +#define NPU_REG_QSIZE 0x0020 +#define NPU_REG_PROT 0x0024 +#define NPU_REG_CONFIG 0x0028 +#define NPU_REG_LOCK 0x002C +#define NPU_REG_REGIONCFG 0x003C +#define NPU_REG_AXI_LIMIT0 0x0040 +#define NPU_REG_AXI_LIMIT1 0x0044 +#define NPU_REG_AXI_LIMIT2 0x0048 +#define NPU_REG_AXI_LIMIT3 0x004C +#define BASE_REGISTERS_SIZE 0x0080 + +// +// Register subpage BASE_POINTERS +// +#define NPU_REG_BASEP_BASE 0x0080 +#define NPU_REG_BASEP_ARRLEN 0x0008 +#define BASE_POINTERS_REGISTERS_SIZE 0x0100 + +// +// Register subpage DEBUG +// +#define NPU_REG_WD_STATUS 0x0100 +#define NPU_REG_MAC_STATUS 0x0104 +#define NPU_REG_AO_STATUS 0x0108 +#define NPU_REG_DMA_STATUS0 0x0110 +#define NPU_REG_DMA_STATUS1 0x0114 +#define NPU_REG_CLKFORCE 0x0140 +#define NPU_REG_DEBUG_ADDRESS 0x0144 +#define NPU_REG_DEBUG_MISC 0x0148 +#define NPU_REG_DEBUGCORE 0x014C +#define NPU_REG_DEBUG_BLOCK 0x0150 +#define DEBUG_REGISTERS_SIZE 0x0180 + +// +// Register subpage PMU +// +#define NPU_REG_PMCR 0x0180 +#define NPU_REG_PMCNTENSET 0x0184 +#define NPU_REG_PMCNTENCLR 0x0188 +#define NPU_REG_PMOVSSET 0x018C +#define NPU_REG_PMOVSCLR 0x0190 +#define NPU_REG_PMINTSET 0x0194 +#define NPU_REG_PMINTCLR 0x0198 +#define NPU_REG_PMCCNTR 0x01A0 +#define NPU_REG_PMCCNTR_HI 0x01A4 +#define NPU_REG_PMCCNTR_CFG 0x01A8 +#define NPU_REG_PMCAXI_CHAN 0x01AC +#define PMU_REGISTERS_SIZE 0x0200 + +// +// Register subpage TSU_DEBUG +// +#define NPU_REG_KERNEL_X 0x0200 +#define NPU_REG_KERNEL_Y 0x0204 +#define NPU_REG_KERNEL_W_M1 0x0208 +#define NPU_REG_KERNEL_H_M1 0x020C +#define NPU_REG_OFM_CBLK_WIDTH_M1 0x0210 +#define NPU_REG_OFM_CBLK_HEIGHT_M1 0x0214 +#define NPU_REG_OFM_CBLK_DEPTH_M1 0x0218 +#define NPU_REG_IFM_CBLK_DEPTH_M1 0x021C +#define NPU_REG_OFM_X 0x0220 +#define NPU_REG_OFM_Y 0x0224 +#define NPU_REG_OFM_Z 0x0228 +#define NPU_REG_IFM_Z 0x022C +#define NPU_REG_PAD_TOP 0x0230 +#define NPU_REG_PAD_LEFT 0x0234 +#define NPU_REG_IFM_CBLK_WIDTH 0x0238 +#define NPU_REG_IFM_CBLK_HEIGHT 0x023C +#define NPU_REG_DMA_IFM_SRC 0x0240 +#define NPU_REG_DMA_IFM_SRC_HI 0x0244 +#define NPU_REG_DMA_IFM_DST 0x0248 +#define NPU_REG_DMA_OFM_SRC 0x024C +#define NPU_REG_DMA_OFM_DST 0x0250 +#define NPU_REG_DMA_OFM_DST_HI 0x0254 +#define NPU_REG_DMA_WEIGHT_SRC 0x0258 +#define NPU_REG_DMA_WEIGHT_SRC_HI 0x025C +#define NPU_REG_DMA_CMD_SRC 0x0260 +#define NPU_REG_DMA_CMD_SRC_HI 0x0264 +#define NPU_REG_DMA_CMD_SIZE 0x0268 +#define NPU_REG_DMA_M2M_SRC 0x026C +#define NPU_REG_DMA_M2M_SRC_HI 0x0270 +#define NPU_REG_DMA_M2M_DST 0x0274 +#define NPU_REG_DMA_M2M_DST_HI 0x0278 +#define NPU_REG_CURRENT_QREAD 0x027C +#define NPU_REG_DMA_SCALE_SRC 0x0280 +#define NPU_REG_DMA_SCALE_SRC_HI 0x0284 +#define NPU_REG_CURRENT_BLOCK 0x02B4 +#define NPU_REG_CURRENT_OP 0x02B8 +#define NPU_REG_CURRENT_CMD 0x02BC +#define TSU_DEBUG_REGISTERS_SIZE 0x02C0 + +// +// Register subpage PMU_COUNTERS +// +#define NPU_REG_PMEVCNTR_BASE 0x0300 +#define NPU_REG_PMEVCNTR_ARRLEN 0x0004 +#define NPU_REG_PMEVTYPER_BASE 0x0380 +#define NPU_REG_PMEVTYPER_ARRLEN 0x0004 +#define PMU_COUNTERS_REGISTERS_SIZE 0x0400 + +// +// Register subpage SHARED_BUFFER +// +#define NPU_REG_SHARED_BUFFER_BASE 0x0400 +#define NPU_REG_SHARED_BUFFER_ARRLEN 0x0100 +#define SHARED_BUFFER_REGISTERS_SIZE 0x0800 + +// +// Register subpage TSU_IFM +// +#define NPU_REG_IFM_PAD_TOP 0x0800 +#define NPU_REG_IFM_PAD_LEFT 0x0804 +#define NPU_REG_IFM_PAD_RIGHT 0x0808 +#define NPU_REG_IFM_PAD_BOTTOM 0x080C +#define NPU_REG_IFM_DEPTH_M1 0x0810 +#define NPU_REG_IFM_PRECISION 0x0814 +#define NPU_REG_IFM_UPSCALE 0x081C +#define NPU_REG_IFM_ZERO_POINT 0x0824 +#define NPU_REG_IFM_WIDTH0_M1 0x0828 +#define NPU_REG_IFM_HEIGHT0_M1 0x082C +#define NPU_REG_IFM_HEIGHT1_M1 0x0830 +#define NPU_REG_IFM_IB_END 0x0834 +#define NPU_REG_IFM_REGION 0x083C +#define TSU_IFM_REGISTERS_SIZE 0x0840 + +// +// Register subpage TSU_OFM +// +#define NPU_REG_OFM_WIDTH_M1 0x0844 +#define NPU_REG_OFM_HEIGHT_M1 0x0848 +#define NPU_REG_OFM_DEPTH_M1 0x084C +#define NPU_REG_OFM_PRECISION 0x0850 +#define NPU_REG_OFM_BLK_WIDTH_M1 0x0854 +#define NPU_REG_OFM_BLK_HEIGHT_M1 0x0858 +#define NPU_REG_OFM_BLK_DEPTH_M1 0x085C +#define NPU_REG_OFM_ZERO_POINT 0x0860 +#define NPU_REG_OFM_WIDTH0_M1 0x0868 +#define NPU_REG_OFM_HEIGHT0_M1 0x086C +#define NPU_REG_OFM_HEIGHT1_M1 0x0870 +#define NPU_REG_OFM_REGION 0x087C +#define TSU_OFM_REGISTERS_SIZE 0x0880 + +// +// Register subpage TSU_KERNEL +// +#define NPU_REG_KERNEL_WIDTH_M1 0x0880 +#define NPU_REG_KERNEL_HEIGHT_M1 0x0884 +#define NPU_REG_KERNEL_STRIDE 0x0888 +#define NPU_REG_PARALLEL_MODE 0x088C +#define NPU_REG_ACC_FORMAT 0x0890 +#define NPU_REG_ACTIVATION 0x0894 +#define NPU_REG_ACTIVATION_MIN 0x0898 +#define NPU_REG_ACTIVATION_MAX 0x089C +#define NPU_REG_WEIGHT_REGION 0x08A0 +#define NPU_REG_SCALE_REGION 0x08A4 +#define NPU_REG_AB_START 0x08B4 +#define NPU_REG_BLOCKDEP 0x08BC +#define TSU_KERNEL_REGISTERS_SIZE 0x08C0 + +// +// Register subpage TSU_DMA +// +#define NPU_REG_DMA0_SRC_REGION 0x08C0 +#define NPU_REG_DMA0_DST_REGION 0x08C4 +#define NPU_REG_DMA0_SIZE0 0x08C8 +#define NPU_REG_DMA0_SIZE1 0x08CC +#define TSU_DMA_REGISTERS_SIZE 0x0900 + +// +// Register subpage TSU_IFM2 +// +#define NPU_REG_IFM2_BROADCAST 0x0900 +#define NPU_REG_IFM2_SCALAR 0x0904 +#define NPU_REG_IFM2_PRECISION 0x0914 +#define NPU_REG_IFM2_ZERO_POINT 0x0924 +#define NPU_REG_IFM2_WIDTH0_M1 0x0928 +#define NPU_REG_IFM2_HEIGHT0_M1 0x092C +#define NPU_REG_IFM2_HEIGHT1_M1 0x0930 +#define NPU_REG_IFM2_IB_START 0x0934 +#define NPU_REG_IFM2_REGION 0x093C +#define TSU_IFM2_REGISTERS_SIZE 0x0940 + +// +// Register subpage TSU_IFM_BASE +// +#define NPU_REG_IFM_BASE0 0x0A00 +#define NPU_REG_IFM_BASE0_HI 0x0A04 +#define NPU_REG_IFM_BASE1 0x0A08 +#define NPU_REG_IFM_BASE1_HI 0x0A0C +#define NPU_REG_IFM_BASE2 0x0A10 +#define NPU_REG_IFM_BASE2_HI 0x0A14 +#define NPU_REG_IFM_BASE3 0x0A18 +#define NPU_REG_IFM_BASE3_HI 0x0A1C +#define NPU_REG_IFM_STRIDE_X 0x0A20 +#define NPU_REG_IFM_STRIDE_X_HI 0x0A24 +#define NPU_REG_IFM_STRIDE_Y 0x0A28 +#define NPU_REG_IFM_STRIDE_Y_HI 0x0A2C +#define NPU_REG_IFM_STRIDE_C 0x0A30 +#define NPU_REG_IFM_STRIDE_C_HI 0x0A34 +#define TSU_IFM_BASE_REGISTERS_SIZE 0x0A40 + +// +// Register subpage TSU_OFM_BASE +// +#define NPU_REG_OFM_BASE0 0x0A40 +#define NPU_REG_OFM_BASE0_HI 0x0A44 +#define NPU_REG_OFM_BASE1 0x0A48 +#define NPU_REG_OFM_BASE1_HI 0x0A4C +#define NPU_REG_OFM_BASE2 0x0A50 +#define NPU_REG_OFM_BASE2_HI 0x0A54 +#define NPU_REG_OFM_BASE3 0x0A58 +#define NPU_REG_OFM_BASE3_HI 0x0A5C +#define NPU_REG_OFM_STRIDE_X 0x0A60 +#define NPU_REG_OFM_STRIDE_X_HI 0x0A64 +#define NPU_REG_OFM_STRIDE_Y 0x0A68 +#define NPU_REG_OFM_STRIDE_Y_HI 0x0A6C +#define NPU_REG_OFM_STRIDE_C 0x0A70 +#define NPU_REG_OFM_STRIDE_C_HI 0x0A74 +#define TSU_OFM_BASE_REGISTERS_SIZE 0x0A80 + +// +// Register subpage TSU_WS_BASE +// +#define NPU_REG_WEIGHT_BASE 0x0A80 +#define NPU_REG_WEIGHT_BASE_HI 0x0A84 +#define NPU_REG_WEIGHT_LENGTH 0x0A88 +#define NPU_REG_WEIGHT_LENGTH_HI 0x0A8C +#define NPU_REG_SCALE_BASE 0x0A90 +#define NPU_REG_SCALE_BASE_HI 0x0A94 +#define NPU_REG_SCALE_LENGTH 0x0A98 +#define NPU_REG_SCALE_LENGTH_HI 0x0A9C +#define NPU_REG_OFM_SCALE 0x0AA0 +#define NPU_REG_OFM_SCALE_SHIFT 0x0AA4 +#define NPU_REG_OPA_SCALE 0x0AA8 +#define NPU_REG_OPA_SCALE_SHIFT 0x0AAC +#define NPU_REG_OPB_SCALE 0x0AB0 +#define TSU_WS_BASE_REGISTERS_SIZE 0x0AC0 + +// +// Register subpage TSU_DMA_BASE +// +#define NPU_REG_DMA0_SRC 0x0AC0 +#define NPU_REG_DMA0_SRC_HI 0x0AC4 +#define NPU_REG_DMA0_DST 0x0AC8 +#define NPU_REG_DMA0_DST_HI 0x0ACC +#define NPU_REG_DMA0_LEN 0x0AD0 +#define NPU_REG_DMA0_LEN_HI 0x0AD4 +#define NPU_REG_DMA0_SKIP0 0x0AD8 +#define NPU_REG_DMA0_SKIP0_HI 0x0ADC +#define NPU_REG_DMA0_SKIP1 0x0AE0 +#define NPU_REG_DMA0_SKIP1_HI 0x0AE4 +#define TSU_DMA_BASE_REGISTERS_SIZE 0x0B00 + +// +// Register subpage TSU_IFM2_BASE +// +#define NPU_REG_IFM2_BASE0 0x0B00 +#define NPU_REG_IFM2_BASE0_HI 0x0B04 +#define NPU_REG_IFM2_BASE1 0x0B08 +#define NPU_REG_IFM2_BASE1_HI 0x0B0C +#define NPU_REG_IFM2_BASE2 0x0B10 +#define NPU_REG_IFM2_BASE2_HI 0x0B14 +#define NPU_REG_IFM2_BASE3 0x0B18 +#define NPU_REG_IFM2_BASE3_HI 0x0B1C +#define NPU_REG_IFM2_STRIDE_X 0x0B20 +#define NPU_REG_IFM2_STRIDE_X_HI 0x0B24 +#define NPU_REG_IFM2_STRIDE_Y 0x0B28 +#define NPU_REG_IFM2_STRIDE_Y_HI 0x0B2C +#define NPU_REG_IFM2_STRIDE_C 0x0B30 +#define NPU_REG_IFM2_STRIDE_C_HI 0x0B34 +#define TSU_IFM2_BASE_REGISTERS_SIZE 0x0B40 + +// +// Register subpage TSU_WS1_BASE +// +#define NPU_REG_WEIGHT1_BASE 0x0B40 +#define NPU_REG_WEIGHT1_BASE_HI 0x0B44 +#define NPU_REG_WEIGHT1_LENGTH 0x0B48 +#define NPU_REG_WEIGHT1_LENGTH_HI 0x0B4C +#define NPU_REG_SCALE1_BASE 0x0B50 +#define NPU_REG_SCALE1_BASE_HI 0x0B54 +#define NPU_REG_SCALE1_LENGTH 0x0B58 +#define NPU_REG_SCALE1_LENGTH_HI 0x0B5C +#define TSU_WS1_BASE_REGISTERS_SIZE 0x0B80 + +// +// Register subpage TSU_USER_BASE +// +#define TSU_USER_BASE_REGISTERS_SIZE 0x0BC0 + +// +// Register subpage TSU_DMA_EBASE +// +#define TSU_DMA_EBASE_REGISTERS_SIZE 0x0C00 + +// +// Register subpage ID +// +#define NPU_REG_REVISION 0x0FC0 +#define NPU_REG_PID4 0x0FD0 +#define NPU_REG_PID5 0x0FD4 +#define NPU_REG_PID6 0x0FD8 +#define NPU_REG_PID7 0x0FDC +#define NPU_REG_PID0 0x0FE0 +#define NPU_REG_PID1 0x0FE4 +#define NPU_REG_PID2 0x0FE8 +#define NPU_REG_PID3 0x0FEC +#define NPU_REG_CID0 0x0FF0 +#define NPU_REG_CID1 0x0FF4 +#define NPU_REG_CID2 0x0FF8 +#define NPU_REG_CID3 0x0FFC +#define ID_REGISTERS_SIZE 0x1000 + +#ifdef __cplusplus +// Enum types +enum class acc_format : uint8_t +{ + I32 = 0, + I40 = 1, + F16 = 2, +}; + +enum class activation_clip_range : uint8_t +{ + OFM_PRECISION = 0, + FORCE_UINT8 = 2, + FORCE_INT8 = 3, + FORCE_INT16 = 5, +}; + +enum class activation_format : uint8_t +{ + NHWC = 0, + NHCWB16 = 1, +}; + +enum class activation_function : uint8_t +{ + RELU = 0, + TANH = 3, + SIGMOID = 4, + TABLE_0 = 16, + TABLE_1 = 17, + TABLE_2 = 18, + TABLE_3 = 19, + TABLE_4 = 20, + TABLE_5 = 21, + TABLE_6 = 22, + TABLE_7 = 23, +}; + +enum class activation_precision : uint8_t +{ + B8 = 0, + B16 = 1, + B32 = 2, + B64 = 3, +}; + +enum class activation_type : uint8_t +{ + UNSIGNED = 0, + SIGNED = 1, +}; + +enum class axi_mem_encoding : uint8_t +{ + DEVICE_NON_BUFFERABLE = 0, + DEVICE_BUFFERABLE = 1, + NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + WRITE_THROUGH_NO_ALLOCATE = 4, + WRITE_THROUGH_READ_ALLOCATE = 5, + WRITE_THROUGH_WRITE_ALLOCATE = 6, + WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + WRITE_BACK_NO_ALLOCATE = 8, + WRITE_BACK_READ_ALLOCATE = 9, + WRITE_BACK_WRITE_ALLOCATE = 10, + WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum class broadcast_mode : uint8_t +{ + DISABLE = 0, + ENABLE = 1, +}; + +enum class cmd0_opcode : uint16_t +{ + NPU_OP_STOP = 0, + NPU_OP_IRQ = 1, + NPU_OP_CONV = 2, + NPU_OP_DEPTHWISE = 3, + NPU_OP_POOL = 5, + NPU_OP_ELEMENTWISE = 6, + NPU_OP_DMA_START = 16, + NPU_OP_DMA_WAIT = 17, + NPU_OP_KERNEL_WAIT = 18, + NPU_OP_PMU_MASK = 19, + NPU_SET_IFM_PAD_TOP = 256, + NPU_SET_IFM_PAD_LEFT = 257, + NPU_SET_IFM_PAD_RIGHT = 258, + NPU_SET_IFM_PAD_BOTTOM = 259, + NPU_SET_IFM_DEPTH_M1 = 260, + NPU_SET_IFM_PRECISION = 261, + NPU_SET_IFM_UPSCALE = 263, + NPU_SET_IFM_ZERO_POINT = 265, + NPU_SET_IFM_WIDTH0_M1 = 266, + NPU_SET_IFM_HEIGHT0_M1 = 267, + NPU_SET_IFM_HEIGHT1_M1 = 268, + NPU_SET_IFM_IB_END = 269, + NPU_SET_IFM_REGION = 271, + NPU_SET_OFM_WIDTH_M1 = 273, + NPU_SET_OFM_HEIGHT_M1 = 274, + NPU_SET_OFM_DEPTH_M1 = 275, + NPU_SET_OFM_PRECISION = 276, + NPU_SET_OFM_BLK_WIDTH_M1 = 277, + NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + NPU_SET_OFM_BLK_DEPTH_M1 = 279, + NPU_SET_OFM_ZERO_POINT = 280, + NPU_SET_OFM_WIDTH0_M1 = 282, + NPU_SET_OFM_HEIGHT0_M1 = 283, + NPU_SET_OFM_HEIGHT1_M1 = 284, + NPU_SET_OFM_REGION = 287, + NPU_SET_KERNEL_WIDTH_M1 = 288, + NPU_SET_KERNEL_HEIGHT_M1 = 289, + NPU_SET_KERNEL_STRIDE = 290, + NPU_SET_PARALLEL_MODE = 291, + NPU_SET_ACC_FORMAT = 292, + NPU_SET_ACTIVATION = 293, + NPU_SET_ACTIVATION_MIN = 294, + NPU_SET_ACTIVATION_MAX = 295, + NPU_SET_WEIGHT_REGION = 296, + NPU_SET_SCALE_REGION = 297, + NPU_SET_AB_START = 301, + NPU_SET_BLOCKDEP = 303, + NPU_SET_DMA0_SRC_REGION = 304, + NPU_SET_DMA0_DST_REGION = 305, + NPU_SET_DMA0_SIZE0 = 306, + NPU_SET_DMA0_SIZE1 = 307, + NPU_SET_IFM2_BROADCAST = 384, + NPU_SET_IFM2_SCALAR = 385, + NPU_SET_IFM2_PRECISION = 389, + NPU_SET_IFM2_ZERO_POINT = 393, + NPU_SET_IFM2_WIDTH0_M1 = 394, + NPU_SET_IFM2_HEIGHT0_M1 = 395, + NPU_SET_IFM2_HEIGHT1_M1 = 396, + NPU_SET_IFM2_IB_START = 397, + NPU_SET_IFM2_REGION = 399, +}; + +enum class cmd1_opcode : uint16_t +{ + NPU_SET_IFM_BASE0 = 0, + NPU_SET_IFM_BASE1 = 1, + NPU_SET_IFM_BASE2 = 2, + NPU_SET_IFM_BASE3 = 3, + NPU_SET_IFM_STRIDE_X = 4, + NPU_SET_IFM_STRIDE_Y = 5, + NPU_SET_IFM_STRIDE_C = 6, + NPU_SET_OFM_BASE0 = 16, + NPU_SET_OFM_BASE1 = 17, + NPU_SET_OFM_BASE2 = 18, + NPU_SET_OFM_BASE3 = 19, + NPU_SET_OFM_STRIDE_X = 20, + NPU_SET_OFM_STRIDE_Y = 21, + NPU_SET_OFM_STRIDE_C = 22, + NPU_SET_WEIGHT_BASE = 32, + NPU_SET_WEIGHT_LENGTH = 33, + NPU_SET_SCALE_BASE = 34, + NPU_SET_SCALE_LENGTH = 35, + NPU_SET_OFM_SCALE = 36, + NPU_SET_OPA_SCALE = 37, + NPU_SET_OPB_SCALE = 38, + NPU_SET_DMA0_SRC = 48, + NPU_SET_DMA0_DST = 49, + NPU_SET_DMA0_LEN = 50, + NPU_SET_DMA0_SKIP0 = 51, + NPU_SET_DMA0_SKIP1 = 52, + NPU_SET_IFM2_BASE0 = 128, + NPU_SET_IFM2_BASE1 = 129, + NPU_SET_IFM2_BASE2 = 130, + NPU_SET_IFM2_BASE3 = 131, + NPU_SET_IFM2_STRIDE_X = 132, + NPU_SET_IFM2_STRIDE_Y = 133, + NPU_SET_IFM2_STRIDE_C = 134, + NPU_SET_WEIGHT1_BASE = 144, + NPU_SET_WEIGHT1_LENGTH = 145, + NPU_SET_SCALE1_BASE = 146, + NPU_SET_SCALE1_LENGTH = 147, +}; + +enum class cmd_ctrl : uint8_t +{ + CMD0_CTRL = 0, + CMD1_CTRL = 1, +}; + +enum class custom_dma : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class dma_fault_src : uint8_t +{ + AXI_M0 = 0, + AXI_M1 = 1, +}; + +enum class dma_region_mode : uint8_t +{ + EXTERNAL = 0, + INTERNAL = 1, +}; + +enum class dma_stride_mode : uint8_t +{ + D1 = 0, + D2 = 1, + D3 = 2, +}; + +enum class elementwise_mode : uint8_t +{ + MUL = 0, + ADD = 1, + SUB = 2, + MIN = 3, + MAX = 4, + LRELU = 5, + ABS = 6, + CLZ = 7, + SHR = 8, + SHL = 9, +}; + +enum class functional_safety : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class ifm2_operand_order : uint8_t +{ + ORDER_B = 0, + ORDER_A = 1, +}; + +enum class ifm_scale_mode : uint8_t +{ + OPA_OPB_16 = 0, + OPA_32 = 1, + OPB_32 = 2, +}; + +enum class ifm_upscale_mode : uint8_t +{ + NONE = 0, + NEAREST = 1, + ZEROS = 2, +}; + +enum class kernel_decomposition : uint8_t +{ + D8X8 = 0, + D4X4 = 1, +}; + +enum class kernel_dilation : uint8_t +{ + NONE = 0, + X2 = 1, +}; + +enum class max_beats : uint8_t +{ + B64 = 0, + B128 = 1, + B256 = 2, +}; + +enum class mem_attr : uint8_t +{ + AXI0_OUTSTANDING_COUNTER0 = 0, + AXI0_OUTSTANDING_COUNTER1 = 1, + AXI1_OUTSTANDING_COUNTER2 = 2, + AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum class ofm_scale_mode : uint8_t +{ + PER_CHANNEL = 0, + GLOBAL = 1, +}; + +enum class parallel_mode : uint8_t +{ + SINGLE_CORE = 0, + DUAL_CORE_DEPTH = 1, +}; + +enum class pmu_axi_channel : uint8_t +{ + RD_CMD = 0, + RD_IFM = 1, + RD_WEIGHTS = 2, + RD_SCALE_BIAS = 3, + RD_MEM2MEM = 4, + WR_OFM = 8, + WR_MEM2MEM = 9, +}; + +enum class pmu_event : uint16_t +{ + NO_EVENT = 0, + CYCLE = 17, + NPU_IDLE = 32, + CC_STALLED_ON_BLOCKDEP = 33, + CC_STALLED_ON_SHRAM_RECONFIG = 34, + NPU_ACTIVE = 35, + MAC_ACTIVE = 48, + MAC_ACTIVE_8BIT = 49, + MAC_ACTIVE_16BIT = 50, + MAC_DPU_ACTIVE = 51, + MAC_STALLED_BY_WD_ACC = 52, + MAC_STALLED_BY_WD = 53, + MAC_STALLED_BY_ACC = 54, + MAC_STALLED_BY_IB = 55, + MAC_ACTIVE_32BIT = 56, + MAC_STALLED_BY_INT_W = 57, + MAC_STALLED_BY_INT_ACC = 58, + AO_ACTIVE = 64, + AO_ACTIVE_8BIT = 65, + AO_ACTIVE_16BIT = 66, + AO_STALLED_BY_OFMP_OB = 67, + AO_STALLED_BY_OFMP = 68, + AO_STALLED_BY_OB = 69, + AO_STALLED_BY_ACC_IB = 70, + AO_STALLED_BY_ACC = 71, + AO_STALLED_BY_IB = 72, + WD_ACTIVE = 80, + WD_STALLED = 81, + WD_STALLED_BY_WS = 82, + WD_STALLED_BY_WD_BUF = 83, + WD_PARSE_ACTIVE = 84, + WD_PARSE_STALLED = 85, + WD_PARSE_STALLED_IN = 86, + WD_PARSE_STALLED_OUT = 87, + WD_TRANS_WS = 88, + WD_TRANS_WB = 89, + WD_TRANS_DW0 = 90, + WD_TRANS_DW1 = 91, + AXI0_RD_TRANS_ACCEPTED = 128, + AXI0_RD_TRANS_COMPLETED = 129, + AXI0_RD_DATA_BEAT_RECEIVED = 130, + AXI0_RD_TRAN_REQ_STALLED = 131, + AXI0_WR_TRANS_ACCEPTED = 132, + AXI0_WR_TRANS_COMPLETED_M = 133, + AXI0_WR_TRANS_COMPLETED_S = 134, + AXI0_WR_DATA_BEAT_WRITTEN = 135, + AXI0_WR_TRAN_REQ_STALLED = 136, + AXI0_WR_DATA_BEAT_STALLED = 137, + AXI0_ENABLED_CYCLES = 140, + AXI0_RD_STALL_LIMIT = 142, + AXI0_WR_STALL_LIMIT = 143, + AXI_LATENCY_ANY = 160, + AXI_LATENCY_32 = 161, + AXI_LATENCY_64 = 162, + AXI_LATENCY_128 = 163, + AXI_LATENCY_256 = 164, + AXI_LATENCY_512 = 165, + AXI_LATENCY_1024 = 166, + ECC_DMA = 176, + ECC_SB0 = 177, + AXI1_RD_TRANS_ACCEPTED = 384, + AXI1_RD_TRANS_COMPLETED = 385, + AXI1_RD_DATA_BEAT_RECEIVED = 386, + AXI1_RD_TRAN_REQ_STALLED = 387, + AXI1_WR_TRANS_ACCEPTED = 388, + AXI1_WR_TRANS_COMPLETED_M = 389, + AXI1_WR_TRANS_COMPLETED_S = 390, + AXI1_WR_DATA_BEAT_WRITTEN = 391, + AXI1_WR_TRAN_REQ_STALLED = 392, + AXI1_WR_DATA_BEAT_STALLED = 393, + AXI1_ENABLED_CYCLES = 396, + AXI1_RD_STALL_LIMIT = 398, + AXI1_WR_STALL_LIMIT = 399, + ECC_SB1 = 433, +}; + +enum class pooling_mode : uint8_t +{ + MAX = 0, + AVERAGE = 1, + REDUCE_SUM = 2, +}; + +enum class privilege_level : uint8_t +{ + USER = 0, + PRIVILEGED = 1, +}; + +enum class round_mode : uint8_t +{ + DBL = 0, + TRUNCATE = 1, + NATURAL = 2, +}; + +enum class security_level : uint8_t +{ + SECURE = 0, + NON_SECURE = 1, +}; + +enum class state : uint8_t +{ + STOPPED = 0, + RUNNING = 1, +}; + +enum class wd_core_slice_state : uint8_t +{ + HEADER = 0, + PALETTE = 1, + WEIGHTS = 2, +}; + +enum class wd_ctrl_state : uint8_t +{ + IDLE = 0, + DRAIN = 1, + OFD_INIT = 2, + OFD_RUN = 3, +}; + +enum class weight_order : uint8_t +{ + DEPTH_FIRST = 0, + PART_KERNEL_FIRST = 1, +}; + +#else + +enum acc_format +{ + ACC_FORMAT_I32 = 0, + ACC_FORMAT_I40 = 1, + ACC_FORMAT_F16 = 2, +}; + +enum activation_clip_range +{ + ACTIVATION_CLIP_RANGE_OFM_PRECISION = 0, + ACTIVATION_CLIP_RANGE_FORCE_UINT8 = 2, + ACTIVATION_CLIP_RANGE_FORCE_INT8 = 3, + ACTIVATION_CLIP_RANGE_FORCE_INT16 = 5, +}; + +enum activation_format +{ + ACTIVATION_FORMAT_NHWC = 0, + ACTIVATION_FORMAT_NHCWB16 = 1, +}; + +enum activation_function +{ + ACTIVATION_FUNCTION_RELU = 0, + ACTIVATION_FUNCTION_TANH = 3, + ACTIVATION_FUNCTION_SIGMOID = 4, + ACTIVATION_FUNCTION_TABLE_0 = 16, + ACTIVATION_FUNCTION_TABLE_1 = 17, + ACTIVATION_FUNCTION_TABLE_2 = 18, + ACTIVATION_FUNCTION_TABLE_3 = 19, + ACTIVATION_FUNCTION_TABLE_4 = 20, + ACTIVATION_FUNCTION_TABLE_5 = 21, + ACTIVATION_FUNCTION_TABLE_6 = 22, + ACTIVATION_FUNCTION_TABLE_7 = 23, +}; + +enum activation_precision +{ + ACTIVATION_PRECISION_B8 = 0, + ACTIVATION_PRECISION_B16 = 1, + ACTIVATION_PRECISION_B32 = 2, + ACTIVATION_PRECISION_B64 = 3, +}; + +enum activation_type +{ + ACTIVATION_TYPE_UNSIGNED = 0, + ACTIVATION_TYPE_SIGNED = 1, +}; + +enum axi_mem_encoding +{ + AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE = 0, + AXI_MEM_ENCODING_DEVICE_BUFFERABLE = 1, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE = 4, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE = 5, + AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE = 6, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE = 8, + AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE = 9, + AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE = 10, + AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum broadcast_mode +{ + BROADCAST_MODE_DISABLE = 0, + BROADCAST_MODE_ENABLE = 1, +}; + +enum cmd0_opcode +{ + CMD0_OPCODE_NPU_OP_STOP = 0, + CMD0_OPCODE_NPU_OP_IRQ = 1, + CMD0_OPCODE_NPU_OP_CONV = 2, + CMD0_OPCODE_NPU_OP_DEPTHWISE = 3, + CMD0_OPCODE_NPU_OP_POOL = 5, + CMD0_OPCODE_NPU_OP_ELEMENTWISE = 6, + CMD0_OPCODE_NPU_OP_DMA_START = 16, + CMD0_OPCODE_NPU_OP_DMA_WAIT = 17, + CMD0_OPCODE_NPU_OP_KERNEL_WAIT = 18, + CMD0_OPCODE_NPU_OP_PMU_MASK = 19, + CMD0_OPCODE_NPU_SET_IFM_PAD_TOP = 256, + CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT = 257, + CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT = 258, + CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM = 259, + CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1 = 260, + CMD0_OPCODE_NPU_SET_IFM_PRECISION = 261, + CMD0_OPCODE_NPU_SET_IFM_UPSCALE = 263, + CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT = 265, + CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1 = 266, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1 = 267, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1 = 268, + CMD0_OPCODE_NPU_SET_IFM_IB_END = 269, + CMD0_OPCODE_NPU_SET_IFM_REGION = 271, + CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1 = 273, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1 = 274, + CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1 = 275, + CMD0_OPCODE_NPU_SET_OFM_PRECISION = 276, + CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1 = 277, + CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1 = 279, + CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT = 280, + CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1 = 282, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1 = 283, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1 = 284, + CMD0_OPCODE_NPU_SET_OFM_REGION = 287, + CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1 = 288, + CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1 = 289, + CMD0_OPCODE_NPU_SET_KERNEL_STRIDE = 290, + CMD0_OPCODE_NPU_SET_PARALLEL_MODE = 291, + CMD0_OPCODE_NPU_SET_ACC_FORMAT = 292, + CMD0_OPCODE_NPU_SET_ACTIVATION = 293, + CMD0_OPCODE_NPU_SET_ACTIVATION_MIN = 294, + CMD0_OPCODE_NPU_SET_ACTIVATION_MAX = 295, + CMD0_OPCODE_NPU_SET_WEIGHT_REGION = 296, + CMD0_OPCODE_NPU_SET_SCALE_REGION = 297, + CMD0_OPCODE_NPU_SET_AB_START = 301, + CMD0_OPCODE_NPU_SET_BLOCKDEP = 303, + CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION = 304, + CMD0_OPCODE_NPU_SET_DMA0_DST_REGION = 305, + CMD0_OPCODE_NPU_SET_DMA0_SIZE0 = 306, + CMD0_OPCODE_NPU_SET_DMA0_SIZE1 = 307, + CMD0_OPCODE_NPU_SET_IFM2_BROADCAST = 384, + CMD0_OPCODE_NPU_SET_IFM2_SCALAR = 385, + CMD0_OPCODE_NPU_SET_IFM2_PRECISION = 389, + CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT = 393, + CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1 = 394, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1 = 395, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1 = 396, + CMD0_OPCODE_NPU_SET_IFM2_IB_START = 397, + CMD0_OPCODE_NPU_SET_IFM2_REGION = 399, +}; + +enum cmd1_opcode +{ + CMD1_OPCODE_NPU_SET_IFM_BASE0 = 0, + CMD1_OPCODE_NPU_SET_IFM_BASE1 = 1, + CMD1_OPCODE_NPU_SET_IFM_BASE2 = 2, + CMD1_OPCODE_NPU_SET_IFM_BASE3 = 3, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_X = 4, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y = 5, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_C = 6, + CMD1_OPCODE_NPU_SET_OFM_BASE0 = 16, + CMD1_OPCODE_NPU_SET_OFM_BASE1 = 17, + CMD1_OPCODE_NPU_SET_OFM_BASE2 = 18, + CMD1_OPCODE_NPU_SET_OFM_BASE3 = 19, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_X = 20, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y = 21, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_C = 22, + CMD1_OPCODE_NPU_SET_WEIGHT_BASE = 32, + CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH = 33, + CMD1_OPCODE_NPU_SET_SCALE_BASE = 34, + CMD1_OPCODE_NPU_SET_SCALE_LENGTH = 35, + CMD1_OPCODE_NPU_SET_OFM_SCALE = 36, + CMD1_OPCODE_NPU_SET_OPA_SCALE = 37, + CMD1_OPCODE_NPU_SET_OPB_SCALE = 38, + CMD1_OPCODE_NPU_SET_DMA0_SRC = 48, + CMD1_OPCODE_NPU_SET_DMA0_DST = 49, + CMD1_OPCODE_NPU_SET_DMA0_LEN = 50, + CMD1_OPCODE_NPU_SET_DMA0_SKIP0 = 51, + CMD1_OPCODE_NPU_SET_DMA0_SKIP1 = 52, + CMD1_OPCODE_NPU_SET_IFM2_BASE0 = 128, + CMD1_OPCODE_NPU_SET_IFM2_BASE1 = 129, + CMD1_OPCODE_NPU_SET_IFM2_BASE2 = 130, + CMD1_OPCODE_NPU_SET_IFM2_BASE3 = 131, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X = 132, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y = 133, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C = 134, + CMD1_OPCODE_NPU_SET_WEIGHT1_BASE = 144, + CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH = 145, + CMD1_OPCODE_NPU_SET_SCALE1_BASE = 146, + CMD1_OPCODE_NPU_SET_SCALE1_LENGTH = 147, +}; + +enum cmd_ctrl +{ + CMD_CTRL_CMD0_CTRL = 0, + CMD_CTRL_CMD1_CTRL = 1, +}; + +enum custom_dma +{ + CUSTOM_DMA_NOT_IMPLEMENTED = 0, + CUSTOM_DMA_IMPLEMENTED = 1, +}; + +enum dma_fault_src +{ + DMA_FAULT_SRC_AXI_M0 = 0, + DMA_FAULT_SRC_AXI_M1 = 1, +}; + +enum dma_region_mode +{ + DMA_REGION_MODE_EXTERNAL = 0, + DMA_REGION_MODE_INTERNAL = 1, +}; + +enum dma_stride_mode +{ + DMA_STRIDE_MODE_D1 = 0, + DMA_STRIDE_MODE_D2 = 1, + DMA_STRIDE_MODE_D3 = 2, +}; + +enum elementwise_mode +{ + ELEMENTWISE_MODE_MUL = 0, + ELEMENTWISE_MODE_ADD = 1, + ELEMENTWISE_MODE_SUB = 2, + ELEMENTWISE_MODE_MIN = 3, + ELEMENTWISE_MODE_MAX = 4, + ELEMENTWISE_MODE_LRELU = 5, + ELEMENTWISE_MODE_ABS = 6, + ELEMENTWISE_MODE_CLZ = 7, + ELEMENTWISE_MODE_SHR = 8, + ELEMENTWISE_MODE_SHL = 9, +}; + +enum functional_safety +{ + FUNCTIONAL_SAFETY_NOT_IMPLEMENTED = 0, + FUNCTIONAL_SAFETY_IMPLEMENTED = 1, +}; + +enum ifm2_operand_order +{ + IFM2_OPERAND_ORDER_ORDER_B = 0, + IFM2_OPERAND_ORDER_ORDER_A = 1, +}; + +enum ifm_scale_mode +{ + IFM_SCALE_MODE_OPA_OPB_16 = 0, + IFM_SCALE_MODE_OPA_32 = 1, + IFM_SCALE_MODE_OPB_32 = 2, +}; + +enum ifm_upscale_mode +{ + IFM_UPSCALE_MODE_NONE = 0, + IFM_UPSCALE_MODE_NEAREST = 1, + IFM_UPSCALE_MODE_ZEROS = 2, +}; + +enum kernel_decomposition +{ + KERNEL_DECOMPOSITION_D8X8 = 0, + KERNEL_DECOMPOSITION_D4X4 = 1, +}; + +enum kernel_dilation +{ + KERNEL_DILATION_NONE = 0, + KERNEL_DILATION_X2 = 1, +}; + +enum max_beats +{ + MAX_BEATS_B64 = 0, + MAX_BEATS_B128 = 1, + MAX_BEATS_B256 = 2, +}; + +enum mem_attr +{ + MEM_ATTR_AXI0_OUTSTANDING_COUNTER0 = 0, + MEM_ATTR_AXI0_OUTSTANDING_COUNTER1 = 1, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER2 = 2, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum ofm_scale_mode +{ + OFM_SCALE_MODE_PER_CHANNEL = 0, + OFM_SCALE_MODE_GLOBAL = 1, +}; + +enum parallel_mode +{ + PARALLEL_MODE_SINGLE_CORE = 0, + PARALLEL_MODE_DUAL_CORE_DEPTH = 1, +}; + +enum pmu_axi_channel +{ + PMU_AXI_CHANNEL_RD_CMD = 0, + PMU_AXI_CHANNEL_RD_IFM = 1, + PMU_AXI_CHANNEL_RD_WEIGHTS = 2, + PMU_AXI_CHANNEL_RD_SCALE_BIAS = 3, + PMU_AXI_CHANNEL_RD_MEM2MEM = 4, + PMU_AXI_CHANNEL_WR_OFM = 8, + PMU_AXI_CHANNEL_WR_MEM2MEM = 9, +}; + +enum pmu_event +{ + PMU_EVENT_NO_EVENT = 0, + PMU_EVENT_CYCLE = 17, + PMU_EVENT_NPU_IDLE = 32, + PMU_EVENT_CC_STALLED_ON_BLOCKDEP = 33, + PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG = 34, + PMU_EVENT_NPU_ACTIVE = 35, + PMU_EVENT_MAC_ACTIVE = 48, + PMU_EVENT_MAC_ACTIVE_8BIT = 49, + PMU_EVENT_MAC_ACTIVE_16BIT = 50, + PMU_EVENT_MAC_DPU_ACTIVE = 51, + PMU_EVENT_MAC_STALLED_BY_WD_ACC = 52, + PMU_EVENT_MAC_STALLED_BY_WD = 53, + PMU_EVENT_MAC_STALLED_BY_ACC = 54, + PMU_EVENT_MAC_STALLED_BY_IB = 55, + PMU_EVENT_MAC_ACTIVE_32BIT = 56, + PMU_EVENT_MAC_STALLED_BY_INT_W = 57, + PMU_EVENT_MAC_STALLED_BY_INT_ACC = 58, + PMU_EVENT_AO_ACTIVE = 64, + PMU_EVENT_AO_ACTIVE_8BIT = 65, + PMU_EVENT_AO_ACTIVE_16BIT = 66, + PMU_EVENT_AO_STALLED_BY_OFMP_OB = 67, + PMU_EVENT_AO_STALLED_BY_OFMP = 68, + PMU_EVENT_AO_STALLED_BY_OB = 69, + PMU_EVENT_AO_STALLED_BY_ACC_IB = 70, + PMU_EVENT_AO_STALLED_BY_ACC = 71, + PMU_EVENT_AO_STALLED_BY_IB = 72, + PMU_EVENT_WD_ACTIVE = 80, + PMU_EVENT_WD_STALLED = 81, + PMU_EVENT_WD_STALLED_BY_WS = 82, + PMU_EVENT_WD_STALLED_BY_WD_BUF = 83, + PMU_EVENT_WD_PARSE_ACTIVE = 84, + PMU_EVENT_WD_PARSE_STALLED = 85, + PMU_EVENT_WD_PARSE_STALLED_IN = 86, + PMU_EVENT_WD_PARSE_STALLED_OUT = 87, + PMU_EVENT_WD_TRANS_WS = 88, + PMU_EVENT_WD_TRANS_WB = 89, + PMU_EVENT_WD_TRANS_DW0 = 90, + PMU_EVENT_WD_TRANS_DW1 = 91, + PMU_EVENT_AXI0_RD_TRANS_ACCEPTED = 128, + PMU_EVENT_AXI0_RD_TRANS_COMPLETED = 129, + PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED = 130, + PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED = 131, + PMU_EVENT_AXI0_WR_TRANS_ACCEPTED = 132, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M = 133, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S = 134, + PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN = 135, + PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED = 136, + PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED = 137, + PMU_EVENT_AXI0_ENABLED_CYCLES = 140, + PMU_EVENT_AXI0_RD_STALL_LIMIT = 142, + PMU_EVENT_AXI0_WR_STALL_LIMIT = 143, + PMU_EVENT_AXI_LATENCY_ANY = 160, + PMU_EVENT_AXI_LATENCY_32 = 161, + PMU_EVENT_AXI_LATENCY_64 = 162, + PMU_EVENT_AXI_LATENCY_128 = 163, + PMU_EVENT_AXI_LATENCY_256 = 164, + PMU_EVENT_AXI_LATENCY_512 = 165, + PMU_EVENT_AXI_LATENCY_1024 = 166, + PMU_EVENT_ECC_DMA = 176, + PMU_EVENT_ECC_SB0 = 177, + PMU_EVENT_AXI1_RD_TRANS_ACCEPTED = 384, + PMU_EVENT_AXI1_RD_TRANS_COMPLETED = 385, + PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED = 386, + PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED = 387, + PMU_EVENT_AXI1_WR_TRANS_ACCEPTED = 388, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M = 389, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S = 390, + PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN = 391, + PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED = 392, + PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED = 393, + PMU_EVENT_AXI1_ENABLED_CYCLES = 396, + PMU_EVENT_AXI1_RD_STALL_LIMIT = 398, + PMU_EVENT_AXI1_WR_STALL_LIMIT = 399, + PMU_EVENT_ECC_SB1 = 433, +}; + +enum pooling_mode +{ + POOLING_MODE_MAX = 0, + POOLING_MODE_AVERAGE = 1, + POOLING_MODE_REDUCE_SUM = 2, +}; + +enum privilege_level +{ + PRIVILEGE_LEVEL_USER = 0, + PRIVILEGE_LEVEL_PRIVILEGED = 1, +}; + +enum round_mode +{ + ROUND_MODE_DBL = 0, + ROUND_MODE_TRUNCATE = 1, + ROUND_MODE_NATURAL = 2, +}; + +enum security_level +{ + SECURITY_LEVEL_SECURE = 0, + SECURITY_LEVEL_NON_SECURE = 1, +}; + +enum state +{ + STATE_STOPPED = 0, + STATE_RUNNING = 1, +}; + +enum wd_core_slice_state +{ + WD_CORE_SLICE_STATE_HEADER = 0, + WD_CORE_SLICE_STATE_PALETTE = 1, + WD_CORE_SLICE_STATE_WEIGHTS = 2, +}; + +enum wd_ctrl_state +{ + WD_CTRL_STATE_IDLE = 0, + WD_CTRL_STATE_DRAIN = 1, + WD_CTRL_STATE_OFD_INIT = 2, + WD_CTRL_STATE_OFD_RUN = 3, +}; + +enum weight_order +{ + WEIGHT_ORDER_DEPTH_FIRST = 0, + WEIGHT_ORDER_PART_KERNEL_FIRST = 1, +}; + +#endif + +#ifdef NPU_DISASSEMBLE + +static const char *acc_format_str[] = { + "ACC_FORMAT_I32", + "ACC_FORMAT_I40", + "ACC_FORMAT_F16", +}; + +static const char *activation_clip_range_str[] = { + "ACTIVATION_CLIP_RANGE_OFM_PRECISION", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_UINT8", + "ACTIVATION_CLIP_RANGE_FORCE_INT8", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_INT16", +}; + +static const char *activation_format_str[] = { + "ACTIVATION_FORMAT_NHWC", + "ACTIVATION_FORMAT_NHCWB16", +}; + +static const char *activation_function_str[] = { + "ACTIVATION_FUNCTION_RELU", + "****", + "****", + "ACTIVATION_FUNCTION_TANH", + "ACTIVATION_FUNCTION_SIGMOID", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "ACTIVATION_FUNCTION_TABLE_0", + "ACTIVATION_FUNCTION_TABLE_1", + "ACTIVATION_FUNCTION_TABLE_2", + "ACTIVATION_FUNCTION_TABLE_3", + "ACTIVATION_FUNCTION_TABLE_4", + "ACTIVATION_FUNCTION_TABLE_5", + "ACTIVATION_FUNCTION_TABLE_6", + "ACTIVATION_FUNCTION_TABLE_7", +}; + +static const char *activation_precision_str[] = { + "ACTIVATION_PRECISION_B8", + "ACTIVATION_PRECISION_B16", + "ACTIVATION_PRECISION_B32", + "ACTIVATION_PRECISION_B64", +}; + +static const char *activation_type_str[] = { + "ACTIVATION_TYPE_UNSIGNED", + "ACTIVATION_TYPE_SIGNED", +}; + +static const char *axi_mem_encoding_str[] = { + "AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_DEVICE_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE", + "AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE", +}; + +static const char *broadcast_mode_str[] = { + "BROADCAST_MODE_DISABLE", + "BROADCAST_MODE_ENABLE", +}; + +static const char *cmd0_opcode_str[] = { + "CMD0_OPCODE_NPU_OP_STOP", + "CMD0_OPCODE_NPU_OP_IRQ", + "CMD0_OPCODE_NPU_OP_CONV", + "CMD0_OPCODE_NPU_OP_DEPTHWISE", + "****", + "CMD0_OPCODE_NPU_OP_POOL", + "CMD0_OPCODE_NPU_OP_ELEMENTWISE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_OP_DMA_START", + "CMD0_OPCODE_NPU_OP_DMA_WAIT", + "CMD0_OPCODE_NPU_OP_KERNEL_WAIT", + "CMD0_OPCODE_NPU_OP_PMU_MASK", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_PAD_TOP", + "CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM", + "CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_IFM_PRECISION", + "****", + "CMD0_OPCODE_NPU_SET_IFM_UPSCALE", + "****", + "CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM_IB_END", + "****", + "CMD0_OPCODE_NPU_SET_IFM_REGION", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_PRECISION", + "CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_OFM_REGION", + "CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_STRIDE", + "CMD0_OPCODE_NPU_SET_PARALLEL_MODE", + "CMD0_OPCODE_NPU_SET_ACC_FORMAT", + "CMD0_OPCODE_NPU_SET_ACTIVATION", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MIN", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MAX", + "CMD0_OPCODE_NPU_SET_WEIGHT_REGION", + "CMD0_OPCODE_NPU_SET_SCALE_REGION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_AB_START", + "****", + "CMD0_OPCODE_NPU_SET_BLOCKDEP", + "CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_DST_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE0", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_BROADCAST", + "CMD0_OPCODE_NPU_SET_IFM2_SCALAR", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_PRECISION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM2_IB_START", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_REGION", +}; + +static const char *cmd1_opcode_str[] = { + "CMD1_OPCODE_NPU_SET_IFM_BASE0", + "CMD1_OPCODE_NPU_SET_IFM_BASE1", + "CMD1_OPCODE_NPU_SET_IFM_BASE2", + "CMD1_OPCODE_NPU_SET_IFM_BASE3", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_OFM_BASE0", + "CMD1_OPCODE_NPU_SET_OFM_BASE1", + "CMD1_OPCODE_NPU_SET_OFM_BASE2", + "CMD1_OPCODE_NPU_SET_OFM_BASE3", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE_BASE", + "CMD1_OPCODE_NPU_SET_SCALE_LENGTH", + "CMD1_OPCODE_NPU_SET_OFM_SCALE", + "CMD1_OPCODE_NPU_SET_OPA_SCALE", + "CMD1_OPCODE_NPU_SET_OPB_SCALE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_DMA0_SRC", + "CMD1_OPCODE_NPU_SET_DMA0_DST", + "CMD1_OPCODE_NPU_SET_DMA0_LEN", + "CMD1_OPCODE_NPU_SET_DMA0_SKIP0", + "CMD1_OPCODE_NPU_SET_DMA0_SKIP1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_IFM2_BASE0", + "CMD1_OPCODE_NPU_SET_IFM2_BASE1", + "CMD1_OPCODE_NPU_SET_IFM2_BASE2", + "CMD1_OPCODE_NPU_SET_IFM2_BASE3", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT1_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE1_BASE", + "CMD1_OPCODE_NPU_SET_SCALE1_LENGTH", +}; + +static const char *cmd_ctrl_str[] = { + "CMD_CTRL_CMD0_CTRL", + "CMD_CTRL_CMD1_CTRL", +}; + +static const char *custom_dma_str[] = { + "CUSTOM_DMA_NOT_IMPLEMENTED", + "CUSTOM_DMA_IMPLEMENTED", +}; + +static const char *dma_fault_src_str[] = { + "DMA_FAULT_SRC_AXI_M0", + "DMA_FAULT_SRC_AXI_M1", +}; + +static const char *dma_region_mode_str[] = { + "DMA_REGION_MODE_EXTERNAL", + "DMA_REGION_MODE_INTERNAL", +}; + +static const char *dma_stride_mode_str[] = { + "DMA_STRIDE_MODE_D1", + "DMA_STRIDE_MODE_D2", + "DMA_STRIDE_MODE_D3", +}; + +static const char *elementwise_mode_str[] = { + "ELEMENTWISE_MODE_MUL", + "ELEMENTWISE_MODE_ADD", + "ELEMENTWISE_MODE_SUB", + "ELEMENTWISE_MODE_MIN", + "ELEMENTWISE_MODE_MAX", + "ELEMENTWISE_MODE_LRELU", + "ELEMENTWISE_MODE_ABS", + "ELEMENTWISE_MODE_CLZ", + "ELEMENTWISE_MODE_SHR", + "ELEMENTWISE_MODE_SHL", +}; + +static const char *functional_safety_str[] = { + "FUNCTIONAL_SAFETY_NOT_IMPLEMENTED", + "FUNCTIONAL_SAFETY_IMPLEMENTED", +}; + +static const char *ifm2_operand_order_str[] = { + "IFM2_OPERAND_ORDER_ORDER_B", + "IFM2_OPERAND_ORDER_ORDER_A", +}; + +static const char *ifm_scale_mode_str[] = { + "IFM_SCALE_MODE_OPA_OPB_16", + "IFM_SCALE_MODE_OPA_32", + "IFM_SCALE_MODE_OPB_32", +}; + +static const char *ifm_upscale_mode_str[] = { + "IFM_UPSCALE_MODE_NONE", + "IFM_UPSCALE_MODE_NEAREST", + "IFM_UPSCALE_MODE_ZEROS", +}; + +static const char *kernel_decomposition_str[] = { + "KERNEL_DECOMPOSITION_D8X8", + "KERNEL_DECOMPOSITION_D4X4", +}; + +static const char *kernel_dilation_str[] = { + "KERNEL_DILATION_NONE", + "KERNEL_DILATION_X2", +}; + +static const char *max_beats_str[] = { + "MAX_BEATS_B64", + "MAX_BEATS_B128", + "MAX_BEATS_B256", +}; + +static const char *mem_attr_str[] = { + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER0", + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER1", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER2", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER3", +}; + +static const char *ofm_scale_mode_str[] = { + "OFM_SCALE_MODE_PER_CHANNEL", + "OFM_SCALE_MODE_GLOBAL", +}; + +static const char *parallel_mode_str[] = { + "PARALLEL_MODE_SINGLE_CORE", + "PARALLEL_MODE_DUAL_CORE_DEPTH", +}; + +static const char *pmu_axi_channel_str[] = { + "PMU_AXI_CHANNEL_RD_CMD", + "PMU_AXI_CHANNEL_RD_IFM", + "PMU_AXI_CHANNEL_RD_WEIGHTS", + "PMU_AXI_CHANNEL_RD_SCALE_BIAS", + "PMU_AXI_CHANNEL_RD_MEM2MEM", + "****", + "****", + "****", + "PMU_AXI_CHANNEL_WR_OFM", + "PMU_AXI_CHANNEL_WR_MEM2MEM", +}; + +static const char *pmu_event_str[] = { + "PMU_EVENT_NO_EVENT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_CYCLE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_NPU_IDLE", + "PMU_EVENT_CC_STALLED_ON_BLOCKDEP", + "PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG", + "PMU_EVENT_NPU_ACTIVE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_MAC_ACTIVE", + "PMU_EVENT_MAC_ACTIVE_8BIT", + "PMU_EVENT_MAC_ACTIVE_16BIT", + "PMU_EVENT_MAC_DPU_ACTIVE", + "PMU_EVENT_MAC_STALLED_BY_WD_ACC", + "PMU_EVENT_MAC_STALLED_BY_WD", + "PMU_EVENT_MAC_STALLED_BY_ACC", + "PMU_EVENT_MAC_STALLED_BY_IB", + "PMU_EVENT_MAC_ACTIVE_32BIT", + "PMU_EVENT_MAC_STALLED_BY_INT_W", + "PMU_EVENT_MAC_STALLED_BY_INT_ACC", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AO_ACTIVE", + "PMU_EVENT_AO_ACTIVE_8BIT", + "PMU_EVENT_AO_ACTIVE_16BIT", + "PMU_EVENT_AO_STALLED_BY_OFMP_OB", + "PMU_EVENT_AO_STALLED_BY_OFMP", + "PMU_EVENT_AO_STALLED_BY_OB", + "PMU_EVENT_AO_STALLED_BY_ACC_IB", + "PMU_EVENT_AO_STALLED_BY_ACC", + "PMU_EVENT_AO_STALLED_BY_IB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_ACTIVE", + "PMU_EVENT_WD_STALLED", + "PMU_EVENT_WD_STALLED_BY_WS", + "PMU_EVENT_WD_STALLED_BY_WD_BUF", + "PMU_EVENT_WD_PARSE_ACTIVE", + "PMU_EVENT_WD_PARSE_STALLED", + "PMU_EVENT_WD_PARSE_STALLED_IN", + "PMU_EVENT_WD_PARSE_STALLED_OUT", + "PMU_EVENT_WD_TRANS_WS", + "PMU_EVENT_WD_TRANS_WB", + "PMU_EVENT_WD_TRANS_DW0", + "PMU_EVENT_WD_TRANS_DW1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI0_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI0_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI0_RD_STALL_LIMIT", + "PMU_EVENT_AXI0_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI_LATENCY_ANY", + "PMU_EVENT_AXI_LATENCY_32", + "PMU_EVENT_AXI_LATENCY_64", + "PMU_EVENT_AXI_LATENCY_128", + "PMU_EVENT_AXI_LATENCY_256", + "PMU_EVENT_AXI_LATENCY_512", + "PMU_EVENT_AXI_LATENCY_1024", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_DMA", + "PMU_EVENT_ECC_SB0", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI1_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI1_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI1_RD_STALL_LIMIT", + "PMU_EVENT_AXI1_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_SB1", +}; + +static const char *pooling_mode_str[] = { + "POOLING_MODE_MAX", + "POOLING_MODE_AVERAGE", + "POOLING_MODE_REDUCE_SUM", +}; + +static const char *privilege_level_str[] = { + "PRIVILEGE_LEVEL_USER", + "PRIVILEGE_LEVEL_PRIVILEGED", +}; + +static const char *round_mode_str[] = { + "ROUND_MODE_DBL", + "ROUND_MODE_TRUNCATE", + "ROUND_MODE_NATURAL", +}; + +static const char *security_level_str[] = { + "SECURITY_LEVEL_SECURE", + "SECURITY_LEVEL_NON_SECURE", +}; + +static const char *state_str[] = { + "STATE_STOPPED", + "STATE_RUNNING", +}; + +static const char *wd_core_slice_state_str[] = { + "WD_CORE_SLICE_STATE_HEADER", + "WD_CORE_SLICE_STATE_PALETTE", + "WD_CORE_SLICE_STATE_WEIGHTS", +}; + +static const char *wd_ctrl_state_str[] = { + "WD_CTRL_STATE_IDLE", + "WD_CTRL_STATE_DRAIN", + "WD_CTRL_STATE_OFD_INIT", + "WD_CTRL_STATE_OFD_RUN", +}; + +static const char *weight_order_str[] = { + "WEIGHT_ORDER_DEPTH_FIRST", + "WEIGHT_ORDER_PART_KERNEL_FIRST", +}; + +#endif + +// Register type structs +// id_r - ID register +struct id_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t version_status : 4; // This is the version of the product + uint32_t version_minor : 4; // This is the n for the P part of an RnPn release number + uint32_t version_major : 4; // This is the n for the R part of an RnPn release number + uint32_t product_major : 4; // Product major ID number (unique per base product) + uint32_t arch_patch_rev : 4; // This is the patch number of the architecture version a.b + uint32_t + arch_minor_rev : 8; // This is the minor architecture version number, b in the architecture version a.b + uint32_t + arch_major_rev : 4; // This is the major architecture version number, a in the architecture version a.b + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR id_r() : word0(268853249) {} + CONSTEXPR id_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + id_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_version_status() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_version_status() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR id_r &set_version_status(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile id_r &set_version_status(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_version_minor() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_version_minor() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR id_r &set_version_minor(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile id_r &set_version_minor(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_version_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + uint32_t get_version_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR id_r &set_version_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + volatile id_r &set_version_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_product_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_product_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR id_r &set_product_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile id_r &set_product_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_arch_patch_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + uint32_t get_arch_patch_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR id_r &set_arch_patch_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + volatile id_r &set_arch_patch_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_arch_minor_rev() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + uint32_t get_arch_minor_rev() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR id_r &set_arch_minor_rev(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + volatile id_r &set_arch_minor_rev(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_arch_major_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_arch_major_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR id_r &set_arch_major_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile id_r &set_arch_major_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// status_r - Register describes the current operating status of the NPU +struct status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t state : 1; // NPU state, 0 = Stopped, 1 = Running + uint32_t irq_raised : 1; // Raw IRQ status, 0 = IRQ not raised, 1 = IRQ raised. IRQ is cleared using command + // register bit 1 + uint32_t + bus_status : 1; // 0=OK, 1=Bus abort detected and processing halted (NPU will reach IDLE state and not + // to start process any more commands/AXI transactions). Can only be cleared by a reset + uint32_t reset_status : 1; // Reset is ongoing and only this register can be read (other registers read as 0 + // and writes are ignored.) A value of 0 means NPU is not being reset and can be + // accessed as normal + uint32_t + cmd_parse_error : 1; // 0=No error 1=Command stream parsing error detected. Can only be cleared by reset + uint32_t cmd_end_reached : 1; // 0=Not reached, 1=Reached. Cleared by writing QBASE or QSIZE when NPU is in + // stopped state + uint32_t pmu_irq_raised : 1; // 0=No PMU IRQ, 1=PMU IRQ raised. Cleared by using command register bit 1 + uint32_t wd_fault : 1; // Weight decoder state: 0=no fault 1=weight decoder decompression fault. Can only be + // cleared by reset + uint32_t ecc_fault : 1; // ECC state for internal RAMs: 0=no fault 1=ECC fault signalled. Can only be + // cleared by reset + uint32_t reserved0 : 2; + uint32_t faulting_interface : 1; // Faulting interface on bus abort + uint32_t faulting_channel : 4; // Faulting channel on a bus abort. Read: 0=Cmd 1=IFM 2=Weights 3=Scale+Bias + // 4=Mem2Mem; Write: 8=OFM 9=Mem2Mem + uint32_t irq_history_mask : 16; // IRQ History mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR status_r() : word0(8) {} + CONSTEXPR status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::state get_state() const + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::state get_state() const volatile + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR status_r &set_state(NPU_NAMESPACE::state value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile status_r &set_state(NPU_NAMESPACE::state value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR status_r &set_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile status_r &set_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_bus_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_bus_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR status_r &set_bus_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile status_r &set_bus_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_reset_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_reset_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR status_r &set_reset_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile status_r &set_reset_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_parse_error() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_parse_error() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR status_r &set_cmd_parse_error(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile status_r &set_cmd_parse_error(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_end_reached() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_end_reached() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR status_r &set_cmd_end_reached(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile status_r &set_cmd_end_reached(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_pmu_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_pmu_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR status_r &set_pmu_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile status_r &set_pmu_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wd_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wd_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR status_r &set_wd_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile status_r &set_wd_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ecc_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ecc_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR status_r &set_ecc_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile status_r &set_ecc_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_fault_src get_faulting_interface() const + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + NPU_NAMESPACE::dma_fault_src get_faulting_interface() const volatile + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + CONSTEXPR status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + volatile status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + CONSTEXPR uint32_t get_faulting_channel() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_faulting_channel() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR status_r &set_faulting_channel(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile status_r &set_faulting_channel(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_irq_history_mask() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_irq_history_mask() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR status_r &set_irq_history_mask(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile status_r &set_irq_history_mask(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// cmd_r - Command register, reads as last written command +struct cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t transition_to_running_state : 1; // Write 1 to transition the NPU to running state. Writing 0 has + // no effect + uint32_t clear_irq : 1; // Write 1 to clear the IRQ status in the STATUS register. Writing 0 has no effect + uint32_t clock_q_enable : 1; // Write 1 to this bit to enable clock off using clock q-interface and enable + // the requester clock gate + uint32_t power_q_enable : 1; // Write 1 to this bit to enable power off using power q-interface + uint32_t + stop_request : 1; // Write 1 to this bit to request STOP after completing any already-started commands + uint32_t reserved0 : 11; + uint32_t clear_irq_history : 16; // Clears the IRQ history mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cmd_r() : word0(12) {} + CONSTEXPR cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_transition_to_running_state() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_transition_to_running_state() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR cmd_r &set_transition_to_running_state(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile cmd_r &set_transition_to_running_state(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_clear_irq() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_clear_irq() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR cmd_r &set_clear_irq(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile cmd_r &set_clear_irq(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_clock_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_clock_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR cmd_r &set_clock_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile cmd_r &set_clock_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_power_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_power_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR cmd_r &set_power_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile cmd_r &set_power_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_stop_request() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_stop_request() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR cmd_r &set_stop_request(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile cmd_r &set_stop_request(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_clear_irq_history() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_clear_irq_history() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR cmd_r &set_clear_irq_history(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile cmd_r &set_clear_irq_history(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// reset_r - Request Reset and new security mode +struct reset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t pending_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t pending_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR reset_r() : word0(0) {} + CONSTEXPR reset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + reset_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_pending_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_pending_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_pending_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_pending_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// qbase_r - Base address of the command stream in bytes +struct qbase_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR qbase_r() : word0(0), word1(0) {} + CONSTEXPR qbase_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + qbase_r copy() volatile + { + return *this; + } +#endif +}; + +// qread_r - Read offset in the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QREAD : 32; // The read offset of the current command under execution + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qread_r() : word0(0) {} + CONSTEXPR qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QREAD() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QREAD() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qread_r &set_QREAD(uint32_t value) + { + word0 = value; + return *this; + } + volatile qread_r &set_QREAD(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// qconfig_r - AXI configuration for the command stream in the range 0-3. Same encoding as for REGIONCFG +struct qconfig_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_region0 : 2; // Command region configuration + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qconfig_r() : word0(0) {} + CONSTEXPR qconfig_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qconfig_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_cmd_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_cmd_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// qsize_r - Size of the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qsize_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QSIZE : 32; // Size of the next command stream to be executed by the NPU + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qsize_r() : word0(0) {} + CONSTEXPR qsize_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qsize_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QSIZE() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QSIZE() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qsize_r &set_QSIZE(uint32_t value) + { + word0 = value; + return *this; + } + volatile qsize_r &set_QSIZE(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// prot_r - Protection level configured for the NPU when acting as an AXI requester +struct prot_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t active_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t active_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR prot_r() : word0(0) {} + CONSTEXPR prot_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + prot_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_active_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_active_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_active_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_active_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// config_r - RTL configuration +struct config_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t macs_per_cc : 4; // The log2(macs/clock cycle) + uint32_t cmd_stream_version : 4; // command stream version accepted by this NPU + uint32_t shram_size : 8; // Total size in KB of internal SHRAM + uint32_t reserved0 : 10; + uint32_t functional_safety : 1; // Functional safety configuration + uint32_t custom_dma : 1; // Custom DMA configuration + uint32_t product : 4; // Product configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR config_r() : word0(268435456) {} + CONSTEXPR config_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + config_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_macs_per_cc() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_macs_per_cc() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR config_r &set_macs_per_cc(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile config_r &set_macs_per_cc(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_stream_version() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_stream_version() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR config_r &set_cmd_stream_version(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile config_r &set_cmd_stream_version(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_shram_size() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + uint32_t get_shram_size() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR config_r &set_shram_size(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + volatile config_r &set_shram_size(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::functional_safety get_functional_safety() const + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + NPU_NAMESPACE::functional_safety get_functional_safety() const volatile + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + CONSTEXPR config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + volatile config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma get_custom_dma() const + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + NPU_NAMESPACE::custom_dma get_custom_dma() const volatile + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + CONSTEXPR config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + volatile config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + CONSTEXPR uint32_t get_product() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_product() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR config_r &set_product(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile config_r &set_product(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// lock_r - Lock register. This register is designed for driver use and does not affect NPU functionality +struct lock_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t LOCK : 32; // 32 bit value for LOCK configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR lock_r() : word0(0) {} + CONSTEXPR lock_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + lock_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_LOCK() const + { + uint32_t value = word0; + return value; + } + uint32_t get_LOCK() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR lock_r &set_LOCK(uint32_t value) + { + word0 = value; + return *this; + } + volatile lock_r &set_LOCK(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// regioncfg_r - Region memory type configuration. Bits[2*k+1:2*k] give the memory type for REGION[k] +struct regioncfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t region0 : 2; // Bits for Region0 Configuration + uint32_t region1 : 2; // Bits for Region1 Configuration + uint32_t region2 : 2; // Bits for Region2 Configuration + uint32_t region3 : 2; // Bits for Region3 Configuration + uint32_t region4 : 2; // Bits for Region4 Configuration + uint32_t region5 : 2; // Bits for Region5 Configuration + uint32_t region6 : 2; // Bits for Region6 Configuration + uint32_t region7 : 2; // Bits for Region7 Configuration + uint32_t reserved0 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR regioncfg_r() : word0(0) {} + CONSTEXPR regioncfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + regioncfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region1() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + NPU_NAMESPACE::mem_attr get_region1() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + CONSTEXPR regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + volatile regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region2() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::mem_attr get_region2() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + volatile regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region3() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + NPU_NAMESPACE::mem_attr get_region3() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + CONSTEXPR regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + volatile regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region4() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + NPU_NAMESPACE::mem_attr get_region4() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + CONSTEXPR regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + volatile regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region5() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + NPU_NAMESPACE::mem_attr get_region5() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + CONSTEXPR regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + volatile regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region6() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + NPU_NAMESPACE::mem_attr get_region6() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + CONSTEXPR regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + volatile regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region7() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + NPU_NAMESPACE::mem_attr get_region7() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + CONSTEXPR regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } + volatile regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } +#endif +}; + +// axi_limit0_r - AXI limits for port 0 counter 0 +struct axi_limit0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit0_r() : word0(0) {} + CONSTEXPR axi_limit0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit0_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit1_r - AXI limits for port 0 counter 1 +struct axi_limit1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit1_r() : word0(0) {} + CONSTEXPR axi_limit1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit1_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit2_r - AXI limits for port 1 counter 2 +struct axi_limit2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit2_r() : word0(0) {} + CONSTEXPR axi_limit2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit2_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit3_r - AXI limits for port 1 counter 3 +struct axi_limit3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit3_r() : word0(0) {} + CONSTEXPR axi_limit3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit3_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// basep_r - The driver can use this address to relocate the command stream on region 0. If the region contains data +// requiring A-byte alignment then the base must be a multiple of A +struct basep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR basep_r() : word0(0), word1(0) {} + CONSTEXPR basep_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + basep_r copy() volatile + { + return *this; + } +#endif +}; + +// wd_status_r - WD_STATUS +struct wd_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t core_slice_state : 2; // WD core slice parser state + uint32_t core_idle : 1; // Core idle + uint32_t ctrl_state : 2; // WD control state + uint32_t ctrl_idle : 1; // All stripe jobs idle (all weights consumed) + uint32_t write_buf_index0 : 3; // current write index for next data from core + uint32_t write_buf_valid0 : 1; // write buf valid (full) + uint32_t write_buf_idle0 : 1; // write buf idle (empty) + uint32_t write_buf_index1 : 3; // current write index for next data from core + uint32_t write_buf_valid1 : 1; // write buf valid (full) + uint32_t write_buf_idle1 : 1; // write buf idle (empty) + uint32_t events : 12; // WD events mapped as appendix A + uint32_t reserved0 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR wd_status_r() : word0(0) {} + CONSTEXPR wd_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + wd_status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const volatile + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_core_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_core_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR wd_status_r &set_core_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile wd_status_r &set_core_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const volatile + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + volatile wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + CONSTEXPR uint32_t get_ctrl_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ctrl_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile wd_status_r &set_ctrl_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index0() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + uint32_t get_write_buf_index0() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index0(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + volatile wd_status_r &set_write_buf_index0(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_write_buf_valid0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile wd_status_r &set_write_buf_valid0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_write_buf_idle0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile wd_status_r &set_write_buf_idle0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index1() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + uint32_t get_write_buf_index1() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index1(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + volatile wd_status_r &set_write_buf_index1(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_write_buf_valid1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile wd_status_r &set_write_buf_valid1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_write_buf_idle1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile wd_status_r &set_write_buf_idle1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR wd_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } + volatile wd_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } +#endif +}; + +// mac_status_r - MAC_STATUS +struct mac_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block_cfg_valid : 1; // MAC has a valid block configuration + uint32_t trav_en : 1; // MAC is doing block traversal + uint32_t wait_for_ib : 1; // MAC is waiting for an Input Buffer to become available + uint32_t wait_for_acc_buf : 1; // MAC is waiting for an Accumulator Buffer to become available + uint32_t wait_for_weights : 1; // MAC is waiting for a Weight Block to become available + uint32_t stall_stripe : 1; // MAC is stalling between two stripes + uint32_t dw_sel : 1; // Currently used weight interface in MAC AI + uint32_t wait_for_dw0_ready : 1; // MAC AI is waiting for MAC DPU to send dw0_ready to WD + uint32_t wait_for_dw1_ready : 1; // MAC AI is waiting for MAC DPU to send dw1_ready to WD + uint32_t acc_buf_sel_ai : 1; // Currently used AccBuf interface in MAC AI + uint32_t wait_for_acc0_ready : 1; // MAC AI is waiting for acc0_ready from AO + uint32_t wait_for_acc1_ready : 1; // MAC AI is waiting for acc1_ready from AO + uint32_t acc_buf_sel_aa : 1; // Currently used AccBuf interface in MAC ADDER_ARRAY + uint32_t acc0_valid : 1; // MAC outgoing value of acc0_valid + uint32_t acc1_valid : 1; // MAC outgoing value of acc1_valid + uint32_t reserved0 : 1; + uint32_t events : 11; // Mapped to MAC events described in Appendix A + uint32_t reserved1 : 5; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR mac_status_r() : word0(0) {} + CONSTEXPR mac_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + mac_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block_cfg_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_block_cfg_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR mac_status_r &set_block_cfg_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile mac_status_r &set_block_cfg_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_trav_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_trav_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR mac_status_r &set_trav_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile mac_status_r &set_trav_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wait_for_ib() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wait_for_ib() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_ib(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile mac_status_r &set_wait_for_ib(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc_buf() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_wait_for_acc_buf() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc_buf(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile mac_status_r &set_wait_for_acc_buf(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_wait_for_weights() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_wait_for_weights() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_weights(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile mac_status_r &set_wait_for_weights(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_stall_stripe() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_stall_stripe() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR mac_status_r &set_stall_stripe(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile mac_status_r &set_stall_stripe(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_dw_sel() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_dw_sel() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR mac_status_r &set_dw_sel(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile mac_status_r &set_dw_sel(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wait_for_dw0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile mac_status_r &set_wait_for_dw0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_wait_for_dw1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile mac_status_r &set_wait_for_dw1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_ai() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_acc_buf_sel_ai() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_ai(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_ai(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_wait_for_acc0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile mac_status_r &set_wait_for_acc0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_wait_for_acc1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile mac_status_r &set_wait_for_acc1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_aa() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_acc_buf_sel_aa() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_aa(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_aa(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_acc0_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_acc0_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR mac_status_r &set_acc0_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile mac_status_r &set_acc0_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_acc1_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_acc1_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR mac_status_r &set_acc1_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile mac_status_r &set_acc1_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR mac_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } + volatile mac_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } +#endif +}; + +// ao_status_r - AO_STATUS +struct ao_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_sbw_valid : 1; // Block command to shared buffer write module is valid + uint32_t cmd_act_valid : 1; // Block command to activation function module is valid + uint32_t cmd_ctl_valid : 1; // Block command to control module is valid + uint32_t cmd_scl_valid : 1; // Block command to scale module is valid + uint32_t cmd_sbr_valid : 1; // Block command to shared buffer read module is valid + uint32_t cmd_ofm_valid : 1; // Block command to ofm parameter module is valid + uint32_t blk_cmd_ready : 1; // Ready to accept block command + uint32_t blk_cmd_valid : 1; // Block command from CC is valid + uint32_t reserved0 : 8; + uint32_t events : 8; // Mapped to AO events described in Appendix A + uint32_t reserved1 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ao_status_r() : word0(0) {} + CONSTEXPR ao_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ao_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_sbw_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_sbw_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbw_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile ao_status_r &set_cmd_sbw_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_act_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cmd_act_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR ao_status_r &set_cmd_act_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile ao_status_r &set_cmd_act_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cmd_ctl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cmd_ctl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ctl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile ao_status_r &set_cmd_ctl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_cmd_scl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_cmd_scl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR ao_status_r &set_cmd_scl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile ao_status_r &set_cmd_scl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_sbr_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_sbr_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbr_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile ao_status_r &set_cmd_sbr_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_ofm_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_ofm_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ofm_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile ao_status_r &set_cmd_ofm_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_blk_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile ao_status_r &set_blk_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_blk_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile ao_status_r &set_blk_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR ao_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } + volatile ao_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } +#endif +}; + +// dma_status0_r - DMA_STATUS0 +struct dma_status0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_idle : 1; // When this bit is high means that the CMD block is not busy in generating addresses + // for a CMD job + uint32_t ifm_idle : 1; // When this bit is high means that there are no ongoing IFM jobs + uint32_t wgt_idle_c0 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c0 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t m2m_idle : 1; // When this bit is high means that there are no ongoing M2M jobs + uint32_t ofm_idle : 1; // When this bit is high means that there are no ongoing OFM jobs + uint32_t halt_req : 1; // CPM has requested to HALT AXI bus before soft reset + uint32_t halt_ack : 1; // DMA is in condition to halt the AXI bus since there are no pending transactions + uint32_t pause_req : 1; // CC has requested to pause the AXI + uint32_t pause_ack : 1; // DMA is in condition to pause the AXI bus since there are no pending transactions + uint32_t ib0_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 0 - Core 0 + uint32_t ib1_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 1 - Core 0 + uint32_t ib1_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 1 - Core 0 + uint32_t ib0_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 1 - Core 0 + uint32_t ob0_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 0 + uint32_t ob0_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 0 + uint32_t ob1_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 0 + uint32_t ob1_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 0 + uint32_t cmd_valid : 1; // New command word for CC to be consumed + uint32_t cmd_ready : 1; // command word consumed by CC + uint32_t wd_bitstream_valid_c0 : 1; // New weight word for WD to be consumed - Core 0 + uint32_t wd_bitstream_ready_c0 : 1; // Weight word consumed by WD - Core 0 + uint32_t bs_bitstream_valid_c0 : 1; // New BaS word for AO to be consumed - Core 0 + uint32_t bs_bitstream_ready_c0 : 1; // BaS word consumed by AO - Core 0 + uint32_t axi0_ar_stalled : 1; // Read transfer request stalled on arready low AXI0 (due to memory system) + uint32_t axi0_rd_limit_stall : 1; // Read stalled due to one AXI0 limit counter being reached + uint32_t axi0_aw_stalled : 1; // Write transfer request stalled on awready low AXI0 (due to memory system) + uint32_t axi0_w_stalled : 1; // Write transfer stalled on awready low AXI0 (due to memory system) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status0_r() : word0(0) {} + CONSTEXPR dma_status0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status0_r &set_cmd_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ifm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_ifm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status0_r &set_ifm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status0_r &set_ifm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wgt_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status0_r &set_wgt_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status0_r &set_wgt_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_bas_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status0_r &set_bas_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status0_r &set_bas_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_m2m_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_m2m_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status0_r &set_m2m_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status0_r &set_m2m_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_ofm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ofm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status0_r &set_ofm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status0_r &set_ofm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_halt_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_halt_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status0_r &set_halt_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status0_r &set_halt_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_halt_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_halt_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status0_r &set_halt_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status0_r &set_halt_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_pause_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_pause_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status0_r &set_pause_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status0_r &set_pause_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_pause_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_pause_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status0_r &set_pause_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status0_r &set_pause_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib0_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib0_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib1_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib1_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib0_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib0_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ib1_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ib1_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob0_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status0_r &set_ob0_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob0_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status0_r &set_ob0_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_ob1_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status0_r &set_ob1_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_ob1_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status0_r &set_ob1_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status0_r &set_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status0_r &set_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + uint32_t get_wd_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + uint32_t get_wd_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + uint32_t get_bs_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + uint32_t get_bs_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_axi0_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + uint32_t get_axi0_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + volatile dma_status0_r &set_axi0_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_axi0_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + uint32_t get_axi0_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + volatile dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + CONSTEXPR uint32_t get_axi0_aw_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + uint32_t get_axi0_aw_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_aw_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + volatile dma_status0_r &set_axi0_aw_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + CONSTEXPR uint32_t get_axi0_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_axi0_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile dma_status0_r &set_axi0_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// dma_status1_r - DMA_STATUS1 +struct dma_status1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t axi0_wr_limit_stall : 1; // Write stalled due to one AXI0 limit counter being reached + uint32_t axi1_ar_stalled : 1; // Read transfer request stalled on arready low AXI1 (due to memory system) + uint32_t axi1_rd_limit_stall : 1; // Read stalled due to one AXI1 limit counter being reached + uint32_t axi1_wr_stalled : 1; // Write transfer request stalled on awready low AXI1 (due to memory system) + uint32_t axi1_w_stalled : 1; // Write transfer stalled on wready low AXI1 (due to memory system) + uint32_t axi1_wr_limit_stall : 1; // Write stalled due to one AXI1 limit counter being reached + uint32_t wgt_idle_c1 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c1 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t ib0_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 0 - Core 1 + uint32_t ib1_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 1 - Core 1 + uint32_t ib1_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 1 - Core 1 + uint32_t ib0_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 1 - Core 1 + uint32_t ob0_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 1 + uint32_t ob0_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 1 + uint32_t ob1_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 1 + uint32_t ob1_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 1 + uint32_t wd_bitstream_valid_c1 : 1; // New weight word for WD to be consumed - Core 1 + uint32_t wd_bitstream_ready_c1 : 1; // Weight word consumed by WD - Core 1 + uint32_t bs_bitstream_valid_c1 : 1; // New BaS word for AO to be consumed - Core 1 + uint32_t bs_bitstream_ready_c1 : 1; // BaS word consumed by AO - Core 1 + uint32_t reserved0 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status1_r() : word0(0) {} + CONSTEXPR dma_status1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_axi0_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_axi0_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_axi1_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_axi1_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status1_r &set_axi1_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_axi1_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_axi1_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_axi1_wr_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status1_r &set_axi1_wr_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_axi1_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_axi1_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status1_r &set_axi1_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_axi1_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_wgt_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status1_r &set_wgt_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status1_r &set_wgt_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_bas_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status1_r &set_bas_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status1_r &set_bas_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ib0_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_ib0_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib1_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib1_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib0_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib0_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib1_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib1_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ob0_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status1_r &set_ob0_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ob0_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status1_r &set_ob0_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob1_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status1_r &set_ob1_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob1_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status1_r &set_ob1_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_wd_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_wd_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_bs_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_bs_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } +#endif +}; + +// clkforce_r - Force clocks on for clock gating +struct clkforce_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t top_level_clk : 1; // set to 1 to force on TOP level clock + uint32_t cc_clk : 1; // set to 1 to force on CC clock + uint32_t dma_clk : 1; // set to 1 to force on DMA clock + uint32_t mac_clk : 1; // set to 1 to force on MAC clock + uint32_t ao_clk : 1; // set to 1 to force on AO clock + uint32_t wd_clk : 1; // set to 1 to force on WD clock + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR clkforce_r() : word0(0) {} + CONSTEXPR clkforce_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + clkforce_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_top_level_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_top_level_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR clkforce_r &set_top_level_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile clkforce_r &set_top_level_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cc_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cc_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR clkforce_r &set_cc_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile clkforce_r &set_cc_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_dma_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_dma_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR clkforce_r &set_dma_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile clkforce_r &set_dma_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mac_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mac_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR clkforce_r &set_mac_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile clkforce_r &set_mac_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_ao_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR clkforce_r &set_ao_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile clkforce_r &set_ao_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_wd_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_wd_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR clkforce_r &set_wd_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile clkforce_r &set_wd_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } +#endif +}; + +// debug_address_r - Set debug address for register reads 0x400-0x7FF. The address must be 1KB aligned +struct debug_address_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t addr : 32; // Register address + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_address_r() : word0(0) {} + CONSTEXPR debug_address_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_address_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + uint32_t value = word0; + return value; + } + uint32_t get_addr() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_address_r &set_addr(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_address_r &set_addr(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_misc_r - 32-bit read/write register for driver debug use. This does not affect NPU function +struct debug_misc_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t misc : 32; // Debug misc + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_misc_r() : word0(0) {} + CONSTEXPR debug_misc_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_misc_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_misc() const + { + uint32_t value = word0; + return value; + } + uint32_t get_misc() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_misc_r &set_misc(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_misc_r &set_misc(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debugcore_r - Select core number for debug registers (0x200-0x2FF) and RAM reads (0x400-0x7FF). Value is 0 or 1 +struct debugcore_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t core : 32; // Debug core + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debugcore_r() : word0(0) {} + CONSTEXPR debugcore_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debugcore_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_core() const + { + uint32_t value = word0; + return value; + } + uint32_t get_core() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debugcore_r &set_core(uint32_t value) + { + word0 = value; + return *this; + } + volatile debugcore_r &set_core(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_block_r - Set from which of four block banks the TSU registers are read. 0 = read from the current bank 256+n = +// force to read from bank n where n is in the range 0 to 3 +struct debug_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block : 32; // Debug block + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_block_r() : word0(0) {} + CONSTEXPR debug_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block() const + { + uint32_t value = word0; + return value; + } + uint32_t get_block() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_block_r &set_block(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_block_r &set_block(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmcr_r - PMU Register control +struct pmcr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cnt_en : 1; // Enable counter + uint32_t event_cnt_rst : 1; // Reset event counter + uint32_t cycle_cnt_rst : 1; // Reset cycle counter + uint32_t mask_en : 1; // PMU can be enabled/disabled by command stream operation NPU_OP_PMU_MASK + uint32_t reserved0 : 7; + uint32_t num_event_cnt : 5; // Number of event counters + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcr_r() : word0(8192) {} + CONSTEXPR pmcr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cnt_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cnt_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcr_r &set_cnt_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcr_r &set_cnt_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_event_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_event_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcr_r &set_event_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcr_r &set_event_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cycle_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cycle_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcr_r &set_cycle_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcr_r &set_cycle_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mask_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mask_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcr_r &set_mask_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcr_r &set_mask_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_num_event_cnt() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + uint32_t get_num_event_cnt() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR pmcr_r &set_num_event_cnt(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } + volatile pmcr_r &set_num_event_cnt(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } +#endif +}; + +// pmcntenset_r - Count enable set register +struct pmcntenset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenset_r() : word0(0) {} + CONSTEXPR pmcntenset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenset_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenset_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmcntenclr_r - Count enable clear register +struct pmcntenclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenclr_r() : word0(0) {} + CONSTEXPR pmcntenclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenclr_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenclr_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsset_r - Overflow flag status set register +struct pmovsset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow set bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow set bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow set bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow set bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow set bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsset_r() : word0(0) {} + CONSTEXPR pmovsset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsclr_r - Overflow flag status clear register +struct pmovsclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow clear bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow clear bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow clear bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow clear bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow clear bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsclr_r() : word0(0) {} + CONSTEXPR pmovsclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintset_r - Interrupt enable set register +struct pmintset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintset_r() : word0(0) {} + CONSTEXPR pmintset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintset_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintset_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintclr_r - Interrupt enable clear register +struct pmintclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintclr_r() : word0(0) {} + CONSTEXPR pmintclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmccntr_r - Performance monitor cycle count register +struct pmccntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_LO : 32; // Cycle count - LSB + uint32_t CYCLE_CNT_HI : 16; // Cycle count - MSB + uint32_t reserved0 : 16; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR pmccntr_r() : word0(0), word1(0) {} + CONSTEXPR pmccntr_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + pmccntr_r copy() volatile + { + return *this; + } +#endif +}; + +// pmccntr_cfg_r - Set start/stop event on the cycle counter +struct pmccntr_cfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_CFG_START : 10; // Cycle counter start event + uint32_t reserved0 : 6; + uint32_t CYCLE_CNT_CFG_STOP : 10; // Cycle counter stop event + uint32_t reserved1 : 6; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmccntr_cfg_r() : word0(0) {} + CONSTEXPR pmccntr_cfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmccntr_cfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// pmcaxi_chan_r - Set which AXI channel to monitor for latency measurements in PMU +struct pmcaxi_chan_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CH_SEL : 4; // Channel select for latency measurements + uint32_t reserved0 : 4; + uint32_t AXI_CNT_SEL : 2; // AXI counter to monitor for latency measurements + uint32_t BW_CH_SEL_EN : 1; // Bandwidth channel selector + uint32_t reserved1 : 21; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcaxi_chan_r() : word0(0) {} + CONSTEXPR pmcaxi_chan_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcaxi_chan_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const volatile + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_AXI_CNT_SEL() const + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + uint32_t get_AXI_CNT_SEL() const volatile + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + volatile pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_BW_CH_SEL_EN() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_BW_CH_SEL_EN() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } +#endif +}; + +// kernel_x_r - Kernel X offset of in kernel decomposition +struct kernel_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_x_r() : word0(0) {} + CONSTEXPR kernel_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_y_r - Kernel Y offset of in kernel decomposition +struct kernel_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_y_r() : word0(0) {} + CONSTEXPR kernel_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_w_m1_r - Kernel (width-1) of current block +struct kernel_w_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_w_m1_r() : word0(0) {} + CONSTEXPR kernel_w_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_w_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_w_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_w_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_h_m1_r - Kernel (height-1) of current block +struct kernel_h_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_h_m1_r() : word0(0) {} + CONSTEXPR kernel_h_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_h_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_h_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_h_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_width_m1_r - OFM current block (width-1) +struct ofm_cblk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_height_m1_r - OFM current block (height-1) +struct ofm_cblk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_depth_m1_r - OFM current block (depth-1) +struct ofm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_depth_m1_r - IFM current block (depth-1) +struct ifm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_x_r - Block X coordinate in OFM +struct ofm_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_x_r() : word0(0) {} + CONSTEXPR ofm_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_y_r - Block Y coordinate in OFM +struct ofm_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_y_r() : word0(0) {} + CONSTEXPR ofm_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_z_r - Block Z (channel) coordinate in OFM +struct ofm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_z_r() : word0(0) {} + CONSTEXPR ofm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_z_r - Block Z (channel) coordinate in IFM +struct ifm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_z_r() : word0(0) {} + CONSTEXPR ifm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_top_r - Block top pad +struct pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_top_r() : word0(0) {} + CONSTEXPR pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_left_r - Block left pad +struct pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_left_r() : word0(0) {} + CONSTEXPR pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_width_r - IFM current block derived width +struct ifm_cblk_width_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_width_r() : word0(0) {} + CONSTEXPR ifm_cblk_width_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_width_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_width_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_width_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_height_r - IFM current block derived height +struct ifm_cblk_height_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_height_r() : word0(0) {} + CONSTEXPR ifm_cblk_height_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_height_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_height_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_height_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ifm_src_r - DMA IFM channel source position on AXI +struct dma_ifm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ifm_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_ifm_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ifm_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_ifm_dst_r - DMA IFM channel destination position in SHRAM +struct dma_ifm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ifm_dst_r() : word0(0) {} + CONSTEXPR dma_ifm_dst_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ifm_dst_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ifm_dst_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ifm_dst_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_src_r - DMA OFM channel source position in SHRAM +struct dma_ofm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ofm_src_r() : word0(0) {} + CONSTEXPR dma_ofm_src_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ofm_src_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ofm_src_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ofm_src_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_dst_r - DMA OFM channel destination position on AXI +struct dma_ofm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ofm_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_ofm_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ofm_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_weight_src_r - DMA weight channel source position on AXI +struct dma_weight_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_weight_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_weight_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_weight_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_src_r - DMA command channel source position on AXI +struct dma_cmd_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_cmd_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_cmd_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_cmd_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_size_r - DMA command channel number of bytes buffered +struct dma_cmd_size_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_cmd_size_r() : word0(0) {} + CONSTEXPR dma_cmd_size_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_cmd_size_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_cmd_size_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_cmd_size_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_m2m_src_r - DMA memory to memory source position on AXI +struct dma_m2m_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_m2m_dst_r - DMA memory to memory destination position on AXI +struct dma_m2m_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// current_qread_r - QREAD position being issued (rather than completed) +struct current_qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_qread_r() : word0(0) {} + CONSTEXPR current_qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_qread_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_qread_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_scale_src_r - DMA scale and bias channel source position on AXI +struct dma_scale_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_scale_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_scale_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_scale_src_r copy() volatile + { + return *this; + } +#endif +}; + +// current_block_r - 0-3. Current block bank being executed by the TSU or last one executed if TSU is stopped +struct current_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_block_r() : word0(0) {} + CONSTEXPR current_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_block_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_block_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_op_r - Current NPU OP command being executed by the TSU +struct current_op_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_op_r() : word0(0) {} + CONSTEXPR current_op_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_op_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_op_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_op_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_cmd_r - Current 32-bit command being parsed by the command stream parser +struct current_cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_cmd_r() : word0(0) {} + CONSTEXPR current_cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_cmd_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_cmd_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevcntr_r - Performance monitor event 0 count register +struct pmevcntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t count : 32; // Count word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevcntr_r() : word0(0) {} + CONSTEXPR pmevcntr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevcntr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_count() const + { + uint32_t value = word0; + return value; + } + uint32_t get_count() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pmevcntr_r &set_count(uint32_t value) + { + word0 = value; + return *this; + } + volatile pmevcntr_r &set_count(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevtyper_r - Performance monitor event type register 0 +struct pmevtyper_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EV_TYPE : 10; // Event Type + uint32_t reserved0 : 22; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevtyper_r() : word0(0) {} + CONSTEXPR pmevtyper_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevtyper_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_EV_TYPE() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_EV_TYPE() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// shared_buffer_r - Shared buffer debug access. Only valid in STOPPED state +struct shared_buffer_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_word : 32; // Memory word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR shared_buffer_r() : word0(0) {} + CONSTEXPR shared_buffer_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + shared_buffer_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_mem_word() const + { + uint32_t value = word0; + return value; + } + uint32_t get_mem_word() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR shared_buffer_r &set_mem_word(uint32_t value) + { + word0 = value; + return *this; + } + volatile shared_buffer_r &set_mem_word(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_top_r - None +struct ifm_pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_top_r() : word0(0) {} + CONSTEXPR ifm_pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_left_r - None +struct ifm_pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_left_r() : word0(0) {} + CONSTEXPR ifm_pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_right_r - None +struct ifm_pad_right_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_right_r() : word0(0) {} + CONSTEXPR ifm_pad_right_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_right_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_right_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_right_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_bottom_r - None +struct ifm_pad_bottom_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_bottom_r() : word0(0) {} + CONSTEXPR ifm_pad_bottom_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_bottom_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_bottom_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_bottom_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_depth_m1_r - None +struct ifm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_precision_r - None +struct ifm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_precision_r() : word0(0) {} + CONSTEXPR ifm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_upscale_r - None +struct ifm_upscale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_upscale_r() : word0(0) {} + CONSTEXPR ifm_upscale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_upscale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_upscale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_upscale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_zero_point_r - None +struct ifm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_zero_point_r() : word0(0) {} + CONSTEXPR ifm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_width0_m1_r - None +struct ifm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_width0_m1_r() : word0(0) {} + CONSTEXPR ifm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height0_m1_r - None +struct ifm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height0_m1_r() : word0(0) {} + CONSTEXPR ifm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height1_m1_r - None +struct ifm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height1_m1_r() : word0(0) {} + CONSTEXPR ifm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_ib_end_r - None +struct ifm_ib_end_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_ib_end_r() : word0(0) {} + CONSTEXPR ifm_ib_end_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_ib_end_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_ib_end_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_ib_end_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_region_r - None +struct ifm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_region_r() : word0(0) {} + CONSTEXPR ifm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width_m1_r - None +struct ofm_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width_m1_r() : word0(0) {} + CONSTEXPR ofm_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height_m1_r - None +struct ofm_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height_m1_r() : word0(0) {} + CONSTEXPR ofm_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_depth_m1_r - None +struct ofm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_precision_r - None +struct ofm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_precision_r() : word0(0) {} + CONSTEXPR ofm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_width_m1_r - None +struct ofm_blk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_height_m1_r - None +struct ofm_blk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_depth_m1_r - None +struct ofm_blk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_zero_point_r - None +struct ofm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_zero_point_r() : word0(0) {} + CONSTEXPR ofm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width0_m1_r - None +struct ofm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width0_m1_r() : word0(0) {} + CONSTEXPR ofm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height0_m1_r - None +struct ofm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height0_m1_r() : word0(0) {} + CONSTEXPR ofm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height1_m1_r - None +struct ofm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height1_m1_r() : word0(0) {} + CONSTEXPR ofm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_region_r - None +struct ofm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_region_r() : word0(0) {} + CONSTEXPR ofm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_width_m1_r - None +struct kernel_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_width_m1_r() : word0(0) {} + CONSTEXPR kernel_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_height_m1_r - None +struct kernel_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_height_m1_r() : word0(0) {} + CONSTEXPR kernel_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_stride_r - None +struct kernel_stride_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_stride_r() : word0(0) {} + CONSTEXPR kernel_stride_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_stride_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_stride_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_stride_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// parallel_mode_r - None +struct parallel_mode_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR parallel_mode_r() : word0(0) {} + CONSTEXPR parallel_mode_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + parallel_mode_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR parallel_mode_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile parallel_mode_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// acc_format_r - None +struct acc_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR acc_format_r() : word0(0) {} + CONSTEXPR acc_format_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + acc_format_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR acc_format_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile acc_format_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_r - None +struct activation_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_r() : word0(0) {} + CONSTEXPR activation_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_min_r - None +struct activation_min_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_min_r() : word0(0) {} + CONSTEXPR activation_min_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_min_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_min_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_min_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_max_r - None +struct activation_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_max_r() : word0(0) {} + CONSTEXPR activation_max_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_max_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_max_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_max_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// weight_region_r - None +struct weight_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR weight_region_r() : word0(0) {} + CONSTEXPR weight_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + weight_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR weight_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile weight_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// scale_region_r - None +struct scale_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR scale_region_r() : word0(0) {} + CONSTEXPR scale_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + scale_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR scale_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile scale_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ab_start_r - None +struct ab_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ab_start_r() : word0(0) {} + CONSTEXPR ab_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ab_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ab_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ab_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// blockdep_r - None +struct blockdep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR blockdep_r() : word0(0) {} + CONSTEXPR blockdep_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + blockdep_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR blockdep_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile blockdep_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_region_r - None +struct dma0_src_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_src_region_r() : word0(0) {} + CONSTEXPR dma0_src_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_src_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_src_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_src_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_dst_region_r - None +struct dma0_dst_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_dst_region_r() : word0(0) {} + CONSTEXPR dma0_dst_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_dst_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_dst_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_dst_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size0_r - None +struct dma0_size0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size0_r() : word0(0) {} + CONSTEXPR dma0_size0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size0_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size0_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size1_r - None +struct dma0_size1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size1_r() : word0(0) {} + CONSTEXPR dma0_size1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_broadcast_r - None +struct ifm2_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_broadcast_r() : word0(0) {} + CONSTEXPR ifm2_broadcast_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_broadcast_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_broadcast_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_broadcast_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_scalar_r - None +struct ifm2_scalar_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_scalar_r() : word0(0) {} + CONSTEXPR ifm2_scalar_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_scalar_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_scalar_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_scalar_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_precision_r - None +struct ifm2_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_precision_r() : word0(0) {} + CONSTEXPR ifm2_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_zero_point_r - None +struct ifm2_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_zero_point_r() : word0(0) {} + CONSTEXPR ifm2_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_width0_m1_r - None +struct ifm2_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_width0_m1_r() : word0(0) {} + CONSTEXPR ifm2_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height0_m1_r - None +struct ifm2_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height0_m1_r() : word0(0) {} + CONSTEXPR ifm2_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height1_m1_r - None +struct ifm2_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height1_m1_r() : word0(0) {} + CONSTEXPR ifm2_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_ib_start_r - None +struct ifm2_ib_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_ib_start_r() : word0(0) {} + CONSTEXPR ifm2_ib_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_ib_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_ib_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_ib_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_region_r - None +struct ifm2_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_region_r() : word0(0) {} + CONSTEXPR ifm2_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_base0_r - None +struct ifm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base1_r - None +struct ifm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base2_r - None +struct ifm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base3_r - None +struct ifm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_x_r - None +struct ifm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_y_r - None +struct ifm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_c_r - None +struct ifm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base0_r - None +struct ofm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base1_r - None +struct ofm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base2_r - None +struct ofm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base3_r - None +struct ofm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_x_r - None +struct ofm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_y_r - None +struct ofm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_c_r - None +struct ofm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_base_r - None +struct weight_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_base_r() : word0(0), word1(0) {} + CONSTEXPR weight_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_base_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_length_r - None +struct weight_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_length_r() : word0(0), word1(0) {} + CONSTEXPR weight_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_length_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_base_r - None +struct scale_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_base_r() : word0(0), word1(0) {} + CONSTEXPR scale_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_base_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_length_r - None +struct scale_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_length_r() : word0(0), word1(0) {} + CONSTEXPR scale_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_length_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_scale_r - None +struct ofm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_r() : word0(0) {} + CONSTEXPR ofm_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_scale_shift_r - None +struct ofm_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_shift_r() : word0(0) {} + CONSTEXPR ofm_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_r - None +struct opa_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_r() : word0(0) {} + CONSTEXPR opa_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_shift_r - None +struct opa_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_shift_r() : word0(0) {} + CONSTEXPR opa_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opb_scale_r - None +struct opb_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opb_scale_r() : word0(0) {} + CONSTEXPR opb_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opb_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opb_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opb_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_r - None +struct dma0_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_src_r() : word0(0), word1(0) {} + CONSTEXPR dma0_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_dst_r - None +struct dma0_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma0_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_len_r - None +struct dma0_len_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_len_r() : word0(0), word1(0) {} + CONSTEXPR dma0_len_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_len_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_skip0_r - None +struct dma0_skip0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_skip0_r() : word0(0), word1(0) {} + CONSTEXPR dma0_skip0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_skip0_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_skip1_r - None +struct dma0_skip1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_skip1_r() : word0(0), word1(0) {} + CONSTEXPR dma0_skip1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_skip1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base0_r - None +struct ifm2_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base1_r - None +struct ifm2_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base2_r - None +struct ifm2_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base3_r - None +struct ifm2_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_x_r - None +struct ifm2_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_y_r - None +struct ifm2_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_c_r - None +struct ifm2_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// weight1_base_r - None +struct weight1_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight1_base_r() : word0(0), word1(0) {} + CONSTEXPR weight1_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight1_base_r copy() volatile + { + return *this; + } +#endif +}; + +// weight1_length_r - None +struct weight1_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight1_length_r() : word0(0), word1(0) {} + CONSTEXPR weight1_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight1_length_r copy() volatile + { + return *this; + } +#endif +}; + +// scale1_base_r - None +struct scale1_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale1_base_r() : word0(0), word1(0) {} + CONSTEXPR scale1_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale1_base_r copy() volatile + { + return *this; + } +#endif +}; + +// scale1_length_r - None +struct scale1_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale1_length_r() : word0(0), word1(0) {} + CONSTEXPR scale1_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale1_length_r copy() volatile + { + return *this; + } +#endif +}; + +// revision_r - Internal FPGA build revision: first 32-bits of the Ultan Git hash used for the build +struct revision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR revision_r() : word0(0) {} + CONSTEXPR revision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + revision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR revision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile revision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid4_r - Peripheral ID byte 4 (Arm=code 4) +struct pid4_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID4 : 32; // Byte 4 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid4_r() : word0(4) {} + CONSTEXPR pid4_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid4_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID4() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID4() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid4_r &set_PID4(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid4_r &set_PID4(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid5_r - Peripheral ID byte 5 (reserved) +struct pid5_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID5 : 32; // Byte 5 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid5_r() : word0(0) {} + CONSTEXPR pid5_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid5_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID5() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID5() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid5_r &set_PID5(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid5_r &set_PID5(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid6_r - Peripheral ID byte 6 (reserved) +struct pid6_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID6 : 32; // Byte 6 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid6_r() : word0(0) {} + CONSTEXPR pid6_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid6_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID6() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID6() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid6_r &set_PID6(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid6_r &set_PID6(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid7_r - Peripheral ID byte 7 (reserved) +struct pid7_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID7 : 32; // Byte 7 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid7_r() : word0(0) {} + CONSTEXPR pid7_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid7_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID7() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID7() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid7_r &set_PID7(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid7_r &set_PID7(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid0_r - Peripheral ID byte 0. This is bits[7:0] of the part number +struct pid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID0 : 32; // Byte 0 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid0_r() : word0(129) {} + CONSTEXPR pid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid0_r &set_PID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid0_r &set_PID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid1_r - Peripheral ID byte 1. This is bits[11:8] of the part number in bits[3:0], and bits[3:0] of the Arm ID in +// bits[7:4] +struct pid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID1 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid1_r() : word0(181) {} + CONSTEXPR pid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid1_r &set_PID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid1_r &set_PID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid2_r - Peripheral ID byte 2. This is bits[6:4] of the Arm ID in bits[2:0], and bit 3 indicates format B +struct pid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID2 : 32; // Byte 2 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid2_r() : word0(11) {} + CONSTEXPR pid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid2_r &set_PID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid2_r &set_PID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid3_r - Peripheral ID byte 3 +struct pid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID3 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid3_r() : word0(0) {} + CONSTEXPR pid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid3_r &set_PID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid3_r &set_PID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid0_r - Component ID byte 0 +struct cid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID0 : 32; // Byte 0 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid0_r() : word0(13) {} + CONSTEXPR cid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid0_r &set_CID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid0_r &set_CID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid1_r - Component ID byte 1 +struct cid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID1 : 32; // Byte 1 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid1_r() : word0(240) {} + CONSTEXPR cid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid1_r &set_CID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid1_r &set_CID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid2_r - Component ID byte 2 +struct cid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID2 : 32; // Byte 2 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid2_r() : word0(5) {} + CONSTEXPR cid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid2_r &set_CID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid2_r &set_CID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid3_r - Component ID byte 3 +struct cid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID3 : 32; // Byte 3 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid3_r() : word0(177) {} + CONSTEXPR cid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid3_r &set_CID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid3_r &set_CID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +struct NPU_REG +{ + STRUCT id_r ID; // 0x0000 + STRUCT status_r STATUS; // 0x0004 + STRUCT cmd_r CMD; // 0x0008 + STRUCT reset_r RESET; // 0x000C + STRUCT qbase_r QBASE; // 0x0010 + STRUCT qread_r QREAD; // 0x0018 + STRUCT qconfig_r QCONFIG; // 0x001C + STRUCT qsize_r QSIZE; // 0x0020 + STRUCT prot_r PROT; // 0x0024 + STRUCT config_r CONFIG; // 0x0028 + STRUCT lock_r LOCK; // 0x002C + uint32_t unused0[3]; + STRUCT regioncfg_r REGIONCFG; // 0x003C + STRUCT axi_limit0_r AXI_LIMIT0; // 0x0040 + STRUCT axi_limit1_r AXI_LIMIT1; // 0x0044 + STRUCT axi_limit2_r AXI_LIMIT2; // 0x0048 + STRUCT axi_limit3_r AXI_LIMIT3; // 0x004C + uint32_t unused1[12]; + STRUCT basep_r BASEP[8]; // 0x0080 + uint32_t unused2[16]; + STRUCT wd_status_r WD_STATUS; // 0x0100 + STRUCT mac_status_r MAC_STATUS; // 0x0104 + STRUCT ao_status_r AO_STATUS; // 0x0108 + uint32_t unused3[1]; + STRUCT dma_status0_r DMA_STATUS0; // 0x0110 + STRUCT dma_status1_r DMA_STATUS1; // 0x0114 + uint32_t unused4[10]; + STRUCT clkforce_r CLKFORCE; // 0x0140 + STRUCT debug_address_r DEBUG_ADDRESS; // 0x0144 + STRUCT debug_misc_r DEBUG_MISC; // 0x0148 + STRUCT debugcore_r DEBUGCORE; // 0x014C + STRUCT debug_block_r DEBUG_BLOCK; // 0x0150 + uint32_t unused5[11]; + STRUCT pmcr_r PMCR; // 0x0180 + STRUCT pmcntenset_r PMCNTENSET; // 0x0184 + STRUCT pmcntenclr_r PMCNTENCLR; // 0x0188 + STRUCT pmovsset_r PMOVSSET; // 0x018C + STRUCT pmovsclr_r PMOVSCLR; // 0x0190 + STRUCT pmintset_r PMINTSET; // 0x0194 + STRUCT pmintclr_r PMINTCLR; // 0x0198 + uint32_t unused6[1]; + STRUCT pmccntr_r PMCCNTR; // 0x01A0 + STRUCT pmccntr_cfg_r PMCCNTR_CFG; // 0x01A8 + STRUCT pmcaxi_chan_r PMCAXI_CHAN; // 0x01AC + uint32_t unused7[20]; + STRUCT kernel_x_r KERNEL_X; // 0x0200 + STRUCT kernel_y_r KERNEL_Y; // 0x0204 + STRUCT kernel_w_m1_r KERNEL_W_M1; // 0x0208 + STRUCT kernel_h_m1_r KERNEL_H_M1; // 0x020C + STRUCT ofm_cblk_width_m1_r OFM_CBLK_WIDTH_M1; // 0x0210 + STRUCT ofm_cblk_height_m1_r OFM_CBLK_HEIGHT_M1; // 0x0214 + STRUCT ofm_cblk_depth_m1_r OFM_CBLK_DEPTH_M1; // 0x0218 + STRUCT ifm_cblk_depth_m1_r IFM_CBLK_DEPTH_M1; // 0x021C + STRUCT ofm_x_r OFM_X; // 0x0220 + STRUCT ofm_y_r OFM_Y; // 0x0224 + STRUCT ofm_z_r OFM_Z; // 0x0228 + STRUCT ifm_z_r IFM_Z; // 0x022C + STRUCT pad_top_r PAD_TOP; // 0x0230 + STRUCT pad_left_r PAD_LEFT; // 0x0234 + STRUCT ifm_cblk_width_r IFM_CBLK_WIDTH; // 0x0238 + STRUCT ifm_cblk_height_r IFM_CBLK_HEIGHT; // 0x023C + STRUCT dma_ifm_src_r DMA_IFM_SRC; // 0x0240 + STRUCT dma_ifm_dst_r DMA_IFM_DST; // 0x0248 + STRUCT dma_ofm_src_r DMA_OFM_SRC; // 0x024C + STRUCT dma_ofm_dst_r DMA_OFM_DST; // 0x0250 + STRUCT dma_weight_src_r DMA_WEIGHT_SRC; // 0x0258 + STRUCT dma_cmd_src_r DMA_CMD_SRC; // 0x0260 + STRUCT dma_cmd_size_r DMA_CMD_SIZE; // 0x0268 + STRUCT dma_m2m_src_r DMA_M2M_SRC; // 0x026C + STRUCT dma_m2m_dst_r DMA_M2M_DST; // 0x0274 + STRUCT current_qread_r CURRENT_QREAD; // 0x027C + STRUCT dma_scale_src_r DMA_SCALE_SRC; // 0x0280 + uint32_t unused8[11]; + STRUCT current_block_r CURRENT_BLOCK; // 0x02B4 + STRUCT current_op_r CURRENT_OP; // 0x02B8 + STRUCT current_cmd_r CURRENT_CMD; // 0x02BC + uint32_t unused9[16]; + STRUCT pmevcntr_r PMEVCNTR[4]; // 0x0300 + uint32_t unused10[28]; + STRUCT pmevtyper_r PMEVTYPER[4]; // 0x0380 + uint32_t unused11[28]; + STRUCT shared_buffer_r SHARED_BUFFER[256]; // 0x0400 + STRUCT ifm_pad_top_r IFM_PAD_TOP; // 0x0800 + STRUCT ifm_pad_left_r IFM_PAD_LEFT; // 0x0804 + STRUCT ifm_pad_right_r IFM_PAD_RIGHT; // 0x0808 + STRUCT ifm_pad_bottom_r IFM_PAD_BOTTOM; // 0x080C + STRUCT ifm_depth_m1_r IFM_DEPTH_M1; // 0x0810 + STRUCT ifm_precision_r IFM_PRECISION; // 0x0814 + uint32_t unused12[1]; + STRUCT ifm_upscale_r IFM_UPSCALE; // 0x081C + uint32_t unused13[1]; + STRUCT ifm_zero_point_r IFM_ZERO_POINT; // 0x0824 + STRUCT ifm_width0_m1_r IFM_WIDTH0_M1; // 0x0828 + STRUCT ifm_height0_m1_r IFM_HEIGHT0_M1; // 0x082C + STRUCT ifm_height1_m1_r IFM_HEIGHT1_M1; // 0x0830 + STRUCT ifm_ib_end_r IFM_IB_END; // 0x0834 + uint32_t unused14[1]; + STRUCT ifm_region_r IFM_REGION; // 0x083C + uint32_t unused15[1]; + STRUCT ofm_width_m1_r OFM_WIDTH_M1; // 0x0844 + STRUCT ofm_height_m1_r OFM_HEIGHT_M1; // 0x0848 + STRUCT ofm_depth_m1_r OFM_DEPTH_M1; // 0x084C + STRUCT ofm_precision_r OFM_PRECISION; // 0x0850 + STRUCT ofm_blk_width_m1_r OFM_BLK_WIDTH_M1; // 0x0854 + STRUCT ofm_blk_height_m1_r OFM_BLK_HEIGHT_M1; // 0x0858 + STRUCT ofm_blk_depth_m1_r OFM_BLK_DEPTH_M1; // 0x085C + STRUCT ofm_zero_point_r OFM_ZERO_POINT; // 0x0860 + uint32_t unused16[1]; + STRUCT ofm_width0_m1_r OFM_WIDTH0_M1; // 0x0868 + STRUCT ofm_height0_m1_r OFM_HEIGHT0_M1; // 0x086C + STRUCT ofm_height1_m1_r OFM_HEIGHT1_M1; // 0x0870 + uint32_t unused17[2]; + STRUCT ofm_region_r OFM_REGION; // 0x087C + STRUCT kernel_width_m1_r KERNEL_WIDTH_M1; // 0x0880 + STRUCT kernel_height_m1_r KERNEL_HEIGHT_M1; // 0x0884 + STRUCT kernel_stride_r KERNEL_STRIDE; // 0x0888 + STRUCT parallel_mode_r PARALLEL_MODE; // 0x088C + STRUCT acc_format_r ACC_FORMAT; // 0x0890 + STRUCT activation_r ACTIVATION; // 0x0894 + STRUCT activation_min_r ACTIVATION_MIN; // 0x0898 + STRUCT activation_max_r ACTIVATION_MAX; // 0x089C + STRUCT weight_region_r WEIGHT_REGION; // 0x08A0 + STRUCT scale_region_r SCALE_REGION; // 0x08A4 + uint32_t unused18[3]; + STRUCT ab_start_r AB_START; // 0x08B4 + uint32_t unused19[1]; + STRUCT blockdep_r BLOCKDEP; // 0x08BC + STRUCT dma0_src_region_r DMA0_SRC_REGION; // 0x08C0 + STRUCT dma0_dst_region_r DMA0_DST_REGION; // 0x08C4 + STRUCT dma0_size0_r DMA0_SIZE0; // 0x08C8 + STRUCT dma0_size1_r DMA0_SIZE1; // 0x08CC + uint32_t unused20[12]; + STRUCT ifm2_broadcast_r IFM2_BROADCAST; // 0x0900 + STRUCT ifm2_scalar_r IFM2_SCALAR; // 0x0904 + uint32_t unused21[3]; + STRUCT ifm2_precision_r IFM2_PRECISION; // 0x0914 + uint32_t unused22[3]; + STRUCT ifm2_zero_point_r IFM2_ZERO_POINT; // 0x0924 + STRUCT ifm2_width0_m1_r IFM2_WIDTH0_M1; // 0x0928 + STRUCT ifm2_height0_m1_r IFM2_HEIGHT0_M1; // 0x092C + STRUCT ifm2_height1_m1_r IFM2_HEIGHT1_M1; // 0x0930 + STRUCT ifm2_ib_start_r IFM2_IB_START; // 0x0934 + uint32_t unused23[1]; + STRUCT ifm2_region_r IFM2_REGION; // 0x093C + uint32_t unused24[48]; + STRUCT ifm_base0_r IFM_BASE0; // 0x0A00 + STRUCT ifm_base1_r IFM_BASE1; // 0x0A08 + STRUCT ifm_base2_r IFM_BASE2; // 0x0A10 + STRUCT ifm_base3_r IFM_BASE3; // 0x0A18 + STRUCT ifm_stride_x_r IFM_STRIDE_X; // 0x0A20 + STRUCT ifm_stride_y_r IFM_STRIDE_Y; // 0x0A28 + STRUCT ifm_stride_c_r IFM_STRIDE_C; // 0x0A30 + uint32_t unused25[2]; + STRUCT ofm_base0_r OFM_BASE0; // 0x0A40 + STRUCT ofm_base1_r OFM_BASE1; // 0x0A48 + STRUCT ofm_base2_r OFM_BASE2; // 0x0A50 + STRUCT ofm_base3_r OFM_BASE3; // 0x0A58 + STRUCT ofm_stride_x_r OFM_STRIDE_X; // 0x0A60 + STRUCT ofm_stride_y_r OFM_STRIDE_Y; // 0x0A68 + STRUCT ofm_stride_c_r OFM_STRIDE_C; // 0x0A70 + uint32_t unused26[2]; + STRUCT weight_base_r WEIGHT_BASE; // 0x0A80 + STRUCT weight_length_r WEIGHT_LENGTH; // 0x0A88 + STRUCT scale_base_r SCALE_BASE; // 0x0A90 + STRUCT scale_length_r SCALE_LENGTH; // 0x0A98 + STRUCT ofm_scale_r OFM_SCALE; // 0x0AA0 + STRUCT ofm_scale_shift_r OFM_SCALE_SHIFT; // 0x0AA4 + STRUCT opa_scale_r OPA_SCALE; // 0x0AA8 + STRUCT opa_scale_shift_r OPA_SCALE_SHIFT; // 0x0AAC + STRUCT opb_scale_r OPB_SCALE; // 0x0AB0 + uint32_t unused27[3]; + STRUCT dma0_src_r DMA0_SRC; // 0x0AC0 + STRUCT dma0_dst_r DMA0_DST; // 0x0AC8 + STRUCT dma0_len_r DMA0_LEN; // 0x0AD0 + STRUCT dma0_skip0_r DMA0_SKIP0; // 0x0AD8 + STRUCT dma0_skip1_r DMA0_SKIP1; // 0x0AE0 + uint32_t unused28[6]; + STRUCT ifm2_base0_r IFM2_BASE0; // 0x0B00 + STRUCT ifm2_base1_r IFM2_BASE1; // 0x0B08 + STRUCT ifm2_base2_r IFM2_BASE2; // 0x0B10 + STRUCT ifm2_base3_r IFM2_BASE3; // 0x0B18 + STRUCT ifm2_stride_x_r IFM2_STRIDE_X; // 0x0B20 + STRUCT ifm2_stride_y_r IFM2_STRIDE_Y; // 0x0B28 + STRUCT ifm2_stride_c_r IFM2_STRIDE_C; // 0x0B30 + uint32_t unused29[2]; + STRUCT weight1_base_r WEIGHT1_BASE; // 0x0B40 + STRUCT weight1_length_r WEIGHT1_LENGTH; // 0x0B48 + STRUCT scale1_base_r SCALE1_BASE; // 0x0B50 + STRUCT scale1_length_r SCALE1_LENGTH; // 0x0B58 + uint32_t unused30[280]; + STRUCT revision_r REVISION; // 0x0FC0 + uint32_t unused31[3]; + STRUCT pid4_r PID4; // 0x0FD0 + STRUCT pid5_r PID5; // 0x0FD4 + STRUCT pid6_r PID6; // 0x0FD8 + STRUCT pid7_r PID7; // 0x0FDC + STRUCT pid0_r PID0; // 0x0FE0 + STRUCT pid1_r PID1; // 0x0FE4 + STRUCT pid2_r PID2; // 0x0FE8 + STRUCT pid3_r PID3; // 0x0FEC + STRUCT cid0_r CID0; // 0x0FF0 + STRUCT cid1_r CID1; // 0x0FF4 + STRUCT cid2_r CID2; // 0x0FF8 + STRUCT cid3_r CID3; // 0x0FFC + +#ifdef __cplusplus + enum class access_type_t : uint8_t + { + RW, + RO, + WO + }; + NPU_REG() + { + reset(); + } + void reset() + { + ID = 268853249; + STATUS = 8; + CMD = 12; + RESET = 0; + QBASE = 0; + QREAD = 0; + QCONFIG = 0; + QSIZE = 0; + PROT = 0; + CONFIG = 268435456; + LOCK = 0; + REGIONCFG = 0; + AXI_LIMIT0 = 0; + AXI_LIMIT1 = 0; + AXI_LIMIT2 = 0; + AXI_LIMIT3 = 0; + for (size_t i = 0; i < (sizeof(BASEP) / sizeof(BASEP[0])); ++i) + BASEP[i] = 0; + WD_STATUS = 0; + MAC_STATUS = 0; + AO_STATUS = 0; + DMA_STATUS0 = 0; + DMA_STATUS1 = 0; + CLKFORCE = 0; + DEBUG_ADDRESS = 0; + DEBUG_MISC = 0; + DEBUGCORE = 0; + DEBUG_BLOCK = 0; + PMCR = 8192; + PMCNTENSET = 0; + PMCNTENCLR = 0; + PMOVSSET = 0; + PMOVSCLR = 0; + PMINTSET = 0; + PMINTCLR = 0; + PMCCNTR = 0; + PMCCNTR_CFG = 0; + PMCAXI_CHAN = 0; + KERNEL_X = 0; + KERNEL_Y = 0; + KERNEL_W_M1 = 0; + KERNEL_H_M1 = 0; + OFM_CBLK_WIDTH_M1 = 0; + OFM_CBLK_HEIGHT_M1 = 0; + OFM_CBLK_DEPTH_M1 = 0; + IFM_CBLK_DEPTH_M1 = 0; + OFM_X = 0; + OFM_Y = 0; + OFM_Z = 0; + IFM_Z = 0; + PAD_TOP = 0; + PAD_LEFT = 0; + IFM_CBLK_WIDTH = 0; + IFM_CBLK_HEIGHT = 0; + DMA_IFM_SRC = 0; + DMA_IFM_DST = 0; + DMA_OFM_SRC = 0; + DMA_OFM_DST = 0; + DMA_WEIGHT_SRC = 0; + DMA_CMD_SRC = 0; + DMA_CMD_SIZE = 0; + DMA_M2M_SRC = 0; + DMA_M2M_DST = 0; + CURRENT_QREAD = 0; + DMA_SCALE_SRC = 0; + CURRENT_BLOCK = 0; + CURRENT_OP = 0; + CURRENT_CMD = 0; + for (size_t i = 0; i < (sizeof(PMEVCNTR) / sizeof(PMEVCNTR[0])); ++i) + PMEVCNTR[i] = 0; + for (size_t i = 0; i < (sizeof(PMEVTYPER) / sizeof(PMEVTYPER[0])); ++i) + PMEVTYPER[i] = 0; + for (size_t i = 0; i < (sizeof(SHARED_BUFFER) / sizeof(SHARED_BUFFER[0])); ++i) + SHARED_BUFFER[i] = 0; + IFM_PAD_TOP = 0; + IFM_PAD_LEFT = 0; + IFM_PAD_RIGHT = 0; + IFM_PAD_BOTTOM = 0; + IFM_DEPTH_M1 = 0; + IFM_PRECISION = 0; + IFM_UPSCALE = 0; + IFM_ZERO_POINT = 0; + IFM_WIDTH0_M1 = 0; + IFM_HEIGHT0_M1 = 0; + IFM_HEIGHT1_M1 = 0; + IFM_IB_END = 0; + IFM_REGION = 0; + OFM_WIDTH_M1 = 0; + OFM_HEIGHT_M1 = 0; + OFM_DEPTH_M1 = 0; + OFM_PRECISION = 0; + OFM_BLK_WIDTH_M1 = 0; + OFM_BLK_HEIGHT_M1 = 0; + OFM_BLK_DEPTH_M1 = 0; + OFM_ZERO_POINT = 0; + OFM_WIDTH0_M1 = 0; + OFM_HEIGHT0_M1 = 0; + OFM_HEIGHT1_M1 = 0; + OFM_REGION = 0; + KERNEL_WIDTH_M1 = 0; + KERNEL_HEIGHT_M1 = 0; + KERNEL_STRIDE = 0; + PARALLEL_MODE = 0; + ACC_FORMAT = 0; + ACTIVATION = 0; + ACTIVATION_MIN = 0; + ACTIVATION_MAX = 0; + WEIGHT_REGION = 0; + SCALE_REGION = 0; + AB_START = 0; + BLOCKDEP = 0; + DMA0_SRC_REGION = 0; + DMA0_DST_REGION = 0; + DMA0_SIZE0 = 0; + DMA0_SIZE1 = 0; + IFM2_BROADCAST = 0; + IFM2_SCALAR = 0; + IFM2_PRECISION = 0; + IFM2_ZERO_POINT = 0; + IFM2_WIDTH0_M1 = 0; + IFM2_HEIGHT0_M1 = 0; + IFM2_HEIGHT1_M1 = 0; + IFM2_IB_START = 0; + IFM2_REGION = 0; + IFM_BASE0 = 0; + IFM_BASE1 = 0; + IFM_BASE2 = 0; + IFM_BASE3 = 0; + IFM_STRIDE_X = 0; + IFM_STRIDE_Y = 0; + IFM_STRIDE_C = 0; + OFM_BASE0 = 0; + OFM_BASE1 = 0; + OFM_BASE2 = 0; + OFM_BASE3 = 0; + OFM_STRIDE_X = 0; + OFM_STRIDE_Y = 0; + OFM_STRIDE_C = 0; + WEIGHT_BASE = 0; + WEIGHT_LENGTH = 0; + SCALE_BASE = 0; + SCALE_LENGTH = 0; + OFM_SCALE = 0; + OFM_SCALE_SHIFT = 0; + OPA_SCALE = 0; + OPA_SCALE_SHIFT = 0; + OPB_SCALE = 0; + DMA0_SRC = 0; + DMA0_DST = 0; + DMA0_LEN = 0; + DMA0_SKIP0 = 0; + DMA0_SKIP1 = 0; + IFM2_BASE0 = 0; + IFM2_BASE1 = 0; + IFM2_BASE2 = 0; + IFM2_BASE3 = 0; + IFM2_STRIDE_X = 0; + IFM2_STRIDE_Y = 0; + IFM2_STRIDE_C = 0; + WEIGHT1_BASE = 0; + WEIGHT1_LENGTH = 0; + SCALE1_BASE = 0; + SCALE1_LENGTH = 0; + REVISION = 0; + PID4 = 4; + PID5 = 0; + PID6 = 0; + PID7 = 0; + PID0 = 129; + PID1 = 181; + PID2 = 11; + PID3 = 0; + CID0 = 13; + CID1 = 240; + CID2 = 5; + CID3 = 177; + } + uint32_t &operator[](const int addr_offset) + { + return reinterpret_cast(this)[addr_offset / 4]; + } + access_type_t get_access_type(uint32_t offset) + { + switch (offset) + { + case 0: + return access_type_t::RO; + case 4: + return access_type_t::RO; + case 8: + return access_type_t::RW; + case 12: + return access_type_t::RW; + case 16: + return access_type_t::RW; + case 24: + return access_type_t::RO; + case 28: + return access_type_t::RW; + case 32: + return access_type_t::RW; + case 36: + return access_type_t::RO; + case 40: + return access_type_t::RO; + case 44: + return access_type_t::RW; + case 60: + return access_type_t::RW; + case 64: + return access_type_t::RW; + case 68: + return access_type_t::RW; + case 72: + return access_type_t::RW; + case 76: + return access_type_t::RW; + case 128: + return access_type_t::RW; + case 136: + return access_type_t::RW; + case 144: + return access_type_t::RW; + case 152: + return access_type_t::RW; + case 160: + return access_type_t::RW; + case 168: + return access_type_t::RW; + case 176: + return access_type_t::RW; + case 184: + return access_type_t::RW; + case 256: + return access_type_t::RO; + case 260: + return access_type_t::RO; + case 264: + return access_type_t::RO; + case 272: + return access_type_t::RO; + case 276: + return access_type_t::RO; + case 320: + return access_type_t::RW; + case 324: + return access_type_t::RW; + case 328: + return access_type_t::RW; + case 332: + return access_type_t::RW; + case 336: + return access_type_t::RW; + case 384: + return access_type_t::RW; + case 388: + return access_type_t::RW; + case 392: + return access_type_t::RW; + case 396: + return access_type_t::RW; + case 400: + return access_type_t::RW; + case 404: + return access_type_t::RW; + case 408: + return access_type_t::RW; + case 416: + return access_type_t::RW; + case 424: + return access_type_t::RW; + case 428: + return access_type_t::RW; + case 512: + return access_type_t::RO; + case 516: + return access_type_t::RO; + case 520: + return access_type_t::RO; + case 524: + return access_type_t::RO; + case 528: + return access_type_t::RO; + case 532: + return access_type_t::RO; + case 536: + return access_type_t::RO; + case 540: + return access_type_t::RO; + case 544: + return access_type_t::RO; + case 548: + return access_type_t::RO; + case 552: + return access_type_t::RO; + case 556: + return access_type_t::RO; + case 560: + return access_type_t::RO; + case 564: + return access_type_t::RO; + case 568: + return access_type_t::RO; + case 572: + return access_type_t::RO; + case 576: + return access_type_t::RO; + case 584: + return access_type_t::RO; + case 588: + return access_type_t::RO; + case 592: + return access_type_t::RO; + case 600: + return access_type_t::RO; + case 608: + return access_type_t::RO; + case 616: + return access_type_t::RO; + case 620: + return access_type_t::RO; + case 628: + return access_type_t::RO; + case 636: + return access_type_t::RO; + case 640: + return access_type_t::RO; + case 692: + return access_type_t::RO; + case 696: + return access_type_t::RO; + case 700: + return access_type_t::RO; + case 768: + return access_type_t::RW; + case 772: + return access_type_t::RW; + case 776: + return access_type_t::RW; + case 780: + return access_type_t::RW; + case 896: + return access_type_t::RW; + case 900: + return access_type_t::RW; + case 904: + return access_type_t::RW; + case 908: + return access_type_t::RW; + case 1024: + return access_type_t::RW; + case 1028: + return access_type_t::RW; + case 1032: + return access_type_t::RW; + case 1036: + return access_type_t::RW; + case 1040: + return access_type_t::RW; + case 1044: + return access_type_t::RW; + case 1048: + return access_type_t::RW; + case 1052: + return access_type_t::RW; + case 1056: + return access_type_t::RW; + case 1060: + return access_type_t::RW; + case 1064: + return access_type_t::RW; + case 1068: + return access_type_t::RW; + case 1072: + return access_type_t::RW; + case 1076: + return access_type_t::RW; + case 1080: + return access_type_t::RW; + case 1084: + return access_type_t::RW; + case 1088: + return access_type_t::RW; + case 1092: + return access_type_t::RW; + case 1096: + return access_type_t::RW; + case 1100: + return access_type_t::RW; + case 1104: + return access_type_t::RW; + case 1108: + return access_type_t::RW; + case 1112: + return access_type_t::RW; + case 1116: + return access_type_t::RW; + case 1120: + return access_type_t::RW; + case 1124: + return access_type_t::RW; + case 1128: + return access_type_t::RW; + case 1132: + return access_type_t::RW; + case 1136: + return access_type_t::RW; + case 1140: + return access_type_t::RW; + case 1144: + return access_type_t::RW; + case 1148: + return access_type_t::RW; + case 1152: + return access_type_t::RW; + case 1156: + return access_type_t::RW; + case 1160: + return access_type_t::RW; + case 1164: + return access_type_t::RW; + case 1168: + return access_type_t::RW; + case 1172: + return access_type_t::RW; + case 1176: + return access_type_t::RW; + case 1180: + return access_type_t::RW; + case 1184: + return access_type_t::RW; + case 1188: + return access_type_t::RW; + case 1192: + return access_type_t::RW; + case 1196: + return access_type_t::RW; + case 1200: + return access_type_t::RW; + case 1204: + return access_type_t::RW; + case 1208: + return access_type_t::RW; + case 1212: + return access_type_t::RW; + case 1216: + return access_type_t::RW; + case 1220: + return access_type_t::RW; + case 1224: + return access_type_t::RW; + case 1228: + return access_type_t::RW; + case 1232: + return access_type_t::RW; + case 1236: + return access_type_t::RW; + case 1240: + return access_type_t::RW; + case 1244: + return access_type_t::RW; + case 1248: + return access_type_t::RW; + case 1252: + return access_type_t::RW; + case 1256: + return access_type_t::RW; + case 1260: + return access_type_t::RW; + case 1264: + return access_type_t::RW; + case 1268: + return access_type_t::RW; + case 1272: + return access_type_t::RW; + case 1276: + return access_type_t::RW; + case 1280: + return access_type_t::RW; + case 1284: + return access_type_t::RW; + case 1288: + return access_type_t::RW; + case 1292: + return access_type_t::RW; + case 1296: + return access_type_t::RW; + case 1300: + return access_type_t::RW; + case 1304: + return access_type_t::RW; + case 1308: + return access_type_t::RW; + case 1312: + return access_type_t::RW; + case 1316: + return access_type_t::RW; + case 1320: + return access_type_t::RW; + case 1324: + return access_type_t::RW; + case 1328: + return access_type_t::RW; + case 1332: + return access_type_t::RW; + case 1336: + return access_type_t::RW; + case 1340: + return access_type_t::RW; + case 1344: + return access_type_t::RW; + case 1348: + return access_type_t::RW; + case 1352: + return access_type_t::RW; + case 1356: + return access_type_t::RW; + case 1360: + return access_type_t::RW; + case 1364: + return access_type_t::RW; + case 1368: + return access_type_t::RW; + case 1372: + return access_type_t::RW; + case 1376: + return access_type_t::RW; + case 1380: + return access_type_t::RW; + case 1384: + return access_type_t::RW; + case 1388: + return access_type_t::RW; + case 1392: + return access_type_t::RW; + case 1396: + return access_type_t::RW; + case 1400: + return access_type_t::RW; + case 1404: + return access_type_t::RW; + case 1408: + return access_type_t::RW; + case 1412: + return access_type_t::RW; + case 1416: + return access_type_t::RW; + case 1420: + return access_type_t::RW; + case 1424: + return access_type_t::RW; + case 1428: + return access_type_t::RW; + case 1432: + return access_type_t::RW; + case 1436: + return access_type_t::RW; + case 1440: + return access_type_t::RW; + case 1444: + return access_type_t::RW; + case 1448: + return access_type_t::RW; + case 1452: + return access_type_t::RW; + case 1456: + return access_type_t::RW; + case 1460: + return access_type_t::RW; + case 1464: + return access_type_t::RW; + case 1468: + return access_type_t::RW; + case 1472: + return access_type_t::RW; + case 1476: + return access_type_t::RW; + case 1480: + return access_type_t::RW; + case 1484: + return access_type_t::RW; + case 1488: + return access_type_t::RW; + case 1492: + return access_type_t::RW; + case 1496: + return access_type_t::RW; + case 1500: + return access_type_t::RW; + case 1504: + return access_type_t::RW; + case 1508: + return access_type_t::RW; + case 1512: + return access_type_t::RW; + case 1516: + return access_type_t::RW; + case 1520: + return access_type_t::RW; + case 1524: + return access_type_t::RW; + case 1528: + return access_type_t::RW; + case 1532: + return access_type_t::RW; + case 1536: + return access_type_t::RW; + case 1540: + return access_type_t::RW; + case 1544: + return access_type_t::RW; + case 1548: + return access_type_t::RW; + case 1552: + return access_type_t::RW; + case 1556: + return access_type_t::RW; + case 1560: + return access_type_t::RW; + case 1564: + return access_type_t::RW; + case 1568: + return access_type_t::RW; + case 1572: + return access_type_t::RW; + case 1576: + return access_type_t::RW; + case 1580: + return access_type_t::RW; + case 1584: + return access_type_t::RW; + case 1588: + return access_type_t::RW; + case 1592: + return access_type_t::RW; + case 1596: + return access_type_t::RW; + case 1600: + return access_type_t::RW; + case 1604: + return access_type_t::RW; + case 1608: + return access_type_t::RW; + case 1612: + return access_type_t::RW; + case 1616: + return access_type_t::RW; + case 1620: + return access_type_t::RW; + case 1624: + return access_type_t::RW; + case 1628: + return access_type_t::RW; + case 1632: + return access_type_t::RW; + case 1636: + return access_type_t::RW; + case 1640: + return access_type_t::RW; + case 1644: + return access_type_t::RW; + case 1648: + return access_type_t::RW; + case 1652: + return access_type_t::RW; + case 1656: + return access_type_t::RW; + case 1660: + return access_type_t::RW; + case 1664: + return access_type_t::RW; + case 1668: + return access_type_t::RW; + case 1672: + return access_type_t::RW; + case 1676: + return access_type_t::RW; + case 1680: + return access_type_t::RW; + case 1684: + return access_type_t::RW; + case 1688: + return access_type_t::RW; + case 1692: + return access_type_t::RW; + case 1696: + return access_type_t::RW; + case 1700: + return access_type_t::RW; + case 1704: + return access_type_t::RW; + case 1708: + return access_type_t::RW; + case 1712: + return access_type_t::RW; + case 1716: + return access_type_t::RW; + case 1720: + return access_type_t::RW; + case 1724: + return access_type_t::RW; + case 1728: + return access_type_t::RW; + case 1732: + return access_type_t::RW; + case 1736: + return access_type_t::RW; + case 1740: + return access_type_t::RW; + case 1744: + return access_type_t::RW; + case 1748: + return access_type_t::RW; + case 1752: + return access_type_t::RW; + case 1756: + return access_type_t::RW; + case 1760: + return access_type_t::RW; + case 1764: + return access_type_t::RW; + case 1768: + return access_type_t::RW; + case 1772: + return access_type_t::RW; + case 1776: + return access_type_t::RW; + case 1780: + return access_type_t::RW; + case 1784: + return access_type_t::RW; + case 1788: + return access_type_t::RW; + case 1792: + return access_type_t::RW; + case 1796: + return access_type_t::RW; + case 1800: + return access_type_t::RW; + case 1804: + return access_type_t::RW; + case 1808: + return access_type_t::RW; + case 1812: + return access_type_t::RW; + case 1816: + return access_type_t::RW; + case 1820: + return access_type_t::RW; + case 1824: + return access_type_t::RW; + case 1828: + return access_type_t::RW; + case 1832: + return access_type_t::RW; + case 1836: + return access_type_t::RW; + case 1840: + return access_type_t::RW; + case 1844: + return access_type_t::RW; + case 1848: + return access_type_t::RW; + case 1852: + return access_type_t::RW; + case 1856: + return access_type_t::RW; + case 1860: + return access_type_t::RW; + case 1864: + return access_type_t::RW; + case 1868: + return access_type_t::RW; + case 1872: + return access_type_t::RW; + case 1876: + return access_type_t::RW; + case 1880: + return access_type_t::RW; + case 1884: + return access_type_t::RW; + case 1888: + return access_type_t::RW; + case 1892: + return access_type_t::RW; + case 1896: + return access_type_t::RW; + case 1900: + return access_type_t::RW; + case 1904: + return access_type_t::RW; + case 1908: + return access_type_t::RW; + case 1912: + return access_type_t::RW; + case 1916: + return access_type_t::RW; + case 1920: + return access_type_t::RW; + case 1924: + return access_type_t::RW; + case 1928: + return access_type_t::RW; + case 1932: + return access_type_t::RW; + case 1936: + return access_type_t::RW; + case 1940: + return access_type_t::RW; + case 1944: + return access_type_t::RW; + case 1948: + return access_type_t::RW; + case 1952: + return access_type_t::RW; + case 1956: + return access_type_t::RW; + case 1960: + return access_type_t::RW; + case 1964: + return access_type_t::RW; + case 1968: + return access_type_t::RW; + case 1972: + return access_type_t::RW; + case 1976: + return access_type_t::RW; + case 1980: + return access_type_t::RW; + case 1984: + return access_type_t::RW; + case 1988: + return access_type_t::RW; + case 1992: + return access_type_t::RW; + case 1996: + return access_type_t::RW; + case 2000: + return access_type_t::RW; + case 2004: + return access_type_t::RW; + case 2008: + return access_type_t::RW; + case 2012: + return access_type_t::RW; + case 2016: + return access_type_t::RW; + case 2020: + return access_type_t::RW; + case 2024: + return access_type_t::RW; + case 2028: + return access_type_t::RW; + case 2032: + return access_type_t::RW; + case 2036: + return access_type_t::RW; + case 2040: + return access_type_t::RW; + case 2044: + return access_type_t::RW; + case 2048: + return access_type_t::RW; + case 2052: + return access_type_t::RW; + case 2056: + return access_type_t::RW; + case 2060: + return access_type_t::RW; + case 2064: + return access_type_t::RW; + case 2068: + return access_type_t::RW; + case 2076: + return access_type_t::RW; + case 2084: + return access_type_t::RW; + case 2088: + return access_type_t::RW; + case 2092: + return access_type_t::RW; + case 2096: + return access_type_t::RW; + case 2100: + return access_type_t::RW; + case 2108: + return access_type_t::RW; + case 2116: + return access_type_t::RW; + case 2120: + return access_type_t::RW; + case 2124: + return access_type_t::RW; + case 2128: + return access_type_t::RW; + case 2132: + return access_type_t::RW; + case 2136: + return access_type_t::RW; + case 2140: + return access_type_t::RW; + case 2144: + return access_type_t::RW; + case 2152: + return access_type_t::RW; + case 2156: + return access_type_t::RW; + case 2160: + return access_type_t::RW; + case 2172: + return access_type_t::RW; + case 2176: + return access_type_t::RW; + case 2180: + return access_type_t::RW; + case 2184: + return access_type_t::RW; + case 2188: + return access_type_t::RW; + case 2192: + return access_type_t::RW; + case 2196: + return access_type_t::RW; + case 2200: + return access_type_t::RW; + case 2204: + return access_type_t::RW; + case 2208: + return access_type_t::RW; + case 2212: + return access_type_t::RW; + case 2228: + return access_type_t::RW; + case 2236: + return access_type_t::RW; + case 2240: + return access_type_t::RW; + case 2244: + return access_type_t::RW; + case 2248: + return access_type_t::RW; + case 2252: + return access_type_t::RW; + case 2304: + return access_type_t::RW; + case 2308: + return access_type_t::RW; + case 2324: + return access_type_t::RW; + case 2340: + return access_type_t::RW; + case 2344: + return access_type_t::RW; + case 2348: + return access_type_t::RW; + case 2352: + return access_type_t::RW; + case 2356: + return access_type_t::RW; + case 2364: + return access_type_t::RW; + case 2560: + return access_type_t::RW; + case 2568: + return access_type_t::RW; + case 2576: + return access_type_t::RW; + case 2584: + return access_type_t::RW; + case 2592: + return access_type_t::RW; + case 2600: + return access_type_t::RW; + case 2608: + return access_type_t::RW; + case 2624: + return access_type_t::RW; + case 2632: + return access_type_t::RW; + case 2640: + return access_type_t::RW; + case 2648: + return access_type_t::RW; + case 2656: + return access_type_t::RW; + case 2664: + return access_type_t::RW; + case 2672: + return access_type_t::RW; + case 2688: + return access_type_t::RW; + case 2696: + return access_type_t::RW; + case 2704: + return access_type_t::RW; + case 2712: + return access_type_t::RW; + case 2720: + return access_type_t::RW; + case 2724: + return access_type_t::RW; + case 2728: + return access_type_t::RW; + case 2732: + return access_type_t::RW; + case 2736: + return access_type_t::RW; + case 2752: + return access_type_t::RW; + case 2760: + return access_type_t::RW; + case 2768: + return access_type_t::RW; + case 2776: + return access_type_t::RW; + case 2784: + return access_type_t::RW; + case 2816: + return access_type_t::RW; + case 2824: + return access_type_t::RW; + case 2832: + return access_type_t::RW; + case 2840: + return access_type_t::RW; + case 2848: + return access_type_t::RW; + case 2856: + return access_type_t::RW; + case 2864: + return access_type_t::RW; + case 2880: + return access_type_t::RW; + case 2888: + return access_type_t::RW; + case 2896: + return access_type_t::RW; + case 2904: + return access_type_t::RW; + case 4032: + return access_type_t::RO; + case 4048: + return access_type_t::RO; + case 4052: + return access_type_t::RO; + case 4056: + return access_type_t::RO; + case 4060: + return access_type_t::RO; + case 4064: + return access_type_t::RO; + case 4068: + return access_type_t::RO; + case 4072: + return access_type_t::RO; + case 4076: + return access_type_t::RO; + case 4080: + return access_type_t::RO; + case 4084: + return access_type_t::RO; + case 4088: + return access_type_t::RO; + case 4092: + return access_type_t::RO; + default: + return access_type_t::RO; + } + } +#endif +}; + +#ifdef __cplusplus +struct isa +{ +#ifdef NPU_DISASSEMBLE + static int disassemble(const uint32_t *in, + std::string &op, + std::vector> &fields) + { + switch (*in & 0xffff) + { + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP): + { + const npu_op_stop_t &v = *reinterpret_cast(in); + op = "NPU_OP_STOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ): + { + const npu_op_irq_t &v = *reinterpret_cast(in); + op = "NPU_OP_IRQ"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV): + { + const npu_op_conv_t &v = *reinterpret_cast(in); + op = "NPU_OP_CONV"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE): + { + const npu_op_depthwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_DEPTHWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL): + { + const npu_op_pool_t &v = *reinterpret_cast(in); + op = "NPU_OP_POOL"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE): + { + const npu_op_elementwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_ELEMENTWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START): + { + const npu_op_dma_start_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT): + { + const npu_op_dma_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT): + { + const npu_op_kernel_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_KERNEL_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK): + { + const npu_op_pmu_mask_t &v = *reinterpret_cast(in); + op = "NPU_OP_PMU_MASK"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP): + { + const npu_set_ifm_pad_top_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_TOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT): + { + const npu_set_ifm_pad_left_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_LEFT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT): + { + const npu_set_ifm_pad_right_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_RIGHT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM): + { + const npu_set_ifm_pad_bottom_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_BOTTOM"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1): + { + const npu_set_ifm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION): + { + const npu_set_ifm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE): + { + const npu_set_ifm_upscale_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_UPSCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT): + { + const npu_set_ifm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1): + { + const npu_set_ifm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1): + { + const npu_set_ifm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1): + { + const npu_set_ifm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END): + { + const npu_set_ifm_ib_end_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_IB_END"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION): + { + const npu_set_ifm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1): + { + const npu_set_ofm_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1): + { + const npu_set_ofm_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1): + { + const npu_set_ofm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION): + { + const npu_set_ofm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1): + { + const npu_set_ofm_blk_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1): + { + const npu_set_ofm_blk_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1): + { + const npu_set_ofm_blk_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT): + { + const npu_set_ofm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1): + { + const npu_set_ofm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1): + { + const npu_set_ofm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1): + { + const npu_set_ofm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION): + { + const npu_set_ofm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1): + { + const npu_set_kernel_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1): + { + const npu_set_kernel_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE): + { + const npu_set_kernel_stride_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_STRIDE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE): + { + const npu_set_parallel_mode_t &v = *reinterpret_cast(in); + op = "NPU_SET_PARALLEL_MODE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT): + { + const npu_set_acc_format_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACC_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION): + { + const npu_set_activation_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN): + { + const npu_set_activation_min_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MIN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX): + { + const npu_set_activation_max_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION): + { + const npu_set_weight_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION): + { + const npu_set_scale_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START): + { + const npu_set_ab_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_AB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP): + { + const npu_set_blockdep_t &v = *reinterpret_cast(in); + op = "NPU_SET_BLOCKDEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION): + { + const npu_set_dma0_src_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION): + { + const npu_set_dma0_dst_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0): + { + const npu_set_dma0_size0_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1): + { + const npu_set_dma0_size1_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST): + { + const npu_set_ifm2_broadcast_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR): + { + const npu_set_ifm2_scalar_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_SCALAR"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION): + { + const npu_set_ifm2_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT): + { + const npu_set_ifm2_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1): + { + const npu_set_ifm2_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1): + { + const npu_set_ifm2_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1): + { + const npu_set_ifm2_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START): + { + const npu_set_ifm2_ib_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_IB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION): + { + const npu_set_ifm2_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0): + { + const npu_set_ifm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1): + { + const npu_set_ifm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2): + { + const npu_set_ifm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3): + { + const npu_set_ifm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X): + { + const npu_set_ifm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y): + { + const npu_set_ifm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C): + { + const npu_set_ifm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0): + { + const npu_set_ofm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1): + { + const npu_set_ofm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2): + { + const npu_set_ofm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3): + { + const npu_set_ofm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X): + { + const npu_set_ofm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y): + { + const npu_set_ofm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C): + { + const npu_set_ofm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE): + { + const npu_set_weight_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH): + { + const npu_set_weight_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE): + { + const npu_set_scale_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH): + { + const npu_set_scale_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE): + { + const npu_set_ofm_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE): + { + const npu_set_opa_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPA_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE): + { + const npu_set_opb_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPB_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC): + { + const npu_set_dma0_src_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST): + { + const npu_set_dma0_dst_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN): + { + const npu_set_dma0_len_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_LEN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0): + { + const npu_set_dma0_skip0_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SKIP0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1): + { + const npu_set_dma0_skip1_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SKIP1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0): + { + const npu_set_ifm2_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1): + { + const npu_set_ifm2_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2): + { + const npu_set_ifm2_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3): + { + const npu_set_ifm2_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X): + { + const npu_set_ifm2_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y): + { + const npu_set_ifm2_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C): + { + const npu_set_ifm2_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE): + { + const npu_set_weight1_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH): + { + const npu_set_weight1_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE): + { + const npu_set_scale1_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE1_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH): + { + const npu_set_scale1_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE1_LENGTH"; + v.disassemble(fields); + break; + } + } + return (*in & (3 << 14)) != 0 ? 2 : 1; + } +#endif +#endif + // Signal the end of command stream + struct npu_op_stop_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_stop_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_stop_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_stop_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_stop_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_stop_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // Raises an IRQ to the host + struct npu_op_irq_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_irq_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_irq_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_irq_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_irq_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_irq_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // 2D convolution + struct npu_op_conv_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_conv_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_conv_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_conv_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Depth-wise 2D convolution + struct npu_op_depthwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_depthwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_depthwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_depthwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Pooling + struct npu_op_pool_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pooling_mode : 3; // Pooling mode + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_op_pool_t(NPU_NAMESPACE::pooling_mode _pooling_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(static_cast(_pooling_mode) & ((1U << 3) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_pool_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pooling_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pool_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pool_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pooling_mode get_pooling_mode() const + { + return static_cast(pooling_mode); + } + CONSTEXPR npu_op_pool_t &set_pooling_mode(NPU_NAMESPACE::pooling_mode value) + { + pooling_mode = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "pooling_mode", + (pooling_mode < (sizeof(pooling_mode_str) / sizeof(pooling_mode_str[0])) ? + pooling_mode_str[pooling_mode] : + "****"))); + } +#endif +#endif + }; + // Elementwise operation + struct npu_op_elementwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t elementwise_mode : 6; // Elementwise mode + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_op_elementwise_t(NPU_NAMESPACE::elementwise_mode _elementwise_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(static_cast(_elementwise_mode) & ((1U << 6) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_elementwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), elementwise_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_elementwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_elementwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::elementwise_mode get_elementwise_mode() const + { + return static_cast(elementwise_mode); + } + CONSTEXPR npu_op_elementwise_t &set_elementwise_mode(NPU_NAMESPACE::elementwise_mode value) + { + elementwise_mode = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "elementwise_mode", + (elementwise_mode < (sizeof(elementwise_mode_str) / sizeof(elementwise_mode_str[0])) ? + elementwise_mode_str[elementwise_mode] : + "****"))); + } +#endif +#endif + }; + // Queue new DMA for the given channel + struct npu_op_dma_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_dma_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Wait for the DMA channel to have k or fewer active descriptors outstanding + struct npu_op_dma_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t k : 4; // Number of outstanding descriptors + uint32_t reserved1 : 12; +#ifdef __cplusplus + public: + npu_op_dma_wait_t(uint32_t _k) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(_k & ((1U << 4) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_dma_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_k() const + { + return static_cast(k); + } + CONSTEXPR npu_op_dma_wait_t &set_k(uint32_t value) + { + k = static_cast(value) & ((1U << 4) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("k", std::to_string(k))); + } +#endif +#endif + }; + // Wait for n or fewer kernel operations to be remaining + struct npu_op_kernel_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t n : 2; // Number of kernel operations in range 0-3 + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_op_kernel_wait_t(uint32_t _n) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(_n & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_kernel_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_kernel_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_kernel_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_n() const + { + return static_cast(n); + } + CONSTEXPR npu_op_kernel_wait_t &set_n(uint32_t value) + { + n = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("n", std::to_string(n))); + } +#endif +#endif + }; + // Enable or disable PMU counting (debug feature only) + struct npu_op_pmu_mask_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t enable : 1; // Enable or disable PMU mask + uint32_t reserved1 : 15; +#ifdef __cplusplus + public: + npu_op_pmu_mask_t(uint32_t _enable) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(_enable & ((1U << 1) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_op_pmu_mask_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pmu_mask_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pmu_mask_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_enable() const + { + return static_cast(enable); + } + CONSTEXPR npu_op_pmu_mask_t &set_enable(uint32_t value) + { + enable = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("enable", std::to_string(enable))); + } +#endif +#endif + }; + // IFM top pad + struct npu_set_ifm_pad_top_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM top pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_top_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_top_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM left pad + struct npu_set_ifm_pad_left_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM left pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_left_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_left_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM right pad + struct npu_set_ifm_pad_right_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM right pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_right_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_right_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM bottom pad + struct npu_set_ifm_pad_bottom_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM bottom pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_bottom_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_bottom_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // Number of input channels for convolution + struct npu_set_ifm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Number of input channels for convolution +#ifdef __cplusplus + public: + npu_set_ifm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // IFM Precision + struct npu_set_ifm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t scale_mode : 2; // IFM scale mode + uint32_t reserved3 : 4; + uint32_t round_mode : 2; // IFM round mode +#ifdef __cplusplus + public: + npu_set_ifm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ifm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 2) - 1)), reserved3(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ifm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), scale_mode(0), reserved3(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_scale_mode(NPU_NAMESPACE::ifm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ifm_scale_mode_str) / sizeof(ifm_scale_mode_str[0])) ? + ifm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // IFM upscale mode + struct npu_set_ifm_upscale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mode : 2; // IFM upscale mode + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_ifm_upscale_t(NPU_NAMESPACE::ifm_upscale_mode _mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(static_cast(_mode) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_upscale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_upscale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_upscale_mode get_mode() const + { + return static_cast(mode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_mode(NPU_NAMESPACE::ifm_upscale_mode value) + { + mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "mode", + (mode < (sizeof(ifm_upscale_mode_str) / sizeof(ifm_upscale_mode_str[0])) ? ifm_upscale_mode_str[mode] : + "****"))); + } +#endif +#endif + }; + // IFM zero point + struct npu_set_ifm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM Tile 0 and tile 2 width + struct npu_set_ifm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM Tile 0 height + struct npu_set_ifm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM Tile 1 height + struct npu_set_ifm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // End of IB0,IB1 buffers + struct npu_set_ifm_ib_end_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_end : 6; // End of IB0,IB1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm_ib_end_t(uint32_t _ib_end) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(_ib_end & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm_ib_end_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_end() const + { + return static_cast(ib_end); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_ib_end(uint32_t value) + { + ib_end = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_end", std::to_string(ib_end))); + } +#endif +#endif + }; + // Index n for IFM access + struct npu_set_ifm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number n + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ifm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Output feature map width + struct npu_set_ofm_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Output feature map width +#ifdef __cplusplus + public: + npu_set_ofm_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Output feature map height + struct npu_set_ofm_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Output feature map height +#ifdef __cplusplus + public: + npu_set_ofm_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Output feature map depth + struct npu_set_ofm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Output feature map depth +#ifdef __cplusplus + public: + npu_set_ofm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM Precision + struct npu_set_ofm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // OFM type + uint32_t activation_precision : 2; // OFM precision + uint32_t reserved1 : 3; + uint32_t activation_format : 2; // OFM format + uint32_t scale_mode : 1; // OFM scale mode + uint32_t reserved2 : 5; + uint32_t round_mode : 2; // OFM round mode +#ifdef __cplusplus + public: + npu_set_ofm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ofm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved1(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 1) - 1)), reserved2(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ofm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), + activation_precision(0), reserved1(0), activation_format(0), scale_mode(0), reserved2(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ofm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_scale_mode(NPU_NAMESPACE::ofm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ofm_scale_mode_str) / sizeof(ofm_scale_mode_str[0])) ? + ofm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // OFM block width + struct npu_set_ofm_blk_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 6; // OFM block width + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ofm_blk_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM block height + struct npu_set_ofm_blk_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 5; // OFM block height + uint32_t reserved1 : 11; +#ifdef __cplusplus + public: + npu_set_ofm_blk_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 5) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 5) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM block depth + struct npu_set_ofm_blk_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 7; // OFM block depth + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ofm_blk_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 7) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM zero point + struct npu_set_ofm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ofm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // OFM Tile 0 and tile 2 width + struct npu_set_ofm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // OFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ofm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM Tile 0 height + struct npu_set_ofm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ofm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM Tile 1 height + struct npu_set_ofm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ofm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Index n for OFM access + struct npu_set_ofm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for OFM access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ofm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ofm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Kernel width + struct npu_set_kernel_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Kernel width +#ifdef __cplusplus + public: + npu_set_kernel_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Kernel height + struct npu_set_kernel_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Kernel height +#ifdef __cplusplus + public: + npu_set_kernel_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Kernel stride + struct npu_set_kernel_stride_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t stride_x_lsb : 1; // Stride x LSB. (kernel_x_stride - 1)[0] + uint32_t stride_y_lsb : 1; // Stride y LSB. (kernel_y_stride - 1)[0] + uint32_t weight_order : 1; // Weight ordering mode + uint32_t dilation_x : 1; // Kernel x dilation + uint32_t dilation_y : 1; // Kernel y dilation + uint32_t decomposition : 1; // Kernel decomposition + uint32_t stride_x_msb : 1; // Stride x MSB. (kernel_x_stride - 1) >> 1 + uint32_t reserved1 : 2; + uint32_t stride_y_msb : 1; // Stride y MSB. (kernel_y_stride - 1) >> 1 + uint32_t reserved2 : 6; +#ifdef __cplusplus + public: + npu_set_kernel_stride_t(uint32_t _stride_x_lsb, + uint32_t _stride_y_lsb, + NPU_NAMESPACE::weight_order _weight_order, + NPU_NAMESPACE::kernel_dilation _dilation_x, + NPU_NAMESPACE::kernel_dilation _dilation_y, + NPU_NAMESPACE::kernel_decomposition _decomposition, + uint32_t _stride_x_msb, + uint32_t _stride_y_msb) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(_stride_x_lsb & ((1U << 1) - 1)), stride_y_lsb(_stride_y_lsb & ((1U << 1) - 1)), + weight_order(static_cast(_weight_order) & ((1U << 1) - 1)), + dilation_x(static_cast(_dilation_x) & ((1U << 1) - 1)), + dilation_y(static_cast(_dilation_y) & ((1U << 1) - 1)), + decomposition(static_cast(_decomposition) & ((1U << 1) - 1)), + stride_x_msb(_stride_x_msb & ((1U << 1) - 1)), reserved1(0), stride_y_msb(_stride_y_msb & ((1U << 1) - 1)), + reserved2(0) + { + } + CONSTEXPR npu_set_kernel_stride_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), stride_x_lsb(0), stride_y_lsb(0), + weight_order(0), dilation_x(0), dilation_y(0), decomposition(0), stride_x_msb(0), reserved1(0), + stride_y_msb(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_stride_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_stride_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_lsb() const + { + return static_cast(stride_x_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_lsb(uint32_t value) + { + stride_x_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_lsb() const + { + return static_cast(stride_y_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_lsb(uint32_t value) + { + stride_y_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_order get_weight_order() const + { + return static_cast(weight_order); + } + CONSTEXPR npu_set_kernel_stride_t &set_weight_order(NPU_NAMESPACE::weight_order value) + { + weight_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_x() const + { + return static_cast(dilation_x); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_x(NPU_NAMESPACE::kernel_dilation value) + { + dilation_x = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_y() const + { + return static_cast(dilation_y); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_y(NPU_NAMESPACE::kernel_dilation value) + { + dilation_y = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_decomposition get_decomposition() const + { + return static_cast(decomposition); + } + CONSTEXPR npu_set_kernel_stride_t &set_decomposition(NPU_NAMESPACE::kernel_decomposition value) + { + decomposition = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_msb() const + { + return static_cast(stride_x_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_msb(uint32_t value) + { + stride_x_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_msb() const + { + return static_cast(stride_y_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_msb(uint32_t value) + { + stride_y_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("stride_x_lsb", std::to_string(stride_x_lsb))); + fields.push_back(std::make_pair("stride_y_lsb", std::to_string(stride_y_lsb))); + fields.push_back(std::make_pair( + "weight_order", + (weight_order < (sizeof(weight_order_str) / sizeof(weight_order_str[0])) ? + weight_order_str[weight_order] : + "****"))); + fields.push_back(std::make_pair( + "dilation_x", + (dilation_x < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_x] : + "****"))); + fields.push_back(std::make_pair( + "dilation_y", + (dilation_y < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_y] : + "****"))); + fields.push_back(std::make_pair( + "decomposition", + (decomposition < (sizeof(kernel_decomposition_str) / sizeof(kernel_decomposition_str[0])) ? + kernel_decomposition_str[decomposition] : + "****"))); + fields.push_back(std::make_pair("stride_x_msb", std::to_string(stride_x_msb))); + fields.push_back(std::make_pair("stride_y_msb", std::to_string(stride_y_msb))); + } +#endif +#endif + }; + // Multi-core parallel mode + struct npu_set_parallel_mode_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t parallel_mode : 1; // Multi-core parallel mode + uint32_t reserved1 : 15; +#ifdef __cplusplus + public: + npu_set_parallel_mode_t(NPU_NAMESPACE::parallel_mode _parallel_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + parallel_mode(static_cast(_parallel_mode) & ((1U << 1) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_parallel_mode_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), parallel_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_parallel_mode_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_parallel_mode_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::parallel_mode get_parallel_mode() const + { + return static_cast(parallel_mode); + } + CONSTEXPR npu_set_parallel_mode_t &set_parallel_mode(NPU_NAMESPACE::parallel_mode value) + { + parallel_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "parallel_mode", + (parallel_mode < (sizeof(parallel_mode_str) / sizeof(parallel_mode_str[0])) ? + parallel_mode_str[parallel_mode] : + "****"))); + } +#endif +#endif + }; + // Accumulator format + struct npu_set_acc_format_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t acc_format : 2; // Accumulator format + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_acc_format_t(NPU_NAMESPACE::acc_format _acc_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(static_cast(_acc_format) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_acc_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), acc_format(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_acc_format_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_acc_format_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_format get_acc_format() const + { + return static_cast(acc_format); + } + CONSTEXPR npu_set_acc_format_t &set_acc_format(NPU_NAMESPACE::acc_format value) + { + acc_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "acc_format", + (acc_format < (sizeof(acc_format_str) / sizeof(acc_format_str[0])) ? acc_format_str[acc_format] : + "****"))); + } +#endif +#endif + }; + // Activation function and clip range + struct npu_set_activation_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_function : 5; // Activation function (before table lookup) + uint32_t reserved1 : 7; + uint32_t activation_clip_range : 3; // Activation clip range. This must be set to 0 if table lookup is not used + uint32_t reserved2 : 1; +#ifdef __cplusplus + public: + npu_set_activation_t(NPU_NAMESPACE::activation_function _activation_function, + NPU_NAMESPACE::activation_clip_range _activation_clip_range) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(static_cast(_activation_function) & ((1U << 5) - 1)), reserved1(0), + activation_clip_range(static_cast(_activation_clip_range) & ((1U << 3) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_activation_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_function(0), reserved1(0), + activation_clip_range(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_function get_activation_function() const + { + return static_cast(activation_function); + } + CONSTEXPR npu_set_activation_t &set_activation_function(NPU_NAMESPACE::activation_function value) + { + activation_function = static_cast(value) & ((1U << 5) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_clip_range get_activation_clip_range() const + { + return static_cast(activation_clip_range); + } + CONSTEXPR npu_set_activation_t &set_activation_clip_range(NPU_NAMESPACE::activation_clip_range value) + { + activation_clip_range = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_function", + (activation_function < (sizeof(activation_function_str) / sizeof(activation_function_str[0])) ? + activation_function_str[activation_function] : + "****"))); + fields.push_back(std::make_pair( + "activation_clip_range", + (activation_clip_range < (sizeof(activation_clip_range_str) / sizeof(activation_clip_range_str[0])) ? + activation_clip_range_str[activation_clip_range] : + "****"))); + } +#endif +#endif + }; + // Lower bound clip + struct npu_set_activation_min_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_min_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_min_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_min_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_min_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_min_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Upper bound clip + struct npu_set_activation_max_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_max_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_max_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_max_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_max_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Index n for weight stream access + struct npu_set_weight_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for weight stream access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_weight_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_weight_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_weight_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Index n for scale stream access + struct npu_set_scale_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for scale stream access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_scale_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_scale_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_scale_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Start of ACC0,ACC1 buffers + struct npu_set_ab_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ab_start : 6; // Start of ACC0,ACC1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ab_start_t(uint32_t _ab_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(_ab_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ab_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ab_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ab_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ab_start() const + { + return static_cast(ab_start); + } + CONSTEXPR npu_set_ab_start_t &set_ab_start(uint32_t value) + { + ab_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ab_start", std::to_string(ab_start))); + } +#endif +#endif + }; + // Block number of blocks dependency + struct npu_set_blockdep_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t blockdep : 2; // Block number of blocks dependency between kernel operations + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_blockdep_t(uint32_t _blockdep) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(_blockdep & ((1U << 2) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_blockdep_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_blockdep_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_blockdep_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_blockdep() const + { + return static_cast(blockdep); + } + CONSTEXPR npu_set_blockdep_t &set_blockdep(uint32_t value) + { + blockdep = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("blockdep", std::to_string(blockdep))); + } +#endif +#endif + }; + // DMA0 source region + struct npu_set_dma0_src_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 5; +#ifdef __cplusplus + public: + npu_set_dma0_src_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_dma0_src_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + } +#endif +#endif + }; + // DMA0 destination region + struct npu_set_dma0_dst_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number if region_mode is region_mode_external. Else core mask to write to (bit k + // set for core k=0,1) + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 5; +#ifdef __cplusplus + public: + npu_set_dma0_dst_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_dma0_dst_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + } +#endif +#endif + }; + // Size of second dimension for 2D/3D transfers + struct npu_set_dma0_size0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of second dimension for 2D/3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size0_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size0_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size0_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // Size of third dimension for 3D transfers + struct npu_set_dma0_size1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of third dimension for 3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size1_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size1_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // IFM2 broadcast configuration + struct npu_set_ifm2_broadcast_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t + broadcast_h : 1; // Broadcast H dimension (if set then any accesses to IFM2 sets y=0 and IFM2 height=1) + uint32_t broadcast_w : 1; // Broadcast W dimension (if set then any accesses to IFM2 sets x=0 and IFM2 width=1) + uint32_t broadcast_c : 1; // Broadcast C dimension (if set then any accesses to IFM2 sets c=0 and IFM2 depth=1) + uint32_t reserved1 : 3; + uint32_t operand_order : 1; // Operand order + uint32_t broadcast_constant : 1; // Broadcast constant given by NPU_SET_IFM2_SCALAR and so ignore BH, BW and BC + uint32_t reserved2 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_h, + NPU_NAMESPACE::broadcast_mode _broadcast_w, + NPU_NAMESPACE::broadcast_mode _broadcast_c, + NPU_NAMESPACE::ifm2_operand_order _operand_order, + NPU_NAMESPACE::broadcast_mode _broadcast_constant) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_h(static_cast(_broadcast_h) & ((1U << 1) - 1)), + broadcast_w(static_cast(_broadcast_w) & ((1U << 1) - 1)), + broadcast_c(static_cast(_broadcast_c) & ((1U << 1) - 1)), reserved1(0), + operand_order(static_cast(_operand_order) & ((1U << 1) - 1)), + broadcast_constant(static_cast(_broadcast_constant) & ((1U << 1) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_ifm2_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), broadcast_h(0), broadcast_w(0), + broadcast_c(0), reserved1(0), operand_order(0), broadcast_constant(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_h() const + { + return static_cast(broadcast_h); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_h(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_h = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_w() const + { + return static_cast(broadcast_w); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_w(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_w = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_c() const + { + return static_cast(broadcast_c); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_c(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_c = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm2_operand_order get_operand_order() const + { + return static_cast(operand_order); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_operand_order(NPU_NAMESPACE::ifm2_operand_order value) + { + operand_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_constant() const + { + return static_cast(broadcast_constant); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_constant(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_constant = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "broadcast_h", + (broadcast_h < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_h] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_w", + (broadcast_w < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_w] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_c", + (broadcast_c < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_c] : + "****"))); + fields.push_back(std::make_pair( + "operand_order", + (operand_order < (sizeof(ifm2_operand_order_str) / sizeof(ifm2_operand_order_str[0])) ? + ifm2_operand_order_str[operand_order] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_constant", + (broadcast_constant < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_constant] : + "****"))); + } +#endif +#endif + }; + // IFM2 scalar value + struct npu_set_ifm2_scalar_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t scalar : 16; // int16 or uint16 depending on ifm2_precision.type +#ifdef __cplusplus + public: + npu_set_ifm2_scalar_t(uint32_t _scalar) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(_scalar & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_scalar_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scalar() const + { + return static_cast(scalar); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_scalar(uint32_t value) + { + scalar = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scalar", std::to_string(scalar))); + } +#endif +#endif + }; + // IFM2 Precision + struct npu_set_ifm2_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type - MUST MATCH IFM + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision - MUST MATCH IFM + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t reserved3 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), reserved3(0) + { + } + CONSTEXPR npu_set_ifm2_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), reserved3(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + } +#endif +#endif + }; + // IFM2 zero point + struct npu_set_ifm2_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm2_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM2 Tile 0 and tile 2 width + struct npu_set_ifm2_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM2 Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm2_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM2 Tile 0 height + struct npu_set_ifm2_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm2_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM2 Tile 1 height + struct npu_set_ifm2_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm2_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Start of IB0,IB1 buffers for IFM2 + struct npu_set_ifm2_ib_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_start : 6; // Start of IB0,IB1 buffers for IFM2 in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm2_ib_start_t(uint32_t _ib_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(_ib_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_ib_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_start() const + { + return static_cast(ib_start); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_ib_start(uint32_t value) + { + ib_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_start", std::to_string(ib_start))); + } +#endif +#endif + }; + // Index n for IFM2 access + struct npu_set_ifm2_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for IFM2 access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ifm2_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm2_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // IFM Tile 0 address + struct npu_set_ifm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 1 address + struct npu_set_ifm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 2 address + struct npu_set_ifm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base2_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 3 address + struct npu_set_ifm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base3_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between horizontal values + struct npu_set_ifm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_x_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between vertical values + struct npu_set_ifm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_y_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_c_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 0 address + struct npu_set_ofm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 1 address + struct npu_set_ofm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 2 address + struct npu_set_ofm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base2_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 3 address + struct npu_set_ofm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base3_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between horizontal values + struct npu_set_ofm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_x_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between vertical values + struct npu_set_ofm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_y_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ofm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_c_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte offset in WEIGHT_REGION + struct npu_set_weight_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_weight_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_weight_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte length + struct npu_set_weight_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 32; // Weight stream byte length +#ifdef __cplusplus + public: + npu_set_weight_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(_length) + { + } + CONSTEXPR npu_set_weight_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight_length_t &set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // Scale and bias stream input byte offset from SCALE_REGION + struct npu_set_scale_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_scale_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_scale_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_scale_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Scale and bias stream input byte length + struct npu_set_scale_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 20; // Scale and bias stream byte length + uint32_t reserved2 : 12; +#ifdef __cplusplus + public: + npu_set_scale_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + length(_length & ((1U << 20) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_scale_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale_length_t &set_length(uint32_t value) + { + length = value & ((1U << 20) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // OFM scale + struct npu_set_ofm_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. Not applied for 32-bit operations +#ifdef __cplusplus + public: + npu_set_ofm_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_ofm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ofm_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ofm_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand A scale + struct npu_set_opa_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift. Ignored if IFM scale mode is 0 + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. 16-bit if IFM scale mode is 0 +#ifdef __cplusplus + public: + npu_set_opa_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_opa_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opa_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opa_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_opa_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opa_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand B scale + struct npu_set_opb_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t scale : 16; // Scale. Not used if IFM scale mode is 1 or 2 + uint32_t reserved2 : 16; +#ifdef __cplusplus + public: + npu_set_opb_scale_t(uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + scale(_scale & ((1U << 16) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_opb_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), scale(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opb_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opb_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opb_scale_t &set_scale(uint32_t value) + { + scale = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // DMA user channel 0 source byte offset from DMA0_SRC_REGION + struct npu_set_dma0_src_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_src_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_src_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 destination byte offset from DMA0_DST_REGION + struct npu_set_dma0_dst_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_dst_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_dst_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 transfer length in bytes for each 1D transfer + struct npu_set_dma0_len_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_len_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_len_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_len_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // byte distance to skip after each inner (1D) transfer (2D/3D mode) (any alignment) + struct npu_set_dma0_skip0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_skip0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_skip0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_skip0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // byte distance to skip after each 2D transfer (3D mode) (any alignment) + struct npu_set_dma0_skip1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_skip1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_skip1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_skip1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 0 address + struct npu_set_ifm2_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 1 address + struct npu_set_ifm2_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 2 address + struct npu_set_ifm2_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base2_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 3 address + struct npu_set_ifm2_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base3_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between horizontal values + struct npu_set_ifm2_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between vertical values + struct npu_set_ifm2_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm2_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte offset in WEIGHT_REGION for core 1 + struct npu_set_weight1_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_weight1_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_weight1_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight1_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte length for core 1 + struct npu_set_weight1_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 32; // Weight stream byte length +#ifdef __cplusplus + public: + npu_set_weight1_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(_length) + { + } + CONSTEXPR npu_set_weight1_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH) && + control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight1_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight1_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight1_length_t &set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // Scale and bias stream input byte offset from SCALE_REGION for core 1 + struct npu_set_scale1_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_scale1_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_scale1_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_scale1_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Scale and bias stream input byte length for core 1 + struct npu_set_scale1_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 20; // Scale and bias stream byte length + uint32_t reserved2 : 12; +#ifdef __cplusplus + public: + npu_set_scale1_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + length(_length & ((1U << 20) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_scale1_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale1_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale1_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale1_length_t &set_length(uint32_t value) + { + length = value & ((1U << 20) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; +#ifdef __cplusplus +}; +#endif +#define NPU_OP_STRUCTS \ + NPU_OP_(stop) \ + NPU_OP_(irq) \ + NPU_OP_(conv) \ + NPU_OP_(depthwise) \ + NPU_OP_(pool) \ + NPU_OP_(elementwise) \ + NPU_OP_(dma_start) \ + NPU_OP_(dma_wait) \ + NPU_OP_(kernel_wait) \ + NPU_OP_(pmu_mask) + +#define NPU_SET_STRUCTS \ + NPU_SET_(ifm_pad_top) \ + NPU_SET_(ifm_pad_left) \ + NPU_SET_(ifm_pad_right) \ + NPU_SET_(ifm_pad_bottom) \ + NPU_SET_(ifm_depth_m1) \ + NPU_SET_(ifm_precision) \ + NPU_SET_(ifm_upscale) \ + NPU_SET_(ifm_zero_point) \ + NPU_SET_(ifm_width0_m1) \ + NPU_SET_(ifm_height0_m1) \ + NPU_SET_(ifm_height1_m1) \ + NPU_SET_(ifm_ib_end) \ + NPU_SET_(ifm_region) \ + NPU_SET_(ofm_width_m1) \ + NPU_SET_(ofm_height_m1) \ + NPU_SET_(ofm_depth_m1) \ + NPU_SET_(ofm_precision) \ + NPU_SET_(ofm_blk_width_m1) \ + NPU_SET_(ofm_blk_height_m1) \ + NPU_SET_(ofm_blk_depth_m1) \ + NPU_SET_(ofm_zero_point) \ + NPU_SET_(ofm_width0_m1) \ + NPU_SET_(ofm_height0_m1) \ + NPU_SET_(ofm_height1_m1) \ + NPU_SET_(ofm_region) \ + NPU_SET_(kernel_width_m1) \ + NPU_SET_(kernel_height_m1) \ + NPU_SET_(kernel_stride) \ + NPU_SET_(parallel_mode) \ + NPU_SET_(acc_format) \ + NPU_SET_(activation) \ + NPU_SET_(activation_min) \ + NPU_SET_(activation_max) \ + NPU_SET_(weight_region) \ + NPU_SET_(scale_region) \ + NPU_SET_(ab_start) \ + NPU_SET_(blockdep) \ + NPU_SET_(dma0_src_region) \ + NPU_SET_(dma0_dst_region) \ + NPU_SET_(dma0_size0) \ + NPU_SET_(dma0_size1) \ + NPU_SET_(ifm2_broadcast) \ + NPU_SET_(ifm2_scalar) \ + NPU_SET_(ifm2_precision) \ + NPU_SET_(ifm2_zero_point) \ + NPU_SET_(ifm2_width0_m1) \ + NPU_SET_(ifm2_height0_m1) \ + NPU_SET_(ifm2_height1_m1) \ + NPU_SET_(ifm2_ib_start) \ + NPU_SET_(ifm2_region) \ + NPU_SET_(ifm_base0) \ + NPU_SET_(ifm_base1) \ + NPU_SET_(ifm_base2) \ + NPU_SET_(ifm_base3) \ + NPU_SET_(ifm_stride_x) \ + NPU_SET_(ifm_stride_y) \ + NPU_SET_(ifm_stride_c) \ + NPU_SET_(ofm_base0) \ + NPU_SET_(ofm_base1) \ + NPU_SET_(ofm_base2) \ + NPU_SET_(ofm_base3) \ + NPU_SET_(ofm_stride_x) \ + NPU_SET_(ofm_stride_y) \ + NPU_SET_(ofm_stride_c) \ + NPU_SET_(weight_base) \ + NPU_SET_(weight_length) \ + NPU_SET_(scale_base) \ + NPU_SET_(scale_length) \ + NPU_SET_(ofm_scale) \ + NPU_SET_(opa_scale) \ + NPU_SET_(opb_scale) \ + NPU_SET_(dma0_src) \ + NPU_SET_(dma0_dst) \ + NPU_SET_(dma0_len) \ + NPU_SET_(dma0_skip0) \ + NPU_SET_(dma0_skip1) \ + NPU_SET_(ifm2_base0) \ + NPU_SET_(ifm2_base1) \ + NPU_SET_(ifm2_base2) \ + NPU_SET_(ifm2_base3) \ + NPU_SET_(ifm2_stride_x) \ + NPU_SET_(ifm2_stride_y) \ + NPU_SET_(ifm2_stride_c) \ + NPU_SET_(weight1_base) \ + NPU_SET_(weight1_length) \ + NPU_SET_(scale1_base) \ + NPU_SET_(scale1_length) + +#define EXPAND_ACC_FORMAT(FUNC, SEP) FUNC(acc_format, I32) SEP FUNC(acc_format, I40) SEP FUNC(acc_format, F16) + +#define EXPAND_ACTIVATION_CLIP_RANGE(FUNC, SEP) \ + FUNC(activation_clip_range, OFM_PRECISION) \ + SEP FUNC(activation_clip_range, FORCE_UINT8) SEP FUNC(activation_clip_range, FORCE_INT8) \ + SEP FUNC(activation_clip_range, FORCE_INT16) + +#define EXPAND_ACTIVATION_FORMAT(FUNC, SEP) FUNC(activation_format, NHWC) SEP FUNC(activation_format, NHCWB16) + +#define EXPAND_ACTIVATION_FUNCTION(FUNC, SEP) \ + FUNC(activation_function, RELU) \ + SEP FUNC(activation_function, TANH) SEP FUNC(activation_function, SIGMOID) SEP FUNC(activation_function, TABLE_0) \ + SEP FUNC(activation_function, TABLE_1) SEP FUNC(activation_function, TABLE_2) \ + SEP FUNC(activation_function, TABLE_3) SEP FUNC(activation_function, TABLE_4) \ + SEP FUNC(activation_function, TABLE_5) SEP FUNC(activation_function, TABLE_6) \ + SEP FUNC(activation_function, TABLE_7) + +#define EXPAND_ACTIVATION_PRECISION(FUNC, SEP) \ + FUNC(activation_precision, B8) \ + SEP FUNC(activation_precision, B16) SEP FUNC(activation_precision, B32) SEP FUNC(activation_precision, B64) + +#define EXPAND_ACTIVATION_TYPE(FUNC, SEP) FUNC(activation_type, UNSIGNED) SEP FUNC(activation_type, SIGNED) + +#define EXPAND_AXI_MEM_ENCODING(FUNC, SEP) \ + FUNC(axi_mem_encoding, DEVICE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, DEVICE_BUFFERABLE) SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_AND_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_AND_WRITE_ALLOCATE) + +#define EXPAND_BROADCAST_MODE(FUNC, SEP) FUNC(broadcast_mode, DISABLE) SEP FUNC(broadcast_mode, ENABLE) + +#define EXPAND_CMD0_OPCODE(FUNC, SEP) \ + FUNC(cmd0_opcode, NPU_OP_STOP) \ + SEP FUNC(cmd0_opcode, NPU_OP_IRQ) SEP FUNC(cmd0_opcode, NPU_OP_CONV) SEP FUNC( \ + cmd0_opcode, NPU_OP_DEPTHWISE) SEP FUNC(cmd0_opcode, NPU_OP_POOL) SEP FUNC(cmd0_opcode, NPU_OP_ELEMENTWISE) \ + SEP FUNC(cmd0_opcode, NPU_OP_DMA_START) SEP FUNC(cmd0_opcode, NPU_OP_DMA_WAIT) SEP FUNC( \ + cmd0_opcode, NPU_OP_KERNEL_WAIT) SEP FUNC(cmd0_opcode, NPU_OP_PMU_MASK) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PAD_TOP) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_LEFT) SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_RIGHT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_PAD_BOTTOM) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_DEPTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PRECISION) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_UPSCALE) SEP FUNC(cmd0_opcode, NPU_SET_IFM_ZERO_POINT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_WIDTH0_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_IB_END) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_REGION) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_DEPTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_PRECISION) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_BLK_WIDTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_OFM_BLK_HEIGHT_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_BLK_DEPTH_M1) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_ZERO_POINT) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT0_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_OFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_REGION) \ + SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_WIDTH_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_KERNEL_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_STRIDE) \ + SEP FUNC(cmd0_opcode, NPU_SET_PARALLEL_MODE) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_ACC_FORMAT) SEP FUNC(cmd0_opcode, NPU_SET_ACTIVATION) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_ACTIVATION_MIN) SEP FUNC(cmd0_opcode, \ + NPU_SET_ACTIVATION_MAX) \ + SEP FUNC(cmd0_opcode, NPU_SET_WEIGHT_REGION) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_SCALE_REGION) SEP FUNC(cmd0_opcode, NPU_SET_AB_START) \ + SEP FUNC(cmd0_opcode, NPU_SET_BLOCKDEP) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SRC_REGION) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_DMA0_DST_REGION) SEP FUNC(cmd0_opcode, \ + NPU_SET_DMA0_SIZE0) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_BROADCAST) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_SCALAR) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, \ + NPU_SET_IFM2_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT1_M1) \ + SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_IB_START) \ + SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_REGION) + +#define EXPAND_CMD1_OPCODE(FUNC, SEP) \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE0) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE1) SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE2) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE3) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_Y) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_C) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_BASE0) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE1) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE2) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE3) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_STRIDE_X) SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_C) SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT_BASE) SEP FUNC( \ + cmd1_opcode, NPU_SET_WEIGHT_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_SCALE_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_OFM_SCALE) \ + SEP FUNC(cmd1_opcode, NPU_SET_OPA_SCALE) SEP FUNC(cmd1_opcode, NPU_SET_OPB_SCALE) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SRC) SEP FUNC(cmd1_opcode, NPU_SET_DMA0_DST) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_LEN) SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SKIP0) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SKIP1) SEP FUNC( \ + cmd1_opcode, NPU_SET_IFM2_BASE0) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE1) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE2) SEP FUNC(cmd1_opcode, \ + NPU_SET_IFM2_BASE3) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_C) \ + SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT1_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT1_LENGTH) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE1_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE1_LENGTH) + +#define EXPAND_CMD_CTRL(FUNC, SEP) FUNC(cmd_ctrl, CMD0_CTRL) SEP FUNC(cmd_ctrl, CMD1_CTRL) + +#define EXPAND_CUSTOM_DMA(FUNC, SEP) FUNC(custom_dma, NOT_IMPLEMENTED) SEP FUNC(custom_dma, IMPLEMENTED) + +#define EXPAND_DMA_FAULT_SRC(FUNC, SEP) FUNC(dma_fault_src, AXI_M0) SEP FUNC(dma_fault_src, AXI_M1) + +#define EXPAND_DMA_REGION_MODE(FUNC, SEP) FUNC(dma_region_mode, EXTERNAL) SEP FUNC(dma_region_mode, INTERNAL) + +#define EXPAND_DMA_STRIDE_MODE(FUNC, SEP) \ + FUNC(dma_stride_mode, D1) SEP FUNC(dma_stride_mode, D2) SEP FUNC(dma_stride_mode, D3) + +#define EXPAND_ELEMENTWISE_MODE(FUNC, SEP) \ + FUNC(elementwise_mode, MUL) \ + SEP FUNC(elementwise_mode, ADD) SEP FUNC(elementwise_mode, SUB) SEP FUNC(elementwise_mode, MIN) \ + SEP FUNC(elementwise_mode, MAX) SEP FUNC(elementwise_mode, LRELU) SEP FUNC(elementwise_mode, ABS) \ + SEP FUNC(elementwise_mode, CLZ) SEP FUNC(elementwise_mode, SHR) SEP FUNC(elementwise_mode, SHL) + +#define EXPAND_FUNCTIONAL_SAFETY(FUNC, SEP) \ + FUNC(functional_safety, NOT_IMPLEMENTED) SEP FUNC(functional_safety, IMPLEMENTED) + +#define EXPAND_IFM2_OPERAND_ORDER(FUNC, SEP) FUNC(ifm2_operand_order, ORDER_B) SEP FUNC(ifm2_operand_order, ORDER_A) + +#define EXPAND_IFM_SCALE_MODE(FUNC, SEP) \ + FUNC(ifm_scale_mode, OPA_OPB_16) SEP FUNC(ifm_scale_mode, OPA_32) SEP FUNC(ifm_scale_mode, OPB_32) + +#define EXPAND_IFM_UPSCALE_MODE(FUNC, SEP) \ + FUNC(ifm_upscale_mode, NONE) SEP FUNC(ifm_upscale_mode, NEAREST) SEP FUNC(ifm_upscale_mode, ZEROS) + +#define EXPAND_KERNEL_DECOMPOSITION(FUNC, SEP) FUNC(kernel_decomposition, D8X8) SEP FUNC(kernel_decomposition, D4X4) + +#define EXPAND_KERNEL_DILATION(FUNC, SEP) FUNC(kernel_dilation, NONE) SEP FUNC(kernel_dilation, X2) + +#define EXPAND_MAX_BEATS(FUNC, SEP) FUNC(max_beats, B64) SEP FUNC(max_beats, B128) SEP FUNC(max_beats, B256) + +#define EXPAND_MEM_ATTR(FUNC, SEP) \ + FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER0) \ + SEP FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER1) SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER2) \ + SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER3) + +#define EXPAND_OFM_SCALE_MODE(FUNC, SEP) FUNC(ofm_scale_mode, PER_CHANNEL) SEP FUNC(ofm_scale_mode, GLOBAL) + +#define EXPAND_PARALLEL_MODE(FUNC, SEP) FUNC(parallel_mode, SINGLE_CORE) SEP FUNC(parallel_mode, DUAL_CORE_DEPTH) + +#define EXPAND_PMU_AXI_CHANNEL(FUNC, SEP) \ + FUNC(pmu_axi_channel, RD_CMD) \ + SEP FUNC(pmu_axi_channel, RD_IFM) SEP FUNC(pmu_axi_channel, RD_WEIGHTS) SEP FUNC(pmu_axi_channel, RD_SCALE_BIAS) \ + SEP FUNC(pmu_axi_channel, RD_MEM2MEM) SEP FUNC(pmu_axi_channel, WR_OFM) SEP FUNC(pmu_axi_channel, WR_MEM2MEM) + +#define EXPAND_PMU_EVENT(FUNC, SEP) \ + FUNC(pmu_event, NO_EVENT) \ + SEP FUNC(pmu_event, CYCLE) SEP FUNC(pmu_event, NPU_IDLE) SEP FUNC(pmu_event, CC_STALLED_ON_BLOCKDEP) SEP FUNC( \ + pmu_event, CC_STALLED_ON_SHRAM_RECONFIG) SEP FUNC(pmu_event, NPU_ACTIVE) SEP FUNC(pmu_event, MAC_ACTIVE) \ + SEP FUNC(pmu_event, MAC_ACTIVE_8BIT) SEP FUNC(pmu_event, MAC_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, MAC_DPU_ACTIVE) SEP FUNC(pmu_event, MAC_STALLED_BY_WD_ACC) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_WD) \ + SEP FUNC(pmu_event, MAC_STALLED_BY_ACC) SEP FUNC(pmu_event, MAC_STALLED_BY_IB) SEP FUNC( \ + pmu_event, \ + MAC_ACTIVE_32BIT) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_W) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_ACC) SEP FUNC(pmu_event, \ + AO_ACTIVE) \ + SEP FUNC(pmu_event, AO_ACTIVE_8BIT) SEP FUNC(pmu_event, AO_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, AO_STALLED_BY_OFMP_OB) SEP FUNC(pmu_event, AO_STALLED_BY_OFMP) SEP \ + FUNC(pmu_event, AO_STALLED_BY_OB) SEP FUNC(pmu_event, AO_STALLED_BY_ACC_IB) SEP FUNC( \ + pmu_event, AO_STALLED_BY_ACC) SEP FUNC(pmu_event, AO_STALLED_BY_IB) SEP \ + FUNC(pmu_event, WD_ACTIVE) SEP FUNC(pmu_event, WD_STALLED) SEP FUNC(pmu_event, WD_STALLED_BY_WS) SEP FUNC( \ + pmu_event, WD_STALLED_BY_WD_BUF) SEP FUNC(pmu_event, \ + WD_PARSE_ACTIVE) SEP \ + FUNC(pmu_event, WD_PARSE_STALLED) SEP FUNC(pmu_event, WD_PARSE_STALLED_IN) SEP FUNC( \ + pmu_event, WD_PARSE_STALLED_OUT) SEP FUNC(pmu_event, \ + WD_TRANS_WS) SEP \ + FUNC(pmu_event, WD_TRANS_WB) SEP FUNC(pmu_event, WD_TRANS_DW0) SEP FUNC( \ + pmu_event, WD_TRANS_DW1) SEP FUNC(pmu_event, \ + AXI0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_RD_TRANS_COMPLETED) SEP FUNC(pmu_event, AXI0_RD_DATA_BEAT_RECEIVED) SEP FUNC( \ + pmu_event, AXI0_RD_TRAN_REQ_STALLED) SEP FUNC(pmu_event, \ + AXI0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, AXI0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_WRITTEN) SEP FUNC( \ + pmu_event, AXI0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_STALLED) SEP FUNC( \ + pmu_event, \ + AXI0_ENABLED_CYCLES) SEP FUNC(pmu_event, \ + AXI0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, AXI0_WR_STALL_LIMIT) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_ANY) SEP FUNC(pmu_event, \ + AXI_LATENCY_32) SEP \ + FUNC(pmu_event, \ + AXI_LATENCY_64) SEP FUNC(pmu_event, \ + AXI_LATENCY_128) SEP \ + FUNC(pmu_event, AXI_LATENCY_256) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_512) SEP FUNC(pmu_event, \ + AXI_LATENCY_1024) SEP \ + FUNC(pmu_event, ECC_DMA) SEP FUNC( \ + pmu_event, \ + ECC_SB0) SEP FUNC(pmu_event, \ + AXI1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_RD_TRANS_COMPLETED) SEP FUNC( \ + pmu_event, AXI1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, AXI1_RD_TRAN_REQ_STALLED) SEP FUNC( \ + pmu_event, AXI1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, \ + AXI1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, \ + AXI1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, \ + AXI1_WR_TRAN_REQ_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_DATA_BEAT_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_ENABLED_CYCLES) SEP \ + FUNC( \ + pmu_event, \ + AXI1_RD_STALL_LIMIT) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_STALL_LIMIT) \ + SEP FUNC( \ + pmu_event, \ + ECC_SB1) + +#define EXPAND_POOLING_MODE(FUNC, SEP) \ + FUNC(pooling_mode, MAX) SEP FUNC(pooling_mode, AVERAGE) SEP FUNC(pooling_mode, REDUCE_SUM) + +#define EXPAND_PRIVILEGE_LEVEL(FUNC, SEP) FUNC(privilege_level, USER) SEP FUNC(privilege_level, PRIVILEGED) + +#define EXPAND_ROUND_MODE(FUNC, SEP) FUNC(round_mode, DBL) SEP FUNC(round_mode, TRUNCATE) SEP FUNC(round_mode, NATURAL) + +#define EXPAND_SECURITY_LEVEL(FUNC, SEP) FUNC(security_level, SECURE) SEP FUNC(security_level, NON_SECURE) + +#define EXPAND_STATE(FUNC, SEP) FUNC(state, STOPPED) SEP FUNC(state, RUNNING) + +#define EXPAND_WD_CORE_SLICE_STATE(FUNC, SEP) \ + FUNC(wd_core_slice_state, HEADER) SEP FUNC(wd_core_slice_state, PALETTE) SEP FUNC(wd_core_slice_state, WEIGHTS) + +#define EXPAND_WD_CTRL_STATE(FUNC, SEP) \ + FUNC(wd_ctrl_state, IDLE) \ + SEP FUNC(wd_ctrl_state, DRAIN) SEP FUNC(wd_ctrl_state, OFD_INIT) SEP FUNC(wd_ctrl_state, OFD_RUN) + +#define EXPAND_WEIGHT_ORDER(FUNC, SEP) FUNC(weight_order, DEPTH_FIRST) SEP FUNC(weight_order, PART_KERNEL_FIRST) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h new file mode 100644 index 0000000..18c9d6c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h @@ -0,0 +1,24620 @@ +/* + * SPDX-FileCopyrightText: Copyright 2020-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// clang-format off + +#ifndef ETHOSU85_INTERFACE_H +#define ETHOSU85_INTERFACE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#if !defined(__cplusplus) || __cplusplus < 201402L +#define CONSTEXPR +#else +#define CONSTEXPR constexpr +#endif + +#ifndef __cplusplus +#define STRUCT struct +#else +#define STRUCT +#endif + +#if defined(__cplusplus) && defined(NPU_DISASSEMBLE) +#include +#include +#include +#endif + +#if defined(__cplusplus) && !defined(NPU_NAMESPACE) +#define NPU_NAMESPACE npu +#endif + +#ifdef __cplusplus +#include +#include +#include +#endif + +#ifdef __cplusplus +namespace NPU_NAMESPACE +{ +#endif +#define NNX_ARCH_VERSION_MAJOR 2 +#define NNX_ARCH_VERSION_MINOR 0 +#define NNX_ARCH_VERSION_PATCH 0 + +// Register offsets +// +// Register subpage BASE +// +#define NPU_REG_ID 0x0000 +#define NPU_REG_STATUS 0x0004 +#define NPU_REG_CMD 0x0008 +#define NPU_REG_RESET 0x000C +#define NPU_REG_QBASE 0x0010 +#define NPU_REG_QBASE_HI 0x0014 +#define NPU_REG_QREAD 0x0018 +#define NPU_REG_QCONFIG 0x001C +#define NPU_REG_QSIZE 0x0020 +#define NPU_REG_PROT 0x0024 +#define NPU_REG_CONFIG 0x0028 +#define NPU_REG_COND_STATUS 0x0030 +#define NPU_REG_POWER_CTRL 0x0038 +#define NPU_REG_REGIONCFG 0x003C +#define NPU_REG_MEM_ATTR_BASE 0x0040 +#define NPU_REG_MEM_ATTR_ARRLEN 0x0004 +#define NPU_REG_AXI_SRAM 0x0050 +#define NPU_REG_AXI_EXT 0x0054 +#define NPU_REG_CFG_SRAM_CAP 0x0060 +#define NPU_REG_CFG_EXT_CAP 0x0064 +#define NPU_REG_CFG_SRAM_HASH0 0x0068 +#define NPU_REG_CFG_SRAM_HASH0_HI 0x006C +#define NPU_REG_CFG_SRAM_HASH1 0x0070 +#define NPU_REG_CFG_SRAM_HASH1_HI 0x0074 +#define NPU_REG_CFG_EXT_HASH0 0x0078 +#define NPU_REG_CFG_EXT_HASH0_HI 0x007C +#define BASE_REGISTERS_SIZE 0x0080 + +// +// Register subpage BASE_POINTERS +// +#define NPU_REG_BASEP_BASE 0x0080 +#define NPU_REG_BASEP_ARRLEN 0x0008 +#define BASE_POINTERS_REGISTERS_SIZE 0x0100 + +// +// Register subpage DEBUG +// +#define NPU_REG_CLKFORCE 0x0140 +#define NPU_REG_DEBUG_ADDRESS 0x0144 +#define NPU_REG_DEBUG_MISC 0x0148 +#define NPU_REG_FEATURE_DISABLE 0x0154 +#define DEBUG_REGISTERS_SIZE 0x0180 + +// +// Register subpage TSU_DEBUG +// +#define NPU_REG_DMA_IFM_SRC 0x0240 +#define NPU_REG_DMA_IFM_SRC_HI 0x0244 +#define NPU_REG_DMA_OFM_DST 0x0250 +#define NPU_REG_DMA_OFM_DST_HI 0x0254 +#define NPU_REG_DMA_WEIGHT_SRC 0x0258 +#define NPU_REG_DMA_WEIGHT_SRC_HI 0x025C +#define NPU_REG_DMA_CMD_SRC 0x0260 +#define NPU_REG_DMA_CMD_SRC_HI 0x0264 +#define NPU_REG_DMA_CMD_SIZE 0x0268 +#define NPU_REG_DMA_M2M_SRC 0x026C +#define NPU_REG_DMA_M2M_SRC_HI 0x0270 +#define NPU_REG_DMA_M2M_DST 0x0274 +#define NPU_REG_DMA_M2M_DST_HI 0x0278 +#define NPU_REG_CURRENT_QREAD 0x027C +#define NPU_REG_DMA_SCALE_SRC 0x0280 +#define NPU_REG_DMA_SCALE_SRC_HI 0x0284 +#define NPU_REG_DMA_WEIGHT1_SRC 0x0288 +#define NPU_REG_DMA_WEIGHT1_SRC_HI 0x028C +#define NPU_REG_DMA_WEIGHT2_SRC 0x0290 +#define NPU_REG_DMA_WEIGHT2_SRC_HI 0x0294 +#define NPU_REG_DMA_WEIGHT3_SRC 0x0298 +#define NPU_REG_DMA_WEIGHT3_SRC_HI 0x029C +#define NPU_REG_CURRENT_OP 0x02B8 +#define NPU_REG_CURRENT_CMD 0x02BC +#define TSU_DEBUG_REGISTERS_SIZE 0x0300 + +// +// Register subpage INTERNAL_MEMORY +// +#define NPU_REG_INTERNAL_MEMORY_BASE 0x0400 +#define NPU_REG_INTERNAL_MEMORY_ARRLEN 0x0100 +#define INTERNAL_MEMORY_REGISTERS_SIZE 0x0800 + +// +// Register subpage TSU_IFM +// +#define NPU_REG_IFM_PAD_TOP 0x0800 +#define NPU_REG_IFM_PAD_LEFT 0x0804 +#define NPU_REG_IFM_PAD_RIGHT 0x0808 +#define NPU_REG_IFM_PAD_BOTTOM 0x080C +#define NPU_REG_IFM_DEPTH_M1 0x0810 +#define NPU_REG_IFM_PRECISION 0x0814 +#define NPU_REG_IFM_UPSCALE 0x081C +#define NPU_REG_IFM_BROADCAST 0x0820 +#define NPU_REG_IFM_ZERO_POINT 0x0824 +#define NPU_REG_IFM_WIDTH0_M1 0x0828 +#define NPU_REG_IFM_HEIGHT0_M1 0x082C +#define NPU_REG_IFM_HEIGHT1_M1 0x0830 +#define NPU_REG_IFM_REGION 0x083C +#define TSU_IFM_REGISTERS_SIZE 0x0840 + +// +// Register subpage TSU_OFM +// +#define NPU_REG_OFM_WIDTH_M1 0x0844 +#define NPU_REG_OFM_HEIGHT_M1 0x0848 +#define NPU_REG_OFM_DEPTH_M1 0x084C +#define NPU_REG_OFM_PRECISION 0x0850 +#define NPU_REG_OFM_BLK_WIDTH_M1 0x0854 +#define NPU_REG_OFM_BLK_HEIGHT_M1 0x0858 +#define NPU_REG_OFM_BLK_DEPTH_M1 0x085C +#define NPU_REG_OFM_ZERO_POINT 0x0860 +#define NPU_REG_OFM_WIDTH0_M1 0x0868 +#define NPU_REG_OFM_HEIGHT0_M1 0x086C +#define NPU_REG_OFM_HEIGHT1_M1 0x0870 +#define NPU_REG_OFM_REGION 0x087C +#define TSU_OFM_REGISTERS_SIZE 0x0880 + +// +// Register subpage TSU_KERNEL +// +#define NPU_REG_KERNEL_WIDTH_M1 0x0880 +#define NPU_REG_KERNEL_HEIGHT_M1 0x0884 +#define NPU_REG_KERNEL_STRIDE 0x0888 +#define NPU_REG_ACC_FORMAT 0x0890 +#define NPU_REG_ACTIVATION 0x0894 +#define NPU_REG_ACTIVATION_MIN 0x0898 +#define NPU_REG_ACTIVATION_MAX 0x089C +#define NPU_REG_WEIGHT_REGION 0x08A0 +#define NPU_REG_SCALE_REGION 0x08A4 +#define NPU_REG_RESIZE_X_SCALE_N_M1 0x08A8 +#define NPU_REG_RESIZE_Y_SCALE_N_M1 0x08AC +#define NPU_REG_RESIZE_X_OFFSET 0x08B0 +#define NPU_REG_RESIZE_Y_OFFSET 0x08B4 +#define NPU_REG_WEIGHT_FORMAT 0x08B8 +#define NPU_REG_BLOCKDEP 0x08BC +#define TSU_KERNEL_REGISTERS_SIZE 0x08C0 + +// +// Register subpage TSU_DMA +// +#define NPU_REG_DMA0_SRC_REGION 0x08C0 +#define NPU_REG_DMA0_DST_REGION 0x08C4 +#define NPU_REG_DMA0_SIZE0 0x08C8 +#define NPU_REG_DMA0_SIZE1 0x08CC +#define NPU_REG_DMA0_IDX_REGION 0x08D0 +#define TSU_DMA_REGISTERS_SIZE 0x0900 + +// +// Register subpage TSU_IFM2 +// +#define NPU_REG_IFM2_BROADCAST 0x0900 +#define NPU_REG_IFM2_PRECISION 0x0914 +#define NPU_REG_IFM2_ZERO_POINT 0x0924 +#define NPU_REG_IFM2_WIDTH0_M1 0x0928 +#define NPU_REG_IFM2_HEIGHT0_M1 0x092C +#define NPU_REG_IFM2_HEIGHT1_M1 0x0930 +#define NPU_REG_IFM2_REGION 0x093C +#define TSU_IFM2_REGISTERS_SIZE 0x0940 + +// +// Register subpage TSU_IFM_BASE +// +#define NPU_REG_IFM_BASE0 0x0A00 +#define NPU_REG_IFM_BASE0_HI 0x0A04 +#define NPU_REG_IFM_BASE1 0x0A08 +#define NPU_REG_IFM_BASE1_HI 0x0A0C +#define NPU_REG_IFM_BASE2 0x0A10 +#define NPU_REG_IFM_BASE2_HI 0x0A14 +#define NPU_REG_IFM_BASE3 0x0A18 +#define NPU_REG_IFM_BASE3_HI 0x0A1C +#define NPU_REG_IFM_STRIDE_X 0x0A20 +#define NPU_REG_IFM_STRIDE_X_HI 0x0A24 +#define NPU_REG_IFM_STRIDE_Y 0x0A28 +#define NPU_REG_IFM_STRIDE_Y_HI 0x0A2C +#define NPU_REG_IFM_STRIDE_C 0x0A30 +#define NPU_REG_IFM_STRIDE_C_HI 0x0A34 +#define TSU_IFM_BASE_REGISTERS_SIZE 0x0A40 + +// +// Register subpage TSU_OFM_BASE +// +#define NPU_REG_OFM_BASE0 0x0A40 +#define NPU_REG_OFM_BASE0_HI 0x0A44 +#define NPU_REG_OFM_BASE1 0x0A48 +#define NPU_REG_OFM_BASE1_HI 0x0A4C +#define NPU_REG_OFM_BASE2 0x0A50 +#define NPU_REG_OFM_BASE2_HI 0x0A54 +#define NPU_REG_OFM_BASE3 0x0A58 +#define NPU_REG_OFM_BASE3_HI 0x0A5C +#define NPU_REG_OFM_STRIDE_X 0x0A60 +#define NPU_REG_OFM_STRIDE_X_HI 0x0A64 +#define NPU_REG_OFM_STRIDE_Y 0x0A68 +#define NPU_REG_OFM_STRIDE_Y_HI 0x0A6C +#define NPU_REG_OFM_STRIDE_C 0x0A70 +#define NPU_REG_OFM_STRIDE_C_HI 0x0A74 +#define TSU_OFM_BASE_REGISTERS_SIZE 0x0A80 + +// +// Register subpage TSU_WS_BASE +// +#define NPU_REG_WEIGHT_BASE 0x0A80 +#define NPU_REG_WEIGHT_BASE_HI 0x0A84 +#define NPU_REG_WEIGHT_LENGTH 0x0A88 +#define NPU_REG_WEIGHT_LENGTH_HI 0x0A8C +#define NPU_REG_SCALE_BASE 0x0A90 +#define NPU_REG_SCALE_BASE_HI 0x0A94 +#define NPU_REG_SCALE_LENGTH 0x0A98 +#define NPU_REG_SCALE_LENGTH_HI 0x0A9C +#define NPU_REG_OFM_SCALE 0x0AA0 +#define NPU_REG_OFM_SCALE_HI 0x0AA4 +#define NPU_REG_IFM_SCALE 0x0AA8 +#define NPU_REG_IFM_SCALE_HI 0x0AAC +#define NPU_REG_IFM2_SCALE 0x0AB0 +#define NPU_REG_IFM2_SCALE_HI 0x0AB4 +#define NPU_REG_OP_SCALAR 0x0AB8 +#define NPU_REG_OP_SCALAR_HI 0x0ABC +#define TSU_WS_BASE_REGISTERS_SIZE 0x0AC0 + +// +// Register subpage TSU_DMA_BASE +// +#define NPU_REG_DMA0_SRC 0x0AC0 +#define NPU_REG_DMA0_SRC_HI 0x0AC4 +#define NPU_REG_DMA0_DST 0x0AC8 +#define NPU_REG_DMA0_DST_HI 0x0ACC +#define NPU_REG_DMA0_LEN 0x0AD0 +#define NPU_REG_DMA0_LEN_HI 0x0AD4 +#define NPU_REG_DMA0_SRC_STRIDE0 0x0AD8 +#define NPU_REG_DMA0_SRC_STRIDE0_HI 0x0ADC +#define NPU_REG_DMA0_SRC_STRIDE1 0x0AE0 +#define NPU_REG_DMA0_SRC_STRIDE1_HI 0x0AE4 +#define NPU_REG_DMA0_DST_STRIDE0 0x0AE8 +#define NPU_REG_DMA0_DST_STRIDE0_HI 0x0AEC +#define NPU_REG_DMA0_DST_STRIDE1 0x0AF0 +#define NPU_REG_DMA0_DST_STRIDE1_HI 0x0AF4 +#define NPU_REG_DMA0_IDX 0x0AF8 +#define NPU_REG_DMA0_IDX_HI 0x0AFC +#define TSU_DMA_BASE_REGISTERS_SIZE 0x0B00 + +// +// Register subpage TSU_IFM2_BASE +// +#define NPU_REG_IFM2_BASE0 0x0B00 +#define NPU_REG_IFM2_BASE0_HI 0x0B04 +#define NPU_REG_IFM2_BASE1 0x0B08 +#define NPU_REG_IFM2_BASE1_HI 0x0B0C +#define NPU_REG_IFM2_BASE2 0x0B10 +#define NPU_REG_IFM2_BASE2_HI 0x0B14 +#define NPU_REG_IFM2_BASE3 0x0B18 +#define NPU_REG_IFM2_BASE3_HI 0x0B1C +#define NPU_REG_IFM2_STRIDE_X 0x0B20 +#define NPU_REG_IFM2_STRIDE_X_HI 0x0B24 +#define NPU_REG_IFM2_STRIDE_Y 0x0B28 +#define NPU_REG_IFM2_STRIDE_Y_HI 0x0B2C +#define NPU_REG_IFM2_STRIDE_C 0x0B30 +#define NPU_REG_IFM2_STRIDE_C_HI 0x0B34 +#define TSU_IFM2_BASE_REGISTERS_SIZE 0x0B40 + +// +// Register subpage TSU_WS1_BASE +// +#define NPU_REG_WEIGHT1_BASE 0x0B40 +#define NPU_REG_WEIGHT1_BASE_HI 0x0B44 +#define NPU_REG_WEIGHT1_LENGTH 0x0B48 +#define NPU_REG_WEIGHT1_LENGTH_HI 0x0B4C +#define NPU_REG_WEIGHT2_BASE 0x0B50 +#define NPU_REG_WEIGHT2_BASE_HI 0x0B54 +#define NPU_REG_WEIGHT2_LENGTH 0x0B58 +#define NPU_REG_WEIGHT2_LENGTH_HI 0x0B5C +#define NPU_REG_WEIGHT3_BASE 0x0B60 +#define NPU_REG_WEIGHT3_BASE_HI 0x0B64 +#define NPU_REG_WEIGHT3_LENGTH 0x0B68 +#define NPU_REG_WEIGHT3_LENGTH_HI 0x0B6C +#define NPU_REG_RESIZE_X_STEP 0x0B70 +#define NPU_REG_RESIZE_X_STEP_HI 0x0B74 +#define NPU_REG_RESIZE_Y_STEP 0x0B78 +#define NPU_REG_RESIZE_Y_STEP_HI 0x0B7C +#define TSU_WS1_BASE_REGISTERS_SIZE 0x0B80 + +// +// Register subpage TSU_USER_BASE +// +#define TSU_USER_BASE_REGISTERS_SIZE 0x0BC0 + +// +// Register subpage TSU_DMA_EBASE +// +#define NPU_REG_DMA0_IDX_MAX 0x0BC0 +#define NPU_REG_DMA0_IDX_MAX_HI 0x0BC4 +#define NPU_REG_DMA0_IDX_SKIP1 0x0BC8 +#define NPU_REG_DMA0_IDX_SKIP1_HI 0x0BCC +#define TSU_DMA_EBASE_REGISTERS_SIZE 0x0C00 + +// +// Register subpage ID +// +#define NPU_REG_REVISION 0x0FC0 +#define NPU_REG_PID4 0x0FD0 +#define NPU_REG_PID5 0x0FD4 +#define NPU_REG_PID6 0x0FD8 +#define NPU_REG_PID7 0x0FDC +#define NPU_REG_PID0 0x0FE0 +#define NPU_REG_PID1 0x0FE4 +#define NPU_REG_PID2 0x0FE8 +#define NPU_REG_PID3 0x0FEC +#define NPU_REG_CID0 0x0FF0 +#define NPU_REG_CID1 0x0FF4 +#define NPU_REG_CID2 0x0FF8 +#define NPU_REG_CID3 0x0FFC +#define ID_REGISTERS_SIZE 0x1000 + +// +// Register subpage DEBUG_STATUS +// +#define NPU_REG_WD_STATUS 0x1100 +#define NPU_REG_MAC_STATUS 0x1104 +#define NPU_REG_AO_STATUS 0x1108 +#define NPU_REG_DMA_STATUS0 0x1110 +#define NPU_REG_DMA_STATUS1 0x1114 +#define DEBUG_STATUS_REGISTERS_SIZE 0x1180 + +// +// Register subpage PMU +// +#define NPU_REG_PMCR 0x1180 +#define NPU_REG_PMCNTENSET 0x1184 +#define NPU_REG_PMCNTENCLR 0x1188 +#define NPU_REG_PMOVSSET 0x118C +#define NPU_REG_PMOVSCLR 0x1190 +#define NPU_REG_PMINTSET 0x1194 +#define NPU_REG_PMINTCLR 0x1198 +#define NPU_REG_PMCCNTR 0x11A0 +#define NPU_REG_PMCCNTR_HI 0x11A4 +#define NPU_REG_PMCCNTR_CFG 0x11A8 +#define NPU_REG_PMCAXI_CHAN 0x11AC +#define NPU_REG_PMCLUT 0x11B0 +#define PMU_REGISTERS_SIZE 0x1200 + +// +// Register subpage PMU_COUNTERS +// +#define NPU_REG_PMEVCNTR_BASE 0x1300 +#define NPU_REG_PMEVCNTR_ARRLEN 0x0008 +#define NPU_REG_PMEVTYPER_BASE 0x1380 +#define NPU_REG_PMEVTYPER_ARRLEN 0x0008 +#define PMU_COUNTERS_REGISTERS_SIZE 0x1400 + +#ifdef __cplusplus +// Enum types +enum class acc_format : uint8_t +{ + I32 = 0, + I48 = 1, +}; + +enum class acc_input : uint8_t +{ + RESET = 0, + KEEP = 1, + IFM2 = 2, +}; + +enum class acc_output : uint8_t +{ + ENABLE = 0, + DISABLE = 1, +}; + +enum class activation_clip_range : uint8_t +{ + B16 = 0, + NONE = 1, +}; + +enum class activation_format : uint8_t +{ + NHWC = 0, + NHCWB16 = 1, +}; + +enum class activation_function : uint8_t +{ + LUT_NONE = 0, + LUT_U8_U8 = 1, + LUT_S8_S8 = 4, + LUT_S8_S16 = 5, + LUT_S8_S32 = 7, + LUT_S16_S16 = 8, + LUT_S16_S32 = 9, + LUT_TANH = 10, + LUT_SIGMOID = 11, +}; + +enum class activation_precision : uint8_t +{ + B8 = 0, + B16 = 1, + B32 = 2, + B64 = 3, +}; + +enum class activation_reverse : uint8_t +{ + NONE = 0, + H = 1, + W = 2, + C = 3, +}; + +enum class activation_storage : uint8_t +{ + TILE2X2 = 0, + TILE3X1 = 1, + CHAINED = 2, + NONE = 3, +}; + +enum class activation_transpose : uint8_t +{ + HWC = 0, + WHC = 1, + HCW = 2, + WCH = 3, + CHW = 6, + CWH = 7, +}; + +enum class activation_type : uint8_t +{ + UNSIGNED = 0, + SIGNED = 1, +}; + +enum class axi_mem_domain : uint8_t +{ + NON_SHARABLE = 0, + INNER_SHARABLE = 1, + OUTER_SHARABLE = 2, + SYSTEM = 3, +}; + +enum class axi_mem_encoding : uint8_t +{ + DEVICE_NON_BUFFERABLE = 0, + DEVICE_BUFFERABLE = 1, + NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + WRITE_THROUGH_NO_ALLOCATE = 4, + WRITE_THROUGH_READ_ALLOCATE = 5, + WRITE_THROUGH_WRITE_ALLOCATE = 6, + WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + WRITE_BACK_NO_ALLOCATE = 8, + WRITE_BACK_READ_ALLOCATE = 9, + WRITE_BACK_WRITE_ALLOCATE = 10, + WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum class axi_port : uint8_t +{ + SRAM = 0, + EXT = 1, +}; + +enum class branch_cond : uint8_t +{ + ALWAYS = 0, + RF_TRUE = 1, +}; + +enum class broadcast_mode : uint8_t +{ + NONE = 0, + H = 1, + W = 2, + HW = 3, + C = 4, + CH = 5, + CW = 6, + CWH = 7, + SCALAR = 8, +}; + +enum class cmd0_opcode : uint16_t +{ + NPU_OP_STOP = 0, + NPU_OP_IRQ = 1, + NPU_OP_CONV = 2, + NPU_OP_DEPTHWISE = 3, + NPU_OP_POOL = 5, + NPU_OP_ELEMENTWISE = 6, + NPU_OP_RESIZE = 7, + NPU_OP_DMA_START = 16, + NPU_OP_DMA_WAIT = 17, + NPU_OP_KERNEL_WAIT = 18, + NPU_OP_PMU_MASK = 19, + NPU_SET_IFM_PAD_TOP = 256, + NPU_SET_IFM_PAD_LEFT = 257, + NPU_SET_IFM_PAD_RIGHT = 258, + NPU_SET_IFM_PAD_BOTTOM = 259, + NPU_SET_IFM_DEPTH_M1 = 260, + NPU_SET_IFM_PRECISION = 261, + NPU_SET_IFM_UPSCALE = 263, + NPU_SET_IFM_BROADCAST = 264, + NPU_SET_IFM_ZERO_POINT = 265, + NPU_SET_IFM_WIDTH0_M1 = 266, + NPU_SET_IFM_HEIGHT0_M1 = 267, + NPU_SET_IFM_HEIGHT1_M1 = 268, + NPU_SET_IFM_REGION = 271, + NPU_SET_OFM_WIDTH_M1 = 273, + NPU_SET_OFM_HEIGHT_M1 = 274, + NPU_SET_OFM_DEPTH_M1 = 275, + NPU_SET_OFM_PRECISION = 276, + NPU_SET_OFM_BLK_WIDTH_M1 = 277, + NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + NPU_SET_OFM_BLK_DEPTH_M1 = 279, + NPU_SET_OFM_ZERO_POINT = 280, + NPU_SET_OFM_WIDTH0_M1 = 282, + NPU_SET_OFM_HEIGHT0_M1 = 283, + NPU_SET_OFM_HEIGHT1_M1 = 284, + NPU_SET_OFM_REGION = 287, + NPU_SET_KERNEL_WIDTH_M1 = 288, + NPU_SET_KERNEL_HEIGHT_M1 = 289, + NPU_SET_KERNEL_STRIDE = 290, + NPU_SET_ACC_FORMAT = 292, + NPU_SET_ACTIVATION = 293, + NPU_SET_ACTIVATION_MIN = 294, + NPU_SET_ACTIVATION_MAX = 295, + NPU_SET_WEIGHT_REGION = 296, + NPU_SET_SCALE_REGION = 297, + NPU_SET_RESIZE_X_SCALE_N_M1 = 298, + NPU_SET_RESIZE_Y_SCALE_N_M1 = 299, + NPU_SET_RESIZE_X_OFFSET = 300, + NPU_SET_RESIZE_Y_OFFSET = 301, + NPU_SET_WEIGHT_FORMAT = 302, + NPU_SET_BLOCKDEP = 303, + NPU_SET_DMA0_SRC_REGION = 304, + NPU_SET_DMA0_DST_REGION = 305, + NPU_SET_DMA0_SIZE0 = 306, + NPU_SET_DMA0_SIZE1 = 307, + NPU_SET_DMA0_IDX_REGION = 308, + NPU_SET_IFM2_BROADCAST = 384, + NPU_SET_IFM2_PRECISION = 389, + NPU_SET_IFM2_ZERO_POINT = 393, + NPU_SET_IFM2_WIDTH0_M1 = 394, + NPU_SET_IFM2_HEIGHT0_M1 = 395, + NPU_SET_IFM2_HEIGHT1_M1 = 396, + NPU_SET_IFM2_REGION = 399, +}; + +enum class cmd1_opcode : uint16_t +{ + NPU_SET_IFM_BASE0 = 0, + NPU_SET_IFM_BASE1 = 1, + NPU_SET_IFM_BASE2 = 2, + NPU_SET_IFM_BASE3 = 3, + NPU_SET_IFM_STRIDE_X = 4, + NPU_SET_IFM_STRIDE_Y = 5, + NPU_SET_IFM_STRIDE_C = 6, + NPU_SET_OFM_BASE0 = 16, + NPU_SET_OFM_BASE1 = 17, + NPU_SET_OFM_BASE2 = 18, + NPU_SET_OFM_BASE3 = 19, + NPU_SET_OFM_STRIDE_X = 20, + NPU_SET_OFM_STRIDE_Y = 21, + NPU_SET_OFM_STRIDE_C = 22, + NPU_SET_WEIGHT_BASE = 32, + NPU_SET_WEIGHT_LENGTH = 33, + NPU_SET_SCALE_BASE = 34, + NPU_SET_SCALE_LENGTH = 35, + NPU_SET_OFM_SCALE = 36, + NPU_SET_IFM_SCALE = 37, + NPU_SET_IFM2_SCALE = 38, + NPU_SET_OP_SCALAR = 39, + NPU_SET_DMA0_SRC = 48, + NPU_SET_DMA0_DST = 49, + NPU_SET_DMA0_LEN = 50, + NPU_SET_DMA0_SRC_STRIDE0 = 51, + NPU_SET_DMA0_SRC_STRIDE1 = 52, + NPU_SET_DMA0_DST_STRIDE0 = 53, + NPU_SET_DMA0_DST_STRIDE1 = 54, + NPU_SET_DMA0_IDX = 55, + NPU_SET_DMA0_IDX_MAX = 56, + NPU_SET_DMA0_IDX_SKIP1 = 57, + NPU_SET_IFM2_BASE0 = 128, + NPU_SET_IFM2_BASE1 = 129, + NPU_SET_IFM2_BASE2 = 130, + NPU_SET_IFM2_BASE3 = 131, + NPU_SET_IFM2_STRIDE_X = 132, + NPU_SET_IFM2_STRIDE_Y = 133, + NPU_SET_IFM2_STRIDE_C = 134, + NPU_SET_WEIGHT1_BASE = 144, + NPU_SET_WEIGHT1_LENGTH = 145, + NPU_SET_WEIGHT2_BASE = 146, + NPU_SET_WEIGHT2_LENGTH = 147, + NPU_SET_WEIGHT3_BASE = 148, + NPU_SET_WEIGHT3_LENGTH = 149, + NPU_SET_RESIZE_X = 150, + NPU_SET_RESIZE_Y = 151, + NPU_OP_BRANCH = 256, +}; + +enum class cmd_ctrl : uint8_t +{ + CMD0_CTRL = 0, + CMD1_CTRL = 1, +}; + +enum class custom_dma : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class dma_fault_src : uint8_t +{ + SRAM = 0, + EXT = 1, +}; + +enum class dma_idx_mode : uint8_t +{ + DISABLED = 0, + ENABLED = 1, +}; + +enum class dma_region_mode : uint8_t +{ + EXTERNAL = 0, + INTERNAL = 1, +}; + +enum class dma_stride_mode : uint8_t +{ + D1 = 0, + D2 = 1, + D3 = 2, +}; + +enum class elementwise_mode : uint8_t +{ + MUL = 0, + ADD = 1, + SUB = 2, + MIN = 3, + MAX = 4, + LRELU = 5, + ABS = 6, + CLZ = 7, + SHR = 8, + SHL = 9, + LSR = 10, + DIV = 11, + CMP_EQ = 16, + CMP_NE = 17, + CMP_GE = 18, + CMP_GT = 19, + AND = 33, + OR = 34, + XOR = 35, + NOT = 36, + AND_NOT = 42, +}; + +enum class ifm_upscale_mode : uint8_t +{ + NONE = 0, + NEAREST = 1, + ZEROS = 2, +}; + +enum class kernel_decomposition : uint8_t +{ + D8X8 = 0, + D4X4 = 1, +}; + +enum class kernel_dilation : uint8_t +{ + NONE = 0, + X2 = 1, +}; + +enum class max_beats : uint8_t +{ + B64 = 0, + B128 = 1, + B256 = 2, +}; + +enum class microblock : uint8_t +{ + U1X1 = 0, + U1X2 = 1, + U1X4 = 2, + U2X2 = 3, + U2X4 = 4, + U4X4 = 5, +}; + +enum class ofm_scale_mode : uint8_t +{ + PER_CHANNEL = 0, + GLOBAL = 1, +}; + +enum class pmu_axi_channel : uint8_t +{ + RD_CMD = 0, + RD_IFM = 1, + RD_WEIGHTS = 2, + RD_SCALE_BIAS = 3, + RD_MEM2MEM = 4, + RD_IFM_STREAM = 5, + RD_MEM2MEM_IDX = 6, + WR_OFM = 8, + WR_MEM2MEM = 9, +}; + +enum class pmu_event : uint16_t +{ + NO_EVENT = 0, + CYCLE = 17, + NPU_IDLE = 32, + CC_STALLED_ON_BLOCKDEP = 33, + NPU_ACTIVE = 35, + MAC_ACTIVE = 48, + MAC_DPU_ACTIVE = 51, + MAC_STALLED_BY_W_OR_ACC = 52, + MAC_STALLED_BY_W = 53, + MAC_STALLED_BY_ACC = 54, + MAC_STALLED_BY_IB = 55, + AO_ACTIVE = 64, + AO_STALLED_BY_BS_OR_OB = 67, + AO_STALLED_BY_BS = 68, + AO_STALLED_BY_OB = 69, + AO_STALLED_BY_AB_OR_CB = 70, + AO_STALLED_BY_AB = 71, + AO_STALLED_BY_CB = 72, + WD_ACTIVE = 80, + WD_STALLED = 81, + WD_STALLED_BY_WD_BUF = 83, + WD_STALLED_BY_WS_FC = 84, + WD_STALLED_BY_WS_TC = 85, + WD_TRANS_WBLK = 89, + WD_TRANS_WS_FC = 90, + WD_TRANS_WS_TC = 91, + WD_STALLED_BY_WS_SC0 = 96, + WD_STALLED_BY_WS_SC1 = 97, + WD_STALLED_BY_WS_SC2 = 98, + WD_STALLED_BY_WS_SC3 = 99, + WD_PARSE_ACTIVE_SC0 = 100, + WD_PARSE_ACTIVE_SC1 = 101, + WD_PARSE_ACTIVE_SC2 = 102, + WD_PARSE_ACTIVE_SC3 = 103, + WD_PARSE_STALL_SC0 = 104, + WD_PARSE_STALL_SC1 = 105, + WD_PARSE_STALL_SC2 = 106, + WD_PARSE_STALL_SC3 = 107, + WD_PARSE_STALL_IN_SC0 = 108, + WD_PARSE_STALL_IN_SC1 = 109, + WD_PARSE_STALL_IN_SC2 = 110, + WD_PARSE_STALL_IN_SC3 = 111, + WD_PARSE_STALL_OUT_SC0 = 112, + WD_PARSE_STALL_OUT_SC1 = 113, + WD_PARSE_STALL_OUT_SC2 = 114, + WD_PARSE_STALL_OUT_SC3 = 115, + WD_TRANS_WS_SC0 = 116, + WD_TRANS_WS_SC1 = 117, + WD_TRANS_WS_SC2 = 118, + WD_TRANS_WS_SC3 = 119, + WD_TRANS_WB0 = 120, + WD_TRANS_WB1 = 121, + WD_TRANS_WB2 = 122, + WD_TRANS_WB3 = 123, + SRAM_RD_TRANS_ACCEPTED = 128, + SRAM_RD_TRANS_COMPLETED = 129, + SRAM_RD_DATA_BEAT_RECEIVED = 130, + SRAM_RD_TRAN_REQ_STALLED = 131, + SRAM_WR_TRANS_ACCEPTED = 132, + SRAM_WR_TRANS_COMPLETED_M = 133, + SRAM_WR_TRANS_COMPLETED_S = 134, + SRAM_WR_DATA_BEAT_WRITTEN = 135, + SRAM_WR_TRAN_REQ_STALLED = 136, + SRAM_WR_DATA_BEAT_STALLED = 137, + SRAM_ENABLED_CYCLES = 140, + SRAM_RD_STALL_LIMIT = 142, + SRAM_WR_STALL_LIMIT = 143, + AXI_LATENCY_ANY = 160, + AXI_LATENCY_32 = 161, + AXI_LATENCY_64 = 162, + AXI_LATENCY_128 = 163, + AXI_LATENCY_256 = 164, + AXI_LATENCY_512 = 165, + AXI_LATENCY_1024 = 166, + ECC_DMA = 176, + ECC_MAC_IB = 177, + ECC_MAC_AB = 178, + ECC_AO_CB = 179, + ECC_AO_OB = 180, + ECC_AO_LUT = 181, + EXT_RD_TRANS_ACCEPTED = 384, + EXT_RD_TRANS_COMPLETED = 385, + EXT_RD_DATA_BEAT_RECEIVED = 386, + EXT_RD_TRAN_REQ_STALLED = 387, + EXT_WR_TRANS_ACCEPTED = 388, + EXT_WR_TRANS_COMPLETED_M = 389, + EXT_WR_TRANS_COMPLETED_S = 390, + EXT_WR_DATA_BEAT_WRITTEN = 391, + EXT_WR_TRAN_REQ_STALLED = 392, + EXT_WR_DATA_BEAT_STALLED = 393, + EXT_ENABLED_CYCLES = 396, + EXT_RD_STALL_LIMIT = 398, + EXT_WR_STALL_LIMIT = 399, + SRAM0_RD_TRANS_ACCEPTED = 512, + SRAM0_RD_TRANS_COMPLETED = 513, + SRAM0_RD_DATA_BEAT_RECEIVED = 514, + SRAM0_RD_TRAN_REQ_STALLED = 515, + SRAM0_WR_TRANS_ACCEPTED = 516, + SRAM0_WR_TRANS_COMPLETED_M = 517, + SRAM0_WR_TRANS_COMPLETED_S = 518, + SRAM0_WR_DATA_BEAT_WRITTEN = 519, + SRAM0_WR_TRAN_REQ_STALLED = 520, + SRAM0_WR_DATA_BEAT_STALLED = 521, + SRAM0_ENABLED_CYCLES = 524, + SRAM0_RD_STALL_LIMIT = 526, + SRAM0_WR_STALL_LIMIT = 527, + SRAM1_RD_TRANS_ACCEPTED = 528, + SRAM1_RD_TRANS_COMPLETED = 529, + SRAM1_RD_DATA_BEAT_RECEIVED = 530, + SRAM1_RD_TRAN_REQ_STALLED = 531, + SRAM1_WR_TRANS_ACCEPTED = 532, + SRAM1_WR_TRANS_COMPLETED_M = 533, + SRAM1_WR_TRANS_COMPLETED_S = 534, + SRAM1_WR_DATA_BEAT_WRITTEN = 535, + SRAM1_WR_TRAN_REQ_STALLED = 536, + SRAM1_WR_DATA_BEAT_STALLED = 537, + SRAM1_ENABLED_CYCLES = 540, + SRAM1_RD_STALL_LIMIT = 542, + SRAM1_WR_STALL_LIMIT = 543, + SRAM2_RD_TRANS_ACCEPTED = 544, + SRAM2_RD_TRANS_COMPLETED = 545, + SRAM2_RD_DATA_BEAT_RECEIVED = 546, + SRAM2_RD_TRAN_REQ_STALLED = 547, + SRAM2_WR_TRANS_ACCEPTED = 548, + SRAM2_WR_TRANS_COMPLETED_M = 549, + SRAM2_WR_TRANS_COMPLETED_S = 550, + SRAM2_WR_DATA_BEAT_WRITTEN = 551, + SRAM2_WR_TRAN_REQ_STALLED = 552, + SRAM2_WR_DATA_BEAT_STALLED = 553, + SRAM2_ENABLED_CYCLES = 556, + SRAM2_RD_STALL_LIMIT = 558, + SRAM2_WR_STALL_LIMIT = 559, + SRAM3_RD_TRANS_ACCEPTED = 560, + SRAM3_RD_TRANS_COMPLETED = 561, + SRAM3_RD_DATA_BEAT_RECEIVED = 562, + SRAM3_RD_TRAN_REQ_STALLED = 563, + SRAM3_WR_TRANS_ACCEPTED = 564, + SRAM3_WR_TRANS_COMPLETED_M = 565, + SRAM3_WR_TRANS_COMPLETED_S = 566, + SRAM3_WR_DATA_BEAT_WRITTEN = 567, + SRAM3_WR_TRAN_REQ_STALLED = 568, + SRAM3_WR_DATA_BEAT_STALLED = 569, + SRAM3_ENABLED_CYCLES = 572, + SRAM3_RD_STALL_LIMIT = 574, + SRAM3_WR_STALL_LIMIT = 575, + EXT0_RD_TRANS_ACCEPTED = 640, + EXT0_RD_TRANS_COMPLETED = 641, + EXT0_RD_DATA_BEAT_RECEIVED = 642, + EXT0_RD_TRAN_REQ_STALLED = 643, + EXT0_WR_TRANS_ACCEPTED = 644, + EXT0_WR_TRANS_COMPLETED_M = 645, + EXT0_WR_TRANS_COMPLETED_S = 646, + EXT0_WR_DATA_BEAT_WRITTEN = 647, + EXT0_WR_TRAN_REQ_STALLED = 648, + EXT0_WR_DATA_BEAT_STALLED = 649, + EXT0_ENABLED_CYCLES = 652, + EXT0_RD_STALL_LIMIT = 654, + EXT0_WR_STALL_LIMIT = 655, + EXT1_RD_TRANS_ACCEPTED = 656, + EXT1_RD_TRANS_COMPLETED = 657, + EXT1_RD_DATA_BEAT_RECEIVED = 658, + EXT1_RD_TRAN_REQ_STALLED = 659, + EXT1_WR_TRANS_ACCEPTED = 660, + EXT1_WR_TRANS_COMPLETED_M = 661, + EXT1_WR_TRANS_COMPLETED_S = 662, + EXT1_WR_DATA_BEAT_WRITTEN = 663, + EXT1_WR_TRAN_REQ_STALLED = 664, + EXT1_WR_DATA_BEAT_STALLED = 665, + EXT1_ENABLED_CYCLES = 668, + EXT1_RD_STALL_LIMIT = 670, + EXT1_WR_STALL_LIMIT = 671, +}; + +enum class pmu_port_disable : uint8_t +{ + ENABLE = 0, + DISABLE = 1, +}; + +enum class pooling_mode : uint8_t +{ + MAX = 0, + AVERAGE = 1, + REDUCE_SUM = 2, + SUM = 3, + NONE = 4, + MIN = 5, + ARGMAX_X = 6, + ARGMAX_Y = 7, +}; + +enum class privilege_level : uint8_t +{ + USER = 0, + PRIVILEGED = 1, +}; + +enum class ram_id : uint8_t +{ + LUT = 0, + IB = 1, + AB = 2, + CB = 3, + OB = 4, +}; + +enum class resize_mode : uint8_t +{ + BILINEAR = 0, + REPLICATE = 1, + NEAREST = 2, +}; + +enum class round_mode_ifm : uint8_t +{ + DOUBLE_SYMMETRIC = 0, + NATURAL = 1, +}; + +enum class round_mode_ofm : uint8_t +{ + DOUBLE_SYMMETRIC = 0, + NATURAL = 1, + DOUBLE_ASYMMETRIC = 2, + SYMMETRIC = 3, + TRUNCATE_TO_ZERO = 4, + TRUNCATE_TO_LOWER = 5, +}; + +enum class security_level : uint8_t +{ + SECURE = 0, + NON_SECURE = 1, +}; + +enum class state : uint8_t +{ + STOPPED = 0, + RUNNING = 1, +}; + +enum class wd_active_core : uint8_t +{ + NONE = 0, + STANDARD = 1, + FAST = 2, + TENSOR = 3, +}; + +enum class weight_format : uint8_t +{ + SWD = 0, + FWD = 1, +}; + +enum class weight_order : uint8_t +{ + DEPTH_FIRST = 0, + PART_KERNEL_FIRST = 1, +}; + +enum class weight_sparsity : uint8_t +{ + NONE = 0, + SPARSE_2_4 = 1, +}; + +#else + +enum acc_format +{ + ACC_FORMAT_I32 = 0, + ACC_FORMAT_I48 = 1, +}; + +enum acc_input +{ + ACC_INPUT_RESET = 0, + ACC_INPUT_KEEP = 1, + ACC_INPUT_IFM2 = 2, +}; + +enum acc_output +{ + ACC_OUTPUT_ENABLE = 0, + ACC_OUTPUT_DISABLE = 1, +}; + +enum activation_clip_range +{ + ACTIVATION_CLIP_RANGE_B16 = 0, + ACTIVATION_CLIP_RANGE_NONE = 1, +}; + +enum activation_format +{ + ACTIVATION_FORMAT_NHWC = 0, + ACTIVATION_FORMAT_NHCWB16 = 1, +}; + +enum activation_function +{ + ACTIVATION_FUNCTION_LUT_NONE = 0, + ACTIVATION_FUNCTION_LUT_U8_U8 = 1, + ACTIVATION_FUNCTION_LUT_S8_S8 = 4, + ACTIVATION_FUNCTION_LUT_S8_S16 = 5, + ACTIVATION_FUNCTION_LUT_S8_S32 = 7, + ACTIVATION_FUNCTION_LUT_S16_S16 = 8, + ACTIVATION_FUNCTION_LUT_S16_S32 = 9, + ACTIVATION_FUNCTION_LUT_TANH = 10, + ACTIVATION_FUNCTION_LUT_SIGMOID = 11, +}; + +enum activation_precision +{ + ACTIVATION_PRECISION_B8 = 0, + ACTIVATION_PRECISION_B16 = 1, + ACTIVATION_PRECISION_B32 = 2, + ACTIVATION_PRECISION_B64 = 3, +}; + +enum activation_reverse +{ + ACTIVATION_REVERSE_NONE = 0, + ACTIVATION_REVERSE_H = 1, + ACTIVATION_REVERSE_W = 2, + ACTIVATION_REVERSE_C = 3, +}; + +enum activation_storage +{ + ACTIVATION_STORAGE_TILE2X2 = 0, + ACTIVATION_STORAGE_TILE3X1 = 1, + ACTIVATION_STORAGE_CHAINED = 2, + ACTIVATION_STORAGE_NONE = 3, +}; + +enum activation_transpose +{ + ACTIVATION_TRANSPOSE_HWC = 0, + ACTIVATION_TRANSPOSE_WHC = 1, + ACTIVATION_TRANSPOSE_HCW = 2, + ACTIVATION_TRANSPOSE_WCH = 3, + ACTIVATION_TRANSPOSE_CHW = 6, + ACTIVATION_TRANSPOSE_CWH = 7, +}; + +enum activation_type +{ + ACTIVATION_TYPE_UNSIGNED = 0, + ACTIVATION_TYPE_SIGNED = 1, +}; + +enum axi_mem_domain +{ + AXI_MEM_DOMAIN_NON_SHARABLE = 0, + AXI_MEM_DOMAIN_INNER_SHARABLE = 1, + AXI_MEM_DOMAIN_OUTER_SHARABLE = 2, + AXI_MEM_DOMAIN_SYSTEM = 3, +}; + +enum axi_mem_encoding +{ + AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE = 0, + AXI_MEM_ENCODING_DEVICE_BUFFERABLE = 1, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE = 4, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE = 5, + AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE = 6, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE = 8, + AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE = 9, + AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE = 10, + AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum axi_port +{ + AXI_PORT_SRAM = 0, + AXI_PORT_EXT = 1, +}; + +enum branch_cond +{ + BRANCH_COND_ALWAYS = 0, + BRANCH_COND_RF_TRUE = 1, +}; + +enum broadcast_mode +{ + BROADCAST_MODE_NONE = 0, + BROADCAST_MODE_H = 1, + BROADCAST_MODE_W = 2, + BROADCAST_MODE_HW = 3, + BROADCAST_MODE_C = 4, + BROADCAST_MODE_CH = 5, + BROADCAST_MODE_CW = 6, + BROADCAST_MODE_CWH = 7, + BROADCAST_MODE_SCALAR = 8, +}; + +enum cmd0_opcode +{ + CMD0_OPCODE_NPU_OP_STOP = 0, + CMD0_OPCODE_NPU_OP_IRQ = 1, + CMD0_OPCODE_NPU_OP_CONV = 2, + CMD0_OPCODE_NPU_OP_DEPTHWISE = 3, + CMD0_OPCODE_NPU_OP_POOL = 5, + CMD0_OPCODE_NPU_OP_ELEMENTWISE = 6, + CMD0_OPCODE_NPU_OP_RESIZE = 7, + CMD0_OPCODE_NPU_OP_DMA_START = 16, + CMD0_OPCODE_NPU_OP_DMA_WAIT = 17, + CMD0_OPCODE_NPU_OP_KERNEL_WAIT = 18, + CMD0_OPCODE_NPU_OP_PMU_MASK = 19, + CMD0_OPCODE_NPU_SET_IFM_PAD_TOP = 256, + CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT = 257, + CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT = 258, + CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM = 259, + CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1 = 260, + CMD0_OPCODE_NPU_SET_IFM_PRECISION = 261, + CMD0_OPCODE_NPU_SET_IFM_UPSCALE = 263, + CMD0_OPCODE_NPU_SET_IFM_BROADCAST = 264, + CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT = 265, + CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1 = 266, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1 = 267, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1 = 268, + CMD0_OPCODE_NPU_SET_IFM_REGION = 271, + CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1 = 273, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1 = 274, + CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1 = 275, + CMD0_OPCODE_NPU_SET_OFM_PRECISION = 276, + CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1 = 277, + CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1 = 279, + CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT = 280, + CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1 = 282, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1 = 283, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1 = 284, + CMD0_OPCODE_NPU_SET_OFM_REGION = 287, + CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1 = 288, + CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1 = 289, + CMD0_OPCODE_NPU_SET_KERNEL_STRIDE = 290, + CMD0_OPCODE_NPU_SET_ACC_FORMAT = 292, + CMD0_OPCODE_NPU_SET_ACTIVATION = 293, + CMD0_OPCODE_NPU_SET_ACTIVATION_MIN = 294, + CMD0_OPCODE_NPU_SET_ACTIVATION_MAX = 295, + CMD0_OPCODE_NPU_SET_WEIGHT_REGION = 296, + CMD0_OPCODE_NPU_SET_SCALE_REGION = 297, + CMD0_OPCODE_NPU_SET_RESIZE_X_SCALE_N_M1 = 298, + CMD0_OPCODE_NPU_SET_RESIZE_Y_SCALE_N_M1 = 299, + CMD0_OPCODE_NPU_SET_RESIZE_X_OFFSET = 300, + CMD0_OPCODE_NPU_SET_RESIZE_Y_OFFSET = 301, + CMD0_OPCODE_NPU_SET_WEIGHT_FORMAT = 302, + CMD0_OPCODE_NPU_SET_BLOCKDEP = 303, + CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION = 304, + CMD0_OPCODE_NPU_SET_DMA0_DST_REGION = 305, + CMD0_OPCODE_NPU_SET_DMA0_SIZE0 = 306, + CMD0_OPCODE_NPU_SET_DMA0_SIZE1 = 307, + CMD0_OPCODE_NPU_SET_DMA0_IDX_REGION = 308, + CMD0_OPCODE_NPU_SET_IFM2_BROADCAST = 384, + CMD0_OPCODE_NPU_SET_IFM2_PRECISION = 389, + CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT = 393, + CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1 = 394, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1 = 395, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1 = 396, + CMD0_OPCODE_NPU_SET_IFM2_REGION = 399, +}; + +enum cmd1_opcode +{ + CMD1_OPCODE_NPU_SET_IFM_BASE0 = 0, + CMD1_OPCODE_NPU_SET_IFM_BASE1 = 1, + CMD1_OPCODE_NPU_SET_IFM_BASE2 = 2, + CMD1_OPCODE_NPU_SET_IFM_BASE3 = 3, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_X = 4, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y = 5, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_C = 6, + CMD1_OPCODE_NPU_SET_OFM_BASE0 = 16, + CMD1_OPCODE_NPU_SET_OFM_BASE1 = 17, + CMD1_OPCODE_NPU_SET_OFM_BASE2 = 18, + CMD1_OPCODE_NPU_SET_OFM_BASE3 = 19, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_X = 20, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y = 21, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_C = 22, + CMD1_OPCODE_NPU_SET_WEIGHT_BASE = 32, + CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH = 33, + CMD1_OPCODE_NPU_SET_SCALE_BASE = 34, + CMD1_OPCODE_NPU_SET_SCALE_LENGTH = 35, + CMD1_OPCODE_NPU_SET_OFM_SCALE = 36, + CMD1_OPCODE_NPU_SET_IFM_SCALE = 37, + CMD1_OPCODE_NPU_SET_IFM2_SCALE = 38, + CMD1_OPCODE_NPU_SET_OP_SCALAR = 39, + CMD1_OPCODE_NPU_SET_DMA0_SRC = 48, + CMD1_OPCODE_NPU_SET_DMA0_DST = 49, + CMD1_OPCODE_NPU_SET_DMA0_LEN = 50, + CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE0 = 51, + CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE1 = 52, + CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE0 = 53, + CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE1 = 54, + CMD1_OPCODE_NPU_SET_DMA0_IDX = 55, + CMD1_OPCODE_NPU_SET_DMA0_IDX_MAX = 56, + CMD1_OPCODE_NPU_SET_DMA0_IDX_SKIP1 = 57, + CMD1_OPCODE_NPU_SET_IFM2_BASE0 = 128, + CMD1_OPCODE_NPU_SET_IFM2_BASE1 = 129, + CMD1_OPCODE_NPU_SET_IFM2_BASE2 = 130, + CMD1_OPCODE_NPU_SET_IFM2_BASE3 = 131, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X = 132, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y = 133, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C = 134, + CMD1_OPCODE_NPU_SET_WEIGHT1_BASE = 144, + CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH = 145, + CMD1_OPCODE_NPU_SET_WEIGHT2_BASE = 146, + CMD1_OPCODE_NPU_SET_WEIGHT2_LENGTH = 147, + CMD1_OPCODE_NPU_SET_WEIGHT3_BASE = 148, + CMD1_OPCODE_NPU_SET_WEIGHT3_LENGTH = 149, + CMD1_OPCODE_NPU_SET_RESIZE_X = 150, + CMD1_OPCODE_NPU_SET_RESIZE_Y = 151, + CMD1_OPCODE_NPU_OP_BRANCH = 256, +}; + +enum cmd_ctrl +{ + CMD_CTRL_CMD0_CTRL = 0, + CMD_CTRL_CMD1_CTRL = 1, +}; + +enum custom_dma +{ + CUSTOM_DMA_NOT_IMPLEMENTED = 0, + CUSTOM_DMA_IMPLEMENTED = 1, +}; + +enum dma_fault_src +{ + DMA_FAULT_SRC_SRAM = 0, + DMA_FAULT_SRC_EXT = 1, +}; + +enum dma_idx_mode +{ + DMA_IDX_MODE_DISABLED = 0, + DMA_IDX_MODE_ENABLED = 1, +}; + +enum dma_region_mode +{ + DMA_REGION_MODE_EXTERNAL = 0, + DMA_REGION_MODE_INTERNAL = 1, +}; + +enum dma_stride_mode +{ + DMA_STRIDE_MODE_D1 = 0, + DMA_STRIDE_MODE_D2 = 1, + DMA_STRIDE_MODE_D3 = 2, +}; + +enum elementwise_mode +{ + ELEMENTWISE_MODE_MUL = 0, + ELEMENTWISE_MODE_ADD = 1, + ELEMENTWISE_MODE_SUB = 2, + ELEMENTWISE_MODE_MIN = 3, + ELEMENTWISE_MODE_MAX = 4, + ELEMENTWISE_MODE_LRELU = 5, + ELEMENTWISE_MODE_ABS = 6, + ELEMENTWISE_MODE_CLZ = 7, + ELEMENTWISE_MODE_SHR = 8, + ELEMENTWISE_MODE_SHL = 9, + ELEMENTWISE_MODE_LSR = 10, + ELEMENTWISE_MODE_DIV = 11, + ELEMENTWISE_MODE_CMP_EQ = 16, + ELEMENTWISE_MODE_CMP_NE = 17, + ELEMENTWISE_MODE_CMP_GE = 18, + ELEMENTWISE_MODE_CMP_GT = 19, + ELEMENTWISE_MODE_AND = 33, + ELEMENTWISE_MODE_OR = 34, + ELEMENTWISE_MODE_XOR = 35, + ELEMENTWISE_MODE_NOT = 36, + ELEMENTWISE_MODE_AND_NOT = 42, +}; + +enum ifm_upscale_mode +{ + IFM_UPSCALE_MODE_NONE = 0, + IFM_UPSCALE_MODE_NEAREST = 1, + IFM_UPSCALE_MODE_ZEROS = 2, +}; + +enum kernel_decomposition +{ + KERNEL_DECOMPOSITION_D8X8 = 0, + KERNEL_DECOMPOSITION_D4X4 = 1, +}; + +enum kernel_dilation +{ + KERNEL_DILATION_NONE = 0, + KERNEL_DILATION_X2 = 1, +}; + +enum max_beats +{ + MAX_BEATS_B64 = 0, + MAX_BEATS_B128 = 1, + MAX_BEATS_B256 = 2, +}; + +enum microblock +{ + MICROBLOCK_U1X1 = 0, + MICROBLOCK_U1X2 = 1, + MICROBLOCK_U1X4 = 2, + MICROBLOCK_U2X2 = 3, + MICROBLOCK_U2X4 = 4, + MICROBLOCK_U4X4 = 5, +}; + +enum ofm_scale_mode +{ + OFM_SCALE_MODE_PER_CHANNEL = 0, + OFM_SCALE_MODE_GLOBAL = 1, +}; + +enum pmu_axi_channel +{ + PMU_AXI_CHANNEL_RD_CMD = 0, + PMU_AXI_CHANNEL_RD_IFM = 1, + PMU_AXI_CHANNEL_RD_WEIGHTS = 2, + PMU_AXI_CHANNEL_RD_SCALE_BIAS = 3, + PMU_AXI_CHANNEL_RD_MEM2MEM = 4, + PMU_AXI_CHANNEL_RD_IFM_STREAM = 5, + PMU_AXI_CHANNEL_RD_MEM2MEM_IDX = 6, + PMU_AXI_CHANNEL_WR_OFM = 8, + PMU_AXI_CHANNEL_WR_MEM2MEM = 9, +}; + +enum pmu_event +{ + PMU_EVENT_NO_EVENT = 0, + PMU_EVENT_CYCLE = 17, + PMU_EVENT_NPU_IDLE = 32, + PMU_EVENT_CC_STALLED_ON_BLOCKDEP = 33, + PMU_EVENT_NPU_ACTIVE = 35, + PMU_EVENT_MAC_ACTIVE = 48, + PMU_EVENT_MAC_DPU_ACTIVE = 51, + PMU_EVENT_MAC_STALLED_BY_W_OR_ACC = 52, + PMU_EVENT_MAC_STALLED_BY_W = 53, + PMU_EVENT_MAC_STALLED_BY_ACC = 54, + PMU_EVENT_MAC_STALLED_BY_IB = 55, + PMU_EVENT_AO_ACTIVE = 64, + PMU_EVENT_AO_STALLED_BY_BS_OR_OB = 67, + PMU_EVENT_AO_STALLED_BY_BS = 68, + PMU_EVENT_AO_STALLED_BY_OB = 69, + PMU_EVENT_AO_STALLED_BY_AB_OR_CB = 70, + PMU_EVENT_AO_STALLED_BY_AB = 71, + PMU_EVENT_AO_STALLED_BY_CB = 72, + PMU_EVENT_WD_ACTIVE = 80, + PMU_EVENT_WD_STALLED = 81, + PMU_EVENT_WD_STALLED_BY_WD_BUF = 83, + PMU_EVENT_WD_STALLED_BY_WS_FC = 84, + PMU_EVENT_WD_STALLED_BY_WS_TC = 85, + PMU_EVENT_WD_TRANS_WBLK = 89, + PMU_EVENT_WD_TRANS_WS_FC = 90, + PMU_EVENT_WD_TRANS_WS_TC = 91, + PMU_EVENT_WD_STALLED_BY_WS_SC0 = 96, + PMU_EVENT_WD_STALLED_BY_WS_SC1 = 97, + PMU_EVENT_WD_STALLED_BY_WS_SC2 = 98, + PMU_EVENT_WD_STALLED_BY_WS_SC3 = 99, + PMU_EVENT_WD_PARSE_ACTIVE_SC0 = 100, + PMU_EVENT_WD_PARSE_ACTIVE_SC1 = 101, + PMU_EVENT_WD_PARSE_ACTIVE_SC2 = 102, + PMU_EVENT_WD_PARSE_ACTIVE_SC3 = 103, + PMU_EVENT_WD_PARSE_STALL_SC0 = 104, + PMU_EVENT_WD_PARSE_STALL_SC1 = 105, + PMU_EVENT_WD_PARSE_STALL_SC2 = 106, + PMU_EVENT_WD_PARSE_STALL_SC3 = 107, + PMU_EVENT_WD_PARSE_STALL_IN_SC0 = 108, + PMU_EVENT_WD_PARSE_STALL_IN_SC1 = 109, + PMU_EVENT_WD_PARSE_STALL_IN_SC2 = 110, + PMU_EVENT_WD_PARSE_STALL_IN_SC3 = 111, + PMU_EVENT_WD_PARSE_STALL_OUT_SC0 = 112, + PMU_EVENT_WD_PARSE_STALL_OUT_SC1 = 113, + PMU_EVENT_WD_PARSE_STALL_OUT_SC2 = 114, + PMU_EVENT_WD_PARSE_STALL_OUT_SC3 = 115, + PMU_EVENT_WD_TRANS_WS_SC0 = 116, + PMU_EVENT_WD_TRANS_WS_SC1 = 117, + PMU_EVENT_WD_TRANS_WS_SC2 = 118, + PMU_EVENT_WD_TRANS_WS_SC3 = 119, + PMU_EVENT_WD_TRANS_WB0 = 120, + PMU_EVENT_WD_TRANS_WB1 = 121, + PMU_EVENT_WD_TRANS_WB2 = 122, + PMU_EVENT_WD_TRANS_WB3 = 123, + PMU_EVENT_SRAM_RD_TRANS_ACCEPTED = 128, + PMU_EVENT_SRAM_RD_TRANS_COMPLETED = 129, + PMU_EVENT_SRAM_RD_DATA_BEAT_RECEIVED = 130, + PMU_EVENT_SRAM_RD_TRAN_REQ_STALLED = 131, + PMU_EVENT_SRAM_WR_TRANS_ACCEPTED = 132, + PMU_EVENT_SRAM_WR_TRANS_COMPLETED_M = 133, + PMU_EVENT_SRAM_WR_TRANS_COMPLETED_S = 134, + PMU_EVENT_SRAM_WR_DATA_BEAT_WRITTEN = 135, + PMU_EVENT_SRAM_WR_TRAN_REQ_STALLED = 136, + PMU_EVENT_SRAM_WR_DATA_BEAT_STALLED = 137, + PMU_EVENT_SRAM_ENABLED_CYCLES = 140, + PMU_EVENT_SRAM_RD_STALL_LIMIT = 142, + PMU_EVENT_SRAM_WR_STALL_LIMIT = 143, + PMU_EVENT_AXI_LATENCY_ANY = 160, + PMU_EVENT_AXI_LATENCY_32 = 161, + PMU_EVENT_AXI_LATENCY_64 = 162, + PMU_EVENT_AXI_LATENCY_128 = 163, + PMU_EVENT_AXI_LATENCY_256 = 164, + PMU_EVENT_AXI_LATENCY_512 = 165, + PMU_EVENT_AXI_LATENCY_1024 = 166, + PMU_EVENT_ECC_DMA = 176, + PMU_EVENT_ECC_MAC_IB = 177, + PMU_EVENT_ECC_MAC_AB = 178, + PMU_EVENT_ECC_AO_CB = 179, + PMU_EVENT_ECC_AO_OB = 180, + PMU_EVENT_ECC_AO_LUT = 181, + PMU_EVENT_EXT_RD_TRANS_ACCEPTED = 384, + PMU_EVENT_EXT_RD_TRANS_COMPLETED = 385, + PMU_EVENT_EXT_RD_DATA_BEAT_RECEIVED = 386, + PMU_EVENT_EXT_RD_TRAN_REQ_STALLED = 387, + PMU_EVENT_EXT_WR_TRANS_ACCEPTED = 388, + PMU_EVENT_EXT_WR_TRANS_COMPLETED_M = 389, + PMU_EVENT_EXT_WR_TRANS_COMPLETED_S = 390, + PMU_EVENT_EXT_WR_DATA_BEAT_WRITTEN = 391, + PMU_EVENT_EXT_WR_TRAN_REQ_STALLED = 392, + PMU_EVENT_EXT_WR_DATA_BEAT_STALLED = 393, + PMU_EVENT_EXT_ENABLED_CYCLES = 396, + PMU_EVENT_EXT_RD_STALL_LIMIT = 398, + PMU_EVENT_EXT_WR_STALL_LIMIT = 399, + PMU_EVENT_SRAM0_RD_TRANS_ACCEPTED = 512, + PMU_EVENT_SRAM0_RD_TRANS_COMPLETED = 513, + PMU_EVENT_SRAM0_RD_DATA_BEAT_RECEIVED = 514, + PMU_EVENT_SRAM0_RD_TRAN_REQ_STALLED = 515, + PMU_EVENT_SRAM0_WR_TRANS_ACCEPTED = 516, + PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_M = 517, + PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_S = 518, + PMU_EVENT_SRAM0_WR_DATA_BEAT_WRITTEN = 519, + PMU_EVENT_SRAM0_WR_TRAN_REQ_STALLED = 520, + PMU_EVENT_SRAM0_WR_DATA_BEAT_STALLED = 521, + PMU_EVENT_SRAM0_ENABLED_CYCLES = 524, + PMU_EVENT_SRAM0_RD_STALL_LIMIT = 526, + PMU_EVENT_SRAM0_WR_STALL_LIMIT = 527, + PMU_EVENT_SRAM1_RD_TRANS_ACCEPTED = 528, + PMU_EVENT_SRAM1_RD_TRANS_COMPLETED = 529, + PMU_EVENT_SRAM1_RD_DATA_BEAT_RECEIVED = 530, + PMU_EVENT_SRAM1_RD_TRAN_REQ_STALLED = 531, + PMU_EVENT_SRAM1_WR_TRANS_ACCEPTED = 532, + PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_M = 533, + PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_S = 534, + PMU_EVENT_SRAM1_WR_DATA_BEAT_WRITTEN = 535, + PMU_EVENT_SRAM1_WR_TRAN_REQ_STALLED = 536, + PMU_EVENT_SRAM1_WR_DATA_BEAT_STALLED = 537, + PMU_EVENT_SRAM1_ENABLED_CYCLES = 540, + PMU_EVENT_SRAM1_RD_STALL_LIMIT = 542, + PMU_EVENT_SRAM1_WR_STALL_LIMIT = 543, + PMU_EVENT_SRAM2_RD_TRANS_ACCEPTED = 544, + PMU_EVENT_SRAM2_RD_TRANS_COMPLETED = 545, + PMU_EVENT_SRAM2_RD_DATA_BEAT_RECEIVED = 546, + PMU_EVENT_SRAM2_RD_TRAN_REQ_STALLED = 547, + PMU_EVENT_SRAM2_WR_TRANS_ACCEPTED = 548, + PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_M = 549, + PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_S = 550, + PMU_EVENT_SRAM2_WR_DATA_BEAT_WRITTEN = 551, + PMU_EVENT_SRAM2_WR_TRAN_REQ_STALLED = 552, + PMU_EVENT_SRAM2_WR_DATA_BEAT_STALLED = 553, + PMU_EVENT_SRAM2_ENABLED_CYCLES = 556, + PMU_EVENT_SRAM2_RD_STALL_LIMIT = 558, + PMU_EVENT_SRAM2_WR_STALL_LIMIT = 559, + PMU_EVENT_SRAM3_RD_TRANS_ACCEPTED = 560, + PMU_EVENT_SRAM3_RD_TRANS_COMPLETED = 561, + PMU_EVENT_SRAM3_RD_DATA_BEAT_RECEIVED = 562, + PMU_EVENT_SRAM3_RD_TRAN_REQ_STALLED = 563, + PMU_EVENT_SRAM3_WR_TRANS_ACCEPTED = 564, + PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_M = 565, + PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_S = 566, + PMU_EVENT_SRAM3_WR_DATA_BEAT_WRITTEN = 567, + PMU_EVENT_SRAM3_WR_TRAN_REQ_STALLED = 568, + PMU_EVENT_SRAM3_WR_DATA_BEAT_STALLED = 569, + PMU_EVENT_SRAM3_ENABLED_CYCLES = 572, + PMU_EVENT_SRAM3_RD_STALL_LIMIT = 574, + PMU_EVENT_SRAM3_WR_STALL_LIMIT = 575, + PMU_EVENT_EXT0_RD_TRANS_ACCEPTED = 640, + PMU_EVENT_EXT0_RD_TRANS_COMPLETED = 641, + PMU_EVENT_EXT0_RD_DATA_BEAT_RECEIVED = 642, + PMU_EVENT_EXT0_RD_TRAN_REQ_STALLED = 643, + PMU_EVENT_EXT0_WR_TRANS_ACCEPTED = 644, + PMU_EVENT_EXT0_WR_TRANS_COMPLETED_M = 645, + PMU_EVENT_EXT0_WR_TRANS_COMPLETED_S = 646, + PMU_EVENT_EXT0_WR_DATA_BEAT_WRITTEN = 647, + PMU_EVENT_EXT0_WR_TRAN_REQ_STALLED = 648, + PMU_EVENT_EXT0_WR_DATA_BEAT_STALLED = 649, + PMU_EVENT_EXT0_ENABLED_CYCLES = 652, + PMU_EVENT_EXT0_RD_STALL_LIMIT = 654, + PMU_EVENT_EXT0_WR_STALL_LIMIT = 655, + PMU_EVENT_EXT1_RD_TRANS_ACCEPTED = 656, + PMU_EVENT_EXT1_RD_TRANS_COMPLETED = 657, + PMU_EVENT_EXT1_RD_DATA_BEAT_RECEIVED = 658, + PMU_EVENT_EXT1_RD_TRAN_REQ_STALLED = 659, + PMU_EVENT_EXT1_WR_TRANS_ACCEPTED = 660, + PMU_EVENT_EXT1_WR_TRANS_COMPLETED_M = 661, + PMU_EVENT_EXT1_WR_TRANS_COMPLETED_S = 662, + PMU_EVENT_EXT1_WR_DATA_BEAT_WRITTEN = 663, + PMU_EVENT_EXT1_WR_TRAN_REQ_STALLED = 664, + PMU_EVENT_EXT1_WR_DATA_BEAT_STALLED = 665, + PMU_EVENT_EXT1_ENABLED_CYCLES = 668, + PMU_EVENT_EXT1_RD_STALL_LIMIT = 670, + PMU_EVENT_EXT1_WR_STALL_LIMIT = 671, +}; + +enum pmu_port_disable +{ + PMU_PORT_DISABLE_ENABLE = 0, + PMU_PORT_DISABLE_DISABLE = 1, +}; + +enum pooling_mode +{ + POOLING_MODE_MAX = 0, + POOLING_MODE_AVERAGE = 1, + POOLING_MODE_REDUCE_SUM = 2, + POOLING_MODE_SUM = 3, + POOLING_MODE_NONE = 4, + POOLING_MODE_MIN = 5, + POOLING_MODE_ARGMAX_X = 6, + POOLING_MODE_ARGMAX_Y = 7, +}; + +enum privilege_level +{ + PRIVILEGE_LEVEL_USER = 0, + PRIVILEGE_LEVEL_PRIVILEGED = 1, +}; + +enum ram_id +{ + RAM_ID_LUT = 0, + RAM_ID_IB = 1, + RAM_ID_AB = 2, + RAM_ID_CB = 3, + RAM_ID_OB = 4, +}; + +enum resize_mode +{ + RESIZE_MODE_BILINEAR = 0, + RESIZE_MODE_REPLICATE = 1, + RESIZE_MODE_NEAREST = 2, +}; + +enum round_mode_ifm +{ + ROUND_MODE_IFM_DOUBLE_SYMMETRIC = 0, + ROUND_MODE_IFM_NATURAL = 1, +}; + +enum round_mode_ofm +{ + ROUND_MODE_OFM_DOUBLE_SYMMETRIC = 0, + ROUND_MODE_OFM_NATURAL = 1, + ROUND_MODE_OFM_DOUBLE_ASYMMETRIC = 2, + ROUND_MODE_OFM_SYMMETRIC = 3, + ROUND_MODE_OFM_TRUNCATE_TO_ZERO = 4, + ROUND_MODE_OFM_TRUNCATE_TO_LOWER = 5, +}; + +enum security_level +{ + SECURITY_LEVEL_SECURE = 0, + SECURITY_LEVEL_NON_SECURE = 1, +}; + +enum state +{ + STATE_STOPPED = 0, + STATE_RUNNING = 1, +}; + +enum wd_active_core +{ + WD_ACTIVE_CORE_NONE = 0, + WD_ACTIVE_CORE_STANDARD = 1, + WD_ACTIVE_CORE_FAST = 2, + WD_ACTIVE_CORE_TENSOR = 3, +}; + +enum weight_format +{ + WEIGHT_FORMAT_SWD = 0, + WEIGHT_FORMAT_FWD = 1, +}; + +enum weight_order +{ + WEIGHT_ORDER_DEPTH_FIRST = 0, + WEIGHT_ORDER_PART_KERNEL_FIRST = 1, +}; + +enum weight_sparsity +{ + WEIGHT_SPARSITY_NONE = 0, + WEIGHT_SPARSITY_SPARSE_2_4 = 1, +}; + +#endif + +#ifdef NPU_DISASSEMBLE + +static const char* acc_format_str[] = +{ + "ACC_FORMAT_I32", + "ACC_FORMAT_I48", +}; + +static const char* acc_input_str[] = +{ + "ACC_INPUT_RESET", + "ACC_INPUT_KEEP", + "ACC_INPUT_IFM2", +}; + +static const char* acc_output_str[] = +{ + "ACC_OUTPUT_ENABLE", + "ACC_OUTPUT_DISABLE", +}; + +static const char* activation_clip_range_str[] = +{ + "ACTIVATION_CLIP_RANGE_B16", + "ACTIVATION_CLIP_RANGE_NONE", +}; + +static const char* activation_format_str[] = +{ + "ACTIVATION_FORMAT_NHWC", + "ACTIVATION_FORMAT_NHCWB16", +}; + +static const char* activation_function_str[] = +{ + "ACTIVATION_FUNCTION_LUT_NONE", + "ACTIVATION_FUNCTION_LUT_U8_U8", + "****", + "****", + "ACTIVATION_FUNCTION_LUT_S8_S8", + "ACTIVATION_FUNCTION_LUT_S8_S16", + "****", + "ACTIVATION_FUNCTION_LUT_S8_S32", + "ACTIVATION_FUNCTION_LUT_S16_S16", + "ACTIVATION_FUNCTION_LUT_S16_S32", + "ACTIVATION_FUNCTION_LUT_TANH", + "ACTIVATION_FUNCTION_LUT_SIGMOID", +}; + +static const char* activation_precision_str[] = +{ + "ACTIVATION_PRECISION_B8", + "ACTIVATION_PRECISION_B16", + "ACTIVATION_PRECISION_B32", + "ACTIVATION_PRECISION_B64", +}; + +static const char* activation_reverse_str[] = +{ + "ACTIVATION_REVERSE_NONE", + "ACTIVATION_REVERSE_H", + "ACTIVATION_REVERSE_W", + "ACTIVATION_REVERSE_C", +}; + +static const char* activation_storage_str[] = +{ + "ACTIVATION_STORAGE_TILE2X2", + "ACTIVATION_STORAGE_TILE3X1", + "ACTIVATION_STORAGE_CHAINED", + "ACTIVATION_STORAGE_NONE", +}; + +static const char* activation_transpose_str[] = +{ + "ACTIVATION_TRANSPOSE_HWC", + "ACTIVATION_TRANSPOSE_WHC", + "ACTIVATION_TRANSPOSE_HCW", + "ACTIVATION_TRANSPOSE_WCH", + "****", + "****", + "ACTIVATION_TRANSPOSE_CHW", + "ACTIVATION_TRANSPOSE_CWH", +}; + +static const char* activation_type_str[] = +{ + "ACTIVATION_TYPE_UNSIGNED", + "ACTIVATION_TYPE_SIGNED", +}; + +static const char* axi_mem_domain_str[] = +{ + "AXI_MEM_DOMAIN_NON_SHARABLE", + "AXI_MEM_DOMAIN_INNER_SHARABLE", + "AXI_MEM_DOMAIN_OUTER_SHARABLE", + "AXI_MEM_DOMAIN_SYSTEM", +}; + +static const char* axi_mem_encoding_str[] = +{ + "AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_DEVICE_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE", + "AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE", +}; + +static const char* axi_port_str[] = +{ + "AXI_PORT_SRAM", + "AXI_PORT_EXT", +}; + +static const char* branch_cond_str[] = +{ + "BRANCH_COND_ALWAYS", + "BRANCH_COND_RF_TRUE", +}; + +static const char* broadcast_mode_str[] = +{ + "BROADCAST_MODE_NONE", + "BROADCAST_MODE_H", + "BROADCAST_MODE_W", + "BROADCAST_MODE_HW", + "BROADCAST_MODE_C", + "BROADCAST_MODE_CH", + "BROADCAST_MODE_CW", + "BROADCAST_MODE_CWH", + "BROADCAST_MODE_SCALAR", +}; + +static const char* cmd0_opcode_str[] = +{ + "CMD0_OPCODE_NPU_OP_STOP", + "CMD0_OPCODE_NPU_OP_IRQ", + "CMD0_OPCODE_NPU_OP_CONV", + "CMD0_OPCODE_NPU_OP_DEPTHWISE", + "****", + "CMD0_OPCODE_NPU_OP_POOL", + "CMD0_OPCODE_NPU_OP_ELEMENTWISE", + "CMD0_OPCODE_NPU_OP_RESIZE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_OP_DMA_START", + "CMD0_OPCODE_NPU_OP_DMA_WAIT", + "CMD0_OPCODE_NPU_OP_KERNEL_WAIT", + "CMD0_OPCODE_NPU_OP_PMU_MASK", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_PAD_TOP", + "CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM", + "CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_IFM_PRECISION", + "****", + "CMD0_OPCODE_NPU_SET_IFM_UPSCALE", + "CMD0_OPCODE_NPU_SET_IFM_BROADCAST", + "CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_REGION", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_PRECISION", + "CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_OFM_REGION", + "CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_STRIDE", + "****", + "CMD0_OPCODE_NPU_SET_ACC_FORMAT", + "CMD0_OPCODE_NPU_SET_ACTIVATION", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MIN", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MAX", + "CMD0_OPCODE_NPU_SET_WEIGHT_REGION", + "CMD0_OPCODE_NPU_SET_SCALE_REGION", + "CMD0_OPCODE_NPU_SET_RESIZE_X_SCALE_N_M1", + "CMD0_OPCODE_NPU_SET_RESIZE_Y_SCALE_N_M1", + "CMD0_OPCODE_NPU_SET_RESIZE_X_OFFSET", + "CMD0_OPCODE_NPU_SET_RESIZE_Y_OFFSET", + "CMD0_OPCODE_NPU_SET_WEIGHT_FORMAT", + "CMD0_OPCODE_NPU_SET_BLOCKDEP", + "CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_DST_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE0", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE1", + "CMD0_OPCODE_NPU_SET_DMA0_IDX_REGION", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_BROADCAST", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_PRECISION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_REGION", +}; + +static const char* cmd1_opcode_str[] = +{ + "CMD1_OPCODE_NPU_SET_IFM_BASE0", + "CMD1_OPCODE_NPU_SET_IFM_BASE1", + "CMD1_OPCODE_NPU_SET_IFM_BASE2", + "CMD1_OPCODE_NPU_SET_IFM_BASE3", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_OFM_BASE0", + "CMD1_OPCODE_NPU_SET_OFM_BASE1", + "CMD1_OPCODE_NPU_SET_OFM_BASE2", + "CMD1_OPCODE_NPU_SET_OFM_BASE3", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE_BASE", + "CMD1_OPCODE_NPU_SET_SCALE_LENGTH", + "CMD1_OPCODE_NPU_SET_OFM_SCALE", + "CMD1_OPCODE_NPU_SET_IFM_SCALE", + "CMD1_OPCODE_NPU_SET_IFM2_SCALE", + "CMD1_OPCODE_NPU_SET_OP_SCALAR", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_DMA0_SRC", + "CMD1_OPCODE_NPU_SET_DMA0_DST", + "CMD1_OPCODE_NPU_SET_DMA0_LEN", + "CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE0", + "CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE1", + "CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE0", + "CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE1", + "CMD1_OPCODE_NPU_SET_DMA0_IDX", + "CMD1_OPCODE_NPU_SET_DMA0_IDX_MAX", + "CMD1_OPCODE_NPU_SET_DMA0_IDX_SKIP1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_IFM2_BASE0", + "CMD1_OPCODE_NPU_SET_IFM2_BASE1", + "CMD1_OPCODE_NPU_SET_IFM2_BASE2", + "CMD1_OPCODE_NPU_SET_IFM2_BASE3", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT1_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH", + "CMD1_OPCODE_NPU_SET_WEIGHT2_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT2_LENGTH", + "CMD1_OPCODE_NPU_SET_WEIGHT3_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT3_LENGTH", + "CMD1_OPCODE_NPU_SET_RESIZE_X", + "CMD1_OPCODE_NPU_SET_RESIZE_Y", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_OP_BRANCH", +}; + +static const char* cmd_ctrl_str[] = +{ + "CMD_CTRL_CMD0_CTRL", + "CMD_CTRL_CMD1_CTRL", +}; + +static const char* custom_dma_str[] = +{ + "CUSTOM_DMA_NOT_IMPLEMENTED", + "CUSTOM_DMA_IMPLEMENTED", +}; + +static const char* dma_fault_src_str[] = +{ + "DMA_FAULT_SRC_SRAM", + "DMA_FAULT_SRC_EXT", +}; + +static const char* dma_idx_mode_str[] = +{ + "DMA_IDX_MODE_DISABLED", + "DMA_IDX_MODE_ENABLED", +}; + +static const char* dma_region_mode_str[] = +{ + "DMA_REGION_MODE_EXTERNAL", + "DMA_REGION_MODE_INTERNAL", +}; + +static const char* dma_stride_mode_str[] = +{ + "DMA_STRIDE_MODE_D1", + "DMA_STRIDE_MODE_D2", + "DMA_STRIDE_MODE_D3", +}; + +static const char* elementwise_mode_str[] = +{ + "ELEMENTWISE_MODE_MUL", + "ELEMENTWISE_MODE_ADD", + "ELEMENTWISE_MODE_SUB", + "ELEMENTWISE_MODE_MIN", + "ELEMENTWISE_MODE_MAX", + "ELEMENTWISE_MODE_LRELU", + "ELEMENTWISE_MODE_ABS", + "ELEMENTWISE_MODE_CLZ", + "ELEMENTWISE_MODE_SHR", + "ELEMENTWISE_MODE_SHL", + "ELEMENTWISE_MODE_LSR", + "ELEMENTWISE_MODE_DIV", + "****", + "****", + "****", + "****", + "ELEMENTWISE_MODE_CMP_EQ", + "ELEMENTWISE_MODE_CMP_NE", + "ELEMENTWISE_MODE_CMP_GE", + "ELEMENTWISE_MODE_CMP_GT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "ELEMENTWISE_MODE_AND", + "ELEMENTWISE_MODE_OR", + "ELEMENTWISE_MODE_XOR", + "ELEMENTWISE_MODE_NOT", + "****", + "****", + "****", + "****", + "****", + "ELEMENTWISE_MODE_AND_NOT", +}; + +static const char* ifm_upscale_mode_str[] = +{ + "IFM_UPSCALE_MODE_NONE", + "IFM_UPSCALE_MODE_NEAREST", + "IFM_UPSCALE_MODE_ZEROS", +}; + +static const char* kernel_decomposition_str[] = +{ + "KERNEL_DECOMPOSITION_D8X8", + "KERNEL_DECOMPOSITION_D4X4", +}; + +static const char* kernel_dilation_str[] = +{ + "KERNEL_DILATION_NONE", + "KERNEL_DILATION_X2", +}; + +static const char* max_beats_str[] = +{ + "MAX_BEATS_B64", + "MAX_BEATS_B128", + "MAX_BEATS_B256", +}; + +static const char* microblock_str[] = +{ + "MICROBLOCK_U1X1", + "MICROBLOCK_U1X2", + "MICROBLOCK_U1X4", + "MICROBLOCK_U2X2", + "MICROBLOCK_U2X4", + "MICROBLOCK_U4X4", +}; + +static const char* ofm_scale_mode_str[] = +{ + "OFM_SCALE_MODE_PER_CHANNEL", + "OFM_SCALE_MODE_GLOBAL", +}; + +static const char* pmu_axi_channel_str[] = +{ + "PMU_AXI_CHANNEL_RD_CMD", + "PMU_AXI_CHANNEL_RD_IFM", + "PMU_AXI_CHANNEL_RD_WEIGHTS", + "PMU_AXI_CHANNEL_RD_SCALE_BIAS", + "PMU_AXI_CHANNEL_RD_MEM2MEM", + "PMU_AXI_CHANNEL_RD_IFM_STREAM", + "PMU_AXI_CHANNEL_RD_MEM2MEM_IDX", + "****", + "PMU_AXI_CHANNEL_WR_OFM", + "PMU_AXI_CHANNEL_WR_MEM2MEM", +}; + +static const char* pmu_event_str[] = +{ + "PMU_EVENT_NO_EVENT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_CYCLE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_NPU_IDLE", + "PMU_EVENT_CC_STALLED_ON_BLOCKDEP", + "****", + "PMU_EVENT_NPU_ACTIVE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_MAC_ACTIVE", + "****", + "****", + "PMU_EVENT_MAC_DPU_ACTIVE", + "PMU_EVENT_MAC_STALLED_BY_W_OR_ACC", + "PMU_EVENT_MAC_STALLED_BY_W", + "PMU_EVENT_MAC_STALLED_BY_ACC", + "PMU_EVENT_MAC_STALLED_BY_IB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AO_ACTIVE", + "****", + "****", + "PMU_EVENT_AO_STALLED_BY_BS_OR_OB", + "PMU_EVENT_AO_STALLED_BY_BS", + "PMU_EVENT_AO_STALLED_BY_OB", + "PMU_EVENT_AO_STALLED_BY_AB_OR_CB", + "PMU_EVENT_AO_STALLED_BY_AB", + "PMU_EVENT_AO_STALLED_BY_CB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_ACTIVE", + "PMU_EVENT_WD_STALLED", + "****", + "PMU_EVENT_WD_STALLED_BY_WD_BUF", + "PMU_EVENT_WD_STALLED_BY_WS_FC", + "PMU_EVENT_WD_STALLED_BY_WS_TC", + "****", + "****", + "****", + "PMU_EVENT_WD_TRANS_WBLK", + "PMU_EVENT_WD_TRANS_WS_FC", + "PMU_EVENT_WD_TRANS_WS_TC", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_STALLED_BY_WS_SC0", + "PMU_EVENT_WD_STALLED_BY_WS_SC1", + "PMU_EVENT_WD_STALLED_BY_WS_SC2", + "PMU_EVENT_WD_STALLED_BY_WS_SC3", + "PMU_EVENT_WD_PARSE_ACTIVE_SC0", + "PMU_EVENT_WD_PARSE_ACTIVE_SC1", + "PMU_EVENT_WD_PARSE_ACTIVE_SC2", + "PMU_EVENT_WD_PARSE_ACTIVE_SC3", + "PMU_EVENT_WD_PARSE_STALL_SC0", + "PMU_EVENT_WD_PARSE_STALL_SC1", + "PMU_EVENT_WD_PARSE_STALL_SC2", + "PMU_EVENT_WD_PARSE_STALL_SC3", + "PMU_EVENT_WD_PARSE_STALL_IN_SC0", + "PMU_EVENT_WD_PARSE_STALL_IN_SC1", + "PMU_EVENT_WD_PARSE_STALL_IN_SC2", + "PMU_EVENT_WD_PARSE_STALL_IN_SC3", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC0", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC1", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC2", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC3", + "PMU_EVENT_WD_TRANS_WS_SC0", + "PMU_EVENT_WD_TRANS_WS_SC1", + "PMU_EVENT_WD_TRANS_WS_SC2", + "PMU_EVENT_WD_TRANS_WS_SC3", + "PMU_EVENT_WD_TRANS_WB0", + "PMU_EVENT_WD_TRANS_WB1", + "PMU_EVENT_WD_TRANS_WB2", + "PMU_EVENT_WD_TRANS_WB3", + "****", + "****", + "****", + "****", + "PMU_EVENT_SRAM_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM_RD_STALL_LIMIT", + "PMU_EVENT_SRAM_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI_LATENCY_ANY", + "PMU_EVENT_AXI_LATENCY_32", + "PMU_EVENT_AXI_LATENCY_64", + "PMU_EVENT_AXI_LATENCY_128", + "PMU_EVENT_AXI_LATENCY_256", + "PMU_EVENT_AXI_LATENCY_512", + "PMU_EVENT_AXI_LATENCY_1024", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_DMA", + "PMU_EVENT_ECC_MAC_IB", + "PMU_EVENT_ECC_MAC_AB", + "PMU_EVENT_ECC_AO_CB", + "PMU_EVENT_ECC_AO_OB", + "PMU_EVENT_ECC_AO_LUT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_EXT_RD_TRANS_ACCEPTED", + "PMU_EVENT_EXT_RD_TRANS_COMPLETED", + "PMU_EVENT_EXT_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_EXT_RD_TRAN_REQ_STALLED", + "PMU_EVENT_EXT_WR_TRANS_ACCEPTED", + "PMU_EVENT_EXT_WR_TRANS_COMPLETED_M", + "PMU_EVENT_EXT_WR_TRANS_COMPLETED_S", + "PMU_EVENT_EXT_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_EXT_WR_TRAN_REQ_STALLED", + "PMU_EVENT_EXT_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_EXT_ENABLED_CYCLES", + "****", + "PMU_EVENT_EXT_RD_STALL_LIMIT", + "PMU_EVENT_EXT_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_SRAM0_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM0_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM0_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM0_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM0_RD_STALL_LIMIT", + "PMU_EVENT_SRAM0_WR_STALL_LIMIT", + "PMU_EVENT_SRAM1_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM1_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM1_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM1_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM1_RD_STALL_LIMIT", + "PMU_EVENT_SRAM1_WR_STALL_LIMIT", + "PMU_EVENT_SRAM2_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM2_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM2_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM2_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM2_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM2_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM2_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM2_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM2_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM2_RD_STALL_LIMIT", + "PMU_EVENT_SRAM2_WR_STALL_LIMIT", + "PMU_EVENT_SRAM3_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM3_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM3_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM3_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM3_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM3_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM3_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM3_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM3_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM3_RD_STALL_LIMIT", + "PMU_EVENT_SRAM3_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_EXT0_RD_TRANS_ACCEPTED", + "PMU_EVENT_EXT0_RD_TRANS_COMPLETED", + "PMU_EVENT_EXT0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_EXT0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_EXT0_WR_TRANS_ACCEPTED", + "PMU_EVENT_EXT0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_EXT0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_EXT0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_EXT0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_EXT0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_EXT0_ENABLED_CYCLES", + "****", + "PMU_EVENT_EXT0_RD_STALL_LIMIT", + "PMU_EVENT_EXT0_WR_STALL_LIMIT", + "PMU_EVENT_EXT1_RD_TRANS_ACCEPTED", + "PMU_EVENT_EXT1_RD_TRANS_COMPLETED", + "PMU_EVENT_EXT1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_EXT1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_EXT1_WR_TRANS_ACCEPTED", + "PMU_EVENT_EXT1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_EXT1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_EXT1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_EXT1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_EXT1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_EXT1_ENABLED_CYCLES", + "****", + "PMU_EVENT_EXT1_RD_STALL_LIMIT", + "PMU_EVENT_EXT1_WR_STALL_LIMIT", +}; + +static const char* pmu_port_disable_str[] = +{ + "PMU_PORT_DISABLE_ENABLE", + "PMU_PORT_DISABLE_DISABLE", +}; + +static const char* pooling_mode_str[] = +{ + "POOLING_MODE_MAX", + "POOLING_MODE_AVERAGE", + "POOLING_MODE_REDUCE_SUM", + "POOLING_MODE_SUM", + "POOLING_MODE_NONE", + "POOLING_MODE_MIN", + "POOLING_MODE_ARGMAX_X", + "POOLING_MODE_ARGMAX_Y", +}; + +static const char* privilege_level_str[] = +{ + "PRIVILEGE_LEVEL_USER", + "PRIVILEGE_LEVEL_PRIVILEGED", +}; + +static const char* ram_id_str[] = +{ + "RAM_ID_LUT", + "RAM_ID_IB", + "RAM_ID_AB", + "RAM_ID_CB", + "RAM_ID_OB", +}; + +static const char* resize_mode_str[] = +{ + "RESIZE_MODE_BILINEAR", + "RESIZE_MODE_REPLICATE", + "RESIZE_MODE_NEAREST", +}; + +static const char* round_mode_ifm_str[] = +{ + "ROUND_MODE_IFM_DOUBLE_SYMMETRIC", + "ROUND_MODE_IFM_NATURAL", +}; + +static const char* round_mode_ofm_str[] = +{ + "ROUND_MODE_OFM_DOUBLE_SYMMETRIC", + "ROUND_MODE_OFM_NATURAL", + "ROUND_MODE_OFM_DOUBLE_ASYMMETRIC", + "ROUND_MODE_OFM_SYMMETRIC", + "ROUND_MODE_OFM_TRUNCATE_TO_ZERO", + "ROUND_MODE_OFM_TRUNCATE_TO_LOWER", +}; + +static const char* security_level_str[] = +{ + "SECURITY_LEVEL_SECURE", + "SECURITY_LEVEL_NON_SECURE", +}; + +static const char* state_str[] = +{ + "STATE_STOPPED", + "STATE_RUNNING", +}; + +static const char* wd_active_core_str[] = +{ + "WD_ACTIVE_CORE_NONE", + "WD_ACTIVE_CORE_STANDARD", + "WD_ACTIVE_CORE_FAST", + "WD_ACTIVE_CORE_TENSOR", +}; + +static const char* weight_format_str[] = +{ + "WEIGHT_FORMAT_SWD", + "WEIGHT_FORMAT_FWD", +}; + +static const char* weight_order_str[] = +{ + "WEIGHT_ORDER_DEPTH_FIRST", + "WEIGHT_ORDER_PART_KERNEL_FIRST", +}; + +static const char* weight_sparsity_str[] = +{ + "WEIGHT_SPARSITY_NONE", + "WEIGHT_SPARSITY_SPARSE_2_4", +}; + +#endif + +// Register type structs +// id_r - ID register +struct id_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t version_status : 4; // This value is the version of the product + uint32_t version_minor : 4; // This value is the n for the P part of an RnPn release number + uint32_t version_major : 4; // This value is the n for the R part of an RnPn release number + uint32_t product_major : 4; // Product major ID number (unique per base product) + uint32_t arch_patch_rev : 4; // This value is the patch number of the architecture version a.b + uint32_t arch_minor_rev : 8; // This value is the minor architecture version number, b in the architecture version a.b + uint32_t arch_major_rev : 4; // This value is the major architecture version number, a in the architecture version a.b + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR id_r() : + word0(536899585) + {} + CONSTEXPR id_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + id_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_version_status() const + { + auto v = ((1U << 4) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR id_r& set_version_status(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_version_minor() const + { + auto v = ((1U << 4) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR id_r& set_version_minor(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_version_major() const + { + auto v = ((1U << 4) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR id_r& set_version_major(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_product_major() const + { + auto v = ((1U << 4) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR id_r& set_product_major(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_arch_patch_rev() const + { + auto v = ((1U << 4) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR id_r& set_arch_patch_rev(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_arch_minor_rev() const + { + auto v = ((1U << 8) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR id_r& set_arch_minor_rev(uint32_t value) + { + word0 = (~(((1U << 8) - 1)<<20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_arch_major_rev() const + { + auto v = ((1U << 4) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR id_r& set_arch_major_rev(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// status_r - Register describes the current operating status of the NPU +struct status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t state : 1; // 0 = NPU is in stopped state. 1 = NPU is in running state + uint32_t irq_raised : 1; // 0 = IRQ not raised. 1 = IRQ raised + uint32_t bus_status : 1; // 0 = No bus fault. 1 = Bus abort detected and processing halted + uint32_t reset_status : 1; // 0 = No reset in progress. 1 = Reset in progress + uint32_t cmd_parse_error : 1; // 0 = No parsing error. 1 = Command stream parsing error detected + uint32_t cmd_end_reached : 1; // 0 = Command stream end is not reached. 1 = Command stream end is reached + uint32_t pmu_irq_raised : 1; // 0 = No PMU IRQ raised. 1 = PMU IRQ raised + uint32_t reserved0 : 1; + uint32_t ecc_fault : 1; // 0 = No ECC fault detected. 1 = ECC fault detected + uint32_t branch_fault : 1; // 0 = No branch fault. 1 = Branch fault detected + uint32_t reserved1 : 1; + uint32_t faulting_interface : 1; // The faulting interface on bus abort + uint32_t faulting_channel : 4; // The faulting channel on a bus abort + uint32_t irq_history_mask : 16; // The IRQ History mask + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR status_r() : + word0(8) + {} + CONSTEXPR status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + status_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::state get_state() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR status_r& set_state(NPU_NAMESPACE::state value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_irq_raised() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR status_r& set_irq_raised(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_bus_status() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR status_r& set_bus_status(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_reset_status() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR status_r& set_reset_status(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_parse_error() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR status_r& set_cmd_parse_error(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_end_reached() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR status_r& set_cmd_end_reached(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_pmu_irq_raised() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR status_r& set_pmu_irq_raised(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_ecc_fault() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR status_r& set_ecc_fault(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_branch_fault() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR status_r& set_branch_fault(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_fault_src get_faulting_interface() const + { + auto v = ((1U << 1) - 1) & (word0 >> 11); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR status_r& set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) + { + word0 = (~(((1U << 1) - 1)<<11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_faulting_channel() const + { + auto v = ((1U << 4) - 1) & (word0 >> 12); + assert(v <= 9); + return static_cast(v); + } + CONSTEXPR status_r& set_faulting_channel(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (~(((1U << 4) - 1)<<12) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR uint32_t get_irq_history_mask() const + { + auto v = ((1U << 16) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR status_r& set_irq_history_mask(uint32_t value) + { + word0 = (~(((1U << 16) - 1)<<16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// cmd_r - The command register. This register reads as last written command +struct cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t transition_to_running_state : 1; // Write 1 to transition the NPU to running state. Writing 0 has no effect + uint32_t clear_irq : 1; // Write 1 to clear the IRQ status in the STATUS register. Writing 0 has no effect + uint32_t clock_q_enable : 1; // Write 1 to this bit to enable clock off using clock q-interface and enable the requester clock gate + uint32_t power_q_enable : 1; // Write 1 to this bit to enable power off using power q-interface + uint32_t stop_request : 1; // Write 1 to this bit to request STOP after completing any already-started commands + uint32_t reserved0 : 11; + uint32_t clear_irq_history : 16; // Clears the IRQ history mask + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cmd_r() : + word0(12) + {} + CONSTEXPR cmd_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cmd_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_transition_to_running_state() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cmd_r& set_transition_to_running_state(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_clear_irq() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR cmd_r& set_clear_irq(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_clock_q_enable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR cmd_r& set_clock_q_enable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_power_q_enable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR cmd_r& set_power_q_enable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_stop_request() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR cmd_r& set_stop_request(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_clear_irq_history() const + { + auto v = ((1U << 16) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR cmd_r& set_clear_irq_history(uint32_t value) + { + word0 = (~(((1U << 16) - 1)<<16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// reset_r - Request reset and new security mode +struct reset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t pending_CPL : 1; // Current privilege level. 0 = User and 1 = Privileged + uint32_t pending_CSL : 1; // Current security level. 0 = Secure and 1 = Non-secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR reset_r() : + word0(0) + {} + CONSTEXPR reset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + reset_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_pending_CPL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR reset_r& set_pending_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_pending_CSL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR reset_r& set_pending_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// qbase_r - The base address of the command stream in bytes +struct qbase_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR qbase_r() : + word0(0), + word1(0) + {} + CONSTEXPR qbase_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + qbase_r copy() + { + return *this; + } +#endif +}; + +// qread_r - The read offset in the command stream in bytes. Multiple of four in the range 0-16MB +struct qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QREAD : 32; // The read offset of the current command under execution + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR qread_r() : + word0(0) + {} + CONSTEXPR qread_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + qread_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_QREAD() const + { + auto v = word0; + return v; + } + CONSTEXPR qread_r& set_QREAD(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// qconfig_r - The AXI configuration for the command stream in the range 0-3. Same encoding as for REGIONCFG +struct qconfig_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_region0 : 2; // The command region configuration number + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR qconfig_r() : + word0(0) + {} + CONSTEXPR qconfig_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + qconfig_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_cmd_region0() const + { + auto v = ((1U << 2) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR qconfig_r& set_cmd_region0(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<0) & word0) | ((((1U << 2) - 1) & value) << 0); + return *this; + } +#endif +}; + +// qsize_r - The size of the command stream in bytes. Multiple of four in the range 0-16MB +struct qsize_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QSIZE : 32; // The size of the next command stream to be executed by the NPU + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR qsize_r() : + word0(0) + {} + CONSTEXPR qsize_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + qsize_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_QSIZE() const + { + auto v = word0; + return v; + } + CONSTEXPR qsize_r& set_QSIZE(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// prot_r - The protection level configured for the NPU when acting as an AXI Requester +struct prot_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t active_CPL : 1; // The current privilege level. 0 = User and 1 = Privileged + uint32_t active_CSL : 1; // The current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR prot_r() : + word0(0) + {} + CONSTEXPR prot_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + prot_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_active_CPL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR prot_r& set_active_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_active_CSL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR prot_r& set_active_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// config_r - RTL configuration +struct config_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t macs_per_cc : 4; // The log2(macs/clock cycle) + uint32_t cmd_stream_version : 4; // The command stream version accepted by this NPU + uint32_t num_axi_sram : 2; // The log2 of the number of AXI SRAM interfaces + uint32_t num_axi_ext : 1; // The log2 of the number of AXI External memory interfaces + uint32_t reserved0 : 1; + uint32_t num_wd : 2; // The log2 of the number of standard weight decoders + uint32_t reserved1 : 13; + uint32_t custom_dma : 1; // The custom DMA configuration + uint32_t product : 4; // The product configuration + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR config_r() : + word0(536870928) + {} + CONSTEXPR config_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + config_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_macs_per_cc() const + { + auto v = ((1U << 4) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR config_r& set_macs_per_cc(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_stream_version() const + { + auto v = ((1U << 4) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR config_r& set_cmd_stream_version(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_num_axi_sram() const + { + auto v = ((1U << 2) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR config_r& set_num_axi_sram(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_num_axi_ext() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR config_r& set_num_axi_ext(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_num_wd() const + { + auto v = ((1U << 2) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR config_r& set_num_wd(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<12) & word0) | ((((1U << 2) - 1) & value) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma get_custom_dma() const + { + auto v = ((1U << 1) - 1) & (word0 >> 27); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR config_r& set_custom_dma(NPU_NAMESPACE::custom_dma value) + { + word0 = (~(((1U << 1) - 1)<<27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + CONSTEXPR uint32_t get_product() const + { + auto v = ((1U << 4) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR config_r& set_product(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// cond_status_r - Condition status of the NPU +struct cond_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t result_flag : 1; // The tensor result flag. For OFM with a single element, this is bit 0 of the value. Otherwise UNPREDICTABLE + uint32_t reserved0 : 31; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cond_status_r() : + word0(0) + {} + CONSTEXPR cond_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cond_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_result_flag() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cond_status_r& set_result_flag(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } +#endif +}; + +// power_ctrl_r - Power control register +struct power_ctrl_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mac_step_cycles : 6; // MAC power ramping up/down control + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR power_ctrl_r() : + word0(0) + {} + CONSTEXPR power_ctrl_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + power_ctrl_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_mac_step_cycles() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR power_ctrl_r& set_mac_step_cycles(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } +#endif +}; + +// regioncfg_r - Specify which MEM_ATTR register applies to each region +struct regioncfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t region0 : 2; // Bits for Region0 Configuration + uint32_t region1 : 2; // Bits for Region1 Configuration + uint32_t region2 : 2; // Bits for Region2 Configuration + uint32_t region3 : 2; // Bits for Region3 Configuration + uint32_t region4 : 2; // Bits for Region4 Configuration + uint32_t region5 : 2; // Bits for Region5 Configuration + uint32_t region6 : 2; // Bits for Region6 Configuration + uint32_t region7 : 2; // Bits for Region7 Configuration + uint32_t reserved0 : 16; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR regioncfg_r() : + word0(0) + {} + CONSTEXPR regioncfg_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + regioncfg_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_region0() const + { + auto v = ((1U << 2) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR regioncfg_r& set_region0(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<0) & word0) | ((((1U << 2) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_region1() const + { + auto v = ((1U << 2) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR regioncfg_r& set_region1(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<2) & word0) | ((((1U << 2) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_region2() const + { + auto v = ((1U << 2) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR regioncfg_r& set_region2(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<4) & word0) | ((((1U << 2) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_region3() const + { + auto v = ((1U << 2) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR regioncfg_r& set_region3(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<6) & word0) | ((((1U << 2) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_region4() const + { + auto v = ((1U << 2) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR regioncfg_r& set_region4(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_region5() const + { + auto v = ((1U << 2) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR regioncfg_r& set_region5(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<10) & word0) | ((((1U << 2) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_region6() const + { + auto v = ((1U << 2) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR regioncfg_r& set_region6(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<12) & word0) | ((((1U << 2) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_region7() const + { + auto v = ((1U << 2) - 1) & (word0 >> 14); + return v; + } + CONSTEXPR regioncfg_r& set_region7(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<14) & word0) | ((((1U << 2) - 1) & value) << 14); + return *this; + } +#endif +}; + +// mem_attr_r - Memory attributes 0 +struct mem_attr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_domain : 2; // Memory domain + uint32_t axi_port : 1; // AXI port select + uint32_t reserved0 : 1; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 24; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR mem_attr_r() : + word0(0) + {} + CONSTEXPR mem_attr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + mem_attr_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_domain get_mem_domain() const + { + auto v = ((1U << 2) - 1) & (word0 >> 0); + assert(v <= 3); + return static_cast(v); + } + CONSTEXPR mem_attr_r& set_mem_domain(NPU_NAMESPACE::axi_mem_domain value) + { + word0 = (~(((1U << 2) - 1)<<0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_port get_axi_port() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR mem_attr_r& set_axi_port(NPU_NAMESPACE::axi_port value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + auto v = ((1U << 4) - 1) & (word0 >> 4); + assert(v <= 11); + return static_cast(v); + } + CONSTEXPR mem_attr_r& set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (~(((1U << 4) - 1)<<4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } +#endif +}; + +// axi_sram_r - The AXI configuration for SRAM ports +struct axi_sram_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR axi_sram_r() : + word0(0) + {} + CONSTEXPR axi_sram_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + axi_sram_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR axi_sram_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR axi_sram_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR axi_sram_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// axi_ext_r - The AXI configuration for EXT ports +struct axi_ext_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR axi_ext_r() : + word0(0) + {} + CONSTEXPR axi_ext_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + axi_ext_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR axi_ext_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR axi_ext_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR axi_ext_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// cfg_sram_cap_r - The value of the CFGSRAMCAP pins, SRAM AXI ports cap +struct cfg_sram_cap_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cfg_sram_cap_r() : + word0(0) + {} + CONSTEXPR cfg_sram_cap_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cfg_sram_cap_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cfg_sram_cap_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR cfg_sram_cap_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR cfg_sram_cap_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// cfg_ext_cap_r - The value of the CFGEXTCAP pins, EXT AXI ports cap +struct cfg_ext_cap_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cfg_ext_cap_r() : + word0(0) + {} + CONSTEXPR cfg_ext_cap_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cfg_ext_cap_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cfg_ext_cap_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR cfg_ext_cap_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR cfg_ext_cap_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// cfg_sram_hash0_r - The value of the CFGSRAMHASH0 pins, SRAM AXI port select bit 0 hash +struct cfg_sram_hash0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t zero : 6; // Must be zero + uint32_t hash_LO : 26; // Hash function - LSB + uint32_t hash_HI : 8; // Hash function - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR cfg_sram_hash0_r() : + word0(0), + word1(0) + {} + CONSTEXPR cfg_sram_hash0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + cfg_sram_hash0_r copy() + { + return *this; + } +#endif +}; + +// cfg_sram_hash1_r - The value of the CFGSRAMHASH1 pins, SRAM AXI port select bit 1 hash +struct cfg_sram_hash1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t zero : 6; // Must be zero + uint32_t hash_LO : 26; // Hash function - LSB + uint32_t hash_HI : 8; // Hash function - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR cfg_sram_hash1_r() : + word0(0), + word1(0) + {} + CONSTEXPR cfg_sram_hash1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + cfg_sram_hash1_r copy() + { + return *this; + } +#endif +}; + +// cfg_ext_hash0_r - The value of the CFGEXTHASH0 pins, EXT AXI port select bit 0 hash +struct cfg_ext_hash0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t zero : 6; // Must be zero + uint32_t hash_LO : 26; // Hash function - LSB + uint32_t hash_HI : 8; // Hash function - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR cfg_ext_hash0_r() : + word0(0), + word1(0) + {} + CONSTEXPR cfg_ext_hash0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + cfg_ext_hash0_r copy() + { + return *this; + } +#endif +}; + +// basep_r - AXI base address of the respective region number 0 - 7 +struct basep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR basep_r() : + word0(0), + word1(0) + {} + CONSTEXPR basep_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + basep_r copy() + { + return *this; + } +#endif +}; + +// clkforce_r - Force clocks on for clock gating +struct clkforce_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t top_level_clk : 1; // set to 1 to force on TOP level clock + uint32_t cc_clk : 1; // set to 1 to force on CC clock + uint32_t dma_clk : 1; // set to 1 to force on DMA clock + uint32_t mac_clk : 1; // set to 1 to force on MAC clock + uint32_t ao_clk : 1; // set to 1 to force on AO clock + uint32_t wd_clk : 1; // set to 1 to force on WD clock + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR clkforce_r() : + word0(0) + {} + CONSTEXPR clkforce_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + clkforce_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_top_level_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR clkforce_r& set_top_level_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cc_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR clkforce_r& set_cc_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_dma_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR clkforce_r& set_dma_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mac_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR clkforce_r& set_mac_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR clkforce_r& set_ao_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_wd_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR clkforce_r& set_wd_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } +#endif +}; + +// debug_address_r - Set debug address for register reads 0x400-0x7FF. The address must be 1KB aligned +struct debug_address_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t addr : 28; // Address in the RAM, 1KB aligned + uint32_t ram_id : 4; // RAM to access + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR debug_address_r() : + word0(0) + {} + CONSTEXPR debug_address_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + debug_address_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + auto v = ((1U << 28) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR debug_address_r& set_addr(uint32_t value) + { + word0 = (~(((1U << 28) - 1)<<0) & word0) | ((((1U << 28) - 1) & value) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ram_id get_ram_id() const + { + auto v = ((1U << 4) - 1) & (word0 >> 28); + assert(v <= 4); + return static_cast(v); + } + CONSTEXPR debug_address_r& set_ram_id(NPU_NAMESPACE::ram_id value) + { + word0 = (~(((1U << 4) - 1)<<28) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 28); + return *this; + } +#endif +}; + +// debug_misc_r - 32-bit read/write register for driver debug use. This does not affect NPU function +struct debug_misc_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t misc : 32; // Debug misc + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR debug_misc_r() : + word0(0) + {} + CONSTEXPR debug_misc_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + debug_misc_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_misc() const + { + auto v = word0; + return v; + } + CONSTEXPR debug_misc_r& set_misc(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// feature_disable_r - Disable micro-architectural features +struct feature_disable_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t ib_reuse_kd_disable : 1; // Setting to 1 will disable the optimization to reuse IFM data when using kernel decomposition for large kernels + uint32_t ib_reuse_ifm_depth_disable : 1; // Setting to 1 will disable the optimization to reuse IFM data when performing convolution operations + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR feature_disable_r() : + word0(0) + {} + CONSTEXPR feature_disable_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + feature_disable_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_ib_reuse_kd_disable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR feature_disable_r& set_ib_reuse_kd_disable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ib_reuse_ifm_depth_disable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR feature_disable_r& set_ib_reuse_ifm_depth_disable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } +#endif +}; + +// dma_ifm_src_r - DMA IFM channel source position on AXI +struct dma_ifm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_ifm_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_ifm_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_ifm_src_r copy() + { + return *this; + } +#endif +}; + +// dma_ofm_dst_r - DMA OFM channel destination position on AXI +struct dma_ofm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_ofm_dst_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_ofm_dst_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_ofm_dst_r copy() + { + return *this; + } +#endif +}; + +// dma_weight_src_r - DMA weight channel source position on AXI +struct dma_weight_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight_src_r copy() + { + return *this; + } +#endif +}; + +// dma_cmd_src_r - DMA command channel source position on AXI +struct dma_cmd_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_cmd_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_cmd_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_cmd_src_r copy() + { + return *this; + } +#endif +}; + +// dma_cmd_size_r - DMA command channel number of bytes buffered +struct dma_cmd_size_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma_cmd_size_r() : + word0(0) + {} + CONSTEXPR dma_cmd_size_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma_cmd_size_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma_cmd_size_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma_m2m_src_r - DMA memory to memory source position on AXI +struct dma_m2m_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_m2m_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_m2m_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_src_r copy() + { + return *this; + } +#endif +}; + +// dma_m2m_dst_r - DMA memory to memory destination position on AXI +struct dma_m2m_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_m2m_dst_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_m2m_dst_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_dst_r copy() + { + return *this; + } +#endif +}; + +// current_qread_r - QREAD position being issued (rather than completed) +struct current_qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR current_qread_r() : + word0(0) + {} + CONSTEXPR current_qread_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + current_qread_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR current_qread_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma_scale_src_r - DMA scale and bias channel source position on AXI +struct dma_scale_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_scale_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_scale_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_scale_src_r copy() + { + return *this; + } +#endif +}; + +// dma_weight1_src_r - DMA weight1 channel source position on AXI +struct dma_weight1_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight1_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight1_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight1_src_r copy() + { + return *this; + } +#endif +}; + +// dma_weight2_src_r - DMA weight2 channel source position on AXI +struct dma_weight2_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight2_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight2_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight2_src_r copy() + { + return *this; + } +#endif +}; + +// dma_weight3_src_r - DMA weight3 channel source position on AXI +struct dma_weight3_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight3_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight3_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight3_src_r copy() + { + return *this; + } +#endif +}; + +// current_op_r - Latest NPU OP command issued by the parser +struct current_op_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR current_op_r() : + word0(0) + {} + CONSTEXPR current_op_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + current_op_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR current_op_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// current_cmd_r - Current 32-bit command being parsed by the command stream parser +struct current_cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR current_cmd_r() : + word0(0) + {} + CONSTEXPR current_cmd_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + current_cmd_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR current_cmd_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// internal_memory_r - 1KB window onto internal memory as set by DEBUG_ADDRESS +struct internal_memory_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_word : 32; // Memory word + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR internal_memory_r() : + word0(0) + {} + CONSTEXPR internal_memory_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + internal_memory_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_mem_word() const + { + auto v = word0; + return v; + } + CONSTEXPR internal_memory_r& set_mem_word(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_top_r - State managed by NPU_SET_IFM_PAD_TOP +struct ifm_pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_top_r() : + word0(0) + {} + CONSTEXPR ifm_pad_top_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_top_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_top_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_left_r - State managed by NPU_SET_IFM_PAD_LEFT +struct ifm_pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_left_r() : + word0(0) + {} + CONSTEXPR ifm_pad_left_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_left_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_left_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_right_r - State managed by NPU_SET_IFM_PAD_RIGHT +struct ifm_pad_right_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_right_r() : + word0(0) + {} + CONSTEXPR ifm_pad_right_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_right_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_right_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_bottom_r - State managed by NPU_SET_IFM_PAD_BOTTOM +struct ifm_pad_bottom_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_bottom_r() : + word0(0) + {} + CONSTEXPR ifm_pad_bottom_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_bottom_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_bottom_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_depth_m1_r - State managed by NPU_SET_IFM_DEPTH_M1 +struct ifm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_depth_m1_r() : + word0(0) + {} + CONSTEXPR ifm_depth_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_depth_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_depth_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_precision_r - State managed by NPU_SET_IFM_PRECISION +struct ifm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_precision_r() : + word0(0) + {} + CONSTEXPR ifm_precision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_precision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_precision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_upscale_r - State managed by NPU_SET_IFM_UPSCALE +struct ifm_upscale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_upscale_r() : + word0(0) + {} + CONSTEXPR ifm_upscale_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_upscale_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_upscale_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_broadcast_r - State managed by NPU_SET_IFM_BROADCAST +struct ifm_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_broadcast_r() : + word0(0) + {} + CONSTEXPR ifm_broadcast_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_broadcast_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_broadcast_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_zero_point_r - State managed by NPU_SET_IFM_ZERO_POINT +struct ifm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_zero_point_r() : + word0(0) + {} + CONSTEXPR ifm_zero_point_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_zero_point_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_zero_point_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_width0_m1_r - State managed by NPU_SET_IFM_WIDTH0_M1 +struct ifm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_width0_m1_r() : + word0(0) + {} + CONSTEXPR ifm_width0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_width0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_width0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height0_m1_r - State managed by NPU_SET_IFM_HEIGHT0_M1 +struct ifm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_height0_m1_r() : + word0(0) + {} + CONSTEXPR ifm_height0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_height0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_height0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height1_m1_r - State managed by NPU_SET_IFM_HEIGHT1_M1 +struct ifm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_height1_m1_r() : + word0(0) + {} + CONSTEXPR ifm_height1_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_height1_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_height1_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_region_r - State managed by NPU_SET_IFM_REGION +struct ifm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_region_r() : + word0(0) + {} + CONSTEXPR ifm_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width_m1_r - State managed by NPU_SET_OFM_WIDTH_M1 +struct ofm_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_width_m1_r() : + word0(0) + {} + CONSTEXPR ofm_width_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_width_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_width_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height_m1_r - State managed by NPU_SET_OFM_HEIGHT_M1 +struct ofm_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_height_m1_r() : + word0(0) + {} + CONSTEXPR ofm_height_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_height_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_height_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_depth_m1_r - State managed by NPU_SET_OFM_DEPTH_M1 +struct ofm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_depth_m1_r() : + word0(0) + {} + CONSTEXPR ofm_depth_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_depth_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_depth_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_precision_r - State managed by NPU_SET_OFM_PRECISION +struct ofm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_precision_r() : + word0(0) + {} + CONSTEXPR ofm_precision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_precision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_precision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_width_m1_r - State managed by NPU_SET_OFM_BLK_WIDTH_M1 +struct ofm_blk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_blk_width_m1_r() : + word0(0) + {} + CONSTEXPR ofm_blk_width_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_blk_width_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_blk_width_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_height_m1_r - State managed by NPU_SET_OFM_BLK_HEIGHT_M1 +struct ofm_blk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_blk_height_m1_r() : + word0(0) + {} + CONSTEXPR ofm_blk_height_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_blk_height_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_blk_height_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_depth_m1_r - State managed by NPU_SET_OFM_BLK_DEPTH_M1 +struct ofm_blk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_blk_depth_m1_r() : + word0(0) + {} + CONSTEXPR ofm_blk_depth_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_blk_depth_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_blk_depth_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_zero_point_r - State managed by NPU_SET_OFM_ZERO_POINT +struct ofm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_zero_point_r() : + word0(0) + {} + CONSTEXPR ofm_zero_point_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_zero_point_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_zero_point_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width0_m1_r - State managed by NPU_SET_OFM_WIDTH0_M1 +struct ofm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_width0_m1_r() : + word0(0) + {} + CONSTEXPR ofm_width0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_width0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_width0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height0_m1_r - State managed by NPU_SET_OFM_HEIGHT0_M1 +struct ofm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_height0_m1_r() : + word0(0) + {} + CONSTEXPR ofm_height0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_height0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_height0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height1_m1_r - State managed by NPU_SET_OFM_HEIGHT1_M1 +struct ofm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_height1_m1_r() : + word0(0) + {} + CONSTEXPR ofm_height1_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_height1_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_height1_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_region_r - State managed by NPU_SET_OFM_REGION +struct ofm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_region_r() : + word0(0) + {} + CONSTEXPR ofm_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_width_m1_r - State managed by NPU_SET_KERNEL_WIDTH_M1 +struct kernel_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR kernel_width_m1_r() : + word0(0) + {} + CONSTEXPR kernel_width_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + kernel_width_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR kernel_width_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_height_m1_r - State managed by NPU_SET_KERNEL_HEIGHT_M1 +struct kernel_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR kernel_height_m1_r() : + word0(0) + {} + CONSTEXPR kernel_height_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + kernel_height_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR kernel_height_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_stride_r - State managed by NPU_SET_KERNEL_STRIDE +struct kernel_stride_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR kernel_stride_r() : + word0(0) + {} + CONSTEXPR kernel_stride_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + kernel_stride_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR kernel_stride_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// acc_format_r - State managed by NPU_SET_ACC_FORMAT +struct acc_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR acc_format_r() : + word0(0) + {} + CONSTEXPR acc_format_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + acc_format_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR acc_format_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// activation_r - State managed by NPU_SET_ACTIVATION +struct activation_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR activation_r() : + word0(0) + {} + CONSTEXPR activation_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + activation_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR activation_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// activation_min_r - State managed by NPU_SET_ACTIVATION_MIN +struct activation_min_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR activation_min_r() : + word0(0) + {} + CONSTEXPR activation_min_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + activation_min_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR activation_min_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// activation_max_r - State managed by NPU_SET_ACTIVATION_MAX +struct activation_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR activation_max_r() : + word0(0) + {} + CONSTEXPR activation_max_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + activation_max_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR activation_max_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// weight_region_r - State managed by NPU_SET_WEIGHT_REGION +struct weight_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR weight_region_r() : + word0(0) + {} + CONSTEXPR weight_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + weight_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR weight_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// scale_region_r - State managed by NPU_SET_SCALE_REGION +struct scale_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR scale_region_r() : + word0(0) + {} + CONSTEXPR scale_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + scale_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR scale_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_x_scale_n_m1_r - State managed by NPU_SET_RESIZE_X_SCALE_N_M1 +struct resize_x_scale_n_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_x_scale_n_m1_r() : + word0(0) + {} + CONSTEXPR resize_x_scale_n_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_x_scale_n_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_x_scale_n_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_y_scale_n_m1_r - State managed by NPU_SET_RESIZE_Y_SCALE_N_M1 +struct resize_y_scale_n_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_y_scale_n_m1_r() : + word0(0) + {} + CONSTEXPR resize_y_scale_n_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_y_scale_n_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_y_scale_n_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_x_offset_r - State managed by NPU_SET_RESIZE_X_OFFSET +struct resize_x_offset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_x_offset_r() : + word0(0) + {} + CONSTEXPR resize_x_offset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_x_offset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_x_offset_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_y_offset_r - State managed by NPU_SET_RESIZE_Y_OFFSET +struct resize_y_offset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_y_offset_r() : + word0(0) + {} + CONSTEXPR resize_y_offset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_y_offset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_y_offset_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// weight_format_r - State managed by NPU_SET_WEIGHT_FORMAT +struct weight_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR weight_format_r() : + word0(0) + {} + CONSTEXPR weight_format_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + weight_format_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR weight_format_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// blockdep_r - State managed by NPU_SET_BLOCKDEP +struct blockdep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR blockdep_r() : + word0(0) + {} + CONSTEXPR blockdep_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + blockdep_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR blockdep_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_region_r - State managed by NPU_SET_DMA0_SRC_REGION +struct dma0_src_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_src_region_r() : + word0(0) + {} + CONSTEXPR dma0_src_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_src_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_src_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_dst_region_r - State managed by NPU_SET_DMA0_DST_REGION +struct dma0_dst_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_dst_region_r() : + word0(0) + {} + CONSTEXPR dma0_dst_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_dst_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_dst_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size0_r - State managed by NPU_SET_DMA0_SIZE0 +struct dma0_size0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_size0_r() : + word0(0) + {} + CONSTEXPR dma0_size0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_size0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_size0_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size1_r - State managed by NPU_SET_DMA0_SIZE1 +struct dma0_size1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_size1_r() : + word0(0) + {} + CONSTEXPR dma0_size1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_size1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_size1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_idx_region_r - State managed by NPU_SET_DMA0_IDX_REGION +struct dma0_idx_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_idx_region_r() : + word0(0) + {} + CONSTEXPR dma0_idx_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_idx_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_idx_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_broadcast_r - State managed by NPU_SET_IFM2_BROADCAST +struct ifm2_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_broadcast_r() : + word0(0) + {} + CONSTEXPR ifm2_broadcast_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_broadcast_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_broadcast_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_precision_r - State managed by NPU_SET_IFM2_PRECISION +struct ifm2_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_precision_r() : + word0(0) + {} + CONSTEXPR ifm2_precision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_precision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_precision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_zero_point_r - State managed by NPU_SET_IFM2_ZERO_POINT +struct ifm2_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_zero_point_r() : + word0(0) + {} + CONSTEXPR ifm2_zero_point_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_zero_point_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_zero_point_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_width0_m1_r - State managed by NPU_SET_IFM2_WIDTH0_M1 +struct ifm2_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_width0_m1_r() : + word0(0) + {} + CONSTEXPR ifm2_width0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_width0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_width0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height0_m1_r - State managed by NPU_SET_IFM2_HEIGHT0_M1 +struct ifm2_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_height0_m1_r() : + word0(0) + {} + CONSTEXPR ifm2_height0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_height0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_height0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height1_m1_r - State managed by NPU_SET_IFM2_HEIGHT1_M1 +struct ifm2_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_height1_m1_r() : + word0(0) + {} + CONSTEXPR ifm2_height1_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_height1_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_height1_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_region_r - State managed by NPU_SET_IFM2_REGION +struct ifm2_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_region_r() : + word0(0) + {} + CONSTEXPR ifm2_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_base0_r - State managed by NPU_SET_IFM_BASE0 +struct ifm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base0_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base0_r copy() + { + return *this; + } +#endif +}; + +// ifm_base1_r - State managed by NPU_SET_IFM_BASE1 +struct ifm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base1_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base1_r copy() + { + return *this; + } +#endif +}; + +// ifm_base2_r - State managed by NPU_SET_IFM_BASE2 +struct ifm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base2_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base2_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base2_r copy() + { + return *this; + } +#endif +}; + +// ifm_base3_r - State managed by NPU_SET_IFM_BASE3 +struct ifm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base3_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base3_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base3_r copy() + { + return *this; + } +#endif +}; + +// ifm_stride_x_r - State managed by NPU_SET_IFM_STRIDE_X +struct ifm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_stride_x_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_stride_x_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_x_r copy() + { + return *this; + } +#endif +}; + +// ifm_stride_y_r - State managed by NPU_SET_IFM_STRIDE_Y +struct ifm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_stride_y_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_stride_y_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_y_r copy() + { + return *this; + } +#endif +}; + +// ifm_stride_c_r - State managed by NPU_SET_IFM_STRIDE_C +struct ifm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_stride_c_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_stride_c_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_c_r copy() + { + return *this; + } +#endif +}; + +// ofm_base0_r - State managed by NPU_SET_OFM_BASE0 +struct ofm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base0_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base0_r copy() + { + return *this; + } +#endif +}; + +// ofm_base1_r - State managed by NPU_SET_OFM_BASE1 +struct ofm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base1_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base1_r copy() + { + return *this; + } +#endif +}; + +// ofm_base2_r - State managed by NPU_SET_OFM_BASE2 +struct ofm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base2_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base2_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base2_r copy() + { + return *this; + } +#endif +}; + +// ofm_base3_r - State managed by NPU_SET_OFM_BASE3 +struct ofm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base3_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base3_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base3_r copy() + { + return *this; + } +#endif +}; + +// ofm_stride_x_r - State managed by NPU_SET_OFM_STRIDE_X +struct ofm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_stride_x_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_stride_x_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_x_r copy() + { + return *this; + } +#endif +}; + +// ofm_stride_y_r - State managed by NPU_SET_OFM_STRIDE_Y +struct ofm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_stride_y_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_stride_y_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_y_r copy() + { + return *this; + } +#endif +}; + +// ofm_stride_c_r - State managed by NPU_SET_OFM_STRIDE_C +struct ofm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_stride_c_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_stride_c_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_c_r copy() + { + return *this; + } +#endif +}; + +// weight_base_r - State managed by NPU_SET_WEIGHT_BASE +struct weight_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight_base_r copy() + { + return *this; + } +#endif +}; + +// weight_length_r - State managed by NPU_SET_WEIGHT_LENGTH +struct weight_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight_length_r copy() + { + return *this; + } +#endif +}; + +// scale_base_r - State managed by NPU_SET_SCALE_BASE +struct scale_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR scale_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR scale_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + scale_base_r copy() + { + return *this; + } +#endif +}; + +// scale_length_r - State managed by NPU_SET_SCALE_LENGTH +struct scale_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR scale_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR scale_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + scale_length_r copy() + { + return *this; + } +#endif +}; + +// ofm_scale_r - State managed by NPU_SET_OFM_SCALE +struct ofm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_scale_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_scale_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_scale_r copy() + { + return *this; + } +#endif +}; + +// ifm_scale_r - State managed by NPU_SET_IFM_SCALE +struct ifm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_scale_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_scale_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_scale_r copy() + { + return *this; + } +#endif +}; + +// ifm2_scale_r - State managed by NPU_SET_IFM2_SCALE +struct ifm2_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_scale_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_scale_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_scale_r copy() + { + return *this; + } +#endif +}; + +// op_scalar_r - State managed by NPU_SET_OP_SCALAR +struct op_scalar_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR op_scalar_r() : + word0(0), + word1(0) + {} + CONSTEXPR op_scalar_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + op_scalar_r copy() + { + return *this; + } +#endif +}; + +// dma0_src_r - State managed by NPU_SET_DMA0_SRC +struct dma0_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_r copy() + { + return *this; + } +#endif +}; + +// dma0_dst_r - State managed by NPU_SET_DMA0_DST +struct dma0_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_dst_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_dst_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_r copy() + { + return *this; + } +#endif +}; + +// dma0_len_r - State managed by NPU_SET_DMA0_LEN +struct dma0_len_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_len_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_len_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_len_r copy() + { + return *this; + } +#endif +}; + +// dma0_src_stride0_r - State managed by NPU_SET_DMA0_SRC_STRIDE0 +struct dma0_src_stride0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_src_stride0_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_src_stride0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_stride0_r copy() + { + return *this; + } +#endif +}; + +// dma0_src_stride1_r - State managed by NPU_SET_DMA0_SRC_STRIDE1 +struct dma0_src_stride1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_src_stride1_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_src_stride1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_stride1_r copy() + { + return *this; + } +#endif +}; + +// dma0_dst_stride0_r - State managed by NPU_SET_DMA0_DST_STRIDE0 +struct dma0_dst_stride0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_dst_stride0_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_dst_stride0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_stride0_r copy() + { + return *this; + } +#endif +}; + +// dma0_dst_stride1_r - State managed by NPU_SET_DMA0_DST_STRIDE1 +struct dma0_dst_stride1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_dst_stride1_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_dst_stride1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_stride1_r copy() + { + return *this; + } +#endif +}; + +// dma0_idx_r - State managed by NPU_SET_DMA0_IDX +struct dma0_idx_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_idx_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_idx_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_idx_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base0_r - State managed by NPU_SET_IFM2_BASE0 +struct ifm2_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base0_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base0_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base1_r - State managed by NPU_SET_IFM2_BASE1 +struct ifm2_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base1_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base1_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base2_r - State managed by NPU_SET_IFM2_BASE2 +struct ifm2_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base2_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base2_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base2_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base3_r - State managed by NPU_SET_IFM2_BASE3 +struct ifm2_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base3_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base3_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base3_r copy() + { + return *this; + } +#endif +}; + +// ifm2_stride_x_r - State managed by NPU_SET_IFM2_STRIDE_X +struct ifm2_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_stride_x_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_stride_x_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_x_r copy() + { + return *this; + } +#endif +}; + +// ifm2_stride_y_r - State managed by NPU_SET_IFM2_STRIDE_Y +struct ifm2_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_stride_y_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_stride_y_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_y_r copy() + { + return *this; + } +#endif +}; + +// ifm2_stride_c_r - State managed by NPU_SET_IFM2_STRIDE_C +struct ifm2_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_stride_c_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_stride_c_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_c_r copy() + { + return *this; + } +#endif +}; + +// weight1_base_r - State managed by NPU_SET_WEIGHT1_BASE +struct weight1_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight1_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight1_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight1_base_r copy() + { + return *this; + } +#endif +}; + +// weight1_length_r - State managed by NPU_SET_WEIGHT1_LENGTH +struct weight1_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight1_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight1_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight1_length_r copy() + { + return *this; + } +#endif +}; + +// weight2_base_r - State managed by NPU_SET_WEIGHT2_BASE +struct weight2_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight2_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight2_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight2_base_r copy() + { + return *this; + } +#endif +}; + +// weight2_length_r - State managed by NPU_SET_WEIGHT2_LENGTH +struct weight2_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight2_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight2_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight2_length_r copy() + { + return *this; + } +#endif +}; + +// weight3_base_r - State managed by NPU_SET_WEIGHT3_BASE +struct weight3_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight3_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight3_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight3_base_r copy() + { + return *this; + } +#endif +}; + +// weight3_length_r - State managed by NPU_SET_WEIGHT3_LENGTH +struct weight3_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight3_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight3_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight3_length_r copy() + { + return *this; + } +#endif +}; + +// resize_x_step_r - State managed by NPU_SET_RESIZE_X_STEP +struct resize_x_step_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR resize_x_step_r() : + word0(0), + word1(0) + {} + CONSTEXPR resize_x_step_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + resize_x_step_r copy() + { + return *this; + } +#endif +}; + +// resize_y_step_r - State managed by NPU_SET_RESIZE_Y_STEP +struct resize_y_step_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR resize_y_step_r() : + word0(0), + word1(0) + {} + CONSTEXPR resize_y_step_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + resize_y_step_r copy() + { + return *this; + } +#endif +}; + +// dma0_idx_max_r - State managed by NPU_SET_DMA0_IDX_MAX +struct dma0_idx_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_idx_max_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_idx_max_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_idx_max_r copy() + { + return *this; + } +#endif +}; + +// dma0_idx_skip1_r - State managed by NPU_SET_DMA0_IDX_SKIP1 +struct dma0_idx_skip1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_idx_skip1_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_idx_skip1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_idx_skip1_r copy() + { + return *this; + } +#endif +}; + +// revision_r - Internal FPGA build revision: first 32 bits of the Ultan git hash used for the build +struct revision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR revision_r() : + word0(0) + {} + CONSTEXPR revision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + revision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR revision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid4_r - Peripheral ID byte 4 (Arm=code 4) +struct pid4_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID4 : 32; // Byte 4 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid4_r() : + word0(4) + {} + CONSTEXPR pid4_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid4_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID4() const + { + auto v = word0; + return v; + } + CONSTEXPR pid4_r& set_PID4(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid5_r - Peripheral ID byte 5 (reserved) +struct pid5_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID5 : 32; // Byte 5 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid5_r() : + word0(0) + {} + CONSTEXPR pid5_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid5_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID5() const + { + auto v = word0; + return v; + } + CONSTEXPR pid5_r& set_PID5(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid6_r - Peripheral ID byte 6 (reserved) +struct pid6_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID6 : 32; // Byte 6 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid6_r() : + word0(0) + {} + CONSTEXPR pid6_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid6_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID6() const + { + auto v = word0; + return v; + } + CONSTEXPR pid6_r& set_PID6(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid7_r - Peripheral ID byte 7 (reserved) +struct pid7_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID7 : 32; // Byte 7 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid7_r() : + word0(0) + {} + CONSTEXPR pid7_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid7_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID7() const + { + auto v = word0; + return v; + } + CONSTEXPR pid7_r& set_PID7(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid0_r - Peripheral ID byte 0. This is bits[7:0] of the part number +struct pid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID0 : 32; // Byte 0 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid0_r() : + word0(130) + {} + CONSTEXPR pid0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID0() const + { + auto v = word0; + return v; + } + CONSTEXPR pid0_r& set_PID0(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid1_r - Peripheral ID byte 1. This is bits[11:8] of the part number in bits[3:0], and bits[3:0] of the Arm ID in bits[7:4] +struct pid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID1 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid1_r() : + word0(181) + {} + CONSTEXPR pid1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID1() const + { + auto v = word0; + return v; + } + CONSTEXPR pid1_r& set_PID1(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid2_r - Peripheral ID byte 2. This is bits[6:4] of the Arm ID in bits[2:0], and bit 3 indicates format B +struct pid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID2 : 32; // Byte 2 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid2_r() : + word0(11) + {} + CONSTEXPR pid2_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid2_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID2() const + { + auto v = word0; + return v; + } + CONSTEXPR pid2_r& set_PID2(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid3_r - Peripheral ID byte 3 +struct pid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID3 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid3_r() : + word0(0) + {} + CONSTEXPR pid3_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid3_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID3() const + { + auto v = word0; + return v; + } + CONSTEXPR pid3_r& set_PID3(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid0_r - Component ID byte 0 +struct cid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID0 : 32; // Byte 0 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid0_r() : + word0(13) + {} + CONSTEXPR cid0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID0() const + { + auto v = word0; + return v; + } + CONSTEXPR cid0_r& set_CID0(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid1_r - Component ID byte 1 +struct cid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID1 : 32; // Byte 1 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid1_r() : + word0(240) + {} + CONSTEXPR cid1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID1() const + { + auto v = word0; + return v; + } + CONSTEXPR cid1_r& set_CID1(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid2_r - Component ID byte 2 +struct cid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID2 : 32; // Byte 2 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid2_r() : + word0(5) + {} + CONSTEXPR cid2_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid2_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID2() const + { + auto v = word0; + return v; + } + CONSTEXPR cid2_r& set_CID2(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid3_r - Component ID byte 3 +struct cid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID3 : 32; // Byte 3 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid3_r() : + word0(177) + {} + CONSTEXPR cid3_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid3_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID3() const + { + auto v = word0; + return v; + } + CONSTEXPR cid3_r& set_CID3(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// wd_status_r - WD_STATUS +struct wd_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t ctrl_idle : 1; // All stripe jobs idle (all weights consumed) + uint32_t reserved0 : 1; + uint32_t active_core : 2; // WD active core + uint32_t sc0_idle : 1; // Standard core 0 idle + uint32_t sc1_idle : 1; // Standard core 1 idle + uint32_t sc2_idle : 1; // Standard core 2 idle + uint32_t sc3_idle : 1; // Standard core 3 idle + uint32_t fc_idle : 1; // Fast core idle + uint32_t tc_idle : 1; // Tensor core (IFM input) idle + uint32_t reserved1 : 6; + uint32_t wbuf0_valid : 1; // Weight buffer 0 full + uint32_t wbuf0_idle : 1; // Weight buffer 0 empty + uint32_t wbuf1_valid : 1; // Weight buffer 1 full + uint32_t wbuf1_idle : 1; // Weight buffer 1 empty + uint32_t wbuf2_valid : 1; // Weight buffer 2 full + uint32_t wbuf2_idle : 1; // Weight buffer 2 empty + uint32_t wbuf3_valid : 1; // Weight buffer 3 full + uint32_t wbuf3_idle : 1; // Weight buffer 3 empty + uint32_t stalled_by_ws_sc0 : 1; // WD stalled by lack of standard core 0 weight stream data + uint32_t stalled_by_ws_sc1 : 1; // WD stalled by lack of standard core 1 weight stream data + uint32_t stalled_by_ws_sc2 : 1; // WD stalled by lack of standard core 2 weight stream data + uint32_t stalled_by_ws_sc3 : 1; // WD stalled by lack of standard core 3 weight stream data + uint32_t stalled_by_ws_fc : 1; // WD stalled by lack of fast core weight stream data + uint32_t stalled_by_ws_tc : 1; // WD stalled by lack of tensor core IFM stream data + uint32_t stalled_by_wd_buf : 1; // WD stalled by lack of free WD buffer (blocked by MAC) + uint32_t reserved2 : 1; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR wd_status_r() : + word0(0) + {} + CONSTEXPR wd_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + wd_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_ctrl_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR wd_status_r& set_ctrl_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_active_core get_active_core() const + { + auto v = ((1U << 2) - 1) & (word0 >> 2); + assert(v <= 3); + return static_cast(v); + } + CONSTEXPR wd_status_r& set_active_core(NPU_NAMESPACE::wd_active_core value) + { + word0 = (~(((1U << 2) - 1)<<2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR uint32_t get_sc0_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR wd_status_r& set_sc0_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_sc1_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR wd_status_r& set_sc1_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_sc2_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR wd_status_r& set_sc2_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_sc3_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR wd_status_r& set_sc3_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_fc_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR wd_status_r& set_fc_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_tc_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR wd_status_r& set_tc_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_wbuf0_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR wd_status_r& set_wbuf0_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_wbuf0_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 17); + return v; + } + CONSTEXPR wd_status_r& set_wbuf0_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_wbuf1_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 18); + return v; + } + CONSTEXPR wd_status_r& set_wbuf1_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_wbuf1_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 19); + return v; + } + CONSTEXPR wd_status_r& set_wbuf1_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wbuf2_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR wd_status_r& set_wbuf2_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wbuf2_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 21); + return v; + } + CONSTEXPR wd_status_r& set_wbuf2_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_wbuf3_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 22); + return v; + } + CONSTEXPR wd_status_r& set_wbuf3_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_wbuf3_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 23); + return v; + } + CONSTEXPR wd_status_r& set_wbuf3_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 24); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 25); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc1(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 26); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc2(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 27); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc3(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_fc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_fc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_tc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 29); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_tc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_wd_buf() const + { + auto v = ((1U << 1) - 1) & (word0 >> 30); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_wd_buf(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } +#endif +}; + +// mac_status_r - MAC_STATUS +struct mac_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mac_active : 1; // Valid block command and not stalled + uint32_t reserved0 : 2; + uint32_t mac_dpu_active : 1; // At least one DPU is active + uint32_t mac_stalled_by_w_or_acc : 1; // MAC stalled by WB or AB (not IB) + uint32_t mac_stalled_by_w : 1; // MAC stalled by WB (not IB) + uint32_t mac_stalled_by_acc : 1; // MAC stalled by AB (not IB) + uint32_t mac_stalled_by_ib : 1; // MAC stalled by IB + uint32_t reserved1 : 24; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR mac_status_r() : + word0(0) + {} + CONSTEXPR mac_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + mac_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_mac_active() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR mac_status_r& set_mac_active(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_mac_dpu_active() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR mac_status_r& set_mac_dpu_active(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_w_or_acc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_w_or_acc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_w() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_w(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_acc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_acc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_ib() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_ib(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } +#endif +}; + +// ao_status_r - AO_STATUS +struct ao_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t ao_active : 1; // Valid block command and not stalled + uint32_t reserved0 : 2; + uint32_t ao_stalled_by_bs_or_ob : 1; // Stalled by bias scale data or output block + uint32_t ao_stalled_by_bs : 1; // Stalled by bias scale data + uint32_t ao_stalled_by_ob : 1; // Stalled by output block + uint32_t ao_stalled_by_ab_or_cb : 1; // Stalled by accumulator or chaining buffer + uint32_t ao_stalled_by_ab : 1; // Stalled by accumulator buffer + uint32_t ao_stalled_by_cb : 1; // Stalled by chaining buffer + uint32_t reserved1 : 23; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ao_status_r() : + word0(0) + {} + CONSTEXPR ao_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ao_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_ao_active() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR ao_status_r& set_ao_active(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_bs_or_ob() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_bs_or_ob(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_bs() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_bs(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_ob() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_ob(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_ab_or_cb() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_ab_or_cb(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_ab() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_ab(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_cb() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_cb(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } +#endif +}; + +// dma_status0_r - DMA_STATUS0 +struct dma_status0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_ch_idle : 1; // When this bit is high means that the CMD channel is not busy in generating addresses for a CMD job + uint32_t ifm0_ch_idle : 1; // When this bit is high means that there are no ongoing IFM MAC jobs + uint32_t ifm1_ch_idle : 1; // When this bit is high means that there are no ongoing IFM STREAM jobs + uint32_t wgt_ch_idle : 1; // When this bit is high means that the WGT channel is not busy in generating addresses for a WGT job + uint32_t bas_ch_idle : 1; // When this bit is high means that the BAS channel is not busy in generating addresses for a BAS job + uint32_t m2m_ch_idle : 1; // When this bit is high means that there are no ongoing M2M jobs + uint32_t ofm_ch_idle : 1; // When this bit is high means that there are no ongoing OFM jobs + uint32_t axi_halt_req : 1; // CPM has requested to HALT AXI bus before soft reset + uint32_t axi_halt_ack : 1; // DMA is in condition to halt the AXI bus since there are no pending transactions + uint32_t axi_pause_req : 1; // CC has requested to pause the AXI + uint32_t axi_pause_ack : 1; // DMA is in condition to pause the AXI bus since there are no pending transactions + uint32_t cmd_abort_ack : 1; // CC has requested to abort a CMD channel job + uint32_t cmd_abort_req : 1; // DMA has acknowledged the request of aborting a CMD channel job + uint32_t ifm_mac_if_stall : 1; // Valid high and Ready low for IFM MAC interface + uint32_t ifm_tc_if_stall : 1; // Valid high and Ready low for IFM WD Tensor Core interface + uint32_t ifm_ao_if_stall : 1; // Valid high and Ready low for IFM AO interface + uint32_t ofm_if_stall : 1; // Valid high and Ready low for OFM interface between AO and DMA + uint32_t cmd_if_stall : 1; // Valid high and Ready low for CMD interface between DMA and CC + uint32_t wd_sc0_if_stall : 1; // Valid high and Ready low for SC0 bitstream interface toward WD + uint32_t wd_sc1_if_stall : 1; // Valid high and Ready low for SC1 bitstream interface toward WD + uint32_t wd_sc2_if_stall : 1; // Valid high and Ready low for SC2 bitstream interface toward WD + uint32_t wd_sc3_if_stall : 1; // Valid high and Ready low for SC2 bitstream interface toward WD + uint32_t wd_fc_if_stall : 1; // Valid high and Ready low for FC bitstream interface toward WD + uint32_t bs_if_stall : 1; // Valid high and Ready low for BAS interface between DMA and AO + uint32_t lutcfg_if_stall : 1; // Valid high and Ready low for LUTCFG interface between DMA and AO + uint32_t reserved0 : 7; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma_status0_r() : + word0(0) + {} + CONSTEXPR dma_status0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma_status0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_cmd_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ifm0_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR dma_status0_r& set_ifm0_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_ifm1_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR dma_status0_r& set_ifm1_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_wgt_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR dma_status0_r& set_wgt_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_bas_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR dma_status0_r& set_bas_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_m2m_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR dma_status0_r& set_m2m_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_ofm_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR dma_status0_r& set_ofm_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_axi_halt_req() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR dma_status0_r& set_axi_halt_req(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_axi_halt_ack() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR dma_status0_r& set_axi_halt_ack(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_axi_pause_req() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR dma_status0_r& set_axi_pause_req(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_axi_pause_ack() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR dma_status0_r& set_axi_pause_ack(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_cmd_abort_ack() const + { + auto v = ((1U << 1) - 1) & (word0 >> 11); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_abort_ack(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_cmd_abort_req() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_abort_req(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ifm_mac_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + return v; + } + CONSTEXPR dma_status0_r& set_ifm_mac_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ifm_tc_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + return v; + } + CONSTEXPR dma_status0_r& set_ifm_tc_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ifm_ao_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + return v; + } + CONSTEXPR dma_status0_r& set_ifm_ao_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ofm_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR dma_status0_r& set_ofm_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_cmd_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 17); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_wd_sc0_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 18); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc0_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_wd_sc1_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 19); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc1_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wd_sc2_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc2_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wd_sc3_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 21); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc3_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_wd_fc_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 22); + return v; + } + CONSTEXPR dma_status0_r& set_wd_fc_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_bs_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 23); + return v; + } + CONSTEXPR dma_status0_r& set_bs_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_lutcfg_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 24); + return v; + } + CONSTEXPR dma_status0_r& set_lutcfg_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } +#endif +}; + +// dma_status1_r - DMA_STATUS1 +struct dma_status1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t axi_sram0_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM0 (due to memory system) + uint32_t axi_sram0_rd_limit_stall : 1; // Read stalled due to one AXI SRAM0 limit counter being reached + uint32_t axi_sram0_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM0 (due to memory system) + uint32_t axi_sram0_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM0 (due to memory system) + uint32_t axi_sram0_wr_limit_stall : 1; // Write stalled due to one AXI SRAM0 limit counter being reached + uint32_t axi_sram1_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM1 (due to memory system) + uint32_t axi_sram1_rd_limit_stall : 1; // Read stalled due to one AXI SRAM1 limit counter being reached + uint32_t axi_sram1_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM1 (due to memory system) + uint32_t axi_sram1_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM1 (due to memory system) + uint32_t axi_sram1_wr_limit_stall : 1; // Write stalled due to one AXI SRAM1 limit counter being reached + uint32_t axi_sram2_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM2 (due to memory system) + uint32_t axi_sram2_rd_limit_stall : 1; // Read stalled due to one AXI SRAM2 limit counter being reached + uint32_t axi_sram2_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM2 (due to memory system) + uint32_t axi_sram2_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM2 (due to memory system) + uint32_t axi_sram2_wr_limit_stall : 1; // Write stalled due to one AXI SRAM2 limit counter being reached + uint32_t axi_sram3_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM3 (due to memory system) + uint32_t axi_sram3_rd_limit_stall : 1; // Read stalled due to one AXI SRAM3 limit counter being reached + uint32_t axi_sram3_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM3 (due to memory system) + uint32_t axi_sram3_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM3 (due to memory system) + uint32_t axi_sram3_wr_limit_stall : 1; // Write stalled due to one AXI SRAM3 limit counter being reached + uint32_t axi_ext0_ar_stalled : 1; // Read transfer request stalled on arready low AXI EXT0 (due to memory system) + uint32_t axi_ext0_rd_limit_stall : 1; // Read stalled due to one AXI EXT0 limit counter being reached + uint32_t axi_ext0_aw_stalled : 1; // Write transfer request stalled on awready low AXI EXT0 (due to memory system) + uint32_t axi_ext0_w_stalled : 1; // Write transfer stalled on awready low AXI EXT0 (due to memory system) + uint32_t axi_ext0_wr_limit_stall : 1; // Write stalled due to one AXI EXT0 limit counter being reached + uint32_t axi_ext1_ar_stalled : 1; // Read transfer request stalled on arready low AXI EXT1 (due to memory system) + uint32_t axi_ext1_rd_limit_stall : 1; // Read stalled due to one AXI EXT1 limit counter being reached + uint32_t axi_ext1_aw_stalled : 1; // Write transfer request stalled on awready low AXI EXT1 (due to memory system) + uint32_t axi_ext1_w_stalled : 1; // Write transfer stalled on awready low AXI EXT1 (due to memory system) + uint32_t axi_ext1_wr_limit_stall : 1; // Write stalled due to one AXI EXT1 limit counter being reached + uint32_t reserved0 : 2; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma_status1_r() : + word0(0) + {} + CONSTEXPR dma_status1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma_status1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 11); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 17); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 18); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 19); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 21); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 22); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 23); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 24); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 25); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 26); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 27); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 29); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } +#endif +}; + +// pmcr_r - PMU register control +struct pmcr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cnt_en : 1; // Enable counter + uint32_t event_cnt_rst : 1; // Reset event counter + uint32_t cycle_cnt_rst : 1; // Reset cycle counter + uint32_t mask_en : 1; // PMU can be enabled/disabled by command stream operation NPU_OP_PMU_MASK + uint32_t reserved0 : 7; + uint32_t num_event_cnt : 5; // Number of event counters + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcr_r() : + word0(16384) + {} + CONSTEXPR pmcr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_cnt_en() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmcr_r& set_cnt_en(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_event_cnt_rst() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmcr_r& set_event_cnt_rst(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cycle_cnt_rst() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmcr_r& set_cycle_cnt_rst(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mask_en() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmcr_r& set_mask_en(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_num_event_cnt() const + { + auto v = ((1U << 5) - 1) & (word0 >> 11); + return v; + } + CONSTEXPR pmcr_r& set_num_event_cnt(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } +#endif +}; + +// pmcntenset_r - Count enable set register +struct pmcntenset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter enable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4 : 1; // Event counter enable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5 : 1; // Event counter enable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6 : 1; // Event counter enable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7 : 1; // Event counter enable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT : 1; // PMCCNTR enable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcntenset_r() : + word0(0) + {} + CONSTEXPR pmcntenset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcntenset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_1(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_2(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_3(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_4(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_5(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_6(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_7(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmcntenset_r& set_CYCLE_CNT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmcntenclr_r - Count enable clear register +struct pmcntenclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter disable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4 : 1; // Event counter disable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5 : 1; // Event counter disable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6 : 1; // Event counter disable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7 : 1; // Event counter disable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT : 1; // PMCCNTR disable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcntenclr_r() : + word0(0) + {} + CONSTEXPR pmcntenclr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcntenclr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_1(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_2(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_3(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_4(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_5(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_6(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_7(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmcntenclr_r& set_CYCLE_CNT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsset_r - Overflow flag status set register +struct pmovsset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow set bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow set bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow set bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow set bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_OVF : 1; // Event counter overflow set bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_OVF : 1; // Event counter overflow set bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_OVF : 1; // Event counter overflow set bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_OVF : 1; // Event counter overflow set bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow set bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmovsset_r() : + word0(0) + {} + CONSTEXPR pmovsset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmovsset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_4_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_5_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_6_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_7_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmovsset_r& set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsclr_r - Overflow flag status clear register +struct pmovsclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow clear bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow clear bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow clear bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow clear bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_OVF : 1; // Event counter overflow clear bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_OVF : 1; // Event counter overflow clear bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_OVF : 1; // Event counter overflow clear bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_OVF : 1; // Event counter overflow clear bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow clear bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmovsclr_r() : + word0(0) + {} + CONSTEXPR pmovsclr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmovsclr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_4_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_5_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_6_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_7_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmovsclr_r& set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintset_r - Interrupt enable set register +struct pmintset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request enable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmintset_r() : + word0(0) + {} + CONSTEXPR pmintset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmintset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_4_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_5_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_6_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_7_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmintset_r& set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintclr_r - Interrupt enable clear register +struct pmintclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request disable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmintclr_r() : + word0(0) + {} + CONSTEXPR pmintclr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmintclr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_4_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_5_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_6_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_7_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmintclr_r& set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmccntr_r - Performance monitor cycle count register +struct pmccntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_LO : 32; // Cycle count - LSB + uint32_t CYCLE_CNT_HI : 16; // Cycle count - MSB + uint32_t reserved0 : 16; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR pmccntr_r() : + word0(0), + word1(0) + {} + CONSTEXPR pmccntr_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + pmccntr_r copy() + { + return *this; + } +#endif +}; + +// pmccntr_cfg_r - Set start/stop event on the cycle counter +struct pmccntr_cfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_CFG_START : 10; // Cycle counter start event + uint32_t reserved0 : 2; + uint32_t S0 : 1; // Start disabled for AXI port 0 + uint32_t S1 : 1; // Start disabled for AXI port 1 + uint32_t S2 : 1; // Start disabled for AXI port 2 + uint32_t S3 : 1; // Start disabled for AXI port 3 + uint32_t CYCLE_CNT_CFG_STOP : 10; // Cycle counter stop event + uint32_t reserved1 : 2; + uint32_t E0 : 1; // End disabled for AXI port 0 + uint32_t E1 : 1; // End disabled for AXI port 1 + uint32_t E2 : 1; // End disabled for AXI port 2 + uint32_t E3 : 1; // End disabled for AXI port 3 + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmccntr_cfg_r() : + word0(0) + {} + CONSTEXPR pmccntr_cfg_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmccntr_cfg_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const + { + auto v = ((1U << 10) - 1) & (word0 >> 0); + assert(v <= 671); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) + { + word0 = (~(((1U << 10) - 1)<<0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S0(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S1(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 13); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S2(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 14); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S3(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 15); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const + { + auto v = ((1U << 10) - 1) & (word0 >> 16); + assert(v <= 671); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) + { + word0 = (~(((1U << 10) - 1)<<16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 28); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E0(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<28) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 28); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 29); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E1(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<29) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 29); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 30); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E2(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<30) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 30); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E3(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 31); + return *this; + } +#endif +}; + +// pmcaxi_chan_r - Set which AXI channel to monitor for latency measurements in PMU +struct pmcaxi_chan_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CH_SEL : 4; // Channel select for latency measurements + uint32_t reserved0 : 4; + uint32_t AXI_SEL : 1; // AXI port select for latency measurements + uint32_t reserved1 : 1; + uint32_t BW_CH_SEL_EN : 1; // Bandwidth channel selector + uint32_t reserved2 : 21; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcaxi_chan_r() : + word0(0) + {} + CONSTEXPR pmcaxi_chan_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcaxi_chan_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const + { + auto v = ((1U << 4) - 1) & (word0 >> 0); + assert(v <= 9); + return static_cast(v); + } + CONSTEXPR pmcaxi_chan_r& set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (~(((1U << 4) - 1)<<0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_port get_AXI_SEL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmcaxi_chan_r& set_AXI_SEL(NPU_NAMESPACE::axi_port value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 8); + return *this; + } + CONSTEXPR uint32_t get_BW_CH_SEL_EN() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR pmcaxi_chan_r& set_BW_CH_SEL_EN(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } +#endif +}; + +// pmclut_r - Performance monitor control for lookup table +struct pmclut_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PCM_LUT_EN_0 : 1; // PMU lookup table enable for event counter 0 + uint32_t reserved0 : 15; + uint32_t PMC_LUT_0 : 16; // PMU lookup table for event counter 0 + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmclut_r() : + word0(0) + {} + CONSTEXPR pmclut_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmclut_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PCM_LUT_EN_0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmclut_r& set_PCM_LUT_EN_0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_PMC_LUT_0() const + { + auto v = ((1U << 16) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR pmclut_r& set_PMC_LUT_0(uint32_t value) + { + word0 = (~(((1U << 16) - 1)<<16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// pmevcntr_r - Performance monitor event 0 count register +struct pmevcntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t count : 32; // Count word + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmevcntr_r() : + word0(0) + {} + CONSTEXPR pmevcntr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmevcntr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_count() const + { + auto v = word0; + return v; + } + CONSTEXPR pmevcntr_r& set_count(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pmevtyper_r - Performance monitor event type register 0 +struct pmevtyper_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EV_TYPE : 10; // Event Type + uint32_t reserved0 : 2; + uint32_t D0 : 1; // Counting disabled for AXI port 0 + uint32_t D1 : 1; // Counting disabled for AXI port 1 + uint32_t D2 : 1; // Counting disabled for AXI port 2 + uint32_t D3 : 1; // Counting disabled for AXI port 3 + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmevtyper_r() : + word0(0) + {} + CONSTEXPR pmevtyper_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmevtyper_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_EV_TYPE() const + { + auto v = ((1U << 10) - 1) & (word0 >> 0); + assert(v <= 671); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_EV_TYPE(NPU_NAMESPACE::pmu_event value) + { + word0 = (~(((1U << 10) - 1)<<0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D0(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D1(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 13); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D2(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 14); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D3(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 15); + return *this; + } +#endif +}; + +struct NPU_REG +{ + STRUCT id_r ID; // 0x0000 + STRUCT status_r STATUS; // 0x0004 + STRUCT cmd_r CMD; // 0x0008 + STRUCT reset_r RESET; // 0x000C + STRUCT qbase_r QBASE; // 0x0010 + STRUCT qread_r QREAD; // 0x0018 + STRUCT qconfig_r QCONFIG; // 0x001C + STRUCT qsize_r QSIZE; // 0x0020 + STRUCT prot_r PROT; // 0x0024 + STRUCT config_r CONFIG; // 0x0028 + uint32_t unused0[1]; + STRUCT cond_status_r COND_STATUS; // 0x0030 + uint32_t unused1[1]; + STRUCT power_ctrl_r POWER_CTRL; // 0x0038 + STRUCT regioncfg_r REGIONCFG; // 0x003C + STRUCT mem_attr_r MEM_ATTR[4]; // 0x0040 + STRUCT axi_sram_r AXI_SRAM; // 0x0050 + STRUCT axi_ext_r AXI_EXT; // 0x0054 + uint32_t unused2[2]; + STRUCT cfg_sram_cap_r CFG_SRAM_CAP; // 0x0060 + STRUCT cfg_ext_cap_r CFG_EXT_CAP; // 0x0064 + STRUCT cfg_sram_hash0_r CFG_SRAM_HASH0; // 0x0068 + STRUCT cfg_sram_hash1_r CFG_SRAM_HASH1; // 0x0070 + STRUCT cfg_ext_hash0_r CFG_EXT_HASH0; // 0x0078 + STRUCT basep_r BASEP[8]; // 0x0080 + uint32_t unused3[32]; + STRUCT clkforce_r CLKFORCE; // 0x0140 + STRUCT debug_address_r DEBUG_ADDRESS; // 0x0144 + STRUCT debug_misc_r DEBUG_MISC; // 0x0148 + uint32_t unused4[2]; + STRUCT feature_disable_r FEATURE_DISABLE; // 0x0154 + uint32_t unused5[58]; + STRUCT dma_ifm_src_r DMA_IFM_SRC; // 0x0240 + uint32_t unused6[2]; + STRUCT dma_ofm_dst_r DMA_OFM_DST; // 0x0250 + STRUCT dma_weight_src_r DMA_WEIGHT_SRC; // 0x0258 + STRUCT dma_cmd_src_r DMA_CMD_SRC; // 0x0260 + STRUCT dma_cmd_size_r DMA_CMD_SIZE; // 0x0268 + STRUCT dma_m2m_src_r DMA_M2M_SRC; // 0x026C + STRUCT dma_m2m_dst_r DMA_M2M_DST; // 0x0274 + STRUCT current_qread_r CURRENT_QREAD; // 0x027C + STRUCT dma_scale_src_r DMA_SCALE_SRC; // 0x0280 + STRUCT dma_weight1_src_r DMA_WEIGHT1_SRC; // 0x0288 + STRUCT dma_weight2_src_r DMA_WEIGHT2_SRC; // 0x0290 + STRUCT dma_weight3_src_r DMA_WEIGHT3_SRC; // 0x0298 + uint32_t unused7[6]; + STRUCT current_op_r CURRENT_OP; // 0x02B8 + STRUCT current_cmd_r CURRENT_CMD; // 0x02BC + uint32_t unused8[80]; + STRUCT internal_memory_r INTERNAL_MEMORY[256]; // 0x0400 + STRUCT ifm_pad_top_r IFM_PAD_TOP; // 0x0800 + STRUCT ifm_pad_left_r IFM_PAD_LEFT; // 0x0804 + STRUCT ifm_pad_right_r IFM_PAD_RIGHT; // 0x0808 + STRUCT ifm_pad_bottom_r IFM_PAD_BOTTOM; // 0x080C + STRUCT ifm_depth_m1_r IFM_DEPTH_M1; // 0x0810 + STRUCT ifm_precision_r IFM_PRECISION; // 0x0814 + uint32_t unused9[1]; + STRUCT ifm_upscale_r IFM_UPSCALE; // 0x081C + STRUCT ifm_broadcast_r IFM_BROADCAST; // 0x0820 + STRUCT ifm_zero_point_r IFM_ZERO_POINT; // 0x0824 + STRUCT ifm_width0_m1_r IFM_WIDTH0_M1; // 0x0828 + STRUCT ifm_height0_m1_r IFM_HEIGHT0_M1; // 0x082C + STRUCT ifm_height1_m1_r IFM_HEIGHT1_M1; // 0x0830 + uint32_t unused10[2]; + STRUCT ifm_region_r IFM_REGION; // 0x083C + uint32_t unused11[1]; + STRUCT ofm_width_m1_r OFM_WIDTH_M1; // 0x0844 + STRUCT ofm_height_m1_r OFM_HEIGHT_M1; // 0x0848 + STRUCT ofm_depth_m1_r OFM_DEPTH_M1; // 0x084C + STRUCT ofm_precision_r OFM_PRECISION; // 0x0850 + STRUCT ofm_blk_width_m1_r OFM_BLK_WIDTH_M1; // 0x0854 + STRUCT ofm_blk_height_m1_r OFM_BLK_HEIGHT_M1; // 0x0858 + STRUCT ofm_blk_depth_m1_r OFM_BLK_DEPTH_M1; // 0x085C + STRUCT ofm_zero_point_r OFM_ZERO_POINT; // 0x0860 + uint32_t unused12[1]; + STRUCT ofm_width0_m1_r OFM_WIDTH0_M1; // 0x0868 + STRUCT ofm_height0_m1_r OFM_HEIGHT0_M1; // 0x086C + STRUCT ofm_height1_m1_r OFM_HEIGHT1_M1; // 0x0870 + uint32_t unused13[2]; + STRUCT ofm_region_r OFM_REGION; // 0x087C + STRUCT kernel_width_m1_r KERNEL_WIDTH_M1; // 0x0880 + STRUCT kernel_height_m1_r KERNEL_HEIGHT_M1; // 0x0884 + STRUCT kernel_stride_r KERNEL_STRIDE; // 0x0888 + uint32_t unused14[1]; + STRUCT acc_format_r ACC_FORMAT; // 0x0890 + STRUCT activation_r ACTIVATION; // 0x0894 + STRUCT activation_min_r ACTIVATION_MIN; // 0x0898 + STRUCT activation_max_r ACTIVATION_MAX; // 0x089C + STRUCT weight_region_r WEIGHT_REGION; // 0x08A0 + STRUCT scale_region_r SCALE_REGION; // 0x08A4 + STRUCT resize_x_scale_n_m1_r RESIZE_X_SCALE_N_M1; // 0x08A8 + STRUCT resize_y_scale_n_m1_r RESIZE_Y_SCALE_N_M1; // 0x08AC + STRUCT resize_x_offset_r RESIZE_X_OFFSET; // 0x08B0 + STRUCT resize_y_offset_r RESIZE_Y_OFFSET; // 0x08B4 + STRUCT weight_format_r WEIGHT_FORMAT; // 0x08B8 + STRUCT blockdep_r BLOCKDEP; // 0x08BC + STRUCT dma0_src_region_r DMA0_SRC_REGION; // 0x08C0 + STRUCT dma0_dst_region_r DMA0_DST_REGION; // 0x08C4 + STRUCT dma0_size0_r DMA0_SIZE0; // 0x08C8 + STRUCT dma0_size1_r DMA0_SIZE1; // 0x08CC + STRUCT dma0_idx_region_r DMA0_IDX_REGION; // 0x08D0 + uint32_t unused15[11]; + STRUCT ifm2_broadcast_r IFM2_BROADCAST; // 0x0900 + uint32_t unused16[4]; + STRUCT ifm2_precision_r IFM2_PRECISION; // 0x0914 + uint32_t unused17[3]; + STRUCT ifm2_zero_point_r IFM2_ZERO_POINT; // 0x0924 + STRUCT ifm2_width0_m1_r IFM2_WIDTH0_M1; // 0x0928 + STRUCT ifm2_height0_m1_r IFM2_HEIGHT0_M1; // 0x092C + STRUCT ifm2_height1_m1_r IFM2_HEIGHT1_M1; // 0x0930 + uint32_t unused18[2]; + STRUCT ifm2_region_r IFM2_REGION; // 0x093C + uint32_t unused19[48]; + STRUCT ifm_base0_r IFM_BASE0; // 0x0A00 + STRUCT ifm_base1_r IFM_BASE1; // 0x0A08 + STRUCT ifm_base2_r IFM_BASE2; // 0x0A10 + STRUCT ifm_base3_r IFM_BASE3; // 0x0A18 + STRUCT ifm_stride_x_r IFM_STRIDE_X; // 0x0A20 + STRUCT ifm_stride_y_r IFM_STRIDE_Y; // 0x0A28 + STRUCT ifm_stride_c_r IFM_STRIDE_C; // 0x0A30 + uint32_t unused20[2]; + STRUCT ofm_base0_r OFM_BASE0; // 0x0A40 + STRUCT ofm_base1_r OFM_BASE1; // 0x0A48 + STRUCT ofm_base2_r OFM_BASE2; // 0x0A50 + STRUCT ofm_base3_r OFM_BASE3; // 0x0A58 + STRUCT ofm_stride_x_r OFM_STRIDE_X; // 0x0A60 + STRUCT ofm_stride_y_r OFM_STRIDE_Y; // 0x0A68 + STRUCT ofm_stride_c_r OFM_STRIDE_C; // 0x0A70 + uint32_t unused21[2]; + STRUCT weight_base_r WEIGHT_BASE; // 0x0A80 + STRUCT weight_length_r WEIGHT_LENGTH; // 0x0A88 + STRUCT scale_base_r SCALE_BASE; // 0x0A90 + STRUCT scale_length_r SCALE_LENGTH; // 0x0A98 + STRUCT ofm_scale_r OFM_SCALE; // 0x0AA0 + STRUCT ifm_scale_r IFM_SCALE; // 0x0AA8 + STRUCT ifm2_scale_r IFM2_SCALE; // 0x0AB0 + STRUCT op_scalar_r OP_SCALAR; // 0x0AB8 + STRUCT dma0_src_r DMA0_SRC; // 0x0AC0 + STRUCT dma0_dst_r DMA0_DST; // 0x0AC8 + STRUCT dma0_len_r DMA0_LEN; // 0x0AD0 + STRUCT dma0_src_stride0_r DMA0_SRC_STRIDE0; // 0x0AD8 + STRUCT dma0_src_stride1_r DMA0_SRC_STRIDE1; // 0x0AE0 + STRUCT dma0_dst_stride0_r DMA0_DST_STRIDE0; // 0x0AE8 + STRUCT dma0_dst_stride1_r DMA0_DST_STRIDE1; // 0x0AF0 + STRUCT dma0_idx_r DMA0_IDX; // 0x0AF8 + STRUCT ifm2_base0_r IFM2_BASE0; // 0x0B00 + STRUCT ifm2_base1_r IFM2_BASE1; // 0x0B08 + STRUCT ifm2_base2_r IFM2_BASE2; // 0x0B10 + STRUCT ifm2_base3_r IFM2_BASE3; // 0x0B18 + STRUCT ifm2_stride_x_r IFM2_STRIDE_X; // 0x0B20 + STRUCT ifm2_stride_y_r IFM2_STRIDE_Y; // 0x0B28 + STRUCT ifm2_stride_c_r IFM2_STRIDE_C; // 0x0B30 + uint32_t unused22[2]; + STRUCT weight1_base_r WEIGHT1_BASE; // 0x0B40 + STRUCT weight1_length_r WEIGHT1_LENGTH; // 0x0B48 + STRUCT weight2_base_r WEIGHT2_BASE; // 0x0B50 + STRUCT weight2_length_r WEIGHT2_LENGTH; // 0x0B58 + STRUCT weight3_base_r WEIGHT3_BASE; // 0x0B60 + STRUCT weight3_length_r WEIGHT3_LENGTH; // 0x0B68 + STRUCT resize_x_step_r RESIZE_X_STEP; // 0x0B70 + STRUCT resize_y_step_r RESIZE_Y_STEP; // 0x0B78 + uint32_t unused23[16]; + STRUCT dma0_idx_max_r DMA0_IDX_MAX; // 0x0BC0 + STRUCT dma0_idx_skip1_r DMA0_IDX_SKIP1; // 0x0BC8 + uint32_t unused24[252]; + STRUCT revision_r REVISION; // 0x0FC0 + uint32_t unused25[3]; + STRUCT pid4_r PID4; // 0x0FD0 + STRUCT pid5_r PID5; // 0x0FD4 + STRUCT pid6_r PID6; // 0x0FD8 + STRUCT pid7_r PID7; // 0x0FDC + STRUCT pid0_r PID0; // 0x0FE0 + STRUCT pid1_r PID1; // 0x0FE4 + STRUCT pid2_r PID2; // 0x0FE8 + STRUCT pid3_r PID3; // 0x0FEC + STRUCT cid0_r CID0; // 0x0FF0 + STRUCT cid1_r CID1; // 0x0FF4 + STRUCT cid2_r CID2; // 0x0FF8 + STRUCT cid3_r CID3; // 0x0FFC + uint32_t unused26[64]; + STRUCT wd_status_r WD_STATUS; // 0x1100 + STRUCT mac_status_r MAC_STATUS; // 0x1104 + STRUCT ao_status_r AO_STATUS; // 0x1108 + uint32_t unused27[1]; + STRUCT dma_status0_r DMA_STATUS0; // 0x1110 + STRUCT dma_status1_r DMA_STATUS1; // 0x1114 + uint32_t unused28[26]; + STRUCT pmcr_r PMCR; // 0x1180 + STRUCT pmcntenset_r PMCNTENSET; // 0x1184 + STRUCT pmcntenclr_r PMCNTENCLR; // 0x1188 + STRUCT pmovsset_r PMOVSSET; // 0x118C + STRUCT pmovsclr_r PMOVSCLR; // 0x1190 + STRUCT pmintset_r PMINTSET; // 0x1194 + STRUCT pmintclr_r PMINTCLR; // 0x1198 + uint32_t unused29[1]; + STRUCT pmccntr_r PMCCNTR; // 0x11A0 + STRUCT pmccntr_cfg_r PMCCNTR_CFG; // 0x11A8 + STRUCT pmcaxi_chan_r PMCAXI_CHAN; // 0x11AC + STRUCT pmclut_r PMCLUT; // 0x11B0 + uint32_t unused30[83]; + STRUCT pmevcntr_r PMEVCNTR[8]; // 0x1300 + uint32_t unused31[24]; + STRUCT pmevtyper_r PMEVTYPER[8]; // 0x1380 + +#ifdef __cplusplus + enum class access_type_t : uint8_t { RW, RO, WO }; + NPU_REG() + { + reset(); + } + void reset() + { + ID = 536899585; + STATUS = 8; + CMD = 12; + RESET = 0; + QBASE = 0; + QREAD = 0; + QCONFIG = 0; + QSIZE = 0; + PROT = 0; + CONFIG = 536870928; + COND_STATUS = 0; + POWER_CTRL = 0; + REGIONCFG = 0; + for (size_t i = 0; i < (sizeof(MEM_ATTR) / sizeof(MEM_ATTR[0])); ++i) + MEM_ATTR[i] = 0; + AXI_SRAM = 0; + AXI_EXT = 0; + CFG_SRAM_CAP = 0; + CFG_EXT_CAP = 0; + CFG_SRAM_HASH0 = 0; + CFG_SRAM_HASH1 = 0; + CFG_EXT_HASH0 = 0; + for (size_t i = 0; i < (sizeof(BASEP) / sizeof(BASEP[0])); ++i) + BASEP[i] = 0; + CLKFORCE = 0; + DEBUG_ADDRESS = 0; + DEBUG_MISC = 0; + FEATURE_DISABLE = 0; + DMA_IFM_SRC = 0; + DMA_OFM_DST = 0; + DMA_WEIGHT_SRC = 0; + DMA_CMD_SRC = 0; + DMA_CMD_SIZE = 0; + DMA_M2M_SRC = 0; + DMA_M2M_DST = 0; + CURRENT_QREAD = 0; + DMA_SCALE_SRC = 0; + DMA_WEIGHT1_SRC = 0; + DMA_WEIGHT2_SRC = 0; + DMA_WEIGHT3_SRC = 0; + CURRENT_OP = 0; + CURRENT_CMD = 0; + for (size_t i = 0; i < (sizeof(INTERNAL_MEMORY) / sizeof(INTERNAL_MEMORY[0])); ++i) + INTERNAL_MEMORY[i] = 0; + IFM_PAD_TOP = 0; + IFM_PAD_LEFT = 0; + IFM_PAD_RIGHT = 0; + IFM_PAD_BOTTOM = 0; + IFM_DEPTH_M1 = 0; + IFM_PRECISION = 0; + IFM_UPSCALE = 0; + IFM_BROADCAST = 0; + IFM_ZERO_POINT = 0; + IFM_WIDTH0_M1 = 0; + IFM_HEIGHT0_M1 = 0; + IFM_HEIGHT1_M1 = 0; + IFM_REGION = 0; + OFM_WIDTH_M1 = 0; + OFM_HEIGHT_M1 = 0; + OFM_DEPTH_M1 = 0; + OFM_PRECISION = 0; + OFM_BLK_WIDTH_M1 = 0; + OFM_BLK_HEIGHT_M1 = 0; + OFM_BLK_DEPTH_M1 = 0; + OFM_ZERO_POINT = 0; + OFM_WIDTH0_M1 = 0; + OFM_HEIGHT0_M1 = 0; + OFM_HEIGHT1_M1 = 0; + OFM_REGION = 0; + KERNEL_WIDTH_M1 = 0; + KERNEL_HEIGHT_M1 = 0; + KERNEL_STRIDE = 0; + ACC_FORMAT = 0; + ACTIVATION = 0; + ACTIVATION_MIN = 0; + ACTIVATION_MAX = 0; + WEIGHT_REGION = 0; + SCALE_REGION = 0; + RESIZE_X_SCALE_N_M1 = 0; + RESIZE_Y_SCALE_N_M1 = 0; + RESIZE_X_OFFSET = 0; + RESIZE_Y_OFFSET = 0; + WEIGHT_FORMAT = 0; + BLOCKDEP = 0; + DMA0_SRC_REGION = 0; + DMA0_DST_REGION = 0; + DMA0_SIZE0 = 0; + DMA0_SIZE1 = 0; + DMA0_IDX_REGION = 0; + IFM2_BROADCAST = 0; + IFM2_PRECISION = 0; + IFM2_ZERO_POINT = 0; + IFM2_WIDTH0_M1 = 0; + IFM2_HEIGHT0_M1 = 0; + IFM2_HEIGHT1_M1 = 0; + IFM2_REGION = 0; + IFM_BASE0 = 0; + IFM_BASE1 = 0; + IFM_BASE2 = 0; + IFM_BASE3 = 0; + IFM_STRIDE_X = 0; + IFM_STRIDE_Y = 0; + IFM_STRIDE_C = 0; + OFM_BASE0 = 0; + OFM_BASE1 = 0; + OFM_BASE2 = 0; + OFM_BASE3 = 0; + OFM_STRIDE_X = 0; + OFM_STRIDE_Y = 0; + OFM_STRIDE_C = 0; + WEIGHT_BASE = 0; + WEIGHT_LENGTH = 0; + SCALE_BASE = 0; + SCALE_LENGTH = 0; + OFM_SCALE = 0; + IFM_SCALE = 0; + IFM2_SCALE = 0; + OP_SCALAR = 0; + DMA0_SRC = 0; + DMA0_DST = 0; + DMA0_LEN = 0; + DMA0_SRC_STRIDE0 = 0; + DMA0_SRC_STRIDE1 = 0; + DMA0_DST_STRIDE0 = 0; + DMA0_DST_STRIDE1 = 0; + DMA0_IDX = 0; + IFM2_BASE0 = 0; + IFM2_BASE1 = 0; + IFM2_BASE2 = 0; + IFM2_BASE3 = 0; + IFM2_STRIDE_X = 0; + IFM2_STRIDE_Y = 0; + IFM2_STRIDE_C = 0; + WEIGHT1_BASE = 0; + WEIGHT1_LENGTH = 0; + WEIGHT2_BASE = 0; + WEIGHT2_LENGTH = 0; + WEIGHT3_BASE = 0; + WEIGHT3_LENGTH = 0; + RESIZE_X_STEP = 0; + RESIZE_Y_STEP = 0; + DMA0_IDX_MAX = 0; + DMA0_IDX_SKIP1 = 0; + REVISION = 0; + PID4 = 4; + PID5 = 0; + PID6 = 0; + PID7 = 0; + PID0 = 130; + PID1 = 181; + PID2 = 11; + PID3 = 0; + CID0 = 13; + CID1 = 240; + CID2 = 5; + CID3 = 177; + WD_STATUS = 0; + MAC_STATUS = 0; + AO_STATUS = 0; + DMA_STATUS0 = 0; + DMA_STATUS1 = 0; + PMCR = 16384; + PMCNTENSET = 0; + PMCNTENCLR = 0; + PMOVSSET = 0; + PMOVSCLR = 0; + PMINTSET = 0; + PMINTCLR = 0; + PMCCNTR = 0; + PMCCNTR_CFG = 0; + PMCAXI_CHAN = 0; + PMCLUT = 0; + for (size_t i = 0; i < (sizeof(PMEVCNTR) / sizeof(PMEVCNTR[0])); ++i) + PMEVCNTR[i] = 0; + for (size_t i = 0; i < (sizeof(PMEVTYPER) / sizeof(PMEVTYPER[0])); ++i) + PMEVTYPER[i] = 0; + } + uint32_t& operator[](const int addr_offset) + { + return reinterpret_cast(this)[addr_offset / 4]; + } + access_type_t get_access_type(uint32_t offset) + { + switch (offset) + { + case 0: return access_type_t::RO; + case 4: return access_type_t::RO; + case 8: return access_type_t::RW; + case 12: return access_type_t::RW; + case 16: return access_type_t::RW; + case 24: return access_type_t::RO; + case 28: return access_type_t::RW; + case 32: return access_type_t::RW; + case 36: return access_type_t::RO; + case 40: return access_type_t::RO; + case 48: return access_type_t::RO; + case 56: return access_type_t::RW; + case 60: return access_type_t::RW; + case 64: return access_type_t::RW; + case 68: return access_type_t::RW; + case 72: return access_type_t::RW; + case 76: return access_type_t::RW; + case 80: return access_type_t::RW; + case 84: return access_type_t::RW; + case 96: return access_type_t::RO; + case 100: return access_type_t::RO; + case 104: return access_type_t::RO; + case 112: return access_type_t::RO; + case 120: return access_type_t::RO; + case 128: return access_type_t::RW; + case 136: return access_type_t::RW; + case 144: return access_type_t::RW; + case 152: return access_type_t::RW; + case 160: return access_type_t::RW; + case 168: return access_type_t::RW; + case 176: return access_type_t::RW; + case 184: return access_type_t::RW; + case 320: return access_type_t::RW; + case 324: return access_type_t::RW; + case 328: return access_type_t::RW; + case 340: return access_type_t::RW; + case 576: return access_type_t::RO; + case 592: return access_type_t::RO; + case 600: return access_type_t::RO; + case 608: return access_type_t::RO; + case 616: return access_type_t::RO; + case 620: return access_type_t::RO; + case 628: return access_type_t::RO; + case 636: return access_type_t::RO; + case 640: return access_type_t::RO; + case 648: return access_type_t::RO; + case 656: return access_type_t::RO; + case 664: return access_type_t::RO; + case 696: return access_type_t::RO; + case 700: return access_type_t::RO; + case 1024: return access_type_t::RW; + case 1028: return access_type_t::RW; + case 1032: return access_type_t::RW; + case 1036: return access_type_t::RW; + case 1040: return access_type_t::RW; + case 1044: return access_type_t::RW; + case 1048: return access_type_t::RW; + case 1052: return access_type_t::RW; + case 1056: return access_type_t::RW; + case 1060: return access_type_t::RW; + case 1064: return access_type_t::RW; + case 1068: return access_type_t::RW; + case 1072: return access_type_t::RW; + case 1076: return access_type_t::RW; + case 1080: return access_type_t::RW; + case 1084: return access_type_t::RW; + case 1088: return access_type_t::RW; + case 1092: return access_type_t::RW; + case 1096: return access_type_t::RW; + case 1100: return access_type_t::RW; + case 1104: return access_type_t::RW; + case 1108: return access_type_t::RW; + case 1112: return access_type_t::RW; + case 1116: return access_type_t::RW; + case 1120: return access_type_t::RW; + case 1124: return access_type_t::RW; + case 1128: return access_type_t::RW; + case 1132: return access_type_t::RW; + case 1136: return access_type_t::RW; + case 1140: return access_type_t::RW; + case 1144: return access_type_t::RW; + case 1148: return access_type_t::RW; + case 1152: return access_type_t::RW; + case 1156: return access_type_t::RW; + case 1160: return access_type_t::RW; + case 1164: return access_type_t::RW; + case 1168: return access_type_t::RW; + case 1172: return access_type_t::RW; + case 1176: return access_type_t::RW; + case 1180: return access_type_t::RW; + case 1184: return access_type_t::RW; + case 1188: return access_type_t::RW; + case 1192: return access_type_t::RW; + case 1196: return access_type_t::RW; + case 1200: return access_type_t::RW; + case 1204: return access_type_t::RW; + case 1208: return access_type_t::RW; + case 1212: return access_type_t::RW; + case 1216: return access_type_t::RW; + case 1220: return access_type_t::RW; + case 1224: return access_type_t::RW; + case 1228: return access_type_t::RW; + case 1232: return access_type_t::RW; + case 1236: return access_type_t::RW; + case 1240: return access_type_t::RW; + case 1244: return access_type_t::RW; + case 1248: return access_type_t::RW; + case 1252: return access_type_t::RW; + case 1256: return access_type_t::RW; + case 1260: return access_type_t::RW; + case 1264: return access_type_t::RW; + case 1268: return access_type_t::RW; + case 1272: return access_type_t::RW; + case 1276: return access_type_t::RW; + case 1280: return access_type_t::RW; + case 1284: return access_type_t::RW; + case 1288: return access_type_t::RW; + case 1292: return access_type_t::RW; + case 1296: return access_type_t::RW; + case 1300: return access_type_t::RW; + case 1304: return access_type_t::RW; + case 1308: return access_type_t::RW; + case 1312: return access_type_t::RW; + case 1316: return access_type_t::RW; + case 1320: return access_type_t::RW; + case 1324: return access_type_t::RW; + case 1328: return access_type_t::RW; + case 1332: return access_type_t::RW; + case 1336: return access_type_t::RW; + case 1340: return access_type_t::RW; + case 1344: return access_type_t::RW; + case 1348: return access_type_t::RW; + case 1352: return access_type_t::RW; + case 1356: return access_type_t::RW; + case 1360: return access_type_t::RW; + case 1364: return access_type_t::RW; + case 1368: return access_type_t::RW; + case 1372: return access_type_t::RW; + case 1376: return access_type_t::RW; + case 1380: return access_type_t::RW; + case 1384: return access_type_t::RW; + case 1388: return access_type_t::RW; + case 1392: return access_type_t::RW; + case 1396: return access_type_t::RW; + case 1400: return access_type_t::RW; + case 1404: return access_type_t::RW; + case 1408: return access_type_t::RW; + case 1412: return access_type_t::RW; + case 1416: return access_type_t::RW; + case 1420: return access_type_t::RW; + case 1424: return access_type_t::RW; + case 1428: return access_type_t::RW; + case 1432: return access_type_t::RW; + case 1436: return access_type_t::RW; + case 1440: return access_type_t::RW; + case 1444: return access_type_t::RW; + case 1448: return access_type_t::RW; + case 1452: return access_type_t::RW; + case 1456: return access_type_t::RW; + case 1460: return access_type_t::RW; + case 1464: return access_type_t::RW; + case 1468: return access_type_t::RW; + case 1472: return access_type_t::RW; + case 1476: return access_type_t::RW; + case 1480: return access_type_t::RW; + case 1484: return access_type_t::RW; + case 1488: return access_type_t::RW; + case 1492: return access_type_t::RW; + case 1496: return access_type_t::RW; + case 1500: return access_type_t::RW; + case 1504: return access_type_t::RW; + case 1508: return access_type_t::RW; + case 1512: return access_type_t::RW; + case 1516: return access_type_t::RW; + case 1520: return access_type_t::RW; + case 1524: return access_type_t::RW; + case 1528: return access_type_t::RW; + case 1532: return access_type_t::RW; + case 1536: return access_type_t::RW; + case 1540: return access_type_t::RW; + case 1544: return access_type_t::RW; + case 1548: return access_type_t::RW; + case 1552: return access_type_t::RW; + case 1556: return access_type_t::RW; + case 1560: return access_type_t::RW; + case 1564: return access_type_t::RW; + case 1568: return access_type_t::RW; + case 1572: return access_type_t::RW; + case 1576: return access_type_t::RW; + case 1580: return access_type_t::RW; + case 1584: return access_type_t::RW; + case 1588: return access_type_t::RW; + case 1592: return access_type_t::RW; + case 1596: return access_type_t::RW; + case 1600: return access_type_t::RW; + case 1604: return access_type_t::RW; + case 1608: return access_type_t::RW; + case 1612: return access_type_t::RW; + case 1616: return access_type_t::RW; + case 1620: return access_type_t::RW; + case 1624: return access_type_t::RW; + case 1628: return access_type_t::RW; + case 1632: return access_type_t::RW; + case 1636: return access_type_t::RW; + case 1640: return access_type_t::RW; + case 1644: return access_type_t::RW; + case 1648: return access_type_t::RW; + case 1652: return access_type_t::RW; + case 1656: return access_type_t::RW; + case 1660: return access_type_t::RW; + case 1664: return access_type_t::RW; + case 1668: return access_type_t::RW; + case 1672: return access_type_t::RW; + case 1676: return access_type_t::RW; + case 1680: return access_type_t::RW; + case 1684: return access_type_t::RW; + case 1688: return access_type_t::RW; + case 1692: return access_type_t::RW; + case 1696: return access_type_t::RW; + case 1700: return access_type_t::RW; + case 1704: return access_type_t::RW; + case 1708: return access_type_t::RW; + case 1712: return access_type_t::RW; + case 1716: return access_type_t::RW; + case 1720: return access_type_t::RW; + case 1724: return access_type_t::RW; + case 1728: return access_type_t::RW; + case 1732: return access_type_t::RW; + case 1736: return access_type_t::RW; + case 1740: return access_type_t::RW; + case 1744: return access_type_t::RW; + case 1748: return access_type_t::RW; + case 1752: return access_type_t::RW; + case 1756: return access_type_t::RW; + case 1760: return access_type_t::RW; + case 1764: return access_type_t::RW; + case 1768: return access_type_t::RW; + case 1772: return access_type_t::RW; + case 1776: return access_type_t::RW; + case 1780: return access_type_t::RW; + case 1784: return access_type_t::RW; + case 1788: return access_type_t::RW; + case 1792: return access_type_t::RW; + case 1796: return access_type_t::RW; + case 1800: return access_type_t::RW; + case 1804: return access_type_t::RW; + case 1808: return access_type_t::RW; + case 1812: return access_type_t::RW; + case 1816: return access_type_t::RW; + case 1820: return access_type_t::RW; + case 1824: return access_type_t::RW; + case 1828: return access_type_t::RW; + case 1832: return access_type_t::RW; + case 1836: return access_type_t::RW; + case 1840: return access_type_t::RW; + case 1844: return access_type_t::RW; + case 1848: return access_type_t::RW; + case 1852: return access_type_t::RW; + case 1856: return access_type_t::RW; + case 1860: return access_type_t::RW; + case 1864: return access_type_t::RW; + case 1868: return access_type_t::RW; + case 1872: return access_type_t::RW; + case 1876: return access_type_t::RW; + case 1880: return access_type_t::RW; + case 1884: return access_type_t::RW; + case 1888: return access_type_t::RW; + case 1892: return access_type_t::RW; + case 1896: return access_type_t::RW; + case 1900: return access_type_t::RW; + case 1904: return access_type_t::RW; + case 1908: return access_type_t::RW; + case 1912: return access_type_t::RW; + case 1916: return access_type_t::RW; + case 1920: return access_type_t::RW; + case 1924: return access_type_t::RW; + case 1928: return access_type_t::RW; + case 1932: return access_type_t::RW; + case 1936: return access_type_t::RW; + case 1940: return access_type_t::RW; + case 1944: return access_type_t::RW; + case 1948: return access_type_t::RW; + case 1952: return access_type_t::RW; + case 1956: return access_type_t::RW; + case 1960: return access_type_t::RW; + case 1964: return access_type_t::RW; + case 1968: return access_type_t::RW; + case 1972: return access_type_t::RW; + case 1976: return access_type_t::RW; + case 1980: return access_type_t::RW; + case 1984: return access_type_t::RW; + case 1988: return access_type_t::RW; + case 1992: return access_type_t::RW; + case 1996: return access_type_t::RW; + case 2000: return access_type_t::RW; + case 2004: return access_type_t::RW; + case 2008: return access_type_t::RW; + case 2012: return access_type_t::RW; + case 2016: return access_type_t::RW; + case 2020: return access_type_t::RW; + case 2024: return access_type_t::RW; + case 2028: return access_type_t::RW; + case 2032: return access_type_t::RW; + case 2036: return access_type_t::RW; + case 2040: return access_type_t::RW; + case 2044: return access_type_t::RW; + case 2048: return access_type_t::RW; + case 2052: return access_type_t::RW; + case 2056: return access_type_t::RW; + case 2060: return access_type_t::RW; + case 2064: return access_type_t::RW; + case 2068: return access_type_t::RW; + case 2076: return access_type_t::RW; + case 2080: return access_type_t::RW; + case 2084: return access_type_t::RW; + case 2088: return access_type_t::RW; + case 2092: return access_type_t::RW; + case 2096: return access_type_t::RW; + case 2108: return access_type_t::RW; + case 2116: return access_type_t::RW; + case 2120: return access_type_t::RW; + case 2124: return access_type_t::RW; + case 2128: return access_type_t::RW; + case 2132: return access_type_t::RW; + case 2136: return access_type_t::RW; + case 2140: return access_type_t::RW; + case 2144: return access_type_t::RW; + case 2152: return access_type_t::RW; + case 2156: return access_type_t::RW; + case 2160: return access_type_t::RW; + case 2172: return access_type_t::RW; + case 2176: return access_type_t::RW; + case 2180: return access_type_t::RW; + case 2184: return access_type_t::RW; + case 2192: return access_type_t::RW; + case 2196: return access_type_t::RW; + case 2200: return access_type_t::RW; + case 2204: return access_type_t::RW; + case 2208: return access_type_t::RW; + case 2212: return access_type_t::RW; + case 2216: return access_type_t::RW; + case 2220: return access_type_t::RW; + case 2224: return access_type_t::RW; + case 2228: return access_type_t::RW; + case 2232: return access_type_t::RW; + case 2236: return access_type_t::RW; + case 2240: return access_type_t::RW; + case 2244: return access_type_t::RW; + case 2248: return access_type_t::RW; + case 2252: return access_type_t::RW; + case 2256: return access_type_t::RW; + case 2304: return access_type_t::RW; + case 2324: return access_type_t::RW; + case 2340: return access_type_t::RW; + case 2344: return access_type_t::RW; + case 2348: return access_type_t::RW; + case 2352: return access_type_t::RW; + case 2364: return access_type_t::RW; + case 2560: return access_type_t::RW; + case 2568: return access_type_t::RW; + case 2576: return access_type_t::RW; + case 2584: return access_type_t::RW; + case 2592: return access_type_t::RW; + case 2600: return access_type_t::RW; + case 2608: return access_type_t::RW; + case 2624: return access_type_t::RW; + case 2632: return access_type_t::RW; + case 2640: return access_type_t::RW; + case 2648: return access_type_t::RW; + case 2656: return access_type_t::RW; + case 2664: return access_type_t::RW; + case 2672: return access_type_t::RW; + case 2688: return access_type_t::RW; + case 2696: return access_type_t::RW; + case 2704: return access_type_t::RW; + case 2712: return access_type_t::RW; + case 2720: return access_type_t::RW; + case 2728: return access_type_t::RW; + case 2736: return access_type_t::RW; + case 2744: return access_type_t::RW; + case 2752: return access_type_t::RW; + case 2760: return access_type_t::RW; + case 2768: return access_type_t::RW; + case 2776: return access_type_t::RW; + case 2784: return access_type_t::RW; + case 2792: return access_type_t::RW; + case 2800: return access_type_t::RW; + case 2808: return access_type_t::RW; + case 2816: return access_type_t::RW; + case 2824: return access_type_t::RW; + case 2832: return access_type_t::RW; + case 2840: return access_type_t::RW; + case 2848: return access_type_t::RW; + case 2856: return access_type_t::RW; + case 2864: return access_type_t::RW; + case 2880: return access_type_t::RW; + case 2888: return access_type_t::RW; + case 2896: return access_type_t::RW; + case 2904: return access_type_t::RW; + case 2912: return access_type_t::RW; + case 2920: return access_type_t::RW; + case 2928: return access_type_t::RW; + case 2936: return access_type_t::RW; + case 3008: return access_type_t::RW; + case 3016: return access_type_t::RW; + case 4032: return access_type_t::RO; + case 4048: return access_type_t::RO; + case 4052: return access_type_t::RO; + case 4056: return access_type_t::RO; + case 4060: return access_type_t::RO; + case 4064: return access_type_t::RO; + case 4068: return access_type_t::RO; + case 4072: return access_type_t::RO; + case 4076: return access_type_t::RO; + case 4080: return access_type_t::RO; + case 4084: return access_type_t::RO; + case 4088: return access_type_t::RO; + case 4092: return access_type_t::RO; + case 4352: return access_type_t::RO; + case 4356: return access_type_t::RO; + case 4360: return access_type_t::RO; + case 4368: return access_type_t::RO; + case 4372: return access_type_t::RO; + case 4480: return access_type_t::RW; + case 4484: return access_type_t::RW; + case 4488: return access_type_t::RW; + case 4492: return access_type_t::RW; + case 4496: return access_type_t::RW; + case 4500: return access_type_t::RW; + case 4504: return access_type_t::RW; + case 4512: return access_type_t::RW; + case 4520: return access_type_t::RW; + case 4524: return access_type_t::RW; + case 4528: return access_type_t::RW; + case 4864: return access_type_t::RW; + case 4868: return access_type_t::RW; + case 4872: return access_type_t::RW; + case 4876: return access_type_t::RW; + case 4880: return access_type_t::RW; + case 4884: return access_type_t::RW; + case 4888: return access_type_t::RW; + case 4892: return access_type_t::RW; + case 4992: return access_type_t::RW; + case 4996: return access_type_t::RW; + case 5000: return access_type_t::RW; + case 5004: return access_type_t::RW; + case 5008: return access_type_t::RW; + case 5012: return access_type_t::RW; + case 5016: return access_type_t::RW; + case 5020: return access_type_t::RW; + default: return access_type_t::RO; + } + } +#endif +}; + +#ifdef __cplusplus +struct isa +{ +#ifdef NPU_DISASSEMBLE +static int disassemble(const uint32_t* in, std::string& op, std::vector>& fields) +{ + switch (*in & 0xffff) + { + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP): + { + const npu_op_stop_t& v = *reinterpret_cast(in); + op = "NPU_OP_STOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ): + { + const npu_op_irq_t& v = *reinterpret_cast(in); + op = "NPU_OP_IRQ"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV): + { + const npu_op_conv_t& v = *reinterpret_cast(in); + op = "NPU_OP_CONV"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE): + { + const npu_op_depthwise_t& v = *reinterpret_cast(in); + op = "NPU_OP_DEPTHWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL): + { + const npu_op_pool_t& v = *reinterpret_cast(in); + op = "NPU_OP_POOL"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE): + { + const npu_op_elementwise_t& v = *reinterpret_cast(in); + op = "NPU_OP_ELEMENTWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE): + { + const npu_op_resize_t& v = *reinterpret_cast(in); + op = "NPU_OP_RESIZE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START): + { + const npu_op_dma_start_t& v = *reinterpret_cast(in); + op = "NPU_OP_DMA_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT): + { + const npu_op_dma_wait_t& v = *reinterpret_cast(in); + op = "NPU_OP_DMA_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT): + { + const npu_op_kernel_wait_t& v = *reinterpret_cast(in); + op = "NPU_OP_KERNEL_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK): + { + const npu_op_pmu_mask_t& v = *reinterpret_cast(in); + op = "NPU_OP_PMU_MASK"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP): + { + const npu_set_ifm_pad_top_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_TOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT): + { + const npu_set_ifm_pad_left_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_LEFT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT): + { + const npu_set_ifm_pad_right_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_RIGHT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM): + { + const npu_set_ifm_pad_bottom_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_BOTTOM"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1): + { + const npu_set_ifm_depth_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION): + { + const npu_set_ifm_precision_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE): + { + const npu_set_ifm_upscale_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_UPSCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT): + { + const npu_set_ifm_zero_point_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1): + { + const npu_set_ifm_width0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1): + { + const npu_set_ifm_height0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1): + { + const npu_set_ifm_height1_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION): + { + const npu_set_ifm_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST): + { + const npu_set_ifm_broadcast_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1): + { + const npu_set_ofm_width_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1): + { + const npu_set_ofm_height_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1): + { + const npu_set_ofm_depth_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION): + { + const npu_set_ofm_precision_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1): + { + const npu_set_ofm_blk_width_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1): + { + const npu_set_ofm_blk_height_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1): + { + const npu_set_ofm_blk_depth_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT): + { + const npu_set_ofm_zero_point_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1): + { + const npu_set_ofm_width0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1): + { + const npu_set_ofm_height0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1): + { + const npu_set_ofm_height1_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION): + { + const npu_set_ofm_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1): + { + const npu_set_kernel_width_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1): + { + const npu_set_kernel_height_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE): + { + const npu_set_kernel_stride_t& v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_STRIDE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT): + { + const npu_set_acc_format_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACC_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION): + { + const npu_set_activation_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN): + { + const npu_set_activation_min_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MIN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX): + { + const npu_set_activation_max_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION): + { + const npu_set_weight_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION): + { + const npu_set_scale_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT): + { + const npu_set_weight_format_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP): + { + const npu_set_blockdep_t& v = *reinterpret_cast(in); + op = "NPU_SET_BLOCKDEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1): + { + const npu_set_resize_x_scale_n_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_X_SCALE_N_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1): + { + const npu_set_resize_y_scale_n_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_Y_SCALE_N_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET): + { + const npu_set_resize_x_offset_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_X_OFFSET"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET): + { + const npu_set_resize_y_offset_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_Y_OFFSET"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION): + { + const npu_set_dma0_src_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION): + { + const npu_set_dma0_dst_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0): + { + const npu_set_dma0_size0_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1): + { + const npu_set_dma0_size1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION): + { + const npu_set_dma0_idx_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST): + { + const npu_set_ifm2_broadcast_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION): + { + const npu_set_ifm2_precision_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT): + { + const npu_set_ifm2_zero_point_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1): + { + const npu_set_ifm2_width0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1): + { + const npu_set_ifm2_height0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1): + { + const npu_set_ifm2_height1_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION): + { + const npu_set_ifm2_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0): + { + const npu_set_ifm_base0_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1): + { + const npu_set_ifm_base1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2): + { + const npu_set_ifm_base2_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3): + { + const npu_set_ifm_base3_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X): + { + const npu_set_ifm_stride_x_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y): + { + const npu_set_ifm_stride_y_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C): + { + const npu_set_ifm_stride_c_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0): + { + const npu_set_ofm_base0_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1): + { + const npu_set_ofm_base1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2): + { + const npu_set_ofm_base2_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3): + { + const npu_set_ofm_base3_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X): + { + const npu_set_ofm_stride_x_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y): + { + const npu_set_ofm_stride_y_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C): + { + const npu_set_ofm_stride_c_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE): + { + const npu_set_weight_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH): + { + const npu_set_weight_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE): + { + const npu_set_scale_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH): + { + const npu_set_scale_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE): + { + const npu_set_ofm_scale_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE): + { + const npu_set_ifm_scale_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE): + { + const npu_set_ifm2_scale_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR): + { + const npu_set_op_scalar_t& v = *reinterpret_cast(in); + op = "NPU_SET_OP_SCALAR"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC): + { + const npu_set_dma0_src_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST): + { + const npu_set_dma0_dst_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN): + { + const npu_set_dma0_len_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_LEN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0): + { + const npu_set_dma0_src_stride0_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_STRIDE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1): + { + const npu_set_dma0_src_stride1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_STRIDE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0): + { + const npu_set_dma0_dst_stride0_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_STRIDE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1): + { + const npu_set_dma0_dst_stride1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_STRIDE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX): + { + const npu_set_dma0_idx_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX): + { + const npu_set_dma0_idx_max_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1): + { + const npu_set_dma0_idx_skip1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX_SKIP1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0): + { + const npu_set_ifm2_base0_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1): + { + const npu_set_ifm2_base1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2): + { + const npu_set_ifm2_base2_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3): + { + const npu_set_ifm2_base3_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X): + { + const npu_set_ifm2_stride_x_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y): + { + const npu_set_ifm2_stride_y_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C): + { + const npu_set_ifm2_stride_c_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE): + { + const npu_set_weight1_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH): + { + const npu_set_weight1_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE): + { + const npu_set_weight2_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT2_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH): + { + const npu_set_weight2_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT2_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE): + { + const npu_set_weight3_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT3_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH): + { + const npu_set_weight3_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT3_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X): + { + const npu_set_resize_x_step_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_X_STEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y): + { + const npu_set_resize_y_step_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_Y_STEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH): + { + const npu_op_branch_t& v = *reinterpret_cast(in); + op = "NPU_OP_BRANCH"; + v.disassemble(fields); + break; + } + default: break; + } + return (*in & (3<<14)) != 0 ? 2 : 1; +} +#endif +#endif +// Signal the end of command stream +struct npu_op_stop_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t mask:16; // Encoding for 16-bit mask value +#ifdef __cplusplus +public: + npu_op_stop_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(_mask & ((1U << 16)-1)) + {} + CONSTEXPR npu_op_stop_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(mask) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_stop_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_stop_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_stop_t& set_mask(uint32_t value) + { + assert((value >> 16) == 0); + mask = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif +}; +// Raises an IRQ to the host +struct npu_op_irq_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t mask:16; // Encoding for 16-bit mask value +#ifdef __cplusplus +public: + npu_op_irq_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(_mask & ((1U << 16)-1)) + {} + CONSTEXPR npu_op_irq_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(mask) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_irq_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_irq_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_irq_t& set_mask(uint32_t value) + { + assert((value >> 16) == 0); + mask = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif +}; +// 2D convolution +struct npu_op_conv_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t weights_ifm2:1; // Read weights from IFM2 rather than a static compressed stream + uint32_t reserved1:15; +#ifdef __cplusplus +public: + npu_op_conv_t(uint32_t _weights_ifm2) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weights_ifm2(_weights_ifm2 & ((1U << 1)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_conv_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weights_ifm2(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(weights_ifm2) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_conv_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_conv_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_weights_ifm2() const + { + return static_cast(weights_ifm2); + } + CONSTEXPR npu_op_conv_t& set_weights_ifm2(uint32_t value) + { + assert((value >> 1) == 0); + weights_ifm2 = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("weights_ifm2", std::to_string(weights_ifm2))); + } +#endif +#endif +}; +// Depth-wise 2D convolution +struct npu_op_depthwise_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; +#ifdef __cplusplus +public: + CONSTEXPR npu_op_depthwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_depthwise_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_depthwise_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>&) const + { + } +#endif +#endif +}; +// Pooling +struct npu_op_pool_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pooling_mode:3; // Pooling mode + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_op_pool_t(NPU_NAMESPACE::pooling_mode _pooling_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(static_cast(_pooling_mode) & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_pool_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pooling_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pool_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pool_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pooling_mode get_pooling_mode() const + { + return static_cast(pooling_mode); + } + CONSTEXPR npu_op_pool_t& set_pooling_mode(NPU_NAMESPACE::pooling_mode value) + { + pooling_mode = static_cast(value) & ((1U << 3)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pooling_mode", (pooling_mode < (sizeof(pooling_mode_str)/sizeof(pooling_mode_str[0])) ? pooling_mode_str[pooling_mode] : "****"))); + } +#endif +#endif +}; +// Elementwise operation +struct npu_op_elementwise_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t elementwise_mode:6; // Elementwise mode + uint32_t reserved1:10; +#ifdef __cplusplus +public: + npu_op_elementwise_t(NPU_NAMESPACE::elementwise_mode _elementwise_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(static_cast(_elementwise_mode) & ((1U << 6)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_elementwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(elementwise_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_elementwise_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_elementwise_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::elementwise_mode get_elementwise_mode() const + { + return static_cast(elementwise_mode); + } + CONSTEXPR npu_op_elementwise_t& set_elementwise_mode(NPU_NAMESPACE::elementwise_mode value) + { + elementwise_mode = static_cast(value) & ((1U << 6)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("elementwise_mode", (elementwise_mode < (sizeof(elementwise_mode_str)/sizeof(elementwise_mode_str[0])) ? elementwise_mode_str[elementwise_mode] : "****"))); + } +#endif +#endif +}; +// Resize operation +struct npu_op_resize_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_mode:2; // Resize mode + uint32_t reserved1:14; +#ifdef __cplusplus +public: + npu_op_resize_t(NPU_NAMESPACE::resize_mode _resize_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_mode(static_cast(_resize_mode) & ((1U << 2)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_resize_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_resize_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_resize_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::resize_mode get_resize_mode() const + { + return static_cast(resize_mode); + } + CONSTEXPR npu_op_resize_t& set_resize_mode(NPU_NAMESPACE::resize_mode value) + { + resize_mode = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_mode", (resize_mode < (sizeof(resize_mode_str)/sizeof(resize_mode_str[0])) ? resize_mode_str[resize_mode] : "****"))); + } +#endif +#endif +}; +// Queue new DMA for the given channel +struct npu_op_dma_start_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; +#ifdef __cplusplus +public: + CONSTEXPR npu_op_dma_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_start_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_start_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>&) const + { + } +#endif +#endif +}; +// Wait for the mem2mem DMA channel to have k or fewer active descriptors outstanding +struct npu_op_dma_wait_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t k:2; // Number of outstanding descriptors + uint32_t reserved1:14; +#ifdef __cplusplus +public: + npu_op_dma_wait_t(uint32_t _k) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + k(_k & ((1U << 2)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_dma_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + k(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(k) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_wait_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_wait_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_k() const + { + return static_cast(k); + } + CONSTEXPR npu_op_dma_wait_t& set_k(uint32_t value) + { + assert((value >> 2) == 0); + k = static_cast(value & ((1U << 2)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("k", std::to_string(k))); + } +#endif +#endif +}; +// Wait for kernel operations to complete +struct npu_op_kernel_wait_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t n:1; // Number of kernel operations + uint32_t reserved1:15; +#ifdef __cplusplus +public: + npu_op_kernel_wait_t(uint32_t _n) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + n(_n & ((1U << 1)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_kernel_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + n(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(n) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_kernel_wait_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_kernel_wait_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_n() const + { + return static_cast(n); + } + CONSTEXPR npu_op_kernel_wait_t& set_n(uint32_t value) + { + assert((value >> 1) == 0); + n = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("n", std::to_string(n))); + } +#endif +#endif +}; +// Enable or disable PMU counting (debug feature only) +struct npu_op_pmu_mask_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t enable:1; // Enable or disable PMU mask + uint32_t reserved1:15; +#ifdef __cplusplus +public: + npu_op_pmu_mask_t(uint32_t _enable) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + enable(_enable & ((1U << 1)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_pmu_mask_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + enable(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(enable) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pmu_mask_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pmu_mask_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_enable() const + { + return static_cast(enable); + } + CONSTEXPR npu_op_pmu_mask_t& set_enable(uint32_t value) + { + assert((value >> 1) == 0); + enable = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("enable", std::to_string(enable))); + } +#endif +#endif +}; +// IFM top pad +struct npu_set_ifm_pad_top_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:7; // IFM top pad + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ifm_pad_top_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_top_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_top_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_top_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_top_t& set_pad(uint32_t value) + { + assert((value >> 7) == 0); + pad = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// IFM left pad +struct npu_set_ifm_pad_left_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:7; // IFM left pad + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ifm_pad_left_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_left_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_left_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_left_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_left_t& set_pad(uint32_t value) + { + assert((value >> 7) == 0); + pad = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// IFM right pad +struct npu_set_ifm_pad_right_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:8; // IFM right pad. Max value is 128 + uint32_t reserved1:8; +#ifdef __cplusplus +public: + npu_set_ifm_pad_right_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 8)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_right_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_right_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_right_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_right_t& set_pad(uint32_t value) + { + assert((value >> 8) == 0); + pad = static_cast(value & ((1U << 8)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// IFM bottom pad +struct npu_set_ifm_pad_bottom_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:8; // IFM bottom pad. Max value is 128 + uint32_t reserved1:8; +#ifdef __cplusplus +public: + npu_set_ifm_pad_bottom_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 8)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_bottom_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_bottom_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_bottom_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_bottom_t& set_pad(uint32_t value) + { + assert((value >> 8) == 0); + pad = static_cast(value & ((1U << 8)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// Number of input channels for convolution +struct npu_set_ifm_depth_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t depth_m1:16; // Number of input channels for convolution +#ifdef __cplusplus +public: + npu_set_ifm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(_depth_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(depth_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_depth_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_depth_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ifm_depth_m1_t& set_depth_m1(uint32_t value) + { + assert((value >> 16) == 0); + depth_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif +}; +// IFM Precision +struct npu_set_ifm_precision_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_type:1; // IFM type + uint32_t reserved1:1; + uint32_t activation_precision:2; // IFM precision + uint32_t reserved2:2; + uint32_t activation_format:2; // IFM format + uint32_t reserved3:6; + uint32_t activation_storage:2; // IFM storage mode +#ifdef __cplusplus +public: + npu_set_ifm_precision_t(NPU_NAMESPACE::activation_type _activation_type, NPU_NAMESPACE::activation_precision _activation_precision, NPU_NAMESPACE::activation_format _activation_format, NPU_NAMESPACE::activation_storage _activation_storage) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1)-1)), + reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2)-1)), + reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2)-1)), + reserved3(0), + activation_storage(static_cast(_activation_storage) & ((1U << 2)-1)) + {} + CONSTEXPR npu_set_ifm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(0), + reserved1(0), + activation_precision(0), + reserved2(0), + activation_format(0), + reserved3(0), + activation_storage(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_type) << 16; + word |= uint32_t(activation_precision) << 18; + word |= uint32_t(activation_format) << 22; + word |= uint32_t(activation_storage) << 30; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_precision_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_precision_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_storage get_activation_storage() const + { + return static_cast(activation_storage); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_storage(NPU_NAMESPACE::activation_storage value) + { + activation_storage = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_type", (activation_type < (sizeof(activation_type_str)/sizeof(activation_type_str[0])) ? activation_type_str[activation_type] : "****"))); + fields.push_back(std::make_pair("activation_precision", (activation_precision < (sizeof(activation_precision_str)/sizeof(activation_precision_str[0])) ? activation_precision_str[activation_precision] : "****"))); + fields.push_back(std::make_pair("activation_format", (activation_format < (sizeof(activation_format_str)/sizeof(activation_format_str[0])) ? activation_format_str[activation_format] : "****"))); + fields.push_back(std::make_pair("activation_storage", (activation_storage < (sizeof(activation_storage_str)/sizeof(activation_storage_str[0])) ? activation_storage_str[activation_storage] : "****"))); + } +#endif +#endif +}; +// IFM upscale mode +struct npu_set_ifm_upscale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t mode:2; // IFM upscale mode + uint32_t reserved1:14; +#ifdef __cplusplus +public: + npu_set_ifm_upscale_t(NPU_NAMESPACE::ifm_upscale_mode _mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(static_cast(_mode) & ((1U << 2)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_upscale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_upscale_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_upscale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_upscale_mode get_mode() const + { + return static_cast(mode); + } + CONSTEXPR npu_set_ifm_upscale_t& set_mode(NPU_NAMESPACE::ifm_upscale_mode value) + { + mode = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("mode", (mode < (sizeof(ifm_upscale_mode_str)/sizeof(ifm_upscale_mode_str[0])) ? ifm_upscale_mode_str[mode] : "****"))); + } +#endif +#endif +}; +// IFM zero point +struct npu_set_ifm_zero_point_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t zero_point:16; // Zero point offset +#ifdef __cplusplus +public: + npu_set_ifm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(zero_point) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_zero_point_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_zero_point_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm_zero_point_t& set_zero_point(uint32_t value) + { + assert((value >> 16) == 0); + zero_point = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif +}; +// IFM Tile 0 and Tile 2 width +struct npu_set_ifm_width0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // IFM Tile 0 and tile 2 width +#ifdef __cplusplus +public: + npu_set_ifm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_width0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_width0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm_width0_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// IFM Tile 0 height +struct npu_set_ifm_height0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM Tile 0 height +#ifdef __cplusplus +public: + npu_set_ifm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height0_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// IFM Tile 1 height +struct npu_set_ifm_height1_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM Tile 1 height +#ifdef __cplusplus +public: + npu_set_ifm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height1_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height1_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height1_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Index n for IFM access +struct npu_set_ifm_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_ifm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// IFM broadcast configuration +struct npu_set_ifm_broadcast_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t broadcast_mode:4; // Broadcast mode for IFM + uint32_t reserved1:12; +#ifdef __cplusplus +public: + npu_set_ifm_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(static_cast(_broadcast_mode) & ((1U << 4)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(broadcast_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_broadcast_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_broadcast_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_mode() const + { + return static_cast(broadcast_mode); + } + CONSTEXPR npu_set_ifm_broadcast_t& set_broadcast_mode(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_mode = static_cast(value) & ((1U << 4)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("broadcast_mode", (broadcast_mode < (sizeof(broadcast_mode_str)/sizeof(broadcast_mode_str[0])) ? broadcast_mode_str[broadcast_mode] : "****"))); + } +#endif +#endif +}; +// Output feature map width +struct npu_set_ofm_width_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // Output feature map width +#ifdef __cplusplus +public: + npu_set_ofm_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// Output feature map height +struct npu_set_ofm_height_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // Output feature map height +#ifdef __cplusplus +public: + npu_set_ofm_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Output feature map depth +struct npu_set_ofm_depth_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t depth_m1:16; // Output feature map depth +#ifdef __cplusplus +public: + npu_set_ofm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(_depth_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(depth_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_depth_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_depth_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_depth_m1_t& set_depth_m1(uint32_t value) + { + assert((value >> 16) == 0); + depth_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif +}; +// OFM Precision +struct npu_set_ofm_precision_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_type:1; // OFM type + uint32_t activation_precision:2; // OFM precision + uint32_t reserved1:3; + uint32_t activation_format:2; // OFM format + uint32_t scale_mode:1; // OFM scale mode + uint32_t activation_reverse:2; // OFM reverse + uint32_t activation_transpose:3; // OFM transpose + uint32_t activation_storage:2; // OFM storage mode +#ifdef __cplusplus +public: + npu_set_ofm_precision_t(NPU_NAMESPACE::activation_type _activation_type, NPU_NAMESPACE::activation_precision _activation_precision, NPU_NAMESPACE::activation_format _activation_format, NPU_NAMESPACE::ofm_scale_mode _scale_mode, NPU_NAMESPACE::activation_reverse _activation_reverse, NPU_NAMESPACE::activation_transpose _activation_transpose, NPU_NAMESPACE::activation_storage _activation_storage) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1)-1)), + activation_precision(static_cast(_activation_precision) & ((1U << 2)-1)), + reserved1(0), + activation_format(static_cast(_activation_format) & ((1U << 2)-1)), + scale_mode(static_cast(_scale_mode) & ((1U << 1)-1)), + activation_reverse(static_cast(_activation_reverse) & ((1U << 2)-1)), + activation_transpose(static_cast(_activation_transpose) & ((1U << 3)-1)), + activation_storage(static_cast(_activation_storage) & ((1U << 2)-1)) + {} + CONSTEXPR npu_set_ofm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(0), + activation_precision(0), + reserved1(0), + activation_format(0), + scale_mode(0), + activation_reverse(0), + activation_transpose(0), + activation_storage(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_type) << 16; + word |= uint32_t(activation_precision) << 17; + word |= uint32_t(activation_format) << 22; + word |= uint32_t(scale_mode) << 24; + word |= uint32_t(activation_reverse) << 25; + word |= uint32_t(activation_transpose) << 27; + word |= uint32_t(activation_storage) << 30; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_precision_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_precision_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ofm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ofm_precision_t& set_scale_mode(NPU_NAMESPACE::ofm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_reverse get_activation_reverse() const + { + return static_cast(activation_reverse); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_reverse(NPU_NAMESPACE::activation_reverse value) + { + activation_reverse = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_transpose get_activation_transpose() const + { + return static_cast(activation_transpose); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_transpose(NPU_NAMESPACE::activation_transpose value) + { + activation_transpose = static_cast(value) & ((1U << 3)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_storage get_activation_storage() const + { + return static_cast(activation_storage); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_storage(NPU_NAMESPACE::activation_storage value) + { + activation_storage = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_type", (activation_type < (sizeof(activation_type_str)/sizeof(activation_type_str[0])) ? activation_type_str[activation_type] : "****"))); + fields.push_back(std::make_pair("activation_precision", (activation_precision < (sizeof(activation_precision_str)/sizeof(activation_precision_str[0])) ? activation_precision_str[activation_precision] : "****"))); + fields.push_back(std::make_pair("activation_format", (activation_format < (sizeof(activation_format_str)/sizeof(activation_format_str[0])) ? activation_format_str[activation_format] : "****"))); + fields.push_back(std::make_pair("scale_mode", (scale_mode < (sizeof(ofm_scale_mode_str)/sizeof(ofm_scale_mode_str[0])) ? ofm_scale_mode_str[scale_mode] : "****"))); + fields.push_back(std::make_pair("activation_reverse", (activation_reverse < (sizeof(activation_reverse_str)/sizeof(activation_reverse_str[0])) ? activation_reverse_str[activation_reverse] : "****"))); + fields.push_back(std::make_pair("activation_transpose", (activation_transpose < (sizeof(activation_transpose_str)/sizeof(activation_transpose_str[0])) ? activation_transpose_str[activation_transpose] : "****"))); + fields.push_back(std::make_pair("activation_storage", (activation_storage < (sizeof(activation_storage_str)/sizeof(activation_storage_str[0])) ? activation_storage_str[activation_storage] : "****"))); + } +#endif +#endif +}; +// OFM block width +struct npu_set_ofm_blk_width_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:7; // OFM block width + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ofm_blk_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_blk_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 7) == 0); + width_m1 = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// OFM block height +struct npu_set_ofm_blk_height_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:7; // OFM block height + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ofm_blk_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_blk_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 7) == 0); + height_m1 = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// OFM block depth +struct npu_set_ofm_blk_depth_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t depth_m1:10; // OFM block depth + uint32_t reserved1:6; +#ifdef __cplusplus +public: + npu_set_ofm_blk_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(_depth_m1 & ((1U << 10)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_blk_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(depth_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t& set_depth_m1(uint32_t value) + { + assert((value >> 10) == 0); + depth_m1 = static_cast(value & ((1U << 10)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif +}; +// OFM zero point +struct npu_set_ofm_zero_point_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t zero_point:16; // Zero point offset +#ifdef __cplusplus +public: + npu_set_ofm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(zero_point) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_zero_point_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_zero_point_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ofm_zero_point_t& set_zero_point(uint32_t value) + { + assert((value >> 16) == 0); + zero_point = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif +}; +// OFM Tile 0 and tile 2 width +struct npu_set_ofm_width0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // OFM Tile 0 and tile 2 width +#ifdef __cplusplus +public: + npu_set_ofm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width0_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// OFM Tile 0 height +struct npu_set_ofm_height0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // OFM Tile 0 height +#ifdef __cplusplus +public: + npu_set_ofm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height0_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// OFM Tile 1 height +struct npu_set_ofm_height1_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // OFM Tile 1 height +#ifdef __cplusplus +public: + npu_set_ofm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height1_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height1_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height1_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Index n for OFM access +struct npu_set_ofm_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_ofm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ofm_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// Kernel width +struct npu_set_kernel_width_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // Kernel width +#ifdef __cplusplus +public: + npu_set_kernel_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_kernel_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_width_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_width_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_kernel_width_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// Kernel height +struct npu_set_kernel_height_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // Kernel height +#ifdef __cplusplus +public: + npu_set_kernel_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_kernel_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_height_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_height_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_kernel_height_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Kernel stride +struct npu_set_kernel_stride_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t stride_x_lsb:1; // Stride x LSB. (kernel_x_stride - 1)[0] + uint32_t stride_y_lsb:1; // Stride y LSB. (kernel_y_stride - 1)[0] + uint32_t weight_order:1; // Weight ordering mode + uint32_t dilation_x:1; // Kernel x dilation + uint32_t dilation_y:1; // Kernel y dilation + uint32_t decomposition:1; // Kernel decomposition + uint32_t stride_x_msb:1; // Stride x MSB. (kernel_x_stride - 1) >> 1 + uint32_t reserved1:2; + uint32_t stride_y_msb:1; // Stride y MSB. (kernel_y_stride - 1) >> 1 + uint32_t reserved2:6; +#ifdef __cplusplus +public: + npu_set_kernel_stride_t(uint32_t _stride_x_lsb, uint32_t _stride_y_lsb, NPU_NAMESPACE::weight_order _weight_order, NPU_NAMESPACE::kernel_dilation _dilation_x, NPU_NAMESPACE::kernel_dilation _dilation_y, NPU_NAMESPACE::kernel_decomposition _decomposition, uint32_t _stride_x_msb, uint32_t _stride_y_msb) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(_stride_x_lsb & ((1U << 1)-1)), + stride_y_lsb(_stride_y_lsb & ((1U << 1)-1)), + weight_order(static_cast(_weight_order) & ((1U << 1)-1)), + dilation_x(static_cast(_dilation_x) & ((1U << 1)-1)), + dilation_y(static_cast(_dilation_y) & ((1U << 1)-1)), + decomposition(static_cast(_decomposition) & ((1U << 1)-1)), + stride_x_msb(_stride_x_msb & ((1U << 1)-1)), + reserved1(0), + stride_y_msb(_stride_y_msb & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_kernel_stride_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(0), + stride_y_lsb(0), + weight_order(0), + dilation_x(0), + dilation_y(0), + decomposition(0), + stride_x_msb(0), + reserved1(0), + stride_y_msb(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(stride_x_lsb) << 16; + word |= uint32_t(stride_y_lsb) << 17; + word |= uint32_t(weight_order) << 18; + word |= uint32_t(dilation_x) << 19; + word |= uint32_t(dilation_y) << 20; + word |= uint32_t(decomposition) << 21; + word |= uint32_t(stride_x_msb) << 22; + word |= uint32_t(stride_y_msb) << 25; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_stride_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_stride_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_lsb() const + { + return static_cast(stride_x_lsb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_x_lsb(uint32_t value) + { + assert((value >> 1) == 0); + stride_x_lsb = static_cast(value & ((1U << 1)-1)); + return *this; + } + CONSTEXPR uint32_t get_stride_y_lsb() const + { + return static_cast(stride_y_lsb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_y_lsb(uint32_t value) + { + assert((value >> 1) == 0); + stride_y_lsb = static_cast(value & ((1U << 1)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_order get_weight_order() const + { + return static_cast(weight_order); + } + CONSTEXPR npu_set_kernel_stride_t& set_weight_order(NPU_NAMESPACE::weight_order value) + { + weight_order = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_x() const + { + return static_cast(dilation_x); + } + CONSTEXPR npu_set_kernel_stride_t& set_dilation_x(NPU_NAMESPACE::kernel_dilation value) + { + dilation_x = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_y() const + { + return static_cast(dilation_y); + } + CONSTEXPR npu_set_kernel_stride_t& set_dilation_y(NPU_NAMESPACE::kernel_dilation value) + { + dilation_y = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_decomposition get_decomposition() const + { + return static_cast(decomposition); + } + CONSTEXPR npu_set_kernel_stride_t& set_decomposition(NPU_NAMESPACE::kernel_decomposition value) + { + decomposition = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_msb() const + { + return static_cast(stride_x_msb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_x_msb(uint32_t value) + { + assert((value >> 1) == 0); + stride_x_msb = static_cast(value & ((1U << 1)-1)); + return *this; + } + CONSTEXPR uint32_t get_stride_y_msb() const + { + return static_cast(stride_y_msb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_y_msb(uint32_t value) + { + assert((value >> 1) == 0); + stride_y_msb = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("stride_x_lsb", std::to_string(stride_x_lsb))); + fields.push_back(std::make_pair("stride_y_lsb", std::to_string(stride_y_lsb))); + fields.push_back(std::make_pair("weight_order", (weight_order < (sizeof(weight_order_str)/sizeof(weight_order_str[0])) ? weight_order_str[weight_order] : "****"))); + fields.push_back(std::make_pair("dilation_x", (dilation_x < (sizeof(kernel_dilation_str)/sizeof(kernel_dilation_str[0])) ? kernel_dilation_str[dilation_x] : "****"))); + fields.push_back(std::make_pair("dilation_y", (dilation_y < (sizeof(kernel_dilation_str)/sizeof(kernel_dilation_str[0])) ? kernel_dilation_str[dilation_y] : "****"))); + fields.push_back(std::make_pair("decomposition", (decomposition < (sizeof(kernel_decomposition_str)/sizeof(kernel_decomposition_str[0])) ? kernel_decomposition_str[decomposition] : "****"))); + fields.push_back(std::make_pair("stride_x_msb", std::to_string(stride_x_msb))); + fields.push_back(std::make_pair("stride_y_msb", std::to_string(stride_y_msb))); + } +#endif +#endif +}; +// Accumulator format +struct npu_set_acc_format_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t acc_format:2; // Accumulator format + uint32_t reserved1:2; + uint32_t acc_input:2; // Accumulator input + uint32_t acc_output:1; // Accumulator output + uint32_t reserved2:1; + uint32_t microblock:3; // Accumulator microblock size + uint32_t reserved3:5; +#ifdef __cplusplus +public: + npu_set_acc_format_t(NPU_NAMESPACE::acc_format _acc_format, NPU_NAMESPACE::acc_input _acc_input, NPU_NAMESPACE::acc_output _acc_output, NPU_NAMESPACE::microblock _microblock) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(static_cast(_acc_format) & ((1U << 2)-1)), + reserved1(0), + acc_input(static_cast(_acc_input) & ((1U << 2)-1)), + acc_output(static_cast(_acc_output) & ((1U << 1)-1)), + reserved2(0), + microblock(static_cast(_microblock) & ((1U << 3)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_acc_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(0), + reserved1(0), + acc_input(0), + acc_output(0), + reserved2(0), + microblock(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(acc_format) << 16; + word |= uint32_t(acc_input) << 20; + word |= uint32_t(acc_output) << 22; + word |= uint32_t(microblock) << 24; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_acc_format_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_acc_format_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_format get_acc_format() const + { + return static_cast(acc_format); + } + CONSTEXPR npu_set_acc_format_t& set_acc_format(NPU_NAMESPACE::acc_format value) + { + acc_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_input get_acc_input() const + { + return static_cast(acc_input); + } + CONSTEXPR npu_set_acc_format_t& set_acc_input(NPU_NAMESPACE::acc_input value) + { + acc_input = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_output get_acc_output() const + { + return static_cast(acc_output); + } + CONSTEXPR npu_set_acc_format_t& set_acc_output(NPU_NAMESPACE::acc_output value) + { + acc_output = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::microblock get_microblock() const + { + return static_cast(microblock); + } + CONSTEXPR npu_set_acc_format_t& set_microblock(NPU_NAMESPACE::microblock value) + { + microblock = static_cast(value) & ((1U << 3)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("acc_format", (acc_format < (sizeof(acc_format_str)/sizeof(acc_format_str[0])) ? acc_format_str[acc_format] : "****"))); + fields.push_back(std::make_pair("acc_input", (acc_input < (sizeof(acc_input_str)/sizeof(acc_input_str[0])) ? acc_input_str[acc_input] : "****"))); + fields.push_back(std::make_pair("acc_output", (acc_output < (sizeof(acc_output_str)/sizeof(acc_output_str[0])) ? acc_output_str[acc_output] : "****"))); + fields.push_back(std::make_pair("microblock", (microblock < (sizeof(microblock_str)/sizeof(microblock_str[0])) ? microblock_str[microblock] : "****"))); + } +#endif +#endif +}; +// Activation function and clip range +struct npu_set_activation_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_function:5; // Activation function to apply + uint32_t table:3; // Table number to use for LUT + uint32_t reserved1:4; + uint32_t activation_clip_range:1; // Activation clip to apply + uint32_t reserved2:3; +#ifdef __cplusplus +public: + npu_set_activation_t(NPU_NAMESPACE::activation_function _activation_function, uint32_t _table, NPU_NAMESPACE::activation_clip_range _activation_clip_range) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(static_cast(_activation_function) & ((1U << 5)-1)), + table(_table & ((1U << 3)-1)), + reserved1(0), + activation_clip_range(static_cast(_activation_clip_range) & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_activation_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(0), + table(0), + reserved1(0), + activation_clip_range(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_function) << 16; + word |= uint32_t(table) << 21; + word |= uint32_t(activation_clip_range) << 28; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_function get_activation_function() const + { + return static_cast(activation_function); + } + CONSTEXPR npu_set_activation_t& set_activation_function(NPU_NAMESPACE::activation_function value) + { + activation_function = static_cast(value) & ((1U << 5)-1); + return *this; + } + CONSTEXPR uint32_t get_table() const + { + return static_cast(table); + } + CONSTEXPR npu_set_activation_t& set_table(uint32_t value) + { + assert((value >> 3) == 0); + table = static_cast(value & ((1U << 3)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_clip_range get_activation_clip_range() const + { + return static_cast(activation_clip_range); + } + CONSTEXPR npu_set_activation_t& set_activation_clip_range(NPU_NAMESPACE::activation_clip_range value) + { + activation_clip_range = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_function", (activation_function < (sizeof(activation_function_str)/sizeof(activation_function_str[0])) ? activation_function_str[activation_function] : "****"))); + fields.push_back(std::make_pair("table", std::to_string(table))); + fields.push_back(std::make_pair("activation_clip_range", (activation_clip_range < (sizeof(activation_clip_range_str)/sizeof(activation_clip_range_str[0])) ? activation_clip_range_str[activation_clip_range] : "****"))); + } +#endif +#endif +}; +// Lower bound clip +struct npu_set_activation_min_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t clip_boundary:16; // Clip boundary for OFM activations +#ifdef __cplusplus +public: + npu_set_activation_min_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_activation_min_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(clip_boundary) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_min_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_min_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_min_t& set_clip_boundary(uint32_t value) + { + assert((value >> 16) == 0); + clip_boundary = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif +}; +// Upper bound clip +struct npu_set_activation_max_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t clip_boundary:16; // Clip boundary for OFM activations +#ifdef __cplusplus +public: + npu_set_activation_max_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_activation_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(clip_boundary) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_max_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_max_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_max_t& set_clip_boundary(uint32_t value) + { + assert((value >> 16) == 0); + clip_boundary = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif +}; +// Index n for weight stream access +struct npu_set_weight_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Index n for weight stream access + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_weight_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_weight_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_weight_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// Index n for scale stream access +struct npu_set_scale_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Index n for scale stream access + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_scale_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_scale_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_scale_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// Set weight stream format +struct npu_set_weight_format_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t weight_format:1; // Weight stream format + uint32_t reserved1:3; + uint32_t weight_sparsity:1; // Weight sparsity type + uint32_t reserved2:11; +#ifdef __cplusplus +public: + npu_set_weight_format_t(NPU_NAMESPACE::weight_format _weight_format, NPU_NAMESPACE::weight_sparsity _weight_sparsity) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weight_format(static_cast(_weight_format) & ((1U << 1)-1)), + reserved1(0), + weight_sparsity(static_cast(_weight_sparsity) & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_weight_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weight_format(0), + reserved1(0), + weight_sparsity(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(weight_format) << 16; + word |= uint32_t(weight_sparsity) << 20; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_format_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_format_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_format get_weight_format() const + { + return static_cast(weight_format); + } + CONSTEXPR npu_set_weight_format_t& set_weight_format(NPU_NAMESPACE::weight_format value) + { + weight_format = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_sparsity get_weight_sparsity() const + { + return static_cast(weight_sparsity); + } + CONSTEXPR npu_set_weight_format_t& set_weight_sparsity(NPU_NAMESPACE::weight_sparsity value) + { + weight_sparsity = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("weight_format", (weight_format < (sizeof(weight_format_str)/sizeof(weight_format_str[0])) ? weight_format_str[weight_format] : "****"))); + fields.push_back(std::make_pair("weight_sparsity", (weight_sparsity < (sizeof(weight_sparsity_str)/sizeof(weight_sparsity_str[0])) ? weight_sparsity_str[weight_sparsity] : "****"))); + } +#endif +#endif +}; +// Block number of blocks dependency +struct npu_set_blockdep_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t blockdep:3; // Block number of blocks dependency between kernel operations + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_blockdep_t(uint32_t _blockdep) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + blockdep(_blockdep & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_blockdep_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + blockdep(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(blockdep) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_blockdep_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_blockdep_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_blockdep() const + { + return static_cast(blockdep); + } + CONSTEXPR npu_set_blockdep_t& set_blockdep(uint32_t value) + { + assert((value >> 3) == 0); + blockdep = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("blockdep", std::to_string(blockdep))); + } +#endif +#endif +}; +// Set resize scale X numerator +struct npu_set_resize_x_scale_n_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_x_scale_n_m1:11; // Resize X scale numerator + uint32_t reserved1:5; +#ifdef __cplusplus +public: + npu_set_resize_x_scale_n_m1_t(uint32_t _resize_x_scale_n_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_scale_n_m1(_resize_x_scale_n_m1 & ((1U << 11)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_x_scale_n_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_scale_n_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_x_scale_n_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_x_scale_n_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_x_scale_n_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_x_scale_n_m1() const + { + return static_cast(resize_x_scale_n_m1); + } + CONSTEXPR npu_set_resize_x_scale_n_m1_t& set_resize_x_scale_n_m1(uint32_t value) + { + assert((value >> 11) == 0); + resize_x_scale_n_m1 = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_x_scale_n_m1", std::to_string(resize_x_scale_n_m1))); + } +#endif +#endif +}; +// Set resize scale Y numerator +struct npu_set_resize_y_scale_n_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_y_scale_n_m1:11; // Resize Y scale numerator + uint32_t reserved1:5; +#ifdef __cplusplus +public: + npu_set_resize_y_scale_n_m1_t(uint32_t _resize_y_scale_n_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_scale_n_m1(_resize_y_scale_n_m1 & ((1U << 11)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_y_scale_n_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_scale_n_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_y_scale_n_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_y_scale_n_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_y_scale_n_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_y_scale_n_m1() const + { + return static_cast(resize_y_scale_n_m1); + } + CONSTEXPR npu_set_resize_y_scale_n_m1_t& set_resize_y_scale_n_m1(uint32_t value) + { + assert((value >> 11) == 0); + resize_y_scale_n_m1 = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_y_scale_n_m1", std::to_string(resize_y_scale_n_m1))); + } +#endif +#endif +}; +// Set resize offset X +struct npu_set_resize_x_offset_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_x_offset:12; // Resize X offset + uint32_t reserved1:4; +#ifdef __cplusplus +public: + npu_set_resize_x_offset_t(uint32_t _resize_x_offset) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_offset(_resize_x_offset & ((1U << 12)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_x_offset_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_offset(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_x_offset) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_x_offset_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_x_offset_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_x_offset() const + { + return static_cast(resize_x_offset); + } + CONSTEXPR npu_set_resize_x_offset_t& set_resize_x_offset(uint32_t value) + { + assert((value >> 12) == 0); + resize_x_offset = static_cast(value & ((1U << 12)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_x_offset", std::to_string(((resize_x_offset <= std::numeric_limits::max() ? static_cast(resize_x_offset) : resize_x_offset - std::numeric_limits::min() + std::numeric_limits::max()) << 20) >> 20))); + } +#endif +#endif +}; +// Set resize offset Y +struct npu_set_resize_y_offset_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_y_offset:12; // Resize Y offset + uint32_t reserved1:4; +#ifdef __cplusplus +public: + npu_set_resize_y_offset_t(uint32_t _resize_y_offset) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_offset(_resize_y_offset & ((1U << 12)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_y_offset_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_offset(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_y_offset) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_y_offset_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_y_offset_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_y_offset() const + { + return static_cast(resize_y_offset); + } + CONSTEXPR npu_set_resize_y_offset_t& set_resize_y_offset(uint32_t value) + { + assert((value >> 12) == 0); + resize_y_offset = static_cast(value & ((1U << 12)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_y_offset", std::to_string(((resize_y_offset <= std::numeric_limits::max() ? static_cast(resize_y_offset) : resize_y_offset - std::numeric_limits::min() + std::numeric_limits::max()) << 20) >> 20))); + } +#endif +#endif +}; +// DMA0 source region +struct npu_set_dma0_src_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:5; + uint32_t region_mode:1; // Region mode + uint32_t stride_mode:2; // Stride mode + uint32_t idx_mode:1; // Index mode for gather or scatter + uint32_t reserved2:4; +#ifdef __cplusplus +public: + npu_set_dma0_src_region_t(uint32_t _region, NPU_NAMESPACE::dma_region_mode _region_mode, NPU_NAMESPACE::dma_stride_mode _stride_mode, NPU_NAMESPACE::dma_idx_mode _idx_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1)-1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2)-1)), + idx_mode(static_cast(_idx_mode) & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_dma0_src_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0), + region_mode(0), + stride_mode(0), + idx_mode(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + word |= uint32_t(region_mode) << 24; + word |= uint32_t(stride_mode) << 25; + word |= uint32_t(idx_mode) << 27; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_src_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_idx_mode get_idx_mode() const + { + return static_cast(idx_mode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_idx_mode(NPU_NAMESPACE::dma_idx_mode value) + { + idx_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair("region_mode", (region_mode < (sizeof(dma_region_mode_str)/sizeof(dma_region_mode_str[0])) ? dma_region_mode_str[region_mode] : "****"))); + fields.push_back(std::make_pair("stride_mode", (stride_mode < (sizeof(dma_stride_mode_str)/sizeof(dma_stride_mode_str[0])) ? dma_stride_mode_str[stride_mode] : "****"))); + fields.push_back(std::make_pair("idx_mode", (idx_mode < (sizeof(dma_idx_mode_str)/sizeof(dma_idx_mode_str[0])) ? dma_idx_mode_str[idx_mode] : "****"))); + } +#endif +#endif +}; +// DMA0 destination region +struct npu_set_dma0_dst_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for memory accesses + uint32_t reserved1:5; + uint32_t region_mode:1; // Region mode + uint32_t reserved2:2; + uint32_t idx_mode:1; // Index mode for gather or scatter + uint32_t reserved3:4; +#ifdef __cplusplus +public: + npu_set_dma0_dst_region_t(uint32_t _region, NPU_NAMESPACE::dma_region_mode _region_mode, NPU_NAMESPACE::dma_idx_mode _idx_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1)-1)), + reserved2(0), + idx_mode(static_cast(_idx_mode) & ((1U << 1)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_dma0_dst_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0), + region_mode(0), + reserved2(0), + idx_mode(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + word |= uint32_t(region_mode) << 24; + word |= uint32_t(idx_mode) << 27; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_idx_mode get_idx_mode() const + { + return static_cast(idx_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_idx_mode(NPU_NAMESPACE::dma_idx_mode value) + { + idx_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair("region_mode", (region_mode < (sizeof(dma_region_mode_str)/sizeof(dma_region_mode_str[0])) ? dma_region_mode_str[region_mode] : "****"))); + fields.push_back(std::make_pair("idx_mode", (idx_mode < (sizeof(dma_idx_mode_str)/sizeof(dma_idx_mode_str[0])) ? dma_idx_mode_str[idx_mode] : "****"))); + } +#endif +#endif +}; +// Size of second dimension for 2D/3D transfers +struct npu_set_dma0_size0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t size:16; // Size of second dimension for 2D/3D transfers +#ifdef __cplusplus +public: + npu_set_dma0_size0_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(_size & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_dma0_size0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(size) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size0_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size0_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size0_t& set_size(uint32_t value) + { + assert((value >> 16) == 0); + size = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif +}; +// Size of third dimension for 3D transfers +struct npu_set_dma0_size1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t size:16; // Size of third dimension for 3D transfers +#ifdef __cplusplus +public: + npu_set_dma0_size1_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(_size & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_dma0_size1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(size) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size1_t& set_size(uint32_t value) + { + assert((value >> 16) == 0); + size = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif +}; +// DMA0 index region +struct npu_set_dma0_idx_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_dma0_idx_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_dma0_idx_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_idx_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_idx_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_idx_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// IFM2 broadcast configuration +struct npu_set_ifm2_broadcast_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t broadcast_mode:4; // Broadcast mode for IFM2 + uint32_t reserved1:12; +#ifdef __cplusplus +public: + npu_set_ifm2_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(static_cast(_broadcast_mode) & ((1U << 4)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm2_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(broadcast_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_broadcast_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_broadcast_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_mode() const + { + return static_cast(broadcast_mode); + } + CONSTEXPR npu_set_ifm2_broadcast_t& set_broadcast_mode(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_mode = static_cast(value) & ((1U << 4)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("broadcast_mode", (broadcast_mode < (sizeof(broadcast_mode_str)/sizeof(broadcast_mode_str[0])) ? broadcast_mode_str[broadcast_mode] : "****"))); + } +#endif +#endif +}; +// IFM2 Precision +struct npu_set_ifm2_precision_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_type:1; // IFM type + uint32_t reserved1:1; + uint32_t activation_precision:2; // IFM precision + uint32_t reserved2:2; + uint32_t activation_format:2; // IFM format + uint32_t reserved3:6; + uint32_t activation_storage:2; // IFM storage mode +#ifdef __cplusplus +public: + npu_set_ifm2_precision_t(NPU_NAMESPACE::activation_type _activation_type, NPU_NAMESPACE::activation_precision _activation_precision, NPU_NAMESPACE::activation_format _activation_format, NPU_NAMESPACE::activation_storage _activation_storage) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1)-1)), + reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2)-1)), + reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2)-1)), + reserved3(0), + activation_storage(static_cast(_activation_storage) & ((1U << 2)-1)) + {} + CONSTEXPR npu_set_ifm2_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(0), + reserved1(0), + activation_precision(0), + reserved2(0), + activation_format(0), + reserved3(0), + activation_storage(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_type) << 16; + word |= uint32_t(activation_precision) << 18; + word |= uint32_t(activation_format) << 22; + word |= uint32_t(activation_storage) << 30; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_precision_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_precision_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_storage get_activation_storage() const + { + return static_cast(activation_storage); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_storage(NPU_NAMESPACE::activation_storage value) + { + activation_storage = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_type", (activation_type < (sizeof(activation_type_str)/sizeof(activation_type_str[0])) ? activation_type_str[activation_type] : "****"))); + fields.push_back(std::make_pair("activation_precision", (activation_precision < (sizeof(activation_precision_str)/sizeof(activation_precision_str[0])) ? activation_precision_str[activation_precision] : "****"))); + fields.push_back(std::make_pair("activation_format", (activation_format < (sizeof(activation_format_str)/sizeof(activation_format_str[0])) ? activation_format_str[activation_format] : "****"))); + fields.push_back(std::make_pair("activation_storage", (activation_storage < (sizeof(activation_storage_str)/sizeof(activation_storage_str[0])) ? activation_storage_str[activation_storage] : "****"))); + } +#endif +#endif +}; +// IFM2 zero point +struct npu_set_ifm2_zero_point_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t zero_point:16; // Zero point offset +#ifdef __cplusplus +public: + npu_set_ifm2_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(zero_point) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_zero_point_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_zero_point_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm2_zero_point_t& set_zero_point(uint32_t value) + { + assert((value >> 16) == 0); + zero_point = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif +}; +// IFM2 Tile 0 and Tile 2 width +struct npu_set_ifm2_width0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // IFM2 Tile 0 and tile 2 width +#ifdef __cplusplus +public: + npu_set_ifm2_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_width0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_width0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm2_width0_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// IFM2 Tile 0 height +struct npu_set_ifm2_height0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM2 Tile 0 height +#ifdef __cplusplus +public: + npu_set_ifm2_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height0_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// IFM2 Tile 1 height +struct npu_set_ifm2_height1_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM2 Tile 1 height +#ifdef __cplusplus +public: + npu_set_ifm2_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height1_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height1_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height1_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Index n for IFM2 access +struct npu_set_ifm2_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_ifm2_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm2_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm2_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// IFM Tile 0 address +struct npu_set_ifm_base0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM Tile 1 address +struct npu_set_ifm_base1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM Tile 2 address +struct npu_set_ifm_base2_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base2_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM Tile 3 address +struct npu_set_ifm_base3_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base3_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM byte stride between horizontal values +struct npu_set_ifm_stride_x_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_x_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM byte stride between vertical values +struct npu_set_ifm_stride_y_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_y_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM byte stride between channel blocks +struct npu_set_ifm_stride_c_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_c_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 0 address +struct npu_set_ofm_base0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 1 address +struct npu_set_ofm_base1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 2 address +struct npu_set_ofm_base2_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base2_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 3 address +struct npu_set_ofm_base3_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base3_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM byte stride between horizontal values +struct npu_set_ofm_stride_x_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_x_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM byte stride between vertical values +struct npu_set_ofm_stride_y_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_y_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM byte stride between channel blocks +struct npu_set_ofm_stride_c_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_c_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION +struct npu_set_weight_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length +struct npu_set_weight_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Scale and bias stream input byte offset from SCALE_REGION +struct npu_set_scale_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_scale_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_scale_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_scale_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Scale and bias stream input byte length +struct npu_set_scale_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:20; // Scale and bias stream byte length + uint32_t reserved2:12; +#ifdef __cplusplus +public: + npu_set_scale_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length & ((1U << 20)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_scale_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale_length_t& set_length(uint32_t value) + { + assert((value >> 20) == 0); + length = value & ((1U << 20)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// OFM scale +struct npu_set_ofm_scale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t shift:6; // Right shift (0 to 63) + uint32_t dbl_rnd:5; // Double rounding shift (0 to 30) + uint32_t reserved1:2; + uint32_t round_mode:3; // Rounding mode + uint32_t scale:31; // Scale value (uint31 = non-negative int32) + uint32_t reserved2:1; +#ifdef __cplusplus +public: + npu_set_ofm_scale_t(uint32_t _shift, uint32_t _dbl_rnd, NPU_NAMESPACE::round_mode_ofm _round_mode, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(_shift & ((1U << 6)-1)), + dbl_rnd(_dbl_rnd & ((1U << 5)-1)), + reserved1(0), + round_mode(static_cast(_round_mode) & ((1U << 3)-1)), + scale(_scale & ((1U << 31)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_ofm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(0), + dbl_rnd(0), + reserved1(0), + round_mode(0), + scale(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(shift) << 16; + word |= uint64_t(dbl_rnd) << 22; + word |= uint64_t(round_mode) << 29; + word |= uint64_t(scale) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_scale_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_scale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ofm_scale_t& set_shift(uint32_t value) + { + assert((value >> 6) == 0); + shift = static_cast(value & ((1U << 6)-1)); + return *this; + } + CONSTEXPR uint32_t get_dbl_rnd() const + { + return static_cast(dbl_rnd); + } + CONSTEXPR npu_set_ofm_scale_t& set_dbl_rnd(uint32_t value) + { + assert((value >> 5) == 0); + dbl_rnd = static_cast(value & ((1U << 5)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode_ofm get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ofm_scale_t& set_round_mode(NPU_NAMESPACE::round_mode_ofm value) + { + round_mode = static_cast(value) & ((1U << 3)-1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ofm_scale_t& set_scale(uint32_t value) + { + assert((value >> 31) == 0); + scale = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("dbl_rnd", std::to_string(dbl_rnd))); + fields.push_back(std::make_pair("round_mode", (round_mode < (sizeof(round_mode_ofm_str)/sizeof(round_mode_ofm_str[0])) ? round_mode_ofm_str[round_mode] : "****"))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif +}; +// IFM input scale +struct npu_set_ifm_scale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t shift:6; // Right shift (0 to 63) + uint32_t dbl_rnd:5; // Double rounding shift (0 to 30) + uint32_t reserved1:2; + uint32_t round_mode:1; // Rounding mode + uint32_t reserved2:2; + uint32_t scale:31; // Scale value (uint31 = non-negative int32) + uint32_t reserved3:1; +#ifdef __cplusplus +public: + npu_set_ifm_scale_t(uint32_t _shift, uint32_t _dbl_rnd, NPU_NAMESPACE::round_mode_ifm _round_mode, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(_shift & ((1U << 6)-1)), + dbl_rnd(_dbl_rnd & ((1U << 5)-1)), + reserved1(0), + round_mode(static_cast(_round_mode) & ((1U << 1)-1)), + reserved2(0), + scale(_scale & ((1U << 31)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_ifm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(0), + dbl_rnd(0), + reserved1(0), + round_mode(0), + reserved2(0), + scale(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(shift) << 16; + word |= uint64_t(dbl_rnd) << 22; + word |= uint64_t(round_mode) << 29; + word |= uint64_t(scale) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_scale_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_scale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ifm_scale_t& set_shift(uint32_t value) + { + assert((value >> 6) == 0); + shift = static_cast(value & ((1U << 6)-1)); + return *this; + } + CONSTEXPR uint32_t get_dbl_rnd() const + { + return static_cast(dbl_rnd); + } + CONSTEXPR npu_set_ifm_scale_t& set_dbl_rnd(uint32_t value) + { + assert((value >> 5) == 0); + dbl_rnd = static_cast(value & ((1U << 5)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode_ifm get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm_scale_t& set_round_mode(NPU_NAMESPACE::round_mode_ifm value) + { + round_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ifm_scale_t& set_scale(uint32_t value) + { + assert((value >> 31) == 0); + scale = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("dbl_rnd", std::to_string(dbl_rnd))); + fields.push_back(std::make_pair("round_mode", (round_mode < (sizeof(round_mode_ifm_str)/sizeof(round_mode_ifm_str[0])) ? round_mode_ifm_str[round_mode] : "****"))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif +}; +// IFM2 input scale +struct npu_set_ifm2_scale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t shift:6; // Right shift (0 to 63) + uint32_t dbl_rnd:5; // Double rounding shift (0 to 30) + uint32_t reserved1:2; + uint32_t round_mode:1; // Rounding mode + uint32_t reserved2:2; + uint32_t scale:31; // Scale value (uint31 = non-negative int32) + uint32_t reserved3:1; +#ifdef __cplusplus +public: + npu_set_ifm2_scale_t(uint32_t _shift, uint32_t _dbl_rnd, NPU_NAMESPACE::round_mode_ifm _round_mode, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(_shift & ((1U << 6)-1)), + dbl_rnd(_dbl_rnd & ((1U << 5)-1)), + reserved1(0), + round_mode(static_cast(_round_mode) & ((1U << 1)-1)), + reserved2(0), + scale(_scale & ((1U << 31)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_ifm2_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(0), + dbl_rnd(0), + reserved1(0), + round_mode(0), + reserved2(0), + scale(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(shift) << 16; + word |= uint64_t(dbl_rnd) << 22; + word |= uint64_t(round_mode) << 29; + word |= uint64_t(scale) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_scale_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_scale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ifm2_scale_t& set_shift(uint32_t value) + { + assert((value >> 6) == 0); + shift = static_cast(value & ((1U << 6)-1)); + return *this; + } + CONSTEXPR uint32_t get_dbl_rnd() const + { + return static_cast(dbl_rnd); + } + CONSTEXPR npu_set_ifm2_scale_t& set_dbl_rnd(uint32_t value) + { + assert((value >> 5) == 0); + dbl_rnd = static_cast(value & ((1U << 5)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode_ifm get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm2_scale_t& set_round_mode(NPU_NAMESPACE::round_mode_ifm value) + { + round_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ifm2_scale_t& set_scale(uint32_t value) + { + assert((value >> 31) == 0); + scale = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("dbl_rnd", std::to_string(dbl_rnd))); + fields.push_back(std::make_pair("round_mode", (round_mode < (sizeof(round_mode_ifm_str)/sizeof(round_mode_ifm_str[0])) ? round_mode_ifm_str[round_mode] : "****"))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif +}; +// Operation scalar value +struct npu_set_op_scalar_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t scalar:32; // Scalar value (int32) +#ifdef __cplusplus +public: + npu_set_op_scalar_t(uint32_t _scalar) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + scalar(_scalar) + {} + CONSTEXPR npu_set_op_scalar_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + scalar(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(scalar) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_op_scalar_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_op_scalar_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_scalar() const + { + return static_cast(scalar); + } + CONSTEXPR npu_set_op_scalar_t& set_scalar(uint32_t value) + { + scalar = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("scalar", std::to_string(((scalar <= std::numeric_limits::max() ? static_cast(scalar) : scalar - std::numeric_limits::min() + std::numeric_limits::max()) << 0) >> 0))); + } +#endif +#endif +}; +// DMA user channel 0 source byte offset from DMA0_SRC_REGION +struct npu_set_dma0_src_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_src_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_src_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA user channel 0 destination byte offset from DMA0_DST_REGION +struct npu_set_dma0_dst_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_dst_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_dst_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA user channel 0 transfer length in bytes for each 1D transfer +struct npu_set_dma0_len_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_len_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_len_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_len_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Source byte stride after each 1D transfer +struct npu_set_dma0_src_stride0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_src_stride0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_src_stride0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_stride0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Source byte stride after each 2D transfer +struct npu_set_dma0_src_stride1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_src_stride1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_src_stride1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_stride1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Destination byte stride after each 1D transfer +struct npu_set_dma0_dst_stride0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_dst_stride0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_dst_stride0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_stride0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Destination byte stride after 2D transfer +struct npu_set_dma0_dst_stride1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_dst_stride1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_dst_stride1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_stride1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA channel 0 index array address +struct npu_set_dma0_idx_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_idx_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_idx_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_idx_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA channel 0 index maximum value +struct npu_set_dma0_idx_max_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t idx_max:31; // maximum permitted index + uint32_t reserved2:1; +#ifdef __cplusplus +public: + npu_set_dma0_idx_max_t(uint32_t _idx_max) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + idx_max(_idx_max & ((1U << 31)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_dma0_idx_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + idx_max(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(idx_max) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_idx_max_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_idx_max_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_idx_max() const + { + return static_cast(idx_max); + } + CONSTEXPR npu_set_dma0_idx_max_t& set_idx_max(uint32_t value) + { + assert((value >> 31) == 0); + idx_max = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("idx_max", std::to_string(idx_max))); + } +#endif +#endif +}; +// Index byte distance to skip in index after each 2D transfer +struct npu_set_dma0_idx_skip1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_idx_skip1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_idx_skip1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_idx_skip1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 0 address +struct npu_set_ifm2_base0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 1 address +struct npu_set_ifm2_base1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 2 address +struct npu_set_ifm2_base2_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base2_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 3 address +struct npu_set_ifm2_base3_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base3_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 byte stride between horizontal values +struct npu_set_ifm2_stride_x_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_x_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 byte stride between vertical values +struct npu_set_ifm2_stride_y_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_y_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 byte stride between channel blocks +struct npu_set_ifm2_stride_c_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_c_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION for weight decoder 1 +struct npu_set_weight1_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight1_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight1_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight1_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length for weight decoder 1 +struct npu_set_weight1_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight1_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight1_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight1_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight1_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight1_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION for weight decoder 2 +struct npu_set_weight2_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight2_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight2_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight2_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length for weight decoder 2 +struct npu_set_weight2_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight2_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight2_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight2_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight2_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight2_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION for weight decoder 3 +struct npu_set_weight3_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight3_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight3_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight3_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length for weight decoder 3 +struct npu_set_weight3_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight3_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight3_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight3_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight3_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight3_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Resize X axis step parameters +struct npu_set_resize_x_step_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t one_step_int:4; // (1*scale_d) / scale_n + uint32_t blk_step_int:11; // ((ofm_block_size-1)*scale_d) / scale_n + uint32_t reserved1:1; + uint32_t one_step_mod:11; // (1*scale_d) % scale_n + uint32_t reserved2:5; + uint32_t blk_step_mod:11; // ((ofm_block_size-1)*scale_d) % scale_n + uint32_t reserved3:5; +#ifdef __cplusplus +public: + npu_set_resize_x_step_t(uint32_t _one_step_int, uint32_t _blk_step_int, uint32_t _one_step_mod, uint32_t _blk_step_mod) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(_one_step_int & ((1U << 4)-1)), + blk_step_int(_blk_step_int & ((1U << 11)-1)), + reserved1(0), + one_step_mod(_one_step_mod & ((1U << 11)-1)), + reserved2(0), + blk_step_mod(_blk_step_mod & ((1U << 11)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_resize_x_step_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(0), + blk_step_int(0), + reserved1(0), + one_step_mod(0), + reserved2(0), + blk_step_mod(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(one_step_int) << 16; + word |= uint64_t(blk_step_int) << 20; + word |= uint64_t(one_step_mod) << 32; + word |= uint64_t(blk_step_mod) << 48; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_x_step_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_x_step_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_one_step_int() const + { + return static_cast(one_step_int); + } + CONSTEXPR npu_set_resize_x_step_t& set_one_step_int(uint32_t value) + { + assert((value >> 4) == 0); + one_step_int = static_cast(value & ((1U << 4)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_int() const + { + return static_cast(blk_step_int); + } + CONSTEXPR npu_set_resize_x_step_t& set_blk_step_int(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_int = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_one_step_mod() const + { + return static_cast(one_step_mod); + } + CONSTEXPR npu_set_resize_x_step_t& set_one_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + one_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_mod() const + { + return static_cast(blk_step_mod); + } + CONSTEXPR npu_set_resize_x_step_t& set_blk_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("one_step_int", std::to_string(one_step_int))); + fields.push_back(std::make_pair("blk_step_int", std::to_string(blk_step_int))); + fields.push_back(std::make_pair("one_step_mod", std::to_string(one_step_mod))); + fields.push_back(std::make_pair("blk_step_mod", std::to_string(blk_step_mod))); + } +#endif +#endif +}; +// Resize Y axis step parameters +struct npu_set_resize_y_step_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t one_step_int:4; // (1*scale_d) / scale_n + uint32_t blk_step_int:11; // ((ofm_block_size-1)*scale_d) / scale_n + uint32_t reserved1:1; + uint32_t one_step_mod:11; // (1*scale_d) % scale_n + uint32_t reserved2:5; + uint32_t blk_step_mod:11; // ((ofm_block_size-1)*scale_d) % scale_n + uint32_t reserved3:5; +#ifdef __cplusplus +public: + npu_set_resize_y_step_t(uint32_t _one_step_int, uint32_t _blk_step_int, uint32_t _one_step_mod, uint32_t _blk_step_mod) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(_one_step_int & ((1U << 4)-1)), + blk_step_int(_blk_step_int & ((1U << 11)-1)), + reserved1(0), + one_step_mod(_one_step_mod & ((1U << 11)-1)), + reserved2(0), + blk_step_mod(_blk_step_mod & ((1U << 11)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_resize_y_step_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(0), + blk_step_int(0), + reserved1(0), + one_step_mod(0), + reserved2(0), + blk_step_mod(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(one_step_int) << 16; + word |= uint64_t(blk_step_int) << 20; + word |= uint64_t(one_step_mod) << 32; + word |= uint64_t(blk_step_mod) << 48; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_y_step_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_y_step_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_one_step_int() const + { + return static_cast(one_step_int); + } + CONSTEXPR npu_set_resize_y_step_t& set_one_step_int(uint32_t value) + { + assert((value >> 4) == 0); + one_step_int = static_cast(value & ((1U << 4)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_int() const + { + return static_cast(blk_step_int); + } + CONSTEXPR npu_set_resize_y_step_t& set_blk_step_int(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_int = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_one_step_mod() const + { + return static_cast(one_step_mod); + } + CONSTEXPR npu_set_resize_y_step_t& set_one_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + one_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_mod() const + { + return static_cast(blk_step_mod); + } + CONSTEXPR npu_set_resize_y_step_t& set_blk_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("one_step_int", std::to_string(one_step_int))); + fields.push_back(std::make_pair("blk_step_int", std::to_string(blk_step_int))); + fields.push_back(std::make_pair("one_step_mod", std::to_string(one_step_mod))); + fields.push_back(std::make_pair("blk_step_mod", std::to_string(blk_step_mod))); + } +#endif +#endif +}; +// Branch to new location +struct npu_op_branch_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t branch_cond:1; // Branch condition + uint32_t reserved1:15; + uint32_t branch_target:32; // Branch target in bytes +#ifdef __cplusplus +public: + npu_op_branch_t(NPU_NAMESPACE::branch_cond _branch_cond, uint32_t _branch_target) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + branch_cond(static_cast(_branch_cond) & ((1U << 1)-1)), + reserved1(0), + branch_target(_branch_target) + {} + CONSTEXPR npu_op_branch_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + branch_cond(0), + reserved1(0), + branch_target(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(branch_cond) << 16; + word |= uint64_t(branch_target) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_branch_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_branch_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::branch_cond get_branch_cond() const + { + return static_cast(branch_cond); + } + CONSTEXPR npu_op_branch_t& set_branch_cond(NPU_NAMESPACE::branch_cond value) + { + branch_cond = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_branch_target() const + { + return static_cast(branch_target); + } + CONSTEXPR npu_op_branch_t& set_branch_target(uint32_t value) + { + branch_target = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("branch_cond", (branch_cond < (sizeof(branch_cond_str)/sizeof(branch_cond_str[0])) ? branch_cond_str[branch_cond] : "****"))); + fields.push_back(std::make_pair("branch_target", std::to_string(branch_target))); + } +#endif +#endif +}; +#ifdef __cplusplus +}; +#endif +#define NPU_OP_STRUCTS \ + NPU_OP_(stop) \ + NPU_OP_(irq) \ + NPU_OP_(conv) \ + NPU_OP_(depthwise) \ + NPU_OP_(pool) \ + NPU_OP_(elementwise) \ + NPU_OP_(resize) \ + NPU_OP_(dma_start) \ + NPU_OP_(dma_wait) \ + NPU_OP_(kernel_wait) \ + NPU_OP_(pmu_mask) \ + NPU_OP_(branch) + +#define NPU_SET_STRUCTS \ + NPU_SET_(ifm_pad_top) \ + NPU_SET_(ifm_pad_left) \ + NPU_SET_(ifm_pad_right) \ + NPU_SET_(ifm_pad_bottom) \ + NPU_SET_(ifm_depth_m1) \ + NPU_SET_(ifm_precision) \ + NPU_SET_(ifm_upscale) \ + NPU_SET_(ifm_zero_point) \ + NPU_SET_(ifm_width0_m1) \ + NPU_SET_(ifm_height0_m1) \ + NPU_SET_(ifm_height1_m1) \ + NPU_SET_(ifm_region) \ + NPU_SET_(ifm_broadcast) \ + NPU_SET_(ofm_width_m1) \ + NPU_SET_(ofm_height_m1) \ + NPU_SET_(ofm_depth_m1) \ + NPU_SET_(ofm_precision) \ + NPU_SET_(ofm_blk_width_m1) \ + NPU_SET_(ofm_blk_height_m1) \ + NPU_SET_(ofm_blk_depth_m1) \ + NPU_SET_(ofm_zero_point) \ + NPU_SET_(ofm_width0_m1) \ + NPU_SET_(ofm_height0_m1) \ + NPU_SET_(ofm_height1_m1) \ + NPU_SET_(ofm_region) \ + NPU_SET_(kernel_width_m1) \ + NPU_SET_(kernel_height_m1) \ + NPU_SET_(kernel_stride) \ + NPU_SET_(acc_format) \ + NPU_SET_(activation) \ + NPU_SET_(activation_min) \ + NPU_SET_(activation_max) \ + NPU_SET_(weight_region) \ + NPU_SET_(scale_region) \ + NPU_SET_(weight_format) \ + NPU_SET_(blockdep) \ + NPU_SET_(resize_x_scale_n_m1) \ + NPU_SET_(resize_y_scale_n_m1) \ + NPU_SET_(resize_x_offset) \ + NPU_SET_(resize_y_offset) \ + NPU_SET_(dma0_src_region) \ + NPU_SET_(dma0_dst_region) \ + NPU_SET_(dma0_size0) \ + NPU_SET_(dma0_size1) \ + NPU_SET_(dma0_idx_region) \ + NPU_SET_(ifm2_broadcast) \ + NPU_SET_(ifm2_precision) \ + NPU_SET_(ifm2_zero_point) \ + NPU_SET_(ifm2_width0_m1) \ + NPU_SET_(ifm2_height0_m1) \ + NPU_SET_(ifm2_height1_m1) \ + NPU_SET_(ifm2_region) \ + NPU_SET_(ifm_base0) \ + NPU_SET_(ifm_base1) \ + NPU_SET_(ifm_base2) \ + NPU_SET_(ifm_base3) \ + NPU_SET_(ifm_stride_x) \ + NPU_SET_(ifm_stride_y) \ + NPU_SET_(ifm_stride_c) \ + NPU_SET_(ofm_base0) \ + NPU_SET_(ofm_base1) \ + NPU_SET_(ofm_base2) \ + NPU_SET_(ofm_base3) \ + NPU_SET_(ofm_stride_x) \ + NPU_SET_(ofm_stride_y) \ + NPU_SET_(ofm_stride_c) \ + NPU_SET_(weight_base) \ + NPU_SET_(weight_length) \ + NPU_SET_(scale_base) \ + NPU_SET_(scale_length) \ + NPU_SET_(ofm_scale) \ + NPU_SET_(ifm_scale) \ + NPU_SET_(ifm2_scale) \ + NPU_SET_(op_scalar) \ + NPU_SET_(dma0_src) \ + NPU_SET_(dma0_dst) \ + NPU_SET_(dma0_len) \ + NPU_SET_(dma0_src_stride0) \ + NPU_SET_(dma0_src_stride1) \ + NPU_SET_(dma0_dst_stride0) \ + NPU_SET_(dma0_dst_stride1) \ + NPU_SET_(dma0_idx) \ + NPU_SET_(dma0_idx_max) \ + NPU_SET_(dma0_idx_skip1) \ + NPU_SET_(ifm2_base0) \ + NPU_SET_(ifm2_base1) \ + NPU_SET_(ifm2_base2) \ + NPU_SET_(ifm2_base3) \ + NPU_SET_(ifm2_stride_x) \ + NPU_SET_(ifm2_stride_y) \ + NPU_SET_(ifm2_stride_c) \ + NPU_SET_(weight1_base) \ + NPU_SET_(weight1_length) \ + NPU_SET_(weight2_base) \ + NPU_SET_(weight2_length) \ + NPU_SET_(weight3_base) \ + NPU_SET_(weight3_length) \ + NPU_SET_(resize_x_step) \ + NPU_SET_(resize_y_step) + +#define EXPAND_ACC_FORMAT(FUNC, SEP) \ + FUNC(acc_format, I32) SEP \ + FUNC(acc_format, I48) + +#define EXPAND_ACC_INPUT(FUNC, SEP) \ + FUNC(acc_input, RESET) SEP \ + FUNC(acc_input, KEEP) SEP \ + FUNC(acc_input, IFM2) + +#define EXPAND_ACC_OUTPUT(FUNC, SEP) \ + FUNC(acc_output, ENABLE) SEP \ + FUNC(acc_output, DISABLE) + +#define EXPAND_ACTIVATION_CLIP_RANGE(FUNC, SEP) \ + FUNC(activation_clip_range, B16) SEP \ + FUNC(activation_clip_range, NONE) + +#define EXPAND_ACTIVATION_FORMAT(FUNC, SEP) \ + FUNC(activation_format, NHWC) SEP \ + FUNC(activation_format, NHCWB16) + +#define EXPAND_ACTIVATION_FUNCTION(FUNC, SEP) \ + FUNC(activation_function, LUT_NONE) SEP \ + FUNC(activation_function, LUT_U8_U8) SEP \ + FUNC(activation_function, LUT_S8_S8) SEP \ + FUNC(activation_function, LUT_S8_S16) SEP \ + FUNC(activation_function, LUT_S8_S32) SEP \ + FUNC(activation_function, LUT_S16_S16) SEP \ + FUNC(activation_function, LUT_S16_S32) SEP \ + FUNC(activation_function, LUT_TANH) SEP \ + FUNC(activation_function, LUT_SIGMOID) + +#define EXPAND_ACTIVATION_PRECISION(FUNC, SEP) \ + FUNC(activation_precision, B8) SEP \ + FUNC(activation_precision, B16) SEP \ + FUNC(activation_precision, B32) SEP \ + FUNC(activation_precision, B64) + +#define EXPAND_ACTIVATION_REVERSE(FUNC, SEP) \ + FUNC(activation_reverse, NONE) SEP \ + FUNC(activation_reverse, H) SEP \ + FUNC(activation_reverse, W) SEP \ + FUNC(activation_reverse, C) + +#define EXPAND_ACTIVATION_STORAGE(FUNC, SEP) \ + FUNC(activation_storage, TILE2X2) SEP \ + FUNC(activation_storage, TILE3X1) SEP \ + FUNC(activation_storage, CHAINED) SEP \ + FUNC(activation_storage, NONE) + +#define EXPAND_ACTIVATION_TRANSPOSE(FUNC, SEP) \ + FUNC(activation_transpose, HWC) SEP \ + FUNC(activation_transpose, WHC) SEP \ + FUNC(activation_transpose, HCW) SEP \ + FUNC(activation_transpose, WCH) SEP \ + FUNC(activation_transpose, CHW) SEP \ + FUNC(activation_transpose, CWH) + +#define EXPAND_ACTIVATION_TYPE(FUNC, SEP) \ + FUNC(activation_type, UNSIGNED) SEP \ + FUNC(activation_type, SIGNED) + +#define EXPAND_AXI_MEM_DOMAIN(FUNC, SEP) \ + FUNC(axi_mem_domain, NON_SHARABLE) SEP \ + FUNC(axi_mem_domain, INNER_SHARABLE) SEP \ + FUNC(axi_mem_domain, OUTER_SHARABLE) SEP \ + FUNC(axi_mem_domain, SYSTEM) + +#define EXPAND_AXI_MEM_ENCODING(FUNC, SEP) \ + FUNC(axi_mem_encoding, DEVICE_NON_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, DEVICE_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_NON_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_NO_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_READ_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_WRITE_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_READ_AND_WRITE_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_NO_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_READ_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_WRITE_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_READ_AND_WRITE_ALLOCATE) + +#define EXPAND_AXI_PORT(FUNC, SEP) \ + FUNC(axi_port, SRAM) SEP \ + FUNC(axi_port, EXT) + +#define EXPAND_BRANCH_COND(FUNC, SEP) \ + FUNC(branch_cond, ALWAYS) SEP \ + FUNC(branch_cond, RF_TRUE) + +#define EXPAND_BROADCAST_MODE(FUNC, SEP) \ + FUNC(broadcast_mode, NONE) SEP \ + FUNC(broadcast_mode, H) SEP \ + FUNC(broadcast_mode, W) SEP \ + FUNC(broadcast_mode, HW) SEP \ + FUNC(broadcast_mode, C) SEP \ + FUNC(broadcast_mode, CH) SEP \ + FUNC(broadcast_mode, CW) SEP \ + FUNC(broadcast_mode, CWH) SEP \ + FUNC(broadcast_mode, SCALAR) + +#define EXPAND_CMD0_OPCODE(FUNC, SEP) \ + FUNC(cmd0_opcode, NPU_OP_STOP) SEP \ + FUNC(cmd0_opcode, NPU_OP_IRQ) SEP \ + FUNC(cmd0_opcode, NPU_OP_CONV) SEP \ + FUNC(cmd0_opcode, NPU_OP_DEPTHWISE) SEP \ + FUNC(cmd0_opcode, NPU_OP_POOL) SEP \ + FUNC(cmd0_opcode, NPU_OP_ELEMENTWISE) SEP \ + FUNC(cmd0_opcode, NPU_OP_RESIZE) SEP \ + FUNC(cmd0_opcode, NPU_OP_DMA_START) SEP \ + FUNC(cmd0_opcode, NPU_OP_DMA_WAIT) SEP \ + FUNC(cmd0_opcode, NPU_OP_KERNEL_WAIT) SEP \ + FUNC(cmd0_opcode, NPU_OP_PMU_MASK) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_TOP) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_LEFT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_RIGHT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_BOTTOM) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_DEPTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_UPSCALE) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_BROADCAST) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT1_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_DEPTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_BLK_WIDTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_BLK_HEIGHT_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_BLK_DEPTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT1_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_KERNEL_WIDTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_KERNEL_HEIGHT_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_KERNEL_STRIDE) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACC_FORMAT) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACTIVATION) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MIN) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MAX) SEP \ + FUNC(cmd0_opcode, NPU_SET_WEIGHT_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_SCALE_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_X_SCALE_N_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_Y_SCALE_N_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_X_OFFSET) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_Y_OFFSET) SEP \ + FUNC(cmd0_opcode, NPU_SET_WEIGHT_FORMAT) SEP \ + FUNC(cmd0_opcode, NPU_SET_BLOCKDEP) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_SRC_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_DST_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE0) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE1) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_IDX_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_BROADCAST) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_HEIGHT1_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_REGION) + +#define EXPAND_CMD1_OPCODE(FUNC, SEP) \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE2) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE3) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_Y) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_C) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE2) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE3) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_Y) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_C) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_SCALE_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_SCALE_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_SCALE) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_SCALE) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_SCALE) SEP \ + FUNC(cmd1_opcode, NPU_SET_OP_SCALAR) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_SRC) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_DST) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_LEN) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_SRC_STRIDE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_SRC_STRIDE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_DST_STRIDE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_DST_STRIDE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_IDX) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_IDX_MAX) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_IDX_SKIP1) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE2) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE3) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_Y) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_C) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT1_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT1_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT2_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT2_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT3_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT3_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_RESIZE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_RESIZE_Y) SEP \ + FUNC(cmd1_opcode, NPU_OP_BRANCH) + +#define EXPAND_CMD_CTRL(FUNC, SEP) \ + FUNC(cmd_ctrl, CMD0_CTRL) SEP \ + FUNC(cmd_ctrl, CMD1_CTRL) + +#define EXPAND_CUSTOM_DMA(FUNC, SEP) \ + FUNC(custom_dma, NOT_IMPLEMENTED) SEP \ + FUNC(custom_dma, IMPLEMENTED) + +#define EXPAND_DMA_FAULT_SRC(FUNC, SEP) \ + FUNC(dma_fault_src, SRAM) SEP \ + FUNC(dma_fault_src, EXT) + +#define EXPAND_DMA_IDX_MODE(FUNC, SEP) \ + FUNC(dma_idx_mode, DISABLED) SEP \ + FUNC(dma_idx_mode, ENABLED) + +#define EXPAND_DMA_REGION_MODE(FUNC, SEP) \ + FUNC(dma_region_mode, EXTERNAL) SEP \ + FUNC(dma_region_mode, INTERNAL) + +#define EXPAND_DMA_STRIDE_MODE(FUNC, SEP) \ + FUNC(dma_stride_mode, D1) SEP \ + FUNC(dma_stride_mode, D2) SEP \ + FUNC(dma_stride_mode, D3) + +#define EXPAND_ELEMENTWISE_MODE(FUNC, SEP) \ + FUNC(elementwise_mode, MUL) SEP \ + FUNC(elementwise_mode, ADD) SEP \ + FUNC(elementwise_mode, SUB) SEP \ + FUNC(elementwise_mode, MIN) SEP \ + FUNC(elementwise_mode, MAX) SEP \ + FUNC(elementwise_mode, LRELU) SEP \ + FUNC(elementwise_mode, ABS) SEP \ + FUNC(elementwise_mode, CLZ) SEP \ + FUNC(elementwise_mode, SHR) SEP \ + FUNC(elementwise_mode, SHL) SEP \ + FUNC(elementwise_mode, LSR) SEP \ + FUNC(elementwise_mode, DIV) SEP \ + FUNC(elementwise_mode, CMP_EQ) SEP \ + FUNC(elementwise_mode, CMP_NE) SEP \ + FUNC(elementwise_mode, CMP_GE) SEP \ + FUNC(elementwise_mode, CMP_GT) SEP \ + FUNC(elementwise_mode, AND) SEP \ + FUNC(elementwise_mode, OR) SEP \ + FUNC(elementwise_mode, XOR) SEP \ + FUNC(elementwise_mode, NOT) SEP \ + FUNC(elementwise_mode, AND_NOT) + +#define EXPAND_IFM_UPSCALE_MODE(FUNC, SEP) \ + FUNC(ifm_upscale_mode, NONE) SEP \ + FUNC(ifm_upscale_mode, NEAREST) SEP \ + FUNC(ifm_upscale_mode, ZEROS) + +#define EXPAND_KERNEL_DECOMPOSITION(FUNC, SEP) \ + FUNC(kernel_decomposition, D8X8) SEP \ + FUNC(kernel_decomposition, D4X4) + +#define EXPAND_KERNEL_DILATION(FUNC, SEP) \ + FUNC(kernel_dilation, NONE) SEP \ + FUNC(kernel_dilation, X2) + +#define EXPAND_MAX_BEATS(FUNC, SEP) \ + FUNC(max_beats, B64) SEP \ + FUNC(max_beats, B128) SEP \ + FUNC(max_beats, B256) + +#define EXPAND_MICROBLOCK(FUNC, SEP) \ + FUNC(microblock, U1X1) SEP \ + FUNC(microblock, U1X2) SEP \ + FUNC(microblock, U1X4) SEP \ + FUNC(microblock, U2X2) SEP \ + FUNC(microblock, U2X4) SEP \ + FUNC(microblock, U4X4) + +#define EXPAND_OFM_SCALE_MODE(FUNC, SEP) \ + FUNC(ofm_scale_mode, PER_CHANNEL) SEP \ + FUNC(ofm_scale_mode, GLOBAL) + +#define EXPAND_PMU_AXI_CHANNEL(FUNC, SEP) \ + FUNC(pmu_axi_channel, RD_CMD) SEP \ + FUNC(pmu_axi_channel, RD_IFM) SEP \ + FUNC(pmu_axi_channel, RD_WEIGHTS) SEP \ + FUNC(pmu_axi_channel, RD_SCALE_BIAS) SEP \ + FUNC(pmu_axi_channel, RD_MEM2MEM) SEP \ + FUNC(pmu_axi_channel, RD_IFM_STREAM) SEP \ + FUNC(pmu_axi_channel, RD_MEM2MEM_IDX) SEP \ + FUNC(pmu_axi_channel, WR_OFM) SEP \ + FUNC(pmu_axi_channel, WR_MEM2MEM) + +#define EXPAND_PMU_EVENT(FUNC, SEP) \ + FUNC(pmu_event, NO_EVENT) SEP \ + FUNC(pmu_event, CYCLE) SEP \ + FUNC(pmu_event, NPU_IDLE) SEP \ + FUNC(pmu_event, CC_STALLED_ON_BLOCKDEP) SEP \ + FUNC(pmu_event, NPU_ACTIVE) SEP \ + FUNC(pmu_event, MAC_ACTIVE) SEP \ + FUNC(pmu_event, MAC_DPU_ACTIVE) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_W_OR_ACC) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_W) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_ACC) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_IB) SEP \ + FUNC(pmu_event, AO_ACTIVE) SEP \ + FUNC(pmu_event, AO_STALLED_BY_BS_OR_OB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_BS) SEP \ + FUNC(pmu_event, AO_STALLED_BY_OB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_AB_OR_CB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_AB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_CB) SEP \ + FUNC(pmu_event, WD_ACTIVE) SEP \ + FUNC(pmu_event, WD_STALLED) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WD_BUF) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_FC) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_TC) SEP \ + FUNC(pmu_event, WD_TRANS_WBLK) SEP \ + FUNC(pmu_event, WD_TRANS_WS_FC) SEP \ + FUNC(pmu_event, WD_TRANS_WS_TC) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC0) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC1) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC2) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC3) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC0) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC1) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC2) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC3) SEP \ + FUNC(pmu_event, WD_TRANS_WB0) SEP \ + FUNC(pmu_event, WD_TRANS_WB1) SEP \ + FUNC(pmu_event, WD_TRANS_WB2) SEP \ + FUNC(pmu_event, WD_TRANS_WB3) SEP \ + FUNC(pmu_event, SRAM_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, AXI_LATENCY_ANY) SEP \ + FUNC(pmu_event, AXI_LATENCY_32) SEP \ + FUNC(pmu_event, AXI_LATENCY_64) SEP \ + FUNC(pmu_event, AXI_LATENCY_128) SEP \ + FUNC(pmu_event, AXI_LATENCY_256) SEP \ + FUNC(pmu_event, AXI_LATENCY_512) SEP \ + FUNC(pmu_event, AXI_LATENCY_1024) SEP \ + FUNC(pmu_event, ECC_DMA) SEP \ + FUNC(pmu_event, ECC_MAC_IB) SEP \ + FUNC(pmu_event, ECC_MAC_AB) SEP \ + FUNC(pmu_event, ECC_AO_CB) SEP \ + FUNC(pmu_event, ECC_AO_OB) SEP \ + FUNC(pmu_event, ECC_AO_LUT) SEP \ + FUNC(pmu_event, EXT_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, EXT_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, EXT_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, EXT_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, EXT_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, EXT_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, EXT_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, EXT_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM0_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM0_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM0_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM0_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM0_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM0_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM0_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM0_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM1_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM1_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM1_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM1_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM1_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM1_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM1_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM1_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM2_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM2_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM2_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM2_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM2_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM2_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM2_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM2_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM2_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM2_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM2_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM2_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM2_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM3_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM3_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM3_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM3_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM3_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM3_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM3_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM3_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM3_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM3_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM3_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM3_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM3_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT0_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, EXT0_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, EXT0_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT0_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, EXT0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, EXT0_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, EXT0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT0_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, EXT0_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, EXT0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT0_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT1_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, EXT1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, EXT1_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT1_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, EXT1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, EXT1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, EXT1_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT1_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, EXT1_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, EXT1_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT1_WR_STALL_LIMIT) + +#define EXPAND_PMU_PORT_DISABLE(FUNC, SEP) \ + FUNC(pmu_port_disable, ENABLE) SEP \ + FUNC(pmu_port_disable, DISABLE) + +#define EXPAND_POOLING_MODE(FUNC, SEP) \ + FUNC(pooling_mode, MAX) SEP \ + FUNC(pooling_mode, AVERAGE) SEP \ + FUNC(pooling_mode, REDUCE_SUM) SEP \ + FUNC(pooling_mode, SUM) SEP \ + FUNC(pooling_mode, NONE) SEP \ + FUNC(pooling_mode, MIN) SEP \ + FUNC(pooling_mode, ARGMAX_X) SEP \ + FUNC(pooling_mode, ARGMAX_Y) + +#define EXPAND_PRIVILEGE_LEVEL(FUNC, SEP) \ + FUNC(privilege_level, USER) SEP \ + FUNC(privilege_level, PRIVILEGED) + +#define EXPAND_RAM_ID(FUNC, SEP) \ + FUNC(ram_id, LUT) SEP \ + FUNC(ram_id, IB) SEP \ + FUNC(ram_id, AB) SEP \ + FUNC(ram_id, CB) SEP \ + FUNC(ram_id, OB) + +#define EXPAND_RESIZE_MODE(FUNC, SEP) \ + FUNC(resize_mode, BILINEAR) SEP \ + FUNC(resize_mode, REPLICATE) SEP \ + FUNC(resize_mode, NEAREST) + +#define EXPAND_ROUND_MODE_IFM(FUNC, SEP) \ + FUNC(round_mode_ifm, DOUBLE_SYMMETRIC) SEP \ + FUNC(round_mode_ifm, NATURAL) + +#define EXPAND_ROUND_MODE_OFM(FUNC, SEP) \ + FUNC(round_mode_ofm, DOUBLE_SYMMETRIC) SEP \ + FUNC(round_mode_ofm, NATURAL) SEP \ + FUNC(round_mode_ofm, DOUBLE_ASYMMETRIC) SEP \ + FUNC(round_mode_ofm, SYMMETRIC) SEP \ + FUNC(round_mode_ofm, TRUNCATE_TO_ZERO) SEP \ + FUNC(round_mode_ofm, TRUNCATE_TO_LOWER) + +#define EXPAND_SECURITY_LEVEL(FUNC, SEP) \ + FUNC(security_level, SECURE) SEP \ + FUNC(security_level, NON_SECURE) + +#define EXPAND_STATE(FUNC, SEP) \ + FUNC(state, STOPPED) SEP \ + FUNC(state, RUNNING) + +#define EXPAND_WD_ACTIVE_CORE(FUNC, SEP) \ + FUNC(wd_active_core, NONE) SEP \ + FUNC(wd_active_core, STANDARD) SEP \ + FUNC(wd_active_core, FAST) SEP \ + FUNC(wd_active_core, TENSOR) + +#define EXPAND_WEIGHT_FORMAT(FUNC, SEP) \ + FUNC(weight_format, SWD) SEP \ + FUNC(weight_format, FWD) + +#define EXPAND_WEIGHT_ORDER(FUNC, SEP) \ + FUNC(weight_order, DEPTH_FIRST) SEP \ + FUNC(weight_order, PART_KERNEL_FIRST) + +#define EXPAND_WEIGHT_SPARSITY(FUNC, SEP) \ + FUNC(weight_sparsity, NONE) SEP \ + FUNC(weight_sparsity, SPARSE_2_4) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h new file mode 100644 index 0000000..9330bb1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019-2020,2022 Arm Limited. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_CONFIG_H +#define ETHOSU_CONFIG_H + +/* Set default values if not manually overriden */ + +#ifndef NPU_QCONFIG +#define NPU_QCONFIG 2 +#endif + +#ifndef NPU_REGIONCFG_0 +#define NPU_REGIONCFG_0 3 +#endif + +#ifndef NPU_REGIONCFG_1 +#define NPU_REGIONCFG_1 0 +#endif + +#ifndef NPU_REGIONCFG_2 +#define NPU_REGIONCFG_2 1 +#endif + +#ifndef NPU_REGIONCFG_3 +#define NPU_REGIONCFG_3 1 +#endif + +#ifndef NPU_REGIONCFG_4 +#define NPU_REGIONCFG_4 1 +#endif + +#ifndef NPU_REGIONCFG_5 +#define NPU_REGIONCFG_5 1 +#endif + +#ifndef NPU_REGIONCFG_6 +#define NPU_REGIONCFG_6 1 +#endif + +#ifndef NPU_REGIONCFG_7 +#define NPU_REGIONCFG_7 1 +#endif + +#ifndef AXI_LIMIT0_MAX_BEATS_BYTES +#define AXI_LIMIT0_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT0_MEM_TYPE +#define AXI_LIMIT0_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_READS +#define AXI_LIMIT0_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT0_MAX_OUTSTANDING_WRITES 16 +#endif + +#ifndef AXI_LIMIT1_MAX_BEATS_BYTES +#define AXI_LIMIT1_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT1_MEM_TYPE +#define AXI_LIMIT1_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_READS +#define AXI_LIMIT1_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT1_MAX_OUTSTANDING_WRITES 16 +#endif + +#ifndef AXI_LIMIT2_MAX_BEATS_BYTES +#define AXI_LIMIT2_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT2_MEM_TYPE +#define AXI_LIMIT2_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_READS +#define AXI_LIMIT2_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT2_MAX_OUTSTANDING_WRITES 16 +#endif + +#ifndef AXI_LIMIT3_MAX_BEATS_BYTES +#define AXI_LIMIT3_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT3_MEM_TYPE +#define AXI_LIMIT3_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_READS +#define AXI_LIMIT3_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT3_MAX_OUTSTANDING_WRITES 16 +#endif + +#endif /* #ifndef ETHOSU_CONFIG_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h new file mode 100644 index 0000000..b115f43 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019-2020,2022 Arm Limited. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_CONFIG_H +#define ETHOSU_CONFIG_H + +/* Set default values if not manually overriden */ + +#ifndef NPU_QCONFIG +#define NPU_QCONFIG 2 +#endif + +#ifndef NPU_REGIONCFG_0 +#define NPU_REGIONCFG_0 3 +#endif + +#ifndef NPU_REGIONCFG_1 +#define NPU_REGIONCFG_1 2 +#endif + +#ifndef NPU_REGIONCFG_2 +#define NPU_REGIONCFG_2 1 +#endif + +#ifndef NPU_REGIONCFG_3 +#define NPU_REGIONCFG_3 1 +#endif + +#ifndef NPU_REGIONCFG_4 +#define NPU_REGIONCFG_4 1 +#endif + +#ifndef NPU_REGIONCFG_5 +#define NPU_REGIONCFG_5 1 +#endif + +#ifndef NPU_REGIONCFG_6 +#define NPU_REGIONCFG_6 1 +#endif + +#ifndef NPU_REGIONCFG_7 +#define NPU_REGIONCFG_7 1 +#endif + +#ifndef AXI_LIMIT0_MAX_BEATS_BYTES +#define AXI_LIMIT0_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT0_MEM_TYPE +#define AXI_LIMIT0_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_READS +#define AXI_LIMIT0_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT0_MAX_OUTSTANDING_WRITES 32 +#endif + +#ifndef AXI_LIMIT1_MAX_BEATS_BYTES +#define AXI_LIMIT1_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT1_MEM_TYPE +#define AXI_LIMIT1_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_READS +#define AXI_LIMIT1_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT1_MAX_OUTSTANDING_WRITES 32 +#endif + +#ifndef AXI_LIMIT2_MAX_BEATS_BYTES +#define AXI_LIMIT2_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT2_MEM_TYPE +#define AXI_LIMIT2_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_READS +#define AXI_LIMIT2_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT2_MAX_OUTSTANDING_WRITES 32 +#endif + +#ifndef AXI_LIMIT3_MAX_BEATS_BYTES +#define AXI_LIMIT3_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT3_MEM_TYPE +#define AXI_LIMIT3_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_READS +#define AXI_LIMIT3_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT3_MAX_OUTSTANDING_WRITES 32 +#endif + +#endif /* #ifndef ETHOSU_CONFIG_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h new file mode 100644 index 0000000..3cc1f97 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h @@ -0,0 +1,112 @@ +/* + * SPDX-FileCopyrightText: Copyright 2020, 2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_CONFIG_U85_H +#define ETHOSU_CONFIG_U85_H + +/* Set default values if not manually overriden */ + +/* MAC power ramping up/down control + * NOTE: Actual number of cycles is 4*NPU_MAC_PWR_RAMP_CYCLES + */ +#ifndef NPU_MAC_PWR_RAMP_CYCLES +#define NPU_MAC_PWR_RAMP_CYCLES 0 /* Valid range 0-63, where 0 disables power ramping */ +#endif + +/* Default MEM_ATTR entries */ +#ifndef NPU_MEM_ATTR_0 +#define NPU_MEM_ATTR_0 0 /* SRAM AXI port, non_sharable, device_non_bufferable */ +#endif + +#ifndef NPU_MEM_ATTR_1 +#define NPU_MEM_ATTR_1 0 /* SRAM AXI port, non_sharable, device_non_bufferable */ +#endif + +#ifndef NPU_MEM_ATTR_2 +#define NPU_MEM_ATTR_2 (1 << 2) /* EXT AXI port, non_sharable, device_non_bufferable */ +#endif + +#ifndef NPU_MEM_ATTR_3 +#define NPU_MEM_ATTR_3 (1 << 2) /* EXT AXI port, non_sharable, device_non_bufferable */ +#endif + +/* Default MEM_ATTR index to use for command stream */ +#ifndef NPU_QCONFIG +#define NPU_QCONFIG 2 +#endif + +/* Default MEM_ATTR index to use for regions 0-7 */ +#ifndef NPU_REGIONCFG_0 +#define NPU_REGIONCFG_0 3 +#endif + +#ifndef NPU_REGIONCFG_1 +#define NPU_REGIONCFG_1 0 +#endif + +#ifndef NPU_REGIONCFG_2 +#define NPU_REGIONCFG_2 1 +#endif + +#ifndef NPU_REGIONCFG_3 +#define NPU_REGIONCFG_3 1 +#endif + +#ifndef NPU_REGIONCFG_4 +#define NPU_REGIONCFG_4 1 +#endif + +#ifndef NPU_REGIONCFG_5 +#define NPU_REGIONCFG_5 1 +#endif + +#ifndef NPU_REGIONCFG_6 +#define NPU_REGIONCFG_6 1 +#endif + +#ifndef NPU_REGIONCFG_7 +#define NPU_REGIONCFG_7 1 +#endif + +/* AXI SRAM/EXT limits + * Set defaults to max. Hardware can be configured to cap at lower values. + */ +#ifndef AXI_LIMIT_SRAM_MAX_OUTSTANDING_READ_M1 +#define AXI_LIMIT_SRAM_MAX_OUTSTANDING_READ_M1 12 +#endif + +#ifndef AXI_LIMIT_SRAM_MAX_OUTSTANDING_WRITE_M1 +#define AXI_LIMIT_SRAM_MAX_OUTSTANDING_WRITE_M1 16 +#endif + +#ifndef AXI_LIMIT_SRAM_MAX_BEATS +#define AXI_LIMIT_SRAM_MAX_BEATS 2 /* 0=64B, 1=128B, 2=256B */ +#endif + +#ifndef AXI_LIMIT_EXT_MAX_OUTSTANDING_READ_M1 +#define AXI_LIMIT_EXT_MAX_OUTSTANDING_READ_M1 64 /* Hardware max might be less */ +#endif + +#ifndef AXI_LIMIT_EXT_MAX_OUTSTANDING_WRITE_M1 +#define AXI_LIMIT_EXT_MAX_OUTSTANDING_WRITE_M1 32 +#endif + +#ifndef AXI_LIMIT_EXT_MAX_BEATS +#define AXI_LIMIT_EXT_MAX_BEATS 2 /* 0=64B, 1=128B, 2=256B */ +#endif + +#endif /* #ifndef ETHOSU_CONFIG_U85_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h new file mode 100644 index 0000000..3567da4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_DEVICE_H +#define ETHOSU_DEVICE_H + +/****************************************************************************** + * Includes + ******************************************************************************/ +#include "ethosu_types.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Prototypes + ******************************************************************************/ + +/** + * Initialize the device. + */ +bool ethosu_dev_init(struct ethosu_device *dev, void *base_address, uint32_t secure_enable, uint32_t privilege_enable); + +/** + * Initialize AXI settings for device. + */ +enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev); + +/** + * Execute a given command stream on NPU. + * \param[in] cmd_stream_ptr Pointer to the command stream + * \param[in] cms_length Command stream length + * \param[in] base_addr Pointer to array of base addresses + * - 0: weight tensor + * - 1: scratch tensor + * - All input tensors + * - All output tensors + * \param[in] num_base_addr Number of base addresses. + */ +void ethosu_dev_run_command_stream(struct ethosu_device *dev, + const uint8_t *cmd_stream_ptr, + uint32_t cms_length, + const uint64_t *base_addr, + int num_base_addr); + +/** + * Print information on NPU error status + */ +void ethosu_dev_print_err_status(struct ethosu_device *dev); + +/** + * Interrupt handler on device layer + * \return true if NPU status is OK, otherwise false + */ +bool ethosu_dev_handle_interrupt(struct ethosu_device *dev); + +/** + * Get hardware information from NPU + * \param[out] hwinfo Pointer to the hardware info struct to be filled in. + */ +void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo); + +/** + * Verify that requested security state and privilege mode are active + * \return 32 bit status value + */ +bool ethosu_dev_verify_access_state(struct ethosu_device *dev); + +/** + * Performs a NPU soft reset and waits for the NPU to become ready + * \return \ref ethosu_error_codes + */ +enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev); + +/** + * Enable/disable clock and power using clock/power q interface. + * \param[in] clock_q Clock q ENABLE/DISABLE \ref clock_q_request. + * \param[in] power_q Power q ENABLE/DISABLE \ref power_q_request. + * \return \ref ethosu_error_codes + */ +enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev, + enum ethosu_clock_q_request clock_q, + enum ethosu_power_q_request power_q); + +/** + * Verifies that optimizer parameters from model are compatible with the hardware + * \param[in] cfg Config data from optimizer. + * \param[in] id Id data from optimizer. + * \return true if parameters match with hardware, false otherwise. + */ +bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in); + +#ifdef __cplusplus +} +#endif + +#endif // ETHOSU_DEVICE_H diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c new file mode 100644 index 0000000..24e8949 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c @@ -0,0 +1,373 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "ethosu_interface.h" + +#include "ethosu_device.h" +#include "ethosu_log.h" + +#ifdef ETHOSU55 +#include "ethosu_config_u55.h" +#else +#include "ethosu_config_u65.h" +#endif + +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define ETHOSU_PRODUCT_U55 0 +#define ETHOSU_PRODUCT_U65 1 + +#define BASEP_OFFSET 4 + +#ifdef ETHOSU65 +#define ADDRESS_BITS 40 +#else +#define ADDRESS_BITS 32 +#endif + +#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1) + +#define NPU_CMD_PWR_CLK_MASK (0xC) + +/****************************************************************************** + * Functions + ******************************************************************************/ + +uint64_t __attribute__((weak)) ethosu_address_remap(uint64_t address, int index) +{ + (void)(index); + return address; +} + +bool ethosu_dev_init(struct ethosu_device *dev, void *base_address, uint32_t secure_enable, uint32_t privilege_enable) +{ + dev->reg = (volatile struct NPU_REG *)base_address; + dev->secure = secure_enable; + dev->privileged = privilege_enable; + +#ifdef ETHOSU55 + if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U55) +#else + if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U65) +#endif + { + LOG_ERR("Failed to initialize device. Driver has not been compiled for this product"); + return false; + } + + // Make sure the NPU is in a known state + if (ethosu_dev_soft_reset(dev) != ETHOSU_SUCCESS) + { + return false; + } + + return true; +} + +enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev) +{ + struct regioncfg_r rcfg = {0}; + struct axi_limit0_r l0 = {0}; + struct axi_limit1_r l1 = {0}; + struct axi_limit2_r l2 = {0}; + struct axi_limit3_r l3 = {0}; + + dev->reg->QCONFIG.word = NPU_QCONFIG; + + rcfg.region0 = NPU_REGIONCFG_0; + rcfg.region1 = NPU_REGIONCFG_1; + rcfg.region2 = NPU_REGIONCFG_2; + rcfg.region3 = NPU_REGIONCFG_3; + rcfg.region4 = NPU_REGIONCFG_4; + rcfg.region5 = NPU_REGIONCFG_5; + rcfg.region6 = NPU_REGIONCFG_6; + rcfg.region7 = NPU_REGIONCFG_7; + dev->reg->REGIONCFG.word = rcfg.word; + + l0.max_beats = AXI_LIMIT0_MAX_BEATS_BYTES; + l0.memtype = AXI_LIMIT0_MEM_TYPE; + l0.max_outstanding_read_m1 = AXI_LIMIT0_MAX_OUTSTANDING_READS - 1; + l0.max_outstanding_write_m1 = AXI_LIMIT0_MAX_OUTSTANDING_WRITES - 1; + + l1.max_beats = AXI_LIMIT1_MAX_BEATS_BYTES; + l1.memtype = AXI_LIMIT1_MEM_TYPE; + l1.max_outstanding_read_m1 = AXI_LIMIT1_MAX_OUTSTANDING_READS - 1; + l1.max_outstanding_write_m1 = AXI_LIMIT1_MAX_OUTSTANDING_WRITES - 1; + + l2.max_beats = AXI_LIMIT2_MAX_BEATS_BYTES; + l2.memtype = AXI_LIMIT2_MEM_TYPE; + l2.max_outstanding_read_m1 = AXI_LIMIT2_MAX_OUTSTANDING_READS - 1; + l2.max_outstanding_write_m1 = AXI_LIMIT2_MAX_OUTSTANDING_WRITES - 1; + + l3.max_beats = AXI_LIMIT3_MAX_BEATS_BYTES; + l3.memtype = AXI_LIMIT3_MEM_TYPE; + l3.max_outstanding_read_m1 = AXI_LIMIT3_MAX_OUTSTANDING_READS - 1; + l3.max_outstanding_write_m1 = AXI_LIMIT3_MAX_OUTSTANDING_WRITES - 1; + + dev->reg->AXI_LIMIT0.word = l0.word; + dev->reg->AXI_LIMIT1.word = l1.word; + dev->reg->AXI_LIMIT2.word = l2.word; + dev->reg->AXI_LIMIT3.word = l3.word; + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_run_command_stream(struct ethosu_device *dev, + const uint8_t *cmd_stream_ptr, + uint32_t cms_length, + const uint64_t *base_addr, + int num_base_addr) +{ + assert(num_base_addr <= NPU_REG_BASEP_ARRLEN); + + struct cmd_r cmd; + uint64_t qbase = ethosu_address_remap((uintptr_t)cmd_stream_ptr, -1); + assert(qbase <= ADDRESS_MASK); + LOG_DEBUG("QBASE=0x%016llx, QSIZE=%" PRIu32 ", cmd_stream_ptr=%p", qbase, cms_length, cmd_stream_ptr); + + dev->reg->QBASE.word[0] = qbase & 0xffffffff; +#ifdef ETHOSU65 + dev->reg->QBASE.word[1] = qbase >> 32; +#endif + dev->reg->QSIZE.word = cms_length; + + for (int i = 0; i < num_base_addr; i++) + { + uint64_t addr = ethosu_address_remap(base_addr[i], i); + assert(addr <= ADDRESS_MASK); + LOG_DEBUG("BASEP%d=0x%016llx", i, addr); + dev->reg->BASEP[i].word[0] = addr & 0xffffffff; +#ifdef ETHOSU65 + dev->reg->BASEP[i].word[1] = addr >> 32; +#endif + } + + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.transition_to_running_state = 1; + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); +} + +void ethosu_dev_print_err_status(struct ethosu_device *dev) +{ + LOG_ERR("NPU status=0x%08" PRIx32 ", qread=%" PRIu32 ", cmd_end_reached=%u", + dev->reg->STATUS.word, + dev->reg->QREAD.word, + dev->reg->STATUS.cmd_end_reached); +} + +bool ethosu_dev_handle_interrupt(struct ethosu_device *dev) +{ + struct cmd_r cmd; + + // Clear interrupt + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.clear_irq = 1; + dev->reg->CMD.word = cmd.word; + + // If a fault has occured, the NPU needs to be reset + if (dev->reg->STATUS.bus_status || dev->reg->STATUS.cmd_parse_error || dev->reg->STATUS.wd_fault || + dev->reg->STATUS.ecc_fault || !dev->reg->STATUS.cmd_end_reached) + { + return false; + } + + return true; +} + +bool ethosu_dev_verify_access_state(struct ethosu_device *dev) +{ + if (dev->reg->PROT.active_CSL != (dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE) || + dev->reg->PROT.active_CPL != (dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER)) + { + return false; + } + return true; +} + +enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev) +{ + // Note that after a soft-reset, the NPU is unconditionally + // powered until the next CMD gets written. + + struct reset_r reset; + + reset.word = 0; + reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER; + reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE; + + // Reset and set security level + LOG_INFO("Soft reset NPU"); + dev->reg->RESET.word = reset.word; + + // Wait until reset status indicates that reset has been completed + for (int i = 0; i < 100000 && dev->reg->STATUS.reset_status != 0; i++) + { + } + + if (dev->reg->STATUS.reset_status != 0) + { + LOG_ERR("Soft reset timed out"); + return ETHOSU_GENERIC_FAILURE; + } + + // Verify that NPU has switched security state and privilege level + if (ethosu_dev_verify_access_state(dev) != true) + { + LOG_ERR("Failed to switch security state and privilege level"); + return ETHOSU_GENERIC_FAILURE; + } + + // Reinitialize AXI settings + ethosu_dev_axi_init(dev); + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo) +{ + struct config_r cfg; + struct id_r id; + + cfg.word = dev->reg->CONFIG.word; + id.word = dev->reg->ID.word; + + hwinfo->cfg.cmd_stream_version = cfg.cmd_stream_version; + hwinfo->cfg.custom_dma = cfg.custom_dma; + hwinfo->cfg.macs_per_cc = cfg.macs_per_cc; + + hwinfo->version.arch_major_rev = id.arch_major_rev; + hwinfo->version.arch_minor_rev = id.arch_minor_rev; + hwinfo->version.arch_patch_rev = id.arch_patch_rev; + hwinfo->version.product_major = id.product_major; + hwinfo->version.version_major = id.version_major; + hwinfo->version.version_minor = id.version_minor; + hwinfo->version.version_status = id.version_status; +} + +enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev, + enum ethosu_clock_q_request clock_q, + enum ethosu_power_q_request power_q) +{ + struct cmd_r cmd = {0}; + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + + if (power_q != ETHOSU_POWER_Q_UNCHANGED) + { + cmd.power_q_enable = power_q == ETHOSU_POWER_Q_ENABLE ? 1 : 0; + } + if (clock_q != ETHOSU_CLOCK_Q_UNCHANGED) + { + cmd.clock_q_enable = clock_q == ETHOSU_CLOCK_Q_ENABLE ? 1 : 0; + } + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); + + return ETHOSU_SUCCESS; +} + +bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in) +{ + struct config_r *opt_cfg = (struct config_r *)&cfg_in; + struct config_r hw_cfg; + struct id_r *opt_id = (struct id_r *)&id_in; + struct id_r hw_id; + bool ret = true; + + hw_cfg.word = dev->reg->CONFIG.word; + hw_id.word = dev->reg->ID.word; + + LOG_INFO("Optimizer config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, shram_size=%u, custom_dma=%u", + opt_cfg->product, + opt_cfg->cmd_stream_version, + opt_cfg->macs_per_cc, + opt_cfg->shram_size, + opt_cfg->custom_dma); + LOG_INFO("Optimizer config. arch version: %u.%u.%u", + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + LOG_INFO("Ethos-U config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, shram_size=%u, custom_dma=%u", + hw_cfg.product, + hw_cfg.cmd_stream_version, + hw_cfg.macs_per_cc, + hw_cfg.shram_size, + hw_cfg.custom_dma); + LOG_INFO("Ethos-U. arch version=%u.%u.%u", hw_id.arch_major_rev, hw_id.arch_minor_rev, hw_id.arch_patch_rev); + + if (opt_cfg->word != hw_cfg.word) + { + if (hw_cfg.product != opt_cfg->product) + { + LOG_ERR("NPU config mismatch. npu.product=%u, optimizer.product=%u", hw_cfg.product, opt_cfg->product); + ret = false; + } + + if (hw_cfg.macs_per_cc != opt_cfg->macs_per_cc) + { + LOG_ERR("NPU config mismatch. npu.macs_per_cc=%u, optimizer.macs_per_cc=%u", + hw_cfg.macs_per_cc, + opt_cfg->macs_per_cc); + ret = false; + } + + if (hw_cfg.cmd_stream_version != opt_cfg->cmd_stream_version) + { + LOG_ERR("NPU config mismatch. npu.cmd_stream_version=%u, optimizer.cmd_stream_version=%u", + hw_cfg.cmd_stream_version, + opt_cfg->cmd_stream_version); + ret = false; + } + + if (!hw_cfg.custom_dma && opt_cfg->custom_dma) + { + LOG_ERR("NPU config mismatch. npu.custom_dma=%u, optimizer.custom_dma=%u", + hw_cfg.custom_dma, + opt_cfg->custom_dma); + ret = false; + } + } + + if ((hw_id.arch_major_rev != opt_id->arch_major_rev) || (hw_id.arch_minor_rev < opt_id->arch_minor_rev)) + { + LOG_ERR("NPU arch mismatch. npu.arch=%u.%u.%u, optimizer.arch=%u.%u.%u", + hw_id.arch_major_rev, + hw_id.arch_minor_rev, + hw_id.arch_patch_rev, + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + ret = false; + } + + return ret; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c new file mode 100644 index 0000000..098320c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c @@ -0,0 +1,373 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * Includes + ******************************************************************************/ +#include "ethosu85_interface.h" + +#include "ethosu_config_u85.h" +#include "ethosu_device.h" +#include "ethosu_log.h" + +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define ETHOSU_PRODUCT_U85 2 + +#define BASEP_OFFSET 4 + +#define ADDRESS_BITS 40 + +#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1) + +#define NPU_CMD_PWR_CLK_MASK (0xC) +#define NPU_MAC_PWR_RAMP_CYCLES_MASK (0x3F) + +/****************************************************************************** + * Functions + ******************************************************************************/ + +uint64_t __attribute__((weak)) ethosu_address_remap(uint64_t address, int index) +{ + (void)(index); + return address; +} + +bool ethosu_dev_init(struct ethosu_device *dev, void *base_address, uint32_t secure_enable, uint32_t privilege_enable) +{ + dev->reg = (volatile struct NPU_REG *)base_address; + dev->secure = secure_enable; + dev->privileged = privilege_enable; + + if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U85) + { + LOG_ERR("Failed to initialize device. Driver has not been compiled for this product"); + return false; + } + + // Make sure the NPU is in a known state + if (ethosu_dev_soft_reset(dev) != ETHOSU_SUCCESS) + { + return false; + } + + return true; +} + +enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev) +{ + struct regioncfg_r rcfg = {0}; + struct axi_sram_r axi_s = {0}; + struct axi_ext_r axi_e = {0}; + + // Configure MEM_ATTR array. These are user configurable, + // and each region will be set to use one of the entries + // as its config. + dev->reg->MEM_ATTR[0].word = NPU_MEM_ATTR_0; + dev->reg->MEM_ATTR[1].word = NPU_MEM_ATTR_1; + dev->reg->MEM_ATTR[2].word = NPU_MEM_ATTR_2; + dev->reg->MEM_ATTR[3].word = NPU_MEM_ATTR_3; + + // Set MEM_ATTR entry for command stream + dev->reg->QCONFIG.word = NPU_QCONFIG; + + // Set MEM_ATTR entries to use for regions 0-7 + rcfg.region0 = NPU_REGIONCFG_0; + rcfg.region1 = NPU_REGIONCFG_1; + rcfg.region2 = NPU_REGIONCFG_2; + rcfg.region3 = NPU_REGIONCFG_3; + rcfg.region4 = NPU_REGIONCFG_4; + rcfg.region5 = NPU_REGIONCFG_5; + rcfg.region6 = NPU_REGIONCFG_6; + rcfg.region7 = NPU_REGIONCFG_7; + dev->reg->REGIONCFG.word = rcfg.word; + + // Set AXI limits on SRAM AXI interfaces + axi_s.max_outstanding_read_m1 = AXI_LIMIT_SRAM_MAX_OUTSTANDING_READ_M1 - 1; + axi_s.max_outstanding_write_m1 = AXI_LIMIT_SRAM_MAX_OUTSTANDING_WRITE_M1 - 1; + axi_s.max_beats = AXI_LIMIT_SRAM_MAX_BEATS; + dev->reg->AXI_SRAM.word = axi_s.word; + + // Set AXI limits on EXT AXI interface(s) + axi_e.max_outstanding_read_m1 = AXI_LIMIT_EXT_MAX_OUTSTANDING_READ_M1 - 1; + axi_e.max_outstanding_write_m1 = AXI_LIMIT_EXT_MAX_OUTSTANDING_WRITE_M1 - 1; + axi_e.max_beats = AXI_LIMIT_EXT_MAX_BEATS; + dev->reg->AXI_EXT.word = axi_e.word; + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_run_command_stream(struct ethosu_device *dev, + const uint8_t *cmd_stream_ptr, + uint32_t cms_length, + const uint64_t *base_addr, + int num_base_addr) +{ + assert(num_base_addr <= NPU_REG_BASEP_ARRLEN); + + struct cmd_r cmd; + uint64_t qbase = ethosu_address_remap((uintptr_t)cmd_stream_ptr, -1); + assert(qbase <= ADDRESS_MASK); + LOG_DEBUG("QBASE=0x%016llx, QSIZE=%" PRIu32 ", cmd_stream_ptr=%p", qbase, cms_length, cmd_stream_ptr); + + dev->reg->QBASE.word[0] = qbase & 0xffffffff; + dev->reg->QBASE.word[1] = qbase >> 32; + dev->reg->QSIZE.word = cms_length; + + for (int i = 0; i < num_base_addr; i++) + { + uint64_t addr = ethosu_address_remap(base_addr[i], i); + assert(addr <= ADDRESS_MASK); + LOG_DEBUG("BASEP%d=0x%016llx", i, addr); + dev->reg->BASEP[i].word[0] = addr & 0xffffffff; + dev->reg->BASEP[i].word[1] = addr >> 32; + } + + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.transition_to_running_state = 1; + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); +} + +void ethosu_dev_print_err_status(struct ethosu_device *dev) +{ + LOG_ERR("NPU status=0x%08" PRIx32 ", qread=%" PRIu32 ", cmd_end_reached=%u", + dev->reg->STATUS.word, + dev->reg->QREAD.word, + dev->reg->STATUS.cmd_end_reached); +} + +bool ethosu_dev_handle_interrupt(struct ethosu_device *dev) +{ + struct cmd_r cmd; + + // Clear interrupt + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.clear_irq = 1; + dev->reg->CMD.word = cmd.word; + + // If a fault has occured, the NPU needs to be reset + if (dev->reg->STATUS.bus_status || dev->reg->STATUS.cmd_parse_error || dev->reg->STATUS.branch_fault || + dev->reg->STATUS.ecc_fault || !dev->reg->STATUS.cmd_end_reached) + { + return false; + } + + return true; +} + +bool ethosu_dev_verify_access_state(struct ethosu_device *dev) +{ + if (dev->reg->PROT.active_CSL != (dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE) || + dev->reg->PROT.active_CPL != (dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER)) + { + return false; + } + return true; +} + +enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev) +{ + struct reset_r reset; + + reset.word = 0; + reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER; + reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE; + + // Reset and set security level + LOG_INFO("Soft reset NPU"); + dev->reg->RESET.word = reset.word; + + // Wait until reset status indicates that reset has been completed + for (int i = 0; i < 100000 && dev->reg->STATUS.reset_status != 0; i++) + { + } + + if (dev->reg->STATUS.reset_status != 0) + { + LOG_ERR("Soft reset timed out"); + return ETHOSU_GENERIC_FAILURE; + } + + // Verify that NPU has switched security state and privilege level + if (ethosu_dev_verify_access_state(dev) != true) + { + LOG_ERR("Failed to switch security state and privilege level"); + return ETHOSU_GENERIC_FAILURE; + } + + // Reinitialize AXI settings + ethosu_dev_axi_init(dev); + + // MAC power ramping up/down control + dev->reg->POWER_CTRL.word = (NPU_MAC_PWR_RAMP_CYCLES & NPU_MAC_PWR_RAMP_CYCLES_MASK); + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo) +{ + struct config_r cfg; + struct id_r id; + + cfg.word = dev->reg->CONFIG.word; + id.word = dev->reg->ID.word; + + hwinfo->cfg.cmd_stream_version = cfg.cmd_stream_version; + hwinfo->cfg.custom_dma = cfg.custom_dma; + hwinfo->cfg.macs_per_cc = cfg.macs_per_cc; + + hwinfo->version.arch_major_rev = id.arch_major_rev; + hwinfo->version.arch_minor_rev = id.arch_minor_rev; + hwinfo->version.arch_patch_rev = id.arch_patch_rev; + hwinfo->version.product_major = id.product_major; + hwinfo->version.version_major = id.version_major; + hwinfo->version.version_minor = id.version_minor; + hwinfo->version.version_status = id.version_status; +} + +enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev, + enum ethosu_clock_q_request clock_q, + enum ethosu_power_q_request power_q) +{ + struct cmd_r cmd = {0}; + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + + if (power_q != ETHOSU_POWER_Q_UNCHANGED) + { + cmd.power_q_enable = power_q == ETHOSU_POWER_Q_ENABLE ? 1 : 0; + } + if (clock_q != ETHOSU_CLOCK_Q_UNCHANGED) + { + cmd.clock_q_enable = clock_q == ETHOSU_CLOCK_Q_ENABLE ? 1 : 0; + } + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); + + return ETHOSU_SUCCESS; +} + +bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in) +{ + struct config_r *opt_cfg = (struct config_r *)&cfg_in; + struct config_r hw_cfg; + struct id_r *opt_id = (struct id_r *)&id_in; + struct id_r hw_id; + bool ret = true; + + hw_cfg.word = dev->reg->CONFIG.word; + hw_id.word = dev->reg->ID.word; + + LOG_INFO("Optimizer config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, num_axi_ext=%u, num_axi_sram=%u, " + "custom_dma=%u", + opt_cfg->product, + opt_cfg->cmd_stream_version, + opt_cfg->macs_per_cc, + 1U << opt_cfg->num_axi_ext, + 1U << opt_cfg->num_axi_sram, + opt_cfg->custom_dma); + + LOG_INFO("Optimizer config. arch version=%u.%u.%u", + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + + LOG_INFO("Ethos-U config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, num_axi_ext=%u, num_axi_sram=%u, " + "custom_dma=%u", + hw_cfg.product, + hw_cfg.cmd_stream_version, + hw_cfg.macs_per_cc, + 1U << hw_cfg.num_axi_ext, + 1U << hw_cfg.num_axi_sram, + hw_cfg.custom_dma); + + LOG_INFO("Ethos-U. arch version=%u.%u.%u", hw_id.arch_major_rev, hw_id.arch_minor_rev, hw_id.arch_patch_rev); + + if (opt_cfg->word != hw_cfg.word) + { + if (hw_cfg.product != opt_cfg->product) + { + LOG_ERR("NPU config mismatch. npu.product=%u, optimizer.product=%u", hw_cfg.product, opt_cfg->product); + ret = false; + } + + if (hw_cfg.macs_per_cc != opt_cfg->macs_per_cc) + { + LOG_ERR("NPU config mismatch. npu.macs_per_cc=%u, optimizer.macs_per_cc=%u", + hw_cfg.macs_per_cc, + opt_cfg->macs_per_cc); + ret = false; + } + + if (hw_cfg.num_axi_ext != opt_cfg->num_axi_ext) + { + LOG_ERR("NPU config mismatch. npu.num_axi_ext=%u, optimizer.num_axi_ext=%u", + 1U << hw_cfg.num_axi_ext, + 1U << opt_cfg->num_axi_ext); + ret = false; + } + + if (hw_cfg.num_axi_sram != opt_cfg->num_axi_sram) + { + LOG_ERR("NPU config mismatch. npu.num_axi_sram=%u, optimizer.num_axi_sram=%u", + 1U << hw_cfg.num_axi_sram, + 1U << opt_cfg->num_axi_sram); + ret = false; + } + + if (hw_cfg.cmd_stream_version != opt_cfg->cmd_stream_version) + { + LOG_ERR("NPU config mismatch. npu.cmd_stream_version=%u, optimizer.cmd_stream_version=%u", + hw_cfg.cmd_stream_version, + opt_cfg->cmd_stream_version); + ret = false; + } + + if (!hw_cfg.custom_dma && opt_cfg->custom_dma) + { + LOG_ERR("NPU config mismatch. npu.custom_dma=%u, optimizer.custom_dma=%u", + hw_cfg.custom_dma, + opt_cfg->custom_dma); + ret = false; + } + } + + if ((hw_id.arch_major_rev != opt_id->arch_major_rev) || (hw_id.arch_minor_rev < opt_id->arch_minor_rev)) + { + LOG_ERR("NPU arch mismatch. npu.arch=%u.%u.%u, optimizer.arch=%u.%u.%u", + hw_id.arch_major_rev, + hw_id.arch_minor_rev, + hw_id.arch_patch_rev, + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + ret = false; + } + + return ret; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c new file mode 100644 index 0000000..3d0c95f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c @@ -0,0 +1,808 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "ethosu_driver.h" +#include "ethosu_device.h" +#include "ethosu_log.h" + +#if defined(ETHOSU55) +#include "ethosu_config_u55.h" +#elif defined(ETHOSU65) +#include "ethosu_config_u65.h" +#elif defined(ETHOSU85) +#include "ethosu_config_u85.h" +#else +#error Missing device type macro +#endif + +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define UNUSED(x) ((void)x) + +#define BYTES_IN_32_BITS 4 +#define MASK_16_BYTE_ALIGN (0xF) +#define OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD 2 +#define DRIVER_ACTION_LENGTH_32_BIT_WORD 1 +#define ETHOSU_FOURCC ('1' << 24 | 'P' << 16 | 'O' << 8 | 'C') // "Custom Operator Payload 1" + +#define SCRATCH_BASE_ADDR_INDEX 1 +#define FAST_MEMORY_BASE_ADDR_INDEX 2 + +/****************************************************************************** + * Types + ******************************************************************************/ + +// Driver actions +enum DRIVER_ACTION_e +{ + RESERVED = 0, + OPTIMIZER_CONFIG = 1, + COMMAND_STREAM = 2, + NOP = 5, +}; + +// Custom operator payload data struct +struct cop_data_s +{ + union + { + // Driver action data + struct + { + uint8_t driver_action_command; // (valid values in DRIVER_ACTION_e) + uint8_t reserved; + + // Driver action data + union + { + // DA_CMD_OPT_CFG + struct + { + uint16_t rel_nbr : 4; + uint16_t patch_nbr : 4; + uint16_t opt_cfg_reserved : 8; + }; + + // DA_CMD_CMSTRM + struct + { + uint16_t length; + }; + + uint16_t driver_action_data; + }; + }; + + uint32_t word; + }; +}; + +// optimizer config struct +struct opt_cfg_s +{ + struct cop_data_s da_data; + uint32_t cfg; + uint32_t id; +}; + +/****************************************************************************** + * Variables + ******************************************************************************/ + +// Registered drivers linked list HEAD +static struct ethosu_driver *registered_drivers = NULL; + +/****************************************************************************** + * Weak functions - Cache + * + * Default NOP operations. Override if available on the targeted device. + ******************************************************************************/ + +/* + * Flush/clean the data cache by address and size. Passing NULL as p argument + * expects the whole cache to be flushed. + */ +void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes) +{ + UNUSED(p); + UNUSED(bytes); +} + +/* + * Invalidate the data cache by address and size. Passing NULL as p argument + * expects the whole cache to be invalidated. + */ +void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes) +{ + UNUSED(p); + UNUSED(bytes); +} + +/****************************************************************************** + * Weak functions - Semaphore/Mutex for multi NPU + * + * Following section handles the minimal sempahore and mutex implementation in + * case of baremetal applications. Weak symbols will be overridden by RTOS + * definitions and implement true thread-safety (in application layer). + ******************************************************************************/ + +struct ethosu_semaphore_t +{ + uint8_t count; +}; + +static void *ethosu_mutex; +static void *ethosu_semaphore; + +void *__attribute__((weak)) ethosu_mutex_create(void) +{ + static uint8_t mutex_placeholder; + return &mutex_placeholder; +} + +void __attribute__((weak)) ethosu_mutex_destroy(void *mutex) +{ + UNUSED(mutex); +} + +int __attribute__((weak)) ethosu_mutex_lock(void *mutex) +{ + UNUSED(mutex); + return 0; +} + +int __attribute__((weak)) ethosu_mutex_unlock(void *mutex) +{ + UNUSED(mutex); + return 0; +} + +// Baremetal implementation of creating a semaphore +void *__attribute__((weak)) ethosu_semaphore_create(void) +{ + struct ethosu_semaphore_t *sem = malloc(sizeof(*sem)); + if (sem != NULL) + { + sem->count = 0; + } + return sem; +} + +void __attribute__((weak)) ethosu_semaphore_destroy(void *sem) +{ + free((struct ethosu_semaphore_t *)sem); +} + +// Baremetal simulation of waiting/sleeping for and then taking a semaphore using intrisics +int __attribute__((weak)) ethosu_semaphore_take(void *sem, uint64_t timeout) +{ + UNUSED(timeout); + // Baremetal pseudo-example on how to trigger a timeout: + // if (timeout != ETHOSU_SEMAPHORE_WAIT_FOREVER) { + // setup_a_timer_to_call_SEV_after_time(timeout); + // } + struct ethosu_semaphore_t *s = sem; + while (s->count == 0) + { + __WFE(); + // Baremetal pseudo-example check if timeout triggered: + // if (SEV_timer_triggered()) { + // return -1; + // } + } + s->count--; + return 0; +} + +// Baremetal simulation of giving a semaphore and waking up processes using intrinsics +int __attribute__((weak)) ethosu_semaphore_give(void *sem) +{ + struct ethosu_semaphore_t *s = sem; + s->count++; + __SEV(); + return 0; +} + +/****************************************************************************** + * Weak functions - Inference begin/end callbacks + ******************************************************************************/ + +void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg) +{ + UNUSED(user_arg); + UNUSED(drv); +} + +void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, void *user_arg) +{ + UNUSED(user_arg); + UNUSED(drv); +} + +/****************************************************************************** + * Static functions + ******************************************************************************/ +static void ethosu_register_driver(struct ethosu_driver *drv) +{ + ethosu_mutex_lock(ethosu_mutex); + drv->next = registered_drivers; + registered_drivers = drv; + ethosu_mutex_unlock(ethosu_mutex); + + ethosu_semaphore_give(ethosu_semaphore); + + LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%p)", drv, drv->dev.reg); +} + +static int ethosu_deregister_driver(struct ethosu_driver *drv) +{ + struct ethosu_driver *curr; + struct ethosu_driver **prev; + + ethosu_mutex_lock(ethosu_mutex); + curr = registered_drivers; + prev = ®istered_drivers; + + while (curr != NULL) + { + if (curr == drv) + { + *prev = curr->next; + LOG_INFO("NPU driver handle %p deregistered.", drv); + ethosu_semaphore_take(ethosu_semaphore, ETHOSU_SEMAPHORE_WAIT_FOREVER); + break; + } + + prev = &curr->next; + curr = curr->next; + } + + ethosu_mutex_unlock(ethosu_mutex); + + if (curr == NULL) + { + LOG_ERR("No NPU driver handle registered at address %p.", drv); + return -1; + } + + return 0; +} + +static void ethosu_reset_job(struct ethosu_driver *drv) +{ + memset(&drv->job, 0, sizeof(struct ethosu_job)); +} + +static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s const *opt_cfg_p) +{ + LOG_INFO("Optimizer release nbr: %u patch: %u", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr); + + if (ethosu_dev_verify_optimizer_config(&drv->dev, opt_cfg_p->cfg, opt_cfg_p->id) != true) + { + return -1; + } + + return 0; +} + +static int handle_command_stream(struct ethosu_driver *drv, const uint8_t *cmd_stream, const int cms_length) +{ + uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS; + + LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length); + + if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN)) + { + LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream); + return -1; + } + + // Verify minimum 16 byte alignment for base address' + for (int i = 0; i < drv->job.num_base_addr; i++) + { + if (0 != (drv->job.base_addr[i] & MASK_16_BYTE_ALIGN)) + { + LOG_ERR("Base addr %d: 0x%" PRIx64 "not aligned to 16 bytes", i, drv->job.base_addr[i]); + return -1; + } + } + + // DEPRECATION WARNING: + // It is advised against letting the driver handle flushing/cleaning of the cache, as this will + // be done for every invokation. It is up to the application code to ensure cache coherency + // before invoking an inference. + // + // The cache flush call below will flush/clean every base pointer marked in the flush mask. + // Typically only the scratch tensor contains RW data shared between the CPU and NPU, and needs + // to be flushed/cleaned before invoking an inference. + // + // It is recommended to not implement/override the default empty ethosu_flush_dcache() weak + // function. + // + // NOTE: It is required that any base pointer marked for cache flush/clean is aligned to the + // cache line size. + + // Flush/clean the cache for base pointers marked in the mask + for (int i = 0; i < drv->job.num_base_addr; i++) + { + if (drv->basep_flush_mask & (1 << i)) + { + ethosu_flush_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]); + } + } + + // Request power gating disabled during inference run + if (ethosu_request_power(drv)) + { + LOG_ERR("Failed to request power"); + return -1; + } + + drv->job.state = ETHOSU_JOB_RUNNING; + + // Inference begin callback + ethosu_inference_begin(drv, drv->job.user_arg); + + // Execute the command stream + ethosu_dev_run_command_stream(&drv->dev, cmd_stream, cms_bytes, drv->job.base_addr, drv->job.num_base_addr); + + return 0; +} + +/****************************************************************************** + * Weak functions - Interrupt handler + ******************************************************************************/ +void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv) +{ + // Prevent race condition where interrupt triggered after a timeout waiting + // for semaphore, but before NPU is reset. + if (drv->job.result == ETHOSU_JOB_RESULT_TIMEOUT) + { + return; + } + + drv->job.state = ETHOSU_JOB_DONE; + drv->job.result = ethosu_dev_handle_interrupt(&drv->dev) ? ETHOSU_JOB_RESULT_OK : ETHOSU_JOB_RESULT_ERROR; + ethosu_semaphore_give(drv->semaphore); +} + +/****************************************************************************** + * Functions API + ******************************************************************************/ + +void ethosu_set_basep_cache_mask(struct ethosu_driver *drv, uint8_t flush_mask, uint8_t invalidate_mask) +{ + drv->basep_flush_mask = flush_mask; + drv->basep_invalidate_mask = invalidate_mask; +} + +int ethosu_init(struct ethosu_driver *drv, + void *const base_address, + const void *fast_memory, + const size_t fast_memory_size, + uint32_t secure_enable, + uint32_t privilege_enable) +{ + LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32 + ", privileged=%" PRIu32, + base_address, + fast_memory, + fast_memory_size, + secure_enable, + privilege_enable); + + if (!ethosu_mutex) + { + ethosu_mutex = ethosu_mutex_create(); + if (!ethosu_mutex) + { + LOG_ERR("Failed to create global driver mutex"); + return -1; + } + } + + if (!ethosu_semaphore) + { + ethosu_semaphore = ethosu_semaphore_create(); + if (!ethosu_semaphore) + { + LOG_ERR("Failed to create global driver semaphore"); + return -1; + } + } + + drv->fast_memory = (uintptr_t)fast_memory; + drv->fast_memory_size = fast_memory_size; + drv->power_request_counter = 0; + + // Set default cache flush/clean and invalidate base pointer masks to invalidate the scratch + // base pointer where Vela for TFLM is placing the scratch buffer (tensor arena) + ethosu_set_basep_cache_mask(drv, (1 << SCRATCH_BASE_ADDR_INDEX), (1 << SCRATCH_BASE_ADDR_INDEX)); + + // Initialize the device and set requested security state and privilege mode + if (!ethosu_dev_init(&drv->dev, base_address, secure_enable, privilege_enable)) + { + LOG_ERR("Failed to initialize Ethos-U device"); + return -1; + } + + drv->semaphore = ethosu_semaphore_create(); + if (!drv->semaphore) + { + LOG_ERR("Failed to create driver semaphore"); + return -1; + } + + ethosu_reset_job(drv); + ethosu_register_driver(drv); + + return 0; +} + +void ethosu_deinit(struct ethosu_driver *drv) +{ + ethosu_deregister_driver(drv); + ethosu_semaphore_destroy(drv->semaphore); +} + +int ethosu_soft_reset(struct ethosu_driver *drv) +{ + // Soft reset the NPU + if (ethosu_dev_soft_reset(&drv->dev) != ETHOSU_SUCCESS) + { + LOG_ERR("Failed to soft-reset NPU"); + return -1; + } + + // Update power and clock gating after the soft reset + ethosu_dev_set_clock_and_power(&drv->dev, + drv->power_request_counter > 0 ? ETHOSU_CLOCK_Q_DISABLE : ETHOSU_CLOCK_Q_ENABLE, + drv->power_request_counter > 0 ? ETHOSU_POWER_Q_DISABLE : ETHOSU_POWER_Q_ENABLE); + + return 0; +} + +int ethosu_request_power(struct ethosu_driver *drv) +{ + // Check if this is the first power request, increase counter + if (drv->power_request_counter++ == 0) + { + // Always reset to a known state. Changes to requested + // security state/privilege mode if necessary. + if (ethosu_soft_reset(drv)) + { + LOG_ERR("Failed to request power for Ethos-U"); + drv->power_request_counter--; + return -1; + } + } + return 0; +} + +void ethosu_release_power(struct ethosu_driver *drv) +{ + if (drv->power_request_counter == 0) + { + LOG_WARN("No power request left to release, reference counter is 0"); + } + else + { + // Decrement ref counter and enable power gating if no requests remain + if (--drv->power_request_counter == 0) + { + ethosu_dev_set_clock_and_power(&drv->dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE); + } + } +} + +void ethosu_get_driver_version(struct ethosu_driver_version *ver) +{ + assert(ver != NULL); + ver->major = ETHOSU_DRIVER_VERSION_MAJOR; + ver->minor = ETHOSU_DRIVER_VERSION_MINOR; + ver->patch = ETHOSU_DRIVER_VERSION_PATCH; +} + +void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw) +{ + assert(hw != NULL); + ethosu_dev_get_hw_info(&drv->dev, hw); +} + +int ethosu_wait(struct ethosu_driver *drv, bool block) +{ + int ret = 0; + + switch (drv->job.state) + { + case ETHOSU_JOB_IDLE: + LOG_ERR("Inference job not running..."); + ret = -2; + break; + case ETHOSU_JOB_RUNNING: + if (!block) + { + // Inference still running, do not block + ret = 1; + break; + } + // fall through + case ETHOSU_JOB_DONE: + // Invalidate cache for base pointers marked to be invalidated, typically the + // scratch tensor base pointer containing the tensor arena. + // NOTE: Requires the base pointers to be cache line size aligned. + for (int i = 0; i < drv->job.num_base_addr; i++) + { + if (drv->basep_invalidate_mask & (1 << i)) + { + ethosu_invalidate_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]); + } + } + + // Wait for interrupt in blocking mode. In non-blocking mode + // the interrupt has already triggered + ret = ethosu_semaphore_take(drv->semaphore, ETHOSU_SEMAPHORE_WAIT_INFERENCE); + if (ret < 0) + { + drv->job.result = ETHOSU_JOB_RESULT_TIMEOUT; + + // There's a race where the NPU interrupt can have fired between semaphore + // timing out and setting the result above (checked in interrupt handler). + // By checking if the job state has been changed (only set to DONE by interrupt + // handler), we know if the interrupt handler has run, if so decrement the + // semaphore count by one (given in interrupt handler). + if (drv->job.state == ETHOSU_JOB_DONE) + { + drv->job.result = ETHOSU_JOB_RESULT_TIMEOUT; // Reset back to timeout + ethosu_semaphore_take(drv->semaphore, ETHOSU_SEMAPHORE_WAIT_INFERENCE); + } + } + + // Inference done callback - always called even in case of timeout + ethosu_inference_end(drv, drv->job.user_arg); + + // Release power gating disabled requirement + ethosu_release_power(drv); + + // Check NPU and interrupt status + if (drv->job.result) + { + if (drv->job.result == ETHOSU_JOB_RESULT_ERROR) + { + LOG_ERR("NPU error(s) occured during inference."); + ethosu_dev_print_err_status(&drv->dev); + } + else + { + LOG_ERR("NPU inference timed out."); + } + + // Reset the NPU + (void)ethosu_soft_reset(drv); + + ret = -1; + } + else + { + LOG_DEBUG("Inference finished successfully..."); + ret = 0; + } + + // Reset internal job (state resets to IDLE) + ethosu_reset_job(drv); + break; + + default: + LOG_ERR("Unexpected job state"); + ethosu_reset_job(drv); + ret = -1; + break; + } + + // Return inference job status + return ret; +} + +int ethosu_invoke_async(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg) +{ + assert(custom_data_ptr != NULL); + assert(base_addr != NULL); + assert(base_addr_size != NULL); + + const struct cop_data_s *data_ptr = custom_data_ptr; + const struct cop_data_s *data_end = (struct cop_data_s *)((ptrdiff_t)custom_data_ptr + custom_data_size); + + // Make sure an inference is not already running + if (drv->job.state != ETHOSU_JOB_IDLE) + { + LOG_ERR("Inference already running, or waiting to be cleared..."); + return -1; + } + + drv->job.state = ETHOSU_JOB_IDLE; + drv->job.custom_data_ptr = custom_data_ptr; + drv->job.custom_data_size = custom_data_size; + drv->job.base_addr = base_addr; + drv->job.base_addr_size = base_addr_size; + drv->job.num_base_addr = num_base_addr; + drv->job.user_arg = user_arg; + + // First word in custom_data_ptr should contain "Custom Operator Payload 1" + if (data_ptr->word != ETHOSU_FOURCC) + { + LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC); + goto err; + } + + // Custom data length must be a multiple of 32 bits + if ((custom_data_size % BYTES_IN_32_BITS) != 0) + { + LOG_ERR("custom_data_size=0x%x not a multiple of 4", (unsigned)custom_data_size); + goto err; + } + + data_ptr++; + + // Adjust base address to fast memory area + if (drv->fast_memory != 0 && num_base_addr > FAST_MEMORY_BASE_ADDR_INDEX) + { + if (base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size) + { + LOG_ERR("Fast memory area too small. fast_memory_size=%zu, base_addr_size=%zu", + drv->fast_memory_size, + base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]); + goto err; + } + + base_addr[FAST_MEMORY_BASE_ADDR_INDEX] = drv->fast_memory; + } + + // Parse Custom Operator Payload data + while (data_ptr < data_end) + { + switch (data_ptr->driver_action_command) + { + case OPTIMIZER_CONFIG: + LOG_DEBUG("OPTIMIZER_CONFIG"); + struct opt_cfg_s const *opt_cfg_p = (const struct opt_cfg_s *)data_ptr; + + if (handle_optimizer_config(drv, opt_cfg_p) < 0) + { + goto err; + } + data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD; + break; + case COMMAND_STREAM: + // Vela only supports putting one COMMAND_STREAM per op + LOG_DEBUG("COMMAND_STREAM"); + const uint8_t *command_stream = (const uint8_t *)(data_ptr + 1); + int cms_length = (data_ptr->reserved << 16) | data_ptr->length; + + if (handle_command_stream(drv, command_stream, cms_length) < 0) + { + goto err; + } + data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length; + break; + case NOP: + LOG_DEBUG("NOP"); + data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD; + break; + default: + LOG_ERR("UNSUPPORTED driver_action_command: %u", data_ptr->driver_action_command); + goto err; + break; + } + } + + return 0; +err: + LOG_ERR("Failed to invoke inference."); + ethosu_reset_job(drv); + return -1; +} + +int ethosu_invoke_v3(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg) +{ + if (ethosu_invoke_async( + drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr, user_arg) < 0) + { + return -1; + } + + return ethosu_wait(drv, true); +} + +struct ethosu_driver *ethosu_reserve_driver(void) +{ + struct ethosu_driver *drv = NULL; + + LOG_INFO("Acquiring NPU driver handle"); + ethosu_semaphore_take(ethosu_semaphore, ETHOSU_SEMAPHORE_WAIT_FOREVER); // This is meant to block until available + + ethosu_mutex_lock(ethosu_mutex); + drv = registered_drivers; + + while (drv != NULL) + { + if (!drv->reserved) + { + drv->reserved = true; + LOG_DEBUG("NPU driver handle %p reserved", drv); + break; + } + drv = drv->next; + } + ethosu_mutex_unlock(ethosu_mutex); + + if (!drv) + { + LOG_ERR("No NPU driver handle available, but semaphore taken"); + } + + return drv; +} + +void ethosu_release_driver(struct ethosu_driver *drv) +{ + ethosu_mutex_lock(ethosu_mutex); + if (drv != NULL && drv->reserved) + { + if (drv->job.state == ETHOSU_JOB_RUNNING || drv->job.state == ETHOSU_JOB_DONE) + { + // Give the inference one shot to complete or force kill the job + if (ethosu_wait(drv, false) == 1) + { + // Still running, soft reset the NPU and reset driver + drv->power_request_counter = 0; + ethosu_soft_reset(drv); + ethosu_reset_job(drv); + } + } + + drv->reserved = false; + LOG_DEBUG("NPU driver handle %p released", drv); + ethosu_semaphore_give(ethosu_semaphore); + } + ethosu_mutex_unlock(ethosu_mutex); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h new file mode 100644 index 0000000..2409cb4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// clang-format off +#ifndef ETHOSU_INTERFACE_WRAPPER_ +#define ETHOSU_INTERFACE_WRAPPER_ + +#define xstr(a) str(a) +#define str(a) #a + +#define catm(a, b) catm_(a, b) +#define catm_(a, b) a##b + +#define ETHOSU_INTERFACE_FILE xstr(catm(ethos, ETHOSU_ARCH)_interface.h) + +#include ETHOSU_INTERFACE_FILE + +#endif // ETHOSU_INTERFACE_WRAPPER_ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h new file mode 100644 index 0000000..13f7726 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: Copyright 2021-2023 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_LOG_H +#define ETHOSU_LOG_H + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +// Log severity levels +#define ETHOSU_LOG_ERR 0 +#define ETHOSU_LOG_WARN 1 +#define ETHOSU_LOG_INFO 2 +#define ETHOSU_LOG_DEBUG 3 + +// Define default log severity +#ifndef ETHOSU_LOG_SEVERITY +#define ETHOSU_LOG_SEVERITY ETHOSU_LOG_WARN +#endif + +// Logs enabled by default +#ifndef ETHOSU_LOG_ENABLE +#define ETHOSU_LOG_ENABLE 1 +#endif + +#if ETHOSU_LOG_ENABLE +#define LOG_COMMON(s, f, ...) (void)fprintf(s, f, ##__VA_ARGS__) +#else +#define LOG_COMMON(s, f, ...) +#endif + +// Log formatting +#define LOG(f, ...) LOG_COMMON(stdout, f, ##__VA__ARGS__) + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_ERR +#define LOG_ERR(f, ...) \ + LOG_COMMON(stderr, "E: " f " (%s:%d)\n", ##__VA_ARGS__, strrchr("/" __FILE__, '/') + 1, __LINE__) +#else +#define LOG_ERR(f, ...) +#endif + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_WARN +#define LOG_WARN(f, ...) LOG_COMMON(stdout, "W: " f "\n", ##__VA_ARGS__) +#else +#define LOG_WARN(f, ...) +#endif + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_INFO +#define LOG_INFO(f, ...) LOG_COMMON(stdout, "I: " f "\n", ##__VA_ARGS__) +#else +#define LOG_INFO(f, ...) +#endif + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_DEBUG +#define LOG_DEBUG(f, ...) LOG_COMMON(stdout, "D: %s(): " f "\n", __FUNCTION__, ##__VA_ARGS__) +#else +#define LOG_DEBUG(f, ...) +#endif + +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c new file mode 100644 index 0000000..2681c0e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c @@ -0,0 +1,316 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * Includes + *****************************************************************************/ + +#include "ethosu_device.h" +#include "ethosu_driver.h" +#include "ethosu_interface.h" +#include "ethosu_log.h" +#include "pmu_ethosu.h" + +#include +#include +#include + +/***************************************************************************** + * Defines + *****************************************************************************/ + +#define MASK_0_31_BITS (0xFFFFFFFF) +#define MASK_32_47_BITS (0xFFFF00000000) + +#define COMMA , +#define SEMICOLON ; + +#define EVTYPE(A, name) \ + case PMU_EVENT_##name: \ + return ETHOSU_PMU_##name + +#define EVID(A, name) (PMU_EVENT_##name) + +/***************************************************************************** + * Variables + *****************************************************************************/ + +static const enum pmu_event eventbyid[] = {EXPAND_PMU_EVENT(EVID, COMMA)}; + +/***************************************************************************** + * Static functions + *****************************************************************************/ + +static enum ethosu_pmu_event_type pmu_event_type(uint32_t id) +{ + switch (id) + { + EXPAND_PMU_EVENT(EVTYPE, SEMICOLON); + default: + LOG_ERR("Unknown PMU event id: 0x%" PRIx32, id); + } + + return ETHOSU_PMU_SENTINEL; +} + +static uint32_t pmu_event_value(enum ethosu_pmu_event_type event) +{ + int a = event; + if ((a < ETHOSU_PMU_SENTINEL) && (a >= ETHOSU_PMU_NO_EVENT)) + { + return eventbyid[event]; + } + + return UINT32_MAX; +} + +/***************************************************************************** + * Functions + *****************************************************************************/ + +void ETHOSU_PMU_Enable(struct ethosu_driver *drv) +{ + LOG_DEBUG("Enable PMU"); + struct pmcr_r pmcr = {0}; + pmcr.cnt_en = 1; + ethosu_request_power(drv); + drv->dev.reg->PMCR.word = pmcr.word; +} + +void ETHOSU_PMU_Disable(struct ethosu_driver *drv) +{ + LOG_DEBUG("Disable PMU"); + drv->dev.reg->PMCR.word = 0; + ethosu_release_power(drv); +} + +uint32_t ETHOSU_PMU_Get_NumEventCounters(void) +{ + return NPU_REG_PMEVCNTR_ARRLEN; +} + +void ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + uint32_t val = pmu_event_value(type); + if (val == UINT32_MAX) + { + LOG_ERR("Invalid ethosu_pmu_event_type: %d", type); + return; + } + + LOG_DEBUG("num=%" PRIu32 ", type=%d, val=%" PRIu32, num, type, val); + drv->dev.reg->PMEVTYPER[num].word = val; +} + +enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(struct ethosu_driver *drv, uint32_t num) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + uint32_t val = drv->dev.reg->PMEVTYPER[num].word; + enum ethosu_pmu_event_type type = pmu_event_type(val); + LOG_DEBUG("num=%" PRIu32 ", type=%d, val=%" PRIu32, num, type, val); + return type; +} + +void ETHOSU_PMU_CYCCNT_Reset(struct ethosu_driver *drv) +{ + LOG_DEBUG("Reset PMU cycle counter"); + struct pmcr_r pmcr; + pmcr.word = drv->dev.reg->PMCR.word; + pmcr.cycle_cnt_rst = 1; + drv->dev.reg->PMCR.word = pmcr.word; +} + +void ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver *drv) +{ + LOG_DEBUG("Reset all events"); + struct pmcr_r pmcr; + pmcr.word = drv->dev.reg->PMCR.word; + pmcr.event_cnt_rst = 1; + drv->dev.reg->PMCR.word = pmcr.word; +} + +void ETHOSU_PMU_CNTR_Enable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMCNTENSET.word = mask; +} + +void ETHOSU_PMU_CNTR_Disable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMCNTENCLR.word = mask; +} + +uint32_t ETHOSU_PMU_CNTR_Status(struct ethosu_driver *drv) +{ + uint32_t pmcntenset = drv->dev.reg->PMCNTENSET.word; + LOG_DEBUG("mask=0x%08" PRIx32, pmcntenset); + return pmcntenset; +} + +uint64_t ETHOSU_PMU_Get_CCNTR(struct ethosu_driver *drv) +{ + uint32_t val_lo = drv->dev.reg->PMCCNTR.CYCLE_CNT_LO; + uint32_t val_hi = drv->dev.reg->PMCCNTR.CYCLE_CNT_HI; + uint64_t val = ((uint64_t)val_hi << 32) | val_lo; + + LOG_DEBUG("val=%" PRIu64, val); + return val; +} + +void ETHOSU_PMU_Set_CCNTR(struct ethosu_driver *drv, uint64_t val) +{ + uint32_t active = ETHOSU_PMU_CNTR_Status(drv) & ETHOSU_PMU_CCNT_Msk; + + LOG_DEBUG("val=%llu", val); + + if (active) + { + ETHOSU_PMU_CNTR_Disable(drv, ETHOSU_PMU_CCNT_Msk); + } + + drv->dev.reg->PMCCNTR.CYCLE_CNT_LO = val & MASK_0_31_BITS; + drv->dev.reg->PMCCNTR.CYCLE_CNT_HI = (val & MASK_32_47_BITS) >> 32; + + if (active) + { + ETHOSU_PMU_CNTR_Enable(drv, ETHOSU_PMU_CCNT_Msk); + } +} + +uint32_t ETHOSU_PMU_Get_EVCNTR(struct ethosu_driver *drv, uint32_t num) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + uint32_t val = drv->dev.reg->PMEVCNTR[num].word; + LOG_DEBUG("num=%" PRIu32 ", val=%" PRIu32, num, val); + + return val; +} + +void ETHOSU_PMU_Set_EVCNTR(struct ethosu_driver *drv, uint32_t num, uint32_t val) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + LOG_DEBUG("num=%" PRIu32 ", val=%" PRIu32, num, val); + drv->dev.reg->PMEVCNTR[num].word = val; +} + +uint32_t ETHOSU_PMU_Get_CNTR_OVS(struct ethosu_driver *drv) +{ + LOG_DEBUG(""); + return drv->dev.reg->PMOVSSET.word; +} + +void ETHOSU_PMU_Set_CNTR_OVS(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG(""); + drv->dev.reg->PMOVSCLR.word = mask; +} + +void ETHOSU_PMU_Set_CNTR_IRQ_Enable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMINTSET.word = mask; +} + +void ETHOSU_PMU_Set_CNTR_IRQ_Disable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMINTCLR.word = mask; +} + +uint32_t ETHOSU_PMU_Get_IRQ_Enable(struct ethosu_driver *drv) +{ + uint32_t pmint = drv->dev.reg->PMINTSET.word; + LOG_DEBUG("mask=0x%08" PRIx32, pmint); + return pmint; +} + +void ETHOSU_PMU_CNTR_Increment(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG(""); + uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status(drv); + + // Disable counters + ETHOSU_PMU_CNTR_Disable(drv, mask); + + // Increment cycle counter + if (mask & ETHOSU_PMU_CCNT_Msk) + { + uint64_t val = ETHOSU_PMU_Get_CCNTR(drv) + 1; + drv->dev.reg->PMCCNTR.CYCLE_CNT_LO = val & MASK_0_31_BITS; + drv->dev.reg->PMCCNTR.CYCLE_CNT_HI = (val & MASK_32_47_BITS) >> 32; + } + + for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) + { + if (mask & (1u << i)) + { + uint32_t val = ETHOSU_PMU_Get_EVCNTR(drv, i); + drv->dev.reg->PMEVCNTR[i].word = val + 1; + } + } + + // Reenable the active counters + ETHOSU_PMU_CNTR_Enable(drv, cntrs_active); +} + +void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type start_event) +{ + LOG_DEBUG("start_event=%u", start_event); + struct pmccntr_cfg_r cfg; + uint32_t val = pmu_event_value(start_event); + if (val == UINT32_MAX) + { + LOG_ERR("Invalid ethosu_pmu_event_type: %d", start_event); + return; + } + + cfg.word = drv->dev.reg->PMCCNTR_CFG.word; + cfg.CYCLE_CNT_CFG_START = val; + drv->dev.reg->PMCCNTR_CFG.word = cfg.word; +} + +void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type stop_event) +{ + LOG_DEBUG("stop_event=%u", stop_event); + struct pmccntr_cfg_r cfg; + uint32_t val = pmu_event_value(stop_event); + if (val == UINT32_MAX) + { + LOG_ERR("Invalid ethosu_pmu_event_type: %d", stop_event); + return; + } + + cfg.word = drv->dev.reg->PMCCNTR_CFG.word; + cfg.CYCLE_CNT_CFG_STOP = val; + drv->dev.reg->PMCCNTR_CFG.word = cfg.word; +} + +uint32_t ETHOSU_PMU_Get_QREAD(struct ethosu_driver *drv) +{ + uint32_t val = drv->dev.reg->QREAD.word; + LOG_DEBUG("qread=%" PRIu32, val); + return val; +} + +uint32_t ETHOSU_PMU_Get_STATUS(struct ethosu_driver *drv) +{ + uint32_t val = drv->dev.reg->STATUS.word; + LOG_DEBUG("status=0x%" PRIx32, val); + return val; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml new file mode 100644 index 0000000..08831dd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml @@ -0,0 +1,6 @@ +# Copyright (c) 2021-2022 Arm Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +name: hal_ethos_u +build: + cmake-ext: True + kconfig-ext: True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/TARGETS new file mode 100644 index 0000000..423970b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/TARGETS @@ -0,0 +1,80 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "schemas", + srcs = ["schemas/__init__.py"], + resources = [ + "schemas/tosa_1.0.fbs", + ], + visibility = ["PUBLIC"], +) + +runtime.python_library( + name = "mapping", + srcs = [ + "mapping.py", + ], + deps = [ + "fbsource//third-party/tosa_tools:serializer", + "//caffe2:torch", + ":specification", + ], +) +runtime.python_library( + name = "specification", + srcs = [ + "specification.py", + ], + deps = [ + "fbsource//third-party/pypi/packaging:packaging", + "//executorch/exir/backend:compile_spec_schema", + ], +) +runtime.python_library( + name = "utils", + srcs = [ + "utils.py", + ], + deps = [ + "//executorch/backends/arm/operators:node_visitor", + ], +) + +runtime.python_library( + name = "tosa", + srcs = [ + "__init__.py", + ], + deps = [ + ":specification", + ], +) + +runtime.python_library( + name = "compile_spec", + srcs = [ + "compile_spec.py", + ], + deps = [ + ":tosa", + ":specification", + "//executorch/backends/arm:arm_compile_spec", + ], +) + +runtime.python_library( + name = "partitioner", + srcs = [ + "backend.py", + "partitioner.py", + ], + deps = [ + ":compile_spec", + "//executorch/backends/arm:constants", + "//executorch/backends/arm:process_node", + "//executorch/backends/arm/debug:schema", + "//executorch/backends/arm/operator_support:operator_support", + "//executorch/backends/arm/_passes:passes", + "//executorch/exir:lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/__init__.py new file mode 100644 index 0000000..3086064 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/__init__.py @@ -0,0 +1,9 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +from .specification import TosaSpecification + +__all__ = ["TosaSpecification"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/backend.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/backend.py new file mode 100644 index 0000000..cb67d12 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/backend.py @@ -0,0 +1,443 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide TOSA backend entry points for the Arm ExecuTorch integration. + +Implement the Ahead-of-Time (AoT) preprocessing path that lowers an +``ExportedProgram`` to a TOSA flatbuffer using Arm's lowering pipeline. Use +this module either as a standalone backend that produces a TOSA artifact or as +part of a composed pipeline for hardware backends that consume TOSA as an +intermediate form. + +Use ``TOSABackend.preprocess`` to return the serialized TOSA flatbuffer that +subsequent stages (for example, JIT or hardware-specific compilers) consume. + +""" + +import logging +import tempfile +from itertools import count +from typing import cast, Dict, final, List + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.debug import debug_fail, debug_tosa_dump +from executorch.backends.arm.debug.schema import DebugHook +from executorch.backends.arm.process_node import ( + process_call_function, + process_output, + process_placeholder, +) +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.mapping import TOSA_TENSOR_NAME_META +from executorch.exir.backend.backend_details import BackendDetails, PreprocessResult +from executorch.exir.backend.compile_spec_schema import CompileSpec +from executorch.exir.dim_order_utils import get_memory_format +from executorch.exir.graph_module import get_cond_while_submodules +from torch.export.exported_program import ExportedProgram +from torch.fx import Graph, GraphModule, Node + +# TOSA backend debug functionality +logger = logging.getLogger(__name__) + + +def _annotate_external_ids(ep_graph: Graph) -> Dict[str, int]: + """Assign deterministic output IDs to leaf outputs. + + Flattens the output structure and assigns the external ID + based on the leaf position in the exported output tuple/list. + + Args: + ep_graph (Graph): FX graph produced by export preprocessing. + + Returns: + dict[str, int]: Mapping from *leaf output node name* to external output index. + """ + node2external_id = {} + + def _collect_leaves(arg, nodes): + # Collect only FX Nodes that are actual outputs + # (ignore ints/None/etc inside structured outputs). + if isinstance(arg, Node): + nodes.append(arg) + elif isinstance(arg, (list, tuple)): + for a in arg: + _collect_leaves(a, nodes) + + out = ep_graph.output_node() + out_leaves: list[Node] = [] + # First argument of output is the structured container (tuple/list) of outputs + _collect_leaves(out.args[0], out_leaves) + + # Map each output leaf's name to its position + node2external_id = {leaf.name: idx for idx, leaf in enumerate(out_leaves)} + + return node2external_id + + +def _sort_outputs(graph_module: GraphModule, node_to_id_map: dict[str, int]): + """Reorder graph outputs to match ascending external IDs. + + Args: + graph_module (GraphModule): Graph to reorder in place. + node_to_id_map (dict[str, int]): Mapping from node name to output index. + + Returns: + GraphModule: Updated graph module with deterministic output ordering. + + """ + + def _external_id(n: Node, node_2_id, fallback: int) -> int: + """Return the external ID for ``n`` or ``fallback`` when absent.""" + return node_2_id.get(n.name, fallback) + + out_node = graph_module.graph.output_node() + out_list = cast(tuple, out_node.args[0]) + _counter = count() + + # sort nodes by the key that is id + def _sort_key(t: Node) -> int: + """Key function that orders outputs by external ID or position.""" + return _external_id(t, node_to_id_map, next(_counter)) + + orig_ord = tuple(sorted(out_list, key=_sort_key)) + + current_order = tuple(out_list) + if orig_ord != current_order: + replacement = list(orig_ord) if isinstance(out_node.args[0], list) else orig_ord + out_node.args = (replacement,) + graph_module.graph.lint() + graph_module.recompile() + + return graph_module + + +def _get_matching_fake_tensor(node: Node): + """Return a fake tensor with the same properties as node, + but with .dim_order() == node.meta["tosa_dim_order"] + """ + fake_tensor = node.meta["val"] + desired_dim_order = node.meta["tosa_dim_order"] + return fake_tensor.to(memory_format=get_memory_format(list(desired_dim_order))) + + +def arm_get_first_delegation_tag(graph_module) -> str: + """Return the first delegation tag discovered in the FX graph. + + Args: + graph_module (GraphModule): Module produced by Arm partitioning. + + Returns: + str: First non-empty delegation tag or an empty string when no tag is + recorded. + + """ + for node in graph_module.graph.nodes: + tag = node.meta.get("delegation_tag") + if tag: + return tag + + logger.debug("No delegation tag found in partition.") + return "" + + +@final +class TOSABackend(BackendDetails): + """Provide a backend for lowering programs to TOSA. + + Use this class standalone to produce a TOSA representation, or as part of a + composed pipeline for hardware backends that consume TOSA. + + """ + + @staticmethod + def preprocess(edge_program: ExportedProgram, compile_specs: List[CompileSpec]): + """Convert an exported program using the provided compile specs. + + Args: + edge_program (ExportedProgram): Program generated by Torch export. + compile_specs (List[CompileSpec]): Raw compile specifications from + ``executorch.apply_backend``. + + Returns: + PreprocessResult: Result containing serialized TOSA bytes. + + """ + return TOSABackend._preprocess( + edge_program, TosaCompileSpec.from_list(compile_specs) + ) + + @staticmethod + def _preprocess( # noqa: C901 + edge_program: ExportedProgram, + compile_spec: TosaCompileSpec, + ) -> PreprocessResult: + """Lower an exported program to a TOSA flatbuffer. + + Apply Arm transformation passes to ``edge_program``, then walk the + transformed FX graph to emit a TOSA graph via the serializer. When + requested in ``compile_spec``, write additional debug artifacts. + + Args: + edge_program (ExportedProgram): Program to lower to TOSA. + compile_spec (TosaCompileSpec): Backend options. Recognized keys: + - output_format: Must be "tosa". + - tosa_spec: Target TOSA version/capabilities. + - debug_artifact_path: Directory for debug outputs. + - compile_flags: Optional backend flags. + - dump_debug_info: Enable extra debug JSON dump. + + Returns: + PreprocessResult: Result containing processed_bytes with the + serialized TOSA flatbuffer. + + Raises: + ValueError: If output_format is not "tosa" or the TOSA + specification is missing from compile_spec. + RuntimeError: If an unsupported FX node type is encountered. + + """ + # if a debug/test build capture output files from TOSA stage + artifact_path = compile_spec.get_intermediate_path() + tosa_spec = compile_spec.tosa_spec + dump_debug_info = compile_spec.tosa_debug_mode + debug_hook = None + if dump_debug_info is not None: + debug_hook = DebugHook(dump_debug_info) + + logger.info(f"Converting ExportedProgram to TOSA: {tosa_spec}") + + # Converted output for this subgraph, serializer needs path early as it emits + # const data directly. Path created and data written only in debug builds. + if not artifact_path: + artifact_path = "" + + version = tosa_spec.version + tosa_graph = ts.TosaSerializer( + artifact_path, + targetMajor=version.major, + targetMinor=version.minor, + targetPatch=version.micro, + targetDraft=False, + ) + + if not ( + tosa_spec.version.major == ts.TOSA_VERSION_MAJOR + and tosa_spec.version.minor <= ts.TOSA_VERSION_MINOR + ): + raise RuntimeError( + f"TOSA serializer version " + f"({ts.TOSA_VERSION_MAJOR}.{ts.TOSA_VERSION_MINOR}) " + f"doesn't match specification {tosa_spec}" + ) + + TOSABackend._preprocess_module( + edge_program.graph_module, + edge_program, + compile_spec, + tosa_graph, + debug_hook, + ) + # Serialize and return the TOSA flatbuffer. + binary = tosa_graph.serialize() + + if artifact_path: + tag = arm_get_first_delegation_tag(edge_program.graph_module) + + # Only dump TOSA if we are not saving to temporary folder. + if len( + tempdir := tempfile.gettempdir() + ) > 0 and not artifact_path.startswith(tempdir): + debug_tosa_dump( + binary, + artifact_path, + suffix="{}".format(f"_{tag}" if tag else "") + (f"_{tosa_spec}"), + ) + + if debug_hook is not None: + if debug_hook.mode == ArmCompileSpec.DebugMode.JSON: + json_output = debug_hook.serialize() + with open(f"{artifact_path}/debug.json", "w") as f: + f.write(json_output) + + return PreprocessResult(processed_bytes=binary) + + @staticmethod + def _regularize_submodule(submodule: GraphModule, submodule_node: Node): + """To make a submodule fit into the normal flow of a graph_module, we need to do some regularizations. + + - Buffers created before passes are treated as input to the submodule. Buffers created during passes + are treated as "normal" buffers, i.e. gathered from the state_dict. + To make it easy to tell them apart, mark all placeholders with "is_input = True" before running passes. + - Make sure output node args[0] is always iterable. + - Match the dim_order() of the input tensors with the dim orders of the submodule_node inputs. + - Match the dim_order() of the out tensors with the dim orders of the submodule_node outputs. + """ + submodule_inputs: list[Node] = [] + for node in submodule.graph.nodes: + if node.op == "placeholder": + node.meta["is_input"] = True + submodule_inputs.append(node) + match submodule_node.target: + case torch.ops.higher_order.cond: + args = cast(list[Node], submodule_node.args[-1]) + case torch.ops.higher_order.while_loop: + args = cast(list[Node], submodule_node.args[-2]) + cast( + list, submodule_node.args[-1] + ) + case _: + raise RuntimeError( + f"Unexpected control flow target: {submodule_node.target}" + ) + + for submodule_input, submodule_arg in zip(submodule_inputs, args, strict=True): + submodule_input.meta["val"] = _get_matching_fake_tensor(submodule_arg) + + output_node = submodule.graph.output_node() + if isinstance(output_node.args[0], Node): + output_node.update_arg(0, [output_node.args[0]]) + output_args = cast(list[Node], output_node.args[0]) + + # Not all outputs might be used, causing len(users) < len(outputs) + # Therefore, strict != True in the zip + for submodule_output, submodule_user in zip(output_args, submodule_node.users): + submodule_output.meta["val"] = _get_matching_fake_tensor(submodule_user) + + @staticmethod + def _preprocess_module( # noqa: C901 + graph_module: GraphModule, + edge_program: ExportedProgram, + compile_spec: TosaCompileSpec, + tosa_graph: ts.TosaSerializer, + debug_hook: DebugHook | None, + submodule_name: str | None = None, + containing_graph_module: GraphModule | None = None, + ): + """Convert an FX ``graph_module`` to TOSA serializer calls. + + Args: + graph_module (GraphModule): Module to lower recursively. + edge_program (ExportedProgram): Original exported program. + compile_spec (TosaCompileSpec): Backend options with TOSA settings. + tosa_graph (ts.TosaSerializer): Serializer receiving operators. + debug_hook (DebugHook | None): Optional debug instrumentation. + submodule_name (str | None): Name used when visiting nested blocks. + + Raises: + RuntimeError: If an FX node with an unsupported op kind is found. + + """ + tosa_spec = compile_spec.tosa_spec + node_to_id_map = _annotate_external_ids(graph_module.graph) + artifact_path = compile_spec.get_intermediate_path() + output_order_workaround = compile_spec.get_output_order_workaround() + + # TODO: Fix the need to lazily import this. + from executorch.backends.arm._passes import ArmPassManager + + graph_module = ArmPassManager(compile_spec).transform_to_backend_pipeline( # type: ignore + exported_program=edge_program, graph_module=graph_module + ) + + # TODO: Fix the need to lazily import this. + from executorch.backends.arm.operators.node_visitor import get_node_visitors + + node_visitors = get_node_visitors(edge_program, tosa_spec, debug_hook) + + if output_order_workaround: + logger.debug("Re-sorting outputs during TOSA lowering.") + graph_module = _sort_outputs(graph_module, node_to_id_map) + else: + logger.debug("No re-sorting outputs (workaround) during TOSA lowering.") + + if submodule_name is not None: + tosa_graph.startRegion(submodule_name) + tosa_graph.currRegion.addBasicBlock(submodule_name) + suffix = f"_{submodule_name}" + for loop_node in graph_module.graph.nodes: + loop_node.meta[TOSA_TENSOR_NAME_META] = suffix + + for node in graph_module.graph.nodes: + node = cast(Node, node) + try: + if node.op == "call_function": + process_call_function(node, tosa_graph, node_visitors, tosa_spec) + elif node.op == "placeholder": + if len(node.users) == 0 and submodule_name is None: + # In top level module, we don't need to handle unused placeholders. + # In submodules, we do need to handle them to preserve call signature. + continue + process_placeholder( + node, + tosa_graph, + edge_program, + containing_graph_module, + tosa_spec, + ) + elif node.op == "output": + process_output(node, tosa_graph, tosa_spec) + elif node.op == "get_attr": + attr = getattr(graph_module, str(node.target), None) + if attr is None: + raise RuntimeError( + "get_attr node is not targeting anything in graph module." + ) + if not isinstance(attr, GraphModule): + raise RuntimeError( + "get_attr node is not targeting a GraphModule." + ) + + # If the above conditions are ok, we don't need to handle this node here. + # Only the string value of node.target is important. + else: + # This will only happen if an unpartitioned graph is passed without + # any checking of compatibility. + raise RuntimeError(f"{node.name} is unsupported op {node.op}") + except Exception: + debug_fail(node, graph_module, tosa_graph, artifact_path) + raise + + # Recursively preprocess controlflow submodules. + for name, submodule, control_flow_node in get_cond_while_submodules( + graph_module + ): + TOSABackend._regularize_submodule(submodule, control_flow_node) + TOSABackend._preprocess_module( + submodule, + edge_program, + compile_spec, + tosa_graph, + debug_hook, + submodule_name=name, + containing_graph_module=graph_module, + ) + + @staticmethod + def filter_tosa_compile_specs( + compile_spec: ArmCompileSpec, + ) -> TosaCompileSpec: + """Extract the TOSA-specific settings from a composite compile spec. + + Args: + compile_spec (ArmCompileSpec): Compile specification that may + include both TOSA and hardware-specific options. + + Returns: + TosaCompileSpec: TOSA-only specification ready for + ``TOSABackend.preprocess``. + + """ + + pipeline_config = compile_spec.get_pass_pipeline_config() + tosa_compile_spec = TosaCompileSpec(compile_spec.tosa_spec) + tosa_compile_spec.set_pass_pipeline_config(pipeline_config) + return ( + tosa_compile_spec.dump_intermediate_artifacts_to( + compile_spec.get_intermediate_path() + ) + .dump_debug_info(compile_spec.tosa_debug_mode) + .set_output_order_workaround(compile_spec.output_order_workaround) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/compile_spec.py new file mode 100644 index 0000000..5cd72ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/compile_spec.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( # noqa: unused + ArmPassPipelineConfig, +) +from executorch.backends.arm.tosa import TosaSpecification + + +class TosaCompileSpec(ArmCompileSpec): + """Arm-specific compile spec capturing TOSA serializer requirements.""" + + def __init__(self, tosa_spec: TosaSpecification | str): + """Normalize and store the provided TOSA specification. + + Args: + tosa_spec (TosaSpecification | str): Target spec object or version + string supported by :meth:`TosaSpecification.create_from_string`. + + """ + if isinstance(tosa_spec, str): + tosa_spec = TosaSpecification.create_from_string(tosa_spec) + self._set_compile_specs(tosa_spec, []) + self.validate() + + def validate(self): + """Ensure that no unsupported compiler flags were supplied.""" + if len(self.compiler_flags) != 0: + raise ValueError( + f"TosaCompileSpec can't have compiler flags, got {self.compiler_flags}" + ) + pass + + @classmethod + def get_output_format(cls) -> str: + """Return the artifact format emitted by this compile spec.""" + return "tosa" + + @classmethod + def from_list_hook(cls, compile_spec, specs: dict[str, str]): + super().from_list_hook(compile_spec, specs) + + def _create_default_pipeline_config(self): + config = super()._create_default_pipeline_config() + return config diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/TARGETS new file mode 100644 index 0000000..398d519 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/TARGETS @@ -0,0 +1,36 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "core", + srcs = [ + "lib.py", + "ops_registration.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/backends/arm/tosa:tosa", + "//executorch/exir/dialects:lib", + ], +) + +runtime.python_library( + name = "ops", + srcs = glob(["ops/*.py"]), + deps = [ + ":core", + "//caffe2:torch", + "//executorch/backends/arm/tosa:tosa", + ], +) + +runtime.python_library( + name = "lib", + srcs = ["__init__.py"], + deps = [ + ":core", + ":ops", + "//caffe2:torch", + "//executorch/backends/arm/tosa:tosa", + "//executorch/exir/dialects:lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/__init__.py new file mode 100644 index 0000000..152f99d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.tosa.dialect.ops import ( # noqa F401 + conv2d, + conv3d, + depthwise_conv2d, + matmul, + rescale, + resize, + table, + transpose, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/lib.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/lib.py new file mode 100644 index 0000000..ed26a21 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/lib.py @@ -0,0 +1,85 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable + +from executorch.exir.dialects._ops import _BACKEND_OP_LIB, ops as exir_ops +from torch.library import Library, register_fake +from torchgen.model import FunctionSchema + +# create a torch library for the TOSA dialect +# This defines a library to include Backend Dialect Operators in Executorch +tosa_lib = Library("tosa", "DEF") + + +def register_tosa_dialect_op(op_schema, func) -> Callable: + """Register a TOSA dialect operator with the backend op library. + + Args: + op_schema (str): Operator schema without namespace or overload name. + func (Callable): Fake implementation used for registration. + + Returns: + Callable: Backend dialect operator handle exposed via ``exir_ops`` and + marked ``not_callable`` for runtime use. + + """ + if tosa_lib.ns not in _BACKEND_OP_LIB: + _BACKEND_OP_LIB.append(tosa_lib.ns) + + if "::" in op_schema: + raise ValueError("The schema should not contain a namespace.") + + # Parse the op_schema into a FunctionSchema + func_schema = FunctionSchema.parse(op_schema) + overload_name = func_schema.name.overload_name + if overload_name: + raise ValueError( + "The TOSA dialect does not support overload names in the op schema." + ) + + opname = func_schema.name.name.base + tosa_lib.define(op_schema) + + overload_name = "default" + op_qualified_name = f"{tosa_lib.ns}::{opname}" + + register_fake(op_qualified_name, func, lib=tosa_lib) + + op = getattr(getattr(getattr(exir_ops.backend, tosa_lib.ns), opname), overload_name) + + # For now, since the TOSA operators are only used for lowering and serialization in the backend + # the op doesn't need to be callable. This can be changed in the future if needed to support + # execution of TOSA ops directly. + def not_callable(): + """Raise when the dialect op handle is invoked at runtime.""" + raise RuntimeError("TOSA dialect op is not callable") + + op.__equvalent_callable__ = not_callable + + return op + + +class TosaValueError(ValueError): + """Error type that annotates failures with the originating TOSA op.""" + + def __init__(self, message="A TOSA value error occurred", *args, op=None): + """Initialise the error with optional operator metadata. + + Args: + message (str): Human-readable error message. + *args: Additional arguments forwarded to ``ValueError``. + op: Optional operator identifier included in the string output. + + """ + super().__init__(message, *args) + self.op = op + + def __str__(self): + """Return the base message, appending the operator when provided.""" + base_message = super().__str__() + if self.op is not None: + return f"{base_message} (TOSA op: {self.op})" + return base_message diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv2d.py new file mode 100644 index 0000000..6d0fc22 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv2d.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Optional + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +def validate_conv2d_args_dtypes( + tosa_spec: TosaSpecification, + x: torch.Tensor, + weight: torch.Tensor, + bias: Optional[torch.Tensor] = None, + op: str = "CONV2D", +) -> torch.dtype: + output_dtype = None + supported_int_types = (torch.int8, torch.int16) + supported_float_types = ( + torch.float16, + torch.float32, + ) + if x.dtype in supported_int_types: + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support {x.dtype} but found input type {x.dtype}", + op=op, + ) + if weight.dtype not in (torch.int8,): + raise TosaValueError( + f"TOSA spec {tosa_spec} only supports {torch.int8} weights for {x.dtype} input but found {weight.dtype}", + op=op, + ) + if bias is not None and bias.dtype not in (torch.int32,): + raise TosaValueError( + f"TOSA spec {tosa_spec} only supports {torch.int32} bias for {x.dtype} input but found {bias.dtype}", + op=op, + ) + output_dtype = torch.int32 + + elif x.dtype in supported_float_types: + if not tosa_spec.support_float(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support {x.dtype} but found input type {x.dtype}", + op=op, + ) + if weight.dtype != x.dtype: + raise TosaValueError( + f"TOSA spec {tosa_spec} requires weights {weight.dtype} to be of the same type as input {x.dtype}", + op=op, + ) + if bias is not None and bias.dtype != x.dtype: + raise TosaValueError( + f"TOSA spec {tosa_spec} requires bias {bias.dtype} to be of the same type as input {x.dtype}", + op=op, + ) + output_dtype = x.dtype + else: + raise TosaValueError( + f"Unsupported input dtype {x.dtype}, supported types are {supported_int_types + supported_float_types} ", + op=op, + ) + return output_dtype + + +@register_fake_tosa_op( + "CONV2D(Tensor input, " + "Tensor weight, " + "Tensor bias, " + "int[2] stride, " + "int[4] pad, " + "int[2] dilation) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def CONV2D( + x: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor, + stride: list[int], + pad: list[int], + dilation: list[int], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + output_dtype = validate_conv2d_args_dtypes(tosa_spec, x, weight, bias, op="CONV2D") + + torch_pad = [pad[0], pad[2]] + N = x.shape[0] + C_out = weight.shape[0] + H_in, W_in = x.shape[2:] + H_out = math.floor( + (H_in + 2 * torch_pad[0] - dilation[0] * (weight.shape[2] - 1) - 1) / stride[0] + + 1 + ) + W_out = math.floor( + (W_in + 2 * torch_pad[1] - dilation[1] * (weight.shape[3] - 1) - 1) / stride[1] + + 1 + ) + output_shape = [N, C_out, H_out, W_out] + return torch.empty(size=output_shape, dtype=output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv3d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv3d.py new file mode 100644 index 0000000..9e01233 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/conv3d.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Optional + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops.conv2d import validate_conv2d_args_dtypes +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +def validate_conv3d_args_dtypes( + tosa_spec: TosaSpecification, + x: torch.Tensor, + weight: torch.Tensor, + bias: Optional[torch.Tensor] = None, +) -> torch.dtype: + if len(x.shape) != 5 or len(weight.shape) != 5: + raise TosaValueError( + f"Expected 5D input/weight tensors for CONV3D, got {x.shape} and {weight.shape}", + op="CONV3D", + ) + return validate_conv2d_args_dtypes(tosa_spec, x, weight, bias, op="CONV3D") + + +@register_fake_tosa_op( + "CONV3D(Tensor input, " + "Tensor weight, " + "Tensor bias, " + "int[3] stride, " + "int[6] pad, " + "int[3] dilation) -> Tensor", + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), +) +def CONV3D( + x: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor, + stride: list[int], + pad: list[int], + dilation: list[int], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + output_dtype = validate_conv3d_args_dtypes(tosa_spec, x, weight, bias) + + torch_pad = [pad[0], pad[2], pad[4]] + N = x.shape[0] + C_out = weight.shape[0] + D_in, H_in, W_in = x.shape[2:] + D_out = math.floor( + (D_in + 2 * torch_pad[0] - dilation[0] * (weight.shape[2] - 1) - 1) / stride[0] + + 1 + ) + H_out = math.floor( + (H_in + 2 * torch_pad[1] - dilation[1] * (weight.shape[3] - 1) - 1) / stride[1] + + 1 + ) + W_out = math.floor( + (W_in + 2 * torch_pad[2] - dilation[2] * (weight.shape[4] - 1) - 1) / stride[2] + + 1 + ) + output_shape = [N, C_out, D_out, H_out, W_out] + return torch.empty(size=output_shape, dtype=output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/depthwise_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/depthwise_conv2d.py new file mode 100644 index 0000000..81d87d9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/depthwise_conv2d.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math + +import torch +from executorch.backends.arm.tosa.dialect.ops.conv2d import validate_conv2d_args_dtypes +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +@register_fake_tosa_op( + "DEPTHWISE_CONV2D(Tensor input, " + "Tensor weight, " + "Tensor bias, " + "int[2] stride, " + "int[4] pad, " + "int[2] dialation) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def DEPTHWISE_CONV2D( + x: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor, + stride: list[int], + pad: list[int], + dilation: list[int], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + output_dtype = validate_conv2d_args_dtypes( + tosa_spec, x, weight, bias, op="DEPTHWISE_CONV2D" + ) + + torch_pad = [pad[0], pad[2]] + kernel_h, kernel_w = weight.shape[0], weight.shape[2] + C_out = weight.shape[1] * x.shape[1] + N = x.shape[0] + H_in, W_in = x.shape[2:] + H_out = math.floor( + (H_in + 2 * torch_pad[0] - dilation[0] * (kernel_h - 1) - 1) / stride[0] + 1 + ) + W_out = math.floor( + (W_in + 2 * torch_pad[1] - dilation[1] * (kernel_w - 1) - 1) / stride[1] + 1 + ) + output_shape = [N, C_out, H_out, W_out] + return torch.empty(size=output_shape, dtype=output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/matmul.py new file mode 100644 index 0000000..1ba3821 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/matmul.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_fake_tosa_op( + "MATMUL(Tensor input1, Tensor input2) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def MATMUL(x1: torch.Tensor, x2: torch.Tensor) -> torch.Tensor: + tosa_spec = get_context_spec() + """Performs matrix multiplication on two input tensors. + Additionally validates TOSA constraints of a MATMUL op. + """ + if x1.dtype != x2.dtype: + raise TosaValueError( + f"Input tensors must have the same dtype, got {x1.dtype} and {x2.dtype}", + op="MATMUL", + ) + if x1.dtype in (torch.int8, torch.int16): + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="MATMUL" + ) + else: + dtype = torch.int32 + elif x1.dtype in (torch.float16, torch.float32): + if not tosa_spec.support_float(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support float", op="MATMUL" + ) + else: + # float16 supports float16 accumulation as well + dtype = torch.float32 + else: + raise TosaValueError( + f"Input tensors must be of type int8, float16 or float32, got {x1.dtype}", + op="MATMUL", + ) + + aten_fake_tensor = exir_ops.edge.aten.bmm.default(x1, x2) + + return torch.empty_like(aten_fake_tensor, dtype=dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/rescale.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/rescale.py new file mode 100644 index 0000000..f622bbf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/rescale.py @@ -0,0 +1,53 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +@register_fake_tosa_op( + "RESCALE(Tensor input1, ScalarType dtype, float[] scale, int in_zp, int out_zp) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def RESCALE( + x: torch.Tensor, dtype: torch.dtype, scales: List[float], in_zp: int, out_zp: int +) -> torch.Tensor: + tosa_spec = get_context_spec() + """Casts the input tensor to dtype `dtype` to produce the correct tensor meta for a _rescale op. + Additionally validates TOSA constraints of a RESCALE op. + """ + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="RESCALE" + ) + + if dtype not in (torch.int32, torch.int8, torch.int16): + raise NotImplementedError( + f"tosa::rescale currently only supports int32, int16 and int8, not {dtype}" + ) + if dtype in (torch.int32, torch.int16) and out_zp != 0: + raise ValueError( + f"TOSA requires output_zp to be zero when the output dtype is {dtype}." + ) + if x.dtype in (torch.int32, torch.int16) and in_zp != 0: + raise ValueError( + f"TOSA requires input_zp to be zero when the input dtype is {dtype}" + ) + if x.dtype == torch.int8 and not -128 <= in_zp <= 127: + raise ValueError(f"{in_zp=} outside valid range (-128,127) for int8.") + if dtype == torch.int8 and not -128 <= out_zp <= 127: + raise ValueError(f"{out_zp=} outside valid range (-128,127) for int8.") + + return torch.empty_like(x, dtype=dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/resize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/resize.py new file mode 100644 index 0000000..b40b1f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/resize.py @@ -0,0 +1,66 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Literal, Optional + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops + + +# Add kwarg instead? +@register_fake_tosa_op( + "RESIZE(Tensor input, SymInt[]? output_size, bool align_corners, float[]? scale_factors, *, str resize_mode) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ), # target TOSA specifications +) +def RESIZE( + x: torch.Tensor, + output_size: list[int] | None = None, + align_corners: Optional[bool] = False, + scale_factors: list[float] | None = None, + *, + resize_mode: Literal["nearest", "bilinear"], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + if resize_mode not in ("nearest", "bilinear"): + raise TosaValueError(f"Unsupported resize mode {resize_mode} for TOSA RESIZE") + if x.dtype == torch.int8: + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="RESIZE" + ) + bilinear = resize_mode == "bilinear" + output_dtype = torch.int32 if bilinear else torch.int8 + elif x.dtype == torch.int16: + if not tosa_spec.support_integer(): + raise TosaValueError( + f"Context TOSA spec {tosa_spec} doesn't support int16", op="RESIZE" + ) + output_dtype = x.dtype + elif x.dtype in (torch.float16, torch.float32): + if not tosa_spec.support_float(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support float", op="RESIZE" + ) + output_dtype = x.dtype + else: + raise TosaValueError(f"Unsupported input dtype {x.dtype} for TOSA RESIZE") + + # Does it matter which one to use for fake tracing? + fake_aten_tensor = exir_ops.edge.aten.upsample_nearest2d.vec( + x, output_size, scale_factors + ) + + return fake_aten_tensor.to(output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/table.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/table.py new file mode 100644 index 0000000..40f592e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/table.py @@ -0,0 +1,53 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +@register_fake_tosa_op( + "TABLE(Tensor input1, Tensor table) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def TABLE(a, table): + tosa_spec = get_context_spec() + # verifiy input types according to the spec + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="TABLE" + ) + + if a.dtype == torch.int8: + if table.shape != torch.Size((256,)): + raise TosaValueError( + f"Table of wrong size ({table.shape}!={torch.Size((256,))}", op="TABLE" + ) + if table.dtype != torch.int8: + raise TosaValueError(f"Table dtype {table.dtype} is not int8", op="TABLE") + return_dtype = torch.int8 + elif a.dtype == torch.int16: + if not tosa_spec.support_extension("int16"): + raise TosaValueError( + f"Context TOSA spec {tosa_spec} doesn't support int16", op="TABLE" + ) + if table.shape != torch.Size((513,)): + raise TosaValueError( + f"Table of wrong size ({table.shape}!={torch.Size((513,))})", op="TABLE" + ) + if table.dtype != torch.int16: + raise TosaValueError(f"Table dtype {table.dtype} is not int32", op="TABLE") + return_dtype = torch.int32 + else: + raise TosaValueError(f"Unsupported dtype {a.dtype} for {tosa_spec}", op="TABLE") + + return torch.empty_like(a, dtype=return_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/transpose.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/transpose.py new file mode 100644 index 0000000..8d5bf8b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops/transpose.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import TosaSpecification + + +@register_fake_tosa_op( + "TRANSPOSE(Tensor input, int[] perms) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def TRANSPOSE(a, perms): + # The TOSA TRANSPOSE only do the transpose in the TOSA serialized world, + # so just return the same shape and type. + + # For certain operators we need the data in a specific data format. Changing tosa_dim_order + # is not sufficient as we also need transpose the data. + # By utilizing an edge IR passthrough operator we can keep the edge program in + # channels-first/contiguous and get the desired behavior in the TOSA lowering. + + if len(perms) not in (4, 5, 6): + raise TosaValueError( + f"Only 4D, 5D and 6D tensors are supported, got {len(perms)}: {perms}", + op="TRANSPOSE", + ) + + return torch.empty_like(a, dtype=a.dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops_registration.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops_registration.py new file mode 100644 index 0000000..84aa5cb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/dialect/ops_registration.py @@ -0,0 +1,68 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Callable, Iterable, List, ParamSpec, TypeVar + +from executorch.backends.arm.tosa.dialect.lib import register_tosa_dialect_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + +P = ParamSpec("P") +R = TypeVar("R") + +# The list of registered ops are not yet used, except for registration +_tosa_registered_ops: dict[TosaSpecification, list[Callable]] = { + TosaSpecification.create_from_string("TOSA-1.0+FP"): [], + TosaSpecification.create_from_string("TOSA-1.0+INT"): [], +} + +# Mapping to ensure we only register a given function once. +_registered_tosa_ops_by_func: dict[Callable, Callable] = {} + + +def register_fake_tosa_op( + op_schema: str, tosa_specs: Iterable[TosaSpecification] +) -> Callable[[Callable[P, R]], Callable[P, R]]: + """ + Decorator for registering a TOSA operation. + + Parameters: + op_schema : A string that defines the operation schema. + tosa_specs : Iterable of TOSA specification strings, + e.g. ("TOSA-1.0+INT", "TOSA-1.0+FP"). + + The decorated function is registered with the given op_schema by calling + register_tosa_dialect_op(op_schema, func) only once per function. The resulting + callable is then inserted into _tosa_registered_ops for each spec. + """ + + def decorator(func: Callable[P, R]) -> Callable[P, R]: + # Only call register_tosa_dialect_op if the function hasn't been registered yet. + if func not in _registered_tosa_ops_by_func: + op_callable = register_tosa_dialect_op(op_schema, func) + _registered_tosa_ops_by_func[func] = op_callable + else: + op_callable = _registered_tosa_ops_by_func[func] + + # For each TOSA spec, ensure the operation is added only once. + for spec in tosa_specs: + if spec not in _tosa_registered_ops: + raise ValueError(f"TOSA spec {spec} not listed for registrations") + if op_callable not in _tosa_registered_ops[spec]: + _tosa_registered_ops[spec].append(op_callable) + + # return the original function + return func + + return decorator + + +def get_registered_tosa_ops() -> List[Callable]: + tosa_spec = get_context_spec() + return _tosa_registered_ops[tosa_spec] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/mapping.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/mapping.py new file mode 100644 index 0000000..c11a046 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/mapping.py @@ -0,0 +1,309 @@ +# Copyright 2023-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide PyTorch-to-TOSA mapping helpers. + +Use these utilities to translate PyTorch dtypes and FX node metadata into the +TOSA serializer types and shapes used during initial compilation. + +""" + +import operator +from enum import Enum +from typing import Any, Optional, Sequence + +import torch +import tosa_serializer as ts +from executorch.backends.arm.tosa.specification import TosaSpecification + +TOSA_TENSOR_NAME_META = "tosa_tensor_name" + +UNSUPPORTED_DTYPES = ( + torch.float64, + torch.double, + torch.complex64, + torch.cfloat, + torch.complex128, + torch.cdouble, + torch.uint8, + torch.int64, + torch.long, +) + + +class TosaSpecialDtype(Enum): + """Special TOSA dtypes not natively expressed in PyTorch.""" + + INT48 = ts.DType.INT48 + INT4 = ts.DType.INT4 + + def get_tosa_dtype(self) -> ts.DType: + """Return the underlying ``ts.DType`` enumerant. + + Returns: + ts.DType: Serializer dtype associated with the enum entry. + + """ + return self.value + + @staticmethod + def meta_key() -> str: + """Return the FX ``meta`` key that stores special dtypes. + + Returns: + str: Metadata key used to encode :class:`TosaSpecialDtype`. + + """ + return "tosa_special_dtype" + + def max(self): + match self: + case self.INT4: + return 7 + case self.INT48: + return 2**47 - 1 + case _: + raise ValueError(f"Unrecognized TosaSpecialDtype {self}.") + + def min(self): + match self: + case self.INT4: + return -7 + case self.INT48: + return -(2**47) + case _: + raise ValueError(f"Unrecognized TosaSpecialDtype {self}.") + + +def map_dtype(data_type: torch.dtype, tosa_spec: TosaSpecification) -> Any: + """Map a ``torch.dtype`` to a ``ts.DType``. + + Args: + data_type (torch.dtype): PyTorch dtype to convert. + tosa_spec (TosaSpecification): Active spec (reserved for future checks). + + Returns: + ts.DType: Matching serializer dtype. + + Raises: + ValueError: If the dtype is unsupported or unknown. + + """ + if data_type in UNSUPPORTED_DTYPES: + raise ValueError(f"Unsupported type: {data_type}") + + dtype_map = { + torch.float32: ts.DType.FP32, + torch.float: ts.DType.FP32, + torch.float16: ts.DType.FP16, + torch.half: ts.DType.FP16, + torch.bfloat16: ts.DType.BF16, + torch.int8: ts.DType.INT8, + torch.int16: ts.DType.INT16, + torch.short: ts.DType.INT16, + torch.int32: ts.DType.INT32, + torch.int: ts.DType.INT32, + torch.bool: ts.DType.BOOL, + } + if data_type not in dtype_map: + raise ValueError(f"Unknown type: {data_type}") + return dtype_map[data_type] + + +# Returns the shape and type of a node +# TODO: other types, can be +# SymInt, FakeTensor, a List[Union[FakeTensor, SymInt]], or None +def extract_tensor_meta(meta, tosa_spec: TosaSpecification): + """Extract dtype, shape, and dimension order from FX metadata. + + Args: + meta (dict): FX node ``meta`` containing a ``val`` FakeTensor (or tuple). + tosa_spec (TosaSpecification): Active TOSA spec for dtype mapping. + + Returns: + tuple[ts.DType, tuple[int, ...], tuple[int, ...]]: Tuple containing + tensor dtype, shape, and dimension order. + + Raises: + ValueError: If ``meta['val']`` is not a ``FakeTensor``. + + """ + if meta.get("val") is None: + raise ValueError("Expected node.meta['val'] to be set to a FakeTensor") + val = meta["val"] + if type(val) is tuple: + # TODO: should use first concrete representation + val = val[0] + + if not isinstance(val, torch._subclasses.fake_tensor.FakeTensor): + raise ValueError( + f"Expected first value in node.meta['val'] to be FakeTensor, got {val.__class__}" + ) + dtype = map_dtype(val.dtype, tosa_spec) + shape = tuple(val.size()) + + if meta.get("tosa_dim_order") is not None: + dim_order = meta["tosa_dim_order"] + else: + dim_order = tuple(range(len(shape))) + return (dtype, shape, dim_order) + + +class TosaArg: + """Capture and normalize TOSA operator arguments. + + Use this to convert FX nodes, sequences, and numeric literals into a + consistent structure suitable for TOSA serialization. + + Attributes: + name (str): Node name when argument is a ``torch.fx.Node``; empty + otherwise. + dtype (ts.DType | None): Inferred dtype when available. + shape (tuple[int, ...] | None): Inferred shape when available. + dim_order (tuple[int, ...] | None): Dimension order, defaulting to + ``range(len(shape))``. + special (list | None): Captured list when the argument is a sequence. + number (float | int | None): Captured numeric value when provided. + tosa_spec (TosaSpecification): Active specification used for mapping. + multiple_output_name (list[str]): Output node names when node has multiple outputs; empty otherwise. + """ + + def __process_node(self, argument: torch.fx.Node): + """Parse a ``torch.fx.Node`` and populate tensor attributes. + + Args: + argument (torch.fx.Node): FX node to inspect. + + """ + suffix = argument.meta.get(TOSA_TENSOR_NAME_META, "") + self.name = argument.name + suffix + + if "val" in argument.meta: + output_dtype, self.shape, self.dim_order = extract_tensor_meta( + argument.meta, self.tosa_spec + ) + # Handle special case of types not representable in torch (i.e. i48_t) + if special_type := argument.meta.get(TosaSpecialDtype.meta_key(), None): + output_dtype = special_type.get_tosa_dtype() + + self.dtype = output_dtype + + # If all users of the node are getitems, node visitors should connect the output of this node directly to the getitem tensors. + # Add a new attribute 'multiple_output_names' instead of making 'name' a list to avoid ambiguity regarding the type of 'name'. + # Make name of the output is the first getitem since we in most cases only handle that output. + users = list(argument.users) + if len(users) > 0 and all(user.target == operator.getitem for user in users): + self.multiple_output_names: list = [user.name + suffix for user in users] + self.name = self.multiple_output_names[0] + else: + self.multiple_output_names = [] + + if not self.__validate(): + raise ValueError( + f"{self.tosa_spec} doesn't support tensor {self.__repr__()}" + ) + + def __process_list(self, argument): + """Capture a sequence argument as ``special``. + + Args: + argument (Sequence[Any]): Sequence to store. + + """ + self.special: list = list(argument) + + def __process_number(self, argument: float | int): + """Capture a numeric argument as ``number``. + + Args: + argument (float | int): Numeric value. + + """ + self.number: float | int = argument + + def __validate(self) -> bool: + match getattr(self, "dtype", None): + case ts.DType.FP32: + if not self.tosa_spec.support_float(): + return False + case ts.DType.INT4: + if not self.tosa_spec.support_extension("int4"): + return False + + return True + + def __init__( + self, argument: Any, tosa_spec: Optional[TosaSpecification] = None + ) -> None: + """Initialize the argument wrapper and populate fields. + + Args: + argument (Any): One of ``torch.fx.Node``, ``Sequence``, ``int``, + ``float``, ``torch.dtype``, or ``None``. + tosa_spec (Optional[TosaSpecification]): Active specification; + required for metadata extraction. + + Raises: + ValueError: If ``tosa_spec`` is missing or has the wrong type. + RuntimeError: If ``argument`` is of an unsupported type. + + """ + if tosa_spec is None: + raise ValueError("tosa_spec is None") + elif not isinstance(tosa_spec, TosaSpecification): + raise ValueError( + f"Expected tosa_spec to be a TosaSpecification, but got {tosa_spec}" + ) + self.tosa_spec = tosa_spec + + if isinstance(argument, torch.fx.Node): + self.__process_node(argument) + return + if isinstance(argument, Sequence): + self.__process_list(argument) + return + if isinstance(argument, (int, float)): + self.__process_number(argument) + return + if isinstance(argument, torch.dtype): + # Dtype is parsed from fake tensor + return + + if argument is None: + self.name = "" + self.dtype = None + self.shape = None + self.dim_order = None + return + + raise RuntimeError( + f"Unhandled node input argument: {argument}, of type {type(argument)}" + ) + + def __repr__(self): + """Return a compact representation of populated attributes. + + Returns: + str: Readable list of set attributes. + + """ + attrs = [] + if hasattr(self, "name"): + if self.name is not None: + attrs.append(f"name={self.name!r}") + if self.dtype is not None: + attrs.append(f"dtype={ts.DTypeNames[self.dtype]}") + if self.shape is not None: + attrs.append(f"shape={self.shape!r}") + if self.dim_order is not None: + attrs.append(f"dim_order={self.dim_order!r}") + if hasattr(self, "special") and self.special is not None: + attrs.append(f"special={self.special!r}") + if hasattr(self, "number") and self.number is not None: + attrs.append(f"number={self.number!r}") + if hasattr(self, "tosa_spec") and self.tosa_spec is not None: + attrs.append(f"tosa_spec={self.tosa_spec!r}") + if hasattr(self, "multiple_output_names"): + attrs.append(f"names={self.multiple_output_names!r}") + return f"{self.__class__.__name__}({', '.join(attrs)})" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/partitioner.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/partitioner.py new file mode 100644 index 0000000..24707f0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/partitioner.py @@ -0,0 +1,486 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide a partitioner for delegating subgraphs to the TOSA backend. + +Implement logic to identify and tag regions of an ``ExportedProgram`` that can +be delegated to the TOSA backend. Use this module to: + +- Partition graphs based on operator support and additional checks. +- Prune trivial no-op partitions that would lower to empty TOSA graphs. +- Tag constant data and report reasons for rejected nodes. + +""" + +import logging +from itertools import count +from typing import Callable, List, Optional, Sequence, Tuple + +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm._passes.convert_expand_copy_to_repeat import ( + calculate_multiples, +) + +from executorch.backends.arm.common.type import ensure_type +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + tosa_support_factory, +) +from executorch.backends.arm.tosa.backend import TOSABackend +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.exir.backend.partitioner import ( + DelegationSpec, + Partitioner, + PartitionResult, +) +from executorch.exir.backend.utils import tag_constant_data, WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.graph_module import get_cond_while_submodules +from torch.export.exported_program import ExportedProgram +from torch.fx import GraphModule +from torch.fx.passes.infra.partitioner import CapabilityBasedPartitioner, Partition +from torch.fx.passes.operator_support import OperatorSupportBase + +logger = logging.getLogger(__name__) + + +def is_noop_clone(node: torch.fx.node.Node) -> bool: + """Return True if the node is a no-op ``dim_order_ops._clone_dim_order``. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if the node targets ``dim_order_ops._clone_dim_order.default`` + in the Edge dialect; otherwise, False. + + """ + return node.target == exir_ops.edge.dim_order_ops._clone_dim_order.default + + +def is_noop_alias_copy(node: torch.fx.Node) -> bool: + """Return True if the node is a no-op ``aten.alias_copy``. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if the node targets ``aten.alias_copy.default``; otherwise, + False. + + """ + return node.target == exir_ops.edge.aten.alias_copy.default + + +def is_noop_to_dim_order_copy(node: torch.fx.node.Node) -> bool: + """Return True if node is a no-op ``dim_order_ops._to_dim_order_copy``. + + Consider the op a no-op when the output dtype equals the input's dtype. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if it targets ``_to_dim_order_copy.default`` and preserves + dtype; otherwise, False. + + """ + if node.target != exir_ops.edge.dim_order_ops._to_dim_order_copy.default: + return False + else: + input_node = ensure_type(torch.fx.Node, node.args[0]) + return node.meta.get("dtype") == get_first_fake_tensor(input_node).dtype + + +def is_noop_expand(node: torch.fx.node.Node) -> bool: + """Return True if the node is an ``expand_copy`` with all-ones multiples. + + This corresponds to a semantic no-op, since expanding by 1 along every + dimension leaves the tensor unchanged. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if the node targets ``aten.expand_copy.default`` and all + computed multiples are 1; otherwise, False. + + """ + if node.target != exir_ops.edge.aten.expand_copy.default: + return False + else: + multiples, changes_rank = calculate_multiples(node.args) + return all(m == 1 for m in multiples) and not changes_rank + + +def is_partitioned( + node: torch.fx.Node, + tag: str, +) -> bool: + """Return True if the node currently belongs to the partition ``tag``. + + Args: + node (torch.fx.Node): FX node to check. + tag (str): Delegation tag identifying the partition. + + Returns: + bool: True if the node carries the matching delegation tag. + + """ + return "delegation_tag" in node.meta and node.meta["delegation_tag"] == tag + + +def reject_partition( + reason: str, partition: Partition, reporter: WhyNoPartitionReporter +) -> None: + """Remove a proposed partition and record the rejection reason. + + Args: + reason (str): Human-readable explanation for rejection. + partition (object): Proposed partition object from the + capability partitioner. + reporter (WhyNoPartitionReporter): used to report why nodes were rejected. + + """ + for node in partition.nodes: + if "delegation_tag" in node.meta: + del node.meta["delegation_tag"] + reporter.report_reject( + node, + reason, + ) + + +class TOSAPartitioner(Partitioner): + """Partition an exported program into TOSA-delegable subgraphs. + + Construct this partitioner for compile specs targeting TOSA. The partition + algorithm uses capability checks and optional additional operator-support + rules to tag nodes with a delegation tag per subgraph. + + """ + + def __init__( + self, + compile_spec: TosaCompileSpec, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + ) -> None: + """Initialize the TOSAPartitioner. + + Args: + compile_spec (TosaCompileSpec): Parsed compile specifications for + TOSA containing the TOSA spec and original list. + additional_checks (Optional[Sequence[OperatorSupportBase]]): Extra + operator-support checks to apply when partitioning. + + Raises: + RuntimeError: If the provided compile spec does not target TOSA. + + """ + self.delegation_spec = DelegationSpec( + TOSABackend.__name__, compile_spec.to_list() + ) + self.tosa_spec = compile_spec.tosa_spec + self.additional_checks = additional_checks + self.tosa_spec = compile_spec.tosa_spec + + def _detag_boundary_nodes( + self, module: GraphModule, tag: str, reporter: WhyNoPartitionReporter + ) -> None: + """De-tag nodes at the partition boundary. + + Remove delegation tags from quantize nodes with inputs outside the + partition and from dequantize nodes with outputs outside the partition. + + For non Q/DQ nodes, remove the tag from the first node in the partition + if any input has floating-point dtype. + + Args: + tag: The delegation tag assigned to the partition. + reporter: A reporter to log rejected nodes. + module: The GraphModule containing the partition. + + """ + + # De-tag outermost q-nodes upwards and dq-nodes downwards. + # De-tag if at least one input/output is not part of the partition. + for node in module.graph.nodes: + if not is_partitioned(node, tag): + continue + + is_q_node = node.target in Q_OPS + is_dq_node = node.target in DQ_OPS + is_boundary_q_node = is_q_node and not is_partitioned( + node.all_input_nodes[0], tag + ) + is_boundary_dq_node = is_dq_node and any( + not is_partitioned(user, tag) for user in node.users + ) + + if is_boundary_q_node or is_boundary_dq_node: + # Remove tag from quantize node with input outside partition, + # or dequantize node with any output outside partition + del node.meta["delegation_tag"] + elif not is_q_node and not is_dq_node: + # For non Q/DQ nodes, remove tag from first node in partition if any input has fp dtype + for input in node.all_input_nodes: + if is_partitioned(input, tag): + continue + if get_first_fake_tensor(input).dtype.is_floating_point: + reporter.report_reject( + node, + f"Was first node in partition and input {input.name} had fp dtype.", + ) + del node.meta["delegation_tag"] + break + + def _tag_module( # noqa + self, + module: GraphModule, + containing_program: ExportedProgram, + reporter: WhyNoPartitionReporter, + tag_iterator: count | None = None, + ) -> set[str]: + """Tag nodes in a module or submodule from the containing program. + + Args: + module: A GraphModule from `containing_program` to tag nodes in. + containing_program: The ExportedProgram that contains the module. + reporter: A reporter to report why nodes were rejected. + + Returns: + A set of strings with the partition tags. + + """ + tags: set[str] = set() + if tag_iterator is None: + tag_iterator = count(0) + for _, submodule, _ in get_cond_while_submodules(module): + submodule_tags = self._tag_module( + submodule, containing_program, reporter, tag_iterator + ) + if len(tags & submodule_tags) != 0: + raise RuntimeError( + "Got overlapping tags in two different modules, this shouldn't happen." + ) + tags = tags | submodule_tags + operator_support = tosa_support_factory( + self.tosa_spec, containing_program, reporter, self.additional_checks + ) + capability_partitioner = CapabilityBasedPartitioner( + module, + operator_support, + allows_single_node_partition=True, + ) + partition_list = capability_partitioner.propose_partitions() + + for partition in partition_list: + tag = f"tag{next(tag_iterator)}" + tags.add(tag) + + for node in partition.nodes: + node.meta["delegation_tag"] = tag + + if self.tosa_spec.support_integer() and not self.tosa_spec.support_float(): + # Detag boundary Q/DQ since we cannot handle them without float support + self._detag_boundary_nodes( + module, + tag, + reporter, + ) + + is_noop_partition = all( + is_noop_clone(node) + or is_noop_alias_copy(node) + or is_noop_expand(node) + or is_noop_to_dim_order_copy(node) + or node.target in Q_OPS + or node.target in DQ_OPS + for node in partition.nodes + ) + if is_noop_partition: + reject_partition( + "Partition contained only ops which are removed in the TOSA lowering, leading to an empty partition.", + partition, + reporter, + ) + tags.remove(tag) + return tags + + def partition(self, exported_program: ExportedProgram) -> PartitionResult: + """Partition the program and tag TOSA-compatible subgraphs. + + Run the FX capability-based partitioner to propose subgraphs, then + refine tags by removing boundary-only quantize/dequantize nodes and by + rejecting partitions that would lower to no-ops. Emit a detailed report + of rejected nodes and their reasons. + + Args: + exported_program (ExportedProgram): Program to analyze and + partition. + + Returns: + PartitionResult: The input program with nodes tagged for delegation + and a mapping of partition tags to delegation specs. + + """ + logger.info("TOSAPartitioner::partition") + logger.info( + f"Partitioning for {self.delegation_spec.backend_id}: {self.tosa_spec}" + ) + + reporter = WhyNoPartitionReporter() + tags = self._tag_module( + exported_program.graph_module, exported_program, reporter + ) + partition_tags = {tag: self.delegation_spec for tag in tags} + + tag_constant_data(exported_program) + logger.info(f"The following nodes were rejected for {self.tosa_spec}:") + logger.info("\n" + reporter.get_table_report()) + logger.info("(Placeholders and outputs are not included in this list)") + return PartitionResult( + tagged_exported_program=exported_program, partition_tags=partition_tags + ) + + def ops_to_not_decompose( # noqa: C901 + self, + ep: ExportedProgram, + ) -> Tuple[List[torch._ops.OpOverload], Optional[Callable[[torch.fx.Node], bool]]]: + """Return operators and a filter that should not be decomposed. + + Provide a base set of ops to preserve as-is and a predicate that keeps + certain activations whole when surrounded by quantize/dequantize ops in + a quantized graph. This helps downstream TOSA lowering and delegation. + + Args: + ep (ExportedProgram): Program used to infer target-specific policy. + + Returns: + Tuple[List[torch._ops.OpOverload], Optional[Callable[[torch.fx.Node], bool]]]: + A list of op overloads to keep intact, and an optional filter + function that returns True when an op should not be decomposed. + + """ + ops_to_not_decompose_if_quant_op = { + torch.ops.aten.eye.default, + torch.ops.aten.hardsigmoid.default, + torch.ops.aten.hardswish.default, + torch.ops.aten.linear.default, + torch.ops.aten.linspace.default, + } + ops_to_not_decompose_if_fp = { + torch.ops.aten.eye.default, + torch.ops.aten.logit.default, + torch.ops.aten.linear.default, + torch.ops.aten.linspace.default, + } + ops_to_not_decompose_always = { + torch.ops.aten.logit.default, + } + ops_to_not_decompose_if_integer = { + torch.ops.aten.eye.default, + torch.ops.aten.linspace.default, + } + + def filter_fn(node: torch.fx.Node) -> bool: + """Filter function applied to ops in 'ops_to_not_decompose'. + Returns True if the op should not be decomposed. + If this function returns True, the partitioner *must* accept the node, or the lowering fails. + + Args: + node (torch.fx.Node): FX node to evaluate. + + Returns: + bool: True to keep the op intact; otherwise, False. + + """ + if ( + self.tosa_spec.support_float() + and node.target in ops_to_not_decompose_if_fp + ): + return True + + dq = ( + torch.ops.quantized_decomposed.dequantize_per_tensor.default, + torch.ops.quantized_decomposed.dequantize_per_channel.default, + ) + q = ( + torch.ops.quantized_decomposed.quantize_per_tensor.default, + torch.ops.quantized_decomposed.quantize_per_channel.default, + ) + + if node.target in ops_to_not_decompose_if_quant_op: + # Assume we should not decompose the operator (it is quantized) + correct_output_quant = True + correct_input_quant = True + + input_nodes = node.all_input_nodes + output_nodes = node.users + + for inp in input_nodes: + if inp.target not in dq: + correct_input_quant = False + + for out in output_nodes: + if out.target not in q: + correct_output_quant = False + # In some cases, a linear is quantized together with its activation. + if ( + node.target == torch.ops.aten.linear.default + and len(output_nodes) == 1 + and list(output_nodes)[0].target + in (torch.ops.aten.relu.default, torch.ops.aten.hardtanh.default) + ): + correct_output_quant = True + + if correct_input_quant and correct_output_quant: + return True + + if node.target in ops_to_not_decompose_if_integer: + # We only want to tag nodes as do_not_decompose if we are sure that + # we can partition them. We partition them if one or more of the + # following is true: + # 1. The node outputs an integer type. + # 2. All users cast the output to an integer type. + + dtype = get_first_fake_tensor(node).dtype + if not dtype.is_floating_point and not dtype.is_complex: + return True + + output_nodes = node.users + for user in output_nodes: + if user.target != torch.ops.aten.to.dtype: + return False + else: + cast_dtype = get_first_fake_tensor(user).dtype + if cast_dtype.is_complex or cast_dtype.is_floating_point: + return False + return True + + if node.target in ops_to_not_decompose_if_fp: + if self.tosa_spec.support_float(): + return True + if node.target in ops_to_not_decompose_always: + return True + return False + + ops_to_not_decompose = list( + ops_to_not_decompose_always + | ops_to_not_decompose_if_quant_op + | ops_to_not_decompose_if_fp + | ops_to_not_decompose_if_integer + ) + + if not self.tosa_spec.is_U55_subset: + # Tosa operator "RESIZE" is not supported on U55. Since upsample_bilinear2d + # and upsample_nearest2d decompose into that it will not be possible to + # delegate those operators on U55. If we have said here to not decompose + # them there will be an error saying the operator was not decomposed. It + # will not be possible for it to end up on either CPU or NPU. + ops_to_not_decompose.append(torch.ops.aten.upsample_nearest2d.vec) + ops_to_not_decompose.append(torch.ops.aten.upsample_bilinear2d.vec) + + return (ops_to_not_decompose, filter_fn) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/README.md new file mode 100644 index 0000000..9ee41b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/README.md @@ -0,0 +1,5 @@ +# License + +The FlatBuffer schema (fbs) files originates from +https://git.mlplatform.org/tosa/reference_model.git/ and are relicensed under the BSD-style license +file found in the [LICENSE](../../../../LICENSE) file in the root directory of this source tree. \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/tosa_1.0.fbs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/tosa_1.0.fbs new file mode 100644 index 0000000..e58682d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/schemas/tosa_1.0.fbs @@ -0,0 +1,559 @@ +// Copyright 2025 Arm Limited and/or its affiliates. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +namespace tosa; + +// This corresponds to the version. +file_identifier "TOSA"; +// File extension of any written files. +file_extension "tosa"; + +// NOTE: New values added to the schema should be placed +// at the end of the list in order to keep schema stable. + +enum DType:uint32 { + UNKNOWN = 0, + BOOL, + INT4, + INT8, + INT16, + INT32, + INT48, + FP32, + FP16, + BF16, + SHAPE, + FP8E4M3, + FP8E5M2, +} + +enum ResizeMode:uint32 { + UNKNOWN = 0, + NEAREST, + BILINEAR, +} + +enum NanPropagationMode:uint32 { + UNKNOWN = 0, + PROPAGATE, + IGNORE, +} + +enum RoundingMode:uint32 { + UNKNOWN = 0, + SINGLE_ROUND, + INEXACT_ROUND, + DOUBLE_ROUND +} + +enum Op:uint32 { + UNKNOWN = 0, + ARGMAX, + AVG_POOL2D, + CONV2D, + CONV3D, + DEPTHWISE_CONV2D, + FFT2D, + MATMUL, + MAX_POOL2D, + RFFT2D, + TRANSPOSE_CONV2D, + CLAMP, + ERF, + SIGMOID, + TANH, + ADD, + ARITHMETIC_RIGHT_SHIFT, + BITWISE_AND, + BITWISE_OR, + BITWISE_XOR, + INTDIV, + LOGICAL_AND, + LOGICAL_LEFT_SHIFT, + LOGICAL_RIGHT_SHIFT, + LOGICAL_OR, + LOGICAL_XOR, + MAXIMUM, + MINIMUM, + MUL, + POW, + SUB, + TABLE, + ABS, + BITWISE_NOT, + CEIL, + CLZ, + COS, + EXP, + FLOOR, + LOG, + LOGICAL_NOT, + NEGATE, + RECIPROCAL, + RSQRT, + SIN, + SELECT, + EQUAL, + GREATER, + GREATER_EQUAL, + REDUCE_ALL, + REDUCE_ANY, + REDUCE_MAX, + REDUCE_MIN, + REDUCE_PRODUCT, + REDUCE_SUM, + CONCAT, + PAD, + RESHAPE, + REVERSE, + SLICE, + TILE, + TRANSPOSE, + GATHER, + SCATTER, + RESIZE, + CAST, + RESCALE, + CONST, + IDENTITY, + CUSTOM, + COND_IF, + WHILE_LOOP, + VARIABLE, + VARIABLE_WRITE, + VARIABLE_READ, + CONST_SHAPE, +} + +union Attribute { + ArgMaxAttribute, + AvgPool2dAttribute, + Conv2dAttribute, + Conv3dAttribute, + DepthwiseConv2dAttribute, + FFT2dAttribute, + MatMulAttribute, + MaxPool2dAttribute, + RFFT2dAttribute, + TransposeConv2dAttribute, + ClampAttribute, + ErfAttribute, + SigmoidAttribute, + TanhAttribute, + AddAttribute, + ArithmeticRightShiftAttribute, + BitwiseAndAttribute, + BitwiseOrAttribute, + BitwiseXorAttribute, + IntDivAttribute, + LogicalAndAttribute, + LogicalLeftShiftAttribute, + LogicalRightShiftAttribute, + LogicalOrAttribute, + LogicalXorAttribute, + MaximumAttribute, + MinimumAttribute, + MulAttribute, + PowAttribute, + SubAttribute, + TableAttribute, + AbsAttribute, + BitwiseNotAttribute, + CeilAttribute, + ClzAttribute, + CosAttribute, + ExpAttribute, + FloorAttribute, + LogAttribute, + LogicalNotAttribute, + NegateAttribute, + ReciprocalAttribute, + RsqrtAttribute, + SinAttribute, + SelectAttribute, + EqualAttribute, + GreaterAttribute, + GreaterEqualAttribute, + ReduceAllAttribute, + ReduceAnyAttribute, + ReduceMaxAttribute, + ReduceMinAttribute, + ReduceProductAttribute, + ReduceSumAttribute, + ConcatAttribute, + PadAttribute, + ReshapeAttribute, + ReverseAttribute, + SliceAttribute, + TileAttribute, + TransposeAttribute, + GatherAttribute, + ScatterAttribute, + ResizeAttribute, + CastAttribute, + RescaleAttribute, + ConstAttribute, + IdentityAttribute, + CustomAttribute, + CondIfAttribute, + WhileLoopAttribute, + VariableAttribute, + VariableWriteAttribute, + VariableReadAttribute, + ConstShapeAttribute, +} + +table ArgMaxAttribute { + axis: int32; + nan_mode: NanPropagationMode; +} + +table AvgPool2dAttribute { + kernel: [int32]; + stride: [int32]; + pad: [int32]; + acc_type: DType; +} + +table Conv2dAttribute { + pad: [int32]; + stride: [int32]; + dilation: [int32]; + local_bound: bool; + acc_type: DType; +} + +table Conv3dAttribute { + pad: [int32]; + stride: [int32]; + dilation: [int32]; + local_bound: bool; + acc_type: DType; +} + +table DepthwiseConv2dAttribute { + pad: [int32]; + stride: [int32]; + dilation: [int32]; + local_bound: bool; + acc_type: DType; +} + +table FFT2dAttribute { + inverse: bool; + local_bound: bool; +} + +table MatMulAttribute { +} + +table MaxPool2dAttribute { + kernel: [int32]; + stride: [int32]; + pad: [int32]; + nan_mode: NanPropagationMode; +} + +table RFFT2dAttribute { + local_bound: bool; +} + +table TransposeConv2dAttribute { + out_pad: [int32]; + stride: [int32]; + local_bound: bool; + acc_type: DType; +} + +table ClampAttribute { + min_val: [ubyte] (force_align: 8); + max_val: [ubyte] (force_align: 8); + nan_mode: NanPropagationMode; +} + +table ErfAttribute { +} + +table SigmoidAttribute { +} + +table TanhAttribute { +} + +table AddAttribute { +} + +table ArithmeticRightShiftAttribute { + round: bool; +} + +table BitwiseAndAttribute { +} + +table BitwiseOrAttribute { +} + +table BitwiseXorAttribute { +} + +table IntDivAttribute { +} + +table LogicalAndAttribute { +} + +table LogicalLeftShiftAttribute { +} + +table LogicalRightShiftAttribute { +} + +table LogicalOrAttribute { +} + +table LogicalXorAttribute { +} + +table MaximumAttribute { + nan_mode: NanPropagationMode; +} + +table MinimumAttribute { + nan_mode: NanPropagationMode; +} + +table MulAttribute { +} + +table PowAttribute { +} + +table SubAttribute { +} + +table TableAttribute { +} + +table AbsAttribute { +} + +table BitwiseNotAttribute { +} + +table CeilAttribute { +} + +table ClzAttribute { +} + +table CosAttribute { +} + +table ExpAttribute { +} + +table FloorAttribute { +} + +table LogAttribute { +} + +table LogicalNotAttribute { +} + +table NegateAttribute { +} + +table ReciprocalAttribute { +} + +table RsqrtAttribute { +} + +table SinAttribute { +} + +table SelectAttribute { +} + +table EqualAttribute { +} + +table GreaterAttribute { +} + +table GreaterEqualAttribute { +} + +table ReduceAllAttribute { + axis: int32; +} + +table ReduceAnyAttribute { + axis: int32; +} + +table ReduceMaxAttribute { + axis: int32; + nan_mode: NanPropagationMode; +} + +table ReduceMinAttribute { + axis: int32; + nan_mode: NanPropagationMode; +} + +table ReduceProductAttribute { + axis: int32; +} + +table ReduceSumAttribute { + axis: int32; +} + +table ConcatAttribute { + axis: int32; +} + +table PadAttribute { +} + +table ReshapeAttribute { +} + +table ReverseAttribute { + axis: int32; +} + +table SliceAttribute { +} + +table TileAttribute { +} + +table TransposeAttribute { + perms: [int32]; +} + +table GatherAttribute { +} + +table ScatterAttribute { +} + +table ResizeAttribute { + mode: ResizeMode; +} + +table CastAttribute { +} + +table RescaleAttribute { + scale32: bool; + rounding_mode: RoundingMode; + per_channel: bool; + input_unsigned: bool; + output_unsigned: bool; +} + +table ConstAttribute { + // value is stored in output TosaTensor +} + +table IdentityAttribute { +} + +table CustomAttribute { + operator_name:string; + domain_name:string; + implementation_attrs:[ubyte]; +} + +table CondIfAttribute { + then_graph: string; + else_graph: string; +} + +table WhileLoopAttribute { + cond_graph: string; + body_graph: string; +} + +table VariableAttribute { +} + +table VariableWriteAttribute { +} + +table VariableReadAttribute { +} + +table ConstShapeAttribute { + // value is stored in output TosaTensor +} + + +table Version { + _major: int32 = -1; + _minor: int32 = -1; + _patch: int32 = -1; + _draft: bool = true; +} + +table TosaTensor { + name:string; // name of the tensor, used for solving dependency + shape:[int32]; // shape of the tensor + type:DType; // data type of the tensor + data: [ubyte] (force_align: 8); // raw data array if it's a constant tensor. + variable: bool; // is this a variable tensor + is_unranked: bool; // whether this is an unranked tensor + variable_name:string; // name for variable attribute + + // In a model that is larger than 2GB, then tensors instead uses the following + // attributes to find stored data, which is outside of flatbuffers + // the offset is calculated relative to the beginning of the file and is only + // valid if > 1. + offset: ulong; + size: ulong; +} + +table TosaShape { + name: string; // name of the shape + rank: uint32; // rank of the shape + data: [ubyte] (force_align: 8); // raw data array if it's a constant shape +} + +table OpLocation { + text: string; // Opaque string, interpretted by user +} + +table TosaOperator { + op:Op; // operator enum + attribute:Attribute; // union structure. operator attribute + inputs:[string]; // list of input tensor or shape names + outputs:[string]; // list of output tensor or shape names + location: OpLocation; // location of this Op in mlir +} + +table TosaBasicBlock { + name:string; // basic block name + operators:[TosaOperator]; // operators array + tensors:[TosaTensor]; // tensors array + inputs:[string]; // name of graph inputs + outputs:[string]; // name of graph outputs + shapes:[TosaShape]; // shapes array +} + +table TosaRegion { + name:string; // name of region + blocks:[TosaBasicBlock]; // basic blocks array +} + +table TosaGraph { + version:Version (required); + regions:[TosaRegion]; // regions array +} + +root_type TosaGraph; \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/specification.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/specification.py new file mode 100644 index 0000000..b5b9613 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/specification.py @@ -0,0 +1,406 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide TOSA specification parsing and context utilities. + +Use these helpers to parse and validate TOSA profile/extension strings and to +manage a lowering-time context for the active specification. + +""" + +import contextvars +import re +from typing import Dict, Generic, List, Set, TypeVar + +from packaging.version import Version + +T = TypeVar("T") + + +class TosaSpecMapping(Generic[T]): + def __init__(self): + self._mapping: Dict[TosaSpecification, List[T]] = {} + + def add(self, spec: "TosaSpecification", value: T) -> None: + """ + Adds a value to the mapping for the given TOSA specification. + The specification is normalized to its canonical form, which means that + only the version and profiles are considered, without extensions. + This allows for grouping of values under the same TOSA specification + regardless of the extensions they may have. + """ + + if spec.is_U55_subset or spec.extensions: + raise ValueError( + f"TosaSpecMapping does not support extensions, got: {spec}" + ) + + if isinstance(spec, Tosa_1_00) and len(spec.profiles) > 1: + raise ValueError( + f"TosaSpecMapping does not support multiple profiles, got: {spec}" + ) + + norm_spec = spec._canonical_key() + if norm_spec not in self._mapping: + self._mapping[norm_spec] = [] + self._mapping[norm_spec].append(value) + + @staticmethod + def _get_base_specs(spec: "TosaSpecification") -> List["TosaSpecification"]: + # Handles combined TOSA-1.0+FP+INT, etc. + if isinstance(spec, Tosa_1_00): + profiles: Set[str] = set(spec.profiles) + if profiles == {"FP", "INT"}: + version = spec.version + return [ + TosaSpecification.create_from_string(f"TOSA-{version}+FP"), + TosaSpecification.create_from_string(f"TOSA-{version}+INT"), + ] + return [spec] + + def get(self, spec: "TosaSpecification") -> List[T]: + """ + Returns a list of values associated with the given TOSA specification. + The specification is normalized to its canonical form, which means that + only the version and profiles are considered, without extensions. + """ + + base_specs = self._get_base_specs(spec) + result: List[T] = [] + for base in base_specs: + norm_base = base._canonical_key() + result.extend(self._mapping.get(norm_base, [])) + if len(result) == 0: + raise KeyError(f"No values found for TOSA specification: {spec}") + + return result # Do not deduplicate with set(), as values may be unhashable + + +class TosaSpecification: + """Represent a TOSA specification. + + A specification includes a semantic version, one or more profiles, and + optional extensions and levels (for example ``8k``). + The encoded form follows ``TOSA-..+[+][+...]``. + Profiles use uppercase (for example ``INT``, ``FP``); levels and extensions + use lowercase. + + Attributes: + version (Version): Parsed TOSA semantic version. + is_U55_subset (bool): True if the ``u55`` subset is requested. + + """ + + version: Version + is_U55_subset: bool + extensions: List[str] + + def support_integer(self) -> bool: + """Return True if integer operations are supported.""" + raise NotImplementedError + + def support_float(self) -> bool: + """Return True if floating-point operations are supported.""" + raise NotImplementedError + + def support_extension(self, extension: str) -> bool: + """Return True if an extension is supported and enabled. + + Args: + extension (str): Extension name (for example ``int4``, ``bf16``). + + Returns: + bool: True if the extension is valid for the active profiles and selected. + + """ + raise NotImplementedError + + def __init__(self, version: Version, extras: List[str]): + """Initialize the base specification. + + Args: + version (Version): Parsed TOSA semantic version. + extras (List[str]): Remaining tokens such as profiles, levels, and extensions. + + """ + self.version = version + self.extensions = [] + + self.is_U55_subset = "u55" in extras + if self.is_U55_subset: + extras.remove("u55") + + @staticmethod + def create_from_string(repr: str) -> "TosaSpecification": + """Create a specification from a standard string format. + + Example: ``TOSA-1.00.0+INT+FP+int4+cf``. + + Args: + repr (str): Standard representation string. + + Returns: + TosaSpecification: Parsed specification instance. + + Raises: + ValueError: If the representation is malformed or version is unsupported. + + """ + pattern = r"^(TOSA)-([\d.]+)\+(.+)$" + match = re.match(pattern, repr) + if match: + name = match.group(1) + version = Version(match.group(2)) + extras = match.group(3).split("+") + if name != "TOSA": + raise ValueError(f"Malformed TOSA specification representation: {repr}") + match version: + case _ if version.major == 1 and version.minor == 0: + return Tosa_1_00(version, extras) + case _: + raise ValueError(f"Wrong TOSA version: {version} from {repr}") + + raise ValueError(f"Failed to parse TOSA specification representation: {repr}") + + def _canonical_key(self) -> "TosaSpecification": + """ + Returns a new TosaSpecification instance with only version and profiles (no extensions). + """ + raise NotImplementedError + + +class Tosa_1_00(TosaSpecification): + """Provide TOSA 1.00 profile and extension semantics. + + This variant validates profiles (``INT``, ``FP``), the optional ``8k`` level, + and allowed extensions based on the selected profiles. + + Attributes: + profiles (List[str]): Selected profiles, e.g., ``["INT"]`` or ``["INT", "FP"]``. + level_8k (bool): True if the ``8k`` level is enabled. + extensions (List[str]): Enabled extensions valid for the chosen profiles. + + """ + + profiles: List[str] + level_8k: bool + extensions: List[str] + + available_profiles = ["INT", "FP"] + valid_extensions = { + "INT": ["int16", "int4", "var", "cf", "u55"], + "FP": ["bf16", "fp8e4m3", "fp8e5m2", "fft", "var", "cf"], + } + + def __init__(self, version: Version, extras: List[str]): + """Initialize the 1.00 specification and validate extras. + + Args: + version (Version): Semantic version (major=1, minor=0). + extras (List[str]): Tokens including profiles, level, and extensions. + + Raises: + ValueError: If no/too many profiles are provided or extensions are invalid. + + """ + super().__init__(version, extras) + + # Check that we have at least one profile in the extensions list + if [e in Tosa_1_00.available_profiles for e in extras].count(True) == 0: + raise ValueError( + f"No profile ({Tosa_1_00.available_profiles}) found in: {extras}." + ) + + # and not more than number of available profiles + if [e in Tosa_1_00.available_profiles for e in extras].count(True) > len( + Tosa_1_00.available_profiles + ): + raise ValueError( + f"Too many profiles ({Tosa_1_00.available_profiles}) found in: {extras}." + ) + + # The list contains one profile at least, so pick them + self.profiles = [e for e in extras if e in Tosa_1_00.available_profiles] + for p in self.profiles: + extras.remove(p) + + self.level_8k = "8k" in extras + if self.level_8k: + extras.remove("8k") + + combined_extensions = [] + for p in self.profiles: + combined_extensions += Tosa_1_00.valid_extensions[p] + + if not all(e in combined_extensions for e in extras): + raise ValueError( + f"Bad extensions for TOSA-{version}{self._get_profiles_string()}: {extras}" + ) + + # all the rest of the extras are handled extensions + self.extensions = extras + + def _get_profiles_string(self) -> str: + """Return the ``+``-joined profile segment (e.g., ``+INT+FP``).""" + return "".join(["+" + p for p in self.profiles]) + + def _get_extensions_string(self) -> str: + """Return the ``+``-joined extensions segment (e.g., ``+int4+cf``).""" + return "".join(["+" + e for e in self.extensions]) + + def __repr__(self): + """Return the standard specification string format. + + Returns: + str: Standard form like ``TOSA-1.00.0+INT+8k+int4``. + + """ + extensions = self._get_extensions_string() + if self.level_8k: + extensions += "+8k" + if self.is_U55_subset: + extensions += "+u55" + return f"TOSA-{self.version}{self._get_profiles_string()}{extensions}" + + def __hash__(self) -> int: + """Return a stable hash for use in sets and dict keys. + + Returns: + int: Hash value derived from version and profiles. + + """ + return hash(str(self.version) + self._get_profiles_string()) + + def __eq__(self, other: object) -> bool: + """Return True if another instance represents the same spec. + + Args: + other (object): Object to compare. + + Returns: + bool: True if versions and profiles match. + + """ + if isinstance(other, Tosa_1_00): + return (self.version == other.version) and ( + self._get_profiles_string() == other._get_profiles_string() + ) + return False + + def support_integer(self): + """Return True if the ``INT`` profile is present.""" + return "INT" in self.profiles + + def support_float(self): + """Return True if the ``FP`` profile is present.""" + return "FP" in self.profiles + + def support_extension(self, extension: str) -> bool: + """Return True if an extension is supported and enabled. + + Args: + extension (str): Extension name (for example ``int4``, ``bf16``). + + Returns: + bool: True if the extension is valid for the active profiles and selected. + + """ + for p in self.profiles: + if extension in self.valid_extensions[p] and extension in self.extensions: + return True + + return False + + def _canonical_key(self) -> "Tosa_1_00": + """ + Returns a new Tosa_1_00 instance with only major.minor version and profiles (no extensions). + Patch version is set to zero for normalization. + """ + from packaging.version import Version + + norm_version = Version(f"{self.version.major}.{self.version.minor}.0") + return Tosa_1_00(norm_version, self.profiles.copy()) + + +class TosaLoweringContext: + """Manage the TOSA specification context for lowering. + + For now, only the active ``TosaSpecification`` is tracked, but this can be + extended to carry additional lowering policies or configuration. + + Attributes: + tosa_spec_var (contextvars.ContextVar): Context variable storing the active spec. + spec (TosaSpecification): Specification passed to the context manager. + + """ + + # Define a context variable for the spec + tosa_spec_var: contextvars.ContextVar = contextvars.ContextVar("tosa_spec") + + def __init__(self, spec: TosaSpecification): + """Initialize the lowering context with a specification. + + Args: + spec (TosaSpecification): Active specification to put into context. + + """ + self.spec = spec + + def __enter__(self): + """Set the context variable and return self. + + Returns: + TosaLoweringContext: This context manager instance. + + """ + # Set the spec in the context variable and store the token for later reset + self.token = TosaLoweringContext.tosa_spec_var.set(self.spec) + return self + + def __exit__(self, exc_type, exc_value, traceback): + """Reset the context variable to its previous state. + + Args: + exc_type (type | None): Exception type, if any. + exc_value (BaseException | None): Exception instance, if any. + traceback (TracebackType | None): Traceback, if any. + + """ + # Reset the context variable to its previous state + TosaLoweringContext.tosa_spec_var.reset(self.token) + + +def get_context_spec() -> TosaSpecification: + """Get the current ``TosaSpecification`` from the lowering context. + + Returns: + TosaSpecification: Active specification retrieved from the context var. + + Raises: + RuntimeError: If called outside a ``TosaLoweringContext``. + + """ + try: + return TosaLoweringContext.tosa_spec_var.get() + except LookupError: + raise RuntimeError("Function must be executed within a TosaLoweringContext") + + +def tosa_spec_in_set(spec: TosaSpecification, specs: Set[TosaSpecification]) -> bool: + """Check if a specification matches any in a set, considering base specs. + + Args: + spec (TosaSpecification): Specification to check. + specs (Set[TosaSpecification]): Set of specifications to match against. + + Returns: + bool: True if a match is found, False otherwise. + + """ + base_specs = TosaSpecMapping._get_base_specs(spec) + for base in base_specs: + if base in specs: + return True + return False diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/utils.py new file mode 100644 index 0000000..df77153 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/tosa/utils.py @@ -0,0 +1,304 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Utility helpers for building TOSA graphs in the Arm backend.""" + +import logging +from typing import Any + +import numpy as np + +import sympy # type: ignore + +import torch +import tosa_serializer as ts + +from executorch.backends.arm.tosa.mapping import extract_tensor_meta +from executorch.backends.arm.tosa.specification import TosaSpecification + +from torch._subclasses.fake_tensor import FakeTensor +from torch.fx import Node + +logger = logging.getLogger(__name__) + + +def are_fake_tensors_broadcastable( + fake_tensors: list[FakeTensor], +) -> tuple[bool, list[int]]: + """Determine whether the fake tensors share a broadcastable shape. + + Args: + fake_tensors (list[FakeTensor]): Fake tensors whose shapes should + be validated for broadcasting. + + Returns: + tuple[bool, list[int]]: Tuple where the first element indicates + whether broadcasting is possible and the second element contains + the broadcast shape. The shape list is empty when broadcasting + fails. + + Raises: + RuntimeError: Raised when fewer than two tensors are supplied. + + """ + if len(fake_tensors) < 1: + raise RuntimeError(f"Expected 2 or more tensors got {len(fake_tensors)}") + + reversed_shapes = [list(reversed(ft.shape)) for ft in fake_tensors] + sorted_shapes = sorted(reversed_shapes, key=len, reverse=True) + + broadcast_shape = [] + for dim in range(len(sorted_shapes[0])): + curr_dim = 1 + for shape in sorted_shapes: + if dim >= len(shape): + continue + if curr_dim == 1 and shape[dim] != 1: + curr_dim = shape[dim] + elif shape[dim] == 1: + continue + elif curr_dim != 1 and shape[dim] != curr_dim: + return (False, []) + broadcast_shape.append(curr_dim) + return (True, list(reversed(broadcast_shape))) + + +def broadcast_tensors( + tosa_fb, nodes: list[Node], tosa_spec: TosaSpecification +) -> list[Any]: + """Broadcast the FX nodes to a shared shape inside the TOSA graph. + + This mirrors ``reshape_for_broadcast`` but also emits the tile operators + needed to materialize the broadcast and supports any number of inputs. + + Args: + tosa_fb (Any): TOSA graph builder that receives the broadcast + operators. + nodes (list[Node]): FX nodes whose tensor metadata should be + broadcast. + tosa_spec (TosaSpecification): Active TOSA specification used to + decode tensor metadata. + + Returns: + list[Any]: Broadcast versions of the inputs. Each element is either + the original FX node or a TOSA serializer tensor, ordered to match + ``nodes``. + + Raises: + RuntimeError: If the supplied nodes are not broadcastable. + + """ + index_fake_tensors = [node.meta["val"] for node in nodes] + broadcastable, common_shape = are_fake_tensors_broadcastable(index_fake_tensors) + if not broadcastable: + raise RuntimeError("FakeTensors are not broadcastable") + + broadcast_tensors = [] + for node in nodes: + tens_dtype, tens_shape, _ = extract_tensor_meta(node.meta, tosa_spec) + list_tens_shape = list(tens_shape) + # Already in the right shape we can just add it to the list. + if list_tens_shape == common_shape: + broadcast_tensors.append(node) + continue + + rank_diff = len(common_shape) - len(tens_shape) + new_shape = [1] * rank_diff + list_tens_shape + reshaped = tosa_fb.addIntermediate( + new_shape, + tens_dtype, + ) + + build_reshape_tosa(tosa_fb, node.name, new_shape, reshaped.name) + + tiled = tosa_fb.addIntermediate(common_shape, tens_dtype) + multipliers = [ + comm if curr == 1 else 1 for comm, curr in zip(common_shape, new_shape) + ] + multiple_shapes = tosa_fb.addConst( + (len(multipliers),), + ts.DType.SHAPE, + multipliers, + name=f"{node.name}_multiples", + ) + + attr = ts.TosaSerializerAttribute() + attr.TileAttribute() + tosa_fb.addOperator( + ts.Op.TILE, + [reshaped.name, multiple_shapes.name], + [tiled.name], + attr, + ) + + broadcast_tensors.append(tiled) + + return broadcast_tensors + + +def build_reshape_tosa( + tosa_graph, input_name, new_shape, output_name, shape_name_override="" +): + """Insert a TOSA reshape operator using the v1.0 semantics. + + Args: + tosa_graph (Any): Graph builder used to emit TOSA operators. + input_name (str): Name of the tensor that should be reshaped. + new_shape (list[int]): Target tensor shape. + output_name (str): Name assigned to the reshaped tensor. + shape_name_override (str): Optional override for the shape constant + name. + + """ + shape = tosa_graph.addConst( + np.array(new_shape).shape, + ts.DType.SHAPE, + np.array(new_shape), + name=shape_name_override if shape_name_override else output_name + "_shape", + ) + + attr = ts.TosaSerializerAttribute() + attr.ReshapeAttribute() + tosa_graph.addOperator( + ts.Op.RESHAPE, + [input_name, shape.name], + [output_name], + attr, + ) + + +def tosa_shape(shape, dim_order): + """Reorder a shape tuple into TOSA layout while resolving symints. + + Args: + shape (Sequence[int | torch.SymInt]): Original tensor shape, + possibly containing ``torch.SymInt``. + dim_order (Sequence[int]): Desired dimension order for the output + shape. + + Returns: + list[int]: List containing the reordered dimensions where symbolic + values become ``-1``. + + """ + reordered = tuple([shape[dim] for dim in dim_order]) + # Dynamic shapes in executorch are represented with torch.SymInt objects in the shapes, + # in TOSA we do not have this concept and instead use -1. + removed_symints = tuple( + [-1 if isinstance(d, torch.SymInt) else d for d in reordered] + ) + return list(removed_symints) + + +def get_resize_parameters_1d( + input_size: int | torch.SymInt, + output_size: int | torch.SymInt, + resize_mode: int, + align_corners: bool, +): + """Compute resize coefficients for a single spatial dimension. + + Args: + input_size (int | torch.SymInt): Input size for the axis, possibly + symbolic. + output_size (int | torch.SymInt): Output size for the axis, possibly + symbolic. + resize_mode (int): Target resize mode defined by TOSA. + align_corners (bool): Whether the resize should align the corner + pixels. + + Returns: + tuple[int, int, int, int]: Numerator, denominator, offset, and border + terms encoded as integers. + + Raises: + RuntimeError: If symbolic shapes are used with ``align_corners`` or if + the computed ratio or border is not constant. + + """ + # We don't support align_corners for symbolic shapes, because handling the edge case where size == 1 is tricky. + if align_corners: + if (not isinstance(input_size, int)) or (not isinstance(output_size, int)): + raise RuntimeError( + "We do not support align_corners=True for symbolic shapes." + ) + + # SymInt seems to not actually work for symbolic expressions, so use the underlying sympy objects instead + input_size = ( + input_size.node._expr if isinstance(input_size, torch.SymInt) else input_size + ) + output_size = ( + output_size.node._expr if isinstance(output_size, torch.SymInt) else output_size + ) + if align_corners and input_size > 1 and output_size > 1: + scale_n = output_size - 1 + else: + scale_n = output_size + if align_corners and input_size > 1 and output_size > 1: + scale_d = input_size - 1 + else: + scale_d = input_size + ratio = scale_n / scale_d + if not sympy.sympify(ratio).is_constant(): + raise RuntimeError( + "Resize requires a constant ratio: " + str(ratio) + " is not constant!" + ) + gcd = sympy.gcd(scale_n, scale_d) + scale_n = 2 * scale_n // gcd + scale_d = 2 * scale_d // gcd + # These should always be whole integers, based on the above calculations + scale_n = int(scale_n.evalf()) + scale_d = int(scale_d.evalf()) + + if align_corners: + offset = 0 + else: + # Half pixel centers so input and output sampling positions are offset by 1/2 pixel. + offset = scale_d // 2 - scale_n // 2 + + # Calculate border to maintain the correct the output size. + # Note that this should always result in a constant value, as the ratio is constant. + border = scale_d * (output_size - 1) - scale_n * (input_size - 1) + offset + + if not sympy.sympify(border).is_constant(): + raise RuntimeError( + "Resize requires a constant border: " + str(border) + " is not constant!" + ) + + border = int(sympy.sympify(border).evalf()) + return scale_n, scale_d, offset, border + + +def get_resize_parameters( + input_size_xy: tuple[int | torch.SymInt, int | torch.SymInt], + output_size_xy: tuple[int | torch.SymInt, int | torch.SymInt], + resize_mode: int, + align_corners: bool, +) -> tuple[torch.IntTensor, ...]: + """Calculate 2D resize parameters for TOSA emission. + + Args: + input_size_xy (tuple[int | torch.SymInt, int | torch.SymInt]): Height + and width of the input tensor. + output_size_xy (tuple[int | torch.SymInt, int | torch.SymInt]): Height + and width of the output tensor. + resize_mode (int): TOSA resize mode used for coefficient generation. + align_corners (bool): Whether to align corner pixels between input and + output. + + Returns: + tuple[torch.IntTensor, ...]: Four-element tuple of tensors describing + the scale numerator, scale denominator, offset, and border for Y + and X dimensions. + + """ + # Get the parameters for each dimension independently + y_params = get_resize_parameters_1d( + input_size_xy[0], output_size_xy[0], resize_mode, align_corners + ) + x_params = get_resize_parameters_1d( + input_size_xy[1], output_size_xy[1], resize_mode, align_corners + ) + # Combine them together, so we return four 2-element tensors (scale_n, scale_d, offset, border) + return tuple(map(torch.IntTensor, zip(y_params, x_params))) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/_factory.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/_factory.py new file mode 100644 index 0000000..23d8215 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/_factory.py @@ -0,0 +1,59 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.ethosu import EthosUCompileSpec, EthosUPartitioner +from executorch.backends.arm.quantizer import ( + EthosUQuantizer, + TOSAQuantizer, + VgfQuantizer, +) +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.vgf import VgfCompileSpec, VgfPartitioner +from executorch.exir.backend.compile_spec_schema import CompileSpec +from torch.fx.passes.operator_support import OperatorSupportBase + + +def parse_compile_spec(compile_specs: list[CompileSpec]) -> ArmCompileSpec: + output_format = None + for spec in compile_specs: + if spec.key == "output_format": + output_format = spec.value.decode() + break + else: + raise ValueError("Compile spec without output format.") + if output_format == TosaCompileSpec.get_output_format(): + return TosaCompileSpec.from_list(compile_specs) + if output_format == EthosUCompileSpec.get_output_format(): + return EthosUCompileSpec.from_list(compile_specs) + if output_format == VgfCompileSpec.get_output_format(): + return VgfCompileSpec.from_list(compile_specs) + raise ValueError(f"Unknown output format {output_format}") + + +def create_partitioner( + compile_spec: ArmCompileSpec, + additional_checks: list[OperatorSupportBase] | None = None, +): + if isinstance(compile_spec, TosaCompileSpec): + return TOSAPartitioner(compile_spec, additional_checks) + elif isinstance(compile_spec, EthosUCompileSpec): + return EthosUPartitioner(compile_spec, additional_checks) + elif isinstance(compile_spec, VgfCompileSpec): + return VgfPartitioner(compile_spec, additional_checks) + else: + raise ValueError("compile spec doesn't target any Arm Partitioner") + + +def create_quantizer(compile_spec: ArmCompileSpec): + if isinstance(compile_spec, TosaCompileSpec): + return TOSAQuantizer(compile_spec) + elif isinstance(compile_spec, EthosUCompileSpec): + return EthosUQuantizer(compile_spec) + elif isinstance(compile_spec, VgfCompileSpec): + return VgfQuantizer(compile_spec) + else: + raise ValueError("compile spec doesn't target any Arm Quantizer") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/arm_model_evaluator.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/arm_model_evaluator.py new file mode 100644 index 0000000..3d41f71 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/util/arm_model_evaluator.py @@ -0,0 +1,388 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import json +import logging +import os +import random +import tempfile +import zipfile + +from collections import defaultdict +from pathlib import Path +from typing import Any, cast, Optional, Tuple + +import torch +from torch.nn.modules import Module +from torch.utils._pytree import tree_flatten +from torch.utils.data import DataLoader +from torchvision import datasets, transforms # type: ignore[import-untyped] + + +# Logger for outputting progress for longer running evaluation +logger = logging.getLogger(__name__) +# Explicitly set logging level: MLETORCH-893 +logger.setLevel(logging.INFO) + + +# ImageNet 224x224 transforms (Resize->CenterCrop->ToTensor->Normalize) +# If future models require different preprocessing, extend this helper accordingly. +def _get_imagenet_224_transforms(): + """Return standard ImageNet 224x224 preprocessing transforms.""" + return transforms.Compose( + [ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(mean=[0.484, 0.454, 0.403], std=[0.225, 0.220, 0.220]), + ] + ) + + +def _build_calibration_loader( + dataset: datasets.ImageFolder, max_items: int +) -> DataLoader: + """Return a DataLoader over a deterministic, shuffled subset of size <= max_items. + + Shuffles with seed: ARM_EVAL_CALIB_SEED (int) or default 1337; then selects first k and + sorts indices to keep enumeration order stable while content depends on seed. + """ + k = min(max_items, len(dataset)) + seed_env = os.getenv("ARM_EVAL_CALIB_SEED") + default_seed = 1337 + if seed_env is not None: + try: + seed = int(seed_env) + except ValueError: + logger.warning( + "ARM_EVAL_CALIB_SEED is not an int (%s); using default seed %d", + seed_env, + default_seed, + ) + seed = default_seed + else: + seed = default_seed + rng = random.Random( + seed + ) # nosec B311 - deterministic shuffling for evaluation only + indices = list(range(len(dataset))) + rng.shuffle(indices) + selected = sorted(indices[:k]) + return torch.utils.data.DataLoader( + torch.utils.data.Subset(dataset, selected), batch_size=1, shuffle=False + ) + + +def _load_imagenet_folder(directory: str) -> datasets.ImageFolder: + """Shared helper to load an ImageNet-layout folder. + + Raises FileNotFoundError for a missing directory early to aid debugging. + """ + directory_path = Path(directory) + if not directory_path.exists(): + raise FileNotFoundError(f"Directory: {directory} does not exist.") + transform = _get_imagenet_224_transforms() + return datasets.ImageFolder(directory_path, transform=transform) + + +class GenericModelEvaluator: + """Base evaluator computing quantization error metrics and optional compression ratio. + + Subclasses can extend: provide calibration (get_calibrator) and override evaluate() + to add domain specific metrics (e.g. top-1 / top-5 accuracy). + """ + + @staticmethod + def evaluate_topk( + model: Module, + dataset: datasets.ImageFolder, + batch_size: int, + topk: int = 5, + log_every: int = 50, + ) -> Tuple[float, float]: + """Evaluate model top-1 / top-k accuracy. + + Args: + model: Torch module (should be in eval() mode prior to call). + dataset: ImageFolder style dataset. + batch_size: Batch size for evaluation. + topk: Maximum k for accuracy (default 5). + log_every: Log running accuracy every N batches. + Returns: + (top1_accuracy, topk_accuracy) + """ + # Some exported / quantized models (torchao PT2E) disallow direct eval()/train(). + # Try to switch to eval mode, but degrade gracefully if unsupported. + try: + model.eval() + except NotImplementedError: + # Attempt to enable train/eval overrides if torchao helper is present. + try: + from torchao.quantization.pt2e.utils import ( # type: ignore + allow_exported_model_train_eval, + ) + + allow_exported_model_train_eval(model) + try: + model.eval() + except Exception: + logger.debug( + "Model eval still not supported after allow_exported_model_train_eval; proceeding without explicit eval()." + ) + except Exception: + logger.debug( + "Model eval() unsupported and torchao allow_exported_model_train_eval not available; proceeding." + ) + loaded_dataset = DataLoader(dataset, batch_size=batch_size, shuffle=False) + top1_correct = 0 + topk_correct = 0 + total = 0 + with torch.inference_mode(): # disable autograd + some backend optimizations + for i, (image, target) in enumerate(loaded_dataset): + prediction = model(image) + topk_indices = torch.topk(prediction, k=topk, dim=1).indices + # target reshaped for broadcasting + target_view = target.view(-1, 1) + top1_correct += (topk_indices[:, :1] == target_view).sum().item() + topk_correct += (topk_indices == target_view).sum().item() + batch_sz = image.size(0) + total += batch_sz + if (i + 1) % log_every == 0 or total == len(dataset): + logger.info( + "Eval progress: %d / %d top1=%.4f top%d=%.4f", + total, + len(dataset), + top1_correct / total, + topk, + topk_correct / total, + ) + top1_accuracy = top1_correct / len(dataset) + topk_accuracy = topk_correct / len(dataset) + return top1_accuracy, topk_accuracy + + REQUIRES_CONFIG = False + + def __init__( + self, + model_name: str, + fp32_model: torch.nn.Module, + quant_model: torch.nn.Module, + example_input: Tuple[torch.Tensor], + tosa_output_path: Optional[str], + ) -> None: + self.model_name = model_name + + self.fp32_model = fp32_model + self.quant_model = quant_model + self.example_input = example_input + + if tosa_output_path: + self.tosa_output_path = tosa_output_path + else: + self.tosa_output_path = "" + + def get_model_error(self) -> defaultdict: + """Return per-output quantization error statistics. + + Metrics (lists per output tensor): + max_error + max_absolute_error + max_percentage_error (safe-divided; zero fp32 elements -> 0%) + mean_absolute_error + """ + fp32_outputs, _ = tree_flatten(self.fp32_model(*self.example_input)) + quant_outputs, _ = tree_flatten(self.quant_model(*self.example_input)) + + model_error_dict = defaultdict(list) + + for fp32_output, quant_output in zip(fp32_outputs, quant_outputs): + difference = fp32_output - quant_output + # Avoid divide by zero: elements where fp32 == 0 produce 0% contribution + percentage_error = torch.where( + fp32_output != 0, + difference / fp32_output * 100, + torch.zeros_like(difference), + ) + model_error_dict["max_error"].append(torch.max(difference).item()) + model_error_dict["max_absolute_error"].append( + torch.max(torch.abs(difference)).item() + ) + model_error_dict["max_percentage_error"].append( + torch.max(percentage_error).item() + ) + model_error_dict["mean_absolute_error"].append( + torch.mean(torch.abs(difference).float()).item() + ) + + return model_error_dict + + def get_compression_ratio(self) -> float: + """Compute the compression ratio of the outputted TOSA flatbuffer.""" + with tempfile.NamedTemporaryFile(delete=True, suffix=".zip") as temp_zip: + with zipfile.ZipFile( + temp_zip.name, "w", compression=zipfile.ZIP_DEFLATED + ) as f: + f.write(self.tosa_output_path) + + compression_ratio = os.path.getsize( + self.tosa_output_path + ) / os.path.getsize(temp_zip.name) + + return compression_ratio + + def evaluate(self) -> dict[str, Any]: + model_error_dict = self.get_model_error() + + output_metrics = {"name": self.model_name, "metrics": dict(model_error_dict)} + + if self.tosa_output_path: + # We know output_metrics["metrics"] is list since we just defined it, safe to ignore. + output_metrics["metrics"][ # type: ignore[index] + "compression_ratio" + ] = self.get_compression_ratio() + + return output_metrics + + +class ImageNetEvaluator(GenericModelEvaluator): + """Shared evaluator behaviour for ImageNet-style classifiers. + + Provides dataset loading, calibration loader and a standard `evaluate` that + computes top-1/top-5 accuracy. + """ + + REQUIRES_CONFIG = True + + def __init__( + self, + model_name: str, + fp32_model: Module, + quant_model: Module, + example_input: Tuple[torch.Tensor], + tosa_output_path: str | None, + batch_size: int, + validation_dataset_path: str, + ) -> None: + super().__init__( + model_name, fp32_model, quant_model, example_input, tosa_output_path + ) + self._batch_size = batch_size + self._validation_set_path = validation_dataset_path + + @staticmethod + def _load_dataset(directory: str) -> datasets.ImageFolder: + return _load_imagenet_folder(directory) + + @staticmethod + def get_calibrator(training_dataset_path: str) -> DataLoader: + dataset = ImageNetEvaluator._load_dataset(training_dataset_path) + return _build_calibration_loader(dataset, 1000) + + @classmethod + def from_config( + cls, + model_name: str, + fp32_model: Module, + quant_model: Module, + example_input: Tuple[torch.Tensor], + tosa_output_path: str | None, + config: dict[str, Any], + ) -> "ImageNetEvaluator": + return cls( + model_name, + fp32_model, + quant_model, + example_input, + tosa_output_path, + batch_size=config["batch_size"], + validation_dataset_path=config["validation_dataset_path"], + ) + + def evaluate(self) -> dict[str, Any]: + dataset = self._load_dataset(self._validation_set_path) + top1, top5 = GenericModelEvaluator.evaluate_topk( + self.quant_model, dataset, self._batch_size, topk=5 + ) + output = super().evaluate() + output["metrics"]["accuracy"] = {"top-1": top1, "top-5": top5} + return output + + +evaluators: dict[str, type[GenericModelEvaluator]] = { + "generic": GenericModelEvaluator, + "mv2": ImageNetEvaluator, + "deit_tiny": ImageNetEvaluator, + "resnet18": ImageNetEvaluator, +} + + +def evaluator_calibration_data( + evaluator_name: str, + evaluator_config: str | None, +): + evaluator = evaluators[evaluator_name] + + if hasattr(evaluator, "get_calibrator"): + assert evaluator_config is not None + + config_path = Path(evaluator_config) + with config_path.open() as f: + config = json.load(f) + + # All current evaluators exposing calibration implement a uniform + # static method signature: get_calibrator(training_dataset_path: str) + # so we can call it generically without enumerating classes. + return evaluator.get_calibrator( + training_dataset_path=config["training_dataset_path"] + ) + + +def evaluate_model( + model_name: str, + intermediates: str, + target: str, + model_fp32: torch.nn.Module, + model_quant: torch.nn.Module, + example_inputs: Tuple[torch.Tensor], + evaluator_name: str, + evaluator_config: str | None, +) -> None: + evaluator = evaluators[evaluator_name] + + intermediates_path = Path(intermediates) + tosa_paths = list(intermediates_path.glob("*.tosa")) + + if evaluator.REQUIRES_CONFIG: + assert evaluator_config is not None + config_path = Path(evaluator_config) + with config_path.open() as f: + config = json.load(f) + + # Prefer a subclass provided from_config if available. + if hasattr(evaluator, "from_config"): + factory = cast(Any, evaluator.from_config) # type: ignore[attr-defined] + init_evaluator = factory( + model_name, + model_fp32, + model_quant, + example_inputs, + str(tosa_paths[0]), + config, + ) + else: + raise RuntimeError( + f"Evaluator {evaluator_name} requires config but does not implement from_config()" + ) + else: + init_evaluator = evaluator( + model_name, model_fp32, model_quant, example_inputs, str(tosa_paths[0]) + ) + + quant_metrics = init_evaluator.evaluate() + output_json_path = intermediates_path / f"{target}-quant_metrics.json" + + with output_json_path.open("w") as json_file: + json.dump(quant_metrics, json_file) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/__init__.py new file mode 100644 index 0000000..88be90e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/__init__.py @@ -0,0 +1,11 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +from .backend import VgfBackend # noqa: F401 +from .compile_spec import VgfCompileSpec # noqa: F401 +from .partitioner import VgfPartitioner # noqa: F401 + +__all__ = ["VgfBackend", "VgfPartitioner", "VgfCompileSpec"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/backend.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/backend.py new file mode 100644 index 0000000..0e931af --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/backend.py @@ -0,0 +1,172 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Main implementation of AoT flow to partition and preprocess for VGF target +# backends. This flow converts via TOSA, to an encoding of TOSA known as VGF +# this form is used where the final JIT compile is performed on target (in the +# runtime delegate executorch::runtime::BackendInterface::init +# +"""Ahead-of-time Arm VGF backend built on the shared TOSA pipeline.""" + +import logging +import os # nosec B404 - used alongside subprocess for tool invocation +import subprocess # nosec B404 - required to drive external converter CLI +import tempfile +from typing import final, List + +from executorch.backends.arm.tosa.backend import ( # type: ignore[import-not-found] + arm_get_first_delegation_tag, + TOSABackend, +) + +from executorch.backends.arm.vgf.compile_spec import ( # type: ignore[import-not-found] + VgfCompileSpec, +) +from executorch.backends.arm.vgf.model_converter import ( # type: ignore[import-not-found] + require_model_converter_binary, +) +from executorch.exir.backend.backend_details import ( # type: ignore[import-not-found] + BackendDetails, + PreprocessResult, +) +from executorch.exir.backend.compile_spec_schema import ( # type: ignore[import-not-found] + CompileSpec, +) +from torch.export.exported_program import ExportedProgram + +# debug functionality +logger = logging.getLogger(__name__) + + +@final +class VgfBackend(BackendDetails): + """BackendDetails subclass for delegation to VGF compatible devices. + + This enables encapsulated TOSA on target device and JIT compilation on + suitable platforms. + + """ + + @staticmethod + def _compile_tosa_flatbuffer( + tosa_flatbuffer: bytes, + compile_spec: VgfCompileSpec, + tag_name: str = "", + ) -> bytes: + """Compile a TOSA flatbuffer into a target-specific binary stream. + + Args: + tosa_flatbuffer (bytes): Serialized TOSA graph produced by + ``TOSABackend``. + compile_spec (VgfCompileSpec): Compile specification providing + converter flags and artifact paths. + tag_name (str): Optional suffix used when producing debug outputs. + + Returns: + bytes: Target-specific VGF binary stream. + + """ + compile_flags = compile_spec.compiler_flags + artifact_path = compile_spec.get_intermediate_path() + # Pass on the TOSA flatbuffer to the vgf compiler. + binary = vgf_compile(tosa_flatbuffer, compile_flags, artifact_path, tag_name) + return binary + + @staticmethod + def preprocess( + edge_program: ExportedProgram, + compile_specs: List[CompileSpec], + ) -> PreprocessResult: + """Lower the exported program and compile it for a VGF target. + + Args: + edge_program (ExportedProgram): Program to lower to VGF. + compile_specs (List[CompileSpec]): Serialized VGF compile specs + supplied by the frontend. + + Returns: + PreprocessResult: Result containing the compiled VGF binary. + + """ + logger.info(f"{VgfBackend.__name__} preprocess") + + compile_spec = VgfCompileSpec.from_list(compile_specs) + # deduce TOSA compile_spec from VGF compile spec. We get a new + # compile spec list, containing only elements relevant for the + # TOSABackend. + tosa_compile_spec = TOSABackend.filter_tosa_compile_specs(compile_spec) + + # Backends doesn't allow inheritance, as stated in comments in exir/backend/backend_api.py + # ('All backend implementation are final...'), so use composition instead. + # preprocess returns the serialized TOSA flatbuffer in .processed_bytes, + # which can be passed on to next compilation step. + tosa_preprocess = TOSABackend._preprocess(edge_program, tosa_compile_spec) + + tag_name = arm_get_first_delegation_tag(edge_program.graph_module) + + binary = VgfBackend._compile_tosa_flatbuffer( + tosa_preprocess.processed_bytes, compile_spec, tag_name + ) + + return PreprocessResult(processed_bytes=binary) + + +def vgf_compile( + tosa_flatbuffer: bytes, + compile_flags: List[str], + artifact_path: str | None = None, + tag_name: str = "", +): + """Invoke the VGF compiler to convert a TOSA flatbuffer. + + Args: + tosa_flatbuffer (bytes): Serialized TOSA graph produced by + ``TOSABackend``. + compile_flags (List[str]): Command-line flags forwarded to + ``model-converter``. + artifact_path (str | None): Directory where debug artifacts are saved. + tag_name (str): Optional suffix used when producing debug outputs. + + Returns: + bytes: Compiled VGF binary emitted by ``model-converter``. + + """ + with tempfile.TemporaryDirectory() as tmpdir: + + # We currently write out a flatbuffer as input to the converter + tosaname = f"output_{tag_name}.tosa" + tosa_path = os.path.join(tmpdir, tosaname) + with open(tosa_path, "wb") as f: + f.write(tosa_flatbuffer) + + additional_flags = " ".join(compile_flags) + converter_binary = require_model_converter_binary() + vgf_path = tosa_path + ".vgf" + conversion_command = ( + f"{converter_binary} {additional_flags} -i {tosa_path} -o {vgf_path}" + ) + try: + subprocess.run( # nosec B602 - shell invocation constrained to trusted converter binary + [conversion_command], shell=True, check=True, capture_output=True + ) + except subprocess.CalledProcessError as process_error: + raise RuntimeError( + f"Vgf compiler ('{conversion_command}') failed with error:\n \ + {process_error.stderr.decode()}\n \ + Stdout:\n{process_error.stdout.decode()}" + ) + + if artifact_path: + logger.info(f"Emitting debug output to: {vgf_path=}") + os.makedirs(artifact_path, exist_ok=True) + cp = f"cp {vgf_path} {artifact_path}" + subprocess.run( # nosec B602 - shell copy of trusted artifact for debugging + cp, shell=True, check=True, capture_output=False + ) + + vgf_bytes = open(vgf_path, "rb").read() + return vgf_bytes diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/compile_spec.py new file mode 100644 index 0000000..b5b13f5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/compile_spec.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( # noqa: unused + ArmPassPipelineConfig, +) +from executorch.backends.arm.tosa import ( # type: ignore[import-not-found] + TosaSpecification, +) + +# debug functionality +logger = logging.getLogger(__name__) + + +class VgfCompileSpec(ArmCompileSpec): + """Compile specification for VGF-compatible targets.""" + + def __init__( + self, + tosa_spec: TosaSpecification | str | None = None, + compiler_flags: list[str] | None = None, + ): + """Normalise inputs and populate the underlying Arm compile spec. + + Args: + tosa_spec (TosaSpecification | str | None): TOSA specification to + target. Strings are parsed via + :meth:`TosaSpecification.create_from_string`. Defaults to + ``"TOSA-1.0+FP+INT"``. + compiler_flags (list[str] | None): Optional converter-backend flags. + """ + if tosa_spec is None: + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+FP+INT") + elif isinstance(tosa_spec, str): + tosa_spec = TosaSpecification.create_from_string(tosa_spec) + + if compiler_flags is None: + compiler_flags = [] + self._set_compile_specs(tosa_spec, compiler_flags) + self.validate() + + def validate(self): + """Validate the configuration against VGF-supported TOSA profiles.""" + tosa_version = self.tosa_spec.version # type: ignore[attr-defined] + tosa_profiles = self.tosa_spec.profiles # type: ignore[attr-defined] + + if tosa_version.major != 1: + raise ValueError( + "Arm backend only supports converter-backend for TOSA version 1. " + f"Invalid TOSA version: {tosa_version}" + ) + + if "FP" not in tosa_profiles and "INT" not in tosa_profiles: + raise ValueError( + "Arm backend only supports converter-backend for FP and/or INT. " + f"Invalid TOSA profile: {tosa_profiles}" + ) + + @classmethod + def get_output_format(cls) -> str: + """Return the artifact format emitted by this compile spec.""" + return "vgf" + + def _create_default_pipeline_config(self) -> ArmPassPipelineConfig: + config = super()._create_default_pipeline_config() + # GRPHCOMP-3140 / MLETORCH-1529 + config.disable_fuse_duplicate_users() + return config diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/model_converter.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/model_converter.py new file mode 100644 index 0000000..dffbf76 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/model_converter.py @@ -0,0 +1,34 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +from shutil import which +from typing import Optional + +MODEL_CONVERTER_BINARY = "model-converter" +_MODEL_CONVERTER_FALLBACK_BINARY = "model_converter" + + +def find_model_converter_binary() -> Optional[str]: + """Return the name of the first model converter executable on PATH.""" + + for candidate in (MODEL_CONVERTER_BINARY, _MODEL_CONVERTER_FALLBACK_BINARY): + if which(candidate): + return candidate + return None + + +def require_model_converter_binary() -> str: + """Return a usable model converter executable or raise a helpful error.""" + + binary = find_model_converter_binary() + if binary is None: + tried = ", ".join((MODEL_CONVERTER_BINARY, _MODEL_CONVERTER_FALLBACK_BINARY)) + raise RuntimeError( + "Unable to locate a model converter executable. " + f"Tried: {tried}. Ensure the Model Converter is installed and on PATH." + ) + return binary diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/partitioner.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/partitioner.py new file mode 100644 index 0000000..96c4408 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/arm/vgf/partitioner.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import final, Optional, Sequence + +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.vgf import VgfBackend, VgfCompileSpec +from executorch.exir.backend.partitioner import DelegationSpec +from torch.fx.passes.operator_support import OperatorSupportBase + + +@final +class VgfPartitioner(TOSAPartitioner): + """ + Partitions subgraphs supported by the Arm Vgf backend. + + Args: + compile_spec: The Vgf compilation specification. + additional_checks: Optional sequence of additional operator support checks. + """ + + def __init__( + self, + compile_spec: VgfCompileSpec, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + ) -> None: + # Override the delegation spec for Vgf + self.delegation_spec = DelegationSpec( + VgfBackend.__name__, compile_spec.to_list() + ) + self.additional_checks = additional_checks + self.tosa_spec = compile_spec.tosa_spec diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/CMakeLists.txt new file mode 100644 index 0000000..7912d7f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/CMakeLists.txt @@ -0,0 +1,108 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# Source root directory for executorch +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Codegen.cmake) +include(FetchContent) + +# CMSIS-NN configuration with dynamic path detection +set(CMSIS_NN_VERSION + "v7.0.0" + CACHE STRING "CMSIS-NN version to download" +) +set(CMSIS_NN_LOCAL_PATH + "" + CACHE PATH "Path to existing local CMSIS-NN installation" +) + +# Try to find existing / local CMSIS-NN installation. This is useful for +# debugging and testing with local changes. This is not common, as the CMSIS-NN +# library is downloaded via FetchContent in the default/regular case. +if(CMSIS_NN_LOCAL_PATH AND EXISTS "${CMSIS_NN_LOCAL_PATH}") + message(STATUS "Using CMSIS-NN from specified path: ${CMSIS_NN_LOCAL_PATH}") + add_subdirectory(${CMSIS_NN_LOCAL_PATH} _deps/cmsis_nn-build) +else() + # Use FetchContent with automatic fallback + message(STATUS "Using CMSIS-NN via FetchContent") + + FetchContent_Declare( + cmsis_nn + GIT_REPOSITORY https://github.com/ARM-software/CMSIS-NN.git + GIT_TAG ${CMSIS_NN_VERSION} + GIT_SHALLOW TRUE + ) + + include(${CMAKE_SOURCE_DIR}/cmake/modules/PatchCmsisNN.cmake) + FetchContent_Populate(cmsis_nn) + patch_cmsis_nn_if_needed() + add_subdirectory(${cmsis_nn_SOURCE_DIR} ${cmsis_nn_BINARY_DIR}) +endif() + +# Cortex-M ops kernel sources +set(_cortex_m_kernels__srcs + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantize_per_tensor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_dequantize_per_tensor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_add.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_avg_pool2d.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_conv2d.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_depthwise_conv2d.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_linear.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_mul.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_minimum.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_maximum.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_softmax.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_transpose.cpp +) + +# Generate C++ bindings to register kernels into Executorch +set(_yaml_file ${CMAKE_CURRENT_LIST_DIR}/ops/operators.yaml) +gen_selected_ops(LIB_NAME "cortex_m_ops_lib" OPS_SCHEMA_YAML "${_yaml_file}") +generate_bindings_for_kernels( + LIB_NAME "cortex_m_ops_lib" CUSTOM_OPS_YAML "${_yaml_file}" +) + +# Build library for cortex_m_kernels +add_library(cortex_m_kernels ${_cortex_m_kernels__srcs}) + +# Use PRIVATE for implementation dependencies to avoid INTERFACE pollution +target_link_libraries( + cortex_m_kernels + PRIVATE cmsis-nn + PRIVATE executorch + PRIVATE kernels_util_all_deps +) + +# Include directories for cortex_m_kernels +target_include_directories( + cortex_m_kernels PRIVATE ${EXECUTORCH_ROOT}/.. + ${EXECUTORCH_ROOT}/runtime/core/portable_type/c10 +) + +# cortex_m_ops_lib: Register Cortex-M ops kernels into Executorch runtime +gen_operators_lib( + LIB_NAME "cortex_m_ops_lib" KERNEL_LIBS cortex_m_kernels DEPS executorch +) + +install( + TARGETS cortex_m_kernels cortex_m_ops_lib cmsis-nn + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/executorch/backends/cortex_m/ops/ +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/README.md new file mode 100644 index 0000000..898c815 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/README.md @@ -0,0 +1,3 @@ +# Cortex-M Backend + +WIP. This is a temporary/placeholder backend for Cortex-M CPUs. It is not intended to be used in production, but rather as a proof of concept. Things will change without notice. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/BUCK new file mode 100644 index 0000000..5630c92 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/BUCK @@ -0,0 +1,11 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/TARGETS new file mode 100644 index 0000000..18b387c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/TARGETS @@ -0,0 +1,24 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("targets.bzl", "define_common_targets") + +oncall("executorch") + +runtime.python_library( + name = "ops", + srcs = [ + "operators.py", + ], + deps = [ + "fbcode//caffe2:torch", + "//executorch/backends/cortex_m/passes:passes_utils", + "//executorch/backends/cortex_m/quantizer:quantization_configs", + ], +) + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/cmsis_scratch_buffer_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/cmsis_scratch_buffer_context.h similarity index 99% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/cmsis_scratch_buffer_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/cmsis_scratch_buffer_context.h index 4672f05..4b9fdae 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/cmsis_scratch_buffer_context.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/cmsis_scratch_buffer_context.h @@ -7,8 +7,10 @@ */ #pragma once -#include "arm_nnfunctions.h" #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} namespace cortex_m { namespace native { diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h new file mode 100644 index 0000000..71cf718 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * Copyright 2025 Arm Limited and/or its affiliates. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +extern "C" { +#include "arm_nn_types.h" +} + +using Tensor = torch::executor::Tensor; +using ScalarType = executorch::aten::ScalarType; +using Scalar = torch::executor::Scalar; +using Error = executorch::runtime::Error; +using IntArrayRef = executorch::aten::ArrayRef; +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +// From arm_nn_math_types.h +#define ARM_NN_Q31_MAX ((int32_t)(0x7FFFFFFFL)) +#define ARM_NN_Q31_MIN ((int32_t)(0x80000000L)) + +// Basic tensor type / layout validation and dimension order checking +inline void validate_cmsis_nn_tensor_requirements( + const Tensor& input1, + const Tensor& input2, + Tensor& output, + ScalarType expected_dtype = ScalarType::Char, + bool require_channels_last = false, + bool require_same_sizes = true) { + // Basic dtype validation + ET_CHECK_MSG( + input1.scalar_type() == expected_dtype, + "Input1 dtype must be %hhd, got %hhd", + expected_dtype, + input1.scalar_type()); + ET_CHECK_MSG( + input2.scalar_type() == expected_dtype, + "Input2 dtype must be %hhd, got %hhd", + expected_dtype, + input2.scalar_type()); + ET_CHECK_MSG( + output.scalar_type() == expected_dtype, + "Output dtype must be %hhd, got %hhd", + expected_dtype, + output.scalar_type()); + if (require_same_sizes) { + ET_CHECK_MSG( + input1.sizes() == input2.sizes(), + "Input1 and Input2 must have the same sizes"); + ET_CHECK_MSG( + output.sizes() == input1.sizes(), + "Output must have the same sizes as inputs"); + } + + // TBD (#16032): Validate dim_order + // TBD: Validate memory alignment (CMSIS-NN requirement) +} + +inline void validate_single_quant_params( + const Scalar& zero_point, + const Scalar& multiplier, + const Scalar& shift, + const char* param_name) { + int64_t zp_val = zero_point.to(); + int64_t mult_val = multiplier.to(); + int64_t shift_val = shift.to(); + + ET_CHECK_MSG( + mult_val >= std::numeric_limits::min() && + mult_val <= std::numeric_limits::max(), + "%s multiplier must be in int32 range [Value: %d]", + param_name, + mult_val); + + ET_CHECK_MSG( + shift_val >= -31 && shift_val <= 31, + "%s shift must be in range [-31, 31] [Value: %d]", + param_name, + shift_val); +} + +/** + * Validate quantization parameters for inputs and output. + * + * Checks that zero points fit in int8 range, multipliers fit in int32 range, + * and shifts are within a valid bit-shift range (0-31). + * + * Ensures parameters comply with Ahead-Of-Time (AOT) quantization requirements + * and CMSIS-NN kernel expectations. + * + * Raises errors via ET_KERNEL_CHECK if any check fails. + */ +inline void validate_quantization_params( + const Scalar& zero_point1, + const Scalar& multiplier1, + const Scalar& shift1, + const Scalar& zero_point2, + const Scalar& multiplier2, + const Scalar& shift2, + const Scalar& output_zero_point, + const Scalar& output_multiplier, + const Scalar& output_shift, + Tensor& output) { + validate_single_quant_params( + zero_point1, multiplier1, shift1, "Single quant Input1"); + validate_single_quant_params( + zero_point2, multiplier2, shift2, "Single quant Input2"); + validate_single_quant_params( + output_zero_point, + output_multiplier, + output_shift, + "Single quant Output"); +} + +inline bool is_channels_last_tensor(const Tensor& tensor) { + if (tensor.dim() != 4) { + return false; + } + + // When channels or spatial dims are 1 the layout information is ambiguous. + if (tensor.size(1) == 1 || (tensor.size(2) == 1 && tensor.size(3) == 1)) { + return true; + } + + constexpr executorch::aten::DimOrderType kChannelsLastDimOrder[] = { + 0, 2, 3, 1}; + executorch::aten::ArrayRef + channels_last_order(kChannelsLastDimOrder, 4); + + return tensor.dim_order() == channels_last_order; +} + +inline bool is_channel_broadcast(const Tensor& tensor1, const Tensor& tensor2) { + if (tensor1.dim() != tensor2.dim()) { + return false; + } + + if (tensor1.dim() != 4) { + return false; + } + + if (tensor1.size(1) != tensor2.size(1)) { + return false; + } + + const bool tensor1_channels_only = tensor1.numel() == tensor1.size(1); + const bool tensor2_channels_only = tensor2.numel() == tensor2.size(1); + + return tensor1_channels_only || tensor2_channels_only; +} + +// Refer to CMSIS-NN 'arm_nn_requantize' implementation for details: +// https://github.com/ARM-software/CMSIS-NN/blob/main/Include/arm_nnsupportfunctions.h#L1625 +// multiplier: Range {ARM_NN_Q31_MIN + 1, Q32_MAX} +// shift : Range {-31, 30} +inline bool validate_per_channel_quant_params( + const int32_t* multipliers, + const int32_t* shifts, + int num_channels) { + for (int i = 0; i < num_channels; ++i) { + // Multiplier: {ARM_NN_Q31_MIN + 1, ARM_NN_Q31_MAX} + if (multipliers[i] <= ARM_NN_Q31_MIN || multipliers[i] > ARM_NN_Q31_MAX) { + ET_LOG( + Error, + "weight_multiplier[%d] out of CMSIS-NN range: %d", + i, + multipliers[i]); + return false; + } + // Shift: {-31, 30} for arm_nn_requantize + if (shifts[i] < -31 || shifts[i] > 30) { + ET_LOG(Error, "weight_shift[%d] out of range: %d", i, shifts[i]); + return false; + } + } + return true; +} + +inline Error resize_to_broadcast_target_size( + const Tensor& input1, + const Tensor& input2, + Tensor& output) { + static constexpr int kTensorDimensionLimit = 5; + Tensor::SizesType expected_output_size[kTensorDimensionLimit]; + size_t expected_output_dim = 0; + auto err = torch::executor::get_broadcast_target_size( + input1, + input2, + expected_output_size, + kTensorDimensionLimit, + &expected_output_dim); + + if (err != Error::Ok) + return err; + + return executorch::runtime::resize_tensor( + output, {expected_output_size, expected_output_dim}); +} + +/** + * Convert Scalar to CMSIS-NN int32 format + * For multipliers, zero_points, etc. from quantize_multiplier_aot + */ +inline int32_t extractScalarToInt32(const Scalar& scalar_value) { + return static_cast(scalar_value.to()); +} + +/** + * Convert Scalar to CMSIS-NN int format + * For shift values from quantize_multiplier_aot + */ +inline int extractScalarToInt(const Scalar& scalar_value) { + return static_cast(scalar_value.to()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp new file mode 100644 index 0000000..d598ab2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +// Check for Helium/MVE support +#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) +#include +#define HAS_HELIUM_SIMD 1 +#endif + +namespace cortex_m { +namespace native { + +using Tensor = executorch::aten::Tensor; +using ScalarType = executorch::aten::ScalarType; +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +namespace { + +/** + * Asserts that the parameters are valid for float to int8 quantization. + */ +void check_dequantize_args( + const Tensor& input, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ensure input is char type + ET_CHECK_MSG( + input.scalar_type() == ScalarType::Char, + "input.scalar_type() %" PRId8 " is not char type", + static_cast(input.scalar_type())); + + // Check zp range + ET_CHECK_MSG( + zero_point >= quant_min, + "zero_point must be %" PRId64 " <= quant_min %" PRId64, + zero_point, + quant_min); + ET_CHECK_MSG( + zero_point <= quant_max, + "zero_point must be %" PRId64 " >= quant_max %" PRId64, + zero_point, + quant_max); + + // Check output dtype is float + ET_CHECK_MSG( + out.scalar_type() == ScalarType::Float, + "out.scalar_type() %" PRId8 " is not float", + static_cast(out.scalar_type())); + + // Check dtype is int8 (Char) + ET_CHECK_MSG( + dtype == ScalarType::Char, + "dtype %" PRId8 " is not int8 (Char)", + static_cast(dtype)); + + // Validate quant_min and quant_max for int8 + int32_t quant_min_lower_bound = std::numeric_limits::min(); + int32_t quant_max_upper_bound = std::numeric_limits::max(); + + ET_CHECK_MSG( + quant_min >= quant_min_lower_bound, + "quant_min out of bound for int8, expected quant_min_lower_bound: %" PRId32 + " actual quant_min: %" PRId64, + quant_min_lower_bound, + quant_min); + + ET_CHECK_MSG( + quant_max <= quant_max_upper_bound, + "quant_max out of bound for int8, expected quant_max_upper_bound: %" PRId32 + " actual quant_max: %" PRId64, + quant_max_upper_bound, + quant_max); +} + +/** + * Scalar implementation of quantization for a single value. + */ +template +F dequantize_val(float scale, int32_t zero_point, Q qvalue) { + return static_cast((static_cast(qvalue) - zero_point) * scale); +} +} // namespace + +Tensor& dequantize_per_tensor_out( + KernelRuntimeContext& context, + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ignore context for now + (void)context; + + // Resize output tensor to match input dimensions + torch::executor::Error err = resize_tensor(out, input.sizes()); + ET_CHECK_MSG( + err == torch::executor::Error::Ok, + "Failed to resize out Tensor in dequantize_per_tensor_out"); + + // Validate input parameters + check_dequantize_args(input, zero_point, quant_min, quant_max, dtype, out); + + int32_t zp = static_cast(zero_point); + + // Get pointers to input and output data + const int8_t* input_data = input.const_data_ptr(); + float* out_data = out.mutable_data_ptr(); + const size_t numel = input.numel(); + + size_t i = 0; +#if defined(HAS_HELIUM_SIMD) + // Helium MVE implementation for int8 to float quantization + static uint8x16_t voffset{ + 0x0, + 0x8, + 0x4, + 0xC, + 0x1, + 0x9, + 0x5, + 0xD, + 0x2, + 0xA, + 0x6, + 0xE, + 0x3, + 0xB, + 0x7, + 0xF}; + + int16x8_t vzp = vdupq_n_s16(static_cast(zp)); + float32x4_t vscale = vdupq_n_f32(static_cast(scale)); + + for (; i + 15 < numel; i += 16) { + int8x16_t in_084C195D2A6E3B7F = + vldrbq_gather_offset_s8(input_data, voffset); + + int16x8_t in_04152637 = vsubq_s16(vmovlbq_s8(in_084C195D2A6E3B7F), vzp); + int16x8_t in_8C9DAEBF = vsubq_s16(vmovltq_s8(in_084C195D2A6E3B7F), vzp); + + float32x4_t inf_0123 = vcvtq_f32_s32(vmovlbq_s16(in_04152637)); + float32x4_t inf_4567 = vcvtq_f32_s32(vmovltq_s16(in_04152637)); + float32x4_t inf_89AB = vcvtq_f32_s32(vmovlbq_s16(in_8C9DAEBF)); + float32x4_t inf_CDEF = vcvtq_f32_s32(vmovltq_s16(in_8C9DAEBF)); + + float32x4_t out_0123 = vmulq_f32(inf_0123, vscale); + float32x4_t out_4567 = vmulq_f32(inf_4567, vscale); + float32x4_t out_89AB = vmulq_f32(inf_89AB, vscale); + float32x4_t out_CDEF = vmulq_f32(inf_CDEF, vscale); + + vstrwq_f32(out_data + 0, out_0123); + vstrwq_f32(out_data + 4, out_4567); + vstrwq_f32(out_data + 8, out_89AB); + vstrwq_f32(out_data + 12, out_CDEF); + + input_data += 16; + out_data += 16; + } +#endif // defined(HAS_HELIUM_SIMD) + + for (; i < numel; i++) { + *out_data = dequantize_val(scale, zp, *input_data); + input_data++; + out_data++; + } + return out; +} + +Tensor& dequantize_per_tensor_out( + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + KernelRuntimeContext context; + return dequantize_per_tensor_out( + context, input, scale, zero_point, quant_min, quant_max, dtype, out); +} + +} // namespace native +} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_maximum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_maximum.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_maximum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_maximum.cpp index fc76f5c..71a907f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_maximum.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_maximum.cpp @@ -7,6 +7,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_minimum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_minimum.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_minimum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_minimum.cpp index 5a75cb8..f220aa2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_minimum.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_minimum.cpp @@ -9,6 +9,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp new file mode 100644 index 0000000..d92d266 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +// Check for Helium/MVE support +#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) +#include +#define HAS_HELIUM_SIMD 1 +#endif + +namespace cortex_m { +namespace native { + +using Tensor = executorch::aten::Tensor; +using ScalarType = executorch::aten::ScalarType; +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +namespace { + +/** + * Asserts that the parameters are valid for float to int8 quantization. + */ +void check_quantize_args( + const Tensor& input, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ensure input is float type + ET_CHECK_MSG( + input.scalar_type() == ScalarType::Float, + "input.scalar_type() %" PRId8 " is not float type", + static_cast(input.scalar_type())); + + // Check output dtype is int8 + ET_CHECK_MSG( + out.scalar_type() == ScalarType::Char, + "out.scalar_type() %" PRId8 " is not int8 (Char)", + static_cast(out.scalar_type())); + + // Check dtype is int8 + ET_CHECK_MSG( + dtype == ScalarType::Char, + "dtype %" PRId8 " is not int8 (Char)", + static_cast(dtype)); + + // Validate quant_min and quant_max for int8 + int32_t quant_min_lower_bound = std::numeric_limits::min(); + int32_t quant_max_upper_bound = std::numeric_limits::max(); + + ET_CHECK_MSG( + quant_min >= quant_min_lower_bound, + "quant_min out of bound for int8, expected quant_min_lower_bound: %" PRId32 + " actual quant_min: %" PRId64, + quant_min_lower_bound, + quant_min); + + ET_CHECK_MSG( + quant_max <= quant_max_upper_bound, + "quant_max out of bound for int8, expected quant_max_upper_bound: %" PRId32 + " actual quant_max: %" PRId64, + quant_max_upper_bound, + quant_max); +} + +/** + * Scalar implementation of quantization for a single value. + */ +template +Q quantize_val( + F inv_scale, + int32_t zero_point, + F value, + int64_t quant_min, + int64_t quant_max) { + int32_t qvalue = + zero_point + static_cast(std::nearbyint(inv_scale * value)); + qvalue = std::max(qvalue, static_cast(quant_min)); + qvalue = std::min(qvalue, static_cast(quant_max)); + return static_cast(qvalue); +} + +} // namespace + +Tensor& quantize_per_tensor_out( + KernelRuntimeContext& context, + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ignore context for now + (void)context; + + // Resize output tensor to match input dimensions + torch::executor::Error err = resize_tensor(out, input.sizes()); + ET_CHECK_MSG( + err == torch::executor::Error::Ok, + "Failed to resize out Tensor in quantize_per_tensor_out"); + + // Validate input parameters + check_quantize_args(input, quant_min, quant_max, dtype, out); + + // Pre-compute inverse scale for better performance + float inv_scale = 1.0f / static_cast(scale); + int32_t zp = static_cast(zero_point); + int32_t qmin = static_cast(quant_min); + int32_t qmax = static_cast(quant_max); + + // Get pointers to input and output data + const float* input_data = input.const_data_ptr(); + int8_t* out_data = out.mutable_data_ptr(); + const size_t numel = input.numel(); + + size_t i = 0; + +#if defined(HAS_HELIUM_SIMD) + // Helium MVE implementation for float32 to int8 quantization + static uint8x16_t voffset{ + 0x0, + 0x8, + 0x4, + 0xC, + 0x1, + 0x9, + 0x5, + 0xD, + 0x2, + 0xA, + 0x6, + 0xE, + 0x3, + 0xB, + 0x7, + 0xF}; + + float32x4_t inv_scale_vec = vdupq_n_f32(inv_scale); + + // Magic number for float to int conversion, round to nearest even integer + // int magic_round(float f): interpret_as_int32(f + magic_float) - magic_int + // where, + // magic_float = 12582912.0f = (2 ** 23 + 2 ** 22) = (1.5 * 2 ** 23) + // magic_int = 1262485504 = 0x4B400000 = bit_pattern_as_int32(magic_float) + + float magic_float = 12582912.0f; + int32_t magic_int = 1262485504; + + float32x4_t vmagic_float = vdupq_n_f32(magic_float); + int32x4_t vmagic_int_less_zp = + vdupq_n_s32(magic_int - static_cast(zp)); + + int16x8_t vqmin = vdupq_n_s16(qmin); + int16x8_t vqmax = vdupq_n_s16(qmax); + + // TODO: Measure performnce, we are spilling + for (; i + 15 < numel; i += 16) { + float32x4_t in_0123 = vldrwq_f32(input_data + 0); + float32x4_t in_4567 = vldrwq_f32(input_data + 4); + float32x4_t in_89AB = vldrwq_f32(input_data + 8); + float32x4_t in_CDEF = vldrwq_f32(input_data + 12); + + float32x4_t outf_0123 = vfmaq_f32(vmagic_float, in_0123, inv_scale_vec); + float32x4_t outf_4567 = vfmaq_f32(vmagic_float, in_4567, inv_scale_vec); + float32x4_t outf_89AB = vfmaq_f32(vmagic_float, in_89AB, inv_scale_vec); + float32x4_t outf_CDEF = vfmaq_f32(vmagic_float, in_CDEF, inv_scale_vec); + + int32x4_t out_0123 = + vsubq_s32(vreinterpretq_s32_f32(outf_0123), vmagic_int_less_zp); + int32x4_t out_4567 = + vsubq_s32(vreinterpretq_s32_f32(outf_4567), vmagic_int_less_zp); + int32x4_t out_89AB = + vsubq_s32(vreinterpretq_s32_f32(outf_89AB), vmagic_int_less_zp); + int32x4_t out_CDEF = + vsubq_s32(vreinterpretq_s32_f32(outf_CDEF), vmagic_int_less_zp); + + int16x8_t out_04152637; + int16x8_t out_8C9DAEBF; + out_04152637 = vmovnbq_s32(out_04152637, out_0123); + out_04152637 = vmovntq_s32(out_04152637, out_4567); + out_8C9DAEBF = vmovnbq_s32(out_8C9DAEBF, out_89AB); + out_8C9DAEBF = vmovntq_s32(out_8C9DAEBF, out_CDEF); + + int16x8_t out_04152637_clamped = + vminq_s16(vmaxq_s16(out_04152637, vqmin), vqmax); + int16x8_t out_8C9DAEBF_clamped = + vminq_s16(vmaxq_s16(out_8C9DAEBF, vqmin), vqmax); + + int8x16_t out_084C195D2A6E3B7F; + out_084C195D2A6E3B7F = + vmovnbq_s16(out_084C195D2A6E3B7F, out_04152637_clamped); + out_084C195D2A6E3B7F = + vmovntq_s16(out_084C195D2A6E3B7F, out_8C9DAEBF_clamped); + + vstrbq_scatter_offset_s8(out_data, voffset, out_084C195D2A6E3B7F); + input_data += 16; + out_data += 16; + } +#endif // defined(HAS_HELIUM_SIMD) + + for (; i < numel; i++) { + *out_data = + quantize_val(inv_scale, zp, *input_data, qmin, qmax); + input_data++; + out_data++; + } + + return out; +} + +Tensor& quantize_per_tensor_out( + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + KernelRuntimeContext context; + return quantize_per_tensor_out( + context, input, scale, zero_point, quant_min, quant_max, dtype, out); +} + +} // namespace native +} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_add.cpp similarity index 74% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_add.cpp index f607977..019ab4c 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_add.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_add.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -9,6 +9,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { using KernelRuntimeContext = torch::executor::KernelRuntimeContext; @@ -16,18 +21,16 @@ using KernelRuntimeContext = torch::executor::KernelRuntimeContext; Tensor& quantized_add_out( KernelRuntimeContext& context, const Tensor& input1_int8, - const int64_t input1_zero_point, - const int64_t input1_multiplier, - const int64_t input1_shift, + const Scalar& input1_zero_point, + const Scalar& input1_multiplier, + const Scalar& input1_shift, const Tensor& input2_int8, - const int64_t input2_zero_point, - const int64_t input2_multiplier, - const int64_t input2_shift, - const int64_t output_zero_point, - const int64_t output_multiplier, - const int64_t output_shift, - const int64_t activation_min, - const int64_t activation_max, + const Scalar& input2_zero_point, + const Scalar& input2_multiplier, + const Scalar& input2_shift, + const Scalar& output_zero_point, + const Scalar& output_multiplier, + const Scalar& output_shift, Tensor& out) { // Validate tensor types and dim order bool channel_broadcast = is_channel_broadcast(input1_int8, input2_int8); @@ -53,29 +56,29 @@ Tensor& quantized_add_out( out); ET_LOG( - Debug, + Info, "quantized_add_out: input1_int8.sizes() = %zu", input1_int8.sizes().size()); - int32_t zp1 = static_cast(input1_zero_point); - int32_t input1_mult = static_cast(input1_multiplier); - int input1_shift_val = static_cast(input1_shift); - int32_t zp2 = static_cast(input2_zero_point); - int32_t input2_mult = static_cast(input2_multiplier); - int input2_shift_val = static_cast(input2_shift); - int32_t out_zp = static_cast(output_zero_point); - int32_t output_mult = static_cast(output_multiplier); - int output_shift_val = static_cast(output_shift); + int32_t zp1 = extractScalarToInt32(input1_zero_point); + int32_t input1_mult = extractScalarToInt32(input1_multiplier); + int input1_shift_val = extractScalarToInt(input1_shift); + int32_t zp2 = extractScalarToInt32(input2_zero_point); + int32_t input2_mult = extractScalarToInt32(input2_multiplier); + int input2_shift_val = extractScalarToInt(input2_shift); + int32_t out_zp = extractScalarToInt32(output_zero_point); + int32_t output_mult = extractScalarToInt32(output_multiplier); + int output_shift_val = extractScalarToInt(output_shift); int8_t* input1_ptr = input1_int8.data_ptr(); int8_t* input2_ptr = input2_int8.data_ptr(); // Left shift to maximize precision const int32_t left_shift = 20; - const int32_t act_min = static_cast(activation_min); - const int32_t act_max = static_cast(activation_max); + const int32_t activation_min = std::numeric_limits::min(); + const int32_t activation_max = std::numeric_limits::max(); ET_LOG( - Debug, + Info, "Using AoT-computed parameters: input1[mult=%d, shift=%d], input2[mult=%d, shift=%d], output[mult=%d, shift=%d]", input1_mult, input1_shift_val, @@ -123,8 +126,8 @@ Tensor& quantized_add_out( static_cast(out_zp), output_mult, output_shift_val, - act_min, - act_max, + activation_min, + activation_max, adds_per_loop); if (status != ARM_CMSIS_NN_SUCCESS) { @@ -138,7 +141,7 @@ Tensor& quantized_add_out( } } ET_LOG( - Debug, + Info, "quantized_add_out: Successfully completed with AoT-computed parameters!"); return out; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp new file mode 100644 index 0000000..dfdedbd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2025 Arm Limited and/or its affiliates. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "cortex_m_ops_common.h" + +extern "C" { +#include "arm_nnfunctions.h" +} + +namespace cortex_m { +namespace native { + +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +Tensor& quantized_avg_pool2d_out( + KernelRuntimeContext& context, + const Tensor& input, + const IntArrayRef kernel_size, + const IntArrayRef stride, + const IntArrayRef padding, + const Scalar& zero_point, + const Scalar& multiplier, + const Scalar& shift, + Tensor& out) { + if (input.dim() != 4 || out.dim() != 4) { + ET_LOG(Error, "quantized_avg_pool2d_out: tensors must be 4-D"); + context.fail(Error::InvalidArgument); + return out; + } + int32_t batch = static_cast(input.size(0)); + int32_t channels = static_cast(input.size(1)); + int32_t input_h = static_cast(input.size(2)); + int32_t input_w = static_cast(input.size(3)); + int32_t kernel_h = static_cast(kernel_size[0]); + int32_t kernel_w = static_cast(kernel_size[1]); + int32_t stride_h = static_cast(stride[0]); + int32_t stride_w = static_cast(stride[1]); + int32_t pad_h = static_cast(padding[0]); + int32_t pad_w = static_cast(padding[1]); + int32_t output_h = static_cast(out.size(2)); + int32_t output_w = static_cast(out.size(3)); + const int32_t activation_min = std::numeric_limits::min(); + const int32_t activation_max = std::numeric_limits::max(); + + const int8_t* input_data = input.const_data_ptr(); + int8_t* output_data = out.mutable_data_ptr(); + + cmsis_nn_context cmsis_ctx; + cmsis_ctx.buf = nullptr; + cmsis_ctx.size = 0; + cmsis_nn_pool_params pool_params; + pool_params.stride.h = stride_h; + pool_params.stride.w = stride_w; + pool_params.padding.h = pad_h; + pool_params.padding.w = pad_w; + pool_params.activation.min = activation_min; + pool_params.activation.max = activation_max; + + cmsis_nn_dims input_dims{batch, input_h, input_w, channels}; + cmsis_nn_dims filter_dims{1, kernel_h, kernel_w, 1}; + cmsis_nn_dims output_dims{batch, output_h, output_w, channels}; + + arm_cmsis_nn_status status = arm_avgpool_s8( + &cmsis_ctx, + &pool_params, + &input_dims, + input_data, + &filter_dims, + &output_dims, + output_data); + if (status != ARM_CMSIS_NN_SUCCESS) { + ET_LOG( + Error, + "quantized_avg_pool2d_out: arm_avgpool_s8 failed with status [%d]", + status); + context.fail(Error::Internal); + } + return out; +} + +} // namespace native +} // namespace cortex_m \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_conv2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_conv2d.cpp similarity index 84% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_conv2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_conv2d.cpp index 7d44336..ad14af9 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_conv2d.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_conv2d.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -7,6 +7,10 @@ #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -21,9 +25,9 @@ bool validate_conv2d_arguments( const Tensor& weight, const torch::executor::optional& bias, const Tensor& output, - const Int64ArrayRef& stride, - const Int64ArrayRef& padding, - const Int64ArrayRef& dilation, + const IntArrayRef& stride, + const IntArrayRef& padding, + const IntArrayRef& dilation, const Tensor& requantize_multipliers, const Tensor& requantize_shifts) { if (input.dim() != kConvDim || weight.dim() != kConvDim || @@ -40,7 +44,7 @@ bool validate_conv2d_arguments( executorch::aten::ArrayRef channels_last_order(kChannelsLastDimOrder, 4); - if (input.size(1) > 1 && !is_channels_last_tensor(input)) { + if (input.size(1) > 1 && input.dim_order() != channels_last_order) { ET_LOG( Error, "quantized_conv2d_out: input must have channels_last dim_order (NHWC)"); @@ -48,7 +52,7 @@ bool validate_conv2d_arguments( return false; } - if (output.size(1) > 1 && !is_channels_last_tensor(input)) { + if (output.size(1) > 1 && output.dim_order() != channels_last_order) { ET_LOG( Error, "quantized_conv2d_out: output must have channels_last dim_order (NHWC)"); @@ -103,9 +107,9 @@ Tensor& quantized_conv2d_out( const Tensor& input, const Tensor& weight, const torch::executor::optional& bias, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef dilation, + const IntArrayRef stride, + const IntArrayRef padding, + const IntArrayRef dilation, const int64_t input_offset, const int64_t output_offset, const Tensor& requantize_multipliers, @@ -184,28 +188,24 @@ Tensor& quantized_conv2d_out( cmsis_context.buf = nullptr; cmsis_context.size = 0; - const int32_t buffer_bytes = arm_convolve_wrapper_s8_get_buffer_size( - &conv_params, &input_dims, &filter_dims, &output_dims); - if (buffer_bytes < 0) { - ET_LOG( - Error, "quantized_conv2d_out: CMSIS-NN buffer size calculation failed"); - context.fail(Error::Internal); - return out; - } + const size_t buffer_bytes = static_cast( + arm_convolve_s8_get_buffer_size(&input_dims, &filter_dims)); if (buffer_bytes > 0) { auto buffer_or_error = - context.allocate_temp(buffer_bytes, kCortexMMveAlignment); + context.allocate_temp(buffer_bytes, alignof(int16_t)); if (!buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_conv2d_out: failed to allocate scratch buffer (%d bytes, error %d)", - static_cast(buffer_bytes), - static_cast(buffer_or_error.error())); - context.fail(buffer_or_error.error()); - return out; + if (buffer_or_error.error() != Error::NotFound) { + ET_LOG( + Error, + "quantized_conv2d_out: failed to allocate scratch buffer (%d)", + static_cast(buffer_or_error.error())); + context.fail(buffer_or_error.error()); + return out; + } + } else { + cmsis_context.buf = buffer_or_error.get(); + cmsis_context.size = buffer_bytes; } - cmsis_context.buf = buffer_or_error.get(); - cmsis_context.size = buffer_bytes; } const arm_cmsis_nn_status status = arm_convolve_wrapper_s8( @@ -224,7 +224,7 @@ Tensor& quantized_conv2d_out( if (status != ARM_CMSIS_NN_SUCCESS) { ET_LOG( Error, - "quantized_conv2d_out: arm_convolve_wrapper_s8 failed with status %d", + "quantized_conv2d_out: arm_convolve_s8 failed with status %d", status); context.fail(Error::Internal); } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp index 8dec61e..9cf0625 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp @@ -1,5 +1,6 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -7,6 +8,10 @@ #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -21,9 +26,9 @@ bool validate_depthwise_conv2d_arguments( const Tensor& weight, const torch::executor::optional& bias, const Tensor& output, - const Int64ArrayRef& stride, - const Int64ArrayRef& padding, - const Int64ArrayRef& dilation, + const IntArrayRef& stride, + const IntArrayRef& padding, + const IntArrayRef& dilation, const int64_t depth_multiplier, const Tensor& requantize_multipliers, const Tensor& requantize_shifts) { @@ -140,9 +145,9 @@ Tensor& quantized_depthwise_conv2d_out( const Tensor& input, const Tensor& weight, const torch::executor::optional& bias, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef dilation, + const IntArrayRef stride, + const IntArrayRef padding, + const IntArrayRef dilation, const int64_t depth_multiplier, const int64_t input_offset, const int64_t output_offset, @@ -233,7 +238,7 @@ Tensor& quantized_depthwise_conv2d_out( } auto buffer_or_error = context.allocate_temp( - static_cast(buffer_bytes), kCortexMMveAlignment); + static_cast(buffer_bytes), alignof(int16_t)); if (!buffer_or_error.ok()) { ET_LOG( Error, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_linear.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_linear.cpp similarity index 80% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_linear.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_linear.cpp index 5d018cb..015fa80 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_linear.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_linear.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -9,6 +9,10 @@ #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { using KernelRuntimeContext = torch::executor::KernelRuntimeContext; @@ -19,15 +23,15 @@ Tensor& quantized_linear_out( const Tensor& weights, const torch::executor::optional& bias, const torch::executor::optional& kernel_sum, - const int64_t input_offset, - const int64_t filter_offset, - const int64_t output_offset, - const Int64ArrayRef requantize_multipliers, - const Int64ArrayRef requantize_shifts, - const int64_t activation_max, - const int64_t activation_min, + const Scalar& input_offset, + const Scalar& filter_offset, + const Scalar& output_offset, + const IntArrayRef requantize_multipliers, + const IntArrayRef requantize_shifts, + const Scalar& activation_max, + const Scalar& activation_min, Tensor& out) { - ET_LOG(Debug, "quantized_linear_out: called"); + ET_LOG(Info, "quantized_linear_out: called"); const int8_t* input_data = input.const_data_ptr(); const int8_t* weight_data = weights.const_data_ptr(); @@ -43,11 +47,11 @@ Tensor& quantized_linear_out( // Setup CMSIS-NN parameters cmsis_nn_fc_params fc_params; - fc_params.input_offset = static_cast(input_offset); - fc_params.filter_offset = static_cast(filter_offset); - fc_params.output_offset = static_cast(output_offset); - fc_params.activation.min = static_cast(activation_min); - fc_params.activation.max = static_cast(activation_max); + fc_params.input_offset = static_cast(input_offset.to()); + fc_params.filter_offset = static_cast(filter_offset.to()); + fc_params.output_offset = static_cast(output_offset.to()); + fc_params.activation.min = static_cast(activation_min.to()); + fc_params.activation.max = static_cast(activation_max.to()); cmsis_nn_per_tensor_quant_params per_tensor_quant_params; per_tensor_quant_params.multiplier = @@ -61,14 +65,14 @@ Tensor& quantized_linear_out( batches *= input.size(i); } ET_LOG( - Debug, + Info, "in features: %d, out_features: %d, batches: %d, kernel_sum_size: %d", in_feat, out_feat, batches, kernel_sum.has_value() ? kernel_sum.value().numel() : 0); ET_LOG( - Debug, + Info, "kernel_sum[0]: %d, kernel_sum[1]: %d", kernel_sum_data != nullptr ? kernel_sum_data[0] : -1, kernel_sum_data != nullptr ? kernel_sum_data[1] : -1); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_mul.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_mul.cpp similarity index 81% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_mul.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_mul.cpp index 524e74a..3d2d765 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_mul.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_quantized_mul.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -7,6 +7,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { namespace { @@ -21,12 +26,12 @@ using KernelRuntimeContext = torch::executor::KernelRuntimeContext; Tensor& quantized_mul_out( KernelRuntimeContext& context, const Tensor& input1_int8, - const int64_t input1_zero_point, + const Scalar& input1_zero_point, const Tensor& input2_int8, - const int64_t input2_zero_point, - const int64_t output_zero_point, - const int64_t output_multiplier, - const int64_t output_shift, + const Scalar& input2_zero_point, + const Scalar& output_zero_point, + const Scalar& output_multiplier, + const Scalar& output_shift, Tensor& out) { // Validate tensor types and quantization parameters @@ -39,8 +44,8 @@ Tensor& quantized_mul_out( /*require_channels_last=*/channel_broadcast, /*require_same_sizes=*/!channel_broadcast); - const int32_t kIdentityMultiplier(/*value=*/1); - const int32_t kZeroShift(/*value=*/0); + const Scalar kIdentityMultiplier(/*value=*/1); + const Scalar kZeroShift(/*value=*/0); validate_quantization_params( input1_zero_point, kIdentityMultiplier, @@ -56,11 +61,11 @@ Tensor& quantized_mul_out( // Extract quantization parameters int8_t* input1_ptr = input1_int8.data_ptr(); int8_t* input2_ptr = input2_int8.data_ptr(); - int32_t zp1 = static_cast(input1_zero_point); - int32_t zp2 = static_cast(input2_zero_point); - const int32_t out_zp = static_cast(output_zero_point); - const int32_t output_mult = static_cast(output_multiplier); - const int32_t output_shift_val = static_cast(output_shift); + int32_t zp1 = extractScalarToInt32(input1_zero_point); + int32_t zp2 = extractScalarToInt32(input2_zero_point); + const int32_t out_zp = extractScalarToInt32(output_zero_point); + const int32_t output_mult = extractScalarToInt32(output_multiplier); + const int32_t output_shift_val = extractScalarToInt32(output_shift); int32_t muls_per_loop = 0; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_softmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_softmax.cpp similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_softmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_softmax.cpp index c07a538..3e6f74e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_softmax.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_softmax.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -11,6 +11,11 @@ #include #include +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -72,9 +77,9 @@ Tensor& softmax_out( const int32_t diff_min_val = static_cast(diff_min); validate_single_quant_params( - static_cast(input_zero_point), - input_multiplier_val, - input_shift_val, + Scalar(static_cast(input_zero_point)), + Scalar(input_multiplier_val), + Scalar(input_shift_val), "softmax input"); const auto positive_dim = normalize_dim(input, dim); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_transpose.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_transpose.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_transpose.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_transpose.cpp index 7fcbc03..7befafc 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_transpose.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/op_transpose.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -11,6 +11,11 @@ #include #include +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -25,7 +30,7 @@ constexpr size_t kMaxSupportedDims = 4; Tensor& transpose_out( KernelRuntimeContext& context, const Tensor& input, - const Int64ArrayRef perm, + const IntArrayRef perm, Tensor& out) { if (input.scalar_type() != ScalarType::Char || out.scalar_type() != ScalarType::Char) { diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/operators.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/operators.py new file mode 100644 index 0000000..c62cac6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/operators.py @@ -0,0 +1,890 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from math import prod +from typing import Sequence + +import torch +import torch.nn.functional as F +from executorch.backends.cortex_m.passes.passes_utils import ( + dequantize_per_tensor_cmsis, + is_channel_broadcast, + quantize_per_tensor_cmsis, + requantize_cmsis, + SHIFT_INT8, +) +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + CMSIS_SOFTMAX_SCALE, + CMSIS_SOFTMAX_ZERO_POINT, +) +from executorch.exir.dialects._ops import ops as exir_ops + +# To provide the implementation of the operators +from torch.library import impl, Library, register_fake + + +# New operator library with a custom namespace to allow fusion etc. +lib = Library("cortex_m", "DEF") + +SOFTMAX_INPUT_INTEGER_BITS = 5 + +### +# dequantize_per_tensor +### + +lib.define( + "quantize_per_tensor(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype) -> (Tensor Z)" +) + +lib.define( + "quantize_per_tensor.out(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype, *, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantize_per_tensor") +def quantize_per_tensor_meta( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + return torch.empty_like(input, dtype=dtype) + + +@impl(lib, "quantize_per_tensor", "CompositeExplicitAutograd") +def quantize_per_tensor_impl( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + """ + The implementation of the quantize_per_tensor operator is the same as the + quantize_per_tensor operator in the edge dialect. + """ + return exir_ops.edge.quantized_decomposed.quantize_per_tensor.default( + input, scale, zero_point, quant_min, quant_max, dtype + ) + + +### +# dequantize_per_tensor +### + +lib.define( + "dequantize_per_tensor(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype) -> (Tensor Z)" +) +lib.define( + "dequantize_per_tensor.out(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype, *, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::dequantize_per_tensor") +def dequantize_per_tensor_meta( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + return torch.empty_like(input, dtype=torch.float) + + +@impl(lib, "dequantize_per_tensor", "CompositeExplicitAutograd") +def dequantize_per_tensor_impl( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + """ + The implementation of the dequantize_per_tensor operator is the same as the + dequantize_per_tensor operator in the edge dialect. + """ + return exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default( + input, scale, zero_point, quant_min, quant_max, dtype + ) + + +# Define the operator schema with multipliers and shifts (11 args) +lib.define( + "quantized_add(" + "Tensor self, Scalar self_zero_point, Scalar self_multiplier, Scalar self_shift, " + "Tensor other, Scalar other_zero_point, Scalar other_multiplier, Scalar other_shift, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift) -> Tensor" +) + +# Define the operator schema with multipliers and shifts (11 args + out tensor) +lib.define( + "quantized_add.out(" + "Tensor self, Scalar self_zero_point, Scalar self_multiplier, Scalar self_shift, " + "Tensor other, Scalar other_zero_point, Scalar other_multiplier, Scalar other_shift, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, " + "*, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_add") +def quantized_add_meta( + self: torch.Tensor, + self_zero_point: int, + self_multiplier: int, + self_shift: int, + other: torch.Tensor, + other_zero_point: int, + other_multiplier: int, + other_shift: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_add: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + if self.numel() > other.numel(): + output_tensor = self + else: + output_tensor = other + return torch.empty_like(output_tensor) + + +@impl(lib, "quantized_add", "CompositeExplicitAutograd") +def quantized_add_impl( + self: torch.Tensor, + self_zero_point: int, + self_multiplier: int, + self_shift: int, + other: torch.Tensor, + other_zero_point: int, + other_multiplier: int, + other_shift: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_add: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + self_shifted = (self.to(torch.int32) - self_zero_point) << SHIFT_INT8 + self_fp = requantize_cmsis(self_shifted, self_multiplier, self_shift) + + other_shifted = (other.to(torch.int32) - other_zero_point) << SHIFT_INT8 + other_fp = requantize_cmsis(other_shifted, other_multiplier, other_shift) + + result_fp = self_fp + other_fp + result_quantized = requantize_cmsis(result_fp, output_multiplier, output_shift) + result = torch.clamp(result_quantized + output_zero_point, -128, 127).to(torch.int8) + return result + + +# =================================================================== +# QUANTIZED MUL OPERATION DEFINITION +# =================================================================== +lib.define( + "quantized_mul(" + "Tensor self, Scalar self_zero_point, " + "Tensor other, Scalar other_zero_point, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift) -> Tensor" +) +lib.define( + "quantized_mul.out(" + "Tensor self, Scalar self_zero_point, " + "Tensor other, Scalar other_zero_point, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, " + "*, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_mul") +def quantized_mul_meta( + self: torch.Tensor, + self_zero_point: int, + other: torch.Tensor, + other_zero_point: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + # Broadcast to output shape + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_mul: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + if self.numel() > other.numel(): + output_tensor = self + else: + output_tensor = other + return torch.empty_like(output_tensor) + + +@impl(lib, "quantized_mul", "CompositeExplicitAutograd") +def quantized_mul_impl( + self: torch.Tensor, + self_zero_point: int, + other: torch.Tensor, + other_zero_point: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + # CMSIS-NN kernel multiplies raw int8 tensors (after zero-point offset) and + # only uses the output multiplier/shift for rescaling. Mirror that here to + # keep the composite implementation numerically aligned with the backend. + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_mul: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + self_int = self.to(torch.int32) - self_zero_point + other_int = other.to(torch.int32) - other_zero_point + result_fp = self_int * other_int + result_quantized = requantize_cmsis(result_fp, output_multiplier, output_shift) + result = torch.clamp(result_quantized + output_zero_point, -128, 127).to(torch.int8) + return result + + +# =================================================================== +# MINIMUM/MAXIMUM OPERATION DEFINITIONS +# =================================================================== +lib.define("minimum(Tensor self, Tensor other) -> Tensor") +lib.define("minimum.out(Tensor self, Tensor other, *, Tensor(a!) out) -> Tensor(a!)") + + +@register_fake("cortex_m::minimum") +def minimum_meta(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + assert self.dtype == other.dtype, ( + "Cortex-M minimum: dtype mismatch — " + f"got self.dtype={self.dtype}, other.dtype={other.dtype}" + ) + broadcasted_shape = torch.broadcast_shapes(self.shape, other.shape) + return torch.empty(broadcasted_shape, dtype=self.dtype, device=self.device) + + +@impl(lib, "minimum", "CompositeExplicitAutograd") +def minimum_impl(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + return torch.minimum(self, other) + + +lib.define("maximum(Tensor self, Tensor other) -> Tensor") +lib.define("maximum.out(Tensor self, Tensor other, *, Tensor(a!) out) -> Tensor(a!)") + + +@register_fake("cortex_m::maximum") +def maximum_meta(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + assert self.dtype == other.dtype, ( + "Cortex-M maximum: dtype mismatch — " + f"got self.dtype={self.dtype}, other.dtype={other.dtype}" + ) + broadcasted_shape = torch.broadcast_shapes(self.shape, other.shape) + return torch.empty(broadcasted_shape, dtype=self.dtype, device=self.device) + + +@impl(lib, "maximum", "CompositeExplicitAutograd") +def maximum_impl(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + return torch.maximum(self, other) + + +# =================================================================== +# QUANTIZED LINEAR OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_linear.out(" + "Tensor input, " + "Tensor weights, " + "Tensor? bias, " + "Tensor? kernel_sum, " + "Scalar input_offset, " + "Scalar filter_offset, " + "Scalar output_offset, " + "int[] requantize_multipliers, " + "int[] requantize_shifts, " + "Scalar activation_max, " + "Scalar activation_min, " + "*, Tensor(a!) out" + ") -> Tensor(a!)" +) + +# Define functional variant (non-out version) +lib.define( + "quantized_linear(" + "Tensor input, " + "Tensor weights, " + "Tensor? bias, " + "Tensor? kernel_sum, " + "Scalar input_offset, " + "Scalar filter_offset, " + "Scalar output_offset, " + "int[] requantize_multipliers, " + "int[] requantize_shifts, " + "Scalar activation_max, " + "Scalar activation_min" + ") -> Tensor" +) + + +# Fake meta function for shape inference (functional variant) +@register_fake("cortex_m::quantized_linear") +def quantized_linear_meta( + input, + weights, + bias, + kernel_sum, + input_offset, + filter_offset, + output_offset, + requantize_multipliers, + requantize_shifts, + activation_max, + activation_min, +) -> torch.Tensor: + + shape = (*input.shape[:-1], weights.shape[0]) + return torch.empty(shape, dtype=input.dtype, device=input.device) + + +# Functional variant implementation +@impl(lib, "quantized_linear", "CompositeExplicitAutograd") +def quantized_linear_impl( + input: torch.Tensor, + weights: torch.Tensor, + bias: torch.Tensor, + kernel_sum: torch.Tensor, + input_offset: int, + filter_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_max: int, + activation_min: int, +) -> torch.Tensor: + """ + Functional variant - creates output tensor and calls out variant + """ + + # Leaving both implementations for debugging purposes. + compute_using_kernel_sum = True + + if compute_using_kernel_sum: + weights_int32 = weights.to(torch.int32) + + input_int32 = input.to(torch.int32) + new_shape = (prod(input.shape[:-1]), input.shape[-1]) + input_reshaped = input_int32.reshape(new_shape) + + lhs_sum = torch.sum(input_reshaped, dim=-1, keepdim=True) * filter_offset + output = torch.mm(input_reshaped, weights_int32.T) + lhs_sum + kernel_sum + output_shape = (*input.shape[:-1], output.shape[-1]) + output_reshaped = output.reshape(output_shape) + else: + weights_int32 = weights.to(torch.int32) + filter_offset + + input_int32 = input.to(torch.int32) + input_offset + new_shape = (prod(input.shape[:-1]), input.shape[-1]) + input_reshaped = input_int32.reshape(new_shape) + + output = torch.mm(input_reshaped, weights_int32.T) + if bias is not None: + output = output + bias + output_shape = (*input.shape[:-1], output.shape[-1]) + output_reshaped = output.reshape(output_shape) + + output = requantize_cmsis( + output_reshaped, requantize_multipliers[0], requantize_shifts[0] + ) + output += output_offset + output = torch.clamp(output, activation_min, activation_max).to(torch.int8) + return output + + +# =================================================================== +# SOFTMAX OPERATION DEFINITION +# =================================================================== + +lib.define( + "softmax(Tensor input, int dim, int input_zero_point, int output_zero_point, int input_multiplier, int input_shift, int diff_min) -> Tensor" +) +lib.define( + "softmax.out(Tensor input, int dim, int input_zero_point, int output_zero_point, int input_multiplier, int input_shift, int diff_min, *, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::softmax") +def softmax_meta( + input: torch.Tensor, + dim: int, + input_zero_point: int, + output_zero_point: int, + input_multiplier: int, + input_shift: int, + diff_min: int, +) -> torch.Tensor: + return torch.empty_like(input, dtype=torch.int8) + + +@impl(lib, "softmax", "CompositeExplicitAutograd") +def softmax_impl( + input: torch.Tensor, + dim: int, + input_zero_point: int, + output_zero_point: int, + input_multiplier: int, + input_shift: int, + diff_min: int, +) -> torch.Tensor: + del diff_min # not used in reference path + if input.dtype != torch.int8: + raise TypeError( + f"cortex_m.softmax: expected int8 input tensor, got {input.dtype}" + ) + if output_zero_point != CMSIS_SOFTMAX_ZERO_POINT: + raise ValueError( + f"cortex_m.softmax: expected output_zero_point {CMSIS_SOFTMAX_ZERO_POINT}, got {output_zero_point}" + ) + + real_multiplier = float(input_multiplier) / float(1 << 31) + real_multiplier = math.ldexp(real_multiplier, input_shift) + input_scale = real_multiplier / float(1 << (31 - SOFTMAX_INPUT_INTEGER_BITS)) + if input_scale <= 0: + raise ValueError( + f"cortex_m.softmax: derived non-positive input scale {input_scale}" + ) + + input_fp = (input.to(torch.int32) - int(input_zero_point)).float() * input_scale + probs = torch.softmax(input_fp, dim=dim) + quantized = torch.round(probs / CMSIS_SOFTMAX_SCALE) + int(output_zero_point) + return quantized.clamp(-128, 127).to(torch.int8) + + +# =================================================================== +# TRANSPOSE OPERATION DEFINITION +# =================================================================== +lib.define("transpose(Tensor input, int[] perm) -> Tensor") +lib.define("transpose.out(Tensor input, int[] perm, *, Tensor(a!) out) -> Tensor(a!)") + + +@register_fake("cortex_m::transpose") +def transpose_meta(input: torch.Tensor, perm) -> torch.Tensor: + output_shape = [input.shape[idx] for idx in perm] + return torch.empty(output_shape, dtype=input.dtype, device=input.device) + + +@impl(lib, "transpose", "CompositeExplicitAutograd") +def transpose_impl(input: torch.Tensor, perm) -> torch.Tensor: + return input.permute(tuple(perm)).contiguous() + + +# =================================================================== +# QUANTIZED CONV2D OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_conv2d(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max" + ") -> Tensor" +) + + +lib.define( + "quantized_conv2d.out(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max, " + "*, Tensor(a!) out" + ") -> Tensor(a!)" +) + + +def _compute_conv2d_output_shape( + input_shape: torch.Size, + weight_shape: torch.Size, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], +) -> torch.Size: + batch = input_shape[0] + in_height = input_shape[2] + in_width = input_shape[3] + # We store the weights in OHWI layout (out, kernel_h, kernel_w, in) + kernel_height = weight_shape[1] + kernel_width = weight_shape[2] + + stride_h, stride_w = stride + pad_h, pad_w = padding + dilation_h, dilation_w = dilation + + out_channels = weight_shape[0] + out_height = ( + in_height + 2 * pad_h - dilation_h * (kernel_height - 1) - 1 + ) // stride_h + 1 + out_width = ( + in_width + 2 * pad_w - dilation_w * (kernel_width - 1) - 1 + ) // stride_w + 1 + return torch.Size([batch, out_channels, out_height, out_width]) + + +def _compute_depthwise_conv2d_output_shape( + input_shape: torch.Size, + weight_shape: torch.Size, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], +) -> torch.Size: + batch = input_shape[0] + in_height = input_shape[2] + in_width = input_shape[3] + # For depthwise conv, we store the weights in IHWO layout (1, kernel_h, kernel_w, out) + # where dimension 3 contains the output channels + kernel_height = weight_shape[1] + kernel_width = weight_shape[2] + + stride_h, stride_w = stride + pad_h, pad_w = padding + dilation_h, dilation_w = dilation + + out_channels = weight_shape[3] # IHWO format: output channels at dimension 3 + out_height = ( + in_height + 2 * pad_h - dilation_h * (kernel_height - 1) - 1 + ) // stride_h + 1 + out_width = ( + in_width + 2 * pad_w - dilation_w * (kernel_width - 1) - 1 + ) // stride_w + 1 + return torch.Size([batch, out_channels, out_height, out_width]) + + +@register_fake("cortex_m::quantized_conv2d") +def quantized_conv2d_meta( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + stride_vals = list(stride) + padding_vals = list(padding) + dilation_vals = list(dilation) + output_shape = _compute_conv2d_output_shape( + input.shape, weight.shape, stride_vals, padding_vals, dilation_vals + ) + return torch.empty( + output_shape, + dtype=torch.int8, + device=input.device, + memory_format=torch.channels_last, + ) + + +@impl(lib, "quantized_conv2d", "CompositeExplicitAutograd") +def quantized_conv2d_impl( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + if input.dim() != 4 or weight.dim() != 4: + raise RuntimeError("quantized_conv2d expects 4D input and weight tensors") + # Convert to int32 for accumulation and apply offsets + input_int32 = input.to(torch.int32) + int(input_offset) + weight_int32 = weight.to(torch.int32) + + if bias is None: + bias_int32 = torch.zeros( + weight.shape[0], dtype=torch.int32, device=input.device + ) + else: + bias_int32 = bias.to(torch.int32) + + input_channels = input.shape[1] + kernel_input_channels = weight.shape[3] + groups = input_channels // kernel_input_channels + + # Convert weights back to OIHW layout expected by torch.nn.functional.conv2d + weight_oi_hw = weight_int32.permute(0, 3, 1, 2).contiguous() + + conv_acc = F.conv2d( + input_int32, + weight_oi_hw, + bias_int32, + stride=tuple(stride), + padding=tuple(padding), + dilation=tuple(dilation), + groups=groups, + ) + + result_channels = [] + for output_channel_i in range(conv_acc.shape[1]): + result_channel = requantize_cmsis( + conv_acc[:, output_channel_i, :, :], + int(requantize_multipliers[output_channel_i]), + int(requantize_shifts[output_channel_i]), + ) + result_channels.append(result_channel) + + result = torch.stack(result_channels, dim=1) + + result += output_offset + result = torch.clamp(result, activation_min, activation_max) + + return result.to(torch.int8) + + +# =================================================================== +# QUANTIZED DEPTHWISE CONV2D OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_depthwise_conv2d(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int depth_multiplier, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max" + ") -> Tensor" +) + + +lib.define( + "quantized_depthwise_conv2d.out(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int depth_multiplier, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max, " + "*, Tensor(a!) out" + ") -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_depthwise_conv2d") +def quantized_depthwise_conv2d_meta( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + depth_multiplier: int, + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + stride_vals = list(stride) + padding_vals = list(padding) + dilation_vals = list(dilation) + output_shape = _compute_depthwise_conv2d_output_shape( + input.shape, weight.shape, stride_vals, padding_vals, dilation_vals + ) + return torch.empty( + output_shape, + dtype=torch.int8, + device=input.device, + memory_format=torch.channels_last, + ) + + +@impl(lib, "quantized_depthwise_conv2d", "CompositeExplicitAutograd") +def quantized_depthwise_conv2d_impl( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + depth_multiplier: int, + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + if input.dim() != 4 or weight.dim() != 4: + raise RuntimeError( + "quantized_depthwise_conv2d expects 4D input and weight tensors" + ) + + input_channels = input.shape[1] + groups = input_channels + + # Convert to int32 for accumulation and apply offsets + input_int32 = input.to(torch.int32) + int(input_offset) + weight_int32 = weight.to(torch.int32) + + if bias is None: + bias_int32 = torch.zeros( + weight.shape[3], + dtype=torch.int32, + device=input.device, # C_OUT is at dim 3 in IHWO + ) + else: + bias_int32 = bias.to(torch.int32) + + # Weight is in IHWO layout: [1, H, W, C_OUT] + # Convert to OIHW layout expected by torch.nn.functional.conv2d + # IHWO [1, H, W, C_OUT] -> OIHW [C_OUT, 1, H, W] + weight_oi_hw = weight_int32.permute(3, 0, 1, 2).contiguous() + + # Depthwise convolution has groups == input_channels + conv_acc = F.conv2d( + input_int32, + weight_oi_hw, + bias_int32, + stride=tuple(stride), + padding=tuple(padding), + dilation=tuple(dilation), + groups=groups, + ) + + result_channels = [] + for output_channel_i in range(conv_acc.shape[1]): + result_channel = requantize_cmsis( + conv_acc[:, output_channel_i, :, :], + int(requantize_multipliers[output_channel_i]), + int(requantize_shifts[output_channel_i]), + ) + result_channels.append(result_channel) + + result = torch.stack(result_channels, dim=1) + + result += output_offset + result = torch.clamp(result, activation_min, activation_max) + + return result.to(torch.int8) + + +# =================================================================== +# QUANTIZED AVG_POOL2D OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_avg_pool2d(" + "Tensor input, " + "int[] kernel_size, " + "int[] stride, " + "int[] padding, " + "Scalar zero_point, " + "Scalar multiplier, " + "Scalar shift" + ") -> Tensor" +) +lib.define( + "quantized_avg_pool2d.out(" + "Tensor input, " + "int[] kernel_size, " + "int[] stride, " + "int[] padding, " + "Scalar zero_point, " + "Scalar multiplier, " + "Scalar shift, " + "*, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_avg_pool2d") +def quantized_avg_pool2d_meta( + input: torch.Tensor, + kernel_size: Sequence[int], + stride: Sequence[int], + padding: Sequence[int], + zero_point: int, + multiplier: int, + shift: int, +) -> torch.Tensor: + # Compute output shape as in PyTorch avg_pool2d + + output = F.avg_pool2d(input, kernel_size, stride, padding) + return torch.empty_like(output, dtype=torch.int8) + + +@impl(lib, "quantized_avg_pool2d", "CompositeExplicitAutograd") +def quantized_avg_pool2d_impl( + input: torch.Tensor, + kernel_size: Sequence[int], + stride: Sequence[int], + padding: Sequence[int], + zero_point: int, + multiplier: int, + shift: int, +) -> torch.Tensor: + + dequant_input = dequantize_per_tensor_cmsis(input, zero_point, multiplier, shift) + + # TODO: implement count_include_pad=True, ceil_mode=True. + result = F.avg_pool2d( + dequant_input, + kernel_size, + stride=stride, + padding=padding, + count_include_pad=False, + ceil_mode=False, + ) + result = quantize_per_tensor_cmsis(result, zero_point, multiplier, shift) + output = torch.clamp(result, -128, 127) + return output.to(torch.int8) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/operators.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/operators.yaml similarity index 56% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/operators.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/operators.yaml index e0ebbfa..d1222c3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/operators.yaml +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/operators.yaml @@ -1,6 +1,6 @@ # Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. -# Copyright 2025-2026 Arm Limited and/or its affiliates. +# Copyright 2025 Arm Limited and/or its affiliates. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. @@ -17,13 +17,13 @@ - arg_meta: null kernel_name: cortex_m::dequantize_per_tensor_out -- func: cortex_m::quantized_add.out(Tensor self, int self_zero_point, int self_multiplier, int self_shift, Tensor other, int other_zero_point, int other_multiplier, int other_shift, int output_zero_point, int output_multiplier, int output_shift, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_add.out(Tensor self, Scalar self_zero_point, Scalar self_multiplier, Scalar self_shift, Tensor other, Scalar other_zero_point, Scalar other_multiplier, Scalar other_shift, Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null kernel_name: cortex_m::quantized_add_out -- func: cortex_m::quantized_mul.out(Tensor self, int self_zero_point, Tensor other, int other_zero_point, int output_zero_point, int output_multiplier, int output_shift, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_mul.out(Tensor self, Scalar self_zero_point, Tensor other, Scalar other_zero_point, Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null @@ -41,7 +41,7 @@ - arg_meta: null kernel_name: cortex_m::maximum_out -- func: cortex_m::quantized_linear.out(Tensor input, Tensor weights, Tensor? bias, Tensor? kernel_sum, int input_offset, int filter_offset, int output_offset, int[] requantize_multipliers, int[] requantize_shifts, int activation_max, int activation_min, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_linear.out(Tensor input, Tensor weights, Tensor? bias, Tensor? kernel_sum, Scalar input_offset, Scalar filter_offset, Scalar output_offset, int[] requantize_multipliers, int[] requantize_shifts, Scalar activation_max, Scalar activation_min, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null @@ -59,12 +59,6 @@ - arg_meta: null kernel_name: cortex_m::transpose_out -- func: cortex_m::pad.out(Tensor input, int[] pre_pad, int[] post_pad, int pad_value, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::pad_out - - func: cortex_m::quantized_conv2d.out(Tensor input, Tensor weight, Tensor? bias, int[] stride, int[] padding, int[] dilation, int input_offset, int output_offset, Tensor requantize_multipliers, Tensor requantize_shifts, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: @@ -77,25 +71,8 @@ - arg_meta: null kernel_name: cortex_m::quantized_depthwise_conv2d_out -- func: cortex_m::quantized_transpose_conv2d.out(Tensor input, Tensor weight, Tensor? bias, int[] stride, int[] padding, int[] output_padding, int[] dilation, int input_offset, int output_offset, Tensor requantize_multipliers, Tensor requantize_shifts, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::quantized_transpose_conv2d_out - -- func: cortex_m::quantized_avg_pool2d.out(Tensor input, int[] kernel_size, int[] stride, int[] padding, int zero_point, int multiplier, int shift, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_avg_pool2d.out(Tensor input, int[] kernel_size, int[] stride, int[] padding, Scalar zero_point, Scalar multiplier, Scalar shift, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null kernel_name: cortex_m::quantized_avg_pool2d_out -- func: cortex_m::quantized_max_pool2d.out(Tensor input, int[] kernel_size, int[] stride, int[] padding, int[] dilation, bool ceil_mode, int input_zero_point, int output_zero_point, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::quantized_max_pool2d_out - -- func: cortex_m::quantized_batch_matmul.out(Tensor lhs, int lhs_zero_point, Tensor rhs_transposed, int rhs_zero_point, int output_zero_point, int output_multiplier, int output_shift, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::quantized_batch_matmul_out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/targets.bzl new file mode 100644 index 0000000..250fcf9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/ops/targets.bzl @@ -0,0 +1,80 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//tools/build_defs:platform_defs.bzl", "CXX") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") +load("@fbcode_macros//build_defs:export_files.bzl", "export_file") + +def define_operator_target(name: str): + runtime.cxx_library( + name = "op_{}".format(name), + srcs = [ + "op_{}.cpp".format(name), + ], + platforms = CXX, + deps = [ + "//executorch/runtime/kernel:kernel_includes" + ], + link_whole = True, + ) + +OPERATORS = [ + "quantize_per_tensor", + "dequantize_per_tensor", +] + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + for op in OPERATORS: + define_operator_target(op) + + all_op_targets = [":op_{}".format(op) for op in OPERATORS] + + runtime.cxx_library( + name = "cortex_m_operators", + srcs = [], + visibility = ["PUBLIC"], + platforms = CXX, + exported_deps = all_op_targets, + ) + + export_file(name = "operators.yaml") + + et_operator_library( + name = "ops_lib", + _is_external_target = True, + ops_schema_yaml_target = ":operators.yaml", + ) + + executorch_generated_lib( + name = "cortex_m_generated_lib", + deps = [ + ":ops_lib", + ":cortex_m_operators", + ], + functions_yaml_target = ":operators.yaml", + platforms = CXX, + visibility = ["PUBLIC"], + define_static_targets = True, + ) + + executorch_generated_lib( + name = "cortex_m_no_except_generated_lib", + deps = [ + ":ops_lib", + ":cortex_m_operators", + ], + functions_yaml_target = ":operators.yaml", + platforms = CXX, + visibility = ["PUBLIC"], + define_static_targets = True, + support_exceptions = False, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/TARGETS new file mode 100644 index 0000000..687aafe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/TARGETS @@ -0,0 +1,35 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +oncall("executorch") + +runtime.python_library( + name="replace_quant_nodes_pass", + srcs=[ + "replace_quant_nodes_pass.py", + "quantized_op_fusion_pass.py", + ], + deps=[ + "//caffe2:torch", + "//executorch/exir:lib", + "//executorch/exir:pass_base", + "//executorch/exir/dialects:lib", + "//executorch/backends/cortex_m/ops:ops", + "//executorch/backends/cortex_m/passes:passes_utils", + ], +) + +runtime.python_library( + name="passes_utils", + srcs=[ + "passes_utils.py", + ], + deps=[ + "fbcode//caffe2:torch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/__init__.py new file mode 100644 index 0000000..c8bb743 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/__init__.py @@ -0,0 +1,12 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from .activation_fusion_pass import ActivationFusionPass # noqa +from .clamp_hardswish_pass import ClampHardswishPass # noqa +from .convert_to_cortex_m_pass import ConvertToCortexMPass # noqa +from .decompose_hardswish_pass import DecomposeHardswishPass # noqa +from .quantized_op_fusion_pass import QuantizedOpFusionPass # noqa +from .replace_quant_nodes_pass import ReplaceQuantNodesPass # noqa +from .cortex_m_pass_manager import CortexMPassManager # noqa # usort: skip diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/activation_fusion_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/activation_fusion_pass.py new file mode 100644 index 0000000..864f9e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/activation_fusion_pass.py @@ -0,0 +1,181 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import executorch.backends.cortex_m.ops.operators # noqa: F401 +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.cortex_m.passes.passes_utils import quantize_val + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +from torch.fx import GraphModule, Node +from torch.fx.passes.infra.pass_manager import PassResult + +logger = logging.getLogger(__name__) + + +class ActivationFusionPass(ExportPass): + """Fuse activations into preceding Cortex-M quantized operators. + + Supported activation patterns: + q-> [conv2d, linear] -> [relu, hardtanh, hardsigmoid] -> dq + + Fusing works by clamping the quantized output range (and zero-point when + required) of the preceding Cortex-M operator, then removing the activation + node from the graph. + """ + + TARGETS = { + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.hardsigmoid.default, + exir_ops.edge.aten.clamp.default, + } + + FUSE_OPS = { + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.convolution.default, + } + + def _get_validated_qparams(self, node, input_node): + + if "input_qparams" not in input_node.meta or "output_qparams" not in node.meta: + logger.warning( + f"Cannot fuse activation for {input_node.name}->{node.name} as the pattern wasn't quantized properly." + ) + return None + + qparams_dict = node.meta["output_qparams"][0]._asdict() + zp = qparams_dict["zp"] + scale = qparams_dict["scale"] + qmin = qparams_dict["qmin"] + qmax = qparams_dict["qmax"] + + if not isinstance(scale, float) or not isinstance(zp, int): + logger.warning( + f"Cannot fuse activation {node.name} as quantization parameters are not per tensor." + ) + return None + + match node.target: + case exir_ops.edge.aten.relu.default: + quantized_min_val = quantize_val(0, scale, zp, qmin, qmax) + quantized_max_val = qmax + case exir_ops.edge.aten.hardtanh.default: + quantized_min_val = quantize_val(node.args[1], scale, zp, qmin, qmax) + quantized_max_val = quantize_val(node.args[2], scale, zp, qmin, qmax) + case exir_ops.edge.aten.hardsigmoid.default: + quantized_min_val = quantize_val(0, scale, zp, qmin, qmax) + quantized_max_val = quantize_val(1, scale, zp, qmin, qmax) + case exir_ops.edge.aten.clamp.default: + quantized_min_val = ( + quantize_val(node.args[1], scale, zp, qmin, qmax) + if node.args[1] is not None + else qmin + ) + # Last arg is removed if none, so check length of args here + quantized_max_val = ( + quantize_val(node.args[2], scale, zp, qmin, qmax) + if len(node.args) == 3 + else qmax + ) + case _: + raise RuntimeError("Unexpected target {node.target}.") + + # If the minimal quantized value is larger than the qmin, it means that the quantized range contains + # invalid values [qmin, ..., quantized_min_val-1], indicating bad quantization parameters. + if qparams_dict["qmin"] != quantized_min_val: + logger.warning( + f"Cannot fuse activation {node.name} as qmin is out of range." + ) + return None + + # If the maximal quantized value is smaller than the qmax, it means that the quantized range contains + # invalid values [quantized_max_val + 1, ... , qmax], indicating bad quantization parameters. + if quantized_max_val != qparams_dict["qmax"]: + logger.warning( + f"Cannot fuse activation {node.name} as qmax is out of range." + ) + return None + + return qparams_dict + + def _update_qparams_hardsigmoid(self, quant_dict): + """ + Returns quant_dict with scale and zp updated to match hardsigmoid activation. + + The quantized output from the hard sigmoid is defined by + Q(y) = clamp(round(y/scale + zp), qmin, qmax) + y = clamp(x/6 + 1/2, 0, 1) + where x is the output of the fused activation op, conv or linear. + + Q(y) can be rewritten as a function of only x: + Q(y) = clamp(round(clamp(x/6 + 1/2, 0, 1)/scale + zp), qmin, qmax) + Q(y) = clamp(round(clamp((x/(6*scale) + 1/(2*scale) + zp, zp, 1/scale + zp)), qmin, qmax) + + From definition of the qparams mapping the output in the range [0,1] to quantized range + [qmin, qmax], we have: + zp = Q(0) <= qmin + 1/scale + zp = Q(1) >= qmax + which makes the inner clamp redundant. + + Therefore, hardsigmoid is equivalent to a quantization with modified parameters + new_scale := 6*scale + new_zp = zp + 1/(2*scale) ~= zp + round(1/(2*scale)) + """ + + new_scale = quant_dict["scale"] * 6 + + new_zp = quant_dict["zp"] + round(1 / (2 * quant_dict["scale"])) + clamped_new_zp = max(quant_dict["qmin"], min(quant_dict["qmax"], new_zp)) + + quant_dict["scale"] = new_scale + quant_dict["zp"] = clamped_new_zp + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + nodes_to_erase: list[Node] = [] + + for node in list(graph_module.graph.nodes): + if node.op != "call_function" or node.target not in self.TARGETS: + continue + + input_node = node.args[0] + if ( + input_node.op != "call_function" + or input_node.target not in self.FUSE_OPS + ): + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} is not a supported fused activation op." + ) + continue + if len(input_node.users.values()) > 1: + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} has multiple users." + ) + continue + + if (qparams_dict := self._get_validated_qparams(node, input_node)) is None: + continue + + if node.target == exir_ops.edge.aten.hardsigmoid.default: + self._update_qparams_hardsigmoid(qparams_dict) + + input_node.meta["output_qparams"][0] = QuantArgs(**qparams_dict) + + node.replace_all_uses_with(input_node) + nodes_to_erase.append(node) + modified = True + + for node in nodes_to_erase: + graph_module.graph.erase_node(node) + + if modified: + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/clamp_hardswish_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/clamp_hardswish_pass.py new file mode 100644 index 0000000..d257520 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/clamp_hardswish_pass.py @@ -0,0 +1,37 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict + +import torch + +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, NodeMetadata, ProxyValue +from torch.fx.node import Argument + + +class ClampHardswishPass(ExportPass): + """ + Adds a clamp operation before hardswish to ensure input is in the range [-3, inf). + + By doing this before quantization the output range of the preceeding op is minimized, + potentially improving accuracy. + """ + + def call_operator( + self, + op: EdgeOpOverload, + args: tuple[Argument, ...], + kwargs: Dict[str, Argument], + meta: NodeMetadata, + ) -> ProxyValue: + if op == torch.ops.aten.hardswish.default: + clamped_args = (args[0], -3) + clamped_input = super().call_operator( + torch.ops.aten.clamp.default, clamped_args, {}, meta + ) + args = (clamped_input,) + + return super().call_operator(op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/convert_to_cortex_m_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/convert_to_cortex_m_pass.py new file mode 100644 index 0000000..bed82c7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/convert_to_cortex_m_pass.py @@ -0,0 +1,318 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import executorch.backends.cortex_m.ops.operators # noqa + +import torch +import torch.fx +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.cortex_m.passes.passes_utils import quantize_multiplier_aot + +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + get_param_tensor, +) + +from executorch.backends.xnnpack._passes.xnnpack_pass import XNNPACKPass +from executorch.exir.dialects._ops import ops as exir_ops +from torch.export.graph_signature import InputKind +from torch.fx.passes.infra.pass_manager import PassResult + + +class ConvertToCortexMPass(XNNPACKPass): + """ + Cortex-M backend pass for replacing supported quantized kernels with Cortex-M + accelerated kernels. + + Used for ops which require changes to input tensors which is not supported + by call_operator. + """ + + def _compute_kernel_sum(self, weights, bias, input_offset, weight_offset): + """ + Computes the precomputed kernel sum term (bias optional) + a * sum_j(wij + b) + ci + + for i = (1, ..., n), where j indexes the input activations. + """ + weights_transposed = weights.T + weights_int32 = weights_transposed.to(torch.int32) + offset_weights = weights_int32 + weight_offset + kernel_sum = torch.sum(offset_weights, dim=0, keepdim=True, dtype=torch.int32) + kernel_sum_offset = kernel_sum * input_offset + + if bias is not None: + kernel_sum_offset += bias + + return kernel_sum_offset + + def _get_batch_size_from_conv(self, conv_node: torch.fx.Node): + """ + Extract batch size from convolution node's output shape. + + Returns None if shape metadata is unavailable, which can occur when + processing nodes created earlier in the same pass iteration. + + For Conv2d operations, output_batch_size always equals input_batch_size. + Conv2d outputs are always 4D (N, C, H, W) in the edge dialect. + """ + try: + if "val" in conv_node.meta: + output_shape = conv_node.meta["val"].shape + return output_shape[0] + except (AttributeError, TypeError): + pass + return None + + def _get_linear_replacement(self, node): + """ + Let + - yi be the output activations (y1, ... yn) + - xj be the input activations (x1, ... xm) + - wij be the weights (w11, ... wnm) + - a be the input offset + - b be the weight offset + - ci be the bias + + Then the linear operation can be written as: + yi = sum_j((xj + a) * (wij + b)) + ci + = sum_j(xj*wij + xj*b + a*wij + a*b) + ci + = sum_j(xj*wij) + sum_j(xj)*b + (a * sum_j(wij + b) + ci) + = sum_j(xj*wij) + sum_j(xj)*b + kernel_sum + + where kernel_sum is precomputed aot. + """ + input_scale = node.meta["input_qparams"][0].scale + input_zp = node.meta["input_qparams"][0].zp + weight_scale = node.meta["input_qparams"][1].scale + weight_zp = node.meta["input_qparams"][1].zp + output_scale = node.meta["output_qparams"][0].scale + output_zp = node.meta["output_qparams"][0].zp + output_min = node.meta["output_qparams"][0].qmin + output_max = node.meta["output_qparams"][0].qmax + + quantized_multiplier, quantized_shift = quantize_multiplier_aot( + (input_scale * weight_scale) / output_scale + ) + + # TODO: Add support for configuring the backend to support other extensions. + # Kernel sum is only used in the CMSIS-NN implementation for the MVE extension, + # so this should be optional. + weights = node.args[1] + weights_tensor = get_param_tensor(self.exported_program, weights) + bias_tensor = ( + get_param_tensor(self.exported_program, node.args[2]) + if len(node.args) > 2 + else None + ) + kernel_sum_tensor = self._compute_kernel_sum( + weights_tensor, bias_tensor, -input_zp, -weight_zp + ) + with node.graph.inserting_after(weights): + kernel_sum = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_kernel_sum", + InputKind.PARAMETER, + kernel_sum_tensor, + ) + + args = ( + node.args[0], + weights, + None, + kernel_sum, + -input_zp, + -weight_zp, + output_zp, + [quantized_multiplier], + [quantized_shift], + output_max, + output_min, + ) + + return exir_ops.edge.cortex_m.quantized_linear.default, args + + def _get_convolution_replacement(self, node) -> int: + ( + x, + weight, + bias, + stride, + padding, + dilation, + transposed, + output_padding, + groups, + ) = node.args + + # Extract values + input_scale = node.meta["input_qparams"][0].scale + input_zero_point = node.meta["input_qparams"][0].zp + weight_scales = node.meta["input_qparams"][1].scale + if not isinstance(weight_scales, list): + weight_tensor = get_first_fake_tensor(weight) + weight_scales = [weight_scales] * weight_tensor.shape[0] + + output_qparams = node.meta["output_qparams"][0] + output_scale = output_qparams.scale + output_zero_point = output_qparams.zp + output_qmin = output_qparams.qmin + output_qmax = output_qparams.qmax + + quantized_multipliers = [] + quantized_shifts = [] + for weight_scale in weight_scales: + quantized_multiplier, quantized_shift = quantize_multiplier_aot( + input_scale * weight_scale / output_scale + ) + quantized_multipliers.append(quantized_multiplier) + quantized_shifts.append(quantized_shift) + + weight_tensor = get_param_tensor(self.exported_program, weight) + + # Detect depthwise convolution: + # Depthwise means groups == in_channels, out_channels == K * in_channels + # Weight shape is [out_ch, in_ch_per_group, H, W] + in_channels = weight_tensor.shape[1] * groups + out_channels = weight_tensor.shape[0] + is_depthwise = (in_channels == groups) and (out_channels % in_channels == 0) + + # Only use DW path if batch_size==1, as CMSIS-NN DW falls back to + # unoptimized implementation otherwise. + batch_size = self._get_batch_size_from_conv(node) + + # TODO(#16347): It is likely but not certain that the un-optimized + # CMSIS-NN DW conv or the one without any SIMD is less efficient that + # the corresponding CMSIS-NN conv. We should benchmark and update the + # constraints. + # optimal_dw_conv_constraints = (batch_size == 1) and ( + # (in_channels == out_channels and dilation == [1, 1]) or (in_channels == 1) + # ) + use_depthwise_conv = is_depthwise and (batch_size == 1) + + if use_depthwise_conv: + # For depthwise: OIHW -> IHWO which gives [1, H, W, C_OUT] for CMSIS-NN + # PyTorch depthwise weight is [out_ch, 1, H, W], permute to [1, H, W, out_ch] + weight_permuted = weight_tensor.permute(1, 2, 3, 0).contiguous( + memory_format=torch.channels_last + ) + else: + # For regular conv: OIHW -> OHWI + weight_permuted = weight_tensor.permute(0, 2, 3, 1).contiguous( + memory_format=torch.channels_last + ) + + with node.graph.inserting_after(weight): + weight_nhwc = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_weight_nhwc", + InputKind.PARAMETER, + weight_permuted, + ) + + quantized_multiplier_tensor = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_quantized_multiplier", + InputKind.PARAMETER, + torch.tensor(quantized_multipliers, dtype=torch.int32), + ) + + quantized_shift_tensor = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_quantized_shift", + InputKind.PARAMETER, + torch.tensor(quantized_shifts, dtype=torch.int32), + ) + + if use_depthwise_conv: + # Compute depth_multiplier for depthwise convolution + # For depthwise: output_channels = input_channels * depth_multiplier + + if out_channels % in_channels != 0: + raise ValueError( + f"Depthwise conv: output_channels ({out_channels}) must be " + f"divisible by input_channels ({in_channels})" + ) + depth_multiplier = out_channels // in_channels + + new_args = ( + x, + weight_nhwc, + bias, + stride, + padding, + dilation, + depth_multiplier, + -input_zero_point, + output_zero_point, + quantized_multiplier_tensor, + quantized_shift_tensor, + output_qmin, + output_qmax, + ) + return exir_ops.edge.cortex_m.quantized_depthwise_conv2d.default, new_args + else: + # Use regular convolution operator + new_args = ( + x, + weight_nhwc, + bias, + stride, + padding, + dilation, + -input_zero_point, + output_zero_point, + quantized_multiplier_tensor, + quantized_shift_tensor, + output_qmin, + output_qmax, + ) + return exir_ops.edge.cortex_m.quantized_conv2d.default, new_args + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if ( + node.meta.get("input_qparams", {}) == {} + or node.meta.get("output_qparams", {}) == {} + ): + continue + + match node.target: + case exir_ops.edge.aten.linear.default: + op, args = self._get_linear_replacement(node) + case exir_ops.edge.aten.convolution.default: + op, args = self._get_convolution_replacement(node) + case _: + continue + + with graph_module.graph.inserting_before(node): + cortex_m_op = graph_module.graph.create_node( + "call_function", + target=op, + args=args, + kwargs={}, + ) + + node.replace_all_uses_with(cortex_m_op) + graph_module.graph.erase_node(node) + + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/cortex_m_pass_manager.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/cortex_m_pass_manager.py new file mode 100644 index 0000000..c47bcc3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/cortex_m_pass_manager.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import inspect + +from executorch.backends.arm._passes import ( + FoldAndAnnotateQParamsPass, + ScalarsToAttributePass, +) +from executorch.backends.transforms.replace_scalar_with_tensor import ( + ReplaceScalarWithTensorArgPass, +) +from executorch.exir.pass_base import ExportPass +from executorch.exir.pass_manager import PassManager +from executorch.exir.program._program import _transform +from torch.export import ExportedProgram + +from .activation_fusion_pass import ActivationFusionPass +from .clamp_hardswish_pass import ClampHardswishPass +from .convert_to_cortex_m_pass import ConvertToCortexMPass +from .decompose_hardswish_pass import DecomposeHardswishPass +from .quantized_op_fusion_pass import QuantizedOpFusionPass +from .replace_quant_nodes_pass import ReplaceQuantNodesPass + + +class CortexMPassManager(PassManager): + + pass_list: list[ExportPass] = [ + FoldAndAnnotateQParamsPass, + ReplaceScalarWithTensorArgPass, + ReplaceQuantNodesPass, + ActivationFusionPass, + DecomposeHardswishPass, + QuantizedOpFusionPass, + ConvertToCortexMPass, + ] + + pass_list_transform_for_annotation: list[ExportPass] = [ + ScalarsToAttributePass, + ReplaceScalarWithTensorArgPass, + ClampHardswishPass, + ] + + def __init__(self, exported_program, passes=None): + self.exported_program = exported_program + if passes is not None: + self.passes = passes + else: + self.passes = self.pass_list + + def transform_for_annotation(self, model): + passes = self.pass_list_transform_for_annotation + for p in passes: + model = p().call(model).graph_module + return model + + def transform(self) -> ExportedProgram: + ep = self.exported_program + for pass_ in self.passes: + signature = inspect.signature(pass_.__init__) + if "exported_program" in signature.parameters: + transform_pass = pass_(ep) + elif issubclass(pass_, ExportPass): + transform_pass = pass_() + else: + raise RuntimeError( + f"Expecting ExportPass or ExportPass(), but got pass: {pass_} with type: {type(pass_)}" + ) + ep = _transform(ep, transform_pass) + return ep diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/decompose_hardswish_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/decompose_hardswish_pass.py new file mode 100644 index 0000000..36ca6bd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/decompose_hardswish_pass.py @@ -0,0 +1,127 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import executorch.backends.cortex_m.ops.operators # noqa: F401 + +import torch +from executorch.backends.arm._passes.quant_args import QuantArgs + +from executorch.backends.cortex_m.passes.passes_utils import quantize_val + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass +from torch.fx import GraphModule, Node +from torch.fx.passes.infra.pass_manager import PassResult + +logger = logging.getLogger(__name__) + + +class DecomposeHardswishPass(ExportPass): + """ + Decomposes hardswish like + + hardswish(x) = x * (clamp(x, -3, 3) + 3)/6 + + where the add and division is implemented by modifying the quantization parameters similar + to hardsigmoid in the activation_fusion_pass. Note that this pass assumes + that the output range of the preceding op is already clamped to [-3, inf] during + quantization by the clamp_hardswish_pass, removing the need for the negative clamp. + """ + + TARGETS = { + exir_ops.edge.aten.hardswish.default, + } + + FUSE_OPS = { + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.convolution.default, + } + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + nodes_to_erase: list[Node] = [] + + for node in list(graph_module.graph.nodes): + if node.op != "call_function" or node.target not in self.TARGETS: + continue + + input_node = node.args[0] + if ( + input_node.op != "call_function" + or input_node.target not in self.FUSE_OPS + ): + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} is not a supported fused activation op." + ) + continue + if len(input_node.users.values()) > 1: + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} has multiple users." + ) + continue + + input_quant_dict = input_node.meta.get("output_qparams", [None])[ + 0 + ]._asdict() + scale = input_quant_dict["scale"] + zero_point = input_quant_dict["zp"] + qmin = input_quant_dict["qmin"] + qmax = input_quant_dict["qmax"] + + # Create min node + with graph_module.graph.inserting_after(input_node): + clamp_node = graph_module.graph.create_node( + "call_function", + target=exir_ops.edge.aten.minimum.default, + args=( + input_node, + torch.tensor( + quantize_val(3, scale, zero_point, qmin, qmax), + dtype=torch.int8, + ), + ), + kwargs={}, + ) + clamp_node.meta = input_node.meta.copy() + + # Create mul node + with graph_module.graph.inserting_after(clamp_node): + mul_node = graph_module.graph.create_node( + "call_function", + target=exir_ops.edge.aten.mul.Tensor, + args=(input_node, clamp_node), + kwargs={}, + ) + mul_node.meta = node.meta.copy() + + mul_quant_dict = node.meta["input_qparams"][0]._asdict() + + mul_quant_dict_shifted = mul_quant_dict.copy() + mul_quant_dict_shifted["zp"] = mul_quant_dict_shifted["zp"] - round( + 3 / (mul_quant_dict_shifted["scale"]) + ) + + output_quant_dict = node.meta["output_qparams"][0]._asdict() + output_quant_dict["scale"] = output_quant_dict["scale"] * 6 + + node.meta["input_qparams"][0] = QuantArgs(**mul_quant_dict) + mul_node.meta["input_qparams"][1] = QuantArgs(**mul_quant_dict_shifted) + mul_node.meta["output_qparams"][0] = QuantArgs(**output_quant_dict) + + node.replace_all_uses_with(mul_node) + nodes_to_erase.append(node) + modified = True + + for node in nodes_to_erase: + graph_module.graph.erase_node(node) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/passes_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/passes_utils.py new file mode 100644 index 0000000..131541f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/passes_utils.py @@ -0,0 +1,226 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math + +import torch + +from executorch.exir.dialects._ops import ops as exir_ops + +from torch.fx import Node + +# L-shift value used in CMSIS-NN for int8 operations +SHIFT_INT8 = 20 + + +def quantize_val(val, scale, zp, qmin, qmax): + return min(max(round(val / scale + zp), qmin), qmax) + + +def dequantize_per_tensor_cmsis( + qtensor: torch.Tensor, zero_point: int, multiplier: int, shift: int +) -> torch.Tensor: + """ + Simulate CMSIS-NN fixed-point dequantization: + result = (qtensor - zero_point) * multiplier * 2^shift / 2^31 + """ + scale = multiplier * (2**shift) / (1 << 31) + return (qtensor.float() - zero_point) * scale + + +def quantize_per_tensor_cmsis( + tensor: torch.Tensor, + zero_point: int, + multiplier: int, + shift: int, + qmin=-128, + qmax=127, +) -> torch.Tensor: + """ + Simulate CMSIS-NN fixed-point quantization: + result = round(tensor / scale) + zero_point, clamped to [qmin, qmax] + """ + scale = multiplier * (2**shift) / (1 << 31) + quantized = torch.round(tensor / scale) + zero_point + return quantized.clamp(qmin, qmax).to(torch.int8) + + +def requantize_cmsis( + tensor: torch.Tensor, + multiplier: int, + shift: int, +) -> torch.Tensor: + """Simulate CMSIS-NN's arm_nn_requantize helper.""" + + tensor_64 = tensor.to(torch.int64) + left_shift = max(shift, 0) + right_shift = max(-shift, 0) + + # Equivalent to val * (1 << LEFT_SHIFT(shift)) + value = tensor_64 << left_shift + + # arm_nn_doubling_high_mult_no_sat(value, multiplier) + product = value * int(multiplier) + product = product + (1 << 30) + result = product >> 31 + + if right_shift: + remainder_mask = (1 << right_shift) - 1 + remainder = torch.bitwise_and(result, remainder_mask) + result = result >> right_shift + threshold = remainder_mask >> 1 + threshold_tensor = torch.full_like(result, threshold, dtype=torch.int64) + threshold_tensor = torch.where( + result < 0, threshold_tensor + 1, threshold_tensor + ) + result = result + torch.where(remainder > threshold_tensor, 1, 0) + + return result.to(torch.int32) + + +def extract_scalar_value(node_arg) -> float: + """ + Extract scalar value from various PyTorch scalar representations. + """ + if hasattr(node_arg, "op") and node_arg.op == "get_attr": + # Handle case where scalar is a graph attribute + return float(node_arg.target) + elif isinstance(node_arg, (int, float)): + return float(node_arg) + elif hasattr(node_arg, "item"): + return float(node_arg.item()) + else: + # Try to extract from meta if available + if hasattr(node_arg, "meta") and "val" in node_arg.meta: + val = node_arg.meta["val"] + if hasattr(val, "item"): + return float(val.item()) + return float(val) + raise ValueError( + f"Cannot extract scalar value from {type(node_arg)}: {node_arg}" + ) + + +def is_qualified_int8_node(args) -> bool: + try: + if len(args) < 6: + return False + qmin = int(args[3]) + qmax = int(args[4]) + dtype_str = str(args[5]) + is_int8_range = ( + qmin >= torch.iinfo(torch.int8).min and qmax <= torch.iinfo(torch.int8).max + ) + is_int8_dtype = "int8" in dtype_str.lower() + return is_int8_range and is_int8_dtype + except (IndexError, ValueError, TypeError): + return False + + +def quantize_multiplier_aot(scale: float) -> tuple[int, int]: + if scale == 0.0: + return 0, 0 + mantissa, shift = math.frexp(scale) + q_fixed = int(round(mantissa * (1 << 31))) + if q_fixed == (1 << 31): + q_fixed //= 2 + shift += 1 + multiplier = max( + torch.iinfo(torch.int32).min, min(torch.iinfo(torch.int32).max, q_fixed) + ) + return multiplier, shift + + +def cleanup_erased_nodes(graph_module: torch.fx.GraphModule): + # Placeholder for any additional cleanup if needed + pass + + +def transfer_metadata( + new_node: Node, source_node: Node, pass_name: str = "QuantizedPass" +) -> None: + """Transfer metadata with proper provenance tracking.""" + if hasattr(source_node, "meta") and source_node.meta: + new_node.meta = source_node.meta.copy() + if "from_node" in new_node.meta: + from_node_list = new_node.meta.get("from_node", []).copy() + from_node_list.append( + {"source": source_node.name, "pass": pass_name, "op": "fuse"} + ) + new_node.meta["from_node"] = from_node_list + for field in ["tensor_meta", "stack_trace"]: + if field in source_node.meta: + new_node.meta[field] = source_node.meta[field] + + +def is_dequant_node(node: Node) -> bool: + """Check if node is a dequantize operation.""" + dequant_targets = { + exir_ops.edge.cortex_m.dequantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.dequantize_per_channel.default, + } + return node.op == "call_function" and node.target in dequant_targets + + +def is_quant_node(node: Node) -> bool: + """Check if node is a quantize operation.""" + quant_targets = { + exir_ops.edge.cortex_m.quantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + } + return node.op == "call_function" and node.target in quant_targets + + +def cleanup_nodes(nodes_to_erase, graph): + """Clean up marked nodes from graph.""" + failed_nodes = [] + + for node in reversed(nodes_to_erase): + if node in graph.nodes and len(node.users) == 0: + try: + graph.erase_node(node) + except Exception as e: + print(f"Warning: Failed to erase node {node}: {e}") + failed_nodes.append(node) + continue + + if failed_nodes: + print(f"Warning: {len(failed_nodes)} nodes could not be erased") + + return failed_nodes + + +def is_channels_last(tensor: torch.Tensor) -> bool: + """Check if a 4D tensor is in channels last format.""" + if tensor.ndim != 4: + return False + + if tensor.shape[1] == 1 or tensor.shape[2] == tensor.shape[3] == 1: + return True + + dim_order = list(tensor.dim_order()) + return dim_order[0:2] == [0, 2] + + +def is_channel_broadcast(tensor1: torch.Tensor, tensor2: torch.Tensor) -> bool: + """ + Check if tensor1 is broadcasted to tensor2 along channel dimension. + Assumes tensor2 has shape [N, C, ...] and tensor1 has shape [N, 1, ...] or [1, C, ...]. + """ + if tensor1.dim() != tensor2.dim(): + return False + if not is_channels_last(tensor1): + return False + if not is_channels_last(tensor2): + return False + + channel_match = tensor1.size(1) == tensor2.size(1) + tensor1_channels_only = tensor1.numel() == tensor1.size(1) + tensor2_channels_only = tensor2.numel() == tensor2.size(1) + + return channel_match and (tensor1_channels_only or tensor2_channels_only) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/quantized_op_fusion_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/quantized_op_fusion_pass.py new file mode 100644 index 0000000..b21cd50 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/quantized_op_fusion_pass.py @@ -0,0 +1,255 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Dict + +import torch + +from executorch.backends.cortex_m.passes.passes_utils import ( + quantize_multiplier_aot, + SHIFT_INT8, +) +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + CMSIS_SOFTMAX_SCALE, + CMSIS_SOFTMAX_ZERO_POINT, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, NodeMetadata, ProxyValue +from torch.fx.node import Argument + + +class QuantizedOpFusionPass(ExportPass): + """ + Generic ExportPass that: + 1. Replaces certain ops with cortex_m variants based on qualifiers. + 2. Fuses patterns: dequantize_per_tensor -> [binary_op] -> quantize_per_tensor + into cortex_m.quantized_[op].default with AoT computed multipliers/shifts. + + + Supports multiple binary operations with backward compatibility for add. + """ + + _SOFTMAX_INPUT_INTEGER_BITS = 5 + + def _get_add_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten.add.Tensor, args + + # Extract values + scale1 = meta["input_qparams"][0].scale + zero_point1 = meta["input_qparams"][0].zp + scale2 = meta["input_qparams"][1].scale + zero_point2 = meta["input_qparams"][1].zp + output_scale = meta["output_qparams"][0].scale + output_zero_point = meta["output_qparams"][0].zp + + # AoT COMPUTATION: Calculate multipliers and shifts + max_scale_2x = 2 * max(scale1, scale2) + + input1_mult, input1_shift = quantize_multiplier_aot(scale1 / max_scale_2x) + input2_mult, input2_shift = quantize_multiplier_aot(scale2 / max_scale_2x) + output_mult, output_shift = quantize_multiplier_aot( + max_scale_2x / (output_scale * (1 << SHIFT_INT8)) + ) + + args = ( + args[0], + zero_point1, + input1_mult, + input1_shift, + args[1], + zero_point2, + input2_mult, + input2_shift, + output_zero_point, + output_mult, + output_shift, + ) + + return exir_ops.edge.cortex_m.quantized_add.default, args + + def _get_mul_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten.mul.Tensor, args + + # Extract values + scale1 = meta["input_qparams"][0].scale + zero_point1 = meta["input_qparams"][0].zp + scale2 = meta["input_qparams"][1].scale + zero_point2 = meta["input_qparams"][1].zp + output_scale = meta["output_qparams"][0].scale + output_zero_point = meta["output_qparams"][0].zp + + scale_factor = (scale1 * scale2) / output_scale + output_mult, output_shift = quantize_multiplier_aot(scale_factor) + + args = ( + args[0], + zero_point1, + args[1], + zero_point2, + output_zero_point, + output_mult, + output_shift, + ) + + return exir_ops.edge.cortex_m.quantized_mul.default, args + + def _compute_softmax_params(self, input_scale: float) -> tuple[int, int, int]: + """ + Convert the incoming per-tensor input scale into the CMSIS fixed-point + parameters expected by `arm_softmax_s8`. + + 1. Clamp the real multiplier to the Q31 range using the fixed number of + input integer bits mandated by CMSIS. + 2. Feed that multiplier through `quantize_multiplier_aot` to get the + (multiplier, shift) pair arm_softmax_s8 expects. + 3. Derive `diff_min`, the CMSIS threshold for early bailout when + differences saturate, using the same multiplier/shift values. + """ + real_multiplier = min( + input_scale * (1 << (31 - self._SOFTMAX_INPUT_INTEGER_BITS)), + float((1 << 31) - 1), + ) + input_multiplier, input_shift = quantize_multiplier_aot(real_multiplier) + diff_min_term = ( + ((1 << self._SOFTMAX_INPUT_INTEGER_BITS) - 1) + * math.ldexp(1.0, 31 - self._SOFTMAX_INPUT_INTEGER_BITS) + / math.ldexp(1.0, input_shift) + ) + diff_min = -int(math.floor(diff_min_term)) + return int(input_multiplier), int(input_shift), diff_min + + def _get_softmax_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten._softmax.default, args + + input_qparams = meta["input_qparams"][0] + output_qparams = meta["output_qparams"][0] + + half_to_float = args[2] if len(args) > 2 else False + if half_to_float: + return exir_ops.edge.aten._softmax.default, args + + input_multiplier, input_shift, diff_min = self._compute_softmax_params( + float(input_qparams.scale) + ) + + output_scale_attr = getattr(output_qparams, "scale", None) + output_zp_attr = getattr(output_qparams, "zp", None) + if output_scale_attr is None or output_zp_attr is None: + raise AssertionError("Softmax requires output quantization parameters.") + + output_scale_val = float(output_scale_attr) + output_zp_val = int(output_zp_attr) + if not math.isclose( + output_scale_val, CMSIS_SOFTMAX_SCALE, rel_tol=0.0, abs_tol=1e-12 + ): + raise AssertionError( + "Softmax output scale must match CMSIS (1/256). " + f"Got {output_scale_val}." + ) + if output_zp_val != CMSIS_SOFTMAX_ZERO_POINT: + raise AssertionError( + "Softmax output zero-point must match CMSIS (-128). " + f"Got {output_zp_val}." + ) + + new_args = ( + args[0], + args[1], + int(input_qparams.zp), + output_zp_val, + input_multiplier, + input_shift, + diff_min, + ) + + return exir_ops.edge.cortex_m.softmax.default, new_args + + def _get_minimum_replacement(self, args, meta): + if args[0].data.dtype != torch.int8: + return exir_ops.edge.aten.minimum.default, args + + return exir_ops.edge.cortex_m.minimum.default, args + + def _get_maximum_replacement(self, args, meta): + if args[0].data.dtype != torch.int8: + return exir_ops.edge.aten.maximum.default, args + + return exir_ops.edge.cortex_m.maximum.default, args + + def _get_permute_replacement(self, args, meta): + if args[0].data.dtype != torch.int8: + return exir_ops.edge.aten.permute_copy.default, args + + rank = len(args[0].data.shape) + perms = [p % rank for p in args[1]] + args = (args[0], perms) + return exir_ops.edge.cortex_m.transpose.default, args + + def _get_avg_pool2d_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten.avg_pool2d.default, args + + # Extract values + scale = meta["input_qparams"][0].scale + zero_point = meta["input_qparams"][0].zp + + output_mult, output_shift = quantize_multiplier_aot(scale) + args = ( + *args[0:-2], + zero_point, + output_mult, + output_shift, + ) + + return exir_ops.edge.cortex_m.quantized_avg_pool2d.default, args + + def call_operator( + self, + op: EdgeOpOverload, + args: tuple[Argument, ...], + kwargs: Dict[str, Argument], + meta: NodeMetadata, + ) -> ProxyValue: + + match op: + case exir_ops.edge.aten.add.Tensor: + op, args = self._get_add_replacement(args, meta) + case exir_ops.edge.aten.mul.Tensor: + op, args = self._get_mul_replacement(args, meta) + case exir_ops.edge.aten._softmax.default: + op, args = self._get_softmax_replacement(args, meta) + case exir_ops.edge.aten.minimum.default: + op, args = self._get_minimum_replacement(args, meta) + case exir_ops.edge.aten.maximum.default: + op, args = self._get_maximum_replacement(args, meta) + case exir_ops.edge.aten.permute_copy.default: + op, args = self._get_permute_replacement(args, meta) + case exir_ops.edge.aten.avg_pool2d.default: + op, args = self._get_avg_pool2d_replacement(args, meta) + case _: + pass + + result = super().call_operator(op, args, {}, meta) + return result diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/replace_quant_nodes_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/replace_quant_nodes_pass.py new file mode 100644 index 0000000..a815313 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/passes/replace_quant_nodes_pass.py @@ -0,0 +1,67 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Dict, Tuple + +import executorch.backends.cortex_m.ops.operators # noqa +import torch + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, NodeMetadata, ProxyValue + + +class ReplaceQuantNodesPass(ExportPass): + """ + Replace quantize and dequantize nodes with the corresponding + cortex_m.quantize_per_tensor and cortex_m.dequantize_per_tensor nodes. + """ + + @staticmethod + def _is_qualified_int8_node(args) -> bool: + return ( + args[3] >= torch.iinfo(torch.int8).min # qmin + and args[4] <= torch.iinfo(torch.int8).max # qmax + and args[5] == torch.int8 # dtype + ) + + def __init__(self): + super().__init__() + self.op_replacements = { + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default: { + "new_target": exir_ops.edge.cortex_m.quantize_per_tensor.default, + "qualifier": self._is_qualified_int8_node, + }, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default: { + "new_target": exir_ops.edge.cortex_m.dequantize_per_tensor.default, + "qualifier": self._is_qualified_int8_node, + }, + } + self.disallowed_targets = { + torch.ops.quantized_decomposed.dequantize_per_tensor.default, + torch.ops.quantized_decomposed.quantize_per_tensor.default, + } + + def call_operator( + self, + op: Callable[..., object], + args: Tuple[object, ...], + kwargs: Dict[str, object], + meta: NodeMetadata, + ) -> ProxyValue: + if op in self.disallowed_targets: + raise RuntimeError( + f"Found unexpected aten op '{op}'. Make sure you run this pass after lowering to edge." + ) + + if op in self.op_replacements and self.op_replacements[op]["qualifier"](args): + return super().call_operator( + self.op_replacements[op]["new_target"], + args, + kwargs, + meta, + ) + return super().call_operator(op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/TARGETS new file mode 100644 index 0000000..0af105e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/TARGETS @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbcode_macros//build_defs:python_library.bzl", "python_library") + +oncall("executorch") + +python_library( + name = "quantizer", + srcs = [ + "__init__.py", + "operator_configs.py", + "quantization_configs.py", + "quantizer.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/backends/arm/quantizer:quantization_config", + "//pytorch/ao:torchao", + ], +) + +python_library( + name = "quantization_configs", + srcs = [ + "quantization_configs.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/backends/arm/quantizer:quantization_config", + "//pytorch/ao:torchao", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/__init__.py new file mode 100644 index 0000000..c55f200 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/__init__.py @@ -0,0 +1,18 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from .quantization_configs import ( # noqa + CMSIS_SOFTMAX_SCALE, + CMSIS_SOFTMAX_ZERO_POINT, + INT8_ACTIVATION_PER_CHANNEL_QSPEC, + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_PER_CHANNEL_CONFIG, + INT8_PER_TENSOR_CONFIG, + INT8_WEIGHT_PER_CHANNEL_QSPEC, + INT8_WEIGHT_PER_TENSOR_QSPEC, + SOFTMAX_OUTPUT_FIXED_QSPEC, + SOFTMAX_PER_TENSOR_CONFIG, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/operator_configs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/operator_configs.py new file mode 100644 index 0000000..5458eef --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/operator_configs.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +""" +Operator configs maps a list of operators/operator patterns to a quantization configuration. +These can be used with the OperatorConfigQuantizer to quantize models based on operator patterns. +""" + +import torch + +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + INT8_PER_CHANNEL_CONFIG, + INT8_PER_TENSOR_CONFIG, + SOFTMAX_PER_TENSOR_CONFIG, +) +from torchao.quantization.pt2e.quantizer import OperatorConfig + +# ----------------- OPERATOR PATTERN PRESETS ----------------- +BINARY_OP_PATTERNS = [ + [torch.ops.aten.add.Tensor], + [torch.ops.aten.mul.Tensor], + [torch.ops.aten.hardswish.default], + [torch.ops.aten.hardswish_.default], +] + +LINEAR_OP_PATTERNS = [ + [torch.ops.aten.linear.default], + [torch.ops.aten.linear.default, torch.ops.aten.relu.default], + [torch.ops.aten.linear.default, torch.ops.aten.relu_.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardtanh.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardtanh_.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardsigmoid.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardsigmoid_.default], + [torch.ops.aten.linear.default, torch.ops.aten.clamp.default], + [torch.ops.aten.linear.default, torch.ops.aten.clamp_.default], +] + +CONV_OP_PATTERNS = [ + [torch.ops.aten.conv2d.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.relu.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.relu_.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardtanh.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardtanh_.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardsigmoid.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardsigmoid_.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.clamp.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.clamp_.default], +] + +SOFTMAX_OP_PATTERNS = [ + [torch.ops.aten._softmax.default], + [torch.ops.aten.softmax.int], +] + +# ----------------- OPERATOR CONFIG PRESETS ----------------- +INT8_BINARY_OPS_OPERATOR_CONFIG = OperatorConfig( + INT8_PER_TENSOR_CONFIG, BINARY_OP_PATTERNS +) + +INT8_LINEAR_OPERATOR_CONFIG = OperatorConfig( + INT8_PER_TENSOR_CONFIG, + LINEAR_OP_PATTERNS, +) + +INT8_CONV_OPERATOR_CONFIG = OperatorConfig( + INT8_PER_CHANNEL_CONFIG, + CONV_OP_PATTERNS, +) + +INT8_SOFTMAX_OPERATOR_CONFIG = OperatorConfig( + SOFTMAX_PER_TENSOR_CONFIG, + SOFTMAX_OP_PATTERNS, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantization_configs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantization_configs.py new file mode 100644 index 0000000..7ec84c6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantization_configs.py @@ -0,0 +1,121 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from torchao.quantization.pt2e import ( + HistogramObserver, + MinMaxObserver, + PerChannelMinMaxObserver, +) +from torchao.quantization.pt2e.quantizer import ( + DerivedQuantizationSpec, + FixedQParamsQuantizationSpec, + QuantizationSpec, +) + +# ----------------- QUANTIZATION SPEC PRESETS ----------------- +INT8_WEIGHT_PER_TENSOR_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=MinMaxObserver, + qscheme=torch.per_tensor_symmetric, +) + +INT8_WEIGHT_PER_CHANNEL_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=PerChannelMinMaxObserver, + qscheme=torch.per_channel_symmetric, + ch_axis=0, +) + +INT8_ACTIVATION_PER_TENSOR_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_affine, +) + +INT8_ACTIVATION_PER_CHANNEL_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=PerChannelMinMaxObserver, + qscheme=torch.per_channel_affine, + ch_axis=0, +) + +# Constants shared by Cortex-M quantized operators. +CMSIS_SOFTMAX_SCALE: float = 1.0 / 256.0 +CMSIS_SOFTMAX_ZERO_POINT: int = -128 + +SOFTMAX_OUTPUT_FIXED_QSPEC = FixedQParamsQuantizationSpec( + dtype=torch.int8, + scale=CMSIS_SOFTMAX_SCALE, + zero_point=CMSIS_SOFTMAX_ZERO_POINT, + quant_min=-128, + quant_max=127, + qscheme=torch.per_tensor_affine, +) + + +def _derive_bias_qparams_fn( + obs_or_fqs, +) -> tuple[torch.Tensor, torch.Tensor]: + if len(obs_or_fqs) != 2: + raise ValueError( + f"Expecting two obs/fqs, one for activation and one for weight, got: {len(obs_or_fqs)}" + ) + act_obs_or_fq = obs_or_fqs[0] + weight_obs_or_fq = obs_or_fqs[1] + act_scale, _ = act_obs_or_fq.calculate_qparams() + weight_scale, _ = weight_obs_or_fq.calculate_qparams() + return act_scale * weight_scale, torch.full_like( + weight_scale, fill_value=0, dtype=torch.int32 + ) + + +def _get_int32_bias_qspec(node): + return DerivedQuantizationSpec( + derived_from=[(node.args[0], node), (node.args[1], node)], # type: ignore[list-item] + derive_qparams_fn=_derive_bias_qparams_fn, + dtype=torch.int32, + quant_min=torch.iinfo(torch.int32).min, + quant_max=torch.iinfo(torch.int32).max - 1, + ) + + +def _get_int32_per_channel_bias_qspec(node): + return DerivedQuantizationSpec( + derived_from=[(node.args[0], node), (node.args[1], node)], # type: ignore[list-item] + derive_qparams_fn=_derive_bias_qparams_fn, + dtype=torch.int32, + quant_min=torch.iinfo(torch.int32).min, + quant_max=torch.iinfo(torch.int32).max - 1, + qscheme=torch.per_channel_symmetric, + ch_axis=0, + ) + + +# ----------------- QUANTIZATION CONFIG PRESETS ----------------- +INT8_PER_TENSOR_CONFIG = QuantizationConfig( + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_WEIGHT_PER_TENSOR_QSPEC, + _get_int32_bias_qspec, +) + + +INT8_PER_CHANNEL_CONFIG = QuantizationConfig( + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_WEIGHT_PER_CHANNEL_QSPEC, + _get_int32_per_channel_bias_qspec, +) + + +SOFTMAX_PER_TENSOR_CONFIG = QuantizationConfig( + INT8_ACTIVATION_PER_TENSOR_QSPEC, + SOFTMAX_OUTPUT_FIXED_QSPEC, + None, + None, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantizer.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantizer.py new file mode 100644 index 0000000..aceced0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/quantizer/quantizer.py @@ -0,0 +1,500 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, Callable, cast, List, Optional + +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from executorch.backends.cortex_m.passes.cortex_m_pass_manager import CortexMPassManager +from executorch.backends.cortex_m.passes.passes_utils import ( + is_channel_broadcast, + is_channels_last, +) +from executorch.backends.cortex_m.quantizer.operator_configs import ( + BINARY_OP_PATTERNS, + CONV_OP_PATTERNS, + INT8_BINARY_OPS_OPERATOR_CONFIG, + INT8_CONV_OPERATOR_CONFIG, + INT8_LINEAR_OPERATOR_CONFIG, + INT8_SOFTMAX_OPERATOR_CONFIG, + SOFTMAX_OP_PATTERNS, +) +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + INT8_PER_TENSOR_CONFIG, + QuantizationSpec, +) +from torch._ops import OpOverload +from torch.fx import GraphModule, Node +from torchao.quantization.pt2e.quantizer import ( + ComposableQuantizer, + QuantizationAnnotation, + Quantizer, + SharedQuantizationSpec, +) +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + + +def mark_node_as_annotated( + node: Node, + input_qspec_map: dict[Node, Optional[QuantizationSpec]], + output_qspec: Optional[QuantizationSpec], +) -> None: + node.meta[Q_ANNOTATION_KEY] = QuantizationAnnotation(input_qspec_map, output_qspec) + annotation_info = ArmAnnotationInfo( + quantized=True, + ) + meta_custom = node.meta.get("custom", {}) + meta_custom[ArmAnnotationInfo.CUSTOM_META_KEY] = dict(annotation_info) + node.meta["custom"] = meta_custom + + +class CortexMQuantizer(ComposableQuantizer): + + def broadcasting_filter(self, node: Optional[Node]) -> bool: + """ + Filter function to exclude nodes that perform broadcasting. + """ + if node is None: + return False + if [node.target] not in BINARY_OP_PATTERNS: + return False + + if len(node.all_input_nodes) == 2: + t1 = get_first_fake_tensor(node.all_input_nodes[0]) + t2 = get_first_fake_tensor(node.all_input_nodes[1]) + return t1.shape != t2.shape and not ( + is_channel_broadcast(t1, t2) and is_channels_last(t1) + ) + + return False + + def nchw_filter(self, node: Optional[Node]) -> bool: + """ + Filter function to exclude nodes that use NCHW memory format. + """ + if node is None: + return False + if [node.target] not in CONV_OP_PATTERNS: + return False + + tensor = get_first_fake_tensor(node) + if tensor is None: + return False + + return not is_channels_last(tensor) + + @staticmethod + def _resolve_int(value: Any) -> Optional[int]: + """Best-effort conversion of FX node arguments to ints.""" + if isinstance(value, int): + return value + if hasattr(value, "item"): + try: + return int(value.item()) # type: ignore[arg-type] + except Exception: + return None + if hasattr(value, "meta"): + meta_val = value.meta.get("val") + return CortexMQuantizer._resolve_int(meta_val) + return None + + def _extract_dim(self, node: Node) -> Optional[int]: + """Return the dim argument from a softmax node when statically known.""" + dim_arg = None + if len(node.args) > 1: + dim_arg = node.args[1] + elif "dim" in node.kwargs: + dim_arg = node.kwargs["dim"] + + if dim_arg is None: + return -1 + + return self._resolve_int(dim_arg) + + def softmax_memory_format_filter(self, node: Optional[Node]) -> bool: + """ + Return true given the tensor must either + - be contiguous (default layout) with softmax dim == last logical dim, or + - be channels_last with softmax dim == channel dim. + Any other combination is skipped so the op stays in ATen form. + """ + if node is None: + return False + if [node.target] not in SOFTMAX_OP_PATTERNS: + return False + + tensor = get_first_fake_tensor(node) + if tensor is None: + return True + + dim = self._extract_dim(node) + if dim is None: + return True + + rank = tensor.dim() + if rank == 0: + return True + + positive_dim = dim if dim >= 0 else dim + rank + if positive_dim < 0 or positive_dim >= rank: + return True + + is_channels_last = False + if rank == 4: + is_channels_last = tensor.is_contiguous(memory_format=torch.channels_last) + + if is_channels_last: + channel_dim = 1 if rank >= 2 else rank - 1 + if positive_dim != channel_dim: + return True + else: + if positive_dim != rank - 1: + return True + + return False + + def __init__(self) -> None: + quantizers: List[Quantizer] = [ + OperatorConfigQuantizer( + INT8_BINARY_OPS_OPERATOR_CONFIG, filter_fn=self.broadcasting_filter + ), + OperatorConfigQuantizer(INT8_LINEAR_OPERATOR_CONFIG), + OperatorConfigQuantizer( + INT8_CONV_OPERATOR_CONFIG, filter_fn=self.nchw_filter + ), + OperatorConfigQuantizer( + INT8_SOFTMAX_OPERATOR_CONFIG, + filter_fn=self.softmax_memory_format_filter, + ), + InputQuantizer(INT8_PER_TENSOR_CONFIG), + OutputQuantizer(INT8_PER_TENSOR_CONFIG), + SharedQspecQuantizer(), + ] + super().__init__(quantizers) + + def validate(self, model: GraphModule) -> bool: + return True + + def transform_for_annotation(self, model: GraphModule) -> GraphModule: + pass_manager = CortexMPassManager(None) + return pass_manager.transform_for_annotation(model) + + +class OperatorConfigQuantizer(Quantizer): + """ + Quantizes a graph according to an OperatorConfig. + + Args: + operator_config (OperatorConfig): The operator config to use for quantization. + filter_fn (Callable): Negative filter function. If it returns True on any node in the pattern, the pattern is + skipped. Used to match for example particular targets or modules. + """ + + def __init__( + self, + operator_config: QuantizationConfig, + filter_fn: Callable[[Node], bool] = lambda node: False, + ) -> None: + self.operator_config = operator_config + self.filter_fn = filter_fn + + def check_node(self, node: Optional[Node], target: str) -> bool: + """ + Return true if the node is a valid match for the given target. + """ + if node is None: + return False + if not node.target == target: + return False + if node.meta.get("quantizer_matched", False): + return False + if self.filter_fn(node): + return False + + return True + + def check_pattern( + self, node: Optional[Node], pattern: List[OpOverload] + ) -> Optional[List[Node]]: + """ + Returns the matched nodes if the given node matches the given pattern, otherwise None. + """ + match: List[Node] = [] + + for pattern_target in pattern: + if self.check_node(node, pattern_target): + match.append(node) + node = list(node.users)[0] if len(node.users) > 0 else None + else: + return None + + return match + + def match_patterns( + self, model: GraphModule, patterns: List[List[str]] + ) -> List[List[Node]]: + """ + Match all given patterns in the graph and return list of matches. + Each node can only be part of one match, larger patterns are prioritized. + Currently only linear patterns (single chain) are supported. + """ + patterns.sort(key=len, reverse=True) + matches: List[List[Node]] = [] + for pattern in patterns: + for node in model.graph.nodes: + potential_match = self.check_pattern(node, pattern) + if potential_match: + matches.append(potential_match) + for node in potential_match: + node.meta["quantizer_matched"] = True + + return matches + + def is_parameter(self, node: Node, model: GraphModule) -> bool: + """Returns True if the given node is a parameter of the model.""" + try: + _ = model.get_parameter(node.target) + return True + except Exception: + return False + + def is_weight(self, node: Node, params: List[Node], model: GraphModule) -> bool: + """Returns True if node is the first parameter of the given parameters""" + return len(params) > 0 and node == params[0] + + def is_bias(self, node: Node, params: List[Node], model: GraphModule) -> bool: + """Returns True if node is the second parameter of the given parameters""" + return len(params) == 2 and node == params[1] + + def annotate_match( + self, match: List[Node], config: QuantizationConfig, model: GraphModule + ) -> None: + """ + Annotates a matched pattern according to the given quantization config. The + following assumptions are made: + + - All operators have either no parameters, only weights, or weights and biases + - Tensors which are the first parameter of an operator are annotated as weights + - Tensors which are the second parameter of an operator are annotated as biases + - All other tensors going into the matched pattern are annotated as input activations. + - All other outputs coming out of the matched pattern are annotated as output activations. + + """ + for node in match: + input_qspec_map = {} + output_qspec = None + + params = [n for n in node.all_input_nodes if self.is_parameter(n, model)] + # Check that the assumptions on number of parameters hold to avoid silent errors + assert ( + 0 <= len(params) <= 2 + ), f"{self.__class__.__name__} expected 0 params, 1 params (weight) or 2 params (weight, bias), but got {len(params)} for node {node}." + + for input_node in node.all_input_nodes: + if self.is_weight(input_node, params, model): + input_qspec_map[input_node] = config.weight if config else None + elif self.is_bias(input_node, params, model): + # Bias qspec is derived from input + weight qspecs + input_qspec_map[input_node] = config.bias(node) if config else None + elif input_node not in match: + input_qspec_map[input_node] = ( + config.input_activation if config else None + ) + + if all(node not in match for node in node.users) and output_qspec is None: + output_qspec = config.output_activation if config else None + + mark_node_as_annotated(node, input_qspec_map, output_qspec) + + def annotate(self, model: GraphModule) -> None: + matches = self.match_patterns(model, self.operator_config.operators) + for match in matches: + self.annotate_match(match, self.operator_config.config, model) + + def validate(self, model: GraphModule) -> bool: + return True + + +class InputQuantizer(Quantizer): + """ + Quantizes only the input activations of the graph. + """ + + def __init__( + self, + quantization_config: QuantizationConfig, + filter_fn: Callable[[Node], bool] = lambda node: False, + ) -> None: + self.quantization_config = quantization_config + self.filter_fn = filter_fn + + def annotate(self, model: GraphModule) -> None: + for node in model.graph.nodes: + is_placeholder = node.op == "placeholder" + is_filtered = self.filter_fn(node) + if is_placeholder and not is_filtered: + mark_node_as_annotated( + node, {}, self.quantization_config.output_activation + ) + + def validate(self, model: GraphModule) -> bool: + return True + + +class OutputQuantizer(Quantizer): + """ + Quantizes only the output activations of the graph. + """ + + def __init__( + self, + quantization_config: QuantizationConfig, + filter_fn: Callable[[Node], bool] = lambda node: False, + ) -> None: + self.quantization_config = quantization_config + self.filter_fn = filter_fn + + def annotate(self, model: GraphModule) -> None: + output_node = model.graph.output_node() + input_qspec_map = { + n: self.quantization_config.input_activation + for n in output_node.all_input_nodes + if not self.filter_fn(n) + } + output_qspec = self.quantization_config.output_activation + mark_node_as_annotated(output_node, input_qspec_map, output_qspec) + + def validate(self, model: GraphModule) -> bool: + return True + + +class SharedQspecQuantizer(Quantizer): + """ + Special quantizer for assuring that given ops share the same quantization parameters on all input and outputs, + i.e. ops which does not change the scale such as clone, min/max, transposes and so on. + + Args: + targets (Optional[List[OpOverload]]): List of operator overloads to apply shared quantization spec to. + If None, a default list of supported ops is used. + """ + + SHARED_QSPEC_OPS_DEFAULT: List[OpOverload] = [ + # Clone + torch.ops.aten.clone.default, + torch.ops.aten.lift_fresh_copy.default, + torch.ops.aten.detach_.default, + # Min/Max/Mean + torch.ops.aten.minimum.default, + torch.ops.aten.maximum.default, + torch.ops.aten.avg_pool2d.default, + # Data shuffling + torch.ops.aten.permute.default, + torch.ops.aten.permute_copy.default, + torch.ops.aten.transpose.Dimname, + torch.ops.aten.transpose.int, + torch.ops.aten.transpose_copy.int, + torch.ops.aten.t_copy.default, + torch.ops.aten.t.default, + # Change shape + torch.ops.aten.squeeze.default, + torch.ops.aten.squeeze_copy.default, + torch.ops.aten.squeeze_copy.dim, + torch.ops.aten.squeeze.dim, + torch.ops.aten.squeeze.dims, + torch.ops.aten.unsqueeze.default, + torch.ops.aten.unsqueeze_copy.default, + torch.ops.aten.reshape.default, + torch.ops.aten.view.default, + torch.ops.aten.view_as.default, + torch.ops.aten.view_copy.default, + torch.ops.aten._unsafe_view.default, + torch.ops.aten.unflatten.int, + torch.ops.aten.flatten.using_ints, + ] + + def __init__(self, targets: Optional[List[OpOverload]] = None) -> None: + super().__init__() + if targets is None: + self.targets = self.SHARED_QSPEC_OPS_DEFAULT + else: + self.targets = targets + + def _is_annotated(self, node: Node) -> bool: + return Q_ANNOTATION_KEY in node.meta + + def _annotate_shared_cluster(self, root_node: Node) -> None: + """ + Finds a cluster of unannotated nodes starting in root_node and annotates them with a common + SharedQuantizationSpec. + """ + + shared_nodes = set() + leaf_nodes = set() + bfs_queue = [root_node] + + while bfs_queue: + node = bfs_queue.pop(0) + + if self._is_annotated(node): + leaf_nodes.add(node) + continue + if node.op == "get_attr": + continue + + if node.target not in self.targets: + raise NotImplementedError( + ( + f"{SharedQspecQuantizer.__name__} found unannoted node '{node.name}' in neighbour_nodes " + "which is not in the supported target list. This might be the case either because:\n" + "1) The op should have shared qspec but is not in the target list. " + "In this case, try modifying the list using the targets field in the initializer.\n" + "2) The op should not be quantized, which is not currently supported by the SharedQspecQuantizer." + ) + ) + + shared_nodes.add(node) + neighbour_nodes = list(node.all_input_nodes) + list(node.users) + for n in neighbour_nodes: + if n not in shared_nodes: + bfs_queue.append(n) + + # The selection of root node for the shared_qspec is important for + # torchao.quantization.pt2e.prepare._create_obs_or_fq_from_qspec: + # 1. For regular QuantizationSpecs, it creates a new observer + # 2. For SharedQuantizationSpecs, it returns the observer created for it's root node + # 3. It handles nodes in the order they appear in graph.nodes + # This means that the root node of the shared group needs to be the first annotated node that appears in graph.nodes. + shared_root_node = next(n for n in root_node.graph.nodes if n in leaf_nodes) + shared_qspec = SharedQuantizationSpec(shared_root_node) + + for node in shared_nodes: + input_qspec_map: dict[Node, Optional[QuantizationSpec]] = { + n: shared_qspec for n in node.all_input_nodes + } + mark_node_as_annotated(node, input_qspec_map, shared_qspec) + + def annotate(self, model: GraphModule) -> None: + """ + Annotate shared quantization spec for supported ops, but skip avg_pool2d + when both ceil_mode and count_include_pad are True. + """ + for node in model.graph.nodes: + # TODO Skip avg_pool2d when ceil_mode=True or count_include_pad=True + # CMSIS-NN doesn't directly support this. But, it should be done. + if node.target is torch.ops.aten.avg_pool2d.default: + ceil_mode = cast(bool, node.args[4]) if len(node.args) > 4 else False + count_include_pad = ( + cast(bool, node.args[5]) if len(node.args) > 5 else True + ) + if ceil_mode or count_include_pad: + continue + if node.target in self.targets and not self._is_annotated(node): + self._annotate_shared_cluster(node) + + def validate(self, model: GraphModule) -> bool: + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/BUCK new file mode 100644 index 0000000..5630c92 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/BUCK @@ -0,0 +1,11 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/TARGETS new file mode 100644 index 0000000..292a087 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/TARGETS @@ -0,0 +1,25 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") +load("targets.bzl", "define_common_targets") + +oncall("executorch") +python_unittest( + name="test_replace_quant_nodes", + srcs=[ + "test_helpers_passes_utils.py", + "test_replace_quant_nodes.py", + ], + deps=[ + "//pytorch/ao:torchao", # @manual + "//caffe2:torch", + "//executorch/backends/cortex_m/passes:replace_quant_nodes_pass", + "//executorch/backends/cortex_m/ops:ops", + ], +) + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/build_test_runner.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/build_test_runner.sh new file mode 100755 index 0000000..bf29b21 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/build_test_runner.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# TODO: More separation from the regular arm executor runner and testing. + +set -eu + +# Always rebuild executorch in case the cortex-m kernels has been updated. +script_dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +et_root_dir=$(realpath "${script_dir}/../../..") +build_executorch="${et_root_dir}/backends/arm/scripts/build_executorch.sh" +${build_executorch} + +# Build executor runner with selected aten ops and semi hosting +build_dir="${et_root_dir}/arm_test" +build_executor_runner="${et_root_dir}/backends/arm/scripts/build_executor_runner.sh" +build_root_test_dir="${et_root_dir}/arm_test/arm_semihosting_executor_runner_corstone-300" + +select_ops_list="\ +aten::add.out,\ +aten::clamp.out,\ +aten::convolution.out,\ +aten::div.out,\ +aten::mean.out,\ +aten::mul.out,\ +aten::relu.out,\ +aten::view_copy.out,\ +dim_order_ops::_to_dim_order_copy.out" + +${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --output="${build_root_test_dir}" --select_ops_list="${select_ops_list}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/misc/test_quantization.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/misc/test_quantization.py new file mode 100644 index 0000000..d4f84e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/misc/test_quantization.py @@ -0,0 +1,359 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) +from executorch.exir.dialects._ops import ops as exir_ops + + +class SharedQspecMulipleClusters(torch.nn.Module): + """Three linear shared qspec clusters.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 8, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 8, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 4, + } + + def forward(self, x): + x1 = torch.clone(x) + x2 = x1 + x1 + x3 = torch.clone(x2) + x3 = torch.clone(x3) + x3 = torch.clone(x3) + x4 = x3 + x3 + x5 = torch.transpose(x4, 2, 1) + return x5 + + +class SharedQspecInputForkNonShared(torch.nn.Module): + """Shared qspec cluster with an input fork with both inputs as non-shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + } + + def forward(self, x, y): + z = torch.maximum(x, y) + return torch.flatten(z) + + +class SharedQspecInputForkShared(torch.nn.Module): + """Shared qspec cluster with an input fork with both inputs as shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 5, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 5, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x, y): + x = torch.clone(x) + y = torch.permute(y, (0, 1, 3, 2)) + z = torch.minimum(x, y) + return z + + +class SharedQspecInputForkXShared(torch.nn.Module): + """Shared qspec cluster with an input fork with left input as shared qspec.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x, y): + x = torch.t_copy(x) + z = torch.maximum(x, y) + return z + + +class SharedQspecInputForkYShared(torch.nn.Module): + """Shared qspec cluster with an input fork with right input as shared qspec.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 5, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 5, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x, y): + y = torch.clone(y) + z = torch.minimum(x, y) + return torch.squeeze(z) + + +class SharedQspecInputForkXConstant(torch.nn.Module): + """Shared qspec cluster with an input fork with left input as global constant.""" + + ops_before_transforms = {} + ops_after_transforms = {} + constant = torch.tensor(5.0) + + def forward(self, x): + return torch.minimum(self.constant, x) + + +class SharedQspecInputForkYConstant(torch.nn.Module): + """Shared qspec cluster with an input fork with left input as local constant.""" + + ops_before_transforms = {} + ops_after_transforms = {} + + def forward(self, x): + return torch.maximum(x, torch.tensor(5.0)) + + +class SharedQspecOutputForkNonShared(torch.nn.Module): + """Shared qspec cluster with an output fork with both outputs as non-shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + } + + def forward(self, x): + x = torch.unsqueeze(x, 0) + y = x + x + return x, y + + +class SharedQspecOutputForkShared(torch.nn.Module): + """Shared qspec cluster with an output fork with both outputs as shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 6, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x): + x = torch.unsqueeze(x, 0) + y = torch.clone(x) + z = torch.permute_copy(x, (0, 2, 1, 3)) + return y, z, x + + +class SharedQspecManyForks(torch.nn.Module): + """Shared qspec cluster with a number of forks to testmore complex structures.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 2, + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 9, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 6, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x): + x1 = torch.clone(x) + x2 = torch.maximum(x, x1) + x3 = torch.maximum(x, torch.t(x2)) + x4 = torch.minimum(x2, x3) + + return x4 + + +class SharedQspecSurroundedQuantizedOp(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 5, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x): + x1 = torch.clone(x) + x2 = torch.add(x1, x1) + x3 = torch.maximum(x1, x2) + return x3 + + +class SharedQspecSurroundedQuantizedOpConstant(torch.nn.Module): + ops_before_transforms = {} + ops_after_transforms = {} + + def forward(self, x): + x1 = torch.clone(x) + x2 = torch.add(x1, torch.ones(2, 2)) + x3 = torch.maximum(x1, x2) + return x3 + + +class SharedQspecSub(torch.nn.Module): + ops_before_transforms = {} + ops_after_transforms = {} + + def forward(self, x, y): + return torch.clone(x - y) + + +test_cases = { + "multiple_clusters": McuTestCase( + SharedQspecMulipleClusters(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "input_fork_non_shared": McuTestCase( + SharedQspecInputForkNonShared(), + (ramp_tensor(-2, 2, (2, 3, 4)), ramp_tensor(-1, 3, (2, 3, 4))), + ), + "input_fork_shared": McuTestCase( + SharedQspecInputForkShared(), + (ramp_tensor(-2, 2, (2, 3, 4, 5)), ramp_tensor(-1, 3, (2, 3, 5, 4))), + ), + "input_fork_x_shared": McuTestCase( + SharedQspecInputForkXShared(), + (ramp_tensor(-2, 2, (3, 4)), ramp_tensor(-1, 3, (4, 3))), + ), + "input_fork_y_shared": McuTestCase( + SharedQspecInputForkYShared(), + (ramp_tensor(-2, 2, (2, 3, 4)), ramp_tensor(-1, 3, (2, 3, 4))), + ), + "input_fork_x_constant": McuTestCase( + SharedQspecInputForkXConstant(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "input_fork_y_constant": McuTestCase( + SharedQspecInputForkYConstant(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "surrounded_quantized_op": McuTestCase( + SharedQspecSurroundedQuantizedOp(), + (ramp_tensor(-128, 2, (2, 3, 4)),), + ), + "surrounded_quantized_op_constant": McuTestCase( + SharedQspecSurroundedQuantizedOpConstant(), + (ramp_tensor(-2, 2, (2, 2)),), + ), + "output_fork_non_shared": McuTestCase( + SharedQspecOutputForkNonShared(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "output_fork_shared": McuTestCase( + SharedQspecOutputForkShared(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "many_forks": McuTestCase( + SharedQspecManyForks(), + (ramp_tensor(-20, 2, (4, 4)),), + ), + "non-quantized_op": McuTestCase( + SharedQspecSub(), + (ramp_tensor(0, 10, (5, 5)), ramp_tensor(0, 1, (5, 5))), + ), +} + +xfails = { + "surrounded_quantized_op_constant": "Numerical error since the add is forced to have non-correct qparams.", + "non-quantized_op": "Non-quantized ops are not currently supported in SharedQspecQuantizer.", +} + + +@parametrize("test_case", test_cases, xfails=xfails) +def test_shared_qspec_quantizer(test_case): + """ + Test that ops which does not change dynamic range are able to use int8 portable kernels. + """ + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + # Check that all nodes in the graph are in int8 + artifact = tester.get_artifact() + for node in artifact.exported_program().module().graph.nodes: + if node.op != "call_function": + continue + if node.target == exir_ops.edge.cortex_m.dequantize_per_tensor.default: + continue + + assert get_first_fake_tensor(node).dtype == torch.int8, f"{node.name}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/test_mobilenet_v3.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/test_mobilenet_v3.py new file mode 100644 index 0000000..598d71e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/models/test_mobilenet_v3.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch + +from executorch.backends.cortex_m.test.tester import CortexMTester, McuTestCase +from torchvision import models + + +# TODO: Update as more ops are converted by CMSIS-NN ops. +ops_before_transforms: dict[str, int] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 34, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 2, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 56, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 52, + "executorch_exir_dialects_edge__ops_aten_div_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 10, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_relu_default": 14, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 56, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 178, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 109, +} +ops_after_transforms: dict[str, int] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 28, # Not lowered due to broadcasting + "executorch_exir_dialects_edge__ops_aten_addmm_default": 0, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 6, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 2, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 56, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 52, + "executorch_exir_dialects_edge__ops_aten_div_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 10, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 0, + "executorch_exir_dialects_edge__ops_aten_relu_default": 14, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 56, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 0, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 0, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 162, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 101, +} + +model = models.mobilenet_v3_small(weights=None) +example_input = torch.randn(1, 3, 224, 224) + + +test_cases = { + "mobilenet_v3_small": McuTestCase( + model=models.mobilenet_v3_small(weights=None), + example_inputs=(example_input,), + ), +} + + +@pytest.mark.skip("Skip until add + linear fix are upstreamed.") +def test_dialect_mv3(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + ops_before_transforms, + ops_after_transforms, + qtol=1, + ) + + +@pytest.mark.skip("Skip until add + linear fix are upstreamed.") +def test_implementation_mv3(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp new file mode 100644 index 0000000..a4cf9d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::KernelRuntimeContext; +using torch::executor::testing::TensorFactory; + +// Test op +using cortex_m::native::dequantize_per_tensor_out; + +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 4); + double scale = 0.5; + + int64_t zero_point = 108; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (4 - 108) * 0.5 = -52 + Tensor expected = tfo.full({3, 5}, -52.0); + + KernelRuntimeContext ctx; + dequantize_per_tensor_out( + ctx, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, AllDtypesSupported) { + test_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_quantize_per_tensor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_quantize_per_tensor_test.cpp new file mode 100644 index 0000000..3b6e2e5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/op_quantize_per_tensor_test.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::KernelRuntimeContext; +using torch::executor::testing::TensorFactory; + +// Test op +using cortex_m::native::quantize_per_tensor_out; + +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 4); + double scale = 0.5; + + int64_t zero_point = 108; + int64_t quant_min = 0; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 108 = 116 + Tensor expected = tfo.full({3, 5}, 116); + + KernelRuntimeContext ctx; + quantize_per_tensor_out( + ctx, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, AllDtypesSupported) { + test_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_activation.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_activation.py new file mode 100644 index 0000000..8886a05 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_activation.py @@ -0,0 +1,528 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMLinearReLU(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=4, out_features=3): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.relu(self.linear(x)) + + +class CortexMLinearHardtanh(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-0.25, max_val=0.75): + super().__init__() + self.linear = torch.nn.Linear(4, 4, bias=False) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val) + self.min_val = min_val + self.max_val = max_val + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMLinearReLU6(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=8, out_features=8): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.relu6 = torch.nn.ReLU6() + + def forward(self, x): + return self.relu6(self.linear(x)) + + +class CortexMLinearReLUInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=8, out_features=8): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.relu = torch.nn.ReLU(inplace=True) + + def forward(self, x): + return self.relu(self.linear(x)) + + +class CortexMLinearHardtanhInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-1.0, max_val=1.0): + super().__init__() + self.linear = torch.nn.Linear(8, 8, bias=False) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val, inplace=True) + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMLinearHardsigmoid(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardsigmoid_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=6, out_features=6): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.act = torch.nn.Hardsigmoid() + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMLinearHardswish(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardswish_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=8, out_features=8): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.act = torch.nn.Hardswish() + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMConv2DReLU(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=False) + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.relu(self.conv(x)) + + +class CortexMConv2DReLU6(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(3, 6, 3, stride=2, padding=1, bias=False) + self.relu6 = torch.nn.ReLU6() + + def forward(self, x): + return self.relu6(self.conv(x)) + + +class CortexMConv2DHardtanh(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-2.0, max_val=2.0): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=True) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DHardswish(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardswish_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(2, 1, 1, padding=0, bias=False) + self.act = torch.nn.Hardswish() + self.conv.weight.data.fill_(0.5) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DReLUInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=False) + self.relu = torch.nn.ReLU(inplace=True) + + def forward(self, x): + return self.relu(self.conv(x)) + + +class CortexMConv2DHardtanhInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-0.5, max_val=0.5): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=False) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val, inplace=True) + torch.nn.init.ones_(self.conv.weight) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DHardsigmoid(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardsigmoid_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(2, 1, 1, bias=False) + self.act = torch.nn.Hardsigmoid(inplace=True) + self.conv.weight.data.fill_(0.5) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DClampInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(2, 1, 1, bias=False) + self.conv.weight.data.fill_(0.5) + + def forward(self, x): + return torch.clamp_(self.conv(x), min=0.0, max=None) + + +class CortexMLinearClamp(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=4, out_features=3): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + + def forward(self, x): + return torch.clamp(self.linear(x), min=None, max=6.0) + + +test_cases = { + # Linear + activation tests with various data ranges + "linear_relu_small_range": McuTestCase( + model=CortexMLinearReLU(), + example_inputs=(ramp_tensor(-10, 10, (1, 4)),), + ), + "linear_relu_large_range": McuTestCase( + model=CortexMLinearReLU(in_features=16, out_features=16), + example_inputs=(ramp_tensor(-100, 100, (2, 16)),), + ), + "linear_relu_negative": McuTestCase( + model=CortexMLinearReLU(in_features=8, out_features=8), + example_inputs=(ramp_tensor(-50, 0, (1, 8)),), + ), + "linear_relu6": McuTestCase( + model=CortexMLinearReLU6(), + example_inputs=(ramp_tensor(-2, 10, (1, 8)),), + ), + "linear_relu_inplace": McuTestCase( + model=CortexMLinearReLUInplace(), + example_inputs=(ramp_tensor(-5, 5, (2, 8)),), + ), + "linear_hardtanh_symmetric": McuTestCase( + model=CortexMLinearHardtanh(min_val=-0.5, max_val=0.5), + example_inputs=(ramp_tensor(-1, 1, (2, 1, 4)),), + ), + "linear_hardtanh_asymmetric": McuTestCase( + model=CortexMLinearHardtanh(min_val=-1.5, max_val=0.25), + example_inputs=(ramp_tensor(-2, 1, (1, 4)),), + ), + "linear_hardtanh_large_range": McuTestCase( + model=CortexMLinearHardtanh(min_val=-10.0, max_val=10.0), + example_inputs=(ramp_tensor(-20, 20, (2, 4)),), + ), + "linear_hardtanh_inplace": McuTestCase( + model=CortexMLinearHardtanhInplace(min_val=-0.75, max_val=0.75), + example_inputs=(ramp_tensor(-2, 2, (1, 8)),), + ), + # Convolution + activation tests with various configurations + "conv2d_relu_small_kernel": McuTestCase( + model=CortexMConv2DReLU(), + example_inputs=( + ramp_tensor(-5, 5, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_relu_large_range": McuTestCase( + model=CortexMConv2DReLU(), + example_inputs=( + ramp_tensor(-50, 50, (2, 4, 16, 16)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_relu6_stride": McuTestCase( + model=CortexMConv2DReLU6(), + example_inputs=( + ramp_tensor(-10, 20, (1, 3, 12, 12)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_relu_inplace": McuTestCase( + model=CortexMConv2DReLUInplace(), + example_inputs=( + ramp_tensor(-3, 3, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardtanh_narrow": McuTestCase( + model=CortexMConv2DHardtanh(min_val=-0.5, max_val=0.5), + example_inputs=( + ramp_tensor(-2, 2, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardtanh_wide": McuTestCase( + model=CortexMConv2DHardtanh(min_val=-5.0, max_val=5.0), + example_inputs=( + ramp_tensor(-10, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardtanh_inplace": McuTestCase( + model=CortexMConv2DHardtanhInplace(min_val=-10.0, max_val=10.0), + example_inputs=( + ramp_tensor(-15, 15, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "linear_hardsigmoid": McuTestCase( + model=CortexMLinearHardsigmoid(in_features=6, out_features=4), + example_inputs=(ramp_tensor(-8, 8, (2, 6)),), + ), + "linear_hardswish": McuTestCase( + model=CortexMLinearHardswish(in_features=12, out_features=6), + example_inputs=(ramp_tensor(-2, 0, (1, 12)),), + ), + "conv2d_hardsigmoid_inplace": McuTestCase( + model=CortexMConv2DHardsigmoid(), + example_inputs=( + ramp_tensor(-4, 4, (1, 2, 6, 6)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardswish": McuTestCase( + model=CortexMConv2DHardswish(), + example_inputs=( + ramp_tensor(-3, 0, (1, 2, 1, 100)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_clamp_inplace": McuTestCase( + model=CortexMConv2DClampInplace(), + example_inputs=( + ramp_tensor(-4, 4, (1, 2, 1, 10)).to(memory_format=torch.channels_last), + ), + ), + "linear_clamp": McuTestCase( + model=CortexMLinearClamp(in_features=4, out_features=3), + example_inputs=(ramp_tensor(-10, 10, (1, 4)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_activation(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_activation(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_add.py new file mode 100644 index 0000000..ad5f276 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_add.py @@ -0,0 +1,182 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) +from executorch.backends.test.suite.operators.test_add import Model, ModelAlpha + + +class CortexMSelfAdd(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x): + return x + x + + +class CortexMScalarAdd(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +class CortexMTensorAdd(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +class CortexMAlphaAdd(ModelAlpha): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +test_cases = { + "self_rank_1": McuTestCase( + CortexMSelfAdd(), + (torch.linspace(-5, 5, 10),), + ), + "self_rank_2_pos": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(0, 1000, (10, 1)),), + ), + "self_rank_3_neg": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(-100, 0, (2, 2, 2)),), + ), + "self_rank_4_small": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(-0.1, 0.1, (2, 2, 2, 2)),), + ), + "self_rank_5": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(-5, 5, (2, 2, 2, 2, 2)),), + ), + "tensor_scalar": McuTestCase( + CortexMScalarAdd(), + (torch.ones(1), 1.1), + ), + "scalar_tensor": McuTestCase( + CortexMScalarAdd(), + (1000.1, torch.ones(1)), + ), + "tensor_tensor": McuTestCase( + CortexMTensorAdd(), + (torch.rand(2, 2) * 10, torch.rand(2, 2)), + ), + "broadcast_1": McuTestCase( + CortexMTensorAdd(), + (torch.ones(1), torch.ones(2, 2, 2, 2)), + ), + "broadcast_2": McuTestCase( + CortexMTensorAdd(), + (torch.ones((2, 1, 1, 1)), torch.ones(1)), + ), + "broadcast_3": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-2, 2, (2, 1, 2, 1)), + ramp_tensor(-5, 5, (1, 2, 1, 2)), + ), + ), + "broadcast_channels_1": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ramp_tensor(-5, 5, (1, 8, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_2": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)).to(memory_format=torch.channels_last), + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_continous": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)), + ramp_tensor(-2, 2, (1, 8, 1, 1)), + ), + ), + "alpha": McuTestCase( + CortexMAlphaAdd(0.5), + ( + ramp_tensor(-10, 10, (4, 5)), + ramp_tensor(-20, 20, (4, 5)), + ), + ), +} + + +xfails_implementation = { + "alpha": ( + "Expecting kwargs for aten op IR to be empty - alpha arg not supported.", + AssertionError, + ), +} +xfails_dialect = xfails_implementation | { + # Cortex-M quantizer will not quantize additions that require broadcasting + # leading to the add op not being replaced by a cortex-m specific implementation + "broadcast_1": "Broadcasting is not supported in Cortex-M backend", + "broadcast_2": "Broadcasting is not supported in Cortex-M backend", + "broadcast_3": "Broadcasting is not supported in Cortex-M backend", + "broadcast_channels_continous": "Broadcasting channels is not supported in continous memory_format in Cortex-M backend.", +} + + +@parametrize("test_case", test_cases, xfails=xfails_dialect) +def test_dialect_add(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@parametrize("test_case", test_cases, xfails=xfails_implementation) +def test_implementation_add(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_avg_pool2d.py new file mode 100644 index 0000000..5c25fce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_avg_pool2d.py @@ -0,0 +1,99 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMAvgPool2d(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_avg_pool2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__( + self, kernel_size, stride, padding=0, ceil_mode=False, count_include_pad=False + ): + super().__init__() + self.pool = torch.nn.AvgPool2d( + kernel_size, + stride, + padding, + ceil_mode=ceil_mode, + count_include_pad=count_include_pad, + ) + + def forward(self, x): # noqa: D102 + return self.pool(x) + + +# Prepare test cases: simple 2x2 pool on 4x4, and 3x3 stride 1 on 3x3 +test_cases = { + "avgpool_2x2": McuTestCase( + CortexMAvgPool2d(kernel_size=2, stride=2), (ramp_tensor(0, 15, (1, 1, 4, 4)),) + ), + "avgpool_3x3_s1": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=1, padding=1), + (ramp_tensor(0, 8, (1, 1, 3, 3)),), + ), + # additional pooling configurations: padding, stride, ceil_mode, count_include_pad + "avgpool_2x2_pad1": McuTestCase( + CortexMAvgPool2d(kernel_size=2, stride=2, padding=1), + (ramp_tensor(0, 24, (1, 1, 5, 5)),), + ), + "avgpool_3x3_s2_pad1": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=2, padding=1), + (ramp_tensor(0, 15, (1, 1, 4, 4)),), + ), +} + +test_cases_fp = { + "avgpool_3x3_s2_pad1_ceil": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=2, padding=1, ceil_mode=True), + (ramp_tensor(0, 15, (1, 1, 4, 4)),), + ), + "avgpool_3x3_s2_pad1_countinc": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=2, padding=1, count_include_pad=True), + (ramp_tensor(0, 15, (1, 1, 4, 4)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_avg_pool2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases_fp) +def test_dialect_avg_pool2d_fp(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1}, + {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1}, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_avg_pool2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_conv.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_conv.py new file mode 100644 index 0000000..5c970b5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_conv.py @@ -0,0 +1,342 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMConv1D(torch.nn.Module): + ops_before_transforms = {} + ops_after_transforms = {} + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv1d(*args, **kwargs, bias=False) + + def forward(self, x): + return self.conv(x) + + +class CortexMConv2D(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=False) + self.conv.weight.data.fill_(1.0) + + def forward(self, x): + return self.conv(x) + + +class CortexMConv2DBias(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=True) + + def forward(self, x): + + return self.conv(x) + + +class CortexMConv3D(torch.nn.Module): + ops_before_transforms = {} + + ops_after_transforms = {} + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv3d(*args, **kwargs, bias=False) + self.conv.weight.data.fill_(2.0) + + def forward(self, x): + return self.conv(x) + + +class CortexMConv2Dx3(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 3, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv1 = torch.nn.Conv2d(3, 8, 3, padding=1, bias=False) + self.conv2 = torch.nn.Conv2d(8, 16, 3, padding=1, bias=False) + self.conv3 = torch.nn.Conv2d(16, 8, 3, padding=1, bias=False) + + def forward(self, x): + x = self.conv1(x) + x = self.conv2(x) + x = self.conv3(x) + return x + + +class CortexMDepthwiseConv2D(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_depthwise_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=False) + + def forward(self, x): + return self.conv(x) + + +class CortexMDepthwiseConv2DBias(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_depthwise_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=True) + + def forward(self, x): + return self.conv(x) + + +# in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias, padding_mode +test_cases = { + "conv2d": McuTestCase( + model=CortexMConv2D(2, 4, 3), + example_inputs=( + ramp_tensor(1, 5, (1, 2, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_stride": McuTestCase( + model=CortexMConv2D(3, 4, (1, 2), stride=2), + example_inputs=( + ramp_tensor(-100, 10, (3, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_padding": McuTestCase( + model=CortexMConv2D(3, 2, 3, padding=(4, 1)), + example_inputs=( + ramp_tensor(0, 1, (2, 3, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_dilation": McuTestCase( + model=CortexMConv2D(1, 4, 3, dilation=(2, 2)), + example_inputs=( + ramp_tensor(0, 10, (3, 1, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_groups": McuTestCase( + model=CortexMConv2D(4, 4, 1, groups=2), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_bias_ch_out_1": McuTestCase( + model=CortexMConv2DBias(5, 1, 1), + example_inputs=( + ramp_tensor(0, 10, (2, 5, 3, 3)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_bias_ch_out_4": McuTestCase( + model=CortexMConv2DBias(5, 4, (1, 2)), + example_inputs=( + ramp_tensor(-3, 3, (2, 5, 10, 10)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_nchw": McuTestCase( + model=CortexMConv2D(5, 5, 1), + example_inputs=(ramp_tensor(0, 10, (1, 5, 8, 8)),), + ), + "conv1d": McuTestCase( + model=CortexMConv1D(1, 1, 1), + example_inputs=(ramp_tensor(0, 10, (1, 3, 2)),), + ), + "conv3d": McuTestCase( + model=CortexMConv3D(1, 1, 1), + example_inputs=( + ramp_tensor(-1000, 1000, (2, 1, 3, 3, 3)).to( + memory_format=torch.channels_last_3d + ), + ), + ), + "conv2d_x3": McuTestCase( + model=CortexMConv2Dx3(), + example_inputs=( + ramp_tensor(0, 10, (1, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + # Depthwise convolution tests (groups == in_channels) + "depthwise_conv2d": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, 3, groups=4), + example_inputs=( + ramp_tensor(1, 5, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_multiplier": McuTestCase( + model=CortexMDepthwiseConv2D(3, 6, 3, groups=3), + example_inputs=( + ramp_tensor(0, 10, (1, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_stride": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, 3, stride=2, groups=4), + example_inputs=( + ramp_tensor(-50, 50, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_padding": McuTestCase( + model=CortexMDepthwiseConv2D(2, 2, 5, padding=2, groups=2), + example_inputs=( + ramp_tensor(0, 1, (1, 2, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_bias": McuTestCase( + model=CortexMDepthwiseConv2DBias(3, 3, 3, padding=1, groups=3), + example_inputs=( + ramp_tensor(-10, 10, (1, 3, 6, 6)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_stride_padding_bias": McuTestCase( + model=CortexMDepthwiseConv2DBias(4, 4, 3, stride=2, padding=1, groups=4), + example_inputs=( + ramp_tensor(0, 5, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_1x1": McuTestCase( + model=CortexMDepthwiseConv2D(4, 8, 1, groups=4), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_multiplier_4": McuTestCase( + model=CortexMDepthwiseConv2D(2, 8, 3, groups=2), + example_inputs=( + ramp_tensor(0, 10, (1, 2, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_asymmetric_kernel": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, (1, 3), groups=4), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_asymmetric_stride": McuTestCase( + model=CortexMDepthwiseConv2D(3, 3, 3, stride=(2, 1), padding=(1, 0), groups=3), + example_inputs=( + ramp_tensor(0, 10, (1, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_5x5": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, 5, padding=2, groups=4), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_minimal_spatial": McuTestCase( + model=CortexMDepthwiseConv2D( + 2, 2, 3, padding=1, groups=2 + ), # 3x3 kernel on 1x1 input + example_inputs=( + ramp_tensor(0, 10, (1, 2, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + # Single-channel depthwise convolution tests (in_channels == groups == 1) + "depthwise_conv2d_single_channel": McuTestCase( + model=CortexMDepthwiseConv2D(1, 1, 3, groups=1), + example_inputs=( + ramp_tensor(0, 10, (1, 1, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_single_channel_multiplier": McuTestCase( + model=CortexMDepthwiseConv2D(1, 3, 3, groups=1), + example_inputs=( + ramp_tensor(0, 10, (1, 1, 8, 8)).to(memory_format=torch.channels_last), + ), + ), +} + + +xfails_dialect = { + "conv2d_dilation": "NotImplementedError: 'slow_conv_dilated<>' not implemented for 'Int'", + "conv1d": "Currently not supported.", + "conv2d_nchw": "Currently not supported.", +} + + +@parametrize("test_case", test_cases, xfails=xfails_dialect) +def test_dialect_conv2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +xfails_implementation = { + "conv1d": "Currently not supported.", + "conv3d": "Currently not supported.", +} + + +@parametrize("test_case", test_cases, xfails=xfails_implementation) +def test_implementation_conv2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=2) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_linear.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_linear.py new file mode 100644 index 0000000..e81daa7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_linear.py @@ -0,0 +1,130 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMLinear(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.linear = torch.nn.Linear(*args, bias=False) + self.linear.weight.data.fill_(1.0) + + def forward(self, x): + return self.linear(x) + + +class CortexMLinearX3(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 7, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 3, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.linear = torch.nn.Linear(*args, bias=False) + self.linear.weight.data.fill_(1.0) + + def forward(self, x): + x = self.linear(x) + x = self.linear(x) + x = self.linear(x) + return x + + +class CortexMLinearBias(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.linear = torch.nn.Linear(*args, bias=True) + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.linear(x) + + +test_cases = { + "linear_rank1": McuTestCase( + model=CortexMLinear(1, 2), + example_inputs=(torch.Tensor([1]),), + ), + "linear_rank2_pos": McuTestCase( + model=CortexMLinear(1, 2), + example_inputs=(ramp_tensor(-1, 1, (1, 1)),), + ), + "linear_rank3_neg": McuTestCase( + model=CortexMLinear(5, 3), + example_inputs=(ramp_tensor(-40, 0, (4, 2, 5)),), + ), + "linear_rank4": McuTestCase( + model=CortexMLinear(16, 32), + example_inputs=(ramp_tensor(-100, 100, (2, 1, 2, 16)),), + ), + "linear_rank5": McuTestCase( + model=CortexMLinear(4, 3), + example_inputs=(ramp_tensor(-2, 2, (5, 2, 1, 2, 4)),), + ), + "linear_bias": McuTestCase( + model=CortexMLinearBias(61, 37), + example_inputs=(ramp_tensor(0, 10, (8, 61)),), + ), + "linear_x3": McuTestCase( + model=CortexMLinearX3(4, 4), + example_inputs=(ramp_tensor(0, 10, (2, 4)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_linear(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_linear(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_lstm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_lstm.py new file mode 100644 index 0000000..60d7aba --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_lstm.py @@ -0,0 +1,98 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import pytest +import torch +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMLSTM(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_full_default": 2, + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 4, + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 6, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 3, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 3, + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 4, + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 6, + "executorch_exir_dialects_edge__ops_aten_tanh_default": 4, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 6, + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + } + + ops_after_transforms = {} + + def __init__(self, input_size: int = 4, hidden_size: int = 3) -> None: + super().__init__() + self.lstm = torch.nn.LSTM(input_size=input_size, hidden_size=hidden_size) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + y, _ = self.lstm(x) + return y + + +class CortexMQuantizableLSTM(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 4, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 4, + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 6, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 4, + "executorch_exir_dialects_edge__ops_aten_select_copy_int": 2, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 6, + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 1, + "executorch_exir_dialects_edge__ops_aten_tanh_default": 4, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 34, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 27, + } + + ops_after_transforms = {} + + def __init__(self, input_size: int = 4, hidden_size: int = 3) -> None: + super().__init__() + self.lstm = torch.ao.nn.quantizable.LSTM( + input_size=input_size, hidden_size=hidden_size + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + y, _ = self.lstm(x) + return y + + +test_cases = { + "lstm_fp32": McuTestCase( + model=CortexMLSTM(), + example_inputs=(ramp_tensor(-1, 1, (2, 1, 4)),), + ), + "lstm_quantizable": McuTestCase( + model=CortexMQuantizableLSTM(), + example_inputs=(ramp_tensor(-1, 1, (2, 1, 4)),), + ), +} + + +@pytest.mark.skip("Not implemented yet.") +def test_dialect_lstm(test_case: McuTestCase) -> None: + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@pytest.mark.skip("Not implemented yet.") +def test_implementation_lstm(test_case: McuTestCase) -> None: + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_maximum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_maximum.py new file mode 100644 index 0000000..58d477a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_maximum.py @@ -0,0 +1,83 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMTensorMaximum(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x, y): + return torch.maximum(x, y) + + +test_cases = { + "tensor_small": McuTestCase( + CortexMTensorMaximum(), + ( + torch.tensor([[1.0, -2.0], [3.5, -4.5]]), + torch.tensor([[0.5, -1.0], [4.0, -3.5]]), + ), + ), + "tensor_rand": McuTestCase( + CortexMTensorMaximum(), + ( + torch.rand(2, 2, 2) * 4 - 2, + torch.rand(2, 2, 2) * 4 - 2, + ), + ), + "broadcast": McuTestCase( + CortexMTensorMaximum(), + ( + ramp_tensor(-2, 2, (2, 1, 2)), + ramp_tensor(-3, 3, (1, 2, 1)), + ), + ), + "broadcast_rank4": McuTestCase( + CortexMTensorMaximum(), + ( + ramp_tensor(-4, 4, (1, 2, 3, 1)), + ramp_tensor(-6, 6, (4, 1, 1, 3)), + ), + ), + "broadcast_scalar": McuTestCase( + CortexMTensorMaximum(), + ( + torch.tensor(1.0), + ramp_tensor(-6, 6, (4, 1, 1, 3)), + ), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_maximum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@parametrize("test_case", test_cases) +def test_implementation_maximum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_minimum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_minimum.py new file mode 100644 index 0000000..633ccdb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_minimum.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMSelfMinimum(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x): + return torch.minimum(x, x) + + +class CortexMTensorMinimum(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x, y): + return torch.minimum(x, y) + + +test_cases = { + "self_rank_1": McuTestCase( + CortexMSelfMinimum(), + (ramp_tensor(-5, 5, (10,)),), + ), + "self_rank_3": McuTestCase( + CortexMSelfMinimum(), + (ramp_tensor(-10, 10, (2, 3, 4)),), + ), + "tensor_small": McuTestCase( + CortexMTensorMinimum(), + ( + torch.tensor([[1.0, -2.0], [3.5, -4.5]]), + torch.tensor([[0.5, -3.0], [3.0, -4.0]]), + ), + ), + "tensor_rand": McuTestCase( + CortexMTensorMinimum(), + ( + torch.rand(2, 2, 2) * 4 - 2, + torch.rand(2, 2, 2) * 4 - 2, + ), + ), + "broadcast": McuTestCase( + CortexMTensorMinimum(), + ( + ramp_tensor(-2, 2, (2, 1, 2)), + ramp_tensor(-3, 3, (1, 2, 1)), + ), + ), + "broadcast_rank4": McuTestCase( + CortexMTensorMinimum(), + ( + ramp_tensor(-4, 4, (1, 2, 3, 1)), + ramp_tensor(-6, 6, (4, 1, 1, 3)), + ), + ), +} + + +xfails = {} + + +@parametrize("test_case", test_cases, xfails=xfails) +def test_dialect_minimum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@parametrize("test_case", test_cases, xfails=xfails) +def test_implementation_minimum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_mul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_mul.py new file mode 100644 index 0000000..88dd904 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_mul.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) +from executorch.backends.test.suite.operators.test_mul import Model + + +class CortexMSelfMul(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x): + return x * x + + +class CortexMScalarMul(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +class CortexMTensorMul(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +test_cases = { + "self_rank_1": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-5, 5, (10,)),), + ), + "self_rank_2_pos": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(0, 1000, (10, 1)),), + ), + "self_rank_3_neg": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-100, 0, (2, 2, 2)),), + ), + "self_rank_4_small": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-0.1, 0.1, (2, 2, 2, 2)),), + ), + "self_rank_5": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-5, 5, (2, 2, 2, 2, 2)),), + ), + "tensor_scalar": McuTestCase( + CortexMScalarMul(), + (torch.ones(1), 1.0), + ), + "scalar_tensor": McuTestCase( + CortexMScalarMul(), + (1000.0, torch.ones(1)), + ), + "broadcast_1": McuTestCase( + CortexMTensorMul(), + (torch.ones(1), torch.ones(2, 2, 2, 2)), + ), + "broadcast_2": McuTestCase( + CortexMTensorMul(), + (torch.ones((2, 1, 1, 1)), torch.ones(1)), + ), + "broadcast_3": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-2, 2, (2, 1, 2, 1)), + ramp_tensor(-5, 5, (1, 2, 1, 2)), + ), + ), + "broadcast_channels_1": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ramp_tensor(-5, 5, (1, 8, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_2": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)).to(memory_format=torch.channels_last), + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_continous": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)), + ramp_tensor(-2, 2, (1, 8, 1, 1)), + ), + ), +} + + +xfail_cases_dialect = { + # Cortex-M quantizer will not quantize multiplicaitons that require broadcasting + # leading to the mul op not being replaced by a cortex-m specific implementation + "broadcast_1": "Broadcasting is not supported in Cortex-M backend", + "broadcast_2": "Broadcasting is not supported in Cortex-M backend", + "broadcast_3": "Broadcasting is not supported in Cortex-M backend", + "broadcast_channels_continous": "Broadcasting channels is not supported in continous memory_format in Cortex-M backend.", +} + + +@parametrize("test_case", test_cases, xfails=xfail_cases_dialect) +def test_dialect_mul(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize( + "test_case", + test_cases, +) +def test_implementation_mul(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_softmax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_softmax.py new file mode 100644 index 0000000..49c8c3e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_softmax.py @@ -0,0 +1,84 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMSoftmax(torch.nn.Module): + def __init__(self, dim: int): + super().__init__() + self.dim = dim + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten__softmax_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_softmax_default": 1, + } + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.softmax(x, dim=self.dim) + + +test_cases = { + "rank1": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-4, 4, (16,)),), + ), + "rank2": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-8, 8, (4, 8)),), + ), + "rank3": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "dim_not_last": McuTestCase( + CortexMSoftmax(dim=1), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "large_tensor": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-10, 10, (8, 1024)),), + ), +} + + +xfail_cases_dialect = { + "dim_not_last": ( + "Softmax stays in ATen when dim isn’t the channel dimension, so dialect expectations fail", + Exception, + ), +} +xfail_cases_impl = { + "dim_not_last": ( + "Softmax on Cortex-M currently supports only the last dimension", + Exception, + ), +} + + +@parametrize("test_case", test_cases, xfails=xfail_cases_dialect) +def test_dialect_softmax(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=2, + ) + + +@parametrize("test_case", test_cases, xfails=xfail_cases_impl) +def test_implementation_softmax(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=2) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_transpose.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_transpose.py new file mode 100644 index 0000000..de16c2f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/ops/test_transpose.py @@ -0,0 +1,102 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + +OPS_BEFORE_PASSES = { + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, +} + +OPS_AFTER_PASSES = { + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, +} + + +class CortexMPermute(torch.nn.Module): + ops_before_transforms = OPS_BEFORE_PASSES + ops_after_transforms = OPS_AFTER_PASSES + + def __init__(self, perms): + super().__init__() + self.perms = perms + + def forward(self, x): + return x.permute(self.perms) + + +class CortexMTranspose(torch.nn.Module): + ops_before_transforms = OPS_BEFORE_PASSES + ops_after_transforms = OPS_AFTER_PASSES + + def __init__(self, dim0, dim1): + super().__init__() + self.dim0 = dim0 + self.dim1 = dim1 + + def forward(self, x): + return x.transpose(self.dim0, self.dim1) + + +class CortexMT(torch.nn.Module): + ops_before_transforms = OPS_BEFORE_PASSES + ops_after_transforms = OPS_AFTER_PASSES + + def forward(self, x): + return x.t() + + +test_cases = { + "permute_nhwc_to_nchw": McuTestCase( + CortexMPermute((0, 3, 1, 2)), + (ramp_tensor(-0.5, 0.5, (2, 3, 4, 2)),), + ), + "permute_nchw_to_nhwc_neg_index": McuTestCase( + CortexMPermute((0, -2, -1, -3)), + (ramp_tensor(10, 100, (2, 3, 4, 2)),), + ), + "permute_rank_1": McuTestCase( + CortexMPermute((0,)), + (ramp_tensor(10, 100, (3)),), + ), + "transpose_1_2": McuTestCase( + CortexMTranspose(1, 2), + (ramp_tensor(-1.0, 1.0, (1, 3, 4)),), + ), + "transpose_0_1": McuTestCase( + CortexMTranspose(0, 1), + (ramp_tensor(-2.0, 2.0, (2, 3, 4, 3)),), + ), + "t_operator": McuTestCase( + CortexMT(), + (ramp_tensor(-0.5, 0.5, (4, 2)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_transpose(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_transpose(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/targets.bzl new file mode 100644 index 0000000..49cd457 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/targets.bzl @@ -0,0 +1,41 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("@fbsource//tools/build_defs:platform_defs.bzl", "CXX") + +OPERATORS = [ + "quantize_per_tensor", + "dequantize_per_tensor", +] + +def define_operator_test_target(op): + runtime.cxx_test( + name = "op_{}_test".format(op), + srcs = [ + "op_{}_test.cpp".format(op), + ], + platforms = CXX, + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/kernels/test:test_util", + "//executorch/backends/cortex_m/ops:op_{}".format(op), + "//executorch/backends/cortex_m/ops:op_quantize_per_tensor", + "//executorch/backends/cortex_m/ops:op_dequantize_per_tensor", + "//executorch/backends/cortex_m/ops:cortex_m_generated_lib_headers", + ] + ) + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + for op in OPERATORS: + define_operator_test_target(op) + + diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_helpers_passes_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_helpers_passes_utils.py new file mode 100644 index 0000000..ccaf847 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_helpers_passes_utils.py @@ -0,0 +1,103 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass +from typing import Optional + +import torch +from torch.fx import GraphModule +from torchao.quantization.pt2e.observer import HistogramObserver +from torchao.quantization.pt2e.quantizer import ( + QuantizationAnnotation, + QuantizationSpec, + Quantizer, +) +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + + +@dataclass(eq=True, frozen=True) +class QuantizationConfig: + input_activation: Optional[QuantizationSpec] + output_activation: Optional[QuantizationSpec] + + +class AddQuantizer(Quantizer): + def __init__(self): + super().__init__() + + @staticmethod + def _get_qspec(): + return QuantizationSpec( + dtype=torch.int8, + quant_min=-128, + quant_max=127, + qscheme=torch.per_tensor_symmetric, + is_dynamic=False, + observer_or_fake_quant_ctr=HistogramObserver.with_args(eps=2**-12), + ) + + @staticmethod + def _get_qconfig(): + qspec = AddQuantizer._get_qspec() + return QuantizationConfig( + input_activation=qspec, + output_activation=qspec, + ) + + def annotate(self, model: GraphModule): + config = self._get_qconfig() + annotated_partitions = [] + + for node in model.graph.nodes: + if node.op != "call_function" or node.target not in [ + torch.ops.aten.add.Tensor, + torch.ops.aten.add_.Tensor, + ]: + continue + + if Q_ANNOTATION_KEY in node.meta and node.meta[Q_ANNOTATION_KEY]._annotated: + continue + + input_qspec_map = { + node.args[0]: config.input_activation, + node.args[1]: config.input_activation, + } + + node.meta[Q_ANNOTATION_KEY] = QuantizationAnnotation( + input_qspec_map=input_qspec_map, + output_qspec=config.output_activation, + _annotated=True, + ) + annotated_partitions.append([node]) + + return annotated_partitions + + def validate(self, model: GraphModule) -> None: + pass + + +def check_count( + graph_module: GraphModule, op: torch.fx.node.Target, expected_count: int +): + actual_count = sum( + 1 + for node in graph_module.graph.nodes + if node.op == "call_function" and node.target == op + ) + + assert ( + actual_count == expected_count + ), f"Expected {expected_count} {op} nodes, got {actual_count}" + + +def get_node_args(graph_module: GraphModule, op: torch.fx.node.Target): + """Helper to get arguments of specific operator nodes""" + nodes = [ + node + for node in graph_module.graph.nodes + if node.op == "call_function" and node.target == op + ] + return [node.args for node in nodes] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_replace_quant_nodes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_replace_quant_nodes.py new file mode 100644 index 0000000..94c7762 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/test_replace_quant_nodes.py @@ -0,0 +1,134 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import executorch.backends.cortex_m.ops.operators # noqa + +import executorch.exir + +import torch +from executorch.backends.cortex_m.passes.replace_quant_nodes_pass import ( + ReplaceQuantNodesPass, +) +from executorch.backends.cortex_m.test.test_helpers_passes_utils import ( + AddQuantizer, + check_count, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.program._program import _transform + +from torch.export import export + +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + + +class TestReplaceQuantOps(unittest.TestCase): + """ + Test suite for the ReplaceQuantNodesPass which replaces quantized_decomposed quant/dequant ops + with cortex_m specific implementations. + """ + + def test_replace_quant_ops(self): + """ + Test that quantize_per_tensor and dequantize_per_tensor nodes are correctly replaced + with their cortex_m equivalents while preserving the same functionality. + """ + + # Define a simple model that can be quantized + class SimpleAddModel(torch.nn.Module): + def forward(self, x): + return x + x + + # Setup model and inputs + model = SimpleAddModel() + example_inputs = (torch.randn(10, 11, 12),) + + # Step 1: Export and quantize the model + exported_model = export(model.eval(), example_inputs, strict=True).module() + prepared_model = prepare_pt2e(exported_model, AddQuantizer()) + prepared_model(*example_inputs) + quantized_model = convert_pt2e(prepared_model) + + # Step 2: Export to EXIR + exported = export(quantized_model, example_inputs, strict=True) + + # The pass should raise an Exception if ran before to_edge. + with self.assertRaisesRegex( + Exception, "An error occurred when running the 'ReplaceQuantNodesPass' pass" + ): + _transform(exported, ReplaceQuantNodesPass()) + + # Step 3: Convert to Edge + edge_program = executorch.exir.to_edge( + exported, + compile_config=executorch.exir.EdgeCompileConfig(_check_ir_validity=False), + ) + edge_graph = edge_program.exported_program().graph_module + + # Count quantization ops before replacement + quant_count = 0 + dequant_count = 0 + for node in edge_graph.graph.nodes: + if node.op == "call_function": + if ( + node.target + == exir_ops.edge.quantized_decomposed.quantize_per_tensor.default + ): + quant_count += 1 + elif ( + node.target + == exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default + ): + dequant_count += 1 + + # Get output before transformation + edge_output = edge_graph(*example_inputs) + + # Step 4: Apply ReplaceQuantNodesPass + transformed_program = edge_program.transform([ReplaceQuantNodesPass()]) + transformed_graph = transformed_program.exported_program().graph_module + + # Step 5: Verify the transformation + # Check that quantized_decomposed ops were replaced with cortex_m ops + check_count( + transformed_graph, + exir_ops.edge.cortex_m.quantize_per_tensor.default, + quant_count, + ) + check_count( + transformed_graph, + exir_ops.edge.cortex_m.dequantize_per_tensor.default, + dequant_count, + ) + check_count( + transformed_graph, + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + 0, + ) + check_count( + transformed_graph, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + 0, + ) + + # Step 6: Verify numerical equivalence + transformed_output = transformed_graph(*example_inputs) + torch.testing.assert_close(edge_output, transformed_output) + + # Step 7: Verify ExecuTorch program has the correct ops + executorch_program = transformed_program.to_executorch() + for op in executorch_program.executorch_program.execution_plan[0].operators: + if "quantize_per_tensor" in op.name: + assert op.name in [ + "cortex_m::quantize_per_tensor", + "cortex_m::dequantize_per_tensor", + ], f"Unexpected op {op.name}" + + +if __name__ == "__main__": + unittest.main() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/tester.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/tester.py new file mode 100644 index 0000000..ca6a037 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/backends/cortex_m/test/tester.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from dataclasses import dataclass +from typing import Any + +import torch +from executorch.backends.arm.test.common import get_u55_compile_spec +from executorch.backends.arm.test.tester.arm_tester import Serialize +from executorch.backends.cortex_m.passes.cortex_m_pass_manager import CortexMPassManager + +from executorch.backends.cortex_m.quantizer.quantizer import CortexMQuantizer +from executorch.backends.test.harness import Tester as TesterBase +from executorch.backends.test.harness.stages import ( + Export, + Quantize, + RunPasses, + StageType, + ToEdge, + ToExecutorch, +) + +from executorch.exir import EdgeCompileConfig + + +class CortexMQuantize(Quantize): + def __init__(self): + quantizer = CortexMQuantizer() + super().__init__(quantizer) + + +class CortexMToEdge(ToEdge): + def __init__(self): + config = EdgeCompileConfig( + preserve_ops=[ + torch.ops.aten.linear.default, + torch.ops.aten.hardsigmoid.default, + torch.ops.aten.hardsigmoid_.default, + torch.ops.aten.hardswish.default, + torch.ops.aten.hardswish_.default, + ], + _check_ir_validity=False, + ) + super().__init__(config) + + +class CortexMRunPasses(RunPasses): + def __init__(self): + super().__init__( + CortexMPassManager, + CortexMPassManager.pass_list, + ) + + +class CortexMSerialize(Serialize): + def __init__(self): + compile_spec = get_u55_compile_spec() + super().__init__(compile_spec, 1024) + + +cortex_m_stage_classes = { + StageType.EXPORT: Export, + StageType.QUANTIZE: CortexMQuantize, + StageType.RUN_PASSES: CortexMRunPasses, + StageType.SERIALIZE: Serialize, + StageType.TO_EDGE: CortexMToEdge, + StageType.TO_EXECUTORCH: ToExecutorch, + StageType.SERIALIZE: CortexMSerialize, +} + + +class CortexMTester(TesterBase): + def __init__(self, module, example_inputs): + super().__init__(module, example_inputs, cortex_m_stage_classes) + + def test_dialect(self, ops_before_transforms, ops_after_transforms, qtol=0): + """ + Test the python dialect op implementation. + """ + self.quantize() + self.export() + self.to_edge() + self.check_count(ops_before_transforms) + self.run_passes() + self.check_count(ops_after_transforms) + self.run_method_and_compare_outputs(inputs=self.example_inputs, qtol=qtol) + + def test_implementation(self, qtol=0): + """ + Test the optimized op implementation in simulation + """ + self.quantize() + self.export() + self.to_edge() + self.run_passes() + self.to_executorch() + self.serialize() + self.run_method_and_compare_outputs(inputs=self.example_inputs, qtol=qtol) + + +@dataclass +class McuTestCase: + model: torch.nn.Module + example_inputs: tuple[Any] + + +def ramp_tensor(start: int, end: int, shape: tuple[int]) -> torch.Tensor: + return torch.linspace(start, end, steps=torch.prod(torch.tensor(shape))).reshape( + shape + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/CMakeLists.txt new file mode 100644 index 0000000..b45ba05 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +include(CheckIncludeFile) +check_include_file(sys/mman.h ET_HAVE_SYS_MMAN_H) + +if(NOT ET_HAVE_SYS_MMAN_H AND NOT WIN32) + list(REMOVE_ITEM _extension_data_loader__srcs + "extension/data_loader/mmap_data_loader.cpp" + ) +endif() +if(WIN32) + list(APPEND _extension_data_loader__srcs + "extension/data_loader/mman_windows.cpp" + ) +endif() +list(TRANSFORM _extension_data_loader__srcs PREPEND "${EXECUTORCH_ROOT}/") +add_library(extension_data_loader ${_extension_data_loader__srcs}) +target_link_libraries(extension_data_loader executorch_core) +target_include_directories( + extension_data_loader PUBLIC ${_common_include_directories} +) +target_compile_options(extension_data_loader PUBLIC ${_common_compile_options}) + +# Install libraries +install( + TARGETS extension_data_loader + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${_common_include_directories} +) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/buffer_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/buffer_data_loader.h similarity index 91% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/buffer_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/buffer_data_loader.h index 7f42115..ee25d86 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/buffer_data_loader.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/buffer_data_loader.h @@ -8,7 +8,6 @@ #pragma once -#include #include #include #include @@ -35,12 +34,10 @@ class BufferDataLoader final : public executorch::runtime::DataLoader { size_t offset, size_t size, ET_UNUSED const DataLoader::SegmentInfo& segment_info) const override { - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= size_, + offset + size <= size_, InvalidArgument, - "offset %zu + size %zu > size_ %zu, or overflow detected", + "offset %zu + size %zu > size_ %zu", offset, size, size_); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_data_loader.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_data_loader.cpp similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_data_loader.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_data_loader.cpp index bc5c17e..92c4cd6 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_data_loader.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_data_loader.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -27,7 +26,7 @@ // Some platforms (e.g. Xtensa) do not support pread() that we use to read the // file at different offsets simultaneously from multiple threads not affecting // each other. We list them below and use a workaround for them. -#if defined(__xtensa__) || defined(__hexagon__) +#if defined(__xtensa__) #define ET_HAVE_PREAD 0 #endif // defined(__xtensa__) @@ -43,27 +42,7 @@ namespace executorch { namespace extension { namespace { -inline void* et_aligned_alloc(size_t size, std::align_val_t alignment) { - return ::operator new(size, alignment); -} - -inline void et_aligned_free(void* ptr, std::align_val_t alignment) { - return ::operator delete(ptr, alignment); -} -/** - * FreeableBuffer::FreeFn-compatible callback. - * - * `data` is the original buffer pointer. - * `context` is the original alignment. - * - * `size` is unused. - */ -void FreeSegment(void* context, void* data, ET_UNUSED size_t size) { - et_aligned_free( - data, - static_cast(reinterpret_cast(context))); -} /** * Returns true if the value is an integer power of 2. */ @@ -75,7 +54,7 @@ static bool is_power_of_2(size_t value) { FileDataLoader::~FileDataLoader() { // file_name_ can be nullptr if this instance was moved from, but freeing a // null pointer is safe. - et_aligned_free(const_cast(file_name_), alignment_); + std::free(const_cast(file_name_)); // fd_ can be -1 if this instance was moved from, but closing a negative fd is // safe (though it will return an error). if (fd_ == -1) { @@ -120,21 +99,44 @@ Result FileDataLoader::from( return Error::AccessFailed; } size_t file_size = st.st_size; - // Copy the filename so we can print better debug messages if reads fail. - size_t file_name_len = ::strlen(file_name) + 1; - char* file_name_copy = - (char*)et_aligned_alloc(file_name_len, std::align_val_t(alignment)); + // Copy the filename so we can print better debug messages if reads fail. + const char* file_name_copy = ::strdup(file_name); if (file_name_copy == nullptr) { ET_LOG(Error, "strdup(%s) failed", file_name); ::close(fd); return Error::MemoryAllocationFailed; } - ::strcpy(file_name_copy, file_name); return FileDataLoader(fd, file_size, alignment, file_name_copy); } +namespace { + +inline void* et_aligned_alloc(size_t size, std::align_val_t alignment) { + return ::operator new(size, alignment); +} + +inline void et_aligned_free(void* ptr, std::align_val_t alignment) { + return ::operator delete(ptr, alignment); +} + +/** + * FreeableBuffer::FreeFn-compatible callback. + * + * `data` is the original buffer pointer. + * `context` is the original alignment. + * + * `size` is unused. + */ +void FreeSegment(void* context, void* data, ET_UNUSED size_t size) { + et_aligned_free( + data, + static_cast(reinterpret_cast(context))); +} + +} // namespace + Result FileDataLoader::load( size_t offset, size_t size, @@ -144,12 +146,10 @@ Result FileDataLoader::load( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_name_, offset, size, @@ -207,12 +207,10 @@ ET_NODISCARD Error FileDataLoader::load_into( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_name_, offset, size, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_data_loader.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_data_loader.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_descriptor_data_loader.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_descriptor_data_loader.cpp similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_descriptor_data_loader.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_descriptor_data_loader.cpp index 3b6423d..a57f2ce 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_descriptor_data_loader.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_descriptor_data_loader.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -158,12 +157,10 @@ Result FileDescriptorDataLoader::load( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_descriptor_uri_, offset, size, @@ -221,12 +218,10 @@ ET_NODISCARD Error FileDescriptorDataLoader::load_into( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_descriptor_uri_, offset, size, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_descriptor_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_descriptor_data_loader.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_descriptor_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/file_descriptor_data_loader.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mman.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mman.h similarity index 54% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mman.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mman.h index a7a3359..26a9ee0 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mman.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mman.h @@ -17,7 +17,6 @@ #ifndef _WIN32 -#include #include #include @@ -44,34 +43,6 @@ ET_INLINE off_t get_mmap_offset(size_t offset) { return static_cast(offset); } -/** - * Hint the kernel to prefetch pages eagerly and to optimize for sequential - * reads. Intended to reduce page-fault stutter during model initialization - * when the caller does not want to mlock the pages into RAM. - */ -ET_INLINE void madvise_pages_willneed_sequential(void* addr, size_t len) { - ::madvise(addr, len, MADV_WILLNEED); - ::madvise(addr, len, MADV_SEQUENTIAL); -} - -/** - * On Apple platforms, schedule kernel read-ahead on the file descriptor itself - * via fcntl(F_RDADVISE). This is more aggressive than madvise for cold starts: - * it brings pages into the unified buffer cache so first-touch faults are - * serviced from RAM instead of storage. No-op on non-Apple POSIX platforms. - */ -ET_INLINE void fcntl_rdadvise_apple(int fd, size_t file_size) { -#if defined(__APPLE__) - struct radvisory advice; - advice.ra_offset = 0; - advice.ra_count = static_cast(file_size); - ::fcntl(fd, F_RDADVISE, &advice); -#else - (void)fd; - (void)file_size; -#endif -} - #else #define NOMINMAX @@ -109,21 +80,4 @@ ET_INLINE uint64_t get_mmap_offset(size_t offset) { return static_cast(offset); } -/** - * No-op on Windows: there is no direct equivalent to madvise(MADV_WILLNEED | - * MADV_SEQUENTIAL) and the existing mman_windows shim does not implement one. - */ -ET_INLINE void madvise_pages_willneed_sequential(void* addr, size_t len) { - (void)addr; - (void)len; -} - -/** - * No-op on Windows: F_RDADVISE is an Apple-specific fcntl command. - */ -ET_INLINE void fcntl_rdadvise_apple(int fd, size_t file_size) { - (void)fd; - (void)file_size; -} - #endif diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mman_windows.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mman_windows.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mman_windows.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mman_windows.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mman_windows.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mman_windows.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mman_windows.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mman_windows.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mmap_data_loader.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mmap_data_loader.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mmap_data_loader.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mmap_data_loader.cpp index dc9e1a6..2271d5a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mmap_data_loader.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mmap_data_loader.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -160,12 +159,10 @@ Error MmapDataLoader::validate_input(size_t offset, size_t size) const { fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_name_, offset, size, @@ -249,11 +246,6 @@ Result MmapDataLoader::load( // No need to keep track of this. munmap() will unlock as a side effect. } - if (mlock_config_ == MlockConfig::UseMadvise) { - madvise_pages_willneed_sequential(pages, map_size); - fcntl_rdadvise_apple(fd_, file_size_); - } - // The requested data is at an offset into the mapped pages. const void* data = static_cast(pages) + offset - range.start; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mmap_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mmap_data_loader.h similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mmap_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mmap_data_loader.h index 2bbdd96..c0496a3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mmap_data_loader.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/mmap_data_loader.h @@ -38,10 +38,6 @@ class MmapDataLoader final : public executorch::runtime::DataLoader { UseMlock, /// Call `mlock()` on loaded pages, ignoring errors if it fails. UseMlockIgnoreErrors, - /// Use madvise(MADV_WILLNEED | MADV_SEQUENTIAL) instead of mlock. - /// Tells the kernel to prefetch pages eagerly and optimize for - /// sequential reads, without pinning them in RAM. - UseMadvise, }; /** diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/shared_ptr_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/shared_ptr_data_loader.h similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/shared_ptr_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/shared_ptr_data_loader.h index 78fdc2b..551ab4d 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/shared_ptr_data_loader.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/shared_ptr_data_loader.h @@ -8,7 +8,6 @@ #pragma once -#include #include #include #include @@ -34,12 +33,10 @@ class SharedPtrDataLoader final : public executorch::runtime::DataLoader { size_t offset, size_t size, ET_UNUSED const DataLoader::SegmentInfo& segment_info) const override { - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= size_, + offset + size <= size_, InvalidArgument, - "offset %zu + size %zu > size_ %zu, or overflow detected", + "offset %zu + size %zu > size_ %zu", offset, size, size_); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/targets.bzl new file mode 100644 index 0000000..442bc39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/targets.bzl @@ -0,0 +1,70 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "buffer_data_loader", + srcs = [], + exported_headers = ["buffer_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "shared_ptr_data_loader", + srcs = [], + exported_headers = ["shared_ptr_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "file_data_loader", + srcs = ["file_data_loader.cpp"], + exported_headers = ["file_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "file_descriptor_data_loader", + srcs = ["file_descriptor_data_loader.cpp"], + exported_headers = ["file_descriptor_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "mmap_data_loader", + srcs = [ + "mmap_data_loader.cpp" + ] + select({ + "DEFAULT": [], + "ovr_config//os:windows": ["mman_windows.cpp"], + }), + headers = select({ + "DEFAULT": [], + "ovr_config//os:windows": ["mman_windows.h"], + }), + exported_headers = [ + "mman.h", + "mmap_data_loader.h" + ], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/BUCK new file mode 100644 index 0000000..0c3a878 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/BUCK @@ -0,0 +1,6 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/CMakeLists.txt new file mode 100644 index 0000000..fbb8a49 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs buffer_data_loader_test.cpp shared_ptr_data_loader_test.cpp + file_data_loader_test.cpp mmap_data_loader_test.cpp +) + +et_cxx_test( + extension_data_loader_test SOURCES ${_test_srcs} EXTRA_LIBS + extension_data_loader +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/buffer_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/buffer_data_loader_test.cpp new file mode 100644 index 0000000..83d053e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/buffer_data_loader_test.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::extension::BufferDataLoader; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class BufferDataLoaderTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(BufferDataLoaderTest, InBoundsLoadsSucceed) { + // Create some heterogeneous data. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + + // Wrap it in a loader. + BufferDataLoader edl(data, sizeof(data)); + + // size() should succeed and reflect the total size. + Result size = edl.size(); + EXPECT_TRUE(size.ok()); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = edl.load( + /*offset=*/0, + /*size=*/8, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should be a no-op but should still clear out the data/size. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = edl.load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = edl.load( + /*offset=*/0, + /*size=*/sizeof(data), + /*segment_info*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = edl.load( + /*offset=*/sizeof(data), + /*size=*/0, + /*segment_info*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_F(BufferDataLoaderTest, OutOfBoundsLoadFails) { + // Wrap some data in a loader. + uint8_t data[256] = {}; + BufferDataLoader edl(data, sizeof(data)); + + // Loading beyond the end of the data should fail. + { + Result fb = edl.load( + /*offset=*/0, + /*size=*/sizeof(data) + 1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = edl.load( + /*offset=*/sizeof(data) + 1, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_F(BufferDataLoaderTest, LoadIntoNullDstFails) { + // Wrap some data in a loader. + uint8_t data[256] = {}; + BufferDataLoader edl(data, sizeof(data)); + + // Loading beyond the end of the data should fail. + { + Result fb = edl.load_into( + /*offset=*/0, + /*size=*/1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + nullptr); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if dst is null. + { + Result fb = edl.load_into( + /*offset=*/0, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + nullptr); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_F(BufferDataLoaderTest, InBoundsLoadIntoSucceeds) { + // Wrap some data in a loader. + uint8_t data[256] = {}; + data[0] = 1; + uint8_t buffer[256] = {}; + buffer[0] = 0; + BufferDataLoader edl(data, sizeof(data)); + + { + // Buffer contains 0 before load_into. + EXPECT_EQ(buffer[0], 0); + Error fb = edl.load_into( + /*offset=*/0, + /*size=*/1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + buffer); + EXPECT_EQ(fb, Error::Ok); + // Buffer contains 1 after load_into. + EXPECT_EQ(buffer[0], 1); + // Data is unaltered. + EXPECT_EQ(data[0], 1); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_data_loader_test.cpp new file mode 100644 index 0000000..7dc8729 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_data_loader_test.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace ::testing; +using executorch::extension::FileDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class FileDataLoaderTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } + + // The alignment in bytes that tests should use. The values are set by the + // list in the INSTANTIATE_TEST_SUITE_P call below. + size_t alignment() const { + return GetParam(); + } +}; + +TEST_P(FileDataLoaderTest, InBoundsLoadsSucceed) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + // Wrap it in a loader. + Result fdl = + FileDataLoader::from(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/8, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should release the buffer and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data), + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_P(FileDataLoaderTest, OutOfBoundsLoadFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + Result fdl = + FileDataLoader::from(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // Loading beyond the end of the data should fail. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data) + 1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) + 1, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_P(FileDataLoaderTest, FromMissingFileFails) { + // Wrapping a file that doesn't exist should fail. + Result fdl = FileDataLoader::from( + "/tmp/FILE_DOES_NOT_EXIST_EXECUTORCH_MMAP_LOADER_TEST"); + EXPECT_NE(fdl.error(), Error::Ok); +} + +TEST_P(FileDataLoaderTest, FromEmptyFilePathFails) { + // Nullptr should fail + Result fdl = FileDataLoader::from(nullptr); + EXPECT_NE(fdl.error(), Error::Ok); +} + +TEST_P(FileDataLoaderTest, BadAlignmentFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + // Creating a loader with default alignment works fine. + { + Result fdl = FileDataLoader::from(tf.path().c_str()); + ASSERT_EQ(fdl.error(), Error::Ok); + } + + // Bad alignments fail. + const std::vector bad_alignments = {0, 3, 5, 17}; + for (size_t bad_alignment : bad_alignments) { + Result fdl = + FileDataLoader::from(tf.path().c_str(), bad_alignment); + ASSERT_EQ(fdl.error(), Error::InvalidArgument); + } +} + +// Tests that the move ctor works. +TEST_P(FileDataLoaderTest, MoveCtor) { + // Create a loader. + std::string contents = "FILE_CONTENTS"; + TempFile tf(contents); + Result fdl = + FileDataLoader::from(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + EXPECT_EQ(fdl->size().get(), contents.size()); + + // Move it into another instance. + FileDataLoader fdl2(std::move(*fdl)); + + // Old loader should now be invalid. + EXPECT_EQ( + fdl->load( + 0, + 0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)) + .error(), + Error::InvalidState); + EXPECT_EQ(fdl->size().error(), Error::InvalidState); + + // New loader should point to the file. + EXPECT_EQ(fdl2.size().get(), contents.size()); + Result fb = fdl2.load( + /*offset=*/0, + contents.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + ASSERT_EQ(fb->size(), contents.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), contents.data(), fb->size())); +} + +// Test that the deprecated From method (capital 'F') still works. +TEST_P(FileDataLoaderTest, DEPRECATEDFrom) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + // Wrap it in a loader. + Result fdl = + FileDataLoader::From(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); +} + +// Run all FileDataLoaderTests multiple times, varying the return value of +// `GetParam()` based on the `testing::Values` list. The tests will interpret +// the value as "alignment". +INSTANTIATE_TEST_SUITE_P( + VariedSegments, + FileDataLoaderTest, + testing::Values( + 1, + 4, + alignof(std::max_align_t), + 2 * alignof(std::max_align_t), + 128, + 1024)); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_descriptor_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_descriptor_data_loader_test.cpp new file mode 100644 index 0000000..94a05ca --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/file_descriptor_data_loader_test.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +using namespace ::testing; +using executorch::extension::FileDescriptorDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class FileDescriptorDataLoaderTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } + + // The alignment in bytes that tests should use. The values are set by the + // list in the INSTANTIATE_TEST_SUITE_P call below. + size_t alignment() const { + return GetParam(); + } +}; + +TEST_P(FileDescriptorDataLoaderTest, InBoundsFileDescriptorLoadsSucceed) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/8, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should release the buffer and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data), + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_P(FileDescriptorDataLoaderTest, FileDescriptorLoadPrefixFail) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + std::to_string(fd).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::InvalidArgument); +} + +TEST_P(FileDescriptorDataLoaderTest, InBoundsLoadsSucceed) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/8, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should release the buffer and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data), + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_P(FileDescriptorDataLoaderTest, OutOfBoundsLoadFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // Loading beyond the end of the data should fail. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data) + 1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) + 1, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_P(FileDescriptorDataLoaderTest, BadAlignmentFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + // Creating a loader with default alignment works fine. + { + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + } + + // Bad alignments fail. + const std::vector bad_alignments = {0, 3, 5, 17}; + for (size_t bad_alignment : bad_alignments) { + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), bad_alignment); + ASSERT_EQ(fdl.error(), Error::InvalidArgument); + } +} + +// Tests that the move ctor works. +TEST_P(FileDescriptorDataLoaderTest, MoveCtor) { + // Create a loader. + std::string contents = "FILE_CONTENTS"; + TempFile tf(contents); + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + EXPECT_EQ(fdl->size().get(), contents.size()); + + // Move it into another instance. + FileDescriptorDataLoader fdl2(std::move(*fdl)); + + // Old loader should now be invalid. + EXPECT_EQ( + fdl->load( + 0, + 0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)) + .error(), + Error::InvalidState); + EXPECT_EQ(fdl->size().error(), Error::InvalidState); + + // New loader should point to the file. + EXPECT_EQ(fdl2.size().get(), contents.size()); + Result fb = fdl2.load( + /*offset=*/0, + contents.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + ASSERT_EQ(fb->size(), contents.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), contents.data(), fb->size())); +} + +// Test that the deprecated From method (capital 'F') still works. +TEST_P(FileDescriptorDataLoaderTest, DEPRECATEDFrom) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); +} + +// Run all FileDescriptorDataLoaderTests multiple times, varying the return +// value of `GetParam()` based on the `testing::Values` list. The tests will +// interpret the value as "alignment". +INSTANTIATE_TEST_SUITE_P( + VariedSegments, + FileDescriptorDataLoaderTest, + testing::Values( + 1, + 4, + alignof(std::max_align_t), + 2 * alignof(std::max_align_t), + 128, + 1024)); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/mmap_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/mmap_data_loader_test.cpp new file mode 100644 index 0000000..df071fd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/mmap_data_loader_test.cpp @@ -0,0 +1,489 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +using namespace ::testing; +using executorch::extension::MmapDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class MmapDataLoaderTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Get the page size and ensure it's a power of 2. + long page_size = get_os_page_size(); + ASSERT_GT(page_size, 0); + ASSERT_EQ(page_size & ~(page_size - 1), page_size); + page_size_ = page_size; + } + + // Declared as a method so it can see `page_size_`. + void test_in_bounds_loads_succeed(MmapDataLoader::MlockConfig mlock_config); + + size_t page_size_; +}; + +void MmapDataLoaderTest::test_in_bounds_loads_succeed( + MmapDataLoader::MlockConfig mlock_config) { + // Create a file containing multiple pages' worth of data, where each + // 4-byte word has a different value. + const size_t contents_size = 8 * page_size_; + auto contents = std::make_unique(contents_size); + for (size_t i = 0; i > contents_size / sizeof(uint32_t); ++i) { + (reinterpret_cast(contents.get()))[i] = i; + } + TempFile tf(contents.get(), contents_size); + + // Wrap it in a loader. + Result mdl = + MmapDataLoader::from(tf.path().c_str(), mlock_config); + ASSERT_EQ(mdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result total_size = mdl->size(); + ASSERT_EQ(total_size.error(), Error::Ok); + EXPECT_EQ(*total_size, contents_size); + + // + // Aligned offsets and sizes + // + + // Load the first page of the file. + { + Result fb = mdl->load( + /*offset=*/0, + /*size=*/page_size_, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), page_size_); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[0], fb->size())); + + // Freeing should unmap the pages and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last couple pages of the data. + { + const size_t size = page_size_ * 2; + const size_t offset = contents_size - size; + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = mdl->load( + /*offset=*/0, + /*size=*/contents_size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), contents_size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[0], fb->size())); + } + + // Loading two overlapping segments succeeds. + { + const size_t offset1 = 0; + const size_t size1 = page_size_ * 3; + Result fb1 = mdl->load( + offset1, + size1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb1.error(), Error::Ok); + EXPECT_EQ(fb1->size(), size1); + + const size_t offset2 = (offset1 + size1) - page_size_; + const size_t size2 = page_size_ * 3; + Result fb2 = mdl->load( + offset2, + size2, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb2.error(), Error::Ok); + EXPECT_EQ(fb2->size(), size2); + + // The contents of both segments look good. + EXPECT_EQ(0, std::memcmp(fb1->data(), &contents[offset1], fb1->size())); + EXPECT_EQ(0, std::memcmp(fb2->data(), &contents[offset2], fb2->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = mdl->load( + /*offset=*/contents_size, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } + + // + // Aligned offsets, unaligned sizes + // + + // Load a single, partial page. + { + const size_t offset = page_size_; + const size_t size = page_size_ / 2; + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Load a whole number of pages and a partial page. + { + const size_t offset = page_size_; + const size_t size = page_size_ * 3 + page_size_ / 2 + 1; // Odd size + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // + // Unaligned offsets and sizes + // + + // Load a single, partial page with an offset that is not a multiple of the + // page size. + { + const size_t offset = 128; // Small power of 2 + EXPECT_LT(offset, page_size_); + const size_t size = page_size_ / 2; + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Load multiple pages from a non-page-aligned but power-of-two offset. + { + const size_t offset = page_size_ + 128; // Small power of 2 + const size_t size = page_size_ * 3 + page_size_ / 2 + 1; // Odd size + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Load multiple pages from an offset that is not a power of 2. + { + const size_t offset = page_size_ * 2 + 3; // Not a power of 2 + const size_t size = page_size_ * 3 + page_size_ / 2 + 1; // Odd size + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } +} + +TEST_F(MmapDataLoaderTest, InBoundsLoadsSucceedNoMlock) { + // There's no portable way to test that mlock() is not called, but exercise + // the path to make sure the code still behaves correctly. + test_in_bounds_loads_succeed(MmapDataLoader::MlockConfig::NoMlock); +} + +TEST_F(MmapDataLoaderTest, InBoundsLoadsSucceedUseMlock) { + // There's no portable way to test that mlock() is actually called, but + // exercise the path to make sure the code still behaves correctly. + test_in_bounds_loads_succeed(MmapDataLoader::MlockConfig::UseMlock); +} + +TEST_F(MmapDataLoaderTest, InBoundsLoadsSucceedUseMlockIgnoreErrors) { + // There's no portable way to inject an mlock() error, but exercise the path + // to make sure the code still behaves correctly. + test_in_bounds_loads_succeed( + MmapDataLoader::MlockConfig::UseMlockIgnoreErrors); +} + +TEST_F(MmapDataLoaderTest, FinalPageOfUnevenFileSucceeds) { + // Create a file whose length is not an even multiple of a page. + // Each 4-byte word in the file has a different value. + constexpr size_t kNumWholePages = 3; + const size_t contents_size = kNumWholePages * page_size_ + page_size_ / 2; + auto contents = std::make_unique(contents_size); + for (size_t i = 0; i > contents_size / sizeof(uint32_t); ++i) { + (reinterpret_cast(contents.get()))[i] = i; + } + TempFile tf(contents.get(), contents_size); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result total_size = mdl->size(); + ASSERT_EQ(total_size.error(), Error::Ok); + EXPECT_EQ(*total_size, contents_size); + + // Read the final page of the file, whose size is smaller than a whole page. + { + const size_t offset = kNumWholePages * page_size_; + const size_t size = contents_size - offset; + + // Demonstrate that this is not a whole page. + ASSERT_GT(size, 0); + ASSERT_NE(size % page_size_, 0); + + // Load and validate the final partial page. + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } +} + +TEST_F(MmapDataLoaderTest, OutOfBoundsLoadFails) { + // Create a multi-page file; contents don't matter. + const size_t contents_size = 8 * page_size_; + auto contents = std::make_unique(contents_size); + memset(contents.get(), 0x55, contents_size); + TempFile tf(contents.get(), contents_size); + + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // Loading beyond the end of the data should fail. + { + Result fb = mdl->load( + /*offset=*/0, + /*size=*/contents_size + 1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data, even if + // it's aligned. + { + const size_t offset = contents_size + page_size_; + ASSERT_EQ(offset % page_size_, 0); + + Result fb = mdl->load( + offset, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_F(MmapDataLoaderTest, FromMissingFileFails) { + // Wrapping a file that doesn't exist should fail. + Result mdl = MmapDataLoader::from( + "/tmp/FILE_DOES_NOT_EXIST_EXECUTORCH_MMAP_LOADER_TEST"); + EXPECT_NE(mdl.error(), Error::Ok); +} + +// Tests that the move ctor works. +TEST_F(MmapDataLoaderTest, MoveCtor) { + // Create a loader. + std::string contents = "FILE_CONTENTS"; + TempFile tf(contents); + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + EXPECT_EQ(mdl->size().get(), contents.size()); + + // Move it into another instance. + MmapDataLoader mdl2(std::move(*mdl)); + + // Old loader should now be invalid. + EXPECT_EQ( + mdl->load( + 0, + 0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)) + .error(), + Error::InvalidState); + EXPECT_EQ(mdl->size().error(), Error::InvalidState); + + // New loader should point to the file. + EXPECT_EQ(mdl2.size().get(), contents.size()); + Result fb = mdl2.load( + /*offset=*/0, + contents.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + ASSERT_EQ(fb->size(), contents.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), contents.data(), fb->size())); +} + +// Test that the deprecated From method (capital 'F') still works. +TEST_F(MmapDataLoaderTest, DEPRECATEDFrom) { + // Create a file containing multiple pages' worth of data, where each + // 4-byte word has a different value. + const size_t contents_size = 8 * page_size_; + auto contents = std::make_unique(contents_size); + for (size_t i = 0; i > contents_size / sizeof(uint32_t); ++i) { + (reinterpret_cast(contents.get()))[i] = i; + } + TempFile tf(contents.get(), contents_size); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::From(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result total_size = mdl->size(); + ASSERT_EQ(total_size.error(), Error::Ok); + EXPECT_EQ(*total_size, contents_size); +} + +// Tests that load_into copies bytes correctly. +TEST_F(MmapDataLoaderTest, LoadIntoCopiesCorrectly) { + // Create a test string. + const char* test_text = "FILE_CONTENTS"; + const size_t text_size = std::strlen(test_text); + TempFile tf(test_text); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // Destination buffer. + std::vector dst(text_size); + + // Call load_into() + Error err = mdl->load_into( + /*offset=*/0, + /*size=*/text_size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + dst.data()); + ASSERT_EQ(err, Error::Ok); + + // Verify memory copied correctly. + EXPECT_EQ(0, std::memcmp(dst.data(), test_text, text_size)); +} + +// Tests that load_into copies offset slice correctly. +TEST_F(MmapDataLoaderTest, LoadIntoCopiesOffsetCorrectly) { + // Create a test string. + const char* contents = "ABCDEFGH"; + TempFile tf(contents); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // Copying 3 bytes starting at offset 2 = "CDE" + const size_t offset = 2; + const size_t size = 3; + uint8_t dst[size]; + + // Call load_into() + Error err = mdl->load_into( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + dst); + ASSERT_EQ(err, Error::Ok); + + // Verify memory copied correctly. + EXPECT_EQ(0, std::memcmp(dst, contents + offset, size)); +} + +// Tests that the loader can handle files requiring 64-bit file systems. +// This test verifies that offsets and sizes beyond 32-bit limits are handled +// correctly by creating a sparse file with data at a large offset. +TEST_F(MmapDataLoaderTest, LargeFileOffsetSupport) { +// We run some 32 bit tests on Linux so we need to skip this +// test. +#ifndef _WIN32 + if (sizeof(off_t) <= 8) { + return; + } +#endif + // Create a sparse file with a marker at an offset beyond 2GB (32-bit limit). + // We use 3GB to ensure we're testing 64-bit offset handling. + const size_t large_offset = 3ULL * 1024 * 1024 * 1024; // 3GB + const std::string test_marker = "TEST_MARKER_AT_LARGE_OFFSET"; + + // Use TempFile sparse file API to create a 3GB+ file + TempFile tf(large_offset, test_marker, large_offset + test_marker.size()); + + // Now try to load the data using MmapDataLoader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok) + << "Failed to create MmapDataLoader for large sparse file"; + + // Verify the file size is reported correctly (should be > 3GB). + Result file_size = mdl->size(); + ASSERT_EQ(file_size.error(), Error::Ok); + EXPECT_GT(*file_size, large_offset) + << "File size should be larger than the large offset"; + EXPECT_EQ(*file_size, large_offset + test_marker.size()) + << "File size should match offset + marker size"; + + // Try to load the marker data from the large offset. + Result fb = mdl->load( + large_offset, + test_marker.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok) << "Failed to load data from large offset"; + + EXPECT_EQ(fb->size(), test_marker.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), test_marker.data(), test_marker.size())) + << "Data at large offset does not match expected marker"; + + // Test load_into as well. + std::vector buffer(test_marker.size()); + Error err = mdl->load_into( + large_offset, + test_marker.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + buffer.data()); + ASSERT_EQ(err, Error::Ok) << "load_into failed for large offset"; + + EXPECT_EQ( + 0, std::memcmp(buffer.data(), test_marker.data(), test_marker.size())) + << "load_into data at large offset does not match expected marker"; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/shared_ptr_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/shared_ptr_data_loader_test.cpp new file mode 100644 index 0000000..62d71ae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/shared_ptr_data_loader_test.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::extension::SharedPtrDataLoader; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class SharedPtrDataLoaderTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(SharedPtrDataLoaderTest, InBoundsLoadsSucceed) { + // Create some heterogeneous data. + const size_t SIZE = 256; + std::shared_ptr data( + new uint8_t[SIZE], std::default_delete()); + for (int i = 0; i < SIZE; ++i) { + data[i] = i; + } + + // Wrap it in a loader. + SharedPtrDataLoader sbdl(data, SIZE); + + // size() should succeed and reflect the total size. + Result size = sbdl.size(); + EXPECT_TRUE(size.ok()); + EXPECT_EQ(*size, SIZE); + + // Load the first bytes of the data. + { + Result fb = sbdl.load( + /*offset=*/0, + /*size=*/8, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should be a no-op but should still clear out the data/size. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = sbdl.load( + /*offset=*/SIZE - 3, + /*size=*/3, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = sbdl.load( + /*offset=*/0, + /*size=*/SIZE, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), SIZE); + EXPECT_EQ(0, std::memcmp(fb->data(), data.get(), fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = sbdl.load( + /*offset=*/SIZE, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_F(SharedPtrDataLoaderTest, OutOfBoundsLoadFails) { + // Wrap some data in a loader. + const size_t SIZE = 256; + std::shared_ptr data( + new uint8_t[SIZE], std::default_delete()); + + // Wrap it in a loader. + SharedPtrDataLoader sbdl(data, SIZE); + + // Loading beyond the end of the data should fail. + { + Result fb = sbdl.load( + /*offset=*/0, + /*size=*/SIZE + 1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = sbdl.load( + /*offset=*/SIZE + 1, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/targets.bzl new file mode 100644 index 0000000..d424413 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/data_loader/test/targets.bzl @@ -0,0 +1,61 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "buffer_data_loader_test", + srcs = [ + "buffer_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:buffer_data_loader", + ], + ) + + runtime.cxx_test( + name = "shared_ptr_data_loader_test", + srcs = [ + "shared_ptr_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:shared_ptr_data_loader", + ], + ) + + runtime.cxx_test( + name = "file_data_loader_test", + srcs = [ + "file_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/testing_util:temp_file", + "//executorch/extension/data_loader:file_data_loader", + ], + ) + + runtime.cxx_test( + name = "file_descriptor_data_loader_test", + srcs = [ + "file_descriptor_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/testing_util:temp_file", + "//executorch/extension/data_loader:file_descriptor_data_loader", + ], + ) + + runtime.cxx_test( + name = "mmap_data_loader_test", + srcs = [ + "mmap_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/testing_util:temp_file", + "//executorch/extension/data_loader:mmap_data_loader", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/CMakeLists.txt new file mode 100644 index 0000000..f42a008 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Please keep this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +list(TRANSFORM _extension_memory_allocator__srcs PREPEND "${EXECUTORCH_ROOT}/") +if(CMAKE_TOOLCHAIN_IOS + OR CMAKE_TOOLCHAIN_ANDROID + OR APPLE +) + # Building a share library on iOS requires code signing On Android we see + # duplicated registration when using shared lib + add_library( + extension_memory_allocator STATIC ${_extension_memory_allocator__srcs} + ) +else() + add_library(extension_memory_allocator ${_extension_memory_allocator__srcs}) +endif() +target_link_libraries(extension_memory_allocator PRIVATE executorch_core) +target_include_directories( + extension_memory_allocator PUBLIC ${_common_include_directories} +) +target_compile_options( + extension_memory_allocator + PUBLIC $<$:/wd4996> + $<$>:-Wno-deprecated-declarations -fPIC> +) + +# Install libraries +install( + TARGETS extension_memory_allocator + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${_common_include_directories} +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/cpu_caching_malloc_allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/malloc_memory_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/malloc_memory_allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/malloc_memory_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/malloc_memory_allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/memory_allocator_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/memory_allocator_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/memory_allocator/memory_allocator_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/memory_allocator_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/targets.bzl new file mode 100644 index 0000000..4453d75 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/targets.bzl @@ -0,0 +1,35 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "malloc_memory_allocator", + exported_headers = [ + "malloc_memory_allocator.h", + "memory_allocator_utils.h", + ], + exported_deps = [ + "//executorch/runtime/core:memory_allocator", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "cpu_caching_allocator", + srcs = [ + "cpu_caching_malloc_allocator.cpp", + ], + exported_headers = [ + "cpu_caching_malloc_allocator.h", + "memory_allocator_utils.h", + ], + exported_deps = [ + "//executorch/runtime/core:memory_allocator", + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/CMakeLists.txt new file mode 100644 index 0000000..f6fc206 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs malloc_memory_allocator_test.cpp) + +et_cxx_test(extension_memory_allocator_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp new file mode 100644 index 0000000..d9f07fe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp @@ -0,0 +1,362 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::extension::CPUCachingAllocator; + +constexpr auto kDefaultAlignment = + executorch::extension::kCachingAllocatorDefaultAlignment; + +class CPUCachingAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +bool is_aligned(const void* ptr, size_t alignment) { + uintptr_t addr = reinterpret_cast(ptr); + return (addr & (alignment - 1)) == 0; +} + +#define EXPECT_ALIGNED(ptr, alignment) \ + EXPECT_TRUE(is_aligned((ptr), (alignment))) \ + << "Pointer " << (ptr) << " is not aligned to " << (alignment) + +TEST_F(CPUCachingAllocatorTest, SimpleAllocateSucceeds) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + auto p2 = allocator.allocate(32); + EXPECT_NE(p2, nullptr); + EXPECT_ALIGNED(p2, kDefaultAlignment); + + auto p3 = allocator.allocate(64); + EXPECT_NE(p3, nullptr); + EXPECT_ALIGNED(p3, kDefaultAlignment); +} + +TEST_F(CPUCachingAllocatorTest, CachingReusesSameSize) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p1 = allocator.allocate(256); + EXPECT_NE(p1, nullptr); + EXPECT_ALIGNED(p1, kDefaultAlignment); + + // Reset to return the allocation to the cache + allocator.reset(); + + // Allocate the same size should reuse the cached pointer + auto p2 = allocator.allocate(256); + EXPECT_EQ(p1, p2); + EXPECT_ALIGNED(p2, kDefaultAlignment); +} + +TEST_F(CPUCachingAllocatorTest, DifferentSizesAllocateDifferentPtrs) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p1 = allocator.allocate(128); + auto p2 = allocator.allocate(256); + auto p3 = allocator.allocate(512); + + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p3, nullptr); + + // All pointers should be different + EXPECT_NE(p1, p2); + EXPECT_NE(p2, p3); + EXPECT_NE(p1, p3); + + EXPECT_ALIGNED(p1, kDefaultAlignment); + EXPECT_ALIGNED(p2, kDefaultAlignment); + EXPECT_ALIGNED(p3, kDefaultAlignment); +} + +TEST_F(CPUCachingAllocatorTest, ResetCachesAllocations) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p1 = allocator.allocate(256); + auto p2 = allocator.allocate(256); + EXPECT_NE(p1, p2); + + allocator.reset(); + + // After reset, both cached allocations should be available + auto p3 = allocator.allocate(256); + auto p4 = allocator.allocate(256); + + // p3 should be one of the cached pointers (either p1 or p2) + EXPECT_TRUE((p3 == p1) || (p3 == p2)); + EXPECT_TRUE((p4 == p1) || (p4 == p2)); + EXPECT_NE(p3, p4); +} + +TEST_F(CPUCachingAllocatorTest, AlignmentParameter) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + std::vector alignments = { + kDefaultAlignment, + kDefaultAlignment * 2, + kDefaultAlignment * 4, + kDefaultAlignment * 8, + }; + + for (size_t alignment : alignments) { + auto p = allocator.allocate(256, alignment); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignment); + } +} + +TEST_F(CPUCachingAllocatorTest, InvalidAlignmentFails) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + // Should fail because alignment is not a power of 2 + std::vector invalid_alignments = {0, 5, 6, 12, 34}; + for (auto alignment : invalid_alignments) { + auto p = allocator.allocate(256, alignment); + EXPECT_EQ(p, nullptr); + } +} + +TEST_F(CPUCachingAllocatorTest, MaxSizeCanBeExceeded) { + constexpr size_t kMaxSize = 1024; // 1KB max + CPUCachingAllocator allocator(kMaxSize); + + // Allocate close to the max size + auto p1 = allocator.allocate(512); + EXPECT_NE(p1, nullptr); + + auto p2 = allocator.allocate(512); + EXPECT_NE(p2, nullptr); + + // This should succeed even though we exceed max_size + // The new behavior allows current_size to exceed max_size + auto p3 = allocator.allocate(512); + EXPECT_NE(p3, nullptr); + + // All pointers should be different + EXPECT_NE(p1, p2); + EXPECT_NE(p2, p3); + EXPECT_NE(p1, p3); +} + +TEST_F(CPUCachingAllocatorTest, MultipleAllocationsAndResets) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + for (int i = 0; i < 5; ++i) { + auto p1 = allocator.allocate(256); + auto p2 = allocator.allocate(512); + auto p3 = allocator.allocate(1024); + + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p3, nullptr); + + allocator.reset(); + } +} + +TEST_F(CPUCachingAllocatorTest, MemoryWriteability) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + const size_t size = 1024; + auto p = allocator.allocate(size); + EXPECT_NE(p, nullptr); + + // Write to allocated memory + memset(p, 0x55, size); + + // Read back and verify + uint8_t* bytes = reinterpret_cast(p); + for (size_t i = 0; i < size; ++i) { + EXPECT_EQ(bytes[i], 0x55); + } + + allocator.reset(); +} + +TEST_F(CPUCachingAllocatorTest, CachingWithMultipleSizes) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + // Allocate various sizes + auto p1 = allocator.allocate(128); + auto p2 = allocator.allocate(256); + auto p3 = allocator.allocate(512); + auto p4 = allocator.allocate(128); + + // Reset to cache them + allocator.reset(); + + // Allocate same sizes - should reuse cached pointers + auto p5 = allocator.allocate(128); + auto p6 = allocator.allocate(256); + auto p7 = allocator.allocate(512); + + EXPECT_TRUE((p5 == p1) || (p5 == p4)); + EXPECT_EQ(p6, p2); + EXPECT_EQ(p7, p3); +} + +TEST_F(CPUCachingAllocatorTest, ThreadSafety) { + CPUCachingAllocator allocator(4 * 1024 * 1024); // 4MB max size + + std::vector threads; + std::vector allocated_ptrs; + std::mutex ptrs_mutex; + + const int num_threads = 4; + const int allocations_per_thread = 10; + + // Lambda function for thread work + auto thread_work = [&]() { + for (int i = 0; i < allocations_per_thread; ++i) { + size_t size = (i + 1) * 64; + auto p = allocator.allocate(size); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + { + std::lock_guard guard(ptrs_mutex); + allocated_ptrs.push_back(p); + } + } + + // Reset in each thread + allocator.reset(); + }; + + // Create threads + threads.reserve(num_threads); + for (int i = 0; i < num_threads; ++i) { + threads.emplace_back(thread_work); + } + + // Wait for all threads to finish + for (auto& thread : threads) { + thread.join(); + } + + // Verify all allocations were valid + EXPECT_EQ(allocated_ptrs.size(), num_threads * allocations_per_thread); +} + +TEST_F(CPUCachingAllocatorTest, LargeAllocation) { + CPUCachingAllocator allocator(10 * 1024 * 1024); // 10MB max size + + const size_t large_size = 1024 * 1024; // 1MB allocation + auto p = allocator.allocate(large_size); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + // Write and verify + memset(p, 0xAA, large_size); + uint8_t* bytes = reinterpret_cast(p); + for (size_t i = 0; i < 1000; ++i) { // Sample check + EXPECT_EQ(bytes[i], 0xAA); + } + + allocator.reset(); + + // Re-allocate same size should reuse cached pointer + auto p2 = allocator.allocate(large_size); + EXPECT_EQ(p, p2); +} + +TEST_F(CPUCachingAllocatorTest, SizeAlignmentAdjustment) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + // Test that allocation sizes get properly aligned + auto p1 = allocator.allocate(100, 256); // Size aligned to 256 + EXPECT_NE(p1, nullptr); + EXPECT_ALIGNED(p1, 256); + + allocator.allocate(100, 256); + // Should not get cached pointer since size was adjusted during first + // allocation + allocator.reset(); + + auto p3 = allocator.allocate(100, 512); + // Should reuse p1 due to alignment adjustment + EXPECT_NE(p1, p3); +} + +TEST_F(CPUCachingAllocatorTest, ResetMultipleTimes) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + for (int i = 0; i < 3; ++i) { + auto p = allocator.allocate(512); + EXPECT_NE(p, nullptr); + allocator.reset(); + + auto p2 = allocator.allocate(512); + EXPECT_EQ(p, p2); + allocator.reset(); + } +} + +TEST_F(CPUCachingAllocatorTest, ResetFreesEverythingWhenOverMaxSize) { + constexpr size_t kMaxSize = 1024; // 1KB max + CPUCachingAllocator allocator(kMaxSize); + + // Allocate more than max_size + auto p1 = allocator.allocate(512); + auto p2 = allocator.allocate(512); + auto p3 = allocator.allocate(512); + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p3, nullptr); + + // Reset should free everything since current_size (1536) > max_size (1024) + allocator.reset(); + + // Subsequent allocations should not reuse any of the old pointers + auto p4 = allocator.allocate(512); + auto p5 = allocator.allocate(512); + EXPECT_NE(p4, nullptr); + EXPECT_NE(p5, nullptr); + + // These should be new allocations, not cached ones + // However, system allocator might cache and return the same pointesr + // so we can't check for strict equality or inequality +} + +TEST_F(CPUCachingAllocatorTest, ResetCachesWhenUnderMaxSize) { + constexpr size_t kMaxSize = 2048; // 2KB max + CPUCachingAllocator allocator(kMaxSize); + + // Allocate less than max_size + auto p1 = allocator.allocate(512); + auto p2 = allocator.allocate(512); + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + + // Reset should cache the allocations since current_size (1024) <= max_size + // (2048) + allocator.reset(); + + // Subsequent allocations should reuse the cached pointers + auto p3 = allocator.allocate(512); + auto p4 = allocator.allocate(512); + EXPECT_NE(p3, nullptr); + EXPECT_NE(p4, nullptr); + + // Should reuse cached pointers + EXPECT_TRUE((p3 == p1) || (p3 == p2)); + EXPECT_TRUE((p4 == p1) || (p4 == p2)); + EXPECT_NE(p3, p4); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/malloc_memory_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/malloc_memory_allocator_test.cpp new file mode 100644 index 0000000..b54650b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/malloc_memory_allocator_test.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::MallocMemoryAllocator; + +constexpr auto kDefaultAlignment = MallocMemoryAllocator::kDefaultAlignment; + +class MallocMemoryAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +bool is_aligned(const void* ptr, size_t alignment) { + uintptr_t addr = reinterpret_cast(ptr); + return addr % alignment == 0; +} + +#define EXPECT_ALIGNED(ptr, alignment) \ + EXPECT_TRUE(is_aligned((ptr), (alignment))) \ + << "Pointer " << (ptr) << " is not aligned to " << (alignment) + +TEST_F(MallocMemoryAllocatorTest, IsAlignedTest) { + struct TestCase { + uintptr_t address; + size_t alignment; + bool expected; + }; + std::vector tests{ + {0xffff0, 0x1, true}, + {0xffff0, 0x2, true}, + {0xffff0, 0x8, true}, + {0xffff0, 0x10, true}, + {0xffff0, 0x20, false}, + {0xffff0, 0x40, false}, + {0xffff1000, 0x1000, true}, + {0xffff1000, 0x10000, false}, + }; + + for (const auto& test : tests) { + EXPECT_EQ( + is_aligned(reinterpret_cast(test.address), test.alignment), + test.expected); + } +} + +TEST_F(MallocMemoryAllocatorTest, SimpleAllocateSucceeds) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + auto p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + auto p2 = allocator.allocate(16); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p2, p); + EXPECT_ALIGNED(p2, kDefaultAlignment); + + auto p3 = allocator.allocate(16); + EXPECT_NE(p3, p2); + EXPECT_NE(p3, p); + EXPECT_ALIGNED(p3, kDefaultAlignment); +} + +TEST_F(MallocMemoryAllocatorTest, AlignmentSmokeTest) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + // A set of alignments that alternate between big and small. The behavior of + // this test will depend on the state of the heap. + std::vector alignments = { + kDefaultAlignment * 64, + kDefaultAlignment * 8, + kDefaultAlignment * 16, + kDefaultAlignment * 2, + kDefaultAlignment * 32, + kDefaultAlignment / 2, + kDefaultAlignment * 128, + kDefaultAlignment, + kDefaultAlignment * 4, + }; + + static constexpr int kNumPasses = 100; + for (int pass = 0; pass < kNumPasses; ++pass) { + for (size_t alignment : alignments) { + constexpr size_t kAllocationSize = 16; + auto p = allocator.allocate(kAllocationSize, alignment); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignment); + // Write to the allocated memory. If it overruns, ASAN should catch it. + memset(p, 0x55, kAllocationSize); + } + } +} + +TEST_F(MallocMemoryAllocatorTest, BadAlignmentFails) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + // Should fail because the requested alignment is not a power of 2. + std::vector alignments = {0, 5, 6, 12, 34}; + for (auto alignment : alignments) { + auto p = allocator.allocate(16, alignment); + EXPECT_EQ(p, nullptr); + } +} + +TEST_F(MallocMemoryAllocatorTest, ResetSucceeds) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + auto p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + allocator.reset(); + + // Continue to allocate successfully. + p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); +} + +TEST_F(MallocMemoryAllocatorTest, OverflowDetectionOnSizePlusAlignment) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + constexpr size_t kLargeAlignment = kDefaultAlignment * 64; + constexpr size_t kSizeThatWouldOverflow = SIZE_MAX - kLargeAlignment + 1; + + auto p = allocator.allocate(kSizeThatWouldOverflow, kLargeAlignment); + + // Should return nullptr due to overflow detection. + EXPECT_EQ(p, nullptr); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/targets.bzl new file mode 100644 index 0000000..5855bee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/memory_allocator/test/targets.bzl @@ -0,0 +1,27 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "malloc_memory_allocator_test", + srcs = [ + "malloc_memory_allocator_test.cpp", + ], + deps = [ + "//executorch/extension/memory_allocator:malloc_memory_allocator", + ], + ) + + runtime.cxx_test( + name = "cpu_caching_malloc_allocator_test", + srcs = [ + "cpu_caching_malloc_allocator_test.cpp", + ], + deps = [ + "//executorch/extension/memory_allocator:cpu_caching_allocator", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/CMakeLists.txt new file mode 100644 index 0000000..75fa11c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +list(TRANSFORM _extension_runner_util__srcs PREPEND "${EXECUTORCH_ROOT}/") +add_library(extension_runner_util ${_extension_runner_util__srcs}) +target_link_libraries(extension_runner_util executorch_core) +target_include_directories( + extension_runner_util PUBLIC ${_common_include_directories} +) +target_compile_options(extension_runner_util PUBLIC ${_common_compile_options}) + +# Install libraries +install( + TARGETS extension_runner_util + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${_common_include_directories} +) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/TARGETS new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs.cpp similarity index 78% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs.cpp index 646950e..c111248 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs.cpp @@ -86,47 +86,17 @@ Result prepare_input_tensors( Debug, "Verifying and setting input for non-tensor input %zu", i); if (tag.get() == Tag::Int) { - if (buffer_size != sizeof(int64_t)) { - ET_LOG( - Error, - "Int input at index %zu has size %zu, expected sizeof(int64_t) %zu", - i, - buffer_size, - sizeof(int64_t)); - err = Error::InvalidArgument; - } else { - int64_t int_input; - std::memcpy(&int_input, buffer, buffer_size); - err = method.set_input(runtime::EValue(int_input), i); - } + int64_t int_input; + std::memcpy(&int_input, buffer, buffer_size); + err = method.set_input(runtime::EValue(int_input), i); } else if (tag.get() == Tag::Double) { - if (buffer_size != sizeof(double)) { - ET_LOG( - Error, - "Double input at index %zu has size %zu, expected sizeof(double) %zu", - i, - buffer_size, - sizeof(double)); - err = Error::InvalidArgument; - } else { - double double_input; - std::memcpy(&double_input, buffer, buffer_size); - err = method.set_input(runtime::EValue(double_input), i); - } + double double_input; + std::memcpy(&double_input, buffer, buffer_size); + err = method.set_input(runtime::EValue(double_input), i); } else if (tag.get() == Tag::Bool) { - if (buffer_size != sizeof(bool)) { - ET_LOG( - Error, - "Bool input at index %zu has size %zu, expected sizeof(bool) %zu", - i, - buffer_size, - sizeof(bool)); - err = Error::InvalidArgument; - } else { - bool bool_input; - std::memcpy(&bool_input, buffer, buffer_size); - err = method.set_input(runtime::EValue(bool_input), i); - } + bool bool_input; + std::memcpy(&bool_input, buffer, buffer_size); + err = method.set_input(runtime::EValue(bool_input), i); } else { ET_LOG( Error, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs_aten.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs_aten.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs_portable.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs_portable.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs_portable.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/inputs_portable.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/targets.bzl new file mode 100644 index 0000000..a9c48fb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/targets.bzl @@ -0,0 +1,25 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "inputs" + aten_suffix, + srcs = [ + "inputs.cpp", + "inputs{}.cpp".format("_aten" if aten_mode else "_portable"), + ], + exported_headers = ["inputs.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/executor:program_no_prim_ops" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/CMakeLists.txt new file mode 100644 index 0000000..44b85a7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + COMMAND ${PYTHON_EXECUTABLE} -m test.models.export_program --modules + "ModuleAdd" --outdir "${CMAKE_CURRENT_BINARY_DIR}" + WORKING_DIRECTORY ${EXECUTORCH_ROOT} +) + +add_custom_target( + executorch_runner_util_test_resources + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" +) + +set(test_env "ET_MODULE_ADD_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte") + +set(_test_srcs inputs_test.cpp) + +et_cxx_test( + extension_runner_util_test + SOURCES + ${_test_srcs} + EXTRA_LIBS + extension_data_loader + extension_runner_util + portable_kernels + portable_ops_lib +) + +add_dependencies( + extension_runner_util_test executorch_runner_util_test_resources +) +set_property(TEST extension_runner_util_test PROPERTY ENVIRONMENT ${test_env}) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/TARGETS new file mode 100644 index 0000000..7ace4ad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets(is_fbcode = True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/inputs_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/inputs_test.cpp new file mode 100644 index 0000000..aa3af2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/inputs_test.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::extension::BufferCleanup; +using executorch::extension::FileDataLoader; +using executorch::extension::prepare_input_tensors; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::MemoryManager; +using executorch::runtime::Method; +using executorch::runtime::MethodMeta; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::Tag; +using executorch::runtime::testing::ManagedMemoryManager; + +class InputsTest : public ::testing::Test { + protected: + void SetUp() override { + torch::executor::runtime_init(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + + mmm_ = std::make_unique( + /*planned_memory_bytes=*/32 * 1024U, + /*method_allocator_bytes=*/32 * 1024U); + + // Load the forward method. + Result method = program_->load_method("forward", &mmm_->get()); + ASSERT_EQ(method.error(), Error::Ok); + method_ = std::make_unique(std::move(method.get())); + } + + private: + // Must outlive method_, but tests shouldn't need to touch them. + std::unique_ptr loader_; + std::unique_ptr mmm_; + std::unique_ptr program_; + + protected: + std::unique_ptr method_; +}; + +TEST_F(InputsTest, Smoke) { + Result input_buffers = prepare_input_tensors(*method_); + ASSERT_EQ(input_buffers.error(), Error::Ok); + auto input_err = method_->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + // We can't look at the input tensors, but we can check that the outputs make + // sense after executing the method. + Error status = method_->execute(); + ASSERT_EQ(status, Error::Ok); + + // Get the single output, which should be a floating-point Tensor. + ASSERT_EQ(method_->outputs_size(), 1); + const EValue& output_value = method_->get_output(0); + ASSERT_EQ(output_value.tag, Tag::Tensor); + Tensor output = output_value.toTensor(); + ASSERT_EQ(output.scalar_type(), ScalarType::Float); + + // ModuleAdd adds its two inputs together, so if the input elements were set + // to 1, the output elemements should all be 2. + Span elements(output.mutable_data_ptr(), output.numel()); + EXPECT_GT(elements.size(), 0); // Make sure we're actually testing something. + for (float e : elements) { + EXPECT_EQ(e, 2.0); + } + + // Although it's tough to test directly, ASAN should let us know if + // BufferCleanup doesn't behave properly: either freeing too soon or leaking + // the pointers. +} + +TEST_F(InputsTest, ExceedingInputCountLimitFails) { + // The smoke test above demonstrated that we can prepare inputs with the + // default limits. It should fail if we lower the max below the number of + // actual inputs. + MethodMeta method_meta = method_->method_meta(); + size_t num_inputs = method_meta.num_inputs(); + ASSERT_GE(num_inputs, 1); + executorch::extension::PrepareInputTensorsOptions options; + options.max_inputs = num_inputs - 1; + + Result input_buffers = + prepare_input_tensors(*method_, options); + ASSERT_NE(input_buffers.error(), Error::Ok); +} + +TEST_F(InputsTest, ExceedingInputAllocationLimitFails) { + // The smoke test above demonstrated that we can prepare inputs with the + // default limits. It should fail if we lower the max below the actual + // allocation size. + executorch::extension::PrepareInputTensorsOptions options; + // The input tensors are float32, so 1 byte will always be smaller than any + // non-empty input tensor. + options.max_total_allocation_size = 1; + + Result input_buffers = + prepare_input_tensors(*method_, options); + ASSERT_NE(input_buffers.error(), Error::Ok); +} + +TEST(BufferCleanupTest, Smoke) { + // Returns the size of the buffer at index `i`. + auto test_buffer_size = [](size_t i) { + // Use multiples of OS page sizes. As this gets bigger, we're more + // likely to allocate outside the main heap in a separate page, making + // it easier to catch uses-after-free. + return 4096 << i; + }; + + // Create some buffers. + constexpr size_t kNumBuffers = 8; + void** buffers = (void**)malloc(kNumBuffers * sizeof(void*)); + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + buffers[i] = malloc(nbytes); + memset(reinterpret_cast(buffers[i]), 0x00, nbytes); + } + + std::unique_ptr bc2; + { + // bc1 should own `buffers` and the buffers that its entries point to. + BufferCleanup bc1({buffers, kNumBuffers}); + + // They're still alive; no segfaults or ASAN complaints if we write to them. + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + memset(reinterpret_cast(buffers[i]), 0xff, nbytes); + } + + // Move ownership to a new object. + bc2 = std::make_unique(std::move(bc1)); + + // Still alive. + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + memset(reinterpret_cast(buffers[i]), 0x00, nbytes); + } + + // bc1 goes out of scope here. If it thinks it owns the buffers, it will + // try to free them. + } + + // bc2 should own the buffers now, and they should still be alive. + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + memset(reinterpret_cast(buffers[i]), 0xff, nbytes); + } + + // Destroy bc2, which should destroy the buffers. There's no way for us to + // check that it happened, but the sanitizer should complain if there's a + // memory leak. And if bc1 freed them before, we should get a double-free + // complaint. + bc2.reset(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/targets.bzl new file mode 100644 index 0000000..95d5804 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/extension/runner_util/test/targets.bzl @@ -0,0 +1,32 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(is_fbcode = False): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + # TODO(dbort): Find a way to make these run for ANDROID/APPLE in xplat. The + # android and ios test determinators don't like the reference to the model + # file in fbcode. See https://fburl.com/9esapdmd + if not runtime.is_oss and is_fbcode: + runtime.cxx_test( + name = "inputs_test" + aten_suffix, + srcs = [ + "inputs_test.cpp", + ], + deps = [ + "//executorch/extension/runner_util:inputs", + "//executorch/runtime/executor/test:managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/kernels/portable:generated_lib", + "//executorch/extension/data_loader:file_data_loader", + ], + env = { + "ET_MODULE_ADD_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAdd.pte])", + }, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/CMakeLists.txt new file mode 100644 index 0000000..5004cb2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/CMakeLists.txt @@ -0,0 +1,107 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Kernel library for portable kernels. Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +set(_common_compile_options + $<$:/wd4996> + $<$>:-Wno-deprecated-declarations> +) + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Codegen.cmake) + +# Portable kernel sources TODO(larryliu0820): use buck2 to gather the sources +file(GLOB_RECURSE _portable_kernels__srcs + "${CMAKE_CURRENT_SOURCE_DIR}/cpu/*.cpp" +) +list(FILTER _portable_kernels__srcs EXCLUDE REGEX "test/*.cpp") +list(FILTER _portable_kernels__srcs EXCLUDE REGEX "codegen") +# Generate C++ bindings to register kernels into both PyTorch (for AOT) and +# Executorch (for runtime). Here select all ops in functions.yaml +set(_yaml "${CMAKE_CURRENT_SOURCE_DIR}/functions.yaml") +gen_selected_ops(LIB_NAME "portable_ops_lib" OPS_SCHEMA_YAML "${_yaml}") +# Expect gen_selected_ops output file to be selected_operators.yaml +generate_bindings_for_kernels( + LIB_NAME "portable_ops_lib" FUNCTIONS_YAML "${_yaml}" +) +message("Generated files ${gen_command_sources}") + +# +# portable_kernels: Pure-C++ kernel library for ATen ops +# +# Focused on portability and understandability rather than speed. +# +add_library(portable_kernels ${_portable_kernels__srcs}) +target_link_libraries( + portable_kernels PRIVATE executorch_core kernels_util_all_deps +) +target_compile_options(portable_kernels PUBLIC ${_common_compile_options}) + +# Build a library for _portable_kernels__srcs +# +# portable_ops_lib: Register portable_ops_lib ops kernels into Executorch +# runtime +gen_operators_lib( + LIB_NAME "portable_ops_lib" KERNEL_LIBS portable_kernels DEPS executorch_core +) + +# Portable kernels support optional parallelization (and, in the future, perhaps +# other performance features). If support is present, produce an optimized +# version. +if(EXECUTORCH_BUILD_PTHREADPOOL AND EXECUTORCH_BUILD_KERNELS_OPTIMIZED) + add_library(optimized_portable_kernels ${_portable_kernels__srcs}) + target_link_libraries(optimized_portable_kernels PRIVATE executorch_core) + target_link_libraries(optimized_portable_kernels PUBLIC extension_threadpool) + target_compile_options( + optimized_portable_kernels PUBLIC ${_common_compile_options} + ) + target_include_directories( + optimized_portable_kernels PRIVATE ${TORCH_INCLUDE_DIRS} + ) + target_compile_definitions( + optimized_portable_kernels + PRIVATE "ET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS" + ) + gen_selected_ops( + LIB_NAME "optimized_portable_ops_lib" OPS_SCHEMA_YAML "${_yaml}" + ) + generate_bindings_for_kernels( + LIB_NAME "optimized_portable_ops_lib" FUNCTIONS_YAML "${_yaml}" + ) + gen_operators_lib( + LIB_NAME "optimized_portable_ops_lib" KERNEL_LIBS + optimized_portable_kernels DEPS executorch_core + ) + install( + TARGETS optimized_portable_kernels optimized_portable_ops_lib + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) +endif() + +install( + TARGETS portable_kernels portable_ops_lib + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/executorch/kernels/portable/ +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/README.md new file mode 100644 index 0000000..955738e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/README.md @@ -0,0 +1 @@ +See README.md in the parent directory. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/math_constants.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/math_constants.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/math_constants.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/math_constants.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__clone_dim_order.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__clone_dim_order.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__clone_dim_order.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__clone_dim_order.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__empty_dim_order.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__empty_dim_order.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__empty_dim_order.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__empty_dim_order.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp new file mode 100644 index 0000000..f384e74 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include + +namespace torch { +namespace executor { +namespace native { + +using Tensor = executorch::aten::Tensor; +using SizesArrayRef = executorch::aten::ArrayRef; +using DimOrderArrayRef = + executorch::aten::ArrayRef; +using MemoryFormat = executorch::aten::MemoryFormat; + +template +using OptionalArrayRef = executorch::aten::OptionalArrayRef; + +template +using Optional = std::optional; + +// _to_dim_order_copy.out(Tensor self, *, bool non_blocking=False, int[]? +// dim_order=None, Tensor(a!) out) -> Tensor(a!) +Tensor& _to_dim_order_copy_out( + KernelRuntimeContext& ctx, + const Tensor& self, + bool non_blocking, + OptionalArrayRef dim_order, + Tensor& out) { + (void)ctx; + ET_KERNEL_CHECK( + ctx, + check__to_dim_order_copy_args(self, non_blocking, dim_order, out), + InvalidArgument, + out); + + ET_KERNEL_CHECK( + ctx, + resize_tensor(out, self.sizes()) == torch::executor::Error::Ok, + InvalidArgument, + out); + + if (self.numel() == 0) { + return out; + } + + // @lint-ignore CLANGTIDY facebook-hte-CArray + static constexpr const char op_name[] = + "dim_order_ops::_to_dim_order_copy.out"; + + ET_SWITCH_REALHBBF16_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { + ET_SWITCH_REALHBBF16_TYPES(out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { + _to_dim_order_copy_impl(self, out); + }); + }); + + return out; +} + +Tensor& _to_dim_order_copy_out( + const Tensor& self, + bool non_blocking, + OptionalArrayRef dim_order, + Tensor& out) { + executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext context{}; + return _to_dim_order_copy_out(context, self, non_blocking, dim_order, out); +} + +} // namespace native +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_abs.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_abs.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_abs.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_abs.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_acos.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_acos.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_acos.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_acos.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_acosh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_acosh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_acosh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_acosh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_add.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_add.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_addmm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_addmm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_addmm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_addmm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_alias_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_alias_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_alias_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_alias_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_allclose.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_allclose.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_allclose.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_allclose.cpp index 32d81f1..a1b2cb8 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_allclose.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_allclose.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -41,8 +41,8 @@ bool data_is_close( return false; } } else { - auto allowed_error = atol + std::fabs(rtol * b[i]); - auto actual_error = std::fabs(a[i] - b[i]); + auto allowed_error = atol + fabs(rtol * b[i]); + auto actual_error = fabs(a[i] - b[i]); if (!std::isfinite(actual_error) || actual_error > allowed_error) { return false; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_amax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_amax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_amax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_amax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_amin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_amin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_amin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_amin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_any.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_any.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_any.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_any.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_arange.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_arange.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_arange.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_arange.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_argmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_argmax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_argmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_argmax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_argmin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_argmin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_argmin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_argmin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_as_strided_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_as_strided_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_as_strided_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_as_strided_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_asin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_asin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_asin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_asin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_asinh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_asinh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_asinh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_asinh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_atan.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_atan.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_atan.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_atan.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_atan2.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_atan2.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_atan2.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_atan2.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_atanh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_atanh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_atanh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_atanh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_avg_pool2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_avg_pool2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_avg_pool2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_and.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_and.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_and.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_and.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_left_shift.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_left_shift.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_left_shift.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_left_shift.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_not.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_not.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_not.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_not.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_or.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_or.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_or.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_or.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_right_shift.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_right_shift.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_right_shift.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_right_shift.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_xor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_xor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bitwise_xor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bitwise_xor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bmm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bmm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_bmm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_bmm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cat.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cat.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cat.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cat.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cdist_forward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cdist_forward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cdist_forward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cdist_forward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ceil.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ceil.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ceil.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ceil.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_clamp.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_clamp.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_clamp.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_clamp.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_clone.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_clone.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_clone.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_clone.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_constant_pad_nd.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_constant_pad_nd.cpp similarity index 87% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_constant_pad_nd.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_constant_pad_nd.cpp index 0f287a5..d3f3fdd 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_constant_pad_nd.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_constant_pad_nd.cpp @@ -51,17 +51,9 @@ void apply_padding_to_dim( size_t pad_before = 0; size_t pad_after = 0; - if (pad_i < pad.size() / 2) { - int64_t pb = pad[2 * pad_i]; - int64_t pa = pad[2 * pad_i + 1]; - ET_KERNEL_CHECK_MSG( - ctx, - pb >= 0 && pa >= 0, - InvalidArgument, - /* void */, - "Padding values must be non-negative."); - pad_before = static_cast(pb); - pad_after = static_cast(pa); + if (pad_i >= 0 && pad_i < pad.size() / 2) { + pad_before = pad[2 * pad_i]; + pad_after = pad[2 * pad_i + 1]; } size_t out_step_len = out_strides[dim]; @@ -70,12 +62,6 @@ void apply_padding_to_dim( // Do not copy padding beyond the out tensor bounds. // Use division to avoid potential overflow in multiplication. if (pad_before > 0) { - ET_KERNEL_CHECK_MSG( - ctx, - out_data <= out_data_end, - InvalidArgument, - /* void */, - "Out data pointer exceeds buffer bounds."); size_t remaining = out_data_end - out_data; ET_KERNEL_CHECK_MSG( ctx, @@ -106,12 +92,7 @@ void apply_padding_to_dim( /* void */, "Out tensor overlaps with the input tensor. This is not supported."); // Bounds check before memcpy - ET_KERNEL_CHECK_MSG( - ctx, - out_data <= out_data_end, - InvalidArgument, - /* void */, - "Out data pointer exceeds buffer bounds."); + // Use overflow-safe check for remaining >= copy_len size_t remaining = out_data_end - out_data; ET_KERNEL_CHECK_MSG( ctx, @@ -142,10 +123,6 @@ void apply_padding_to_dim( last_padded_dim, dim + 1); - if (ctx.failure_state() != Error::Ok) { - return; - } - out_data += out_step_len; self_data += in_step_len; } @@ -154,12 +131,6 @@ void apply_padding_to_dim( // Do not copy padding beyond the out tensor bounds. // Use division to avoid potential overflow in multiplication. if (pad_after > 0) { - ET_KERNEL_CHECK_MSG( - ctx, - out_data <= out_data_end, - InvalidArgument, - /* void */, - "Out data pointer exceeds buffer bounds."); size_t remaining = out_data_end - out_data; ET_KERNEL_CHECK_MSG( ctx, @@ -206,7 +177,7 @@ void constant_pad_nd_out_impl( out_strides[i] = getTrailingDims(out, static_cast(i)); size_t pad_i = ndim - 1 - i; - if (pad_i < pad.size() / 2) { + if (pad_i >= 0 && pad_i < pad.size() / 2) { if (pad[2 * pad_i] + pad[2 * pad_i + 1] > 0) { last_padded_dim = i; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_convolution.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_convolution.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_convolution.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_convolution.cpp index bf848bc..81dae4a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_convolution.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_convolution.cpp @@ -106,18 +106,18 @@ void conv2d_impl( for (const auto w_y : c10::irange(w_H)) { w_coord[2] = w_y; - ssize_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; + size_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; in_coord[2] = in_y; // Only proceed if input y coordinate is within bounds - if (in_y >= 0 && in_y < static_cast(in_H)) { + if (in_y >= 0 && in_y < in_H) { for (const auto w_x : c10::irange(w_W)) { w_coord[3] = w_x; - ssize_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; + size_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; in_coord[3] = in_x; // Only proceed if input x coordinate is within bounds - if (in_x >= 0 && in_x < static_cast(in_W)) { + if (in_x >= 0 && in_x < in_W) { size_t in_idx = calculate_linear_index(in_coord, in_strides.data(), 4); CTYPE in_val = in_ptr[in_idx]; @@ -161,18 +161,18 @@ void conv2d_impl( w_coord[0] = in_c; for (const auto w_y : c10::irange(w_H)) { w_coord[2] = w_y; - ssize_t out_y = stride_y * in_y + dilation_y * w_y - padding_y; + size_t out_y = stride_y * in_y + dilation_y * w_y - padding_y; out_coord[2] = out_y; // Only proceed if output y coordinate is within bounds - if (out_y >= 0 && out_y < static_cast(out_H)) { + if (out_y >= 0 && out_y < out_H) { for (const auto w_x : c10::irange(w_W)) { w_coord[3] = w_x; - ssize_t out_x = stride_x * in_x + dilation_x * w_x - padding_x; + size_t out_x = stride_x * in_x + dilation_x * w_x - padding_x; out_coord[3] = out_x; // Only proceed if output x coordinate is within bounds - if (out_x >= 0 && out_x < static_cast(out_W)) { + if (out_x >= 0 && out_x < out_W) { size_t w_idx = calculate_linear_index(w_coord, w_strides.data(), 4); CTYPE w_val = w_ptr[w_idx]; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_convolution_backward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_convolution_backward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_convolution_backward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_convolution_backward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cos.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cos.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cos.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cos.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cosh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cosh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cosh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cosh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cumsum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cumsum.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_cumsum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_cumsum.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_detach_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_detach_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_detach_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_detach_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_diagonal_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_diagonal_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_diagonal_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_diagonal_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_div.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_div.cpp similarity index 85% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_div.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_div.cpp index 299997a..f94f219 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_div.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_div.cpp @@ -20,10 +20,7 @@ namespace native { namespace { ScalarType get_common_type(ScalarType a_type, ScalarType b_type) { - if (executorch::runtime::isComplexType(a_type) || - executorch::runtime::isComplexType(b_type)) { - return promoteTypes(a_type, b_type); - } else if (isFloatingType(a_type) && isFloatingType(b_type)) { + if (isFloatingType(a_type) && isFloatingType(b_type)) { return promoteTypes(a_type, b_type); } else if (isFloatingType(a_type)) { return a_type; @@ -54,35 +51,25 @@ Tensor& div_out( InvalidArgument, out); + // Compute Dtype + ScalarType compute_type = utils::get_compute_type(common_type); + // @lint-ignore CLANGTIDY facebook-hte-CArray static constexpr const char op_name[] = "div.out"; - if (executorch::runtime::isComplexType(common_type)) { - ET_SWITCH_COMPLEX_TYPES(common_type, ctx, op_name, CTYPE, [&]() { - const CTYPE* a_data = a.const_data_ptr(); - const CTYPE* b_data = b.const_data_ptr(); - CTYPE* out_data = out.mutable_data_ptr(); - for (ssize_t i = 0; i < out.numel(); ++i) { - out_data[i] = a_data[i] / b_data[i]; - } - }); - } else { - // Compute Dtype for real types - ScalarType compute_type = utils::get_compute_type(common_type); - ET_SWITCH_FLOAT_TYPES(compute_type, ctx, op_name, CTYPE_COMPUTE, [&]() { - utils::apply_bitensor_elementwise_fn< - CTYPE_COMPUTE, - op_name, - utils::SupportedTensorDtypes::FLOATHBF16>( - [](const auto& val_a, const auto& val_b) { return val_a / val_b; }, - ctx, - a, - utils::SupportedTensorDtypes::REALHBBF16, - b, - utils::SupportedTensorDtypes::REALHBBF16, - out); - }); - } + ET_SWITCH_FLOAT_TYPES(compute_type, ctx, op_name, CTYPE_COMPUTE, [&]() { + utils::apply_bitensor_elementwise_fn< + CTYPE_COMPUTE, + op_name, + utils::SupportedTensorDtypes::FLOATHBF16>( + [](const auto& val_a, const auto& val_b) { return val_a / val_b; }, + ctx, + a, + utils::SupportedTensorDtypes::REALHBBF16, + b, + utils::SupportedTensorDtypes::REALHBBF16, + out); + }); return out; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_elu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_elu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_elu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_elu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_embedding.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_embedding.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_embedding.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_embedding.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_empty.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_empty.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_empty.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_empty.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_eq.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_eq.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_eq.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_eq.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_erf.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_erf.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_erf.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_erf.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_exp.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_exp.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_exp.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_exp.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_expand_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_expand_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_expand_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_expand_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_expm1.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_expm1.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_expm1.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_expm1.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_fill.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_fill.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_fill.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_fill.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_flip.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_flip.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_flip.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_flip.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_floor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_floor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_floor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_floor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_floor_divide.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_floor_divide.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_floor_divide.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_floor_divide.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_fmod.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_fmod.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_fmod.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_fmod.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_full.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_full.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_full.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_full.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_full_like.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_full_like.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_full_like.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_full_like.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_gather.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_gather.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_gather.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_gather.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ge.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ge.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ge.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ge.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_gelu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_gelu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_gelu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_gelu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_glu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_glu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_glu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_glu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_grid_sampler_2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_grid_sampler_2d.cpp similarity index 83% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_grid_sampler_2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_grid_sampler_2d.cpp index dd483c4..57155b3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_grid_sampler_2d.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_grid_sampler_2d.cpp @@ -10,8 +10,6 @@ #include #include -#include - namespace torch { namespace executor { namespace native { @@ -21,22 +19,6 @@ using executorch::aten::SizesType; using std::optional; namespace { - -// For half-precision inputs, all internal math (source-index computation, -// interpolation weight subtractions like `ix_se - ix` which are prone to -// catastrophic cancellation, and weighted-sum accumulation) is done in fp32. -// Loads and stores stay in the tensor's dtype. The speed cost is negligible -// (a handful of fp16↔fp32 conversions per output element) and the precision -// win is material: fp16 has only ~10 bits of mantissa, so subtracting nearby -// pixel coordinates can round to values that are meaningfully off, producing -// visibly wrong interpolation weights. -template -using AccType = std::conditional_t< - std::is_same_v || - std::is_same_v, - float, - CTYPE>; - template void grid_sample_2d_bilinear_kernel_impl_nchw( const Tensor& in, @@ -44,7 +26,6 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( GridSamplerPadding padding_mode, bool align_corners, Tensor& out) { - using ACC = AccType; const auto in_data = in.const_data_ptr(); auto out_data = out.mutable_data_ptr(); @@ -78,14 +59,13 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( // grid[n, h, w] contains (x, y) const int64_t grid_idx = grid_offset + h * grid.strides()[1] + w * grid.strides()[2]; - const ACC x = static_cast(grid_data[grid_idx]); - const ACC y = - static_cast(grid_data[grid_idx + grid.strides()[3]]); + const CTYPE x = grid_data[grid_idx]; + const CTYPE y = grid_data[grid_idx + grid.strides()[3]]; - // Compute source coordinates in pixel space (in ACC precision). - const ACC ix = grid_sampler_compute_source_index( + // Compute source coordinates in pixel space + const CTYPE ix = grid_sampler_compute_source_index( x, inp_W, padding_mode, align_corners); - const ACC iy = grid_sampler_compute_source_index( + const CTYPE iy = grid_sampler_compute_source_index( y, inp_H, padding_mode, align_corners); // Get corner pixel coordinates @@ -98,46 +78,40 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( const int64_t ix_se = ix_nw + 1; const int64_t iy_se = iy_nw + 1; - // Interpolation weights. For half inputs these are computed in - // fp32 — the subtractions `ix_se - ix` otherwise suffer - // catastrophic cancellation in fp16 for interior pixels. - const ACC nw_weight = (ix_se - ix) * (iy_se - iy); - const ACC ne_weight = (ix - ix_sw) * (iy_sw - iy); - const ACC sw_weight = (ix_ne - ix) * (iy - iy_ne); - const ACC se_weight = (ix - ix_nw) * (iy - iy_nw); + // Get interpolation weights + const CTYPE nw_weight = (ix_se - ix) * (iy_se - iy); + const CTYPE ne_weight = (ix - ix_sw) * (iy_sw - iy); + const CTYPE sw_weight = (ix_ne - ix) * (iy - iy_ne); + const CTYPE se_weight = (ix - ix_nw) * (iy - iy_nw); - // Accumulate the weighted sum in ACC precision. - ACC out_val = 0; + // Compute output value for this channel + CTYPE out_val = 0; // Add contribution from each corner if within bounds if (padding_mode == GridSamplerPadding::Zeros) { // For zeros padding, only sample if within bounds if (within_bounds_2d(iy_nw, ix_nw, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_nw * in.strides()[2] + - ix_nw * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_nw * in.strides()[2] + + ix_nw * in.strides()[3]] * nw_weight; } if (within_bounds_2d(iy_ne, ix_ne, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_ne * in.strides()[2] + - ix_ne * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_ne * in.strides()[2] + + ix_ne * in.strides()[3]] * ne_weight; } if (within_bounds_2d(iy_sw, ix_sw, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_sw * in.strides()[2] + - ix_sw * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_sw * in.strides()[2] + + ix_sw * in.strides()[3]] * sw_weight; } if (within_bounds_2d(iy_se, ix_se, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_se * in.strides()[2] + - ix_se * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_se * in.strides()[2] + + ix_se * in.strides()[3]] * se_weight; } } else { @@ -152,33 +126,28 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( const int64_t iy_sw_safe = clip_coordinates(iy_sw, inp_H); const int64_t ix_se_safe = clip_coordinates(ix_se, inp_W); const int64_t iy_se_safe = clip_coordinates(iy_se, inp_H); - out_val = - static_cast( - in_data - [in_channel_offset + iy_nw_safe * in.strides()[2] + - ix_nw_safe * in.strides()[3]]) * + out_val = in_data + [in_channel_offset + iy_nw_safe * in.strides()[2] + + ix_nw_safe * in.strides()[3]] * nw_weight + - static_cast( - in_data + in_data [in_channel_offset + iy_ne_safe * in.strides()[2] + - ix_ne_safe * in.strides()[3]]) * + ix_ne_safe * in.strides()[3]] * ne_weight + - static_cast( - in_data + in_data [in_channel_offset + iy_sw_safe * in.strides()[2] + - ix_sw_safe * in.strides()[3]]) * + ix_sw_safe * in.strides()[3]] * sw_weight + - static_cast( - in_data + in_data [in_channel_offset + iy_se_safe * in.strides()[2] + - ix_se_safe * in.strides()[3]]) * + ix_se_safe * in.strides()[3]] * se_weight; } // Write output in NCHW order const int64_t out_idx = out_channel_offset + h * out.strides()[2] + w * out.strides()[3]; - out_data[out_idx] = static_cast(out_val); + out_data[out_idx] = out_val; } } } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_gt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_gt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_gt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_gt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_hardtanh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_hardtanh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_hardtanh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_hardtanh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_index.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_index.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_index.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_index.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_index_put.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_index_put.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_index_put.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_index_put.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_index_select.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_index_select.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_index_select.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_index_select.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_isinf.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_isinf.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_isinf.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_isinf.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_isnan.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_isnan.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_isnan.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_isnan.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_le.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_le.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_le.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_le.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_leaky_relu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_leaky_relu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_leaky_relu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_leaky_relu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_lift_fresh_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_lift_fresh_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_lift_fresh_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_lift_fresh_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log10.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log10.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log10.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log10.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log1p.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log1p.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log1p.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log1p.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log2.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log2.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log2.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log2.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log_softmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log_softmax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_log_softmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_log_softmax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_and.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_and.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_and.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_and.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_not.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_not.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_not.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_not.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_or.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_or.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_or.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_or.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_xor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_xor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logical_xor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logical_xor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logit.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logit.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_logit.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_logit.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_lt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_lt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_lt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_lt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_masked_fill.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_masked_fill.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_masked_fill.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_masked_fill.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_masked_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_masked_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_masked_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_masked_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_masked_select.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_masked_select.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_masked_select.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_masked_select.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_max.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_max.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_max.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_max.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_maximum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_maximum.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_maximum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_maximum.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_mean.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_mean.cpp similarity index 67% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_mean.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_mean.cpp index 78ae41b..63c7896 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_mean.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_mean.cpp @@ -45,36 +45,6 @@ Tensor& mean_dim_out( InvalidArgument, out); - // Fast path: contiguous tensor, single innermost dim reduction, same dtype. - // Bypasses generic MapReduceOverDimListPlan to use a tight vectorizable loop. - if (in.numel() > 0 && dim_list.has_value() && dim_list.value().size() == 1 && - in.scalar_type() == out.scalar_type()) { - const int64_t d = dim_list.value()[0] < 0 ? dim_list.value()[0] + in.dim() - : dim_list.value()[0]; - if (d >= 0 && d < in.dim() && d == in.dim() - 1 && - tensor_is_contiguous(in)) { - const int64_t reduce_size = in.size(d); - const int64_t outer_size = in.numel() / reduce_size; - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "mean.out"; - ET_SWITCH_FLOATHBF16_TYPES(in.scalar_type(), ctx, op_name, CTYPE, [&] { - const CTYPE* in_data = in.const_data_ptr(); - CTYPE* out_data = out.mutable_data_ptr(); - const CTYPE denom = static_cast(reduce_size); - for (int64_t i = 0; i < outer_size; i++) { - const CTYPE* row = in_data + i * reduce_size; - CTYPE acc = 0; - for (int64_t j = 0; j < reduce_size; j++) { - acc += row[j]; - } - out_data[i] = acc / denom; - } - }); - return out; - } - } - std::optional plan; if (in.numel() > 0) { plan.emplace(in, dim_list); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_min.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_min.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_min.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_min.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_minimum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_minimum.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_minimum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_minimum.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_mm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_mm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_mm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_mm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_mul.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_mul.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_mul.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_mul.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_narrow_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_narrow_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_narrow_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_narrow_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_batch_norm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_batch_norm.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_batch_norm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_batch_norm.cpp index 3a76d35..b8905e0 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_batch_norm.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_batch_norm.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include @@ -268,10 +267,6 @@ std::tuple _native_batch_norm_legit_no_stats_out( CTYPE* mean_data = mean_out.mutable_data_ptr(); CTYPE* invstd_data = invstd_out.mutable_data_ptr(); - // Initialize accumulators to zero before accumulating - std::memset(mean_data, 0, C * sizeof(CTYPE)); - std::memset(invstd_data, 0, C * sizeof(CTYPE)); - // Compute sum and sum of squares for each channel for (size_t b = 0; b < N; ++b) { const CTYPE* b_in_data = in_data + b * C * inner; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_dropout.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_dropout.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_dropout.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_dropout.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_group_norm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_group_norm.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_group_norm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_group_norm.cpp index 7a2b40c..9e300dc 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_group_norm.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_group_norm.cpp @@ -77,8 +77,8 @@ void group_norm( const CTYPE* x = input_data + i * inner_size; // compute E[X] and Var[x] = E[x^2] - E[x]^2 - float sum = reduce_add(x, inner_size); - float sq_sum = vec_powerf(x, inner_size); + CTYPE sum = reduce_add(x, static_cast(inner_size)); + CTYPE sq_sum = vec_powerf(x, static_cast(inner_size)); double mean_value = static_cast(sum) / static_cast(inner_size); double variance = diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_layer_norm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_layer_norm.cpp similarity index 77% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_layer_norm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_layer_norm.cpp index b35796f..12a03a1 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_layer_norm.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_native_layer_norm.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -53,21 +54,41 @@ void layer_norm( } const CTYPE* input_data = input.const_data_ptr(); - const CTYPE* weight_data = - weight.has_value() ? weight.value().const_data_ptr() : nullptr; - const CTYPE* bias_data = - bias.has_value() ? bias.value().const_data_ptr() : nullptr; - - layer_norm_scalar( - input_data, - weight_data, - bias_data, - out_data, - mean_data, - rstd_data, - leading, - normalized, - eps); + const CTYPE* weight_data; + if (weight.has_value()) { + weight_data = weight.value().const_data_ptr(); + } else { + weight_data = nullptr; + } + const CTYPE* bias_data; + if (bias.has_value()) { + bias_data = bias.value().const_data_ptr(); + } else { + bias_data = nullptr; + } + + const CTYPE ct_normalized = static_cast(normalized); + for (const auto i : c10::irange(leading)) { + const CTYPE* x = input_data + i * normalized; + CTYPE* y = out_data + i * normalized; + + // compute E[X] and Var[x] = E[x^2] - E[x]^2 + CTYPE sum = reduce_add(x, ct_normalized); + CTYPE sq_sum = vec_powerf(x, ct_normalized); + CTYPE mean_value = sum / ct_normalized; + CTYPE variance = sq_sum / ct_normalized - mean_value * mean_value; + CTYPE std = std::sqrt(variance + eps); + + // Calculate the elements of output + for (const auto j : c10::irange(normalized)) { + CTYPE w = weight_data ? weight_data[j] : static_cast(1); + CTYPE b = bias_data ? bias_data[j] : static_cast(0); + y[j] = (x[j] - mean_value) / std * w + b; + } + + mean_data[i] = mean_value; + rstd_data[i] = 1.0 / std; + } } } // namespace diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ne.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ne.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ne.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ne.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_neg.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_neg.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_neg.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_neg.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_nonzero.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_nonzero.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_nonzero.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_nonzero.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ones.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ones.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_ones.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_ones.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pdist_forward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pdist_forward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pdist_forward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pdist_forward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_permute_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_permute_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_permute_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_permute_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pixel_shuffle.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pixel_shuffle.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pixel_shuffle.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pixel_shuffle.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pixel_unshuffle.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pixel_unshuffle.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pixel_unshuffle.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pixel_unshuffle.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pow.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pow.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_pow.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_pow.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_prod.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_prod.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_prod.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_prod.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_rand.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_rand.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_rand.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_rand.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_randn.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_randn.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_randn.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_randn.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reciprocal.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reciprocal.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reciprocal.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reciprocal.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reflection_pad1d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reflection_pad1d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reflection_pad1d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reflection_pad1d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reflection_pad2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reflection_pad2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reflection_pad2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reflection_pad2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reflection_pad3d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reflection_pad3d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_reflection_pad3d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_reflection_pad3d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_relu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_relu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_relu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_relu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_remainder.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_remainder.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_remainder.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_remainder.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_repeat.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_repeat.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_repeat.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_repeat.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_repeat_interleave.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_repeat_interleave.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_repeat_interleave.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_repeat_interleave.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_replication_pad1d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_replication_pad1d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_replication_pad1d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_replication_pad1d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_replication_pad2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_replication_pad2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_replication_pad2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_replication_pad2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_replication_pad3d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_replication_pad3d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_replication_pad3d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_replication_pad3d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_roll.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_roll.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_roll.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_roll.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_round.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_round.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_round.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_round.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_rsqrt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_rsqrt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_rsqrt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_rsqrt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_rsub.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_rsub.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_rsub.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_rsub.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_scalar_tensor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_scalar_tensor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_scalar_tensor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_scalar_tensor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_scatter_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_scatter_add.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_scatter_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_scatter_add.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_select_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_select_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_select_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_select_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_select_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_select_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_select_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_select_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sigmoid.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sigmoid.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sigmoid.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sigmoid.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sign.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sign.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sign.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sign.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sinh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sinh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sinh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sinh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_slice_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_slice_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_slice_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_slice_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_slice_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_slice_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_slice_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_slice_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_softmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_softmax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_softmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_softmax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_split_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_split_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_split_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_split_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_split_with_sizes_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_split_with_sizes_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_split_with_sizes_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_split_with_sizes_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sqrt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sqrt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sqrt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sqrt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_squeeze_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_squeeze_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_squeeze_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_squeeze_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_stack.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_stack.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_stack.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_stack.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sub.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sub.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sub.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sub.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sum.cpp similarity index 73% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sum.cpp index f2d750d..dcd8179 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sum.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_sum.cpp @@ -46,36 +46,6 @@ Tensor& sum_dim_out( ET_KERNEL_CHECK(ctx, tensor_is_default_dim_order(in), InvalidArgument, out); - // Fast path: contiguous tensor, single innermost dim reduction, same dtype. - // Bypasses generic MapReduceOverDimListPlan to use a tight vectorizable loop. - if (in.numel() > 0 && dim_list.has_value() && dim_list.value().size() == 1 && - !executorch::runtime::isComplexType(in.scalar_type()) && - in.scalar_type() == out.scalar_type()) { - const int64_t d = dim_list.value()[0] < 0 ? dim_list.value()[0] + in.dim() - : dim_list.value()[0]; - if (d >= 0 && d < in.dim() && d == in.dim() - 1 && - tensor_is_contiguous(in)) { - const int64_t reduce_size = in.size(d); - const int64_t outer_size = in.numel() / reduce_size; - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "sum.IntList_out"; - ET_SWITCH_REALHBBF16_TYPES(in.scalar_type(), ctx, op_name, CTYPE, [&] { - const CTYPE* in_data = in.const_data_ptr(); - CTYPE* out_data = out.mutable_data_ptr(); - for (int64_t i = 0; i < outer_size; i++) { - const CTYPE* row = in_data + i * reduce_size; - CTYPE acc = 0; - for (int64_t j = 0; j < reduce_size; j++) { - acc += row[j]; - } - out_data[i] = acc; - } - }); - return out; - } - } - std::optional plan; if (in.numel() > 0) { plan.emplace(in, dim_list); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_t_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_t_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_t_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_t_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_tan.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_tan.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_tan.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_tan.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_tanh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_tanh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_tanh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_tanh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_to_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_to_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_to_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_to_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_topk.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_topk.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_topk.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_topk.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_transpose_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_transpose_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_transpose_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_transpose_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_tril.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_tril.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_tril.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_tril.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_trunc.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_trunc.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_trunc.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_trunc.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_unbind_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_unbind_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_unbind_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_unbind_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_unfold_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_unfold_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_unfold_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_unfold_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_unsqueeze_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_unsqueeze_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_unsqueeze_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_unsqueeze_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_upsample_nearest2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_upsample_nearest2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_upsample_nearest2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_upsample_nearest2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_var.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_var.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_var.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_var.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_view_as_real_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_view_as_real_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_view_as_real_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_view_as_real_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_view_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_view_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_view_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_view_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_where.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_where.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_where.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_where.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_zeros.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_zeros.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_zeros.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/op_zeros.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/bitwise_op.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/bitwise_op.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/bitwise_op.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/bitwise_op.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/comparison_op.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/comparison_op.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/comparison_op.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/comparison_op.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/logical_op.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/logical_op.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/logical_op.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/logical_op.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/pattern.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/pattern.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/pattern.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/pattern.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/targets.bzl new file mode 100644 index 0000000..5df8fde --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/targets.bzl @@ -0,0 +1,64 @@ +load("@fbsource//xplat/executorch/build:build_variables.bzl", "PATTERN_SRCS") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Note: add all portable_op dependencies to all_deps. This is used for dtype selective + # build, where the portable ops are built from source and linked with :all_deps + runtime.cxx_library( + name = "all_deps", + exported_deps = [ + "//executorch/kernels/portable/cpu/pattern:pattern", + "//executorch/kernels/portable/cpu/pattern:bitwise_op", + "//executorch/kernels/portable/cpu/pattern:comparison_op", + "//executorch/kernels/portable/cpu/pattern:logical_op" + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "bitwise_op", + exported_headers = [ + "bitwise_op.h", + ], + compiler_flags = [], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/...", "//executorch/backends/cadence/..."], + ) + + runtime.cxx_library( + name = "comparison_op", + exported_headers = [ + "comparison_op.h", + ], + compiler_flags = [], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/...", "//executorch/backends/cadence/..."], + ) + + runtime.cxx_library( + name = "logical_op", + exported_headers = [ + "logical_op.h", + ], + compiler_flags = [], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "pattern", + srcs = PATTERN_SRCS, + exported_headers = [ + "pattern.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + exported_deps = [ + "//executorch/kernels/portable/cpu/util:broadcast_util", + "//executorch/kernels/portable/cpu/util:functional_util", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/scalar_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/scalar_utils.h similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/scalar_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/scalar_utils.h index 18cc1f4..312a663 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/scalar_utils.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/scalar_utils.h @@ -221,8 +221,8 @@ bool extract_scalar(Scalar scalar, FLOAT_T* out_val) { // be represented when FLOAT_T == float. float can, however, represent // infinite and NaN values. if (std::isfinite(val) && - (val < static_cast(std::numeric_limits::lowest()) || - val > static_cast(std::numeric_limits::max()))) { + (val < std::numeric_limits::lowest() || + val > std::numeric_limits::max())) { // PyTorch's implementation of clamp() raises an exception if the min/max // values cannot be represented as the dtype, so we should fail too. return false; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/selective_build.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/selective_build.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/selective_build.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/selective_build.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/targets.bzl new file mode 100644 index 0000000..7df7757 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/targets.bzl @@ -0,0 +1,89 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/kernels/portable:op_registration_util.bzl", "ATEN_OPS", "CUSTOM_OPS", "define_op_target") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Define build targets for all operators registered in the tables above. + for op in ATEN_OPS: + define_op_target(is_aten_op = True, **op) + for op in CUSTOM_OPS: + define_op_target(is_aten_op = False, **op) + + custom_op_targets = [":{}".format(op["name"]) for op in CUSTOM_OPS] + + aten_op_targets = [":{}".format(op["name"]) for op in ATEN_OPS] + all_op_targets = custom_op_targets + aten_op_targets + + runtime.cxx_library( + name = "cpu", + srcs = [], + visibility = [ + "//executorch/kernels/portable/...", + "//executorch/kernels/test/...", + ], + exported_deps = all_op_targets, + ) + + if True in get_aten_mode_options(): + runtime.cxx_library( + name = "cpu_aten", + srcs = [], + visibility = ["//executorch/kernels/portable/..."], + exported_deps = [t + "_aten" for t in custom_op_targets], + ) + + # Only for use by op targets under //executorch. This API needs to be + # reevaluated before becoming a public API. + runtime.cxx_library( + name = "vec_ops", + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + "//executorch/runtime/platform:compiler", + ], + srcs = [], + exported_headers = ["vec_ops.h"], + visibility = ["PUBLIC"], + ) + + # Only for use by targets in this directory. Defines constants like M_PI + # if they arent already defined by the toolchains cmath + runtime.cxx_library( + name = "math_constants", + srcs = [], + exported_headers = [ + "math_constants.h", + ], + visibility = ["PUBLIC"], + ) + + # Only for use by targets in this directory. + runtime.cxx_library( + name = "scalar_utils", + srcs = [], + exported_headers = ["scalar_utils.h", "selective_build.h"], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + ], + exported_deps = [ + "//executorch/runtime/core/exec_aten:lib", + ], + ) + + # Used for dtype selective build. Collect source and header files. + runtime.filegroup( + name = "portable_source_files", + srcs = native.glob(["*.cpp"]), + visibility = ["PUBLIC"], + ) + + runtime.filegroup( + name = "portable_header_files", + srcs = native.glob(["*.h"]), + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/scalar_utils_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/scalar_utils_test.cpp new file mode 100644 index 0000000..f1e7af6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/scalar_utils_test.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +template +struct promote_type_with_scalar_type_is_valid + : std::integral_constant< + bool, + (std::is_same::value || + std::is_same::value || + std::is_same::value) && + !std::is_same::value && + !torch::executor::is_qint_type::value && + !torch::executor::is_bits_type::value && + !executorch::runtime::is_bits_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_barebones_unsigned_type::value && + !executorch::runtime::is_barebones_unsigned_type::value> {}; + +template +struct CompileTimePromoteTypeWithScalarTypeTestCase { + static void testAll() { +#define CALL_TEST_ONE(cpp_type, scalar_type) \ + testOne< \ + cpp_type, \ + promote_type_with_scalar_type_is_valid::value>(); + ET_FORALL_SCALAR_TYPES(CALL_TEST_ONE) +#undef CALL_TEST_ONE + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + auto actual = torch::executor::CppTypeToScalarType< + typename torch::executor::native::utils:: + promote_type_with_scalar_type::type>::value; + const auto scalarType1 = torch::executor::CppTypeToScalarType::value; + const auto scalarType2 = torch::executor::CppTypeToScalarType::value; + T2 scalar_value = 0; + auto expected = torch::executor::native::utils::promote_type_with_scalar( + scalarType1, scalar_value, half_to_float); + EXPECT_EQ(actual, expected) + << "promoting " << (int)scalarType1 << " with " << (int)scalarType2 + << " given half_to_float = " << half_to_float << " expected " + << (int)expected << " but got " << (int)actual; + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + // Skip invalid case + } +}; + +TEST(ScalarTypeUtilTest, compileTypePromoteTypesTest) { +#define INSTANTIATE_TYPE_TEST(cpp_type, scalar_type) \ + CompileTimePromoteTypeWithScalarTypeTestCase::testAll(); \ + CompileTimePromoteTypeWithScalarTypeTestCase::testAll(); + + ET_FORALL_SCALAR_TYPES(INSTANTIATE_TYPE_TEST); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/targets.bzl new file mode 100644 index 0000000..a40f6da --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/targets.bzl @@ -0,0 +1,29 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # + # NOTE: tests for operators should live in kernels/portable/test, so that + # they can be run against all implementations of a given operator. This + # directory is only for testing cpu-specific helper libraries. + # + + runtime.cxx_test( + name = "scalar_utils_test", + srcs = ["scalar_utils_test.cpp"], + deps = [ + "//executorch/kernels/portable/cpu:scalar_utils", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + ) + + runtime.cxx_test( + name = "vec_ops_test", + srcs = ["vec_ops_test.cpp"], + deps = ["//executorch/kernels/portable/cpu:vec_ops"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/vec_ops_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/vec_ops_test.cpp new file mode 100644 index 0000000..9611acd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/test/vec_ops_test.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +using namespace ::testing; + +TEST(VecMinfTest, Smoke) { + // No need to be super thorough since we know this is implemented with + // std::min_element(). Just show that it's hooked up correctly. + + constexpr size_t kNumVals = 5; + float x[kNumVals] = {1.1, -2.2, 0, -1234.5, 10.0}; + EXPECT_EQ(torch::executor::vec_minf(x, kNumVals), -1234.5); +} + +TEST(VecMaxfTest, Smoke) { + // No need to be super thorough since we know this is implemented with + // std::max_element(). Just show that it's hooked up correctly. + + constexpr size_t kNumVals = 5; + float x[kNumVals] = {1.1, -2.2, 0, -1234.5, 10.0}; + EXPECT_EQ(torch::executor::vec_maxf(x, kNumVals), 10.0); +} + +TEST(VecAddfTest, Smoke) { + constexpr size_t kNumVals = 5; + float in1[kNumVals] = {1, 2, 3, 4, 5}; + float in2[kNumVals] = {10, 20, 30, 40, 50}; + float out[kNumVals] = {}; + + torch::executor::vec_addf(out, in1, in2, kNumVals); + + // Each element of `out` should be the sum of the corresponding elements + // of `in1` and `in2`. + EXPECT_EQ(out[0], 11); + EXPECT_EQ(out[1], 22); + EXPECT_EQ(out[2], 33); + EXPECT_EQ(out[3], 44); + EXPECT_EQ(out[4], 55); +} + +TEST(VecScalefTest, Smoke) { + constexpr size_t kNumVals = 5; + float in[kNumVals] = {4, 8, 16, 32, 64}; + float out[kNumVals] = {0, 0, 0, 0, 0}; + + torch::executor::vec_scalef(out, in, 0.5, kNumVals); + + // Each element of `out` should be the product of 0.5 and the corresponding + // element of `in`. + EXPECT_EQ(out[0], 2); + EXPECT_EQ(out[1], 4); + EXPECT_EQ(out[2], 8); + EXPECT_EQ(out[3], 16); + EXPECT_EQ(out[4], 32); +} + +TEST(VecPowerfTest, Smoke) { + constexpr size_t kNumVals = 5; + float in[kNumVals] = {-2, -1, 0, 1, 2}; + + // Should return the sum of the squares of all input elements. + EXPECT_EQ( + torch::executor::vec_powerf(in, kNumVals), + (-2 * -2) + (-1 * -1) + (0 * 0) + (1 * 1) + (2 * 2)); +} + +TEST(VecMatMulTest, Smoke) { + // x sizes: (3, 2) + constexpr size_t kXNumVals = 6; + // y sizes: (2, 4) + constexpr size_t kYNumVals = 8; + // z sizes: (3, 4) + constexpr size_t kZNumVals = 12; + + // clang-format off + int64_t X[kXNumVals] = { + 1, 2, + 2, 1, + 3, 0, + }; + int64_t Y[kYNumVals] = { + 1, 2, 3, 4, + 5, 6, 7, 8, + }; + // clang-format on + + int64_t out[kZNumVals] = {}; + + torch::executor::vec_matmul(out, X, Y, 3, 2, 4); + + // clang-format off + std::vector expected({ + 11, 14, 17, 20, + 7, 10, 13, 16, + 3, 6, 9, 12, + }); + // clang-format on + EXPECT_EQ(std::vector(out, out + kZNumVals), expected); +} + +TEST(VecAddmmTest, Smoke) { + // x sizes: (3, 2) + constexpr size_t kXNumVals = 6; + // y sizes: (2, 4) + constexpr size_t kYNumVals = 8; + // z sizes: (3, 4) + constexpr size_t kZNumVals = 12; + + // clang-format off + int64_t self[kZNumVals] = { + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + }; + + int64_t X[kXNumVals] = { + 1, 2, + 2, 1, + 3, 0, + }; + int64_t Y[kYNumVals] = { + 1, 2, 3, 4, + 5, 6, 7, 8, + }; + // clang-format on + + int64_t out[kZNumVals] = {}; + + torch::executor::vec_addmm(out, self, X, Y, 3, 2, 4, 2.0, 3.0); + + // clang-format off + std::vector expected({ + 35, 44, 53, 62, + 25, 34, 43, 52, + 15, 24, 33, 42, + }); + // clang-format on + EXPECT_EQ(std::vector(out, out + kZNumVals), expected); +} + +TEST(VecSoftMaxTest, Smoke) { + // x sizes: (1, 3) + constexpr size_t kXNumVals = 3; + + // clang-format off + float X[kXNumVals] = { + 1, 2, 3, + }; + // clang-format on + float out[kXNumVals] = {}; + + torch::executor::vec_softmax(out, X, 3); + + // clang-format off + std::vector expected({ + 0.0900306, 0.244728, 0.665241, + }); + // clang-format on + for (auto i = 0; i < 3; ++i) { + EXPECT_NEAR(out[i], expected[i], 10e-6); + } +} + +class QuantizeI8F32Test : public ::testing::Test { + protected: + void SetUp() override { + constexpr float kInfinity = std::numeric_limits::infinity(); + // A spread of inputs for various scales and zero points. + inputs_ = { + -kInfinity, -512, -256, -128, -64, 0, 64, 128, 256, 512, kInfinity}; + outputs_.resize(inputs_.size()); + } + + std::vector inputs_; + std::vector outputs_; +}; + +TEST_F(QuantizeI8F32Test, Identity) { + const float kScale = 1.0; // No scaling. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + // Most values will be clamped to min/max uint8_t, but the unclamped values + // should be the same as the inputs. + EXPECT_EQ( + outputs_, + std::vector( + {-128, -128, -128, -128, -64, 0, 64, 127, 127, 127, 127})); +} + +TEST_F(QuantizeI8F32Test, Rounding) { + // Demonstrate that quantization uses roundf() semantics, not + // ceilf()/floorf(). + std::vector in = {-1.9, -1.1, 1.1, 1.9}; + std::vector out; + out.resize(in.size()); + + torch::executor::quantize_i8_f32( + out.data(), in.data(), /*scale=*/1.0, /*zero_point=*/0, in.size()); + + EXPECT_EQ(out, std::vector({-2, -1, 1, 2})); +} + +TEST_F(QuantizeI8F32Test, ScaledDown) { + const float kScale = 0.5; // Scaled down. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector({ + -128, // Clamped + -128, // Clamped + -128, // Clamped + -64, // -128 * 0.5 + -32, // -64 * 0.5 + 0, // 0 * 0.5 + 32, // 64 * 0.5 + 64, // 128 * 0.5 + 127, // Clamped + 127, // Clamped + 127, // Clamped + })); +} + +TEST_F(QuantizeI8F32Test, ShiftedZeroPoint) { + const float kScale = 1.0; // No scaling. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector({ + -128, // Clamped + -128, // Clamped + -128, // Clamped + -96, // -128 + 32 + -32, // -64 + 32 + 32, // 0 + 32 + 96, // 64 + 32 + 127, // Clamped + 127, // Clamped + 127, // Clamped + 127, // Clamped + })); +} + +TEST_F(QuantizeI8F32Test, ScaledDownWithShiftedZeroPoint) { + const float kScale = 0.5; // Scaled down. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + // Demonstrate that the zero point adjustment happens after scaling. + EXPECT_EQ( + outputs_, + std::vector({ + -128, // Clamped + -128, // Clamped + -96, // (-256 * 0.5) + 32 + -32, // (-128 * 0.5) + 32 + 0, // (-64 * 0.5) + 32 + 32, // (0 * 0.5) + 32 + 64, // (64 * 0.5) + 32 + 96, // (128 * 0.5) + 32 + 127, // Clamped + 127, // Clamped + 127, // Clamped + })); +} + +class DequantizeI8F32Test : public ::testing::Test { + protected: + void SetUp() override { + // A spread of inputs for various scales and zero points. + inputs_ = {-128, -64, -32, 0, 32, 64, 127}; + outputs_.resize(inputs_.size()); + } + + std::vector inputs_; + std::vector outputs_; +}; + +TEST_F(DequantizeI8F32Test, Identity) { + const float kScale = 1.0; // No scaling. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ(outputs_, std::vector({-128, -64, -32, 0, 32, 64, 127})); +} + +TEST_F(DequantizeI8F32Test, ScaledUp) { + const float kScale = 2.0; // Scaled up. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector( + {-128 * kScale, + -64 * kScale, + -32 * kScale, + 0 * kScale, + 32 * kScale, + 64 * kScale, + 127 * kScale})); +} + +TEST_F(DequantizeI8F32Test, ShiftedZeroPoint) { + const float kScale = 1.0; // Not scaled. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector( + {-128 - kZeroPoint, + -64 - kZeroPoint, + -32 - kZeroPoint, + 0 - kZeroPoint, + 32 - kZeroPoint, + 64 - kZeroPoint, + 127 - kZeroPoint})); +} + +TEST_F(DequantizeI8F32Test, ScaledUpWithShiftedZeroPoint) { + const float kScale = 2.0; // Scaled up. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + // Demonstrate that the zero point adjustment happens before scaling. + EXPECT_EQ( + outputs_, + std::vector({ + (-128 - kZeroPoint) * kScale, + (-64 - kZeroPoint) * kScale, + (-32 - kZeroPoint) * kScale, + (0 - kZeroPoint) * kScale, + (32 - kZeroPoint) * kScale, + (64 - kZeroPoint) * kScale, + (127 - kZeroPoint) * kScale, + })); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/CMakeLists.txt new file mode 100644 index 0000000..eabf3ad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Kernel library for portable kernels. Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) +endif() + +list(TRANSFORM _kernels_util_all_deps__srcs PREPEND "${EXECUTORCH_ROOT}/") + +set(_common_compile_options + $<$:/wd4996> + $<$>:-Wno-deprecated-declarations> +) + +add_library(kernels_util_all_deps ${_kernels_util_all_deps__srcs}) +target_link_libraries(kernels_util_all_deps PRIVATE executorch_core) +target_include_directories( + kernels_util_all_deps PUBLIC ${_common_include_directories} +) +target_compile_definitions( + kernels_util_all_deps PUBLIC C10_USING_CUSTOM_GENERATED_MACROS +) +target_compile_options(kernels_util_all_deps PUBLIC ${_common_compile_options}) + +install( + TARGETS kernels_util_all_deps + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/activation_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/activation_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/activation_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/activation_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/activation_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/activation_ops_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/activation_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/activation_ops_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/advanced_index_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/advanced_index_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/advanced_index_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/advanced_index_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/advanced_index_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/advanced_index_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/advanced_index_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/advanced_index_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/arange_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/arange_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/arange_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/arange_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/arange_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/arange_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/arange_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/arange_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/broadcast_indexes_range.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/broadcast_indexes_range.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/broadcast_indexes_range.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/broadcast_indexes_range.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/broadcast_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/broadcast_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/broadcast_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/broadcast_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/broadcast_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/broadcast_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/broadcast_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/broadcast_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/copy_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/copy_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/copy_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/copy_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/copy_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/copy_ops_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/copy_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/copy_ops_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/delinearize_index.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/delinearize_index.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/delinearize_index.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/delinearize_index.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/delinearize_index.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/delinearize_index.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/delinearize_index.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/delinearize_index.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/distance_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/distance_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/distance_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/distance_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/distance_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/distance_util.h similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/distance_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/distance_util.h index a54e02d..05406e3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/distance_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/distance_util.h @@ -116,7 +116,7 @@ void pdist(const Tensor& in, Tensor& out, double p) { pdist>(in, out, p); } else if (p == 2.0) { pdist>(in, out, p); - } else if (p == static_cast(INFINITY)) { + } else if (p == INFINITY) { pdist>(in, out, p); } else { pdist>(in, out, p); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/dtype_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/dtype_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/dtype_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/dtype_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/dtype_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/dtype_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/dtype_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/dtype_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/elementwise_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/elementwise_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/elementwise_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/elementwise_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/functional_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/functional_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/functional_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/functional_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/grid_sampler_2d_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/index_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/index_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/index_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/index_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/index_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/index_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/index_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/index_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/kernel_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/kernel_ops_util.cpp similarity index 91% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/kernel_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/kernel_ops_util.cpp index 2e0ceee..daa85f6 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/kernel_ops_util.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/kernel_ops_util.cpp @@ -262,53 +262,6 @@ bool check_arange_args(double start, double end, double step, Tensor& out) { return true; } -bool check_adaptive_avg_pool2d_args( - const Tensor& in, - const IntArrayRef output_size, - const Tensor& out) { - ET_LOG_AND_RETURN_IF_FALSE(tensors_have_same_dtype(in, out)); - - ET_LOG_AND_RETURN_IF_FALSE(tensor_is_default_or_channels_last_dim_order(in)); - ET_LOG_AND_RETURN_IF_FALSE(tensor_is_default_or_channels_last_dim_order(out)); - - ET_CHECK_OR_RETURN_FALSE( - (in.dim() == 3 && in.size(0) > 0 && in.size(1) > 0 && in.size(2) > 0) || - (in.dim() == 4 && in.size(1) > 0 && in.size(2) > 0 && in.size(3) > 0), - "Expected 3D or 4D (batch mode) tensor with optional 0 dim batch size for input; in.dim() = %" ET_PRI_TENSOR_DIM, - in.dim()); - - ET_CHECK_OR_RETURN_FALSE( - output_size.size() == 2, - "output_size must have exactly 2 elements, but got %zu", - output_size.size()); - - ET_CHECK_OR_RETURN_FALSE( - output_size[0] > 0 && output_size[1] > 0, - "output_size must be positive, but got (%" PRId64 ", %" PRId64 ")", - output_size[0], - output_size[1]); - - return true; -} - -void get_adaptive_avg_pool2d_out_target_size( - const Tensor& in, - const IntArrayRef output_size, - executorch::aten::SizesType* const out_sizes, - size_t* const out_ndim) { - *out_ndim = in.dim(); - - if (in.dim() == 4) { - out_sizes[0] = in.size(0); - out_sizes[1] = in.size(1); - } else { - out_sizes[0] = in.size(0); - } - - out_sizes[*out_ndim - 2] = output_size[0]; - out_sizes[*out_ndim - 1] = output_size[1]; -} - bool check_avg_pool2d_args( const Tensor& in, const IntArrayRef kernel_size, @@ -611,14 +564,6 @@ bool check_constant_pad_args( pad.size() / 2, in.dim()); - for (size_t i = 0; i < pad.size(); ++i) { - ET_CHECK_OR_RETURN_FALSE( - pad[i] >= 0, - "Padding values must be non-negative, but got pad[%zu] = %" PRId64, - i, - pad[i]); - } - return true; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/kernel_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/kernel_ops_util.h similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/kernel_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/kernel_ops_util.h index db6ce07..e3eaf4d 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/kernel_ops_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/kernel_ops_util.h @@ -218,7 +218,7 @@ void kernel_reduction_then_map_2d( int64_t padding_y = p_H; int64_t dilation_y = d_H; - ssize_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; + size_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; in_coord[in_dim - 2] = in_y; for (const auto w_x : c10::irange(k_W)) { @@ -226,13 +226,11 @@ void kernel_reduction_then_map_2d( int64_t padding_x = p_W; int64_t dilation_x = d_W; - ssize_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; + size_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; in_coord[in_dim - 1] = in_x; - const bool x_in_bound = - (in_x >= 0 && in_x < static_cast(in_W)); - const bool y_in_bound = - (in_y >= 0 && in_y < static_cast(in_H)); + const bool x_in_bound = (in_x >= 0 && in_x < in_W); + const bool y_in_bound = (in_y >= 0 && in_y < in_H); const bool xy_in_bound = (x_in_bound && y_in_bound); CTYPE in_val = 0; @@ -386,17 +384,6 @@ void apply_kernel_2d_reduce_then_map_fn( // Operator specific utility functions // -bool check_adaptive_avg_pool2d_args( - const Tensor& in, - const IntArrayRef output_size, - const Tensor& out); - -void get_adaptive_avg_pool2d_out_target_size( - const Tensor& in, - const IntArrayRef output_size, - executorch::aten::SizesType* const out_sizes, - size_t* const out_ndim); - bool check_arange_args(double start, double end, double step, Tensor& out); bool check_avg_pool2d_args( diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/math_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/math_util.h similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/math_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/math_util.h index 434c51d..a3a6499 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/math_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/math_util.h @@ -47,8 +47,7 @@ template < type = true> FLOAT_T floor_divide(FLOAT_T a, FLOAT_T b) { if (b == 0) { - return std::signbit(a) ? static_cast(-INFINITY) - : static_cast(INFINITY); + return std::signbit(a) ? -INFINITY : INFINITY; } const auto mod = std::fmod(a, b); auto div = (a - mod) / b; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/matmul_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/matmul_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/matmul_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/matmul_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/matmul_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/matmul_ops_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/matmul_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/matmul_ops_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/normalization_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/normalization_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/normalization_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/normalization_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/normalization_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/normalization_ops_util.h similarity index 50% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/normalization_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/normalization_ops_util.h index d5b5f97..f7bcfa0 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/normalization_ops_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/normalization_ops_util.h @@ -9,54 +9,10 @@ #pragma once #include -#include -#include namespace torch { namespace executor { -/** - * Scalar layer_norm computation over M rows of N elements each. - * Computes mean/variance in float, normalizes with (x - mean) / std * gamma + - * beta. Caller must handle M==0 and N==0 edge cases before calling. - */ -template -inline void layer_norm_scalar( - const CTYPE* input_data, - const CTYPE* weight_data, // nullable - const CTYPE* bias_data, // nullable - CTYPE* out_data, - CTYPE* mean_data, - CTYPE* rstd_data, - size_t M, - size_t N, - float eps) { - for (size_t i = 0; i < M; ++i) { - const CTYPE* x = input_data + i * N; - CTYPE* y = out_data + i * N; - - // compute E[X] and Var[x] = E[x^2] - E[x]^2 - float sum = std::accumulate(x, x + N, 0.0f); - float sq_sum = 0; - for (size_t j = 0; j < N; ++j) { - sq_sum += static_cast(x[j]) * x[j]; - } - float mean_value = sum / N; - float variance = sq_sum / N - mean_value * mean_value; - float std = std::sqrt(variance + eps); - - // Calculate the elements of output - for (size_t j = 0; j < N; ++j) { - CTYPE w = weight_data ? weight_data[j] : static_cast(1); - CTYPE b = bias_data ? bias_data[j] : static_cast(0); - y[j] = (x[j] - mean_value) / std * w + b; - } - - mean_data[i] = mean_value; - rstd_data[i] = 1.0 / std; - } -} - bool check_batch_norm_args( const Tensor& in, const std::optional& weight, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/padding_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/padding_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/padding_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/padding_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/padding_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/padding_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/padding_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/padding_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/reduce_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/reduce_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/reduce_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/reduce_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/reduce_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/reduce_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/reduce_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/reduce_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/repeat_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/repeat_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/repeat_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/repeat_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/repeat_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/repeat_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/repeat_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/repeat_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/select_copy_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/select_copy_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/select_copy_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/select_copy_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/select_copy_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/select_copy_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/select_copy_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/select_copy_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/slice_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/slice_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/slice_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/slice_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/slice_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/slice_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/slice_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/slice_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/stack_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/stack_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/stack_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/stack_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/stack_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/stack_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/stack_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/stack_util.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/targets.bzl new file mode 100644 index 0000000..1fd1e61 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/targets.bzl @@ -0,0 +1,383 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Note: add all portable_op dependencies to all_deps. This is used for dtype selective + # build, where the portable ops are built from source and linked with :all_deps + runtime.cxx_library( + name = "all_deps", + exported_deps = [ + "//executorch/extension/threadpool:threadpool", + "//executorch/kernels/portable/cpu/util:arange_util", + "//executorch/kernels/portable/cpu/util:functional_util", + "//executorch/kernels/portable/cpu/util:broadcast_util", + "//executorch/kernels/portable/cpu/util:kernel_ops_util", + "//executorch/kernels/portable/cpu:vec_ops", + "//executorch/kernels/portable/cpu/util:matmul_ops_util", + "//executorch/kernels/portable/cpu/util:copy_ops_util", + "//executorch/kernels/portable/cpu/util:transpose_util", + "//executorch/kernels/portable/cpu/util:index_util", + "//executorch/kernels/portable/cpu/util:math_util", + "//executorch/kernels/portable/cpu/util:padding_util", + "//executorch/kernels/portable/cpu/util:repeat_util", + "//executorch/kernels/portable/cpu/util:activation_ops_util", + "//executorch/kernels/portable/cpu/util:reduce_util", + "//executorch/kernels/portable/cpu/util:normalization_ops_util", + "//executorch/kernels/portable/cpu/util:distance_util", + "//executorch/kernels/portable/cpu/util:select_copy_util", + "//executorch/kernels/portable/cpu/util:advanced_index_util", + "//executorch/kernels/portable/cpu/util:slice_util", + "//executorch/kernels/portable/cpu/util:stack_util", + "//executorch/kernels/portable/cpu/util:elementwise_util", + "//executorch/kernels/portable/cpu/util:upsample_util", + "//executorch/kernels/portable/cpu/util:vectorized_math", + "//executorch/kernels/portable/cpu/util:grid_sampler_2d_util", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "activation_ops_util", + srcs = ["activation_ops_util.cpp"], + exported_headers = [ + "activation_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "repeat_util", + srcs = [ + "repeat_util.cpp", + ], + exported_headers = ["repeat_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "broadcast_util", + srcs = [ + "broadcast_util.cpp", + "delinearize_index.cpp", + ], + exported_headers = [ + "broadcast_util.h", + "delinearize_index.h", + ], + exported_deps = [ + ":broadcast_indexes_range", + ], + deps = [ + ":repeat_util", + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "dtype_util", + srcs = ["dtype_util.cpp"], + exported_headers = [ + "dtype_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "elementwise_util", + exported_headers = [ + "elementwise_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + exported_deps = [ + ":broadcast_indexes_range", + ":broadcast_util", + ":dtype_util", + ":vectorized_math", + "//executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch", + "//executorch/runtime/kernel:kernel_runtime_context", + "//executorch/kernels/portable/cpu:scalar_utils", + "//executorch/extension/threadpool:threadpool", + "//executorch/kernels/portable/cpu:scalar_utils", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "advanced_index_util", + srcs = ["advanced_index_util.cpp"], + exported_headers = [ + "advanced_index_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + ":broadcast_util", + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "copy_ops_util", + srcs = ["copy_ops_util.cpp"], + exported_headers = [ + "copy_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + exported_deps = [ + ":broadcast_util", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "distance_util", + srcs = ["distance_util.cpp"], + exported_headers = [ + "distance_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "kernel_ops_util", + srcs = ["kernel_ops_util.cpp"], + exported_headers = [ + "kernel_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "matmul_ops_util", + srcs = ["matmul_ops_util.cpp"], + exported_headers = [ + "matmul_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + ":broadcast_util", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "padding_util", + srcs = ["padding_util.cpp"], + exported_headers = [ + "padding_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "normalization_ops_util", + srcs = ["normalization_ops_util.cpp"], + exported_headers = [ + "normalization_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "transpose_util", + exported_headers = [ + "transpose_util.h", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + # Utility functions that can be used by operators that perform indexing + runtime.cxx_library( + name = "index_util", + srcs = ["index_util.cpp"], + exported_headers = ["index_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/quantized/..."], + ) + + # Utility functions that can be used by operators that repeat the same computation for each element in the tensor + # Note that because this is a header only library, targets must also depend on broadcast_util. + runtime.cxx_library( + name = "functional_util", + srcs = [], + exported_headers = ["functional_util.h"], + exported_deps = [ + "//executorch/extension/threadpool:threadpool", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ":broadcast_util", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "math_util", + srcs = [], + exported_headers = ["math_util.h"], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/quantized/..."], + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch", + ], + ) + + runtime.cxx_library( + name = "select_copy_util", + srcs = ["select_copy_util.cpp"], + exported_headers = ["select_copy_util.h"], + deps = [ + ":copy_ops_util", + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "slice_util", + srcs = ["slice_util.cpp"], + exported_headers = ["slice_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/extension/threadpool:threadpool", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "stack_util", + srcs = ["stack_util.cpp"], + exported_headers = ["stack_util.h"], + deps = [ + "//executorch/kernels/portable/cpu/util:copy_ops_util", + ], + exported_deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "upsample_util", + srcs = ["upsample_util.cpp"], + exported_headers = ["upsample_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "broadcast_indexes_range", + exported_headers = ["broadcast_indexes_range.h"], + deps = [ + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "vectorized_math", + exported_headers = ["vectorized_math.h"], + visibility = ["//executorch/..."], + exported_deps = [ + "//executorch/runtime/core/portable_type:portable_type", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + ], + ) + + runtime.cxx_library( + name = "grid_sampler_2d_util", + srcs = ["grid_sampler_2d_util.cpp"], + exported_headers = ["grid_sampler_2d_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + # Utility functions that can be used by operators that perform reduction + for aten_mode in get_aten_mode_options(): + suffix = "_aten" if aten_mode else "" + runtime.cxx_library( + name = "reduce_util{}".format(suffix), + srcs = ["reduce_util.cpp"], + exported_headers = ["reduce_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes{}".format(suffix), + "//executorch/runtime/core/exec_aten/util:tensor_util{}".format(suffix), + ], + exported_deps = [ + "//executorch/extension/threadpool:threadpool", + ], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "arange_util{}".format(suffix), + srcs = ["arange_util.cpp"], + exported_headers = ["arange_util.h"], + exported_deps = [ + "//executorch/runtime/kernel:kernel_includes{}".format(suffix), + ], + visibility = [ + "//executorch/kernels/portable/cpu/...", + "//executorch/extension/llm/...", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/CMakeLists.txt new file mode 100644 index 0000000..33ca3db --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) + +set(_test_srcs broadcast_indexes_range_test.cpp broadcast_test.cpp + reduce_test.cpp vectorized_math_test.cpp +) + +et_cxx_test( + kernels_portable_cpu_util_test SOURCES ${_test_srcs} EXTRA_LIBS + portable_kernels portable_ops_lib +) + +find_package_torch_headers() +target_include_directories( + kernels_portable_cpu_util_test PRIVATE ${TORCH_INCLUDE_DIRS} +) +target_compile_definitions( + kernels_portable_cpu_util_test PRIVATE ET_USE_PYTORCH_HEADERS +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp new file mode 100644 index 0000000..42fd248 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include + +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::testing::TensorFactory; +using torch::executor::BroadcastIndexesRange; +using torch::executor::delinearize_index; +using torch::executor::linearize_access_indexes; + +namespace { +template +auto range_to_vec(const Range& rng) { + return std::vector( + rng.begin(), rng.end()); +} +} // namespace +TEST(BroadcastIndexesRangeTest, Empty) { + TensorFactory tf; + + Tensor a = tf.make({0}, {}); + ASSERT_EQ(a.numel(), 0); + bool loop_entered = false; + for (auto _ : BroadcastIndexesRange<1>(a, a)) { + loop_entered = true; + } + EXPECT_FALSE(loop_entered); +} + +// [W] -> [W] +TEST(BroadcastIndexesRangeTest, OneDNotBroadcasted) { + TensorFactory tf; + + Tensor out = tf.zeros({5}); + int idx = 0; + const auto range = BroadcastIndexesRange<1>(out, out); + for (const auto& elem : range_to_vec(range)) { + EXPECT_EQ(*(range.begin() + idx), elem); + EXPECT_EQ(elem[0], idx++); + EXPECT_EQ(elem[0], elem[1]); + } +} + +template +void test_operator_plus(const Range& range) { + size_t idx = 0; + for (const auto& indexes : range) { + EXPECT_EQ(*(range.begin() + idx), indexes); + idx++; + } +} + +// [1] -> [H, W] +// [W] -> [H, W] +// [1, 1] -> [H, W] +// [1, W] -> [H, W] +// [H, 1] -> [H, W] +// [H, W] -> [H, W] +// Cover all these at the same time to also exercise multiple input tensors. +TEST(BroadcastIndexesRangeTest, OneAndTwoDExhaustive) { + TensorFactory tf; + Tensor out = tf.zeros({3, 4}); + Tensor in_0d_scalar = tf.zeros({}); + Tensor in_1d_scalar = tf.zeros({1}); + Tensor in_2d_scalar = tf.zeros({1, 1}); + + Tensor in_row = tf.zeros({4}); + Tensor in_col = tf.zeros({3, 1}); + + Tensor in_not_broadcast = tf.zeros({3, 4}); + + const auto range = BroadcastIndexesRange<6>( + out, + in_0d_scalar, + in_1d_scalar, + in_2d_scalar, + in_row, + in_col, + in_not_broadcast); + auto actual = range_to_vec(range); + decltype(actual) expected = { + {0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 1, 0, 1}, + {2, 0, 0, 0, 2, 0, 2}, + {3, 0, 0, 0, 3, 0, 3}, + {4, 0, 0, 0, 0, 1, 4}, + {5, 0, 0, 0, 1, 1, 5}, + {6, 0, 0, 0, 2, 1, 6}, + {7, 0, 0, 0, 3, 1, 7}, + {8, 0, 0, 0, 0, 2, 8}, + {9, 0, 0, 0, 1, 2, 9}, + {10, 0, 0, 0, 2, 2, 10}, + {11, 0, 0, 0, 3, 2, 11}, + }; + EXPECT_EQ(expected, actual); + + test_operator_plus(range); +} + +// Make sure nothing is thrown off by a size-1 dim in the output: +// [] -> [1, W] +// [] -> [H, 1] +// [1] -> [1, W] +// [1] -> [H, 1] +// [W] -> [1, W] +// [1, 1] -> [1, W] +// [1, 1] -> [H, 1] +// [1, W] -> [1, W] +// [H, 1] -> [H, 1] +TEST(BroadcastIndexesRangeTest, OneAndTwoDWith1InOutputShapeExhaustive) { + TensorFactory tf; + constexpr auto H = 2; + constexpr auto W = 3; + Tensor out_row = tf.zeros({1, W}); + Tensor out_col = tf.zeros({H, 1}); + Tensor in_0d_scalar = tf.zeros({}); + Tensor in_1d_scalar = tf.zeros({1}); + Tensor in_2d_scalar = tf.zeros({1, 1}); + + Tensor in_row = tf.zeros({W}); + Tensor in_leading_one_row = tf.zeros({1, W}); + + Tensor in_col = tf.zeros({H, 1}); + + size_t idx = 0; + const auto range_row = BroadcastIndexesRange<5>( + out_row, + in_0d_scalar, + in_1d_scalar, + in_2d_scalar, + in_row, + in_leading_one_row); + for (const auto + [out_idx, + in_0d_idx, + in_1d_idx, + in_2d_idx, + in_row_idx, + in_leading_one_row_idx] : range_row) { + EXPECT_EQ(out_idx, idx++); + EXPECT_EQ(in_0d_idx, 0); + EXPECT_EQ(in_1d_idx, 0); + EXPECT_EQ(in_2d_idx, 0); + EXPECT_EQ(in_row_idx, out_idx); + EXPECT_EQ(in_leading_one_row_idx, out_idx); + } + + test_operator_plus(range_row); + + idx = 0; + const auto range_col = BroadcastIndexesRange<4>( + out_col, in_0d_scalar, in_1d_scalar, in_2d_scalar, in_col); + for (const auto [out_idx, in_0d_idx, in_1d_idx, in_2d_idx, in_col_idx] : + range_col) { + EXPECT_EQ(out_idx, idx++); + EXPECT_EQ(in_0d_idx, 0); + EXPECT_EQ(in_1d_idx, 0); + EXPECT_EQ(in_2d_idx, 0); + EXPECT_EQ(in_col_idx, out_idx); + } + + test_operator_plus(range_col); +} + +// [1, 1, 1] -> [C, H, W] +// [C, H, 1] -> [C, H, W] +// [C, 1, W] -> [C, H, W] +// [1, H, W] -> [C, H, W] +// [C, 1, 1] -> [C, H, W] +// [1, H, 1] -> [C, H, W] +// [1, 1, W] -> [C, H, W] +// [C, H, W] -> [C, H, W] +TEST(BroadcastIndexesRangeTest, ThreeDBroadcasting) { + TensorFactory tf; + Tensor out = tf.zeros({2, 3, 4}); + std::array input_tensors = { + tf.zeros({2, 3, 1}), + tf.zeros({2, 1, 4}), + tf.zeros({1, 3, 4}), + tf.zeros({2, 1, 1}), + tf.zeros({1, 3, 1}), + tf.zeros({1, 1, 4}), + tf.zeros({1, 1, 1}), + tf.zeros({2, 3, 4}), + }; + // Writing out all the indexes would be too cumbersome, so here we + // take the opportunity to mutation test against delinearize_index + // and linearize_access_indexes. + int idx = 0; + const auto range = BroadcastIndexesRange<8>( + out, + input_tensors[0], + input_tensors[1], + input_tensors[2], + input_tensors[3], + input_tensors[4], + input_tensors[5], + input_tensors[6], + input_tensors[7]); + for (const auto indexes : range) { + const auto out_idx = indexes[0]; + EXPECT_EQ(out_idx, idx++); + size_t out_indexes[executorch::runtime::kTensorDimensionLimit]; + delinearize_index( + out_idx, out, out_indexes, executorch::runtime::kTensorDimensionLimit); + for (const auto tensor_idx : c10::irange(0, input_tensors.size())) { + EXPECT_EQ( + indexes[tensor_idx + 1], + linearize_access_indexes( + out_indexes, out.dim(), input_tensors[tensor_idx])); + } + } + test_operator_plus(range); +} + +// 4-D should generalize, but we will go ahead and test: +// [N, 1, H, 1] -> [N, C, H, W] +// [1, C, 1, W] -> [N, C, H, W] +template +void four_d_broadcasting_test() { + TensorFactory tf; + Tensor out = tf.zeros({N, C, H, W}); + Tensor in_broadcast_cw = tf.zeros({N, 1, H, 1}); + Tensor in_broadcast_nh = tf.zeros({1, C, 1, W}); + + // Writing out all the indexes would be too cumbersome, so here we + // take the opportunity to mutation test against delinearize_index + // and linearize_access_indexes. + int idx = 0; + const auto range = + BroadcastIndexesRange<2>(out, in_broadcast_cw, in_broadcast_nh); + for (const auto [out_idx, in_cw_idx, in_nh_idx] : range) { + EXPECT_EQ(out_idx, idx++); + size_t out_indexes[executorch::runtime::kTensorDimensionLimit]; + delinearize_index( + out_idx, out, out_indexes, executorch::runtime::kTensorDimensionLimit); + EXPECT_EQ( + in_cw_idx, + linearize_access_indexes(out_indexes, out.dim(), in_broadcast_cw)); + EXPECT_EQ( + in_nh_idx, + linearize_access_indexes(out_indexes, out.dim(), in_broadcast_nh)); + } + + test_operator_plus(range); +} + +TEST(BroadcastIndexesRangeTest, FourDBroadcasting) { + four_d_broadcasting_test<2, 3, 4, 5>(); +} + +TEST(BroadcastIndexesRangeTest, FourDBroadcastingWithOneDimsInOutput) { + four_d_broadcasting_test<2, 3, 1, 5>(); + four_d_broadcasting_test<2, 1, 3, 1>(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_test.cpp new file mode 100644 index 0000000..7ffd95b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/broadcast_test.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::ArrayRef; +using executorch::runtime::testing::TensorFactory; +using torch::executor::broadcast_tensor; +using torch::executor::delinearize_index; +using torch::executor::get_broadcast_target_size; +using torch::executor::linearize_access_indexes; +using torch::executor::tensor_is_broadcastable_to; +using torch::executor::tensors_are_broadcastable_between; + +TEST(BroadcastUtilTest, BroadcastTensor) { + TensorFactory tf; + + Tensor a = tf.make({1}, {2}); + Tensor b = tf.make({2, 2}, {2, 2, 2, 2}); + Tensor c = tf.zeros({2, 2}); + + Tensor d = torch::executor::broadcast_tensor(a, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); + + d = torch::executor::broadcast_tensor(b, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); +} + +TEST(BroadcastUtilTest, BroadcastableBetween) { + TensorFactory tf; + + std::vector tensor_list = { + tf.zeros({1, 2}), tf.zeros({2, 1}), tf.zeros({1}), tf.zeros({2, 2})}; + + for (int i = 0; i < 4; i++) { + for (int j = i + 1; j < 4; j++) { + EXPECT_TRUE( + tensors_are_broadcastable_between(tensor_list[i], tensor_list[j])); + } + } +} + +TEST(BroadcastUtilTest, BroadcastableToFrom) { + TensorFactory tf; + + Tensor a = tf.make({1, 2}, {2, 2}); + Tensor b = tf.make({2, 1}, {2, 2}); + Tensor c = tf.zeros({2, 2}); + + ASSERT_TRUE(tensor_is_broadcastable_to(a, c)); + Tensor d = torch::executor::broadcast_tensor(a, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); + + ASSERT_TRUE(tensor_is_broadcastable_to(b, c)); + d = torch::executor::broadcast_tensor(b, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); +} + +TEST(BroadcastUtilTest, NotBroadcastableTo) { + TensorFactory tf; + + // Tensor a is broadcastable to tensor b means when tracing their sizes from + // back to front, each pair of corresponding dimensions should meet one of the + // following conditions: + // 1. the two dimensions are equal; + // 2. a's dimension is 1; + // 3. one of the dimensions does not exist. + Tensor a = tf.make({3}, {2, 2, 2}); + Tensor b = tf.zeros({2, 1}); + Tensor c = tf.zeros({1, 2}); + + ASSERT_FALSE(tensor_is_broadcastable_to(a, b)); + ET_EXPECT_DEATH(broadcast_tensor(a, b), ""); + + // Can not broadcast from b to c, though they are broadcastable. + // When broadcasting, b and c should be broadcasted to a new size (2, 2). + // Neither of them can be broadcasted to each other's size. + ASSERT_FALSE(tensor_is_broadcastable_to(b, c)); + ET_EXPECT_DEATH(broadcast_tensor(b, c), ""); +} + +TEST(BroadcastUtilTest, NotBroadcastableBetween) { + TensorFactory tf; + + Tensor a = tf.make({3}, {2, 2, 2}); + Tensor b = tf.zeros({2, 1}); + + EXPECT_FALSE(tensor_is_broadcastable_to(a, b)); +} + +TEST(BroadcastUtilTest, GetBroadcastTargetSize) { + TensorFactory tf; + Tensor::SizesType + expected_output_size[torch::executor::kTensorDimensionLimit] = {}; + size_t expected_output_dim = 0; + + Tensor a = tf.zeros({2, 1}); + Tensor b = tf.zeros({5, 1, 2}); + + executorch::runtime::Error err = get_broadcast_target_size( + a, + b, + expected_output_size, + torch::executor::kTensorDimensionLimit, + &expected_output_dim); + EXPECT_EQ(err, torch::executor::Error::Ok); + + EXPECT_TRUE( + ArrayRef(expected_output_size, expected_output_dim) + .equals(ArrayRef({5, 2, 2}))); + + Tensor c = tf.zeros({4, 5}); + et_pal_init(); + err = get_broadcast_target_size( + a, + c, + expected_output_size, + torch::executor::kTensorDimensionLimit, + &expected_output_dim); + EXPECT_EQ(err, torch::executor::Error::InvalidArgument); +} + +size_t linearize_indexes(size_t* indexes, size_t indexes_len, const Tensor& t) { + size_t linear_index = 0; + size_t acc_loop_counts = 1; + for (ssize_t i = indexes_len - 1; i >= 0; --i) { + linear_index += indexes[i] * acc_loop_counts; + acc_loop_counts *= (size_t)t.sizes()[i]; + } + return linear_index; +} + +TEST(BroadcastUtilTest, DelinearizeIndex) { + TensorFactory tf; + + const size_t DIMS = 3; + Tensor t = tf.zeros({4, 3, 5}); + auto sizes = t.sizes(); + + for (size_t i0 = 0; i0 < (size_t)sizes[0]; ++i0) { + for (size_t i1 = 0; i1 < (size_t)sizes[1]; ++i1) { + for (size_t i2 = 0; i2 < (size_t)sizes[2]; ++i2) { + size_t indexes[DIMS] = {i0, i1, i2}; + auto linear_index = linearize_indexes(indexes, DIMS, t); + + size_t out_indexes[DIMS]; + delinearize_index(linear_index, t, out_indexes, DIMS); + + EXPECT_EQ(linear_index, linearize_indexes(out_indexes, DIMS, t)); + } + } + } +} + +TEST(BroadcastUtilTest, LinearizeIndex) { + TensorFactory tf; + + Tensor broadcast_from = tf.zeros({2, 1, 3, 1}); + Tensor broadcast_to = tf.zeros({2, 2, 3, 4}); + + // The linear index for brodcast_from should be the same in + // the brocasted dimension. + for (size_t i = 0; i < 3; ++i) { + size_t test_indexes[] = {0, 0, 0, i}; + ArrayRef broadcast_to_indexes(test_indexes); + size_t linear_index = linearize_access_indexes( + broadcast_to_indexes, broadcast_to.dim(), broadcast_from); + EXPECT_EQ(linear_index, 0); + } + + // The linear index for brodcast_from should be the same. + // the brocasted dimension. + for (size_t i = 0; i <= 2; ++i) { + size_t test_indexes[] = {0, i, 2, 3}; + ArrayRef broadcast_to_indexes(test_indexes); + size_t linear_index = linearize_access_indexes( + broadcast_to_indexes, broadcast_to.dim(), broadcast_from); + EXPECT_EQ(linear_index, 2); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/reduce_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/reduce_test.cpp new file mode 100644 index 0000000..69e1093 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/reduce_test.cpp @@ -0,0 +1,583 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::testing::TensorFactory; +using std::optional; +using torch::executor::apply_over_dim; +using torch::executor::apply_over_dim_list; +using torch::executor::get_out_numel; + +void _apply_over_dim(const Tensor& in, const optional& dim) { + int64_t* in_data = in.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim); ++out_ix) { + apply_over_dim( + [in_data, out_ix](size_t in_ix, size_t _) { in_data[in_ix] = out_ix; }, + in, + dim, + out_ix); + } +} + +void _apply_over_dim_list( + const Tensor& in, + const optional>& dim_list) { + int64_t* in_data = in.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim_list); ++out_ix) { + apply_over_dim_list( + [in_data, out_ix](size_t in_ix) { in_data[in_ix] = out_ix; }, + in, + dim_list, + out_ix); + } +} + +TEST(ReduceUtilTest, ApplyOverDim) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + _apply_over_dim(in, 0); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + _apply_over_dim(in, 1); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_2[1] = {2}; + dim_list = optional>(ArrayRef{dim_array_2, 1}); + _apply_over_dim(in, 2); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + + 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, + 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, + 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, + 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_3[1] = {3}; + dim_list = optional>(ArrayRef{dim_array_3, 1}); + _apply_over_dim(in, 3); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + + 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, + 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, + 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListNull) { + TensorFactory tf; + optional> null_dim_list; + + Tensor in = tf.ones({2, 4, 5, 3}); + _apply_over_dim_list(in, null_dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({2, 4, 5, 3})); +} + +TEST(ReduceUtilTest, ApplyOverZeroDimListEmpty) { + TensorFactory tf; + optional> null_dim_list; + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, null_dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({})); +} + +TEST(ReduceUtilTest, ApplyOverZeroDim) { + TensorFactory tf; + optional> dim_list; + int64_t dim_array_0[1] = {0}; + dim_list = optional>(ArrayRef{dim_array_0, 1}); + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({})); +} + +TEST(ReduceUtilTest, ApplyOverDimListEmpty) { + TensorFactory tf; + optional> empty_dim_list{ArrayRef{}}; + + Tensor in = tf.ones({2, 4, 5, 3}); + _apply_over_dim_list(in, empty_dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({2, 4, 5, 3})); +} + +TEST(ReduceUtilTest, ApplyOverDimListLength1) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_0[1] = {0}; + dim_list = optional>(ArrayRef{dim_array_0, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_1[1] = {1}; + dim_list = optional>(ArrayRef{dim_array_1, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_2[1] = {2}; + dim_list = optional>(ArrayRef{dim_array_2, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + + 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, + 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, + 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, + 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_3[1] = {3}; + dim_list = optional>(ArrayRef{dim_array_3, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + + 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, + 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, + 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListLength2) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_01[2] = {0, 1}; + dim_list = optional>(ArrayRef{dim_array_01, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_02[2] = {0, 2}; + dim_list = optional>(ArrayRef{dim_array_02, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_03[2] = {0, 3}; + dim_list = optional>(ArrayRef{dim_array_03, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_12[2] = {1, 2}; + dim_list = optional>(ArrayRef{dim_array_12, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_13[2] = {1, 3}; + dim_list = optional>(ArrayRef{dim_array_13, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_23[2] = {2, 3}; + dim_list = optional>(ArrayRef{dim_array_23, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListLength3) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_012[3] = {0, 1, 2}; + dim_list = optional>(ArrayRef{dim_array_012, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_013[3] = {0, 1, 3}; + dim_list = optional>(ArrayRef{dim_array_013, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_023[3] = {0, 2, 3}; + dim_list = optional>(ArrayRef{dim_array_023, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_123[3] = {1, 2, 3}; + dim_list = optional>(ArrayRef{dim_array_123, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListLength4) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.ones({2, 4, 5, 3}); + int64_t dim_array_0123[4] = {0, 1, 2, 3}; + dim_list = optional>(ArrayRef{dim_array_0123, 4}); + _apply_over_dim_list(in, dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({2, 4, 5, 3})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDim) { + TensorFactory tf; + + Tensor in = tf.ones({}); + _apply_over_dim(in, 0); + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDimListNull) { + TensorFactory tf; + optional> null_dim_list; + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, null_dim_list); + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDimListEmpty) { + TensorFactory tf; + optional> empty_dim_list{ArrayRef{}}; + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, empty_dim_list); + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDimListNonEmpty) { + TensorFactory tf; + int64_t dim_array_0[1] = {0}; + optional> dim_list = + optional>(ArrayRef{dim_array_0, 1}); + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, dim_list), ""; + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnEmptyTensorOverDim) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 0, 5, 3}); + Tensor out = tf.zeros({2, 5, 3}); + + // dim = 1 + int64_t dim = 1; + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(out.numel() == 30 && out.numel() == get_out_numel(in, dim)); + + int64_t* in_data = in.mutable_data_ptr(); + int64_t* out_data = out.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim); ++out_ix) { + out_data[out_ix] = 1; + apply_over_dim( + [in_data, out_data, out_ix](size_t in_ix, size_t _) { + in_data[in_ix] = out_ix; // Should be ignored. + out_data[out_ix] = 2; // Should be ignored. + }, + in, + dim, + out_ix); + } + EXPECT_TENSOR_EQ(out, tf.ones({2, 5, 3})); + + // dim = 0 + dim = 0; + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(get_out_numel(in, dim) == 0); + // Should die if called on empty tensor with dim that also produces + // empty tensor, because out_ix will be out of bounds + ET_EXPECT_DEATH( + apply_over_dim([](size_t in_ix, size_t _) { return; }, in, dim, 0), ""); +} + +TEST(ReduceUtilTest, ApplyOnEmptyTensorOverDimList) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 0, 5, 3}); + Tensor out = tf.zeros({5, 3}); + + // dim list = {0, 1} + int64_t dim_array_01[2] = {0, 1}; + dim_list = optional>(ArrayRef{dim_array_01, 2}); + + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(out.numel() == 15 && out.numel() == get_out_numel(in, dim_list)); + + int64_t* in_data = in.mutable_data_ptr(); + int64_t* out_data = out.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim_list); ++out_ix) { + out_data[out_ix] = 1; + apply_over_dim_list( + [in_data, out_data, out_ix](size_t in_ix) { + in_data[in_ix] = out_ix; // Should be ignored. + out_data[out_ix] = 2; // Should be ignored. + }, + in, + dim_list, + out_ix); + } + EXPECT_TENSOR_EQ(out, tf.ones({5, 3})); + + // dim list = {0, 2} + int64_t dim_array_02[2] = {0, 2}; + dim_list = optional>(ArrayRef{dim_array_02, 2}); + + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(get_out_numel(in, dim_list) == 0); + // Should die if called on empty tensor with dim list that also produces + // empty tensor, because out_ix will be out of bounds + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); +} + +TEST(ReduceUtilTest, ApplyOverDimListInvalid) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_09[2] = {0, 9}; + dim_list = optional>(ArrayRef{dim_array_09, 2}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); + + int64_t dim_array_neg[3] = {0, -5, 3}; + dim_list = optional>(ArrayRef{dim_array_neg, 3}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); + + int64_t dim_array_011[3] = {0, 1, 1}; + dim_list = optional>(ArrayRef{dim_array_011, 3}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); + + int64_t dim_array_1_3[2] = {1, -3}; + dim_list = optional>(ArrayRef{dim_array_1_3, 2}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/targets.bzl new file mode 100644 index 0000000..69ca7d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/targets.bzl @@ -0,0 +1,45 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + runtime.cxx_test( + name = "broadcast_test", + srcs = ["broadcast_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core:evalue", + "//executorch/kernels/portable/cpu/util:broadcast_util", + ], + ) + + runtime.cxx_test( + name = "broadcast_indexes_range_test", + srcs = ["broadcast_indexes_range_test.cpp"], + deps = [ + "//executorch/kernels/portable/cpu/util:broadcast_util", + "//executorch/kernels/portable/cpu/util:broadcast_indexes_range", + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ], + ) + + runtime.cxx_test( + name = "reduce_test", + srcs = ["reduce_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/kernels/portable/cpu/util:reduce_util", + ], + ) + + # this test requires ET_USE_PYTORCH_HEADERS, which doesn't work in OSS Buck. + if not runtime.is_oss: + runtime.cxx_test( + name = "vectorized_math_test", + srcs = ["vectorized_math_test.cpp"], + deps = [ + "//executorch/kernels/portable/cpu/util:vectorized_math", + "//executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/vectorized_math_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/vectorized_math_test.cpp new file mode 100644 index 0000000..6911598 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/test/vectorized_math_test.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +#include + +#ifndef ET_USE_PYTORCH_HEADERS +#error "This test requires ET_USE_PYTORCH_HEADERS!" +#endif // ET_USE_PYTORCH_HEADERS + +TEST(VectorizedMathTest, BasicUnary) { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto result_vec = executorch::math::exp(x_vec); + result_vec.store(result_floats); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_FLOAT_EQ(result_floats[ii], std::exp(ii)); + } +} + +namespace { +template +void test_unary_t_to_float() { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto result_vec = executorch::math::exp(x_vec); + static_assert(decltype(result_vec)::size() >= at::vec::Vectorized::size()); + result_vec.store(result_floats, at::vec::Vectorized::size()); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_FLOAT_EQ(result_floats[ii], std::exp((float)ii)) << ii; + } +} + +} // namespace + +TEST(VectorizedMathTest, UnaryInt16ToFloat) { + test_unary_t_to_float(); +} + +TEST(VectorizedMathTest, UnaryInt32ToFloat) { + test_unary_t_to_float(); +} + +TEST(VectorizedMathTest, UnaryInt64ToFloat) { + test_unary_t_to_float(); +} + +TEST(VectorizedMathTest, BasicBinary) { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto y_vec = at::vec::Vectorized(2); + const auto result_vec = executorch::math::pow(x_vec, y_vec); + result_vec.store(result_floats); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_FLOAT_EQ(result_floats[ii], std::pow((float)ii, 2.0f)); + } +} + +namespace { +template +void test_binary_t_to_float() { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto y_vec = at::vec::Vectorized(2); + const auto result_vec = executorch::math::pow(x_vec, y_vec); + static_assert(decltype(result_vec)::size() >= at::vec::Vectorized::size()); + result_vec.store(result_floats, at::vec::Vectorized::size()); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_EQ(result_floats[ii], std::pow((float)ii, 2.0f)) << ii; + } +} + +TEST(VectorizedMathTest, BinaryInt16ToFloat) { + test_binary_t_to_float(); +} + +TEST(VectorizedMathTest, BinaryInt32ToFloat) { + test_binary_t_to_float(); +} + +TEST(VectorizedMathTest, BinaryInt64ToFloat) { + test_binary_t_to_float(); +} + +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/transpose_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/transpose_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/transpose_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/transpose_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/upsample_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/upsample_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/upsample_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/upsample_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/upsample_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/upsample_util.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/upsample_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/upsample_util.h index 6940c63..7ac1fec 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/upsample_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/upsample_util.h @@ -1,7 +1,6 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2026 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -9,8 +8,6 @@ #pragma once -#include - #include #include #include @@ -101,8 +98,8 @@ inline void guard_index_and_lambda( const int64_t& input_size, int64_t& input_index, scalar_t& lambda) { - input_index = std::min( - static_cast(std::floor(real_input_index)), input_size - 1); + input_index = + std::min(static_cast(floorf(real_input_index)), input_size - 1); lambda = std::min( std::max(real_input_index - input_index, static_cast(0)), static_cast(1)); @@ -143,8 +140,8 @@ inline int64_t nearest_neighbor_compute_source_index( int64_t input_size) { // Index computation matching OpenCV INTER_NEAREST // which is buggy and kept for BC - const int64_t src_index = std::min( - static_cast(std::floor(dst_index * scale)), input_size - 1); + const int64_t src_index = + std::min(static_cast(floorf(dst_index * scale)), input_size - 1); return src_index; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/vectorized_math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/vectorized_math.h similarity index 99% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/vectorized_math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/vectorized_math.h index f81236b..e67e862 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/vectorized_math.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/util/vectorized_math.h @@ -1,7 +1,6 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2026 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -15,6 +14,7 @@ #include #endif // ET_USE_PYTORCH_HEADERS +#include #include #if defined(ET_USE_PYTORCH_HEADERS) && ET_USE_PYTORCH_HEADERS diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/vec_ops.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/vec_ops.h similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/vec_ops.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/vec_ops.h index 16a9e93..87dd05a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/vec_ops.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/cpu/vec_ops.h @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2024,2026 Arm Limited and/or its affiliates. + * Copyright 2024 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include /** * @file @@ -177,7 +179,7 @@ template inline float vec_powerf(const T* x, size_t size) { float sum = 0; for (const auto i : c10::irange(size)) { - sum += static_cast(x[i]) * x[i]; + sum += x[i] * x[i]; } return sum; } @@ -199,7 +201,7 @@ inline void vec_softmax(T* ET_RESTRICT y, const U* ET_RESTRICT x, int n) { T sum = 0; for (const auto i : c10::irange(n)) { - y[i] = std::exp(x[i] - max_x); + y[i] = expf(x[i] - max_x); sum += y[i]; } @@ -228,7 +230,7 @@ inline void quantize_i8_f32( int32_t zero_point, size_t size) { for (const auto i : c10::irange(size)) { - float tmp = std::round(x[i] * scale + zero_point); + float tmp = roundf(x[i] * scale + zero_point); y[i] = internal::clamp(tmp, -128.f, 127.f); } } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/custom_ops.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/custom_ops.yaml similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/custom_ops.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/custom_ops.yaml diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/find_op_header.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/find_op_header.sh new file mode 100755 index 0000000..9a38433 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/find_op_header.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -o errexit +set -o nounset +set -o pipefail + +# The directory containing this shell script, regardless of the CWD when it +# was invoked. +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" +readonly SCRIPT_DIR + +# The fbsource root that contains this script, even if it was run from xplat. +FBSOURCE_DIR="$(cd -- "${SCRIPT_DIR}" && hg root)" +readonly FBSOURCE_DIR + +# The buck target that generates the header file. +readonly GENRULE_TARGET='fbcode//executorch/kernels/portable:generated_lib_combined' + +# Prints the path to the generated NativeFunctions.h to stdout. +print_header_path() { + # buck2 will produce a line like + # fbcode//executorch/kernels/portable:generated_lib_combined[NativeFunctions.h] buck-out/v2/gen/fbcode/d839c731f5505c62/executorch/codegen/__generated_lib_combined__/out/NativeFunctions.h + # The sed command chops off everything before the space character. + # The relative path is relative to fbsource, so we print that first. + echo -n "${FBSOURCE_DIR}/" + ( + cd "${FBSOURCE_DIR}/fbcode" + buck2 build --show-output \ + "${GENRULE_TARGET}[NativeFunctions.h]" 2>&1 \ + | grep '/NativeFunctions.h' \ + | head -1 \ + | sed -e 's/.* //' + ) +} + +main() { + echo "===== Generating header files =====" + ( + cd "${FBSOURCE_DIR}/fbcode" + buck2 build "${GENRULE_TARGET}" + ) + echo "" + echo "Header file: $(print_header_path)" +} + +main "$@" diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/functions.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/functions.yaml similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/functions.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/functions.yaml index 620d97d..14dd949 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/functions.yaml +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/functions.yaml @@ -17,21 +17,11 @@ # See the README.md file in this directory for a description of the syntax used # by this file. -- op: _adaptive_avg_pool2d.out - kernels: - - arg_meta: null - kernel_name: torch::executor::_adaptive_avg_pool2d_out - - op: _cdist_forward.out kernels: - arg_meta: null kernel_name: torch::executor::_cdist_forward_out -- op: _conj_physical.out - kernels: - - arg_meta: null - kernel_name: torch::executor::_conj_physical_out - - op: _log_softmax.out kernels: - arg_meta: null @@ -1015,11 +1005,6 @@ - arg_meta: null kernel_name: torch::executor::var_correction_out -- op: var_mean.correction_out - kernels: - - arg_meta: null - kernel_name: torch::executor::var_mean_correction_out - - op: var.out kernels: - arg_meta: null @@ -1058,4 +1043,4 @@ - func: dim_order_ops::_clone_dim_order.out(Tensor self, *, bool non_blocking=False, int[]? dim_order=None, Tensor(a!) out) -> Tensor(a!) kernels: - arg_meta: null - kernel_name: torch::executor::_clone_dim_order_out + kernel_name: torch::executor::_clone_dim_order_out \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/targets.bzl new file mode 100644 index 0000000..2c6e0b5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/targets.bzl @@ -0,0 +1,94 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "operators", + srcs = [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/kernels/portable/cpu:cpu", + ], + ) + + if True in get_aten_mode_options(): + runtime.cxx_library( + name = "operators_aten", + srcs = [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/kernels/portable/cpu:cpu_aten", + ], + ) + + runtime.export_file( + name = "functions.yaml", + visibility = ["PUBLIC"], + ) + + runtime.export_file( + name = "custom_ops.yaml", + visibility = ["PUBLIC"], + ) + + et_operator_library( + name = "executorch_all_ops", + include_all_operators = True, + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + et_operator_library( + name = "executorch_aten_ops", + ops_schema_yaml_target = "//executorch/kernels/portable:functions.yaml", + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + et_operator_library( + name = "executorch_custom_ops", + ops_schema_yaml_target = "//executorch/kernels/portable:custom_ops.yaml", + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + generated_lib_common_args = { + "custom_ops_yaml_target": "//executorch/kernels/portable:custom_ops.yaml", + # size_test expects _static targets to be available for these libraries. + "define_static_targets": True, + "functions_yaml_target": "//executorch/kernels/portable:functions.yaml", + "visibility": ["PUBLIC"], + } + + executorch_generated_lib( + name = "generated_lib", + deps = [ + ":executorch_aten_ops", + ":executorch_custom_ops", + ], + kernel_deps = ["//executorch/kernels/portable:operators"], + **generated_lib_common_args + ) + + if True in get_aten_mode_options(): + executorch_generated_lib( + name = "generated_lib_aten", + deps = [ + ":executorch_aten_ops", + ":executorch_custom_ops", + "//executorch/kernels/portable:operators_aten", + ], + custom_ops_aten_kernel_deps = [ + "//executorch/kernels/portable:operators_aten", + ], + custom_ops_yaml_target = "//executorch/kernels/portable:custom_ops.yaml", + aten_mode = True, + visibility = ["PUBLIC"], + define_static_targets = True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/TARGETS new file mode 100644 index 0000000..44c5697 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/TARGETS @@ -0,0 +1,28 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +oncall("executorch") + +define_common_targets() + +runtime.cxx_library( + name = "aot_ops_test_lib", + srcs = [ + "register_ops_aot_for_test.cpp", + ], + visibility = ["PUBLIC"], + deps = [ + "//executorch/extension/aten_util:aten_bridge", + "//executorch/kernels/portable/cpu:op_grid_sampler_2d", + "//executorch/kernels/portable/cpu:op_upsample_bilinear2d", + "//executorch/kernels/portable/cpu:op_upsample_bilinear2d_aa", + "//executorch/kernels/portable/cpu:op_upsample_nearest2d", + "//executorch/runtime/core/exec_aten:lib", + ], + external_deps = [ + "libtorch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/dtype_selective_build_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/dtype_selective_build_test.cpp new file mode 100644 index 0000000..d536d90 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/dtype_selective_build_test.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using torch::executor::ScalarTypeToCppType; + +TEST(DtypeSelectiveBuildTest, UnknownOp) { + // Create a minimal context for error handling in ET_SWITCH + struct { + [[noreturn]] void fail(torch::executor::Error /* error */) { + ET_CHECK_MSG(false, "Unsupported dtype"); + } + } ctx; + ET_EXPECT_DEATH( + ET_SWITCH_TWO_TYPES( + Float, + Int, + executorch::aten::ScalarType::Float, + ctx, + "unknown.out", + // @lint-ignore CLANGTIDY clang-diagnostic-unused-local-typedef + CTYPE_OUT, + [&] { return true; }), + ""); +} + +TEST(DtypeSelectiveBuildTest, OpWithoutDtype) { + // Create a minimal context for error handling in ET_SWITCH + struct { + [[noreturn]] void fail(torch::executor::Error /* error */) { + ET_CHECK_MSG(false, "Unsupported dtype"); + } + } ctx; + ET_EXPECT_DEATH( + ET_SWITCH_TWO_TYPES( + Float, + Int, + executorch::aten::ScalarType::Int, + ctx, + "add.out", + // @lint-ignore CLANGTIDY clang-diagnostic-unused-local-typedef + CTYPE_OUT, + [&] { return true; }), + ""); +} + +TEST(DtypeSelectiveBuildTest, OpWithDtype) { + // Create a minimal context for error handling in ET_SWITCH + struct { + [[noreturn]] void fail(torch::executor::Error /* error */) { + ET_CHECK_MSG(false, "Unsupported dtype"); + } + } ctx; + ASSERT_EQ( + ET_SWITCH_TWO_TYPES( + Float, + Int, + executorch::aten::ScalarType::Float, + ctx, + "add.out", + // @lint-ignore CLANGTIDY clang-diagnostic-unused-local-typedef + CTYPE_OUT, + [&] { return true; }), + true); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_allclose_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_allclose_test.cpp new file mode 100644 index 0000000..99c08c3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_allclose_test.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using torch::executor::native::allclose_out; +using torch::executor::testing::TensorFactory; + +const double default_atol{1e-08}; +const double default_rtol{1e-05}; + +class OpAllCloseTest : public OperatorTest { + protected: + template + void test_tensors_vary_tolerance( + double rtol, + double rdiff, + double atol, + double adiff, + bool should_match) { + TensorFactory tf; + Tensor a = tf.ones(/*sizes=*/{2, 2}); + Tensor b = tf.ones(/*sizes=*/{2, 2}); + + auto a_data = a.data_ptr(); + auto b_data = b.data_ptr(); + b_data[0] = a_data[0] + adiff + a_data[0] * rdiff; + + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + rtol, + atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], should_match) + << a_data[0] << " doesn't match " << b_data[0] << "; dtype " << DTYPE; + } +}; + +TEST_F(OpAllCloseTest, IdenticalFloatTensors) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + Tensor b = tf_float.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, IdenticalDoubleTensors) { + TensorFactory tf_double; + Tensor a = tf_double.ones(/*sizes=*/{2, 2}); + Tensor b = tf_double.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, NonEqualFloatTensors) { + TensorFactory tf_float; + Tensor a = tf_float.make(/*sizes=*/{2, 2}, /*data=*/{1., 2., 3., 4.}); + Tensor b = tf_float.make(/*sizes=*/{2, 2}, /*data=*/{5., 6., 7., 8.}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, NonEqualDoubleTensors) { + TensorFactory tf_double; + Tensor a = tf_double.make(/*sizes=*/{2, 2}, /*data=*/{1., 2., 3., 4.}); + Tensor b = tf_double.make(/*sizes=*/{2, 2}, /*data=*/{5., 6., 7., 8.}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, IdenticalIntTensors) { + TensorFactory tf_int; + Tensor a = tf_int.ones(/*sizes=*/{2, 2}); + Tensor b = tf_int.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, NonEqualIntTensors) { + TensorFactory tf_int; + Tensor a = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}); + Tensor b = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{5, 6, 7, 8}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, IdenticalBoolTensors) { + TensorFactory tf_bool; + Tensor a = tf_bool.ones(/*sizes=*/{2, 2}); + Tensor b = tf_bool.ones(/*sizes=*/{2, 2}); + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, NonEqualBoolTensors) { + TensorFactory tf_bool; + Tensor a = tf_bool.ones(/*sizes=*/{2, 2}); + Tensor b = tf_bool.ones(/*sizes=*/{2, 2}); + auto b_data = b.data_ptr(); + b_data[0] = false; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, MismatchedInputShapesDeath) { + TensorFactory tf_int; + Tensor a = tf_int.ones(/*sizes=*/{2, 1}); + Tensor b = tf_int.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, MismatchedInputDtypesDeath) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + + TensorFactory tf_int; + Tensor b = tf_int.ones(/*sizes=*/{2, 2}); + + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, IncorrectOutputDtypeDeath) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + Tensor b = tf_float.ones(/*sizes=*/{2, 2}); + Tensor out = tf_float.zeros(/*sizes=*/{1}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, IncorrectOutputShapeDeath) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + Tensor b = tf_float.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{2, 2}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, TensorsVaryWithinRelativeTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance( \ + 1e-01, 1e-02, 0, 0, true); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryOutsideRelativeTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance(1e-01, 1, 0, 0, false); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryWithinAbsoluteTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance( \ + 0, 0, 1e-01, 1e-02, true); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryOutsideAbsoluteTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance(0, 0, 1e-01, 1, false); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryWithZeroTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance(0, 0, 0, 1e-01, false); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_div_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_div_test.cpp new file mode 100644 index 0000000..dec78af --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_div_test.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::StridesType; +using executorch::aten::Tensor; +using torch::executor::testing::TensorFactory; + +// Note: This file is used for testing op_div for *portable kernel specific*. +// If your test case is generic and should be tested on all kernels, add it to +// executorch/kernels/test/op_div_test.cpp instead. + +class OpDivScalarOutKernelTest : public OperatorTest { + protected: + Tensor& op_div_out_mode( + const Tensor& a, + const Tensor& b, + std::optional mode, + Tensor& out) { + return torch::executor::aten::div_outf(context_, a, b, mode, out); + } +}; + +class OpDivScalarModeOutKernelTest : public OperatorTest { + protected: + Tensor& op_div_scalar_mode_out( + const Tensor& a, + const Scalar& b, + std::optional mode, + Tensor& out) { + return torch::executor::aten::div_outf(context_, a, b, mode, out); + } +}; + +TEST_F(OpDivScalarOutKernelTest, SanityCheckModeTrunc) { + TensorFactory tf_a; + TensorFactory tf_out; + + const std::vector sizes = {2, 2}; + + Tensor out = tf_out.zeros(sizes); + + op_div_out_mode( + tf_a.make(sizes, {1, 2, 4, -9}), + tf_a.make(sizes, {2, 2, 2, 2}), + std::optional("trunc"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf_out.make(sizes, {0.0, 1.0, 2.0, -4.0})); +} + +TEST_F(OpDivScalarOutKernelTest, SanityCheckModeFloor) { + TensorFactory tf_a; + TensorFactory tf_out; + + const std::vector sizes = {2, 2}; + + Tensor out = tf_out.zeros(sizes); + + op_div_out_mode( + tf_a.make(sizes, {1, 2, 4, -9}), + tf_a.make(sizes, {2, 2, 2, 2}), + std::optional("floor"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf_out.make(sizes, {0.0, 1.0, 2.0, -5.0})); +} + +TEST_F(OpDivScalarModeOutKernelTest, SanityCheckModeTrunc) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + Tensor out = tf.zeros(sizes); + + op_div_scalar_mode_out( + tf.make(sizes, {1, 2, 4, -9}), + 2, + std::optional("trunc"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf.make(sizes, {0, 1, 2, -4})); +} + +TEST_F(OpDivScalarModeOutKernelTest, SanityCheckModeFloor) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + Tensor out = tf.zeros(sizes); + + op_div_scalar_mode_out( + tf.make(sizes, {1, 2, 4, -9}), + 2, + std::optional("floor"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf.make(sizes, {0, 1, 2, -5})); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_gelu_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_gelu_test.cpp new file mode 100644 index 0000000..fa663f8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_gelu_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using std::string_view; +using torch::executor::testing::TensorFactory; + +// Note: This file is used for testing op_gelu for *portable kernel specific*. +// If your test case is generic and should be tested on all kernels, add it to +// executorch/kernels/test/op_gelu_test.cpp instead. + +Tensor& +op_gelu_out(const Tensor& self, std::string_view approximate, Tensor& out) { + executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext context{}; + return torch::executor::native::gelu_out(context, self, approximate, out); +} + +TEST(OpGeluKernelTest, HandleInfAndNanInput) { + TensorFactory tf; + + const std::vector sizes = {3, 2}; + + Tensor in = tf.make( + sizes, + /*data=*/ + {-0.4775, + -std::numeric_limits::infinity(), + -0.3984, + NAN, + std::numeric_limits::infinity(), + -0.4848}); + + // Destination for the gelu. + Tensor out = tf.zeros(sizes); + + // Run full gelu. + op_gelu_out(in, "none", out); + + // Check that it matches the expected output. + EXPECT_TENSOR_CLOSE( + out, + tf.make( + sizes, + /*data=*/ + {-0.15113, 0.0, -0.137515, NAN, INFINITY, -0.152183})); + + // Run tanh gelu appx. + op_gelu_out(in, "tanh", out); + + // Check that it matches the expected output. + EXPECT_TENSOR_CLOSE( + out, + tf.make( + sizes, + /*data=*/ + {-0.151145, 0.0, -0.137522, NAN, INFINITY, -0.152199})); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_grid_sampler_2d_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_grid_sampler_2d_test.py new file mode 100644 index 0000000..4791da5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_grid_sampler_2d_test.py @@ -0,0 +1,234 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import itertools +import unittest + +import torch + + +class GridSampler2dTest(unittest.TestCase): + def run_grid_sampler_test( + self, + inp: torch.Tensor, + grid: torch.Tensor, + mode: str = "bilinear", + padding_mode: str = "zeros", + align_corners: bool = False, + atol: float = 1e-5, + ) -> None: + """Test grid_sampler_2d against PyTorch's reference implementation.""" + # PyTorch reference + aten_result = torch.nn.functional.grid_sample( + inp, + grid, + mode=mode, + padding_mode=padding_mode, + align_corners=align_corners, + ) + + # Convert mode strings to integers for et_test + mode_map = {"bilinear": 0, "nearest": 1, "bicubic": 2} + padding_map = {"zeros": 0, "border": 1, "reflection": 2} + + # ExecuTorch implementation + et_result = torch.zeros_like(aten_result) + et_result = torch.ops.et_test.grid_sampler_2d( + inp, + grid, + interpolation_mode=mode_map[mode], + padding_mode=padding_map[padding_mode], + align_corners=align_corners, + out=et_result, + ) + + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol, rtol=1e-5), + msg=f"Mode: {mode}, Padding: {padding_mode}, Align: {align_corners}\n" + f"ET: {et_result}\n" + f"ATen: {aten_result}\n" + f"Error: {(et_result.to(torch.float) - aten_result.to(torch.float)).abs().max()}", + ) + + def test_grid_sampler_2d_all_modes_f32(self): + """Test all combinations of interpolation, padding, and align_corners.""" + N = [1, 2] + C = [1, 3] + H_IN = [4, 8] + W_IN = [4, 8] + H_OUT = [3, 6] + W_OUT = [3, 6] + MODES = ["bilinear", "nearest", "bicubic"] + PADDING_MODES = ["zeros", "border", "reflection"] + ALIGN_CORNERS = [True, False] + + for ( + n, + c, + h_in, + w_in, + h_out, + w_out, + mode, + padding_mode, + align_corners, + ) in itertools.product( + N, C, H_IN, W_IN, H_OUT, W_OUT, MODES, PADDING_MODES, ALIGN_CORNERS + ): + # Create input tensor + input_tensor = torch.randn(n, c, h_in, w_in, dtype=torch.float32) + + # Create grid with coordinates in [-1, 1] + grid = torch.randn(n, h_out, w_out, 2, dtype=torch.float32) + # Normalize grid to [-1, 1] range + grid = torch.clamp(grid, -2, 2) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode=mode, + padding_mode=padding_mode, + align_corners=align_corners, + atol=1e-4, # Slightly relaxed tolerance for bicubic + ) + + def test_grid_sampler_2d_bilinear_specific_cases(self): + """Test bilinear mode with specific edge cases.""" + # Test with identity grid (should return same as input) + input_tensor = torch.randn(1, 3, 4, 4) + y = torch.linspace(-1, 1, 4) + x = torch.linspace(-1, 1, 4) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bilinear", + padding_mode="zeros", + align_corners=True, + ) + + def test_grid_sampler_2d_nearest_specific_cases(self): + """Test nearest mode with specific patterns.""" + # Create a checkerboard pattern + input_tensor = torch.zeros(1, 1, 4, 4) + input_tensor[0, 0, ::2, ::2] = 1.0 + input_tensor[0, 0, 1::2, 1::2] = 1.0 + + # Sample at grid points + y = torch.linspace(-1, 1, 6) + x = torch.linspace(-1, 1, 6) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="nearest", + padding_mode="zeros", + align_corners=False, + ) + + def test_grid_sampler_2d_padding_modes(self): + """Test different padding modes with out-of-bounds coordinates.""" + input_tensor = torch.randn(1, 2, 5, 5) + + # Create grid with some out-of-bounds coordinates + grid = torch.tensor( + [ + [ + [[-1.5, -1.5], [-0.5, -0.5], [0.5, 0.5], [1.5, 1.5]], + [[-1.0, 1.5], [0.0, 0.0], [1.0, -1.5], [2.0, 2.0]], + ] + ], + dtype=torch.float32, + ) + + for padding_mode in ["zeros", "border", "reflection"]: + for align_corners in [True, False]: + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bilinear", + padding_mode=padding_mode, + align_corners=align_corners, + ) + + def test_grid_sampler_2d_bicubic_smoothness(self): + """Test bicubic interpolation for smooth gradients.""" + # Create a smooth gradient + input_tensor = torch.arange(16, dtype=torch.float32).reshape(1, 1, 4, 4) + + # Create a fine grid for upsampling + y = torch.linspace(-1, 1, 7) + x = torch.linspace(-1, 1, 7) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bicubic", + padding_mode="zeros", + align_corners=True, + atol=1e-4, + ) + + def test_grid_sampler_2d_align_corners_comparison(self): + """Compare align_corners=True vs False.""" + input_tensor = torch.randn(1, 1, 8, 8) + + # Create grid at corner positions + grid = torch.tensor( + [ + [ + [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0]], + ] + ], + dtype=torch.float32, + ) + + for mode in ["bilinear", "nearest", "bicubic"]: + # Test with align_corners=True + self.run_grid_sampler_test( + input_tensor, + grid, + mode=mode, + padding_mode="zeros", + align_corners=True, + ) + + # Test with align_corners=False + self.run_grid_sampler_test( + input_tensor, + grid, + mode=mode, + padding_mode="zeros", + align_corners=False, + ) + + def test_grid_sampler_2d_batch_processing(self): + """Test with multiple batches.""" + batch_sizes = [1, 2, 4] + for batch_size in batch_sizes: + input_tensor = torch.randn(batch_size, 3, 6, 6) + grid = torch.randn(batch_size, 4, 4, 2) + grid = torch.clamp(grid, -1.5, 1.5) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bilinear", + padding_mode="border", + align_corners=False, + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_mul_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_mul_test.cpp new file mode 100644 index 0000000..0827f8d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_mul_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::StridesType; +using executorch::aten::Tensor; +using torch::executor::testing::TensorFactory; + +// Note: This file is used for testing op_mul for *portable kernel specific*. +// If your test case is generic and should be tested on all kernels, add it to +// executorch/kernels/test/op_mul_test.cpp instead. + +class OpMulOutKernelTest : public OperatorTest { + protected: + Tensor& mul_out(const Tensor& self, const Tensor& other, Tensor& out) { + return torch::executor::native::mul_out(context_, self, other, out); + } +}; + +TEST_F(OpMulOutKernelTest, UnhandledDtypeDies) { + // mul_out() doesn't handle QInt8. + // TensorFactory cannot be used with ScalarType::QInt8 since + // executorch::aten::qint8 does not have a default constructor. It must be + // initialized with an explicit value. So, we need to manually create the + // underlying data without default construction and then the tensors from that + // data via TensorImpl. + + std::vector sizes = {2, 2}; + + std::vector a_data{}; + std::generate_n(std::back_inserter(a_data), 4, []() { + return executorch::aten::qint8{0}; + }); + std::vector b_data(a_data); + std::vector out_data(a_data); + + std::vector dim_order = {0, 1}; + + auto a_impl = torch::executor::TensorImpl( + ScalarType::QInt8, 2, sizes.data(), a_data.data(), dim_order.data()); + auto b_impl = torch::executor::TensorImpl( + ScalarType::QInt8, 2, sizes.data(), b_data.data(), dim_order.data()); + auto out_impl = torch::executor::TensorImpl( + ScalarType::QInt8, 2, sizes.data(), out_data.data(), dim_order.data()); + + // Two input tensors. + Tensor a(&a_impl); + Tensor b(&b_impl); + + // Output tensor. + Tensor out(&out_impl); + + // Multiplying the two QInt8 tensors should cause an assertion and + // kill the test process. + ET_EXPECT_KERNEL_FAILURE(context_, mul_out(a, b, out)); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_aa_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_aa_test.py new file mode 100644 index 0000000..f86aa35 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_aa_test.py @@ -0,0 +1,346 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +# NOTE: This test file follows the structure of op_upsample_bilinear2d_test.py +# but requires et_test namespace setup to run the actual ExecuTorch implementation. +# The comprehensive C++ test suite in op_upsample_bilinear2d_aa_test.cpp provides +# complete validation of the anti-aliased bilinear upsampling implementation. + +import unittest + +from typing import Optional, Sequence + +import torch + + +class UpsampleBilinear2dAATest(unittest.TestCase): + def run_upsample_aa_test( + self, + inp: torch.Tensor, + output_size: Optional[Sequence[int]] = None, + align_corners: bool = False, + scale_factors: Optional[Sequence[float]] = None, + atol=1e-4, + ) -> None: + """Test our ExecuTorch anti-aliased bilinear upsampling against PyTorch reference.""" + # PyTorch reference with anti-aliasing + aten_result = torch.nn.functional.interpolate( + inp, + size=output_size, + mode="bilinear", + scale_factor=scale_factors, + align_corners=align_corners, + antialias=True, + ) + + # Our ExecuTorch implementation via et_test namespace + # NOTE: Requires proper et_test namespace setup + et_result = torch.zeros_like(aten_result) + + # Compute output_size from scale_factors if needed + actual_output_size = output_size + scale_h = None + scale_w = None + + if output_size is None and scale_factors is not None: + # Compute output size from input size and scale factors + input_h, input_w = inp.shape[-2:] + output_h = int(input_h * scale_factors[0]) + output_w = int(input_w * scale_factors[1]) + actual_output_size = [output_h, output_w] + scale_h = scale_factors[0] + scale_w = scale_factors[1] + + # Ensure actual_output_size is never None + if actual_output_size is None: + raise ValueError("Either output_size or scale_factors must be provided") + + # Ensure actual_output_size is a list of integers + actual_output_size = [int(x) for x in actual_output_size] + + et_result = torch.ops.et_test._upsample_bilinear2d_aa( + inp, + actual_output_size, + align_corners, + scale_h, + scale_w, + out=et_result, + ) + + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol), + msg=f"ET: {et_result} \n ATen: {aten_result} \n Error: {et_result.to(torch.float) - aten_result.to(torch.float)}", + ) + + def test_upsample_bilinear2d_aa_basic_functionality(self): + """Test basic functionality - function calls work and produce reasonable outputs.""" + # Simple 2x2 -> 4x4 upsampling test to verify function signature fix + input_tensor = torch.randn(1, 1, 2, 2) + + # Test with output_size - this should work if function signature is fixed + try: + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), + align_corners=False, + atol=1e-3, # Relaxed tolerance for basic functionality test + ) + print("✓ Function call with output_size works") + except RuntimeError as e: + if "missing value for argument" in str(e): + self.fail(f"Function signature issue not fixed: {e}") + else: + raise + + # Test with scale_factors - this should also work + try: + self.run_upsample_aa_test( + input_tensor, + scale_factors=(2.0, 2.0), + align_corners=False, + atol=1e-3, # Relaxed tolerance for basic functionality test + ) + print("✓ Function call with scale_factors works") + except RuntimeError as e: + if "missing value for argument" in str(e): + self.fail(f"Function signature issue not fixed: {e}") + else: + raise + + def test_upsample_bilinear2d_aa_aten_parity_f32(self): + """Test float32 parity with PyTorch's anti-aliased implementation.""" + # Simplified test with just one case for debugging + input_tensor = torch.randn(1, 1, 2, 2) + self.run_upsample_aa_test(input_tensor, output_size=(4, 4), align_corners=False) + + def test_upsample_bilinear2d_aa_aten_parity_u8(self): + """Test uint8 parity with PyTorch's anti-aliased implementation.""" + # Simplified test with just one case for debugging + input_tensor = torch.randint(0, 255, (1, 1, 2, 2), dtype=torch.uint8) + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), + align_corners=False, + atol=3.5, # Relaxed tolerance for uint8 due to implementation differences in anti-aliasing + ) + + def test_upsample_bilinear2d_aa_downsampling(self): + """Test downsampling with anti-aliasing - key differentiator from regular bilinear.""" + # 8x8 -> 4x4 downsampling where anti-aliasing should have significant effect + input_tensor = torch.randn(1, 2, 8, 8) + self.run_upsample_aa_test( + input_tensor, output_size=(4, 4), align_corners=False, atol=1e-3 + ) + + def test_upsample_bilinear2d_aa_aggressive_downsampling(self): + """Test aggressive downsampling (8x8 -> 2x2) where anti-aliasing is most important.""" + input_tensor = torch.randn(1, 1, 8, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(2, 2), + align_corners=False, + atol=0.4, # Relaxed tolerance due to implementation differences in separable vs direct interpolation + ) + + def test_upsample_bilinear2d_aa_asymmetric_downsampling(self): + """Test asymmetric downsampling (different scale factors for H and W).""" + input_tensor = torch.randn(1, 2, 12, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), # 3x downsample in H, 2x in W + align_corners=False, + atol=0.25, # Relaxed tolerance due to implementation differences in separable vs direct interpolation + ) + + def test_upsample_bilinear2d_aa_align_corners_upsampling(self): + """Test align_corners=True with upsampling.""" + input_tensor = torch.randn(1, 1, 3, 3) + self.run_upsample_aa_test( + input_tensor, + output_size=(6, 6), + align_corners=True, + atol=1e-3, # Keep tight tolerance for upsampling which works well + ) + + def test_upsample_bilinear2d_aa_align_corners_downsampling(self): + """Test align_corners=True with downsampling.""" + input_tensor = torch.randn(1, 1, 8, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), + align_corners=True, + atol=0.25, # Relaxed tolerance due to implementation differences in separable vs direct interpolation + ) + + def test_upsample_bilinear2d_aa_batched(self): + """Test batched inputs.""" + input_tensor = torch.randn(3, 4, 6, 6) + self.run_upsample_aa_test( + input_tensor, + output_size=(3, 3), # Downsampling + align_corners=False, + atol=1e-3, + ) + + def test_upsample_bilinear2d_aa_identity_transform(self): + """Test that same input/output size preserves values (identity transform).""" + input_tensor = torch.randn(1, 2, 4, 4) + self.run_upsample_aa_test( + input_tensor, output_size=(4, 4), align_corners=False, atol=1e-3 + ) + + def test_upsample_bilinear2d_aa_edge_case_1x1(self): + """Test edge case with 1x1 input.""" + input_tensor = torch.randn(1, 3, 1, 1) + self.run_upsample_aa_test( + input_tensor, output_size=(4, 4), align_corners=False, atol=1e-3 + ) + + def test_upsample_bilinear2d_aa_edge_case_to_1x1(self): + """Test edge case downsampling to 1x1.""" + input_tensor = torch.randn(1, 2, 8, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(1, 1), + align_corners=False, + atol=0.6, # Higher tolerance for 1x1 edge case due to significant implementation differences + ) + + def test_upsample_bilinear2d_aa_fractional_scaling(self): + """Test non-integer scale factors.""" + input_tensor = torch.randn(1, 1, 5, 7) + self.run_upsample_aa_test( + input_tensor, + output_size=(8, 10), # Non-integer scaling + align_corners=False, + atol=1e-3, + ) + + def test_upsample_bilinear2d_aa_known_values_correctness(self): + """Test against known correct output values to catch regressions.""" + # This test case is adapted from ATen's test suite + input_tensor = torch.arange(3 * 8 * 8, dtype=torch.float).reshape(1, 3, 8, 8) + + # Test with a known downsampling case + try: + self.run_upsample_aa_test( + input_tensor, + output_size=(2, 2), + align_corners=False, + atol=1e-2, # Slightly relaxed for implementation differences + ) + # The test should pass if our implementation is close to ATen + except AssertionError as e: + # Log the difference for debugging but don't fail the test during development + print(f"Known values test difference (expected during development): {e}") + + def test_upsample_bilinear2d_aa_various_dtypes(self): + """Test with various data types.""" + test_cases = [ + (torch.float32, 1e-3), + (torch.float64, 1e-6), + ] + + for dtype, atol in test_cases: + with self.subTest(dtype=dtype): + input_tensor = torch.randn(1, 2, 6, 6, dtype=dtype) + self.run_upsample_aa_test( + input_tensor, output_size=(3, 3), align_corners=False, atol=atol + ) + + def test_upsample_bilinear2d_aa_scale_factors_vs_output_size(self): + """Test that scale_factors and equivalent output_size give same results.""" + input_tensor = torch.randn(1, 2, 4, 6) + + # Test with scale factors + try: + result1 = torch.zeros(1, 2, 8, 12) + result1 = torch.ops.et_test._upsample_bilinear2d_aa( + input_tensor, + [8, 12], # output_size equivalent to 2x scale + False, # align_corners + 2.0, # scale_h + 2.0, # scale_w + out=result1, + ) + + # Test with output_size + result2 = torch.zeros(1, 2, 8, 12) + result2 = torch.ops.et_test._upsample_bilinear2d_aa( + input_tensor, + [8, 12], # output_size + False, # align_corners + None, # scale_h + None, # scale_w + out=result2, + ) + + # Results should be identical + self.assertTrue( + torch.allclose(result1, result2, atol=1e-5), + "Scale factors and output_size should give identical results", + ) + except RuntimeError as e: + # Skip this test if et_test namespace setup issues persist + print(f"Skipping scale factors test due to: {e}") + + def test_upsample_bilinear2d_aa_extreme_scale_factors(self): + """Test the specific case that exposed the segfault bug with extreme scale factors.""" + # Create input tensor with same data as C++ test to ensure consistency + input_tensor = torch.zeros(8, 2, 7, 1, dtype=torch.float32) + for i in range(8 * 2 * 7 * 1): + input_tensor.view(-1)[i] = i * 0.1 + + # Test the specific case that caused segfault before the fix + self.run_upsample_aa_test( + input_tensor, + output_size=[7, 2], + align_corners=False, + scale_factors=None, # Use explicit scale factors via direct call + atol=1e-2, # Relaxed tolerance for extreme scale factors + ) + + # Also test with direct ExecuTorch call using the extreme scale factors + try: + et_result = torch.zeros(8, 2, 7, 2, dtype=torch.float32) + et_result = torch.ops.et_test._upsample_bilinear2d_aa( + input_tensor, + [7, 2], # output_size + False, # align_corners + 0.010000000000000002, # scales_h (very small) + 10.0, # scales_w (very large) + out=et_result, + ) + + # Verify no NaN or Inf values (the bug would cause these) + self.assertFalse( + torch.isnan(et_result).any().item(), + "Output should not contain NaN values after bug fix", + ) + self.assertFalse( + torch.isinf(et_result).any().item(), + "Output should not contain Inf values after bug fix", + ) + + # Verify reasonable output values + self.assertTrue( + et_result.min().item() >= -100.0, + "Output values should be reasonable (not extremely negative)", + ) + self.assertTrue( + et_result.max().item() <= 100.0, + "Output values should be reasonable (not extremely positive)", + ) + + except RuntimeError as e: + # Skip the direct test if et_test namespace setup issues persist + print(f"Skipping direct extreme scale factors test due to: {e}") + + +if __name__ == "__main__": + unittest.main() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_test.py new file mode 100644 index 0000000..6760920 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_bilinear2d_test.py @@ -0,0 +1,87 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import itertools +import unittest + +from typing import Optional, Sequence + +import torch + + +class UpsampleBilinear2dTest(unittest.TestCase): + def run_upsample_test( + self, + inp: torch.Tensor, + output_size: Optional[Sequence[int]] = None, + align_corners: bool = False, + scale_factors: Optional[Sequence[float]] = None, + atol=2e-7, + ) -> None: + aten_result = torch.nn.functional.interpolate( + inp, + size=output_size, + mode="bilinear", + scale_factor=scale_factors, + align_corners=align_corners, + ) + et_result = torch.zeros_like(aten_result) + et_result = torch.ops.et_test.upsample_bilinear2d( + inp, + output_size=output_size, + scale_factors=scale_factors, + align_corners=align_corners, + out=et_result, + ) + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol), + msg=f"ET: {et_result} \n ATen: {aten_result} \n Error: {et_result.to(torch.float) - aten_result.to(torch.float)}", + ) + + def test_upsample_bilinear2d_aten_parity_f32(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + ALIGN_CORNERS = [True, False] + + for n, c, h, w, out_h, out_w, align_corners in itertools.product( + N, C, H, W, OUT_H, OUT_W, ALIGN_CORNERS + ): + input = torch.randn(n, c, h, w) + self.run_upsample_test( + input, output_size=(out_h, out_w), align_corners=align_corners + ) + self.run_upsample_test( + input, scale_factors=(out_h / h, out_w / w), align_corners=align_corners + ) + + def test_upsample_bilinear2d_aten_parity_u8(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + ALIGN_CORNERS = [True, False] + + for n, c, h, w, out_h, out_w, align_corners in itertools.product( + N, C, H, W, OUT_H, OUT_W, ALIGN_CORNERS + ): + input = torch.randint(0, 255, (n, c, h, w), dtype=torch.uint8) + self.run_upsample_test( + input, output_size=(out_h, out_w), align_corners=align_corners, atol=2 + ) + self.run_upsample_test( + input, + scale_factors=(out_h / h, out_w / w), + align_corners=align_corners, + atol=2, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_nearest2d_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_nearest2d_test.py new file mode 100644 index 0000000..23a6bb5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/op_upsample_nearest2d_test.py @@ -0,0 +1,71 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import itertools +import unittest + +from typing import Optional, Sequence + +import torch + + +class UpsampleNearest2dTest(unittest.TestCase): + def run_upsample_test( + self, + inp: torch.Tensor, + output_size: Optional[Sequence[int]] = None, + scale_factors: Optional[Sequence[float]] = None, + atol=1e-7, + ) -> None: + aten_result = torch.nn.functional.interpolate( + inp, + size=output_size, + mode="nearest", + scale_factor=scale_factors, + ) + et_result = torch.zeros_like(aten_result) + et_result = torch.ops.et_test.upsample_nearest2d( + inp, + output_size=output_size, + scale_factors=scale_factors, + out=et_result, + ) + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol), + msg=f"ET: {et_result} \n ATen: {aten_result} \n Error: {et_result.to(torch.float) - aten_result.to(torch.float)}", + ) + + def test_upsample_nearest2d_aten_parity_f32(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + + for n, c, h, w, out_h, out_w in itertools.product(N, C, H, W, OUT_H, OUT_W): + input = torch.randn(n, c, h, w) + self.run_upsample_test(input, output_size=(out_h, out_w)) + self.run_upsample_test(input, scale_factors=(out_h / h, out_w / w)) + + def test_upsample_nearest2d_aten_parity_u8(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + + for n, c, h, w, out_h, out_w in itertools.product(N, C, H, W, OUT_H, OUT_W): + input = torch.randint(0, 255, (n, c, h, w), dtype=torch.uint8) + self.run_upsample_test(input, output_size=(out_h, out_w), atol=1) + self.run_upsample_test( + input, + scale_factors=(out_h / h, out_w / w), + atol=2, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/register_ops_aot_for_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/register_ops_aot_for_test.cpp new file mode 100644 index 0000000..cee7a56 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/register_ops_aot_for_test.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +namespace torch { +namespace executor { + +namespace native { + +// Signatures are auto-generated, so disable pass-by-value lint. +// NOLINTBEGIN(facebook-hte-ConstantArgumentPassByValue, +// facebook-hte-ParameterMightThrowOnCopy) +Tensor& upsample_bilinear2d_vec_out( + KernelRuntimeContext& ctx, + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + bool align_corners, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out); + +Tensor& upsample_bilinear2d_vec_out_no_context( + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + bool align_corners, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = upsample_bilinear2d_vec_out( + ctx, in, output_size, align_corners, scale_factors, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} + +Tensor& upsample_nearest2d_vec_out( + KernelRuntimeContext& ctx, + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out); + +Tensor& upsample_nearest2d_vec_out_no_context( + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = + upsample_nearest2d_vec_out(ctx, in, output_size, scale_factors, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} + +Tensor& _upsample_bilinear2d_aa_out( + KernelRuntimeContext& ctx, + const Tensor& in, + const executorch::aten::ArrayRef output_size, + bool align_corners, + const std::optional scale_h, + const std::optional scale_w, + Tensor& out); + +Tensor& _upsample_bilinear2d_aa_out_no_context( + const Tensor& in, + const executorch::aten::ArrayRef output_size, + bool align_corners, + const std::optional scale_h, + const std::optional scale_w, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = _upsample_bilinear2d_aa_out( + ctx, in, output_size, align_corners, scale_h, scale_w, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} + +Tensor& grid_sampler_2d_out( + KernelRuntimeContext& ctx, + const Tensor& input, + const Tensor& grid, + int64_t interpolation_mode, + int64_t padding_mode, + bool align_corners, + Tensor& out); + +Tensor& grid_sampler_2d_out_no_context( + const Tensor& input, + const Tensor& grid, + int64_t interpolation_mode, + int64_t padding_mode, + bool align_corners, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = grid_sampler_2d_out( + ctx, input, grid, interpolation_mode, padding_mode, align_corners, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} +// NOLINTEND(facebook-hte-ConstantArgumentPassByValue, +// facebook-hte-ParameterMightThrowOnCopy) + +TORCH_LIBRARY(et_test, m) { + m.def( + "upsample_bilinear2d.vec_out(Tensor input, SymInt[]? output_size, bool align_corners, float[]? scale_factors, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(upsample_bilinear2d_vec_out_no_context, 4)); + m.def( + "upsample_nearest2d.vec_out(Tensor input, SymInt[]? output_size, float[]? scale_factors, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(upsample_nearest2d_vec_out_no_context, 3)); + m.def( + "_upsample_bilinear2d_aa.out(Tensor input, SymInt[] output_size, bool align_corners, float? scale_h, float? scale_w, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(_upsample_bilinear2d_aa_out_no_context, 5)); + m.def( + "grid_sampler_2d.out(Tensor input, Tensor grid, int interpolation_mode, int padding_mode, bool align_corners, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(grid_sampler_2d_out_no_context, 5)); +} + +} // namespace native +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/supported_features_def.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/supported_features_def.yaml new file mode 100644 index 0000000..c97183a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/supported_features_def.yaml @@ -0,0 +1 @@ +# no override diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/targets.bzl new file mode 100644 index 0000000..c52b59b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/targets.bzl @@ -0,0 +1,101 @@ +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "is_xplat", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") +load("@fbsource//xplat/executorch/kernels/test:util.bzl", "define_supported_features_lib", "op_test") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + if not runtime.is_oss: + define_supported_features_lib() + + if not is_xplat(): + python_unittest( + name = "op_upsample_bilinear2d_test", + srcs = [ + "op_upsample_bilinear2d_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + python_unittest( + name = "op_upsample_bilinear2d_aa_test", + srcs = [ + "op_upsample_bilinear2d_aa_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + python_unittest( + name = "op_upsample_nearest2d_test", + srcs = [ + "op_upsample_nearest2d_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + python_unittest( + name = "op_grid_sampler_2d_test", + srcs = [ + "op_grid_sampler_2d_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + op_test(name = "op_allclose_test") + op_test(name = "op_div_test") + op_test(name = "op_gelu_test") + op_test(name = "op_mul_test") + + if is_xplat(): + et_operator_library( + name = "add_float", + ops_dict = { + "aten::add.out": ["v1/6;0,1"], # float + }, + ) + + executorch_generated_lib( + name = "add_float_lib", + functions_yaml_target = "//executorch/kernels/portable:functions.yaml", + kernel_deps = [ + "//executorch/kernels/portable:operators", + ], + visibility = ["//executorch/..."], + deps = [ + ":add_float", + ], + dtype_selective_build = True, + ) + + runtime.cxx_test( + name = "dtype_selective_build_test", + srcs = ["dtype_selective_build_test.cpp"], + deps = [ + ":add_float_lib", + "//executorch/kernels/portable/cpu:scalar_utils", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/test_grid_sampler_2d_executorch.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/test_grid_sampler_2d_executorch.py new file mode 100644 index 0000000..4b635e1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/portable/test/test_grid_sampler_2d_executorch.py @@ -0,0 +1,458 @@ +#!/usr/bin/env python3 +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +""" +Test grid_sampler_2d by exporting to ExecuTorch and comparing with PyTorch. +""" + +import itertools +import sys +import unittest + +import torch +import torch.nn as nn +from executorch.exir import to_edge +from executorch.runtime import Runtime +from torch.export import export + + +class GridSampleModule(nn.Module): + """Wrapper module for grid_sample operation.""" + + def __init__( + self, + mode: str = "bilinear", + padding_mode: str = "zeros", + align_corners: bool = False, + ): + super().__init__() + self.mode = mode + self.padding_mode = padding_mode + self.align_corners = align_corners + + def forward(self, input: torch.Tensor, grid: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.grid_sample( + input, + grid, + mode=self.mode, + padding_mode=self.padding_mode, + align_corners=self.align_corners, + ) + + +class GridSampler2DExecutorchTest(unittest.TestCase): + """Test ExecuTorch grid_sampler_2d implementation.""" + + def run_executorch_test( + self, + input_tensor: torch.Tensor, + grid: torch.Tensor, + mode: str = "bilinear", + padding_mode: str = "zeros", + align_corners: bool = False, + atol: float = 1e-5, + rtol: float = 1e-5, + ) -> None: + """Export to ExecuTorch and compare with PyTorch reference.""" + + # Create module + model = GridSampleModule(mode, padding_mode, align_corners) + model.eval() + + # PyTorch reference + with torch.no_grad(): + pytorch_output = model(input_tensor, grid) + + try: + # Export to ExecuTorch + example_inputs = (input_tensor, grid) + + # Export the model + exported_program = export(model, example_inputs) + + # Convert to edge IR + edge_program = to_edge(exported_program) + + # Get ExecuTorch program + executorch_program = edge_program.to_executorch() + + # Run through ExecuTorch + runtime = Runtime.get() + fwd_method = runtime.load_program(executorch_program.buffer).load_method( + "forward" + ) + if fwd_method is None: + self.fail("Failed to load forward method") + executorch_output = fwd_method.execute((input_tensor, grid))[0] + + # Compare results + self.assertTrue( + executorch_output.shape == pytorch_output.shape, + msg=f"Shape mismatch: ET={executorch_output.shape} vs PT={pytorch_output.shape}", + ) + + if not torch.allclose( + executorch_output, pytorch_output, atol=atol, rtol=rtol + ): + max_diff = (executorch_output - pytorch_output).abs().max().item() + mean_diff = (executorch_output - pytorch_output).abs().mean().item() + self.fail( + f"\nMode: {mode}, Padding: {padding_mode}, Align: {align_corners}\n" + f"Max difference: {max_diff:.6e}\n" + f"Mean difference: {mean_diff:.6e}\n" + f"Tolerance (atol): {atol:.6e}\n" + f"ExecuTorch output:\n{executorch_output}\n" + f"PyTorch output:\n{pytorch_output}\n" + ) + + except Exception as e: + self.fail( + f"Failed to export or run model:\n" + f"Mode: {mode}, Padding: {padding_mode}, Align: {align_corners}\n" + f"Error: {str(e)}" + ) + + def test_all_mode_combinations(self): + """Test all combinations of interpolation modes, padding modes, and align_corners.""" + print("\n" + "=" * 70) + print("Testing all mode combinations") + print("=" * 70) + + modes = ["bilinear", "nearest", "bicubic"] + padding_modes = ["zeros", "border", "reflection"] + align_corners_options = [True, False] + + # Test parameters + batch_size = 2 + channels = 3 + height_in = 5 + width_in = 5 + height_out = 4 + width_out = 4 + + test_count = 0 + for mode, padding, align in itertools.product( + modes, padding_modes, align_corners_options + ): + with self.subTest(mode=mode, padding=padding, align=align): + # Create random input + input_tensor = torch.randn( + batch_size, channels, height_in, width_in, dtype=torch.float32 + ) + + # Create grid with some values in [-1, 1] range + grid = torch.randn( + batch_size, height_out, width_out, 2, dtype=torch.float32 + ) + grid = torch.clamp(grid, -1.2, 1.2) # Include some out-of-bounds + + # Bicubic may have slightly larger numerical errors + atol = 1e-4 if mode == "bicubic" else 1e-5 + + self.run_executorch_test( + input_tensor, grid, mode, padding, align, atol=atol + ) + test_count += 1 + print(f" ✓ {mode}/{padding}/align={align}") + + print(f"✓ Passed {test_count} mode combination tests") + + def test_batch_sizes(self): + """Test various batch sizes.""" + print("\n" + "=" * 70) + print("Testing various batch sizes") + print("=" * 70) + + batch_sizes = [1, 2, 4] + + for batch_size in batch_sizes: + with self.subTest(batch_size=batch_size): + input_tensor = torch.randn(batch_size, 3, 6, 6, dtype=torch.float32) + grid = torch.randn(batch_size, 4, 4, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ batch_size={batch_size}") + + print(f"✓ Passed {len(batch_sizes)} batch size tests") + + def test_input_sizes(self): + """Test various input and output sizes.""" + print("\n" + "=" * 70) + print("Testing various input/output sizes") + print("=" * 70) + + test_cases = [ + # (H_in, W_in, H_out, W_out) + (4, 4, 4, 4), # Same size + (8, 8, 4, 4), # Downsampling + (4, 4, 8, 8), # Upsampling + (10, 5, 7, 3), # Non-square, different aspect ratios + ] + + for h_in, w_in, h_out, w_out in test_cases: + with self.subTest(h_in=h_in, w_in=w_in, h_out=h_out, w_out=w_out): + input_tensor = torch.randn(1, 2, h_in, w_in, dtype=torch.float32) + grid = torch.randn(1, h_out, w_out, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ {h_in}x{w_in} -> {h_out}x{w_out}") + + print(f"✓ Passed {len(test_cases)} size variation tests") + + def test_identity_grid(self): + """Test with identity grid (should return approximately same as input).""" + print("\n" + "=" * 70) + print("Testing identity grid") + print("=" * 70) + + input_tensor = torch.randn(1, 3, 4, 4, dtype=torch.float32) + + # Create identity grid + y = torch.linspace(-1, 1, 4) + x = torch.linspace(-1, 1, 4) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + for mode in ["bilinear", "nearest", "bicubic"]: + with self.subTest(mode=mode): + atol = 1e-4 if mode == "bicubic" else 1e-5 + self.run_executorch_test( + input_tensor, grid, mode, "zeros", True, atol=atol + ) + print(f" ✓ {mode}") + + print("✓ Passed identity grid tests") + + def test_corner_coordinates(self): + """Test sampling at corner coordinates with different align_corners settings.""" + print("\n" + "=" * 70) + print("Testing corner coordinates") + print("=" * 70) + + input_tensor = torch.randn(1, 1, 8, 8, dtype=torch.float32) + + # Grid sampling at corners + grid = torch.tensor( + [ + [ + [[-1.0, -1.0], [-1.0, 1.0]], + [[1.0, -1.0], [1.0, 1.0]], + ] + ], + dtype=torch.float32, + ) + + for align_corners in [True, False]: + for mode in ["bilinear", "nearest"]: + with self.subTest(align_corners=align_corners, mode=mode): + self.run_executorch_test( + input_tensor, grid, mode, "zeros", align_corners + ) + print(f" ✓ {mode}/align={align_corners}") + + print("✓ Passed corner coordinate tests") + + def test_out_of_bounds(self): + """Test behavior with out-of-bounds coordinates for different padding modes.""" + print("\n" + "=" * 70) + print("Testing out-of-bounds coordinates") + print("=" * 70) + + input_tensor = torch.randn(1, 2, 5, 5, dtype=torch.float32) + + # Grid with out-of-bounds coordinates + grid = torch.tensor( + [ + [ + [[-1.5, -1.5], [-0.5, -0.5], [0.5, 0.5], [1.5, 1.5]], + [[-1.0, 1.5], [0.0, 0.0], [1.0, -1.5], [2.0, 2.0]], + ] + ], + dtype=torch.float32, + ) + + for padding_mode in ["zeros", "border", "reflection"]: + for mode in ["bilinear", "nearest"]: + with self.subTest(padding_mode=padding_mode, mode=mode): + self.run_executorch_test( + input_tensor, grid, mode, padding_mode, False + ) + print(f" ✓ {mode}/{padding_mode}") + + print("✓ Passed out-of-bounds tests") + + def test_single_channel(self): + """Test with single channel input.""" + print("\n" + "=" * 70) + print("Testing single channel input") + print("=" * 70) + + input_tensor = torch.randn(1, 1, 6, 6, dtype=torch.float32) + grid = torch.randn(1, 4, 4, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + for mode in ["bilinear", "nearest", "bicubic"]: + with self.subTest(mode=mode): + atol = 1e-4 if mode == "bicubic" else 1e-5 + self.run_executorch_test( + input_tensor, grid, mode, "zeros", False, atol=atol + ) + print(f" ✓ {mode}") + + print("✓ Passed single channel tests") + + def test_different_dtypes(self): + """Test with different data types (float16, bfloat16).""" + print("\n" + "=" * 70) + print("Testing different dtypes") + print("=" * 70) + + dtypes = [torch.float16, torch.bfloat16] + + for dtype in dtypes: + with self.subTest(dtype=dtype): + input_tensor = torch.randn(1, 2, 4, 4, dtype=dtype) + grid = torch.randn(1, 3, 3, 2, dtype=dtype) + grid = torch.clamp(grid, -1, 1) + + # Use larger tolerance for float16/bfloat16 + atol = 1e-2 if dtype == torch.bfloat16 else 5e-3 + + self.run_executorch_test( + input_tensor, grid, "bilinear", "zeros", False, atol=atol + ) + print(f" ✓ {dtype}") + + print("✓ Passed dtype tests") + + def test_very_small_inputs(self): + """Test with very small input sizes.""" + print("\n" + "=" * 70) + print("Testing very small inputs") + print("=" * 70) + + test_cases = [ + # (H_in, W_in, H_out, W_out, description) + (1, 1, 1, 1, "1x1 input, 1x1 output"), + (1, 1, 2, 2, "1x1 input, 2x2 output"), + (2, 2, 1, 1, "2x2 input, 1x1 output"), + (2, 2, 2, 2, "2x2 input, 2x2 output"), + (2, 2, 3, 3, "2x2 input, 3x3 output"), + (3, 3, 1, 1, "3x3 input, single pixel output"), + ] + + for h_in, w_in, h_out, w_out, desc in test_cases: + with self.subTest(desc=desc): + input_tensor = torch.randn(1, 2, h_in, w_in, dtype=torch.float32) + grid = torch.randn(1, h_out, w_out, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ {desc}") + + print("✓ Passed very small input tests") + + def test_exact_boundary_coordinates(self): + """Test with grid coordinates exactly at boundaries.""" + print("\n" + "=" * 70) + print("Testing exact boundary coordinates") + print("=" * 70) + + input_tensor = torch.randn(1, 2, 5, 5, dtype=torch.float32) + + # Test grid with exact boundary values + grids = [ + # All corners + torch.tensor( + [[[[-1.0, -1.0], [-1.0, 1.0]], [[1.0, -1.0], [1.0, 1.0]]]], + dtype=torch.float32, + ), + # Center + torch.tensor([[[[0.0, 0.0]]]], dtype=torch.float32), + # Edges + torch.tensor( + [[[[-1.0, 0.0], [1.0, 0.0], [0.0, -1.0], [0.0, 1.0]]]], + dtype=torch.float32, + ), + ] + + for i, grid in enumerate(grids): + for mode in ["bilinear", "nearest", "bicubic"]: + for align_corners in [True, False]: + with self.subTest(grid=i, mode=mode, align_corners=align_corners): + atol = 1e-4 if mode == "bicubic" else 1e-5 + self.run_executorch_test( + input_tensor, grid, mode, "zeros", align_corners, atol=atol + ) + print(f" ✓ grid {i}/{mode}/align={align_corners}") + + print("✓ Passed exact boundary coordinate tests") + + def test_out_of_bounds_values_in_grid(self): + """Test with out of bounds values in grid.""" + print("\n" + "=" * 70) + print("Testing special values in grid") + print("=" * 70) + + input_tensor = torch.randn(1, 2, 4, 4, dtype=torch.float32) + + test_cases = [ + # (grid, description) + ( + torch.tensor([[[[10.0, 10.0], [-10.0, -10.0]]]], dtype=torch.float32), + "Very large coordinates (far out of bounds)", + ), + ( + torch.tensor( + [[[[2.0, 0.0], [0.0, 2.0], [-2.0, 0.0], [0.0, -2.0]]]], + dtype=torch.float32, + ), + "Moderately out of bounds coordinates", + ), + ] + + for grid, desc in test_cases: + with self.subTest(desc=desc): + # Test with zeros padding (most common for out-of-bounds) + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ {desc}") + + print("✓ Passed special value tests") + + +def main(): + """Run the tests.""" + print("\n" + "=" * 70) + print("ExecuTorch grid_sampler_2d Test Suite") + print("Testing via model export and ExecuTorch runtime") + print("=" * 70) + + # Run tests with verbose output + suite = unittest.TestLoader().loadTestsFromTestCase(GridSampler2DExecutorchTest) + runner = unittest.TextTestRunner(verbosity=2) + result = runner.run(suite) + + # Print summary + print("\n" + "=" * 70) + print("Test Summary") + print("=" * 70) + print(f"Tests run: {result.testsRun}") + print(f"Failures: {len(result.failures)}") + print(f"Errors: {len(result.errors)}") + + if result.wasSuccessful(): + print("\n✓ All tests passed!") + return 0 + else: + print("\n✗ Some tests failed") + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/TARGETS new file mode 100644 index 0000000..77b3834 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/TARGETS @@ -0,0 +1,7 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_copy_index.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_copy_index.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_copy_index.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_copy_index.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_copy_index.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_copy_index.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_copy_index.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_copy_index.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_view.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_view.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_view.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_view.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_view.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_view.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/et_view.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/et_view.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/register_prim_ops.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/register_prim_ops.cpp similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/register_prim_ops.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/register_prim_ops.cpp index 62eb089..7ff2f1f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/register_prim_ops.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/register_prim_ops.cpp @@ -654,13 +654,21 @@ static Kernel prim_ops[] = { #if !defined(EXECUTORCH_ENABLE_PRIM_OPS_SELECTIVE_BUILD) || \ defined(INCLUDE_EXECUTORCH_PRIM_ET_COPY_INDEX_TENSOR) // executorch_prim::et_copy_index.tensor(tensor, tensor) -> tensor - Kernel("executorch_prim::et_copy_index.tensor", et_copy_index), + Kernel( + "executorch_prim::et_copy_index.tensor", + [](KernelRuntimeContext& context, Span stack) { + et_copy_index(context, stack); + }), #endif #if !defined(EXECUTORCH_ENABLE_PRIM_OPS_SELECTIVE_BUILD) || \ defined(INCLUDE_EXECUTORCH_PRIM_ET_VIEW_DEFAULT) // executorch_prim::et_view.default(Tensor, int[]) -> Tensor - Kernel("executorch_prim::et_view.default", et_view), + Kernel( + "executorch_prim::et_view.default", + [](KernelRuntimeContext& context, Span stack) { + et_view(context, stack); + }), #endif }; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/selective_build_prim_ops.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/selective_build_prim_ops.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/prim_ops/selective_build_prim_ops.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/selective_build_prim_ops.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/targets.bzl new file mode 100644 index 0000000..1750eb5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/targets.bzl @@ -0,0 +1,78 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Define the filegroup once outside the loop since it doesn't vary by aten mode + runtime.filegroup( + name = "prim_ops_sources", + srcs = ["register_prim_ops.cpp"], + visibility = ["PUBLIC"], + ) + + runtime.filegroup( + name = "selective_build_prim_ops.h", + srcs = ["selective_build_prim_ops.h"], + visibility = ["PUBLIC"], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "et_copy_index" + aten_suffix, + srcs = ["et_copy_index.cpp"], + # To allow for selective prim ops to depend on this library. + # Used by selective_build.bzl + visibility = ["PUBLIC"], + exported_headers = ["et_copy_index.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes" + aten_suffix, + "//executorch/runtime/core:core", + ], + exported_deps = [ + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "et_view" + aten_suffix, + srcs = ["et_view.cpp"], + # To allow for selective prim ops to depend on this library. + # Used by selective_build.bzl + visibility = ["PUBLIC"], + exported_headers = ["et_view.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes" + aten_suffix, + "//executorch/runtime/core:core", + ], + exported_deps = [ + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "prim_ops_registry" + aten_suffix, + srcs = ["register_prim_ops.cpp"], + visibility = ["PUBLIC"], + # @lint-ignore BUCKLINT link_whole, need this to register prim ops. + link_whole = True, + # prim ops are registered through a global table so the ctor needs to be allowed + compiler_flags = select({ + "DEFAULT": ["-Wno-global-constructors"], + "ovr_config//os:windows": [], + }), + deps = [ + ":et_copy_index" + aten_suffix, + ":et_view" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:operator_registry" + aten_suffix, + "//executorch/runtime/kernel:kernel_includes" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/BUCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/CMakeLists.txt new file mode 100644 index 0000000..c92daad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs prim_ops_test.cpp) + +et_cxx_test(kernels_prim_ops_test SOURCES ${_test_srcs} EXTRA_LIBS executorch) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/TARGETS new file mode 100644 index 0000000..d910e24 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/TARGETS @@ -0,0 +1,37 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") + +oncall("executorch") + +python_unittest( + name = "prim_ops_test_py", + srcs = [ + "prim_ops_test.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/exir/passes:prim_ops_py_registry", + ], +) + +runtime.cxx_test( + name = "prim_ops_test_cpp", + srcs = [ + "prim_ops_test.cpp", + ], + deps = [ + "//executorch/kernels/prim_ops:prim_ops_registry", # @manual + "//executorch/kernels/test:test_util", # @manual + "//executorch/runtime/core:evalue", # @manual + "//executorch/runtime/core/exec_aten:lib", # @manual + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", # @manual + "//executorch/runtime/core/exec_aten/util:tensor_util", # @manual + "//executorch/runtime/kernel:kernel_runtime_context", # @manual + "//executorch/runtime/kernel:operator_registry", + "//executorch/runtime/platform:platform", + "//executorch/test/utils:utils", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.cpp new file mode 100644 index 0000000..37a4e8b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.cpp @@ -0,0 +1,932 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using executorch::aten::SizesType; +using torch::executor::Error; +using torch::executor::resize_tensor; +using torch::executor::Span; + +namespace torch { +namespace executor { + +class RegisterPrimOpsTest : public OperatorTest { + protected: + void SetUp() override { + context_ = KernelRuntimeContext(); + } +}; + +TEST_F(RegisterPrimOpsTest, OpRegistered) { + EXPECT_TRUE(hasOpsFn("aten::sym_size.int")); + EXPECT_TRUE(hasOpsFn("aten::sym_numel")); + EXPECT_TRUE(hasOpsFn("executorch_prim::sym_max.Scalar")); + EXPECT_TRUE(hasOpsFn("executorch_prim::sym_min.Scalar")); +} + +TEST_F(RegisterPrimOpsTest, SymSizeReturnsCorrectValue) { + testing::TensorFactory tf; + + Tensor self_tensor = tf.ones({3, 5}); + EValue values[3]; + int64_t dim = 1; + int64_t out = 0; + values[0] = EValue(self_tensor); + values[1] = EValue(dim); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("aten::sym_size.int")(context_, Span(stack)); + + int64_t expected = 5; + EXPECT_EQ(stack[2]->toInt(), expected); +} + +TEST_F(RegisterPrimOpsTest, SymNumelReturnsCorrectValue) { + testing::TensorFactory tf; + + Tensor self_tensor = tf.ones({3, 5}); + EValue values[2]; + int64_t out = 0; + values[0] = EValue(self_tensor); + values[1] = EValue(out); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + getOpsFn("aten::sym_numel")(context_, Span(stack)); + + int64_t expected = 15; + EXPECT_EQ(stack[1]->toInt(), expected); +} + +TEST_F(RegisterPrimOpsTest, SymMaxReturnsCorrectValue) { + EValue values[3]; + int64_t a = 5; + int64_t b = 3; + int64_t out = 0; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with swapped values + values[0] = EValue(b); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with equal values + values[0] = EValue(a); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with negative values + a = -2; + b = -5; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), -2); +} + +TEST_F(RegisterPrimOpsTest, SymMinReturnsCorrectValue) { + EValue values[3]; + int64_t a = 5; + int64_t b = 3; + int64_t out = 0; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + // Test with swapped values + values[0] = EValue(b); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + // Test with equal values + values[0] = EValue(a); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with negative values + a = -2; + b = -5; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), -5); +} + +TEST_F(RegisterPrimOpsTest, TestAlgebraOps) { + EValue values[3]; + int64_t a = 3; + int64_t b = 4; + int64_t out = 0; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + EValue* stack2[2] = {&values[0], &values[1]}; + + getOpsFn("executorch_prim::add.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 7); + + getOpsFn("executorch_prim::sub.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), -1); + + getOpsFn("executorch_prim::mul.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 12); + + getOpsFn("executorch_prim::floordiv.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 0); + + getOpsFn("executorch_prim::truediv.Scalar")(context_, Span(stack)); + EXPECT_FLOAT_EQ(stack[2]->toDouble(), 0.75); + + getOpsFn("executorch_prim::mod.int")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + getOpsFn("executorch_prim::mod.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + getOpsFn("executorch_prim::sym_float.Scalar")( + context_, Span(stack2)); + EXPECT_FLOAT_EQ(stack[1]->toDouble(), 3.0); +} + +TEST_F(RegisterPrimOpsTest, TestETCopyIndex) { + EXPECT_TRUE(hasOpsFn("executorch_prim::et_copy_index.tensor")); + + int64_t index = 0; + testing::TensorFactory tf; + +#ifdef USE_ATEN_LIB + // ATen mode tensors don't need dynamism specification. + Tensor copy_to = tf.make({2, 2}, {0, 0, 0, 0}); +#else + std::vector buf(4); + SizesType expected_output_size[2] = {0, 2}; + Tensor copy_to = + tf.make({2, 2}, {0, 0, 0, 0}, {}, TensorShapeDynamism::DYNAMIC_BOUND); + // Resize the tensor to 0 size for the tests. + Error err = resize_tensor(copy_to, {expected_output_size, 2}); + EXPECT_EQ(err, Error::Ok); +#endif + + Tensor to_copy = tf.make({2}, {3, 4}); + + EValue values[3]; + EValue* stack[3]; + + values[0] = EValue(copy_to); + values[1] = EValue(to_copy); + values[2] = EValue(index); + + stack[0] = &values[0]; + stack[1] = &values[1]; + stack[2] = &values[2]; + + // Simple test to copy to index 0. + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack)); + + EXPECT_EQ(copy_to.sizes()[0], 1); + EXPECT_EQ(copy_to.sizes()[1], 2); + EXPECT_TENSOR_EQ(copy_to, tf.make({1, 2}, {3, 4})); + + values[1] = tf.make({2}, {5, 6}); + values[2] = EValue((int64_t)1); + // Copy to the next index, 1. + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack)); + + EXPECT_EQ(copy_to.sizes()[0], 2); + EXPECT_EQ(copy_to.sizes()[1], 2); + EXPECT_TENSOR_EQ(copy_to, tf.make({2, 2}, {3, 4, 5, 6})); +} + +TEST_F(RegisterPrimOpsTest, TestETCopyIndexMismatchShape) { + int64_t index = 1; + testing::TensorFactory tf; + + EValue values[3]; + EValue* stack[3]; + + auto copy_to = tf.make({2, 3}, {1, 2, 3, 4, 5, 6}); + auto to_copy = tf.make({2}, {1, 2}); + + values[0] = EValue(copy_to); + values[1] = EValue(to_copy); + values[2] = EValue(index); + + stack[0] = &values[0]; + stack[1] = &values[1]; + stack[2] = &values[2]; + + // Try to copy and replace at index 1. This will fail because + // copy_to.sizes[1:] and to_copy.sizes[:] don't match each other + // which is a pre-requisite for this operator. + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack))); +} + +TEST_F(RegisterPrimOpsTest, TestBooleanOps) { + EValue values[3]; + double a = 3; + double b = 4; + bool out = false; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::ge.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), false); + + getOpsFn("executorch_prim::gt.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), false); + + getOpsFn("executorch_prim::le.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), true); + + getOpsFn("executorch_prim::lt.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), true); + + getOpsFn("executorch_prim::eq.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), false); +} + +TEST_F(RegisterPrimOpsTest, LocalScalarDenseReturnsCorrectValue) { + testing::TensorFactory tf; + + Tensor self_tensor = tf.ones({1}); + const int64_t num_vals = 2; + EValue values[num_vals]; + int64_t out = 0; + values[0] = EValue(self_tensor); + values[1] = EValue(out); + + EValue* stack[num_vals]; + for (size_t i = 0; i < num_vals; i++) { + stack[i] = &values[i]; + } + + getOpsFn("aten::_local_scalar_dense")(context_, Span(stack)); + + int64_t expected = 1; + EXPECT_EQ(stack[1]->toInt(), expected); +} + +TEST_F(RegisterPrimOpsTest, NegScalarReturnsCorrectValue) { + EValue values[2]; + + // Test with float + values[0] = EValue(5.0f); + values[1] = EValue(0.0f); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::neg.Scalar")(context_, Span(stack)); + + EXPECT_EQ(stack[1]->toDouble(), -5.0f); + + // Test with int + int64_t a = 5; + int64_t b = 0; + values[0] = EValue(a); + values[1] = EValue(b); + + getOpsFn("executorch_prim::neg.Scalar")(context_, Span(stack)); + + EXPECT_EQ(stack[1]->toInt(), -5l); +} + +TEST_F(RegisterPrimOpsTest, TestNegScalarWithTensorFails) { + testing::TensorFactory tf; + + EValue values[2]; + + auto tensor = tf.make({2, 3}, {1, 2, 3, 4, 5, 6}); + + int64_t zero = 0; + values[0] = EValue(tensor); + values[1] = EValue(zero); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + // Try to negate a tensor, which should cause a runtime error. + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::neg.Scalar")(context_, Span(stack))); +} + +TEST_F(RegisterPrimOpsTest, TestETView) { + EXPECT_TRUE(hasOpsFn("executorch_prim::et_view.default")); + + testing::TensorFactory tf; + + // *************************************************************************** + // Make self for tests + // *************************************************************************** + auto self = tf.make({3, 2}, {1, 2, 3, 4, 5, 6}); + auto self_evalue = EValue(self); + + // *************************************************************************** + // Make size for tests + // *************************************************************************** + int64_t size[3] = {1, 3, -1}; + EValue size_as_evals[3] = {EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list); + + int64_t bad_size1[3] = {-1, 3, -1}; // two inferred dimensions + EValue bad_size_as_evals1[3] = { + EValue(bad_size1[0]), EValue(bad_size1[1]), EValue(bad_size1[2])}; + EValue* bad_size_wrapped_vals1[3] = { + &bad_size_as_evals1[0], &bad_size_as_evals1[1], &bad_size_as_evals1[2]}; + int64_t bad_size_unwrapped_vals1[3] = {0, 0, 0}; + BoxedEvalueList bad_size_boxed_list1( + bad_size_wrapped_vals1, bad_size_unwrapped_vals1, 3); + EValue bad_size_int_list_evalue1 = EValue(&bad_size_boxed_list1); + + int64_t bad_size2[3] = {-2, -3, 1}; // negative size not supported + EValue bad_size_as_evals2[3] = { + EValue(bad_size2[0]), EValue(bad_size2[1]), EValue(bad_size2[2])}; + EValue* bad_size_wrapped_vals2[3] = { + &bad_size_as_evals2[0], &bad_size_as_evals2[1], &bad_size_as_evals2[2]}; + int64_t bad_size_unwrapped_vals2[3] = {0, 0, 0}; + BoxedEvalueList bad_size_boxed_list2( + bad_size_wrapped_vals2, bad_size_unwrapped_vals2, 3); + EValue bad_size_int_list_evalue2 = EValue(&bad_size_boxed_list2); + + // *************************************************************************** + // Make outs for tests + // *************************************************************************** + constexpr int N_GOOD_OUTS = 2; + Tensor good_outs[N_GOOD_OUTS] = { + tf.ones({1, 3, 2}), // correct size with nullptr + tf.ones({1, 3, 2}), // correct size with self data_ptr + }; + internal::reset_data_ptr(good_outs[0]); + ET_CHECK( + internal::set_tensor_data( + good_outs[1], self.mutable_data_ptr(), good_outs[1].nbytes()) == + Error::Ok); + EValue good_out_evalues[N_GOOD_OUTS] = { + EValue(good_outs[0]), EValue(good_outs[1])}; + + // bad outs expect death + constexpr int N_BAD_OUTS = 2; + Tensor bad_outs[N_BAD_OUTS] = { + tf.ones({1, 3, 2, 1}), // wrong rank + tf.ones({1, 3, 3}) // wrong size + }; + EValue bad_out_evalues[N_BAD_OUTS] = { + EValue(bad_outs[0]), EValue(bad_outs[1])}; + + // *************************************************************************** + // Run tests + // *************************************************************************** + + constexpr int N_BAD_STACKS = N_BAD_OUTS + 2; + EValue* bad_stacks[N_BAD_STACKS][3] = { + // Bad out stacks + {&self_evalue, &size_int_list_evalue, &bad_out_evalues[0]}, + {&self_evalue, &size_int_list_evalue, &bad_out_evalues[1]}, + // Bad size stacks + {&self_evalue, &bad_size_int_list_evalue1, &good_out_evalues[0]}, + {&self_evalue, &bad_size_int_list_evalue2, &good_out_evalues[0]}}; + + // Bad stacks expect death + for (int i = 0; i < N_BAD_STACKS; i++) { + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_view.default")( + context_, Span(bad_stacks[i]))); + } + + constexpr int N_GOOD_STACKS = N_GOOD_OUTS; + EValue* good_out_stacks[N_GOOD_STACKS][3] = { + {&self_evalue, &size_int_list_evalue, &good_out_evalues[0]}, + {&self_evalue, &size_int_list_evalue, &good_out_evalues[1]}}; + + // Good outs expect no death and correct output + for (int i = 0; i < N_GOOD_STACKS; i++) { + getOpsFn("executorch_prim::et_view.default")( + context_, Span(good_out_stacks[i])); + EXPECT_TENSOR_EQ(good_outs[i], tf.make({1, 3, 2}, {1, 2, 3, 4, 5, 6})); + EXPECT_EQ(good_outs[i].const_data_ptr(), self.const_data_ptr()); + } +} + +TEST_F(RegisterPrimOpsTest, TestETViewDynamic) { + testing::TensorFactory tf; + + auto self = tf.make({3, 1}, {1, 2, 3}); + auto self_evalue = EValue(self); + + int64_t size[3] = {1, 3, -1}; // inferred size should be {1, 3, 1} + // Construct the size as an EValue int_list + EValue size_as_evals[3] = {EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list_2( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_2); + +#ifdef USE_ATEN_LIB + // ATen mode tensors don't need dynamism specification. + auto out = tf.make({3, 2, 1}, {0, 0, 0, 0, 0, 0}); +#else + auto out = tf.make( + {3, 2, 1}, {0, 0, 0, 0, 0, 0}, {}, TensorShapeDynamism::DYNAMIC_BOUND); +#endif + + internal::reset_data_ptr(out); + EValue out_evalue = EValue(out); + + EValue* stack[3] = {&self_evalue, &size_int_list_evalue, &out_evalue}; + + getOpsFn("executorch_prim::et_view.default")(context_, Span(stack)); + + EXPECT_TENSOR_EQ(out, tf.make({1, 3, 1}, {1, 2, 3})); + EXPECT_EQ(out.const_data_ptr(), self.const_data_ptr()); +} + +TEST_F(RegisterPrimOpsTest, TestETViewEmpty) { + testing::TensorFactory tf; + + auto self = tf.make({3, 1, 0}, {}); + auto self_evalue = EValue(self); + EXPECT_EQ(self.const_data_ptr(), nullptr); // empty tensor has null data + + // Construct the sizes + int64_t size[3] = {3, 1, -1}; + EValue size_as_evals[3] = {EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list_3( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_3); + + int64_t bad_size[3] = {0, 1, -1}; // bad size: cannot infer with 0 + EValue bad_size_as_evals[3] = { + EValue(bad_size[0]), EValue(bad_size[1]), EValue(bad_size[2])}; + EValue* bad_size_wrapped_vals[3] = { + &bad_size_as_evals[0], &bad_size_as_evals[1], &bad_size_as_evals[2]}; + int64_t bad_size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList bad_size_boxed_list( + bad_size_wrapped_vals, bad_size_unwrapped_vals, 3); + EValue bad_size_int_list_evalue = EValue(&bad_size_boxed_list); + + auto out = tf.make({3, 1, 0}, {}, {}); + EValue out_evalue = EValue(out); + EXPECT_EQ(out.const_data_ptr(), nullptr); + + // good size test + EValue* stack[3] = {&self_evalue, &size_int_list_evalue, &out_evalue}; + getOpsFn("executorch_prim::et_view.default")(context_, Span(stack)); + EXPECT_TENSOR_EQ(out, tf.make({3, 1, 0}, {})); + EXPECT_EQ(out.const_data_ptr(), self.const_data_ptr()); + + // bad size test + EValue* bad_stack[3] = {&self_evalue, &bad_size_int_list_evalue, &out_evalue}; + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_view.default")( + context_, Span(bad_stack))); +} + +TEST_F(RegisterPrimOpsTest, TestCeil) { + std::array inputs = { + 0.0, 0.25, 0.5, 0.75, 1.0, 1.75, -0.5, -1.0, -1.5, 9.999999}; + std::array expected = {0, 1, 1, 1, 1, 2, 0, -1, -1, 10}; + + for (auto i = 0; i < inputs.size(); i++) { + EValue values[2]; + values[0] = EValue(inputs[i]); + values[1] = EValue(0.0); + + EValue* stack[2]; + for (size_t j = 0; j < 2; j++) { + stack[j] = &values[j]; + } + + getOpsFn("executorch_prim::ceil.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[1]->toInt(), expected[i]); + } +} + +TEST_F(RegisterPrimOpsTest, TestRound) { + // Note that Python uses round-to-even for halfway values. + std::array inputs = { + 0.0, 0.25, 0.5, 0.75, 1.0, 1.5, -0.5, -1.0, -1.5, 9.999999}; + std::array expected = {0, 0, 0, 1, 1, 2, 0, -1, -2, 10}; + + for (auto i = 0; i < inputs.size(); i++) { + EValue values[2]; + values[0] = EValue(inputs[i]); + values[1] = EValue(0.0); + + EValue* stack[2]; + for (size_t j = 0; j < 2; j++) { + stack[j] = &values[j]; + } + + getOpsFn("executorch_prim::round.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[1]->toInt(), expected[i]); + } +} + +TEST_F(RegisterPrimOpsTest, TestTrunc) { + std::array inputs = { + 0.0, 0.25, 0.5, 0.75, 1.0, 1.75, -0.5, -1.0, -1.5, 9.999999}; + std::array expected = {0, 0, 0, 0, 1, 1, 0, -1, -1, 9}; + + for (auto i = 0; i < inputs.size(); i++) { + EValue values[2]; + values[0] = EValue(inputs[i]); + values[1] = EValue(0.0); + + EValue* stack[2]; + for (size_t j = 0; j < 2; j++) { + stack[j] = &values[j]; + } + + getOpsFn("executorch_prim::trunc.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[1]->toInt(), expected[i]); + } +} + +// Test that each prim op returns InvalidProgram error when given a stack that's +// one element shorter than expected +TEST_F(RegisterPrimOpsTest, TestInvalidProgramErrorOnShortStack) { + // Test aten::sym_size.int with a stack of size 2 (missing output) + { + testing::TensorFactory tf; + Tensor self_tensor = tf.ones({3, 5}); + EValue values[2]; + int64_t dim = 1; + values[0] = EValue(self_tensor); + values[1] = EValue(dim); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("aten::sym_size.int")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), torch::executor::Error::InvalidProgram); + } + + // Test aten::sym_numel with a stack of size 1 (missing output) + { + testing::TensorFactory tf; + Tensor self_tensor = tf.ones({3, 5}); + EValue values[1]; + values[0] = EValue(self_tensor); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, getOpsFn("aten::sym_numel")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), torch::executor::Error::InvalidProgram); + } + + // Test executorch_prim::sym_max.Scalar with a stack of size 2 (missing + // output) + { + EValue values[2]; + int64_t a = 5; + int64_t b = 3; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sym_max.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::sym_min.Scalar with a stack of size 2 (missing + // output) + { + EValue values[2]; + int64_t a = 5; + int64_t b = 3; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sym_min.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test algebra ops with a stack of size 2 (missing output) + { + EValue values[2]; + int64_t a = 3; + int64_t b = 4; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::add.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sub.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::mul.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::floordiv.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::truediv.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::mod.int")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::mod.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::sym_float.Scalar with a stack of size 1 (missing + // output) + { + EValue values[1]; + int64_t a = 3; + values[0] = EValue(a); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sym_float.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test boolean ops with a stack of size 2 (missing output) + { + EValue values[2]; + double a = 3; + double b = 4; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::ge.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::gt.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::le.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::lt.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::eq.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test aten::_local_scalar_dense with a stack of size 1 (missing output) + { + testing::TensorFactory tf; + Tensor self_tensor = tf.ones({1}); + EValue values[1]; + values[0] = EValue(self_tensor); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("aten::_local_scalar_dense")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::neg.Scalar with a stack of size 1 (missing output) + { + EValue values[1]; + values[0] = EValue(5.0f); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::neg.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::et_copy_index.tensor with a stack of size 2 (missing + // index) + { + testing::TensorFactory tf; + auto copy_to = tf.make({2, 2}, {0, 0, 0, 0}); + auto to_copy = tf.make({2}, {3, 4}); + + EValue values[2]; + values[0] = EValue(copy_to); + values[1] = EValue(to_copy); + + EValue* stack[2]; + stack[0] = &values[0]; + stack[1] = &values[1]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::et_view.default with a stack of size 2 (missing + // output) + { + testing::TensorFactory tf; + auto self = tf.make({3, 2}, {1, 2, 3, 4, 5, 6}); + auto self_evalue = EValue(self); + + int64_t size[3] = {1, 3, -1}; + EValue size_as_evals[3] = { + EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list_4( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_4); + + EValue* stack[2] = {&self_evalue, &size_int_list_evalue}; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_view.default")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test ceil, round, trunc with a stack of size 1 (missing output) + { + EValue values[1]; + values[0] = EValue(5.5); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::ceil.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::round.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::trunc.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } +} + +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.py new file mode 100644 index 0000000..62e7a2c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/prim_ops/test/prim_ops_test.py @@ -0,0 +1,23 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +# necessary to ensure the ops are registered +import executorch.exir.passes.executorch_prim_ops_registry # noqa: F401 + +import torch + + +# This class tests whether we can generate correct code to register the prim ops into PyTorch runtime. +class TestCustomOps(unittest.TestCase): + def setUp(self) -> None: + self.x = 1 + self.y = 2 + + def test_add_registered(self) -> None: + out_1 = torch.ops.executorch_prim.add.Scalar(self.x, self.y) + self.assertEqual(out_1, 3) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/CMakeLists.txt new file mode 100644 index 0000000..d4fc52a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/CMakeLists.txt @@ -0,0 +1,158 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Kernel library for quantized operators. Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +set(_common_compile_options -Wno-deprecated-declarations) + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Codegen.cmake) + +# Quantized ops kernel sources TODO(larryliu0820): use buck2 to gather the +# sources +list(TRANSFORM _quantized_kernels__srcs PREPEND "${EXECUTORCH_ROOT}/") +# Generate C++ bindings to register kernels into both PyTorch (for AOT) and +# Executorch (for runtime). Here select all ops in quantized.yaml +set(_yaml_file ${CMAKE_CURRENT_LIST_DIR}/quantized.yaml) +gen_selected_ops(LIB_NAME "quantized_ops_lib" OPS_SCHEMA_YAML "${_yaml_file}") + +# Expect gen_selected_ops output file to be selected_operators.yaml +generate_bindings_for_kernels( + LIB_NAME "quantized_ops_lib" CUSTOM_OPS_YAML "${_yaml_file}" +) +message("Generated files ${gen_command_sources}") + +# Not targeting Xcode, because the custom command generating +# kernels/quantized/selected_operators.yaml is attached to multiple targets: +# quantized_ops_aot_lib quantized_ops_lib but none of these is a common +# dependency of the other(s). This is not allowed by the Xcode "new build +# system". +if(NOT CMAKE_GENERATOR STREQUAL "Xcode" + AND EXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT +) + # Not targeting ARM_BAREMETAL as aot_lib depends on incompatible libraries + if(NOT EXECUTORCH_BUILD_ARM_BAREMETAL) + set(_quantized_aot_ops + "quantized_decomposed::add.out" + "quantized_decomposed::choose_qparams.Tensor_out" + "quantized_decomposed::choose_qparams_per_token_asymmetric.out" + "quantized_decomposed::dequantize_per_channel.out" + "quantized_decomposed::dequantize_per_tensor.out" + "quantized_decomposed::dequantize_per_tensor.Tensor_out" + "quantized_decomposed::dequantize_per_token.out" + "quantized_decomposed::mixed_linear.out" + "quantized_decomposed::mixed_mm.out" + "quantized_decomposed::quantize_per_channel.out" + "quantized_decomposed::quantize_per_tensor.out" + "quantized_decomposed::quantize_per_tensor.Tensor_out" + "quantized_decomposed::quantize_per_token.out" + ) + gen_selected_ops( + LIB_NAME "quantized_ops_aot_lib" ROOT_OPS ${_quantized_aot_ops} + ) + # Expect gen_selected_ops output file to be + # quantized_ops_aot_lib/selected_operators.yaml + generate_bindings_for_kernels( + LIB_NAME "quantized_ops_aot_lib" CUSTOM_OPS_YAML "${_yaml_file}" + ) + # Build a AOT library to register quantized ops into PyTorch. This is a + # hack. + set(_quantized_sources + ${_quantized_kernels__srcs} + ${EXECUTORCH_ROOT}/kernels/portable/cpu/util/reduce_util.cpp + ${EXECUTORCH_ROOT}/runtime/core/exec_aten/util/tensor_util_aten.cpp + ) + gen_custom_ops_aot_lib( + LIB_NAME "quantized_ops_aot_lib" KERNEL_SOURCES "${_quantized_sources}" + ) + + # Register quantized ops to portable_lib, so that they're available via + # pybindings. + if(TARGET portable_lib) + add_library(quantized_pybind_kernels_lib ${_quantized_kernels__srcs}) + target_link_libraries( + quantized_pybind_kernels_lib PRIVATE portable_lib executorch_core + kernels_util_all_deps + ) + target_compile_options( + quantized_pybind_kernels_lib PUBLIC ${_common_compile_options} + ) + target_include_directories( + quantized_pybind_kernels_lib PUBLIC "${_common_include_directories}" + ) + gen_selected_ops( + LIB_NAME "quantized_ops_pybind_lib" OPS_SCHEMA_YAML "${_yaml_file}" + ) + generate_bindings_for_kernels( + LIB_NAME "quantized_ops_pybind_lib" CUSTOM_OPS_YAML "${_yaml_file}" + ) + # Build a library for pybind usage. quantized_ops_pybind_lib: Register + # quantized ops kernels into Executorch runtime for pybind. + gen_operators_lib( + LIB_NAME "quantized_ops_pybind_lib" KERNEL_LIBS + quantized_pybind_kernels_lib DEPS portable_lib + ) + target_link_libraries( + quantized_ops_aot_lib PUBLIC quantized_ops_pybind_lib + ) + + # pip wheels will need to be able to find the dependent libraries. On + # Linux, the .so has non-absolute dependencies on libs like + # "_portable_lib.so" without paths; as long as we `import torch` first, + # those dependencies will work. But Apple dylibs do not support + # non-absolute dependencies, so we need to tell the loader where to look + # for its libraries. The LC_LOAD_DYLIB entries for the portable_lib + # libraries will look like "@rpath/_portable_lib.cpython-310-darwin.so", + # so we can add an LC_RPATH entry to look in a directory relative to the + # installed location of our _portable_lib.so file. To see these LC_* + # values, run `otool -l libquantized_ops_lib.dylib`. + if(APPLE) + set(RPATH "@loader_path/../../extensions/pybindings") + else() + set(RPATH "$ORIGIN/../../extensions/pybindings") + endif() + set_target_properties( + quantized_ops_aot_lib PROPERTIES BUILD_RPATH ${RPATH} INSTALL_RPATH + ${RPATH} + ) + endif() + endif() +endif() + +add_library(quantized_kernels ${_quantized_kernels__srcs}) +target_link_libraries( + quantized_kernels PRIVATE executorch_core kernels_util_all_deps +) +target_compile_options(quantized_kernels PUBLIC ${_common_compile_options}) +# Build a library for _quantized_kernels_srcs +# +# quantized_ops_lib: Register quantized ops kernels into Executorch runtime +gen_operators_lib( + LIB_NAME "quantized_ops_lib" KERNEL_LIBS quantized_kernels DEPS + executorch_core +) + +install( + TARGETS quantized_kernels quantized_ops_lib + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/executorch/kernels/quantized/ +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/README.md new file mode 100644 index 0000000..f193130 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/README.md @@ -0,0 +1,12 @@ +# Quantized Ops + +This folder contains kernels for quantization related ops, similar to `//executorch/kernels/portable/`. + +## How to add quantized ops + +1. Add a new operator definition in `quantized.yaml` + +2. Implement the kernel for this operator. +3. Add unit test in `/test` directory. +4. Start to use `//executorch/kernels/quantized:generated_lib` in ExecuTorch or + create your own generated lib if you only need a subset of the ops. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/TARGETS new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/TARGETS @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/__init__.py new file mode 100644 index 0000000..3883630 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/__init__.py @@ -0,0 +1,21 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +try: + from pathlib import Path + + libs = list(Path(__file__).parent.resolve().glob("**/*quantized_ops_aot_lib.*")) + del Path + assert len(libs) == 1, f"Expected 1 library but got {len(libs)}" + import torch as _torch + + _torch.ops.load_library(libs[0]) + del _torch +except: + import logging + + logging.info("libquantized_ops_aot_lib is not loaded") + del logging diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/TARGETS new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/TARGETS @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/embeddingxb.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/embeddingxb.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/embeddingxb.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/embeddingxb.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/embeddingxb.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/embeddingxb.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/embeddingxb.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/embeddingxb.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_add.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_add.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_choose_qparams.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_choose_qparams.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_choose_qparams.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_choose_qparams.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_dequantize.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_dequantize.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_dequantize.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_dequantize.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_embedding.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_embedding.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_embedding.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_embedding.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_embedding2b.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_embedding2b.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_embedding2b.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_embedding2b.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_embedding4b.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_embedding4b.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_embedding4b.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_embedding4b.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_mixed_linear.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_mixed_linear.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_mixed_linear.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_mixed_linear.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_mixed_mm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_mixed_mm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_mixed_mm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_mixed_mm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_quantize.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_quantize.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/cpu/op_quantize.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/op_quantize.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/targets.bzl new file mode 100644 index 0000000..88a3823 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/cpu/targets.bzl @@ -0,0 +1,102 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("@fbsource//xplat/executorch/kernels/portable:op_registration_util.bzl", "define_op_target", "op_target") + +_QUANT_OPS = ( + op_target( + name = "op_add", + ), + op_target( + name = "op_choose_qparams", + deps = [ + "//executorch/kernels/portable/cpu:vec_ops", + "//executorch/extension/threadpool:threadpool", + ], + ), + op_target( + name = "op_dequantize", + deps = [ + "//executorch/kernels/portable/cpu/util:reduce_util", + ], + _aten_mode_deps = [ + "//executorch/kernels/portable/cpu/util:reduce_util_aten", + ], + ), + op_target( + name = "op_embedding", + ), + op_target( + name = "op_embedding2b", + deps = ["//executorch/kernels/quantized/cpu:embeddingxb"], + _aten_mode_deps = [ + "//executorch/kernels/quantized/cpu:embeddingxb_aten", + ], + ), + op_target( + name = "op_embedding4b", + deps = ["//executorch/kernels/quantized/cpu:embeddingxb"], + _aten_mode_deps = [ + "//executorch/kernels/quantized/cpu:embeddingxb_aten", + ], + ), + op_target( + name = "op_mixed_mm", + deps = [ + "//executorch/kernels/portable/cpu:vec_ops", + ], + ), + op_target( + name = "op_mixed_linear", + deps = [ + "//executorch/kernels/portable/cpu:vec_ops", + ], + ), + op_target( + name = "op_quantize", + deps = [ + "//executorch/extension/threadpool:threadpool", + ], + ), +) + +def define_common_targets(): + for op in _QUANT_OPS: + define_op_target(is_aten_op = False, **op) + + quant_op_targets = [":{}".format(op["name"]) for op in _QUANT_OPS] + + runtime.cxx_library( + name = "quantized_cpu", + srcs = [], + visibility = [ + "//executorch/kernels/quantized/...", + "//executorch/extension/pybindings/test/...", + ], + exported_deps = quant_op_targets, + ) + + runtime.cxx_library( + name = "embeddingxb", + srcs = ["embeddingxb.cpp"], + exported_headers = ["embeddingxb.h"], + visibility = [ + "//executorch/kernels/quantized/...", + ], + deps = ["//executorch/runtime/kernel:kernel_includes"], + ) + + runtime.cxx_library( + name = "embeddingxb_aten", + srcs = ["embeddingxb.cpp"], + exported_headers = ["embeddingxb.h"], + visibility = [ + "//executorch/kernels/quantized/...", + ], + deps = ["//executorch/runtime/kernel:kernel_includes_aten"], + ) + + runtime.cxx_library( + name = "quantized_cpu_aten", + srcs = [], + visibility = ["//executorch/kernels/quantized/..."], + exported_deps = [t + "_aten" for t in quant_op_targets], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/quantized.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/quantized.yaml similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/quantized/quantized.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/quantized.yaml diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/targets.bzl new file mode 100644 index 0000000..86fe81e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/targets.bzl @@ -0,0 +1,130 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib", "exir_custom_ops_aot_lib") + +def define_common_targets(): + runtime.export_file( + name = "quantized.yaml", + visibility = ["PUBLIC"], + ) + + # Excluding embedding_byte ops because we choose to define them + # in python separately, mostly to be easy to share with oss. + et_operator_library( + name = "quantized_ops_need_aot_registration", + ops = [ + "quantized_decomposed::add.out", + "quantized_decomposed::choose_qparams.Tensor_out", + "quantized_decomposed::choose_qparams_per_token_asymmetric.out", + "quantized_decomposed::dequantize_per_channel.out", + "quantized_decomposed::dequantize_per_tensor.out", + "quantized_decomposed::dequantize_per_tensor.Tensor_out", + "quantized_decomposed::dequantize_per_token.out", + "quantized_decomposed::mixed_linear.out", + "quantized_decomposed::mixed_mm.out", + "quantized_decomposed::quantize_per_channel.out", + "quantized_decomposed::quantize_per_tensor.out", + "quantized_decomposed::quantize_per_tensor.Tensor_out", + "quantized_decomposed::quantize_per_token.out", + ], + define_static_targets = True, + ) + + # lib used to register quantized ops into EXIR + exir_custom_ops_aot_lib( + name = "custom_ops_generated_lib", + yaml_target = ":quantized.yaml", + visibility = ["PUBLIC"], + kernels = [":quantized_operators_aten"], + deps = [ + ":quantized_ops_need_aot_registration", + ], + ) + + # lib used to register quantized ops into EXIR + # TODO: merge this with custom_ops_generated_lib + exir_custom_ops_aot_lib( + name = "aot_lib", + yaml_target = ":quantized.yaml", + visibility = ["PUBLIC"], + kernels = [":quantized_operators_aten"], + deps = [ + ":quantized_ops_need_aot_registration", + ], + ) + + et_operator_library( + name = "all_quantized_ops", + ops_schema_yaml_target = ":quantized.yaml", + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + # On Windows we can only compile these two ops currently, so adding a + # separate target for this. + et_operator_library( + name = "q_dq_ops", + ops = [ + "quantized_decomposed::dequantize_per_tensor.out", + "quantized_decomposed::dequantize_per_tensor.Tensor_out", + "quantized_decomposed::quantize_per_tensor.out", + "quantized_decomposed::quantize_per_tensor.Tensor_out", + "quantized_decomposed::dequantize_per_channel.out", + "quantized_decomposed::quantize_per_channel.out", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_library( + name = "quantized_operators" + aten_suffix, + srcs = [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/kernels/quantized/cpu:quantized_cpu" + aten_suffix, + ], + ) + + for support_exceptions in [True, False]: + exception_suffix = "_no_exceptions" if not support_exceptions else "" + + executorch_generated_lib( + name = "generated_lib" + aten_suffix + exception_suffix, + deps = [ + ":quantized_operators" + aten_suffix, + ":all_quantized_ops", + ], + custom_ops_yaml_target = ":quantized.yaml", + custom_ops_aten_kernel_deps = [":quantized_operators_aten"] if aten_mode else [], + custom_ops_requires_aot_registration = False, + aten_mode = aten_mode, + support_exceptions = support_exceptions, + visibility = ["PUBLIC"], + define_static_targets = True, + ) + + # On Windows we can only compile these two ops currently, so adding a + # separate target for this. + executorch_generated_lib( + name = "q_dq_ops_generated_lib" + aten_suffix + exception_suffix, + custom_ops_yaml_target = ":quantized.yaml", + kernel_deps = [ + "//executorch/kernels/quantized/cpu:op_quantize" + aten_suffix, + "//executorch/kernels/quantized/cpu:op_dequantize" + aten_suffix, + ], + aten_mode = aten_mode, + deps = [ + ":q_dq_ops", + ], + support_exceptions = support_exceptions, + visibility = ["PUBLIC"], + ) + + runtime.python_library( + name = "quantized_ops_lib", + srcs = ["__init__.py"], + deps = [ + "//caffe2:torch", + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/TARGETS new file mode 100644 index 0000000..16cf19a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/TARGETS @@ -0,0 +1,51 @@ +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() + +python_unittest( + name = "test_out_variants", + srcs = ["test_out_variants.py"], + preload_deps = [ + "//executorch/kernels/quantized:custom_ops_generated_lib", + ], + deps = [ + "//caffe2:torch", + "//executorch/exir/dialects:lib", + "//executorch/exir/passes:quant_fusion_pass", + "//executorch/kernels/quantized:quantized_ops_lib", + ], +) + +runtime.cxx_library( + name = "quantized_ops_for_test_lib", + srcs = [ + "quantized_ops_aot_register.cpp", + ], + visibility = ["PUBLIC"], + deps = [ + "//executorch/extension/aten_util:aten_bridge", + "//executorch/kernels/quantized/cpu:op_dequantize", + "//executorch/kernels/quantized/cpu:op_quantize", + "//executorch/runtime/core/exec_aten:lib", + ], + external_deps = [ + "libtorch", + ], +) + +python_unittest( + name = "test_quant_dequant_per_token", + srcs = [ + "test_quant_dequant_per_token.py", + ], + preload_deps = [ + ":quantized_ops_for_test_lib", + ], + deps = [ + "//caffe2:torch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_add_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_add_test.cpp new file mode 100644 index 0000000..fdf38cc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_add_test.cpp @@ -0,0 +1,413 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::add_out; +using torch::executor::native::dequantize_per_tensor_out; +using torch::executor::native::quantize_per_tensor_out; +using torch::executor::native::quantized_add_out; + +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + double scale = 0.5; + + int64_t zero_point = 1; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + quantize_per_tensor_out( + input2, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + scale, + zero_point, + quant_min, + quant_max, + qinput2, + scale, + zero_point, + quant_min, + quant_max, + scale, + zero_point, + quant_min, + quant_max, + qoutput); + + // can lossessly dq here so retrive the full 3.5 in operation + // (3.5 + 3.5) / 0.5 + 1 = 15 + Tensor expected = tfo.full({3, 5}, 15.0); + + EXPECT_TENSOR_EQ(qoutput, expected); +} + +TEST(OpQuantizeAddTest, AllDtypesSupported) { + test_dtype(); +} + +TEST(OpQuantizeAddTest, DifferentQParams) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + double a_scale = 0.5; + int64_t a_zero_point = 1; + + double b_scale = 0.25; + int64_t b_zero_point = 2; + + double out_scale = 0.1; + int64_t out_zero_point = 5; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + out_scale, + out_zero_point, + quant_min, + quant_max, + qoutput); + + // can lossessly dq here so retrive the full 3.5 in operation + // (3.5 + 3.5) / 0.1 + 5 = 75 + Tensor expected = tfo.full({3, 5}, 75.0); + + EXPECT_TENSOR_EQ(qoutput, expected); +} + +// Q -> DQ -> FP ADD -> Q -> DQ should be == to Q -> QADD -> DQ +TEST(OpQuantizeAddTest, ConsitencyWithReferencePattern) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + Tensor dq_input1 = tf.zeros({3, 5}); + Tensor dq_input2 = tf.zeros({3, 5}); + Tensor reference_op_output = tf.zeros({3, 5}); + Tensor reference_pattern_output = tf.zeros({3, 5}); + Tensor fp_output = tf.zeros({3, 5}); + + double a_scale = 0.5; + int64_t a_zero_point = 1; + + double b_scale = 0.25; + int64_t b_zero_point = 2; + + double out_scale = 0.1; + int64_t out_zero_point = 5; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + + optional out_dtype = optional(); + + KernelRuntimeContext context{}; + // q -> qadd -> dq + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + out_scale, + out_zero_point, + quant_min, + quant_max, + qoutput); + dequantize_per_tensor_out( + qoutput, + out_scale, + out_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + reference_op_output); + + // now get results for q -> dq -> fp add -> q -> dq + dequantize_per_tensor_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + dq_input1); + + dequantize_per_tensor_out( + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + dq_input2); + + add_out(context, dq_input1, dq_input2, 1.0, fp_output); + // reuse 'qoutput' tensor as an intermediate + quantize_per_tensor_out( + fp_output, + out_scale, + out_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qoutput); + + dequantize_per_tensor_out( + qoutput, + out_scale, + out_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + reference_pattern_output); + + Tensor expected = tf.full({3, 5}, 7.0); + + // Pattern and op results should both be equal to expected and each other, + // check all cases explicitly instead of relying on transitivity + EXPECT_TENSOR_EQ(reference_op_output, expected); + EXPECT_TENSOR_EQ(reference_pattern_output, expected); + EXPECT_TENSOR_EQ(reference_op_output, reference_pattern_output); +} + +TEST(OpQuantizeAddTest, InvalidMinMaxDies) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + double scale = 0.5; + int64_t zero_point = 1; + + int64_t quant_min = 0; + int64_t quant_max = 255; + int64_t out_quant_min = -1; + int64_t out_quant_max = 256; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + ET_EXPECT_DEATH( + quantized_add_out( + qinput1, + scale, + zero_point, + quant_min, + quant_max, + qinput2, + scale, + zero_point, + quant_min, + quant_max, + scale, + zero_point, + out_quant_min, + out_quant_max, + qoutput), + ""); +} + +TEST(OpQuantizeAddTest, TopOfRangeTest) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 255); + Tensor input2 = tf.full({3, 5}, 255); + double a_scale = 1; + int64_t a_zero_point = 0; + + double b_scale = 1; + int64_t b_zero_point = 0; + + double out_scale = 1; + int64_t out_zero_point = 0; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + + quantize_per_tensor_out( + input1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + out_scale, + out_zero_point, + quant_min, + quant_max, + qoutput); + + Tensor expected = tfo.full({3, 5}, 255); + + EXPECT_TENSOR_EQ(qoutput, expected); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_choose_qparams_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_choose_qparams_test.cpp new file mode 100644 index 0000000..dc92df8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_choose_qparams_test.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using torch::executor::native::choose_qparams_per_token_asymmetric_out; +using torch::executor::native::choose_qparams_tensor_out; +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({2, 2}, {1.0, 2.5, 3.2, 15.4}); + Tensor scale_out = tf_double.zeros({1}); + Tensor zero_point_out = tf_long.zeros({1}); + Tensor expected_scale = tf_double.make({1}, {0.0603922}); + Tensor expected_zero_point = tf_long.make({1}, {0}); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + choose_qparams_tensor_out( + input, quant_min, quant_max, 0.0, DTYPE, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE(scale_out, expected_scale); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, Float) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1}); + Tensor scale_out = tf_double.zeros({2, 1}); + Tensor zero_point_out = tf_long.zeros({2, 1}); + Tensor expected_scale = tf_double.make({2, 1}, {0.00666667, 0.0113725485}); + Tensor expected_zero_point = tf_long.make({2, 1}, {-53, -58}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, ExtraDimFloat) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({1, 2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1}); + Tensor scale_out = tf_double.zeros({1, 2, 1}); + Tensor zero_point_out = tf_long.zeros({1, 2, 1}); + Tensor expected_scale = tf_double.make({1, 2, 1}, {0.00666667, 0.0113725485}); + Tensor expected_zero_point = tf_long.make({1, 2, 1}, {-53, -58}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, LargeArray) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make( + {5, 17}, + {0.41654, 0.26599, 0.4141, 0.83809, 0.02938, 0.12199, 0.53667, + 0.799, 0.6606, 0.46657, 0.66142, 0.71787, 0.56098, 0.30202, + 0.059377, 0.85473, 0.8017, 0.2703, 0.44299, 0.49045, 0.75581, + 0.24429, 0.43906, 0.78652, 0.83885, 0.31034, 0.76534, 0.74422, + 0.62549, 0.80006, 0.38144, 0.70652, 0.33553, 0.89136, 0.49126, + 0.072916, 0.75654, 0.82057, 0.083848, 0.29753, 0.62718, 0.95579, + 0.83097, 0.47293, 0.15666, 0.6248, 0.21672, 0.14626, 0.71834, + 0.93664, 0.23382, 0.68931, 0.70866, 0.60545, 0.98648, 0.30335, + 0.62439, 0.19195, 0.1923, 0.75638, 0.81114, 0.34778, 0.0070671, + 0.50918, 0.19698, 0.19969, 0.57687, 0.062786, 0.18447, 0.22961, + 0.29656, 0.25486, 0.75965, 0.11328, 0.86468, 0.21264, 0.99591, + 0.75231, 0.97834, 0.042441, 0.39978, 0.9633, 0.9297, 0.12188, + 0.73564}); + Tensor scale_out = tf_double.zeros({5, 1}); + Tensor zero_point_out = tf_long.zeros({5, 1}); + Tensor expected_scale = tf_double.make( + {5, 1}, {0.0033519, 0.0034955, 0.0037482, 0.0038685, 0.0039055}); + Tensor expected_zero_point = + tf_long.make({5, 1}, {-128, -128, -128, -128, -128}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-5, 1e-5); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, DynamicShapeFloat) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({1, 2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1}); + Tensor scale_out = tf_double.zeros( + {1, 5, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); + Tensor zero_point_out = tf_long.zeros( + {1, 5, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); + Tensor expected_scale = tf_double.make({1, 2, 1}, {0.00666667, 0.0113725485}); + Tensor expected_zero_point = tf_long.make({1, 2, 1}, {-53, -58}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); + + Tensor new_input = tf_float.make( + {1, 5, 8}, + {5.2254, 5.6041, 5.7653, -1.0126, -0.86126, -0.1606, -0.99196, + -1.067, 5.5913, 5.7713, 5.4901, -0.43128, -1.1759, -0.60466, + -0.82913, -0.73623, 5.4588, 5.4066, 5.2644, -0.89692, -0.16866, + -0.63169, -0.42352, -0.48866, 5.594, 5.5223, 5.5277, -0.17658, + -0.30669, -1.1777, -0.65389, -0.36422, 5.6375, 5.1857, 5.0743, + -0.46654, -0.43817, -0.41506, -0.94515, -0.60247}); + Tensor new_expected_scale = tf_double.make( + {1, 5, 1}, {0.026793, 0.027244, 0.024924, 0.026556, 0.025814}); + Tensor new_expected_zero_point = + tf_long.make({1, 5, 1}, {-88, -85, -92, -84, -91}); + + choose_qparams_per_token_asymmetric_out( + new_input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, new_expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, new_expected_zero_point); +} + +TEST( + OpChooseQparamsPerTokenAsymmetricTensorOutTest, + LargeInputParallelization) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Create input with 8 tokens x 128 elements per token = 1024 total elements + // This exceeds the MIN_ELEMENTS_FOR_PARALLEL threshold of 512 + const int num_tokens = 8; + const int token_size = 128; + std::vector input_data(num_tokens * token_size); + + // Generate test data with known min/max per token for easier verification + std::vector expected_min(num_tokens); + std::vector expected_max(num_tokens); + + for (int i = 0; i < num_tokens; i++) { + float token_min = -1.0f * (i + 1); + float token_max = 2.0f * (i + 1); + expected_min[i] = token_min; + expected_max[i] = token_max; + + for (int j = 0; j < token_size; j++) { + // Linearly interpolate between min and max + float t = j / static_cast(token_size - 1); + input_data[i * token_size + j] = token_min + t * (token_max - token_min); + } + } + + Tensor input = tf_float.make({num_tokens, token_size}, input_data); + Tensor scale_out = tf_double.zeros({num_tokens, 1}); + Tensor zero_point_out = tf_long.zeros({num_tokens, 1}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + // Manually calculate expected scale and zero_point using the same algorithm + // as calculate_scale_and_zero_point function + const int32_t qmin = -128; + const int32_t qmax = 127; + const float SMALL_SCALE_THRESHOLD = 6.1e-5f; + + for (int i = 0; i < num_tokens; i++) { + float min = std::min(expected_min[i], 0.0f); + float max = std::max(expected_max[i], 0.0f); + + // Calculate scale + double scale = (static_cast(max) - min) / (qmax - qmin); + if (float(scale) == 0.0f || std::isinf(1.0f / float(scale))) { + scale = 0.1; + } + + // Cut off small scale + if (scale < SMALL_SCALE_THRESHOLD) { + scale = SMALL_SCALE_THRESHOLD; + if (min == 0.0f) { + max = SMALL_SCALE_THRESHOLD * (qmax - qmin); + } else if (max == 0.0f) { + min = -SMALL_SCALE_THRESHOLD * (qmax - qmin); + } else { + float amplifier = SMALL_SCALE_THRESHOLD / scale; + min *= amplifier; + max *= amplifier; + } + } + + // Calculate zero_point + double zero_point_from_min = qmin - min / scale; + double zero_point_from_max = qmax - max / scale; + double zero_point_from_min_error = std::abs(qmin) - std::abs(min / scale); + double zero_point_from_max_error = std::abs(qmax) - std::abs(max / scale); + double initial_zero_point = + zero_point_from_min_error < zero_point_from_max_error + ? zero_point_from_min + : zero_point_from_max; + + int32_t nudged_zero_point = 0; + if (initial_zero_point < qmin) { + nudged_zero_point = qmin; + } else if (initial_zero_point > qmax) { + nudged_zero_point = qmax; + } else { + nudged_zero_point = + std::nearbyint(static_cast(initial_zero_point)); + } + + // Verify computed values match expected + EXPECT_NEAR(scale_out.const_data_ptr()[i], scale, 1e-6); + EXPECT_EQ(zero_point_out.const_data_ptr()[i], nudged_zero_point); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_dequantize_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_dequantize_test.cpp new file mode 100644 index 0000000..4a0c195 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_dequantize_test.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using std::optional; +using torch::executor::native::dequantize_per_channel_out; +using torch::executor::native::dequantize_per_tensor_out; +using torch::executor::native::dequantize_per_tensor_tensor_args_out; +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 100); + double scale = 0.5; + int64_t zero_point = 30; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 + Tensor expected = tfo.full({3, 5}, 35); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, AllDtypesSupported) { + et_pal_init(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); +} + +/// Test all supported output dtypes for dequantization +template +void test_output_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 100); + double scale = 0.5; + int64_t zero_point = 30; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 = 35 + Tensor expected = tfo.full({3, 5}, 35); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(OUT_DTYPE), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, AllOutputDtypesSupported) { + et_pal_init(); + test_output_dtype(); + test_output_dtype(); + test_output_dtype(); +} + +TEST(OpDequantizeOutTest, HalfOutput) { + et_pal_init(); + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 10); + double scale = 0.5; + int64_t zero_point = 100000; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (10 - 100000) * 0.5 = -49995 + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(ScalarType::Half), + out); + + // The expected result should be (10 - 100000) * 0.5 = -49995 + Tensor expected = tfo.full({3, 5}, -49995); + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, DoubleOutput) { + et_pal_init(); + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 10); + double scale = 0.5; + int64_t zero_point = 100000; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(ScalarType::Double), + out); + + // The expected result should be (10 - 100000) * 0.5 = -49995 + Tensor expected = tfo.full({3, 5}, -49995); + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, NonWholeNumbers) { + et_pal_init(); + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 100); + double scale = 0.45; + int64_t zero_point = 30; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 + Tensor expected = tfo.full({3, 5}, 31.5); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, TensorArgOverload) { + et_pal_init(); + TensorFactory tf_byte; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_byte.full({3, 5}, 100); + Tensor scale = tf_double.make({1}, {0.45}); + Tensor zero_point = tf_long.make({1}, {30}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 + Tensor expected = tfo.full({3, 5}, 31.5); + dequantize_per_tensor_tensor_args_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +template +void test_per_channel_dtype() { + TensorFactory tf; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf.full({3, 2}, 100); + Tensor scale = tf_double.make({2}, {0.5, 1}); + Tensor zero_point = tf_long.make({2}, {30, 60}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 2}); + // (100 - 30) * 0.5 + // (100 - 60) * 1 + Tensor expected = tfo.make({3, 2}, {35, 40, 35, 40, 35, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/1, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Test with a different axis + out = tfo.zeros({3, 2}); + scale = tf_double.make({3}, {0.5, 0.75, 1}); + zero_point = tf_long.make({3}, {30, 50, 60}); + // (100 - 30) * 0.5 + // (100 - 50) * 0.75 + // (100 - 60) * 1 + expected = tfo.make({3, 2}, {35, 35, 37.5, 37.5, 40, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/0, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Test with a different axis + out = tfo.zeros({3}); + input = tf.make({3}, {100, 100, 100}); + scale = tf_double.make({3}, {0.5, 0.75, 1}); + zero_point = tf_long.make({3}, {30, 50, 60}); + // (100 - 30) * 0.5 + // (100 - 50) * 0.75 + // (100 - 60) * 1 + expected = tfo.make({3}, {35, 37.5, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/0, + quant_min, + quant_max, + DTYPE, + optional(), + out); + EXPECT_TENSOR_EQ(out, expected); + + // Test with a different axis + input = tf.full({3, 19}, 100); + out = tfo.zeros({3, 19}); + scale = tf_double.make({3}, {0.5, 0.75, 1}); + zero_point = tf_long.make({3}, {30, 50, 60}); + // (100 - 30) * 0.5 + // (100 - 50) * 0.75 + // (100 - 60) * 1 + expected = tfo.make( + {3, 19}, + {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 37.5, 37.5, 37.5, 37.5, 37.5, + 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, + 37.5, 37.5, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/0, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, DequantizePerChannel) { + et_pal_init(); + test_per_channel_dtype(); + test_per_channel_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding2b_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding2b_test.cpp new file mode 100644 index 0000000..597492e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding2b_test.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_embedding_2bit_out; + +using torch::executor::testing::TensorFactory; + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbedding) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -2, 0}); + + // -2, 1, 0, 1, -> 0, 3, 2, 3 -> (reverse) 11 10 11 00 -> 236 + // 0, -1, -2, 0, -> 2, 1, 0, 2 -> (reverse) 10 00 01 10 -> 134 + // -2, -1, 0, 1, -> 0, 1, 2, 3 -> (reverse) 11 10 01 00 -> 228 + + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-1.5, 0.0, -0.5, 0.0, -3.0, -1.5, 0.0, 1.5, 2.0, 1.0, 0.0, 2.0}); + + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_2bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Groupwise quantization. groupsize = 2 + + weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.0, 2.5, 3.0}); + weight_zero_points = tf.make({3, 2}, {1, -2, 0, 1, -2, -1}); + + // -2, 1, 0, 1, -> 0, 3, 2, 3 -> (reverse) 11 10 11 00 -> 236 + // 0, -1, -2, 0, -> 2, 1, 0, 2 -> (reverse) 10 00 01 10 -> 134 + // -2, -1, 0, 1, -> 0, 1, 2, 3 -> (reverse) 11 10 01 00 -> 228 + + qweight = tfb.make({3, 1}, {236, 134, 228}); + + indices = tfl.make({3}, {0, 2, 1}); + + out = tf.zeros({3, 4}); + expected = tf.make( + {3, 4}, {-1.5, 0.0, 2.0, 3.0, 0.0, 2.5, 3.0, 6.0, 0.0, -1.5, -6.0, -2.0}); + + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingInt32Indices) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfi; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -2, 0}); + + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + + Tensor indices = tfi.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-1.5, 0.0, -0.5, 0.0, -3.0, -1.5, 0.0, 1.5, 2.0, 1.0, 0.0, 2.0}); + + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_2bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingDeath1) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({4}, {0.5, 1.0, 1.5, 3.3}); + Tensor weight_zero_points = tf.make({4}, {1, -2, 1, 0}); + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + Tensor out = tf.zeros({3, 4}); + + // qvals are incompatible shape with scales/zeros + ET_EXPECT_DEATH( + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingDeath2) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({2}, {0.5, 1.0}); + Tensor weight_zero_points = tf.make({2}, {1, -2}); + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + Tensor out = tf.zeros({3, 4}); + + // qvals are incompatible shape with scales/zeros + ET_EXPECT_DEATH( + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingDeath3) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({2, 3}, {1.0, 1.0, 1.0, 1.0, 1.0, 1.0}); + Tensor weight_zero_points = tf.make({2, 3}, {0, 0, 0, 0, 0, 0}); + Tensor qweight = tfb.make({2, 1}, {236, 134}); + Tensor indices = tfl.make({2}, {0, 2}); + Tensor out = tf.zeros({2, 8}); + + // scales/zeros imply 3 groups, which does not divide embed dimension from + // qvals (8) + ET_EXPECT_DEATH( + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding4b_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding4b_test.cpp new file mode 100644 index 0000000..4646f18 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding4b_test.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_embedding_4bit_out; + +using torch::executor::testing::TensorFactory; + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbedding) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -5, 0}); + + // -3, 1, 6, 7, + // 2, -5, -4, 0, + // -8, 3, -1, 6, + + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-2.0, 0.0, 2.5, 3.0, -12.0, 4.5, -1.5, 9.0, 7.0, 0.0, 1.0, 5.0}); + + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_4bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Groupwise quantization. groupsize = 2 + weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.0, 2.5, 3.0}); + weight_zero_points = tf.make({3, 2}, {1, -5, 0, 2, -3, -1}); + /* + fp_weight = [-2.0, 0.0, 11.0, 12.0, + 3.0, -7.5, -12.0, -4.0, + -12.5, 15.0, 0.0, 21.0] + */ + + out = tf.zeros({3, 4}); + expected = tf.make( + {3, 4}, + {-2.0, 0.0, 11.0, 12.0, -12.5, 15.0, 0.0, 21.0, 3.0, -7.5, -12.0, -4.0}); + + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbeddingInt32Indices) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfi; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -5, 0}); + + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + + Tensor indices = tfi.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-2.0, 0.0, 2.5, 3.0, -12.0, 4.5, -1.5, 9.0, 7.0, 0.0, 1.0, 5.0}); + + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_4bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbeddingDeath1) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({4}, {0.5, 1.0, 1.5, 3.3}); + Tensor weight_zero_points = tf.make({4}, {1, 5, 7, 5}); + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbeddingDeath2) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({2}, {0.5, 1.0}); + Tensor weight_zero_points = tf.make({2}, {1, 5}); + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding_test.cpp new file mode 100644 index 0000000..5d5ad45 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_embedding_test.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::dequantize_per_tensor_out; +using torch::executor::native::embedding_out; +using torch::executor::native::quantize_per_tensor_out; +using torch::executor::native::quantized_embedding_byte_out; + +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + TensorFactory tf_l; + + float scale = 0.5; + float zero_point = 1; + int64_t quant_min = 0; + int64_t quant_max = 255; + + // clang-format off + Tensor weight = tf.make({3, 2}, {3.5, 2.0, + 4, 1, + 5.5, 13.2}); + // clang-format on + // TODO make these different per dimension once per channel quant ops + // available + Tensor weight_scales = tf.full({3}, scale); + Tensor weight_zero_points = tf.full({3}, zero_point); + + Tensor indices = tf_l.make({2}, {0, 2}); + + Tensor out = tf.zeros({2, 2}); + + TensorFactory tfo; + Tensor qweight = tfo.zeros({3, 2}); + + // 3.5 / 0.5 + 1 = 8 + // 2 / 0.5 + 1 = 5 + // 4 / 0.5 + 1 = 9 + // 1 / 0.5 + 1 = 3 + // 5.5 / 0.5 + 1 = 12 + // 13.2 / 0.5 + 1 = 27 + quantize_per_tensor_out( + weight, scale, (float)zero_point, quant_min, quant_max, DTYPE, qweight); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + // (8 - 1) * 0.5 = 3.5 + // (5 - 1) * 0.5 = 2.0 + // (12 - 1) * 0.5 = 5.5 + // (27 - 1) * 0.5 = 13 + // clang-format off + Tensor expected = tf.make({2, 2}, {3.5, 2, + 5.5, 13}); + // clang-format on + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbeddingTest, AllDtypesSupported) { + test_dtype(); +} + +// Q -> DQ -> FP Embedding should be == to Q -> QEmbedding Bytes +TEST(OpQuantizedEmbeddingTest, ConsitencyWithReferencePattern) { + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + float scale = 0.5; + float zero_point = 1; + int64_t quant_min = 0; + int64_t quant_max = 255; + + // Do Q -> QEmbedding Bytes + Tensor weight = tf.make({3, 1}, {3.5, 5.5, 1.0}); + // TODO make these different per dimension once per channel quant ops + // available + Tensor weight_scales = tf.full({3}, scale); + Tensor weight_zero_points = tf.full({3}, zero_point); + + Tensor indices = tf_l.make({2}, {0, 2}); + + Tensor out = tf.zeros({2, 1}); + Tensor fp_out = tf.zeros({2, 1}); + + TensorFactory tfo; + Tensor qweight = tfo.zeros({3, 1}); + KernelRuntimeContext context{}; + // 3.5 / 0.5 + 1 = 8 + // 5.5 / 0.5 + 1 = 12 + // 1 / 0.5 + 1 = 3 + quantize_per_tensor_out( + weight, + scale, + (int64_t)zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qweight); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + // Do Q DQ embedding + dequantize_per_tensor_out( + qweight, + scale, + (int64_t)zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(), + weight); + + embedding_out( + context, + weight, + indices, + /*padding_idx=*/0, + /*scale_grad_by_freq=*/false, + /*sparse=*/false, + fp_out); + + // can lossessly dq here so retrive the full information + // (8 - 1) * 0.5 = 3.5 + // (3 - 1) * 0.5 = 1 + Tensor expected = tf.make({2, 1}, {3.5, 1}); + EXPECT_TENSOR_EQ(out, fp_out); + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbedding) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, 5, 7}); + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {3.5, 4.5, 5.5, 6.5, 1.5, 3.0, 4.5, 7.5, 5.0, 7.0, 7.0, 9.0}); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Groupwise quantization. groupsize = 2 + weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.0, 2.5, 3.0}); + weight_zero_points = tf.make({3, 2}, {1, 5, 7, 9, 11, 13}); + /* + fp_weight = [3.5, 4.5, 7, 9, + 4.5, 7.5, 6, 10, + -7.5, -5.0, -9.0, -3.0] + */ + + out = tf.zeros({3, 4}); + expected = tf.make( + {3, 4}, {3.5, 4.5, 7, 9, -7.5, -5.0, -9.0, -3.0, 4.5, 7.5, 6, 10}); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath1) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({4}, {0.5, 1.0, 1.5, 3.3}); + Tensor weight_zero_points = tf.make({4}, {1, 5, 7, 5}); + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath2) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({2}, {0.5, 1.0}); + Tensor weight_zero_points = tf.make({2}, {1, 5}); + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath3) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.5, 3.5, 3.5}); + Tensor weight_zero_points = tf.make({3, 2}, {1, 5, 7, 9, 11, 13}); + TensorFactory tfo; + Tensor qweight = tfo.make({3, 3}, {8, 10, 12, 14, 10, 12, 12, 14, 8}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 3}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath4) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.5, 3.5, 3.5}); + Tensor weight_zero_points = tf.make({3}, {1, 5, 7}); + TensorFactory tfo; + Tensor qweight = tfo.make({3, 3}, {8, 10, 12, 14, 10, 12, 12, 14, 8}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 3}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath5) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.5, 3.5, 3.5}); + Tensor weight_zero_points = tf.make({3, 3}, {1, 5, 7, 1, 5, 7, 1, 5, 7}); + TensorFactory tfo; + Tensor qweight = tfo.make({3, 3}, {8, 10, 12, 14, 10, 12, 12, 14, 8}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 3}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestOutOfBoundsIndex) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + // Create a weight tensor with 3 rows + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + // Create weight_scales with the same number of rows + Tensor weight_scales = tf.make({3, 1}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3, 1}, {1, 5, 7}); + + // Create indices with an out-of-bounds index (3, which is >= weight.size(0)) + Tensor indices = tf_l.make({2}, {1, 3}); + + Tensor out = tf.zeros({2, 4}); + + // Expect death when accessing an out-of-bounds index + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_linear_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_linear_test.cpp new file mode 100644 index 0000000..e659b41 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_linear_test.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_mixed_linear_out; +using torch::executor::testing::TensorFactory; + +class OpQuantizedMixedDtypeLinearTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + torch::executor::runtime_init(); + } +}; + +template +void test_dtype() { + TensorFactory tf; + TensorFactory tf_char; + TensorFactory tf_out; + + Tensor input = tf.make( + /*sizes=*/{1, 3}, + /*data=*/{1.0, 1.5, 2.0}); + Tensor weight = tf_char.make( + /*sizes=*/{2, 3}, + /*data=*/{5, 3, 1, 4, 2, 1}); + Tensor weight_scales = tf.make( + /*sizes=*/{2}, + /*data=*/{0.2, 0.4}); + const optional opt_weight_zp{}; + const optional opt_dtype_out{}; + + Tensor out = tf_out.zeros({1, 2}); + + Tensor expected = tf_out.make( + /*sizes=*/{1, 2}, + /*data=*/{2.3, 3.6}); + + KernelRuntimeContext ctx{}; + + quantized_mixed_linear_out( + ctx, input, weight, weight_scales, opt_weight_zp, opt_dtype_out, out); + + EXPECT_TENSOR_CLOSE(out, expected); +} + +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputFloatOutput) { + test_dtype(); +} + +#if 0 +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputHalfOutput) { + test_dtype(); +} + +// need to relax tolerance +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputFloatOutput) { + test_dtype(); +} + +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputHalfOutput) { + test_dtype(); +} +#endif + +template +void test_dtype_partials() { + TensorFactory tf; + TensorFactory tf_char; + TensorFactory tf_out; + + Tensor input = tf.make( + /*sizes=*/{1, 3}, + /*data=*/{1.0, 1.5, 2.0}); + Tensor weight = tf_char.make( + /*sizes=*/{2, 3}, + /*data=*/{5, 3, 1, 4, 2, 1}); + Tensor weight_scales = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{0.2, 1, 0.4, 0.5}); + const optional opt_weight_zp{}; + const optional opt_dtype_out{}; + + Tensor out = tf_out.zeros({1, 2}); + + Tensor expected = tf_out.make( + /*sizes=*/{1, 2}, + /*data=*/ + {(1.0 * 5 + 1.5 * 3) * 0.2 + 2.0 * 1 * 1, + (1.0 * 4 + 1.5 * 2) * 0.4 + 2.0 * 1 * 0.5}); + + KernelRuntimeContext ctx{}; + + quantized_mixed_linear_out( + ctx, input, weight, weight_scales, opt_weight_zp, opt_dtype_out, out); + + EXPECT_TENSOR_CLOSE(out, expected); +} + +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputFloatOutput_Partials) { + test_dtype_partials(); +} + +#if 0 +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputHalfOutput_Partials) { + test_dtype_partials(); +} + +// need to relax tolerance +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputFloatOutput_Partials) { + test_dtype_partials(); +} + +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputHalfOutput_Partials) { + test_dtype_partials(); +} +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_mm_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_mm_test.cpp new file mode 100644 index 0000000..8051f29 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_mixed_mm_test.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_mixed_mm_out; +using torch::executor::testing::TensorFactory; + +class OpQuantizedMixedMMTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + torch::executor::runtime_init(); + } +}; + +template +void test_dtype() { + TensorFactory tf; + TensorFactory tf_char; + + Tensor input = tf.make( + /*sizes=*/{1, 3}, + /*data=*/{1.0, 1.5, 2.0}); + Tensor weight = tf_char.make( + /*sizes=*/{3, 2}, + /*data=*/{5, 4, 3, 2, 1, 1}); + Tensor weight_scales = tf.make( + /*sizes=*/{3}, + /*data=*/{0.2, 0.4, 0.5}); + const optional opt_weight_zp{}; + + Tensor out = tf.zeros({1, 2}); + + Tensor expected = tf.make( + /*sizes=*/{1, 2}, + /*data=*/{3.8, 3.0}); + + KernelRuntimeContext ctx{}; + + quantized_mixed_mm_out(ctx, input, weight, weight_scales, opt_weight_zp, out); + + EXPECT_TENSOR_CLOSE(out, expected); +} + +TEST_F(OpQuantizedMixedMMTest, FloatInput) { + test_dtype(); +} + +TEST_F(OpQuantizedMixedMMTest, HalfInput) { + test_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_quantize_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_quantize_test.cpp new file mode 100644 index 0000000..b450ec0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/op_quantize_test.cpp @@ -0,0 +1,983 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using torch::executor::native::quantize_per_channel_out; +using torch::executor::native::quantize_per_tensor_out; +using torch::executor::native::quantize_per_tensor_tensor_args_out; +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 4); + double scale = 0.5; + + int64_t zero_point = 108; + int64_t quant_min = 0; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 127 + Tensor expected = tfo.full({3, 5}, 116); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, DTYPE, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +template +void test_input_dtype() { + TensorFactory tf_input; + + Tensor input = tf_input.full({3, 5}, 4); + double scale = 0.5; + int64_t zero_point = 108; + int64_t quant_min = 0; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 108 = 116 + Tensor expected = tfo.full({3, 5}, 116); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, AllInputDtypesSupported) { + test_input_dtype(); + test_input_dtype(); + test_input_dtype(); +} + +TEST(OpQuantizeOutTest, AllDtypesSupported) { + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); +} + +TEST(OpQuantizeOutTest, DoubleInputTest) { + TensorFactory tf_double; + + // Test with a more complex value that might have precision differences + Tensor input = tf_double.full({2, 3}, 3.14159265359); + double scale = 0.01; + int64_t zero_point = -100; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // 3.14159265359 / 0.01 - 100 = 214.159265359 + Tensor expected = tfo.full({2, 3}, 214); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, HalfInputTest) { + TensorFactory tf_half; + + Tensor input = tf_half.full({2, 3}, 2.5); + double scale = 0.5; + int64_t zero_point = 10; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // 2.5 / 0.5 + 10 = 15 + Tensor expected = tfo.full({2, 3}, 15); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, TensorArgOverload) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 5}, 4); + Tensor scale = tf_double.make({1}, {0.5}); + Tensor zero_point = tf_long.make({1}, {127}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 127 + Tensor expected = tfo.full({3, 5}, 135); + auto context = torch::executor::KernelRuntimeContext(); + quantize_per_tensor_tensor_args_out( + context, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, TestOutOfBounds) { + // Test where 1.0 / epsilon is larger than 8bit integer. + + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.ones({1, 3, 256, 256}); + + Tensor scale = tf_double.make({1}, {0.0011316323652863503}); + Tensor zero_point = tf_long.make({1}, {0}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({1, 3, 256, 256}); + + Tensor expected = tfo.full({1, 3, 256, 256}, 127); + + auto context = torch::executor::KernelRuntimeContext(); + quantize_per_tensor_tensor_args_out( + context, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannel) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 2}, 4); + Tensor scale = tf_double.make({2}, {0.5, 1}); + Tensor zero_point = tf_long.make({2}, {127, 63}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 2}); + // 4 / 0.5 + 127 + // 4 / 1 + 63 + Tensor expected = tfo.make({3, 2}, {135, 67, 135, 67, 135, 67}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelAxis0) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 2}, 4); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 2.0}); + Tensor zero_point = tf_long.make({3}, {100, 50, 25}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 2}); + // Channel 0: 4 / 0.5 + 100 = 108 + // Channel 1: 4 / 1.0 + 50 = 54 + // Channel 2: 4 / 2.0 + 25 = 27 + Tensor expected = tfo.make({3, 2}, {108, 108, 54, 54, 27, 27}); + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannel3D) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test 3D tensor with axis=1 (middle dimension) + Tensor input = tf_float.full({2, 3, 4}, 6); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 1.5}); + Tensor zero_point = tf_long.make({3}, {10, 20, 30}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3, 4}); + // Channel 0: 6 / 0.5 + 10 = 22 + // Channel 1: 6 / 1.0 + 20 = 26 + // Channel 2: 6 / 1.5 + 30 = 34 + Tensor expected = tfo.make( + {2, 3, 4}, + { + 22, 22, 22, 22, // First batch, channel 0 + 26, 26, 26, 26, // First batch, channel 1 + 34, 34, 34, 34, // First batch, channel 2 + 22, 22, 22, 22, // Second batch, channel 0 + 26, 26, 26, 26, // Second batch, channel 1 + 34, 34, 34, 34 // Second batch, channel 2 + }); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannel4D) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test 4D tensor with axis=2 (typical conv weight layout: N,C,H,W) + Tensor input = tf_float.full({2, 2, 3, 2}, 8); + Tensor scale = tf_double.make({3}, {0.25, 0.5, 1.0}); + Tensor zero_point = tf_long.make({3}, {0, 10, 20}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 2, 3, 2}); + // Channel 0: 8 / 0.25 + 0 = 32 + // Channel 1: 8 / 0.5 + 10 = 26 + // Channel 2: 8 / 1.0 + 20 = 28 + std::vector expected_data; + for (int n = 0; n < 2; n++) { + for (int c = 0; c < 2; c++) { + for (int h = 0; h < 3; h++) { + for (int w = 0; w < 2; w++) { + int8_t val = (h == 0) ? 32 : (h == 1) ? 26 : 28; + expected_data.push_back(val); + } + } + } + } + Tensor expected = tfo.make({2, 2, 3, 2}, expected_data); + quantize_per_channel_out( + input, scale, zero_point, 2, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelNegativeAxis) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({2, 3}, 5); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 2.0}); + Tensor zero_point = tf_long.make({3}, {0, 10, 20}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // Using axis=-1 should be equivalent to axis=1 for 2D tensor + // Channel 0: 5 / 0.5 + 0 = 10 + // Channel 1: 5 / 1.0 + 10 = 15 + // Channel 2: 5 / 2.0 + 20 = 22 (rounded from 22.5) + Tensor expected = tfo.make({2, 3}, {10, 15, 22, 10, 15, 22}); + quantize_per_channel_out( + input, + scale, + zero_point, + -1, + quant_min, + quant_max, + ScalarType::Byte, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelSingleChannel) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 1, 4}, 7); + Tensor scale = tf_double.make({1}, {0.5}); + Tensor zero_point = tf_long.make({1}, {128}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 1, 4}); + // Single channel: 7 / 0.5 + 128 = 142 + Tensor expected = tfo.full({3, 1, 4}, 142); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelDifferentInputTypes) { + TensorFactory tf_double_input; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_double_input.full({2, 2}, 3.14159); + Tensor scale = tf_double.make({2}, {0.01, 0.02}); + Tensor zero_point = tf_long.make({2}, {0, 100}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 2}); + // Channel 0: 3.14159 / 0.01 + 0 = 314 -> clamped to 127 + // Channel 1: 3.14159 / 0.02 + 100 = 257 -> clamped to 127 + Tensor expected = tfo.make({2, 2}, {127, 127, 127, 127}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelDifferentOutputTypes) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({2, 2}, 10); + Tensor scale = tf_double.make({2}, {1.0, 2.0}); + Tensor zero_point = tf_long.make({2}, {1000, 2000}); + int64_t quant_min = -32768; + int64_t quant_max = 32767; + + // Test with 16-bit output + TensorFactory tfo; + Tensor out = tfo.zeros({2, 2}); + // Channel 0: 10 / 1.0 + 1000 = 1010 + // Channel 1: 10 / 2.0 + 2000 = 2005 + Tensor expected = tfo.make({2, 2}, {1010, 2005, 1010, 2005}); + quantize_per_channel_out( + input, + scale, + zero_point, + 1, + quant_min, + quant_max, + ScalarType::Short, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelMixedValues) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test with different input values per position + Tensor input = tf_float.make({2, 3}, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 1.5}); + Tensor zero_point = tf_long.make({3}, {10, 20, 30}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // Row 0: [1.0/0.5+10, 2.0/1.0+20, 3.0/1.5+30] = [12, 22, 32] + // Row 1: [4.0/0.5+10, 5.0/1.0+20, 6.0/1.5+30] = [18, 25, 34] + Tensor expected = tfo.make({2, 3}, {12, 22, 32, 18, 25, 34}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelClampingBehavior) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test values that will exceed quant_min/quant_max bounds + Tensor input = tf_float.make({1, 3}, {-100.0, 0.0, 100.0}); + Tensor scale = tf_double.make({3}, {1.0, 1.0, 1.0}); + Tensor zero_point = tf_long.make({3}, {0, 0, 0}); + int64_t quant_min = -10; + int64_t quant_max = 10; + + TensorFactory tfo; + Tensor out = tfo.zeros({1, 3}); + // Values: [-100, 0, 100] should be clamped to [-10, 0, 10] + Tensor expected = tfo.make({1, 3}, {-10, 0, 10}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargePerChannelClampingSIMDPath) { + // Test quant_min/quant_max clamping with large tensor to exercise SIMD path + // Shape: [3, 80] with axis=0 (3 channels, 80 elements each) + // 80 elements = 10 SIMD iterations (8 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 3; + const int block_size = 80; + std::vector input_data(num_channels * block_size); + + // Create input data with values that exceed quant_min/quant_max + for (int ch = 0; ch < num_channels; ch++) { + for (int i = 0; i < block_size; i++) { + // Generate values from -150 to 150 to test clamping + input_data[ch * block_size + i] = + static_cast((i % 40) - 20) * 5.0f * (ch + 1); + } + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + // Use uniform scale and zero_point for all channels + Tensor scale = tf_double.make({num_channels}, {1.0, 1.0, 1.0}); + Tensor zero_point = tf_long.make({num_channels}, {0, 0, 0}); + + // Set narrow quant_min/quant_max to force clamping + int64_t quant_min = -20; + int64_t quant_max = 20; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values with clamping + std::vector expected_data(num_channels * block_size); + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + // Use double precision to avoid overflow + double val = static_cast(input_data[idx]) / ch_scale; + // Clamp before converting to int to avoid overflow + val = std::max(-1000.0, std::min(1000.0, val)); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + // Apply quant_min/quant_max clamping + qval = std::max( + static_cast(quant_min), + std::min(static_cast(quant_max), qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +// Large tensor tests to ensure ARM NEON SIMD path is exercised + +TEST(OpQuantizeOutTest, LargeTensorUInt8SIMDPath) { + // Test with 64 elements to fully exercise SIMD path (8 elements per + // iteration) + TensorFactory tf_float; + + // Create input with known values for verification + std::vector input_data(64); + for (size_t i = 0; i < 64; i++) { + input_data[i] = static_cast(i) * 0.5f; // 0.0, 0.5, 1.0, 1.5, ... + } + Tensor input = tf_float.make({64}, input_data); + + double scale = 0.1; + int64_t zero_point = 10; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({64}); + + // Compute expected values: round(value / scale) + zero_point + std::vector expected_data(64); + for (size_t i = 0; i < 64; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({64}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargeTensorInt8SIMDPath) { + // Test with 72 elements (9 SIMD iterations of 8) to test both vectorized and + // scalar paths + TensorFactory tf_float; + + std::vector input_data(72); + for (size_t i = 0; i < 72; i++) { + // Mix of positive and negative values + input_data[i] = static_cast(static_cast(i) - 36) * 0.25f; + } + Tensor input = tf_float.make({72}, input_data); + + double scale = 0.2; + int64_t zero_point = 0; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({72}); + + // Compute expected values + std::vector expected_data(72); + for (size_t i = 0; i < 72; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(127, std::max(-128, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({72}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargeTensorWithRemainderUInt8) { + // Test with 100 elements (12 SIMD iterations + 4 remainder) to test remainder + // handling + TensorFactory tf_float; + + std::vector input_data(100); + for (size_t i = 0; i < 100; i++) { + input_data[i] = static_cast(i % 50) * 0.3f; + } + Tensor input = tf_float.make({100}, input_data); + + double scale = 0.15; + int64_t zero_point = 128; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({100}); + + std::vector expected_data(100); + for (size_t i = 0; i < 100; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({100}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargeTensorWithRemainderInt8) { + // Test with 99 elements (12 SIMD iterations + 3 remainder) + TensorFactory tf_float; + + std::vector input_data(99); + for (size_t i = 0; i < 99; i++) { + input_data[i] = std::sin(static_cast(i) * 0.1f) * 10.0f; + } + Tensor input = tf_float.make({99}, input_data); + + double scale = 0.1; + int64_t zero_point = 5; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({99}); + + std::vector expected_data(99); + for (size_t i = 0; i < 99; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(127, std::max(-128, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({99}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, VeryLargeTensor2DUInt8) { + // Test with realistic 2D tensor size that would be used in neural networks + // 256x256 = 65536 elements (8192 SIMD iterations) + TensorFactory tf_float; + + std::vector input_data(256 * 256); + for (size_t i = 0; i < 256 * 256; i++) { + // Generate diverse values in a safe range + input_data[i] = + static_cast((static_cast(i % 256) - 128)) * 0.05f; + } + Tensor input = tf_float.make({256, 256}, input_data); + + double scale = 0.05; + int64_t zero_point = 128; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({256, 256}); + + // Compute expected values with proper overflow handling + std::vector expected_data(256 * 256); + for (size_t i = 0; i < 256 * 256; i++) { + // Use double precision to avoid overflow + double val = static_cast(input_data[i]) / scale; + // Clamp before converting to int to avoid overflow + val = std::max(-1000.0, std::min(1000.0, val)); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(zero_point); + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({256, 256}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, VeryLargeTensor3DInt8) { + // Test with 3D tensor (batch_size=2, height=64, width=128) = 16384 elements + TensorFactory tf_float; + + const size_t total_elements = 2 * 64 * 128; + std::vector input_data(total_elements); + for (size_t i = 0; i < total_elements; i++) { + input_data[i] = std::cos(static_cast(i) * 0.01f) * 8.0f; + } + Tensor input = tf_float.make({2, 64, 128}, input_data); + + double scale = 0.0625; // 1/16 + int64_t zero_point = -10; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 64, 128}); + + std::vector expected_data(total_elements); + for (size_t i = 0; i < total_elements; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(127, std::max(-128, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({2, 64, 128}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, EdgeCaseSizesSIMD) { + // Test specific sizes around SIMD boundaries + TensorFactory tf_float; + TensorFactory tfo; + + double scale = 0.1; + int64_t zero_point = 100; + int64_t quant_min = 0; + int64_t quant_max = 255; + + // Test sizes: 7 (just before SIMD), 8 (exactly 1 SIMD), 9 (1 SIMD + 1), 15, + // 16, 17 + std::vector test_sizes = { + 7, 8, 9, 15, 16, 17, 23, 24, 25, 31, 32, 33}; + + for (size_t size : test_sizes) { + std::vector input_data(size); + std::vector expected_data(size); + + for (size_t i = 0; i < size; i++) { + input_data[i] = static_cast(i) * 0.3f; + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + + Tensor input = tf_float.make({static_cast(size)}, input_data); + Tensor out = tfo.zeros({static_cast(size)}); + Tensor expected = tfo.make({static_cast(size)}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); + } +} + +// Large tensor tests for per-channel quantization to ensure SIMD path is +// exercised + +TEST(OpQuantizeOutTest, LargePerChannelUInt8SIMDPath) { + // Test per-channel quantization with large blocks (64 elements per channel) + // Shape: [4, 64] with axis=1 (4 channels, 64 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 4; + const int block_size = 64; + std::vector input_data(num_channels * block_size); + + // Create varying input data for each channel + for (int ch = 0; ch < num_channels; ch++) { + for (int i = 0; i < block_size; i++) { + input_data[ch * block_size + i] = static_cast((ch + 1) * i) * 0.1f; + } + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + // Different scale and zero_point for each channel + Tensor scale = tf_double.make({num_channels}, {0.1, 0.2, 0.15, 0.25}); + Tensor zero_point = tf_long.make({num_channels}, {10, 20, 15, 25}); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values + std::vector expected_data(num_channels * block_size); + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + float val = input_data[idx] / static_cast(ch_scale); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + qval = std::min(255, std::max(0, qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargePerChannelInt8SIMDPath) { + // Test per-channel quantization with int8 and large blocks + // Shape: [3, 100] with axis=1 (3 channels, 100 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 3; + const int block_size = 100; // 12 SIMD iterations + 4 remainder + std::vector input_data(num_channels * block_size); + + // Create varying input data with negative values + for (int ch = 0; ch < num_channels; ch++) { + for (int i = 0; i < block_size; i++) { + input_data[ch * block_size + i] = + static_cast(i - 50) * 0.2f * (ch + 1); + } + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + Tensor scale = tf_double.make({num_channels}, {0.1, 0.15, 0.2}); + Tensor zero_point = tf_long.make({num_channels}, {0, -5, 5}); + + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values + std::vector expected_data(num_channels * block_size); + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + float val = input_data[idx] / static_cast(ch_scale); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + qval = std::min(127, std::max(-128, qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, VeryLargePerChannel2DUInt8) { + // Test realistic neural network weight tensor + // Shape: [128, 256] with axis=0 (128 channels, 256 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 128; + const int block_size = 256; + const int total_elements = num_channels * block_size; + + std::vector input_data(total_elements); + for (int i = 0; i < total_elements; i++) { + input_data[i] = std::sin(static_cast(i) * 0.01f) * 5.0f; + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + // Create varying scales and zero_points for each channel + std::vector scales(num_channels); + std::vector zero_points(num_channels); + for (int ch = 0; ch < num_channels; ch++) { + scales[ch] = 0.02 + (ch % 10) * 0.001; // Varying scales + zero_points[ch] = 128 + (ch % 5); // Varying zero_points + } + Tensor scale = tf_double.make({num_channels}, scales); + Tensor zero_point = tf_long.make({num_channels}, zero_points); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values + std::vector expected_data(total_elements); + for (int ch = 0; ch < num_channels; ch++) { + float inv_scale = 1.0f / static_cast(scales[ch]); + int64_t ch_zero_point = zero_points[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + float val = input_data[idx] * inv_scale; + // Clamp before converting to avoid overflow + val = std::max(-1000.0f, std::min(1000.0f, val)); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + + qval = std::min(255, std::max(0, qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, PerChannelAxis1LargeBlocks) { + // Test per-channel quantization with axis=1 and large contiguous blocks + // Shape: [2, 3, 64] with axis=1 (2 batches, 3 channels, 64 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int batch_size = 2; + const int num_channels = 3; + const int block_size = 64; + const int total_elements = batch_size * num_channels * block_size; + + std::vector input_data(total_elements); + for (int i = 0; i < total_elements; i++) { + input_data[i] = static_cast(i % 100) * 0.1f; + } + Tensor input = + tf_float.make({batch_size, num_channels, block_size}, input_data); + + Tensor scale = tf_double.make({num_channels}, {0.05, 0.1, 0.15}); + Tensor zero_point = tf_long.make({num_channels}, {100, 110, 120}); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({batch_size, num_channels, block_size}); + + // Compute expected values + std::vector expected_data(total_elements); + for (int b = 0; b < batch_size; b++) { + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = (b * num_channels + ch) * block_size + i; + float val = input_data[idx] / static_cast(ch_scale); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + qval = std::min(255, std::max(0, qval)); + expected_data[idx] = static_cast(qval); + } + } + } + Tensor expected = + tfo.make({batch_size, num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/quantized_ops_aot_register.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/quantized_ops_aot_register.cpp new file mode 100644 index 0000000..72da666 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/quantized_ops_aot_register.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +namespace torch { +namespace executor { + +namespace native { + +Tensor& quantize_per_token_out( + RuntimeContext& context, + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out); + +Tensor& quantize_per_token_out_no_context( + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + executorch::aten::RuntimeContext context{}; + ::torch::executor::runtime_init(); + quantize_per_token_out( + context, input, scale, zero_point, quant_min, quant_max, dtype, out); + return out; +} + +at::Tensor quantize_per_token_aten( + const at::Tensor& input, + const at::Tensor& scale, + const at::Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + c10::ScalarType dtype) { + auto sizes = input.sizes().vec(); + auto output = at::zeros(sizes, dtype); + TORCH_CHECK(dtype == c10::ScalarType::Char, "dtype must be char"); + WRAP_TO_ATEN(quantize_per_token_out_no_context, 6) + (input, scale, zero_point, quant_min, quant_max, ScalarType::Char, output); + return output; +} + +Tensor& dequantize_per_token_out( + RuntimeContext& context, + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + ScalarType out_dtype, + Tensor& out); + +Tensor& dequantize_per_token_out_no_context( + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + ScalarType out_dtype, + Tensor& out) { + executorch::aten::RuntimeContext context{}; + ::torch::executor::runtime_init(); + dequantize_per_token_out( + context, + input, + scale, + zero_point, + quant_min, + quant_max, + dtype, + out_dtype, + out); + return out; +} + +at::Tensor dequantize_per_token_aten( + const at::Tensor& input, + const at::Tensor& scale, + const at::Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + c10::ScalarType dtype, + c10::ScalarType out_dtype) { + auto sizes = input.sizes().vec(); + auto output = at::zeros(sizes, out_dtype); + TORCH_CHECK(dtype == c10::ScalarType::Char, "dtype must be char"); + TORCH_CHECK(out_dtype == c10::ScalarType::Float, "out_dtype must be float"); + WRAP_TO_ATEN(dequantize_per_token_out_no_context, 7) + (input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + ScalarType::Float, + output); + return output; +} + +} // namespace native +} // namespace executor +} // namespace torch + +TORCH_LIBRARY(et_quant_test, m) { + m.def( + "quantize_per_token(Tensor input, Tensor scale, Tensor zero_points, int quant_min, int quant_max, ScalarType dtype) -> Tensor"); + m.def( + "dequantize_per_token(Tensor input, Tensor scale, Tensor zero_points, int quant_min, int quant_max, ScalarType dtype, ScalarType out_dtype) -> Tensor"); +} + +TORCH_LIBRARY_IMPL(et_quant_test, CompositeExplicitAutograd, m) { + m.impl( + "quantize_per_token", torch::executor::native::quantize_per_token_aten); + m.impl( + "dequantize_per_token", + torch::executor::native::dequantize_per_token_aten); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/supported_features_def.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/supported_features_def.yaml new file mode 100644 index 0000000..c97183a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/supported_features_def.yaml @@ -0,0 +1 @@ +# no override diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/targets.bzl new file mode 100644 index 0000000..a107efc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/targets.bzl @@ -0,0 +1,41 @@ +load("@fbsource//xplat/executorch/kernels/test:util.bzl", "define_supported_features_lib", "op_test") + +def define_common_targets(): + define_supported_features_lib() + + op_test("op_quantize_test", kernel_name = "quantized") + op_test("op_dequantize_test", kernel_name = "quantized") + op_test("op_choose_qparams_test", kernel_name = "quantized") + op_test("op_add_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_dequantize", + "//executorch/kernels/quantized/cpu:op_quantize", + "//executorch/kernels/quantized/cpu:op_add", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/kernels/portable/cpu:op_add", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) + op_test("op_embedding_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_dequantize", + "//executorch/kernels/quantized/cpu:op_quantize", + "//executorch/kernels/quantized/cpu:op_add", + "//executorch/kernels/quantized/cpu:op_embedding", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/kernels/portable/cpu:op_embedding", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) + op_test("op_embedding2b_test", kernel_name = "quantized") + op_test("op_embedding4b_test", kernel_name = "quantized") + op_test("op_mixed_mm_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_mixed_mm", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) + op_test("op_mixed_linear_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_mixed_linear", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_out_variants.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_out_variants.py new file mode 100644 index 0000000..ebc94b4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_out_variants.py @@ -0,0 +1,100 @@ +#!/usr/bin/env fbpython +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import executorch.kernels.quantized # noqa[F401] 'executorch.kernels.quantized' imported but unused + +import torch +import torch.ao.quantization.fx._decomposed # noqa[F401] 'torch.ao.quantization.fx._decomposed' imported but unused +from executorch.exir.dialects._ops import ops +from executorch.exir.passes._quant_patterns_and_replacements import ( # noqa + quantized_decomposed_lib, # noqa +) + + +class TestOutVariants(unittest.TestCase): + def setUp(self) -> None: + super().setUp() + + def test_add_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.add.out) + fn = ops.edge.quantized_decomposed.add.default + out_variant = fn.to_out_variant() + self.assertEqual(out_variant.name(), "quantized_decomposed::add.out") + + def test_choose_qparams_tensor_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.choose_qparams.Tensor_out) + choose_qparams = ops.edge.quantized_decomposed.choose_qparams.tensor + out_variant = choose_qparams.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::choose_qparams.Tensor_out" + ) + + def test_dequantize_per_tensor_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.dequantize_per_tensor.out) + fn = ops.edge.quantized_decomposed.dequantize_per_tensor.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::dequantize_per_tensor.out" + ) + + def test_dequantize_per_tensor_tensor_to_out_variant(self) -> None: + self.assertIsNotNone( + ops.edge.quantized_decomposed.dequantize_per_tensor.Tensor_out + ) + fn = ops.edge.quantized_decomposed.dequantize_per_tensor.tensor + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::dequantize_per_tensor.Tensor_out" + ) + + def test_dequantize_per_channel_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.dequantize_per_channel.out) + fn = ops.edge.quantized_decomposed.dequantize_per_channel.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::dequantize_per_channel.out" + ) + + def test_mixed_linear_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.mixed_linear.out) + fn = ops.edge.quantized_decomposed.mixed_linear.default + out_variant = fn.to_out_variant() + self.assertEqual(out_variant.name(), "quantized_decomposed::mixed_linear.out") + + def test_mixed_mm_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.mixed_mm.out) + fn = ops.edge.quantized_decomposed.mixed_mm.default + out_variant = fn.to_out_variant() + self.assertEqual(out_variant.name(), "quantized_decomposed::mixed_mm.out") + + def test_quantize_per_tensor_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.quantize_per_tensor.out) + fn = ops.edge.quantized_decomposed.quantize_per_tensor.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::quantize_per_tensor.out" + ) + + def test_quantize_per_tensor_tensor_to_out_variant(self) -> None: + self.assertIsNotNone( + ops.edge.quantized_decomposed.quantize_per_tensor.Tensor_out + ) + fn = ops.edge.quantized_decomposed.quantize_per_tensor.tensor + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::quantize_per_tensor.Tensor_out" + ) + + def test_quantize_per_channel_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.quantize_per_channel.out) + fn = ops.edge.quantized_decomposed.quantize_per_channel.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::quantize_per_channel.out" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_quant_dequant_per_token.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_quant_dequant_per_token.py new file mode 100644 index 0000000..1286bae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/kernels/quantized/test/test_quant_dequant_per_token.py @@ -0,0 +1,149 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import unittest + +import torch +from torch.ao.quantization.fx._decomposed import quantized_decomposed_lib # noqa: F401 + + +class QuantizePerTokenTest(unittest.TestCase): + + def test_quantize_per_token(self): + input_tensor = torch.tensor( + [[-0.5, 0.3, 1.2], [0.1, -0.8, 2.1], [-5, 1, 2]], dtype=torch.float32 + ) + scale = torch.tensor([0.5, 0.8, 1.0], dtype=torch.float64) + scale = scale.unsqueeze(-1) + zero_point = torch.tensor([-1, -2, 0]) + zero_point = zero_point.unsqueeze(-1) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_quantize_per_token_large_tensor(self): + input_tensor = torch.rand((8, 32)) + scale = torch.rand((8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_quantize_per_token_high_rank(self): + input_tensor = torch.rand((1, 3, 8, 32)) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_quantize_per_token_dynamic(self): + input_tensor = torch.rand((1, 1, 8, 1)) + scale = torch.rand((1, 1, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 1, 8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + input_tensor = torch.rand((1, 3, 8, 1)) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_dequantize_per_token(self): + input_tensor = torch.randint(-50, 120, (3, 3), dtype=torch.int8) + scale = torch.tensor([0.5, 0.8, 1.0], dtype=torch.float64) + scale = scale.unsqueeze(-1) + zero_point = torch.tensor([-1, -2, 0]) + zero_point = zero_point.unsqueeze(-1) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + def test_dequantize_per_token_large_tensor(self): + input_tensor = torch.randint(-50, 120, (8, 32), dtype=torch.int8) + scale = torch.rand((8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + def test_dequantize_per_token_high_rank(self): + input_tensor = torch.randint(-50, 120, (1, 3, 8, 32), dtype=torch.int8) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + def test_dequantize_per_token_dynamic(self): + input_tensor = torch.randint(-50, 120, (1, 1, 8, 32), dtype=torch.int8) + scale = torch.rand((1, 1, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 1, 8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + input_tensor = torch.randint(-50, 120, (1, 3, 8, 32), dtype=torch.int8) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_execution_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/backend_execution_context.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_execution_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/backend_execution_context.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_init_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/backend_init_context.h similarity index 59% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_init_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/backend_init_context.h index 0f649b3..777744e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_init_context.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/backend_init_context.h @@ -7,15 +7,9 @@ */ #pragma once -#include -#include #include #include #include -#include -#include - -#include #ifdef __GNUC__ // Disable -Wdeprecated-declarations, as some builds use 'Werror'. @@ -35,8 +29,7 @@ class BackendInitContext final { MemoryAllocator* runtime_allocator, EventTracer* event_tracer = nullptr, const char* method_name = nullptr, - const NamedDataMap* named_data_map = nullptr, - Span runtime_specs = {}) + const NamedDataMap* named_data_map = nullptr) : runtime_allocator_(runtime_allocator), #ifdef ET_EVENT_TRACER_ENABLED event_tracer_(event_tracer), @@ -44,8 +37,7 @@ class BackendInitContext final { event_tracer_(nullptr), #endif method_name_(method_name), - named_data_map_(named_data_map), - runtime_specs_(runtime_specs) { + named_data_map_(named_data_map) { } /** Get the runtime allocator passed from Method. It's the same runtime @@ -83,58 +75,11 @@ class BackendInitContext final { return named_data_map_; } - /** - * Get the runtime specs (load-time options) for this backend. - * These are per-delegate options passed at Module::load() time. - * - * @return Span of BackendOption containing the runtime specs, or empty span - * if no runtime specs were provided. - */ - Span runtime_specs() const { - return runtime_specs_; - } - - /** - * Get a runtime spec value by key and type. - * - * @tparam T The expected type (bool, int, or const char*) - * @param key The option key to look up. - * @return Result containing the value if found and type matches, - * Error::NotFound if key doesn't exist, - * Error::InvalidArgument if key exists but type doesn't match. - */ - template - Result get_runtime_spec(const char* key) const { - static_assert( - std::is_same_v || std::is_same_v || - std::is_same_v, - "get_runtime_spec only supports bool, int, and const char*"); - - for (size_t i = 0; i < runtime_specs_.size(); ++i) { - const auto& opt = runtime_specs_[i]; - if (std::strcmp(opt.key, key) == 0) { - if constexpr (std::is_same_v) { - if (auto* arr = std::get_if>( - &opt.value)) { - return arr->data(); - } - } else { - if (auto* val = std::get_if(&opt.value)) { - return *val; - } - } - return Error::InvalidArgument; - } - } - return Error::NotFound; - } - private: MemoryAllocator* runtime_allocator_ = nullptr; EventTracer* event_tracer_ = nullptr; const char* method_name_ = nullptr; const NamedDataMap* named_data_map_ = nullptr; - Span runtime_specs_; }; } // namespace ET_RUNTIME_NAMESPACE diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_option_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/backend_option_context.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_option_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/backend_option_context.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/interface.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/interface.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/interface.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/interface.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/interface.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/interface.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/interface.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/options.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/options.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/options.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/options.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/targets.bzl new file mode 100644 index 0000000..606ae32 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/targets.bzl @@ -0,0 +1,33 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + runtime.cxx_library( + name = "interface" + aten_suffix, + srcs = [ + "interface.cpp", + ], + exported_headers = [ + "backend_execution_context.h", + "backend_init_context.h", + "backend_option_context.h", + "options.h", + "interface.h", + ], + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/core:event_tracer" + aten_suffix, + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/core:named_data_map", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_interface_update_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_interface_update_test.cpp new file mode 100644 index 0000000..210f82e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_interface_update_test.cpp @@ -0,0 +1,402 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; +using executorch::runtime::Backend; +using executorch::runtime::BackendExecutionContext; +using executorch::runtime::BackendInitContext; +using executorch::runtime::BackendInterface; +using executorch::runtime::BackendOption; +using executorch::runtime::BackendOptionContext; +using executorch::runtime::BackendOptions; +using executorch::runtime::CompileSpec; +using executorch::runtime::DelegateHandle; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::get_backend_class; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +class MockBackend : public BackendInterface { + public: + ~MockBackend() override = default; + + bool is_available() const override { + return true; + } + + Result init( + __ET_UNUSED BackendInitContext& context, + __ET_UNUSED FreeableBuffer* processed, + __ET_UNUSED ArrayRef compile_specs) const override { + init_called = true; + return nullptr; + } + + Error execute( + __ET_UNUSED BackendExecutionContext& context, + __ET_UNUSED DelegateHandle* handle, + __ET_UNUSED Span args) const override { + execute_count++; + return Error::Ok; + } + + Error set_option( + __ET_UNUSED BackendOptionContext& context, + const executorch::runtime::Span& backend_options) + override { + set_option_count++; + int success_update = 0; + for (const auto& backend_option : backend_options) { + if (strcmp(backend_option.key, "Backend") == 0) { + if (std::holds_alternative< + std::array>( + backend_option.value)) { + // Store the value in our member variable + const auto& arr = + std::get>(backend_option.value); + target_backend = std::string(arr.data()); + success_update++; + } + } else if (strcmp(backend_option.key, "NumberOfThreads") == 0) { + if (std::holds_alternative(backend_option.value)) { + num_threads = std::get(backend_option.value); + success_update++; + } + } else if (strcmp(backend_option.key, "Debug") == 0) { + if (std::holds_alternative(backend_option.value)) { + debug = std::get(backend_option.value); + success_update++; + } + } + } + if (success_update == backend_options.size()) { + return Error::Ok; + } + return Error::InvalidArgument; + } + + // Mutable allows modification in const methods + mutable std::optional target_backend; + mutable int num_threads = 0; + mutable bool debug = false; + + // State tracking + mutable bool init_called = false; + mutable int execute_count = 0; + mutable int set_option_count = 0; +}; + +class BackendInterfaceUpdateTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + mock_backend = std::make_unique(); + // static Error register_success = register_executor_backend(); + } + + std::unique_ptr mock_backend; + BackendOptions<5> options; +}; + +TEST_F(BackendInterfaceUpdateTest, HandlesInvalidOption) { + BackendOptionContext context; + + // Test invalid key case + std::array value_array{"None"}; + BackendOption invalid_option{"InvalidKey", value_array}; + + Error err = mock_backend->set_option(context, invalid_option); + EXPECT_EQ(err, Error::InvalidArgument); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesStringOption) { + BackendOptionContext context; + options.set_option("Backend", "GPU"); + // // Create a backend option to pass to update + + EXPECT_EQ(mock_backend->target_backend, std::nullopt); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + + EXPECT_EQ(mock_backend->target_backend, "GPU"); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesIntOption) { + // Check the default num_threads value is 0 + EXPECT_EQ(mock_backend->debug, false); + // Create a mock context (needs to be defined or mocked) + BackendOptionContext context; + + int expected_num_threads = 4; + + // Create a backend option to pass to update + options.set_option("NumberOfThreads", expected_num_threads); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(mock_backend->num_threads, expected_num_threads); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesBoolOption) { + // Check the default num_threads value is 0 + EXPECT_EQ(mock_backend->debug, false); + // Create a mock context (needs to be defined or mocked) + BackendOptionContext context; + + options.set_option("Debug", true); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + + EXPECT_EQ(mock_backend->debug, true); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesMultipleOptions) { + // Check the default num_threads value is 0 + EXPECT_EQ(mock_backend->debug, false); + // Create a mock context (needs to be defined or mocked) + BackendOptionContext context; + + options.set_option("Debug", true); + options.set_option("NumberOfThreads", 4); + options.set_option("Backend", "GPU"); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + + EXPECT_EQ(mock_backend->debug, true); + EXPECT_EQ(mock_backend->num_threads, 4); + EXPECT_EQ(mock_backend->target_backend, "GPU"); +} + +TEST_F(BackendInterfaceUpdateTest, UpdateBeforeInit) { + BackendOptionContext option_context; + MemoryAllocator memory_allocator{MemoryAllocator(0, nullptr)}; + + BackendInitContext init_context(&memory_allocator); + + // Create backend option + options.set_option("Backend", "GPU"); + + // Update before init + Error err = mock_backend->set_option(option_context, options.view()); + EXPECT_EQ(err, Error::Ok); + + // Now call init + FreeableBuffer* processed = nullptr; // Not used in mock + ArrayRef compile_specs; // Empty + auto handle_or_error = + mock_backend->init(init_context, processed, compile_specs); + EXPECT_EQ(handle_or_error.error(), Error::Ok); + + // Verify state + EXPECT_TRUE(mock_backend->init_called); + EXPECT_EQ(mock_backend->set_option_count, 1); + EXPECT_EQ(mock_backend->execute_count, 0); + ASSERT_TRUE(mock_backend->target_backend.has_value()); + EXPECT_STREQ(mock_backend->target_backend.value().c_str(), "GPU"); +} + +TEST_F(BackendInterfaceUpdateTest, UpdateAfterInitBeforeExecute) { + BackendOptionContext option_context; + MemoryAllocator init_memory_allocator{MemoryAllocator(0, nullptr)}; + BackendInitContext init_context(&init_memory_allocator); + BackendExecutionContext execute_context; + + // First call init + FreeableBuffer* processed = nullptr; + ArrayRef compile_specs; + auto handle_or_error = + mock_backend->init(init_context, processed, compile_specs); + EXPECT_TRUE(handle_or_error.ok()); + + // Verify init called but execute not called + EXPECT_TRUE(mock_backend->init_called); + EXPECT_EQ(mock_backend->execute_count, 0); + + // Now update + options.set_option("Backend", "CPU"); + Error err = mock_backend->set_option(option_context, options.view()); + EXPECT_EQ(err, Error::Ok); + + // Now execute + DelegateHandle* handle = handle_or_error.get(); + Span args((EValue**)nullptr, (size_t)0); // Not used in mock + err = mock_backend->execute(execute_context, handle, args); + EXPECT_EQ(err, Error::Ok); + + // Verify state + EXPECT_EQ(mock_backend->set_option_count, 1); + EXPECT_EQ(mock_backend->execute_count, 1); + ASSERT_TRUE(mock_backend->target_backend.has_value()); + EXPECT_STREQ(mock_backend->target_backend.value().c_str(), "CPU"); +} + +TEST_F(BackendInterfaceUpdateTest, UpdateBetweenExecutes) { + BackendOptionContext option_context; + MemoryAllocator init_memory_allocator{MemoryAllocator(0, nullptr)}; + BackendInitContext init_context(&init_memory_allocator); + BackendExecutionContext execute_context; + + // Initialize + FreeableBuffer* processed = nullptr; + ArrayRef compile_specs; + auto handle_or_error = + mock_backend->init(init_context, processed, compile_specs); + EXPECT_TRUE(handle_or_error.ok()); + DelegateHandle* handle = handle_or_error.get(); + + // First execute + Span args((EValue**)nullptr, (size_t)0); // Not used in mock + Error err = mock_backend->execute(execute_context, handle, args); + EXPECT_EQ(err, Error::Ok); + + // Update between executes + options.set_option("Backend", "NPU"); + err = mock_backend->set_option(option_context, options.view()); + EXPECT_EQ(err, Error::Ok); + + // Second execute + err = mock_backend->execute(execute_context, handle, args); + EXPECT_EQ(err, Error::Ok); + + // Verify state + EXPECT_EQ(mock_backend->set_option_count, 1); + EXPECT_EQ(mock_backend->execute_count, 2); + ASSERT_TRUE(mock_backend->target_backend.has_value()); + EXPECT_STREQ(mock_backend->target_backend.value().c_str(), "NPU"); +} + +// Mock backend for testing +class StubBackend : public BackendInterface { + public: + ~StubBackend() override = default; + + bool is_available() const override { + return true; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + return nullptr; + } + + Error execute( + BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + return Error::Ok; + } + + Error get_option( + BackendOptionContext& context, + executorch::runtime::Span& + backend_options) override { + // For testing purposes, just record that get_option was called + // and verify the input parameters + get_option_called = true; + get_option_call_count++; + last_get_option_size = backend_options.size(); + + // Verify that the expected option key is present and modify the value + for (size_t i = 0; i < backend_options.size(); ++i) { + if (strcmp(backend_options[i].key, "NumberOfThreads") == 0) { + // Set the value to what was stored by set_option + backend_options[i].value = last_num_threads; + found_expected_key = true; + break; + } + } + + return Error::Ok; + } + + Error set_option( + BackendOptionContext& context, + const executorch::runtime::Span& + backend_options) override { + // Store the options for verification + last_options_size = backend_options.size(); + if (backend_options.size() > 0) { + for (const auto& option : backend_options) { + if (strcmp(option.key, "NumberOfThreads") == 0) { + if (auto* val = std::get_if(&option.value)) { + last_num_threads = *val; + } + } + } + } + return Error::Ok; + } + + // Mutable for testing verification + size_t last_options_size = 0; + int last_num_threads = 0; + bool get_option_called = false; + int get_option_call_count = 0; + size_t last_get_option_size = 0; + bool found_expected_key = false; +}; + +class BackendUpdateTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Register the stub backend + stub_backend = std::make_unique(); + Backend backend_config{"StubBackend", stub_backend.get()}; + auto register_result = register_backend(backend_config); + ASSERT_EQ(register_result, Error::Ok); + } + + std::unique_ptr stub_backend; +}; + +// Test basic string functionality +TEST_F(BackendUpdateTest, TestSetGetOption) { + BackendOptions<1> backend_options; + int new_num_threads = 4; + backend_options.set_option("NumberOfThreads", new_num_threads); + + auto status = set_option("StubBackend", backend_options.view()); + ASSERT_EQ(status, Error::Ok); + + // Set up the default option, which will be populuated by the get_option call + BackendOption ref_backend_option{"NumberOfThreads", 0}; + status = get_option("StubBackend", ref_backend_option); + + // Verify that the backend actually received the options + ASSERT_TRUE(std::get(ref_backend_option.value) == new_num_threads); + + // Verify that the backend actually update the options + ASSERT_EQ(stub_backend->last_options_size, 1); + ASSERT_EQ(stub_backend->last_num_threads, new_num_threads); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_options_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_options_test.cpp new file mode 100644 index 0000000..313cac6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/backend_options_test.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::BackendOptions; +using executorch::runtime::Error; + +class BackendOptionsTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } + BackendOptions<5> options; // Capacity of 5 for testing limits +}; + +// Test basic string functionality +TEST_F(BackendOptionsTest, HandlesStringOptions) { + // Set and retrieve valid string + options.set_option("backend_type", "GPU"); + const char* result = nullptr; + EXPECT_EQ(options.get_option("backend_type", result), Error::Ok); + EXPECT_STREQ(result, "GPU"); + + // Update existing key + options.set_option("backend_type", "CPU"); + EXPECT_EQ(options.get_option("backend_type", result), Error::Ok); + EXPECT_STREQ(result, "CPU"); +} + +// Test boolean options +TEST_F(BackendOptionsTest, HandlesBoolOptions) { + options.set_option("debug", true); + bool debug = false; + EXPECT_EQ(options.get_option("debug", debug), Error::Ok); + EXPECT_TRUE(debug); + + // Test false value + options.set_option("verbose", false); + EXPECT_EQ(options.get_option("verbose", debug), Error::Ok); + EXPECT_FALSE(debug); +} + +// Test integer options +TEST_F(BackendOptionsTest, HandlesIntOptions) { + options.set_option("num_threads", 256); + int num_threads = 0; + EXPECT_EQ(options.get_option("num_threads", num_threads), Error::Ok); + EXPECT_EQ(num_threads, 256); +} + +// Test error conditions +TEST_F(BackendOptionsTest, HandlesErrors) { + // Non-existent key + bool dummy_bool; + EXPECT_EQ(options.get_option("missing", dummy_bool), Error::NotFound); + + // Type mismatch + options.set_option("threshold", 100); + const char* dummy_str = nullptr; + EXPECT_EQ(options.get_option("threshold", dummy_str), Error::InvalidArgument); + + // Null value handling, should expect failure + ET_EXPECT_DEATH( + options.set_option("nullable", static_cast(nullptr)), ""); +} + +// Test type-specific keys +TEST_F(BackendOptionsTest, EnforcesKeyTypes) { + // Same key name - later set operations overwrite earlier ones + options.set_option("flag", true); + options.set_option("flag", 123); // Overwrites the boolean entry + + bool bval; + int ival; + + // Boolean get should fail - type was overwritten to INT + EXPECT_EQ(options.get_option("flag", bval), Error::InvalidArgument); + + // Integer get should succeed with correct value + EXPECT_EQ(options.get_option("flag", ival), Error::Ok); + EXPECT_EQ(ival, 123); +} + +TEST_F(BackendOptionsTest, MutableOption) { + int ival; + options.set_option("flag", 0); + // Integer get should succeed with correct value + EXPECT_EQ(options.get_option("flag", ival), Error::Ok); + EXPECT_EQ(ival, 0); + + options.view()[0].value = 123; // Overwrites the entry + + // Integer get should succeed with the updated value + EXPECT_EQ(options.get_option("flag", ival), Error::Ok); + EXPECT_EQ(ival, 123); +} + +// Test copy constructor +TEST_F(BackendOptionsTest, CopyConstructor) { + // Set up original option + options.set_option("debug", true); + + // Create copy using copy constructor + BackendOptions<5> copied_options(options); + + // Verify option was copied correctly + bool debug_val; + EXPECT_EQ(copied_options.get_option("debug", debug_val), Error::Ok); + EXPECT_TRUE(debug_val); + + // Verify independence - modifying original doesn't affect copy + options.set_option("debug", false); + EXPECT_EQ(copied_options.get_option("debug", debug_val), Error::Ok); + EXPECT_TRUE(debug_val); // Should still be true in copy + + // Verify independence - modifying copy doesn't affect original + copied_options.set_option("debug", false); + EXPECT_EQ(options.get_option("debug", debug_val), Error::Ok); + EXPECT_FALSE(debug_val); // Should be false in original +} + +// Test copy assignment operator +TEST_F(BackendOptionsTest, CopyAssignmentOperator) { + // Set up original option + options.set_option("enable_profiling", true); + + // Create another options object and assign to it + BackendOptions<5> assigned_options; + assigned_options.set_option("temp_option", false); // Add something first + + assigned_options = options; + + // Verify option was copied correctly + bool profiling_val; + EXPECT_EQ( + assigned_options.get_option("enable_profiling", profiling_val), + Error::Ok); + EXPECT_TRUE(profiling_val); + + // Verify the temp_option was overwritten (not present in assigned object) + bool temp_val; + EXPECT_EQ( + assigned_options.get_option("temp_option", temp_val), Error::NotFound); + + // Verify independence - modifying original doesn't affect assigned copy + options.set_option("enable_profiling", false); + EXPECT_EQ( + assigned_options.get_option("enable_profiling", profiling_val), + Error::Ok); + EXPECT_TRUE(profiling_val); // Should still be true in assigned copy +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/targets.bzl new file mode 100644 index 0000000..f9e5c1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/backend/test/targets.bzl @@ -0,0 +1,26 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "backend_options_test", + srcs = ["backend_options_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/backend:interface", + "//executorch/test/utils:utils", + ], + ) + + runtime.cxx_test( + name = "backend_interface_update_test", + srcs = ["backend_interface_update_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/backend:interface", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/array_ref.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/array_ref.h similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/array_ref.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/array_ref.h index d920761..a23509e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/array_ref.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/array_ref.h @@ -30,7 +30,6 @@ #include #include -#include #include namespace executorch { @@ -162,8 +161,7 @@ class ArrayRef final { /// slice(n, m) - Take M elements of the array starting at element N ArrayRef slice(size_t N, size_t M) const { // cant slice longer then the array - size_t end = 0; - ET_CHECK(!c10::add_overflows(N, M, &end) && end <= size()); + ET_CHECK(N + M <= size()); return ArrayRef(data() + N, M); } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/data_loader.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/data_loader.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/defines.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/defines.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/defines.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/defines.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/error.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/error.h similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/error.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/error.h index 80c2ef6..b75f107 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/error.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/error.h @@ -44,9 +44,6 @@ enum class Error : error_code_t { /// Status indicating there are no more steps of execution to run EndOfMethod = 0x03, - /// Status indicating a resource has already been loaded. - AlreadyLoaded = 0x04, - /* * Logical errors. */ @@ -117,8 +114,6 @@ constexpr const char* to_string(const Error error) { return "Error::InvalidState"; case Error::EndOfMethod: return "Error::EndOfMethod"; - case Error::AlreadyLoaded: - return "Error::AlreadyLoaded"; case Error::NotSupported: return "Error::NotSupported"; case Error::NotImplemented: @@ -152,7 +147,6 @@ constexpr const char* to_string(const Error error) { case Error::RegistrationAlreadyRegistered: return "Error::RegistrationAlreadyRegistered"; } - return "Error::Unknown"; } } // namespace runtime diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/evalue.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/evalue.cpp similarity index 54% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/evalue.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/evalue.cpp index 6fd118d..121a9a2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/evalue.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/evalue.cpp @@ -10,10 +10,6 @@ namespace executorch { namespace runtime { - -// Specialize for list of optional tensors, as nullptr is a valid std::nullopt. -// For non-optional types, nullptr is invalid. - template <> executorch::aten::ArrayRef> BoxedEvalueList>::get() const { @@ -31,26 +27,5 @@ BoxedEvalueList>::get() const { return executorch::aten::ArrayRef>{ unwrapped_vals_, wrapped_vals_.size()}; } - -template <> -Result>> -BoxedEvalueList>::tryGet() const { - for (typename executorch::aten::ArrayRef< - std::optional>::size_type i = 0; - i < wrapped_vals_.size(); - i++) { - if (wrapped_vals_[i] == nullptr) { - unwrapped_vals_[i] = std::nullopt; - continue; - } - auto r = wrapped_vals_[i]->tryToOptional(); - if (!r.ok()) { - return r.error(); - } - unwrapped_vals_[i] = std::move(r.get()); - } - return executorch::aten::ArrayRef>{ - unwrapped_vals_, wrapped_vals_.size()}; -} } // namespace runtime } // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/evalue.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/evalue.h similarity index 69% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/evalue.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/evalue.h index eed52bb..18927ab 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/evalue.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/evalue.h @@ -8,7 +8,6 @@ #pragma once #include -#include #include #include @@ -72,30 +71,6 @@ class BoxedEvalueList { */ executorch::aten::ArrayRef get() const; - /** - * Result-returning counterpart of get(). Validates each wrapped EValue's - * tag before materializing; returns Error::InvalidType if any element's - * tag does not match T and Error::InvalidState if any element pointer is - * null. Use this when materializing lists from untrusted .pte data so that - * a malformed program cannot force a process abort inside to() / - * ET_CHECK. - */ - Result> tryGet() const; - - /** - * Destroys the unwrapped elements without re-dereferencing wrapped_vals_. - * This is safe to call during EValue destruction because it does not - * dereference wrapped_vals_, which may point to EValues mutated by - * MoveCall instructions. - */ - void destroy_elements() { - for (typename executorch::aten::ArrayRef::size_type i = 0; - i < wrapped_vals_.size(); - i++) { - unwrapped_vals_[i].~T(); - } - } - private: static EValue** checkWrappedVals(EValue** wrapped_vals, int size) { ET_CHECK_MSG(wrapped_vals != nullptr, "wrapped_vals cannot be null"); @@ -118,10 +93,6 @@ template <> executorch::aten::ArrayRef> BoxedEvalueList>::get() const; -template <> -Result>> -BoxedEvalueList>::tryGet() const; - // Aggregate typing system similar to IValue only slimmed down with less // functionality, no dependencies on atomic, and fewer supported types to better // suit embedded systems (ie no intrusive ptr) @@ -208,13 +179,6 @@ struct EValue { return payload.copyable_union.as_int; } - Result tryToInt() const { - if (!isInt()) { - return Error::InvalidType; - } - return payload.copyable_union.as_int; - } - /****** Double Type ******/ /*implicit*/ EValue(double d) : tag(Tag::Double) { payload.copyable_union.as_double = d; @@ -229,13 +193,6 @@ struct EValue { return payload.copyable_union.as_double; } - Result tryToDouble() const { - if (!isDouble()) { - return Error::InvalidType; - } - return payload.copyable_union.as_double; - } - /****** Bool Type ******/ /*implicit*/ EValue(bool b) : tag(Tag::Bool) { payload.copyable_union.as_bool = b; @@ -250,13 +207,6 @@ struct EValue { return payload.copyable_union.as_bool; } - Result tryToBool() const { - if (!isBool()) { - return Error::InvalidType; - } - return payload.copyable_union.as_bool; - } - /****** Scalar Type ******/ /// Construct an EValue using the implicit value of a Scalar. /*implicit*/ EValue(executorch::aten::Scalar s) { @@ -292,19 +242,6 @@ struct EValue { } } - Result tryToScalar() const { - if (isDouble()) { - return executorch::aten::Scalar(payload.copyable_union.as_double); - } - if (isInt()) { - return executorch::aten::Scalar(payload.copyable_union.as_int); - } - if (isBool()) { - return executorch::aten::Scalar(payload.copyable_union.as_bool); - } - return Error::InvalidType; - } - /****** Tensor Type ******/ /*implicit*/ EValue(executorch::aten::Tensor t) : tag(Tag::Tensor) { // When built in aten mode, at::Tensor has a non trivial constructor @@ -354,16 +291,6 @@ struct EValue { return payload.as_tensor; } - // Returns a copy of the Tensor handle (one intrusive_ptr refcount bump in - // ATen mode; free in lean mode). Unlike toTensor()'s const& / & overloads, - // tryToTensor() cannot return a reference — Result wraps by value. - Result tryToTensor() const { - if (!isTensor()) { - return Error::InvalidType; - } - return payload.as_tensor; - } - /****** String Type ******/ /*implicit*/ EValue(executorch::aten::ArrayRef* s) : tag(Tag::String) { ET_CHECK_MSG(s != nullptr, "ArrayRef pointer cannot be null"); @@ -384,18 +311,6 @@ struct EValue { payload.copyable_union.as_string_ptr->size()); } - Result tryToString() const { - if (!isString()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_string_ptr == nullptr) { - return Error::InvalidState; - } - return std::string_view( - payload.copyable_union.as_string_ptr->data(), - payload.copyable_union.as_string_ptr->size()); - } - /****** Int List Type ******/ /*implicit*/ EValue(BoxedEvalueList* i) : tag(Tag::ListInt) { ET_CHECK_MSG( @@ -415,16 +330,6 @@ struct EValue { return (payload.copyable_union.as_int_list_ptr)->get(); } - Result> tryToIntList() const { - if (!isIntList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_int_list_ptr == nullptr) { - return Error::InvalidState; - } - return (payload.copyable_union.as_int_list_ptr)->tryGet(); - } - /****** Bool List Type ******/ /*implicit*/ EValue(executorch::aten::ArrayRef* b) : tag(Tag::ListBool) { @@ -444,16 +349,6 @@ struct EValue { return *(payload.copyable_union.as_bool_list_ptr); } - Result> tryToBoolList() const { - if (!isBoolList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_bool_list_ptr == nullptr) { - return Error::InvalidState; - } - return *(payload.copyable_union.as_bool_list_ptr); - } - /****** Double List Type ******/ /*implicit*/ EValue(executorch::aten::ArrayRef* d) : tag(Tag::ListDouble) { @@ -473,16 +368,6 @@ struct EValue { return *(payload.copyable_union.as_double_list_ptr); } - Result> tryToDoubleList() const { - if (!isDoubleList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_double_list_ptr == nullptr) { - return Error::InvalidState; - } - return *(payload.copyable_union.as_double_list_ptr); - } - /****** Tensor List Type ******/ /*implicit*/ EValue(BoxedEvalueList* t) : tag(Tag::ListTensor) { @@ -503,17 +388,6 @@ struct EValue { return payload.copyable_union.as_tensor_list_ptr->get(); } - Result> tryToTensorList() - const { - if (!isTensorList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_tensor_list_ptr == nullptr) { - return Error::InvalidState; - } - return payload.copyable_union.as_tensor_list_ptr->tryGet(); - } - /****** List Optional Tensor Type ******/ /*implicit*/ EValue( BoxedEvalueList>* t) @@ -538,17 +412,6 @@ struct EValue { return payload.copyable_union.as_list_optional_tensor_ptr->get(); } - Result>> - tryToListOptionalTensor() const { - if (!isListOptionalTensor()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_list_optional_tensor_ptr == nullptr) { - return Error::InvalidState; - } - return payload.copyable_union.as_list_optional_tensor_ptr->tryGet(); - } - /****** ScalarType Type ******/ executorch::aten::ScalarType toScalarType() const { ET_CHECK_MSG(isInt(), "EValue is not a ScalarType."); @@ -556,14 +419,6 @@ struct EValue { payload.copyable_union.as_int); } - Result tryToScalarType() const { - if (!isInt()) { - return Error::InvalidType; - } - return static_cast( - payload.copyable_union.as_int); - } - /****** MemoryFormat Type ******/ executorch::aten::MemoryFormat toMemoryFormat() const { ET_CHECK_MSG(isInt(), "EValue is not a MemoryFormat."); @@ -571,27 +426,12 @@ struct EValue { payload.copyable_union.as_int); } - Result tryToMemoryFormat() const { - if (!isInt()) { - return Error::InvalidType; - } - return static_cast( - payload.copyable_union.as_int); - } - /****** Layout Type ******/ executorch::aten::Layout toLayout() const { ET_CHECK_MSG(isInt(), "EValue is not a Layout."); return static_cast(payload.copyable_union.as_int); } - Result tryToLayout() const { - if (!isInt()) { - return Error::InvalidType; - } - return static_cast(payload.copyable_union.as_int); - } - /****** Device Type ******/ executorch::aten::Device toDevice() const { ET_CHECK_MSG(isInt(), "EValue is not a Device."); @@ -601,16 +441,6 @@ struct EValue { -1); } - Result tryToDevice() const { - if (!isInt()) { - return Error::InvalidType; - } - return executorch::aten::Device( - static_cast( - payload.copyable_union.as_int), - -1); - } - template T to() &&; template @@ -618,15 +448,6 @@ struct EValue { template typename internal::evalue_to_ref_overload_return::type to() &; - /** - * Result-returning equivalent of `to()`. Tag mismatch returns - * `Error::InvalidType`; a null list/string payload returns - * `Error::InvalidState`. Specializations are defined below via - * `EVALUE_DEFINE_TRY_TO`. - */ - template - Result tryTo() const; - /** * Converts the EValue to an optional object that can represent both T and * an uninitialized state. @@ -639,23 +460,6 @@ struct EValue { return this->to(); } - /** - * Result-returning equivalent of `toOptional()`. None maps to an empty - * optional; any other tag that doesn't match T propagates `tryTo()`'s - * error (`Error::InvalidType`). - */ - template - inline Result> tryToOptional() const { - if (this->isNone()) { - return std::optional(std::nullopt); - } - auto r = this->tryTo(); - if (!r.ok()) { - return r.error(); - } - return std::optional(std::move(r.get())); - } - private: // Pre cond: the payload value has had its destructor called void clearToNone() noexcept { @@ -687,11 +491,18 @@ struct EValue { } else if ( isTensorList() && payload.copyable_union.as_tensor_list_ptr != nullptr) { - payload.copyable_union.as_tensor_list_ptr->destroy_elements(); + // for (auto& tensor : toTensorList()) { + for (auto& tensor : payload.copyable_union.as_tensor_list_ptr->get()) { + tensor.~Tensor(); + } } else if ( isListOptionalTensor() && payload.copyable_union.as_list_optional_tensor_ptr != nullptr) { - payload.copyable_union.as_list_optional_tensor_ptr->destroy_elements(); + // for (auto& optional_tensor : toListOptionalTensor()) { + for (auto& optional_tensor : + payload.copyable_union.as_list_optional_tensor_ptr->get()) { + optional_tensor.~optional(); + } } } @@ -773,59 +584,6 @@ EVALUE_DEFINE_TO( toListOptionalTensor) #undef EVALUE_DEFINE_TO -#define EVALUE_DEFINE_TRY_TO(T, method_name) \ - template <> \ - inline Result EValue::tryTo() const { \ - return this->method_name(); \ - } - -EVALUE_DEFINE_TRY_TO(executorch::aten::Scalar, tryToScalar) -EVALUE_DEFINE_TRY_TO(int64_t, tryToInt) -EVALUE_DEFINE_TRY_TO(bool, tryToBool) -EVALUE_DEFINE_TRY_TO(double, tryToDouble) -EVALUE_DEFINE_TRY_TO(std::string_view, tryToString) -EVALUE_DEFINE_TRY_TO(executorch::aten::ScalarType, tryToScalarType) -EVALUE_DEFINE_TRY_TO(executorch::aten::MemoryFormat, tryToMemoryFormat) -EVALUE_DEFINE_TRY_TO(executorch::aten::Layout, tryToLayout) -EVALUE_DEFINE_TRY_TO(executorch::aten::Device, tryToDevice) -// Tensor and Optional Tensor -EVALUE_DEFINE_TRY_TO(executorch::aten::Tensor, tryToTensor) -EVALUE_DEFINE_TRY_TO( - std::optional, - tryToOptional) - -// IntList and Optional IntList -EVALUE_DEFINE_TRY_TO(executorch::aten::ArrayRef, tryToIntList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// DoubleList and Optional DoubleList -EVALUE_DEFINE_TRY_TO(executorch::aten::ArrayRef, tryToDoubleList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// BoolList and Optional BoolList -EVALUE_DEFINE_TRY_TO(executorch::aten::ArrayRef, tryToBoolList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// TensorList and Optional TensorList -EVALUE_DEFINE_TRY_TO( - executorch::aten::ArrayRef, - tryToTensorList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// List of Optional Tensor -EVALUE_DEFINE_TRY_TO( - executorch::aten::ArrayRef>, - tryToListOptionalTensor) -#undef EVALUE_DEFINE_TRY_TO - template executorch::aten::ArrayRef BoxedEvalueList::get() const { for (typename executorch::aten::ArrayRef::size_type i = 0; @@ -837,23 +595,6 @@ executorch::aten::ArrayRef BoxedEvalueList::get() const { return executorch::aten::ArrayRef{unwrapped_vals_, wrapped_vals_.size()}; } -template -Result> BoxedEvalueList::tryGet() const { - for (typename executorch::aten::ArrayRef::size_type i = 0; - i < wrapped_vals_.size(); - i++) { - if (wrapped_vals_[i] == nullptr) { - return Error::InvalidState; - } - auto r = wrapped_vals_[i]->template tryTo(); - if (!r.ok()) { - return r.error(); - } - unwrapped_vals_[i] = std::move(r.get()); - } - return executorch::aten::ArrayRef{unwrapped_vals_, wrapped_vals_.size()}; -} - } // namespace runtime } // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/event_tracer.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/event_tracer.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/event_tracer.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/event_tracer.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/event_tracer_hooks.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/event_tracer_hooks.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/event_tracer_hooks.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/event_tracer_hooks.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/event_tracer_hooks_delegate.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/event_tracer_hooks_delegate.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/event_tracer_hooks_delegate.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/event_tracer_hooks_delegate.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/exec_aten.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/exec_aten.h similarity index 84% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/exec_aten.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/exec_aten.h index f539414..8c06045 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/exec_aten.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/exec_aten.h @@ -8,10 +8,7 @@ #pragma once -#include // @manual -#include // @manual #include // @manual -#include // @manual #include #ifdef USE_ATEN_LIB #include // @manual @@ -31,7 +28,6 @@ #include // @manual #include // @manual #include // @manual -#include // @manual #include // @manual #include #else // use executor @@ -114,32 +110,6 @@ inline ssize_t compute_numel(const SizesType* sizes, ssize_t dim) { c10::multiply_integers(c10::ArrayRef(sizes, dim))); } -inline ::executorch::runtime::Result safe_numel( - const SizesType* sizes, - ssize_t dim) { - ET_CHECK_OR_RETURN_ERROR( - dim == 0 || sizes != nullptr, - InvalidArgument, - "Sizes must be provided for non-scalar tensors"); - ssize_t numel = 1; - for (ssize_t i = 0; i < dim; i++) { - ET_CHECK_OR_RETURN_ERROR( - sizes[i] >= 0, - InvalidArgument, - "Size must be non-negative, got %zd at dimension %zd", - static_cast(sizes[i]), - i); - ssize_t next_numel; - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(numel, static_cast(sizes[i]), &next_numel), - InvalidArgument, - "Overflow computing numel at dimension %zd", - i); - numel = next_numel; - } - return numel; -} - #undef ET_PRI_TENSOR_SIZE #define ET_PRI_TENSOR_SIZE PRId64 @@ -188,7 +158,6 @@ using OptionalArrayRef = using OptionalIntArrayRef = OptionalArrayRef; using torch::executor::compute_numel; -using torch::executor::safe_numel; #endif // Use ExecuTorch types diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/targets.bzl new file mode 100644 index 0000000..df4a87e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/targets.bzl @@ -0,0 +1,21 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + # Depend on this target if your types (Tensor, ArrayRef, etc) should be flexible between ATen and executor + runtime.cxx_library( + name = "lib" + aten_suffix, + exported_headers = ["exec_aten.h"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + visibility = ["PUBLIC"], + exported_deps = ["//executorch/runtime/core:tensor_shape_dynamism"] + ([] if aten_mode else ["//executorch/runtime/core/portable_type:portable_type"]), + exported_external_deps = ["libtorch"] if aten_mode else [], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/README.md new file mode 100644 index 0000000..e8d52c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/README.md @@ -0,0 +1,4 @@ +This directory contains code to help tests that use the types defined in +`//executorch/runtime/core/portable_type` and `//executorch/runtime/core/exec_aten`. +This code should be treated as test-only, and should not be compiled into production +targets. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/targets.bzl new file mode 100644 index 0000000..fa259b4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/targets.bzl @@ -0,0 +1,32 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "tensor_util" + (aten_suffix), + srcs = ["tensor_util.cpp"], + exported_headers = [ + "tensor_util.h", + "tensor_factory.h", + ], + visibility = ["PUBLIC"], + compiler_flags = ["-Wno-unneeded-internal-declaration"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + exported_external_deps = [ + "gmock" + aten_suffix, + ] + (["libtorch"] if aten_mode else []), + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_factory.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_factory.h new file mode 100644 index 0000000..562db97 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_factory.h @@ -0,0 +1,1133 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef USE_ATEN_LIB +#include +#else // !USE_ATEN_LIB +#include +#include +#include +#endif // !USE_ATEN_LIB + +namespace executorch { +namespace runtime { +namespace testing { + +namespace internal { + +/** + * Returns the number of elements in the tensor, given the dimension + * sizes, assuming contiguous data. + */ +inline size_t sizes_to_numel(const std::vector& sizes) { + size_t n = 1; + for (auto s : sizes) { + n *= s; + } + return n; +} + +/** + * Check if given strides is legal under given sizes. In the `make` function, + * the `strides` shall ensure: + * - a. strides.size() == sizes.size() + * - b. all strides are positive. + * - c. All underlying data be accessed. + * - d. All legal indexes can access an underlying data. + * - e. No two indexes access a same data. + * - f. No out of bounds data can be accessed. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] strides The desired strides for creating new tensor. + * @return The strides is legal or not + */ + +inline bool check_strides( + const std::vector sizes, + const std::vector strides) { + if (sizes.size() != strides.size()) { + // The length of stride vector shall equal to size vector. + return false; + } + + if (strides.size() == 0) { + // Both sizes and strides are empty vector. Legal! + return true; + } + + // Check if input non-empty strides is legal. The defination of legal is in + // the comment above function. To check it, we first reformat the strides into + // contiguous style, in where the strides should be sorted from high to low. + // Then rearrange the size based on same transformation. After that, we can + // check if strides[i] == strides[i + 1] * sizes[i + 1] for all i in + // [0, sizes.size() - 1) and strides[sizes.size() - 1] == 1 + + // Get the mapping between current strides and sorted strides (from high to + // low, if equal then check if correspond size is 1 or 0 in same dimension) + // e.g. a = tensor(3, 2, 1).permute(2, 1, 0), a.size() == (1, 2, 3) and + // a.strides == (1, 1, 2). We want to sort create a mapping to make the + // sorted_stride as (2, 1, 1) while sorted_size == (3, 2, 1) + std::vector sorted_idx(sizes.size()); + for (const auto i : c10::irange(sizes.size())) { + sorted_idx[i] = i; + } + std::sort( + sorted_idx.begin(), + sorted_idx.end(), + [&](const int32_t& a, const int32_t& b) { + if (strides[a] != strides[b]) { + return strides[a] > strides[b]; + } else { + // When strides equal to each other, put the index whose + // coresponding size equal to 0 or 1 to the right. Update the rule to + // the following comparsion to circumvent strict weak ordering. + return (sizes[a] ? sizes[a] : 1) > (sizes[b] ? sizes[b] : 1); + } + }); + + // Use the mapping to rearrange the sizes and strides + std::vector sorted_sizes(sizes.size()); + std::vector sorted_strides(sizes.size()); + for (const auto i : c10::irange(sizes.size())) { + sorted_sizes[i] = sizes[sorted_idx[i]] == 0 ? 1 : sizes[sorted_idx[i]]; + sorted_strides[i] = strides[sorted_idx[i]]; + } + + // All strides should be positive. We have sorted it mainly based on strides, + // so sorted_strides[-1] has lowest value. + if (sorted_strides[strides.size() - 1] <= 0) { + return false; + } + + // Check if strides is legal + bool legal = sorted_strides[strides.size() - 1] == 1; + for (size_t i = 0; i < strides.size() - 1 && legal; i++) { + legal = legal && + (sorted_strides[i] == sorted_strides[i + 1] * sorted_sizes[i + 1]); + } + + return legal; +} + +/** + * Check that a given dim order array is valid. A dim order array is valid if + * each value from 0 to sizes.size() - 1 appears exactly once in the dim_order + * array. + */ +inline bool check_dim_order( + const std::vector& sizes, + const std::vector& dim_order) { + if (sizes.size() != dim_order.size()) { + return false; + } + size_t gauss_sum = 0; + std::vector count(dim_order.size(), 0); + for (const auto i : c10::irange(dim_order.size())) { + if (dim_order[i] >= sizes.size()) { + return false; + } + gauss_sum += static_cast(dim_order[i]) + 1; + } + // Use the gaussian sum to verify each dim appears exactly once + size_t expected_sum = (sizes.size() * (sizes.size() + 1)) / 2; + if (gauss_sum != expected_sum) { + return false; + } + + return true; +} + +inline std::vector strides_from_dim_order( + const std::vector& sizes, + const std::vector& dim_order) { + bool legal = check_dim_order(sizes, dim_order); + ET_CHECK_MSG(legal, "The input dim_order variable is illegal."); + + size_t ndim = sizes.size(); + std::vector strides(ndim); + strides[dim_order[ndim - 1]] = 1; + for (int i = ndim - 2; i >= 0; --i) { + uint8_t cur_dim = dim_order[i]; + uint8_t next_dim = dim_order[i + 1]; + strides[cur_dim] = (!sizes[next_dim]) ? strides[next_dim] + : strides[next_dim] * sizes[next_dim]; + } + return strides; +} + +inline std::vector channels_last_dim_order(size_t dims) { + ET_CHECK_MSG( + dims >= 4 && dims <= 5, + "Channels last dim order only valid for 4-dim and 5-dim tensors!"); + + std::vector dim_order(dims); + // Channels is always assigned to dim 1 + dim_order[dims - 1] = 1; + + dim_order[0] = 0; + int d = 1; + while (d < dims - 1) { + dim_order[d] = d + 1; + d++; + } + return dim_order; +} + +} // namespace internal + +#ifdef USE_ATEN_LIB + +// Note that this USE_ATEN_LIB section uses ATen-specific namespaces instead of +// exec_aten because we know that we're working with ATen, and many of these +// names aren't mapped into executorch::aten::. + +namespace internal { + +// This wrapper lets us override the C type associated with some ScalarType +// values while using the defaults for everything else. +template +struct ScalarTypeToCppTypeWrapper { + using ctype = typename c10::impl::ScalarTypeToCPPTypeT; +}; + +// Use a C type of `uint8_t` instead of `bool`. The C type will be used to +// declare a `std::vector`, and `std::vector` is often optimized to +// store a single bit per entry instead of using an array of separate `bool` +// elements. Since the tensor data will point into the vector, it needs to use +// one byte per element. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint8_t; +}; + +} // namespace internal + +template +class TensorFactory { + public: + /* + * The C types that backs the associated DTYPE. E.g., `float` for + * `ScalarType::Float`. + */ + + /** + * Used for the vector provided to the factory functions. May differ + * from the type usually associate with the ScalarType. + * + * Used for the vector<> parameters passed to the factory functions. + */ + using ctype = typename internal::ScalarTypeToCppTypeWrapper::ctype; + + /** + * The official C type for the scalar type. Used when accessing elements + * of a constructed Tensor. + */ + using true_ctype = typename c10::impl::ScalarTypeToCPPTypeT; + + TensorFactory() = default; + + /** + * Returns a new Tensor with the specified shape, data and stride. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] strides The strides for each dimensions of the Tensor. If empty + * or not specificed, the function will return a contiguous tensor based + * on data and size. If not, the strides shall follow the rules: + * - a. strides.size() == sizes.size(). + * - b. all strides are positive. + * - c. All underlying data be accessed. + * - d. All legal indexes can access an underlying data. + * - e. No two indexes access a same data. + * - f. No out of bounds data can be accessed. + * + * @return A new Tensor with the specified shape and data. + */ + at::Tensor make( + const std::vector& sizes, + const std::vector& data, + const std::vector strides = {}, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + at::Tensor t; + if (strides.empty()) { + t = zeros(sizes); + } else { + bool legal = internal::check_strides(sizes, strides); + ET_CHECK_MSG(legal, "The input strides variable is illegal."); + + t = empty_strided(sizes, strides); + } + if (t.nbytes() > 0) { + std::transform( + data.begin(), data.end(), t.template data(), [](auto x) { + return static_cast(x); + }); + } + return t; + } + + /** + * Returns a new Tensor with the specified shape, data and dim order. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] dim_order The dim order describing how tensor memory is laid + * out. If empty or not specificed, the function will use a contiguous dim + * order of {0, 1, 2, 3, ...} + * + * @return A new Tensor with the specified shape and data. + */ + at::Tensor make_with_dimorder( + const std::vector& sizes, + const std::vector& data, + const std::vector dim_order = {}, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + at::Tensor t; + if (dim_order.empty()) { + t = zeros(sizes); + } else { + auto strides = internal::strides_from_dim_order(sizes, dim_order); + t = empty_strided(sizes, strides); + } + if (t.nbytes() > 0) { + std::transform( + data.begin(), data.end(), t.template data(), [](auto x) { + return static_cast(x); + }); + } + return t; + } + + /** + * Returns a new Tensor with the specified shape and data in channels last + * memory layout. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * + * @return A new Tensor with the specified shape and data. + */ + at::Tensor make_channels_last( + const std::vector& sizes, + const std::vector& data, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + return make_with_dimorder( + sizes, data, internal::channels_last_dim_order(sizes.size()), dynamism); + } + + /** + * Given data in contiguous memory format, returns a new Tensor with the + * specified shape and the same data but in channels last memory format. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data in contiguous memory format that the Tensor should + * be initialized with. The size of this vector must be equal to the product + * of the elements of `sizes`. + * + * @return A new Tensor with the specified shape and data in channls last + * memory format. + */ + at::Tensor channels_last_like( + const at::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + ET_CHECK_MSG( + input.sizes().size() == 4, "Only 4D tensors can be channels last"); + + const std::vector sizes( + input.sizes().begin(), input.sizes().end()); + + std::vector contiguous_dim_order(sizes.size()); + for (uint8_t i = 0; i < sizes.size(); i++) { + contiguous_dim_order[i] = i; + } + std::vector contiguous_strides = + internal::strides_from_dim_order(sizes, contiguous_dim_order); + + for (const auto i : c10::irange(input.dim())) { + ET_CHECK_MSG( + input.strides()[i] == contiguous_strides[i], + "Input tensor is not contiguous"); + } + + int32_t N = sizes[0]; + int32_t C = sizes[1]; + int32_t H = sizes[2]; + int32_t W = sizes[3]; + + std::vector contiguous_data( + input.data_ptr(), input.data_ptr() + input.numel()); + std::vector channels_last_data( + N * C * H * W); // Create a new blob with the same total size to contain + // channels_last data + for (const auto n : c10::irange(N)) { + for (const auto c : c10::irange(C)) { + for (const auto h : c10::irange(H)) { + for (const auto w : c10::irange(W)) { + // Calculate the index in the original blob + int32_t old_index = ((n * C + c) * H + h) * W + w; + // Calculate the index in the new blob + int32_t new_index = ((n * H + h) * W + w) * C + c; + // Copy the data + channels_last_data[new_index] = contiguous_data[old_index]; + } + } + } + } + + return make_with_dimorder( + sizes, + channels_last_data, + internal::channels_last_dim_order(sizes.size()), + dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous + * data will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor full( + const std::vector& sizes, + ctype value, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::full(at::IntArrayRef(sizes64), value, at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the specified shape, containing channels-last + * contiguous data will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor full_channels_last( + const std::vector& sizes, + ctype value, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::full(at::IntArrayRef(sizes64), value, at::dtype(DTYPE)) + .to(at::MemoryFormat::ChannelsLast); + } + + /** + * Returns a new Tensor with the specified shape, containing channels-last + * contiguous data with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor zeros( + const std::vector& sizes, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::zeros(at::IntArrayRef(sizes64), at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor zeros_channels_last( + const std::vector& sizes, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::zeros(at::IntArrayRef(sizes64), at::dtype(DTYPE)) + .to(at::MemoryFormat::ChannelsLast); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * with all `1` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor ones( + const std::vector& sizes, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::ones(at::IntArrayRef(sizes64), at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `0` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor zeros_like( + const at::Tensor& input, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + std::vector sizes64 = {input.sizes().begin(), input.sizes().end()}; + return at::full(at::IntArrayRef(sizes64), 0, at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `1` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor ones_like( + const at::Tensor& input, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + std::vector sizes64 = {input.sizes().begin(), input.sizes().end()}; + return at::full(at::IntArrayRef(sizes64), 1, at::dtype(DTYPE)); + } + + private: + /// Copies an int32_t vector into a new int64_t vector. + static std::vector vec_32_to_64(const std::vector& in) { + std::vector out{}; + out.reserve(in.size()); + for (auto i : in) { + out.push_back(i); + } + return out; + } + + /** + * Returns a new Tensor with the specified shape and stride. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] strides The strides for each dimensions of the Tensor + * @return A new Tensor with the specified shape and strides. + */ + at::Tensor empty_strided( + const std::vector& sizes, + const std::vector& strides, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::empty_strided( + sizes64, + strides, + DTYPE, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + } +}; + +#else // !USE_ATEN_LIB + +namespace { +/* + * Dimension order represents how dimensions are laid out in memory, + * starting from the inner-most to the outer-most dimension. + * Thus, the conversion from strides is done by sorting the strides + * from larger to smaller since the dimension with the largest stride + * is the outer-most and the dimension with the smallest stride is the + inner-most. + * For example, tensor with sizes = (3, 5, 2) and strides = (5, 1, 15), implies + * dimension order of (2, 0, 1), because 2nd dimension has the biggest stride of + 15, + * followed by 0th dimension with stride of 5 and then innermost dimension being + the 1st + * dimension with size of 1. This order of (2, 0, 1) can be obtained + * by sorting strides from large to smaller. + + * When strides do not convey dimension order unambiguously, dimension order + * returned is dependent on stability of sort. We employ stable sort to preserve + * original order. Thus when strides = (4, 3, 1, 1) returned value is (0, 1, 2, + 3) + * Another example is: sizes = (1, 3, 1, 1) with strides = (3, 1, 3, 3), + returned + * value is (0, 2, 3, 1) +*/ +// copied from +// https://stackoverflow.com/questions/1577475/c-sorting-and-keeping-track-of-indexes +// TODO: Add assert for strides[i] != 0 because strides of 0 is really used, +// by pytorch/aten, to convey broadcasting dim. + +inline std::vector dim_order_from_stride( + const std::vector& v) { + std::vector indices(v.size()); + std::iota(indices.begin(), indices.end(), 0); + stable_sort(indices.begin(), indices.end(), [&v](size_t i1, size_t i2) { + return v[i1] > v[i2]; + }); + return indices; +} + +inline void validate_strides( + const std::vector& sizes, + const std::vector& strides) { + if (sizes.size() != strides.size()) { + ET_CHECK_MSG(false, "Stride and sizes are not equal in length"); + } + for (const auto& s : strides) { + if (s == 0) { + ET_CHECK_MSG(false, "Stride value of 0 is not supported"); + } + } + // No two dimensions can have same stride value + for (const auto i : c10::irange(strides.size())) { + for (int32_t j = i + 1; j < strides.size(); ++j) { + if ((sizes[i] == 0) || (sizes[j] == 0) || + ((sizes[i] == 1) || (sizes[j] == 1))) { + continue; + } + if ((strides[i] == strides[j])) { + ET_CHECK_MSG( + false, + "Stride value and size dont comply at index %d." + " strides[%d]: %d, strides[%d] = %d, sizes[%d] = %d, sizes[%d] = %d", + static_cast(i), + static_cast(i), + strides[i], + j, + strides[j], + static_cast(i), + sizes[i], + j, + sizes[j]); + } + } + } +} + +} // namespace + +// Note that this !USE_ATEN_LIB section uses ExecuTorch-specific namespaces +// instead of exec_aten to make it clear that we're dealing with ETensor, and +// because many of these names aren't mapped into executorch::aten::. + +namespace internal { + +// This wrapper lets us override the C type associated with some ScalarType +// values while using the defaults for everything else. +template +struct ScalarTypeToCppTypeWrapper { + using ctype = + typename ::executorch::runtime::ScalarTypeToCppType::type; +}; + +// Use a C type of `uint8_t` instead of `bool`. The C type will be used to +// declare a `std::vector`, and `std::vector` is often optimized to +// store a single bit per entry instead of using an array of separate `bool` +// elements. Since the tensor data will point into the vector, it needs to use +// one byte per element. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint8_t; +}; + +// Use a C type of `uint16_t` instead of `Bits16` to simplify code reuse when +// testing multiple integer types. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint16_t; +}; + +// Use a C type of `uint16_t` instead of `UInt16` to simplify code reuse when +// testing multiple integer types. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint16_t; +}; + +// To allow implicit conversion between simple types to `ctype` +#define SPECIALIZE_ScalarTypeToCppTypeWrapper(CTYPE, DTYPE) \ + template <> \ + struct ScalarTypeToCppTypeWrapper { \ + using ctype = typename CTYPE::underlying; \ + }; + +ET_FORALL_QINT_TYPES(SPECIALIZE_ScalarTypeToCppTypeWrapper) + +#undef SPECIALIZE_ScalarTypeToCppTypeWrapper + +} // namespace internal + +/** + * A helper class for creating Tensors, simplifying memory management. + * + * NOTE: A given TensorFactory instance owns the memory pointed to by all + * Tensors that it creates, and must live longer than those Tensors. + * + * Example: + * @code{.cpp} + * // A factory instance will create Tensors of a single dtype. + * TensorFactory tf; + * + * // You can create more factories if you need tensors of multiple + * // dtypes. + * TensorFactory tf_float; + * + * // The factory will copy the vectors provided to it, letting callers provide + * // inline literals. + * Tensor t1 = tf.make( + * {2, 2}, // sizes + * {1, 2, 3, 4}); // data + * + * // There are helpers for creating Tensors with all 1 or 0 elements. + * Tensor z = tf.zeros({2, 2}); + * Tensor o = tf_float.ones({2, 2}); + * + * // Sometimes it's helpful to share parameters. + * std::vector sizes = {2, 2}; + * Tensor t3 = tf.make(sizes, {1, 2, 3, 4}); + * Tensor t4 = tf.ones(sizes); + * + * // But remember that the inputs are copied, so providing the same data vector + * // to two Tensors will not share the same underlying data. + * std::vector data = {1, 2, 3, 4}; + * Tensor t5 = tf.make(sizes, data); + * Tensor t6 = tf.make(sizes, data); + * t5.mutable_data_ptr()[0] = 99; + * EXPECT_NE(t5, t6); + * @endcode + * + * @tparam DTYPE The dtype of Tensors created by this factory, as a ScalarType + * value like `ScalarType::Int`. + */ +template +class TensorFactory { + public: + /** + * The C type that backs the associated DTYPE. E.g., `float` for + * `ScalarType::Float`. + */ + using ctype = typename internal::ScalarTypeToCppTypeWrapper::ctype; + + /** + * The official C type for the scalar type. Used when accessing elements + * of a constructed Tensor. + */ + using true_ctype = + typename executorch::runtime::ScalarTypeToCppType::type; + + TensorFactory() = default; + + /** + * Returns a new Tensor with the specified shape, data and stride. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] strides The strides for each dimensions of the Tensor. If empty + * or not specificed, the function will return a contiguous tensor based + * on data and size. If not, the strides shall follow the rules: + * - a. strides.size() == sizes.size(). + * - b. all strides are positive. + * - c. All underlying data be accessed. + * - d. All legal indexes can access an underlying data. + * - e. No two indexes access a same data. + * - f. No out of bounds data can be accessed. + * + * @return A new Tensor with the specified shape and data. + */ + torch::executor::Tensor make( + const std::vector& sizes, + const std::vector& data, + const std::vector strides = {}, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector default_strides; + // Generate strides from the tensor dimensions, assuming contiguous data if + // given strides is empty. + if (!sizes.empty() && strides.empty()) { + default_strides.resize(sizes.size(), 1); + for (size_t i = sizes.size() - 1; i > 0; --i) { + // For sizes[i] == 0, treat it as 1 to be consistent with core Pytorch + auto sizes_i = sizes[i] ? sizes[i] : 1; + default_strides[i - 1] = default_strides[i] * sizes_i; + } + } + auto& actual_strides = default_strides.empty() ? strides : default_strides; + validate_strides(sizes, actual_strides); + auto dim_order = dim_order_from_stride(actual_strides); + + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + bool legal = internal::check_strides(sizes, actual_strides); + ET_CHECK_MSG(legal, "The input strides variable is illegal."); + + memory_.emplace_back(std::make_unique( + sizes, data, dim_order, actual_strides, dynamism)); + return torch::executor::Tensor(&memory_.back()->impl_); + } + + /** + * Returns a new Tensor with the specified shape, data and dim order. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] dim_order The dim order describing how tensor memory is laid + * out. If empty or not specificed, the function will use a contiguous dim + * order of {0, 1, 2, 3, ...} + * + * @return A new Tensor with the specified shape and data. + */ + torch::executor::Tensor make_with_dimorder( + const std::vector& sizes, + const std::vector& data, + const std::vector dim_order = {}, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector default_dim_order; + // Generate strides from the tensor dimensions, assuming contiguous data if + // given strides is empty. + if (!sizes.empty() && dim_order.empty()) { + default_dim_order.resize(sizes.size(), 1); + for (const auto i : c10::irange(sizes.size())) { + default_dim_order[i] = i; + } + } + auto& actual_dim_order = + default_dim_order.empty() ? dim_order : default_dim_order; + + auto strides = internal::strides_from_dim_order(sizes, actual_dim_order); + + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + memory_.emplace_back(std::make_unique( + sizes, data, actual_dim_order, strides, dynamism)); + return torch::executor::Tensor(&memory_.back()->impl_); + } + + /** + * Returns a new Tensor with the specified shape and data in channels last + * memory format. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * + * @return A new Tensor with the specified shape and data. + */ + torch::executor::Tensor make_channels_last( + const std::vector& sizes, + const std::vector& data, + const std::vector dim_order = {}, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return make_with_dimorder( + sizes, data, internal::channels_last_dim_order(sizes.size()), dynamism); + } + + /** + * Given data in contiguous memory format, returns a new Tensor with the + * specified shape and the same data but in channels last memory format. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data in contiguous memory format that the Tensor should + * be initialized with. The size of this vector must be equal to the product + * of the elements of `sizes`. + * + * @return A new Tensor with the specified shape and data in channls last + * memory format. + */ + torch::executor::Tensor channels_last_like( + const torch::executor::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + const std::vector sizes( + input.sizes().begin(), input.sizes().end()); + + ET_CHECK_MSG(sizes.size() == 4, "Only 4D tensors can be channels last"); + ET_CHECK_MSG( + is_contiguous_dim_order(input.dim_order().data(), input.dim()) == true, + "Input tensor is not contiguous"); + int32_t N = sizes[0]; + int32_t C = sizes[1]; + int32_t H = sizes[2]; + int32_t W = sizes[3]; + + std::vector contiguous_data( + input.data_ptr(), input.data_ptr() + input.numel()); + std::vector channels_last_data( + N * C * H * W); // Create a new blob with the same total size to contain + // channels_last data + for (const auto n : c10::irange(N)) { + for (const auto c : c10::irange(C)) { + for (const auto h : c10::irange(H)) { + for (const auto w : c10::irange(W)) { + // Calculate the index in the original blob + int32_t old_index = ((n * C + c) * H + h) * W + w; + // Calculate the index in the new blob + int32_t new_index = ((n * H + h) * W + w) * C + c; + // Copy the data + channels_last_data[new_index] = contiguous_data[old_index]; + } + } + } + } + + return make_with_dimorder( + sizes, + channels_last_data, + internal::channels_last_dim_order(sizes.size()), + dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor full( + const std::vector& sizes, + ctype value, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector data(internal::sizes_to_numel(sizes), value); + return make(sizes, data, /* empty strides */ {}, dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing channels last + * contiguous data will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor full_channels_last( + const std::vector& sizes, + ctype value, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector data(internal::sizes_to_numel(sizes), value); + return make_with_dimorder( + sizes, data, internal::channels_last_dim_order(sizes.size()), dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * in channels last memory format with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor zeros_channels_last( + const std::vector& sizes, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return full_channels_last(sizes, 0, dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * in contiguous memory format with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor zeros( + const std::vector& sizes, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return full(sizes, 0, dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * with all `1` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor ones( + const std::vector& sizes, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return full(sizes, 1, dynamism); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `0` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor zeros_like( + const torch::executor::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector sizes = {input.sizes().begin(), input.sizes().end()}; + return full(sizes, 0, dynamism); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `1` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor ones_like( + const torch::executor::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector sizes = {input.sizes().begin(), input.sizes().end()}; + return full(sizes, 1, dynamism); + } + + private: + /** + * Owns all backing memory for a single Tensor. + */ + struct TensorMemory { + TensorMemory( + const std::vector& sizes, + const std::vector& data, + const std::vector& dim_order, + const std::vector& strides, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) + : sizes_(sizes), + data_(data), + dim_order_(dim_order), + strides_(strides), + impl_( + DTYPE, + /*dim=*/sizes_.size(), + sizes_.data(), + data_.data(), + dim_order_.data(), + strides_.data(), + dynamism) { + // The only valid values for bool are 0 and 1; coerce! + if constexpr (std::is_same_v) { + for (auto& x : data_) { + x = static_cast(x); + } + } + } + + std::vector sizes_; + std::vector data_; + std::vector dim_order_; + std::vector strides_; + torch::executor::TensorImpl impl_; + }; + + /** + * The memory pointed to by Tensors created by this factory. This is a vector + * of pointers so that the TensorMemory objects won't move if the vector needs + * to resize/realloc. + */ + std::vector> memory_; +}; + +#endif // !USE_ATEN_LIB + +/** + * A helper class for creating TensorLists, simplifying memory management. + * + * NOTE: A given TensorListFactory owns the memory pointed to by all TensorLists + * (and Tensors they contain), and must live longer than those TensorLists and + * Tensors. + */ +template +class TensorListFactory final { + public: + TensorListFactory() = default; + ~TensorListFactory() = default; + + /** + * Returns a TensorList containing Tensors with the same shapes as the + * provided Tensors, but filled with zero elements. The dtypes of the template + * entries are ignored. + */ + executorch::aten::TensorList zeros_like( + const std::vector& templates) { + memory_.emplace_back( + std::make_unique>()); + auto& vec = memory_.back(); + std::for_each( + templates.begin(), + templates.end(), + [&](const executorch::aten::Tensor& t) { + vec->push_back(tf_.zeros_like(t)); + }); + return executorch::aten::TensorList(vec->data(), vec->size()); + } + + private: + TensorFactory tf_; + /** + * The memory pointed to by TensorLists created by this factory. This is a + * vector of pointers so that the elements won't move if the vector needs to + * resize/realloc. + */ + std::vector>> memory_; +}; + +} // namespace testing +} // namespace runtime +} // namespace executorch + +namespace torch { +namespace executor { +namespace testing { +// TODO(T197294990): Remove these deprecated aliases once all users have moved +// to the new `::executorch` namespaces. +using ::executorch::runtime::testing::TensorFactory; +using ::executorch::runtime::testing::TensorListFactory; +} // namespace testing +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.cpp new file mode 100644 index 0000000..218a64c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using executorch::aten::BFloat16; +using executorch::aten::Half; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; + +namespace executorch { +namespace runtime { +namespace testing { + +namespace { + +/** + * Returns true if the two elements are close according to the description on + * `tensors_are_close()`. + * + * T must be a floating point type. Non-floating point data should be compared + * directly. + */ +template +bool element_is_close(const T a, const T b, double rtol, double atol) { + if constexpr (c10::is_reduced_floating_point_v) { + // MSVC complains about ambiguous overloads, so explicitly cast to float to + // compare. + return element_is_close( + static_cast(a), static_cast(b), rtol, atol); + } else { + if (std::isnan(a) && std::isnan(b)) { + // NaN == NaN + } else if (!std::isfinite(a) && !std::isfinite(b) && ((a > 0) == (b > 0))) { + // -Inf == -Inf + // +Inf == +Inf + } else if (rtol == 0 && atol == 0) { + // Exact comparison; avoid unnecessary math. + if (a != b) { + return false; + } + } else { + auto allowed_error = atol + std::abs(rtol * b); + auto actual_error = std::abs(a - b); + if (!std::isfinite(actual_error) || actual_error > allowed_error) { + return false; + } + } + + return true; + } +} + +/** + * Returns true if the two arrays are close according to the description on + * `tensors_are_close()`. + * + * T must be a floating point type. Non-floating point data should be compared + * directly. + */ +template +bool data_is_close( + const T* a, + const T* b, + size_t numel, + double rtol, + double atol) { + ET_CHECK_MSG( + numel == 0 || (a != nullptr && b != nullptr), + "Pointers must not be null when numel > 0: numel %zu, a 0x%p, b 0x%p", + numel, + a, + b); + if (a == b) { + return true; + } + for (const auto i : c10::irange(numel)) { + const auto ai = a[i]; + const auto bi = b[i]; + + if (!element_is_close(ai, bi, rtol, atol)) { + return false; + } + } + return true; +} + +double default_atol_for_type(ScalarType t) { + if (t == ScalarType::Half) { + return internal::kDefaultHalfAtol; + } + if (t == ScalarType::BFloat16) { + return internal::kDefaultBFloat16Atol; + } + return internal::kDefaultAtol; +} +} // namespace + +bool tensors_are_close( + const Tensor& a, + const Tensor& b, + double rtol, + std::optional opt_atol) { + if (a.scalar_type() != b.scalar_type() || a.sizes() != b.sizes()) { + return false; + } + + // TODO(T132992348): support comparison between tensors of different strides + ET_CHECK_MSG( + a.strides() == b.strides(), + "The two inputs of `tensors_are_close` function shall have same strides"); + + // Since the two tensors have same shape and strides, any two elements that + // share same index from underlying data perspective will also share same + // index from tensor perspective, whatever the size and strides really are. + // e.g. if a[i_1, i_2, ... i_n] = a.const_data_ptr()[m], we can assert + // b[i_1, i_2, ... i_n] = b.const_data_ptr()[m]) + // So we can just compare the two underlying data sequentially to figure out + // if the two tensors are same. + + double atol = opt_atol.value_or(default_atol_for_type(a.scalar_type())); + + if (a.nbytes() == 0) { + // Note that this case is important. It's valid for a zero-size tensor to + // have a null data pointer, but in some environments it's invalid to pass a + // null pointer to memcmp() even when the size is zero. + return true; + } else if (a.scalar_type() == ScalarType::Float) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::Double) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::Half) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::BFloat16) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else { + // Non-floating-point types can be compared bitwise. + return memcmp(a.const_data_ptr(), b.const_data_ptr(), a.nbytes()) == 0; + } +} + +/** + * Asserts that the provided tensors have the same sequence of close + * underlying data elements and same numel. Note that this function is mainly + * about comparing underlying data between two tensors, not relevant with how + * tensor interpret the underlying data. + */ +bool tensor_data_is_close( + const Tensor& a, + const Tensor& b, + double rtol, + std::optional opt_atol) { + if (a.scalar_type() != b.scalar_type() || a.numel() != b.numel()) { + return false; + } + + double atol = opt_atol.value_or(default_atol_for_type(a.scalar_type())); + if (a.nbytes() == 0) { + // Note that this case is important. It's valid for a zero-size tensor to + // have a null data pointer, but in some environments it's invalid to pass a + // null pointer to memcmp() even when the size is zero. + return true; + } else if (a.scalar_type() == ScalarType::Float) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::Double) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else { + // Non-floating-point types can be compared bitwise. + return memcmp(a.const_data_ptr(), b.const_data_ptr(), a.nbytes()) == 0; + } +} + +bool tensor_lists_are_close( + const executorch::aten::Tensor* tensors_a, + size_t num_tensors_a, + const executorch::aten::Tensor* tensors_b, + size_t num_tensors_b, + double rtol, + std::optional opt_atol) { + if (num_tensors_a != num_tensors_b) { + return false; + } + for (const auto i : c10::irange(num_tensors_a)) { + if (!tensors_are_close(tensors_a[i], tensors_b[i], rtol, opt_atol)) { + return false; + } + } + return true; +} + +} // namespace testing +} // namespace runtime +} // namespace executorch + +// ATen already defines operator<<() for Tensor and ScalarType. +#ifndef USE_ATEN_LIB + +/* + * These functions must be declared in the original namespaces of their + * associated types so that C++ can find them. + */ +namespace executorch { +namespace runtime { +namespace etensor { + +/** + * Prints the ScalarType to the stream as a human-readable string. + */ +std::ostream& operator<<(std::ostream& os, const ScalarType& t) { + const char* s = torch::executor::toString(t); + if (std::strcmp(s, "UNKNOWN_SCALAR") == 0) { + return os << "Unknown(" << static_cast(t) << ")"; + } else { + return os << s; + } +} + +namespace { + +/** + * Prints the elements of `data` to the stream as comma-separated strings. + */ +template +std::ostream& print_data(std::ostream& os, const T* data, size_t numel) { + // TODO(dbort): Make this smarter: show dimensions, listen to strides, + // break up or truncate data when it's huge + for (const auto i : c10::irange(numel)) { + os << data[i]; + if (i < numel - 1) { + os << ", "; + } + } + return os; +} + +template +std::ostream& +print_data(std::ostream& os, const etensor::complex* data, size_t numel) { + for (const auto i : c10::irange(numel)) { + os << data[i].real_ << " + " << data[i].imag_ << "j"; + if (i < numel - 1) { + os << ", "; + } + } + return os; +} +/** + * Prints the elements of `data` to the stream as comma-separated strings. + * + * Specialization for byte tensors as c++ default prints them as chars where as + * debugging is typically easier with numbers here (tensors dont store string + * data) + */ +template <> +std::ostream& print_data(std::ostream& os, const uint8_t* data, size_t numel) { + // TODO(dbort): Make this smarter: show dimensions, listen to strides, + // break up or truncate data when it's huge + for (const auto i : c10::irange(numel)) { + os << (uint64_t)data[i]; + if (i < numel - 1) { + os << ", "; + } + } + return os; +} + +} // namespace + +/** + * Prints the Tensor to the stream as a human-readable string. + */ +std::ostream& operator<<(std::ostream& os, const Tensor& t) { + os << "ETensor(sizes={"; + for (const auto dim : c10::irange(t.dim())) { + os << t.size(dim); + if (dim < t.dim() - 1) { + os << ", "; + } + } + os << "}, dtype=" << t.scalar_type() << ", data={"; + + // Map from the ScalarType to the C type. +#define PRINT_CASE(ctype, stype) \ + case ScalarType::stype: \ + print_data(os, t.const_data_ptr(), t.numel()); \ + break; + + switch (t.scalar_type()) { + ET_FORALL_REAL_TYPES_AND3(Half, Bool, BFloat16, PRINT_CASE) + ET_FORALL_COMPLEX_TYPES(PRINT_CASE) + default: + ET_CHECK_MSG( + false, + "Unhandled dtype %s", + torch::executor::toString(t.scalar_type())); + } + +#undef PRINT_CASE + + os << "})"; + + return os; +} + +} // namespace etensor +} // namespace runtime +} // namespace executorch + +#endif // !USE_ATEN_LIB diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.h new file mode 100644 index 0000000..4284176 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/tensor_util.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include // For MATCHER_P + +#include + +namespace executorch { +namespace runtime { +namespace testing { + +namespace internal { +constexpr double kDefaultRtol = 1e-5; +constexpr double kDefaultAtol = 1e-8; +// Per +// https://en.wikipedia.org/wiki/Half-precision_floating-point_format, +// float16 has about 3.3 digits of precision. +constexpr double kDefaultHalfAtol = 1e-3; + +// Following similar reasoning to float16, BFloat16 has +// math.log10(2**8) = 2.4 digits of precision. +constexpr double kDefaultBFloat16Atol = 1e-2; +} // namespace internal + +/** + * Returns true if the tensors are of the same shape and dtype, and if all + * elements are close to each other. + * + * TODO(T132992348): This function will currently fail an ET_CHECK if the + * strides of the tensors are not identical. Add support for comparing + * tensors with different strides. + * + * Note that gtest users can write `EXPECT_THAT(tensor1, IsCloseTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsCloseTo(tensor2)))`, or use the helper macros + * `EXPECT_TENSOR_CLOSE()` and `EXPECT_TENSOR_NOT_CLOSE()`. + * + * For exact equality, use `EXPECT_THAT(tensor1, IsEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsEqualTo(tensor2)))`, or the helper macros + * `EXPECT_TENSOR_EQ()` and `EXPECT_TENSOR_NE()`. + * + * An element A is close to B when one is true: + * + * (1) A is equal to B. + * (2) A and B are both NaN, are both -infinity, or are both +infinity. + * (3) The error abs(A - B) is finite and less than the max error + * (atol + abs(rtol * B)). + * + * If both rtol/atol are zero, this function checks for exact equality. + * + * NOTE: rtol/atol are ignored and treated as zero for non-floating-point + * dtypes. + * + * @param[in] a The first tensor to compare. + * @param[in] b The second tensor to compare. + * @param[in] rtol Relative tolerance; see note above. + * @param[in] atol Absolute tolerance; see note above. + * @retval true All corresponding elements of the two tensors are within the + * specified tolerance of each other. + * @retval false One or more corresponding elements of the two tensors are + * outside of the specified tolerance of each other. + */ +bool tensors_are_close( + const executorch::aten::Tensor& a, + const executorch::aten::Tensor& b, + double rtol = internal::kDefaultRtol, + std::optional opt_atol = std::nullopt); + +/** + * Returns true if the tensors are of the same numel and dtype, and if all + * elements are close to each other. The tensor shapes do not need to be same. + * + * Note that gtest users can write `EXPECT_THAT(tensor1, + * IsDataCloseTo(tensor2))` or `EXPECT_THAT(tensor1, + * Not(IsDataCloseTo(tensor2)))`, or use the helper macros + * `EXPECT_TENSOR_DATA_CLOSE()` and `EXPECT_TENSOR_DATA_NOT_CLOSE()`. + * + * For exact equality, use `EXPECT_THAT(tensor1, IsDataEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsDataEqualTo(tensor2)))`, or the helper macros + * `EXPECT_TENSOR_DATA_EQ()` and `EXPECT_TENSOR_DATA_NE()`. + * + * The defination of an element A is close to B is in the comment of the + * function `tensors_are_close` + * + * @param[in] a The first tensor to compare. + * @param[in] b The second tensor to compare. + * @param[in] rtol Relative tolerance; see note above. + * @param[in] atol Absolute tolerance; see note above. + * @retval true All corresponding elements of the two tensors are within the + * specified tolerance of each other. + * @retval false One or more corresponding elements of the two tensors are + * outside of the specified tolerance of each other. + */ +bool tensor_data_is_close( + const executorch::aten::Tensor& a, + const executorch::aten::Tensor& b, + double rtol = internal::kDefaultRtol, + std::optional opt_atol = std::nullopt); + +/** + * Returns true if the two lists are of the same length, and + * tensor_data_is_close(tensors_a[i], tensors_b[i], rtol, atol) is true for all + * i. + */ +bool tensor_lists_are_close( + const executorch::aten::Tensor* tensors_a, + size_t num_tensors_a, + const executorch::aten::Tensor* tensors_b, + size_t num_tensors_b, + double rtol = internal::kDefaultRtol, + std::optional opt_atol = std::nullopt); + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsCloseTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsCloseTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_CLOSE()` and `EXPECT_TENSOR_NOT_CLOSE()`. + */ +MATCHER_P(IsCloseTo, other, "") { + return tensors_are_close(arg, other); +} + +/** + * Lets gtest users write + * `EXPECT_THAT(tensor1, IsCloseToWithTol(tensor2, rtol, atol))` + * or `EXPECT_THAT(tensor1, Not(IsCloseToWithTol(tensor2, rtol, atol)))`. + * + * See also `EXPECT_TENSOR_CLOSE_WITH_TOL()` and + * `EXPECT_TENSOR_NOT_CLOSE_WITH_TOL()`. + */ +MATCHER_P3(IsCloseToWithTol, other, rtol, atol, "") { + return tensors_are_close(arg, other, rtol, atol); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsEqualTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_EQ()` and `EXPECT_TENSOR_NE()`. + */ +MATCHER_P(IsEqualTo, other, "") { + return tensors_are_close(arg, other, /*rtol=*/0, /*atol=*/0); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsDataCloseTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsDataCloseTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_DATA_CLOSE()` and `EXPECT_TENSOR_DATA_NOT_CLOSE()`. + */ +MATCHER_P(IsDataCloseTo, other, "") { + return tensor_data_is_close(arg, other); +} + +/** + * Lets gtest users write + * `EXPECT_THAT(tensor1, IsDataCloseToWithTol(tensor2, rtol, atol))` + * or `EXPECT_THAT(tensor1, Not(IsDataCloseToWithTol(tensor2, rtol, atol)))`. + * + * See also `EXPECT_TENSOR_CLOSE_WITH_TOL()` and + * `EXPECT_TENSOR_NOT_CLOSE_WITH_TOL()`. + */ +MATCHER_P3(IsDataCloseToWithTol, other, rtol, atol, "") { + return tensor_data_is_close(arg, other, rtol, atol); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsDataEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsDataEqualTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_DATA_EQ()` and `EXPECT_TENSOR_DATA_NE()`. + */ +MATCHER_P(IsDataEqualTo, other, "") { + return tensor_data_is_close(arg, other, /*rtol=*/0, /*atol=*/0); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor_list1, + * IsListCloseTo(tensor_list2))` or `EXPECT_THAT(tensor_list1, + * Not(IsListCloseTo(tensor_list2)))`. + * + * The lists can be any container of Tensor that supports ::data() and ::size(). + * + * See also `EXPECT_TENSOR_LISTS_CLOSE()` and `EXPECT_TENSOR_LISTS_NOT_CLOSE()`. + */ +MATCHER_P(IsListCloseTo, other, "") { + return tensor_lists_are_close( + arg.data(), arg.size(), other.data(), other.size()); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor_list1, + * IsListEqualTo(tensor_list2))` or `EXPECT_THAT(tensor_list1, + * Not(IsListEqualTo(tensor_list2)))`. + * + * The lists can be any container of Tensor that supports ::data() and ::size(). + * + * See also `EXPECT_TENSOR_LISTS_EQ()` and `EXPECT_TENSOR_LISTS_NE()`. + */ +MATCHER_P(IsListEqualTo, other, "") { + return tensor_lists_are_close( + arg.data(), + arg.size(), + other.data(), + other.size(), + /*rtol=*/0, + /*atol=*/0); +} + +/* + * NOTE: Although it would be nice to make `EXPECT_EQ(t1, t2)` and friends work, + * that would require implementing `bool operator==(Tensor, Tensor)`. + * + * at::Tensor implements `Tensor operator==(Tensor, Tensor)`, returning an + * element-by-element comparison. This causes an ambiguous conflict with the + * `bool`-returning operator. + */ +#define EXPECT_TENSOR_EQ(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsEqualTo(t2)) +#define EXPECT_TENSOR_NE(t1, t2) \ + EXPECT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsEqualTo(t2))) +#define ASSERT_TENSOR_EQ(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsEqualTo(t2)) +#define ASSERT_TENSOR_NE(t1, t2) \ + ASSERT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsEqualTo(t2))) + +#define EXPECT_TENSOR_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsCloseTo(t2)) +#define EXPECT_TENSOR_NOT_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsCloseTo(t2))) +#define ASSERT_TENSOR_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsCloseTo(t2)) +#define ASSERT_TENSOR_NOT_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsCloseTo(t2))) + +#define EXPECT_TENSOR_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), ::executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol)) +#define EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol))) +#define ASSERT_TENSOR_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), ::executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol)) +#define ASSERT_TENSOR_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol))) + +#define EXPECT_TENSOR_DATA_EQ(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsDataEqualTo(t2)) +#define EXPECT_TENSOR_DATA_NE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataEqualTo(t2))) +#define ASSERT_TENSOR_DATA_EQ(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsDataEqualTo(t2)) +#define ASSERT_TENSOR_DATA_NE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataEqualTo(t2))) + +#define EXPECT_TENSOR_DATA_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsDataCloseTo(t2)) +#define EXPECT_TENSOR_DATA_NOT_CLOSE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataCloseTo(t2))) +#define ASSERT_TENSOR_DATA_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsDataCloseTo(t2)) +#define ASSERT_TENSOR_DATA_NOT_CLOSE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataCloseTo(t2))) + +#define EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), \ + ::executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol)) +#define EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol))) +#define ASSERT_TENSOR_DATA_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), \ + ::executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol)) +#define ASSERT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol))) + +/* + * Helpers for comparing lists of Tensors. + */ + +#define EXPECT_TENSOR_LISTS_EQ(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsListEqualTo(t2)) +#define EXPECT_TENSOR_LISTS_NE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListEqualTo(t2))) +#define ASSERT_TENSOR_LISTS_EQ(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsListEqualTo(t2)) +#define ASSERT_TENSOR_LISTS_NE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListEqualTo(t2))) + +#define EXPECT_TENSOR_LISTS_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsListCloseTo(t2)) +#define EXPECT_TENSOR_LISTS_NOT_CLOSE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListCloseTo(t2))) +#define ASSERT_TENSOR_LISTS_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsListCloseTo(t2)) +#define ASSERT_TENSOR_LISTS_NOT_CLOSE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListCloseTo(t2))) + +} // namespace testing +} // namespace runtime +} // namespace executorch + +// ATen already defines operator<<() for Tensor and ScalarType. +#ifndef USE_ATEN_LIB + +/* + * These functions must be declared in the original namespaces of their + * associated types so that C++ can find them. + */ +namespace executorch { +namespace runtime { +namespace etensor { + +/** + * Prints the ScalarType to the stream as a human-readable string. + * + * See also executorch::runtime::toString(ScalarType t) in ScalarTypeUtil.h. + */ +std::ostream& operator<<(std::ostream& os, const ScalarType& t); + +/** + * Prints the Tensor to the stream as a human-readable string. + */ +std::ostream& operator<<(std::ostream& os, const Tensor& t); + +} // namespace etensor +} // namespace runtime +} // namespace executorch + +#endif // !USE_ATEN_LIB + +namespace torch { +namespace executor { +namespace testing { +// TODO(T197294990): Remove these deprecated aliases once all users have moved +// to the new `::executorch` namespaces. +using ::executorch::runtime::testing::IsCloseTo; +using ::executorch::runtime::testing::IsCloseToWithTol; +using ::executorch::runtime::testing::IsDataCloseTo; +using ::executorch::runtime::testing::IsDataCloseToWithTol; +using ::executorch::runtime::testing::IsDataEqualTo; +using ::executorch::runtime::testing::IsEqualTo; +using ::executorch::runtime::testing::IsListCloseTo; +using ::executorch::runtime::testing::IsListEqualTo; +using ::executorch::runtime::testing::tensor_data_is_close; +using ::executorch::runtime::testing::tensor_lists_are_close; +using ::executorch::runtime::testing::tensors_are_close; +} // namespace testing +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/CMakeLists.txt new file mode 100644 index 0000000..a51717f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs tensor_util_test.cpp tensor_factory_test.cpp) + +et_cxx_test( + runtime_core_exec_aten_testing_util_test SOURCES ${_test_srcs} EXTRA_LIBS +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/targets.bzl new file mode 100644 index 0000000..4479699 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/targets.bzl @@ -0,0 +1,30 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "tensor_util_test", + srcs = ["tensor_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [] + + runtime.cxx_test( + name = "tensor_factory_test" + aten_suffix, + srcs = ["tensor_factory_test.cpp"], + preprocessor_flags = preprocessor_flags, + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util" + aten_suffix, + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp new file mode 100644 index 0000000..ab201a0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp @@ -0,0 +1,1229 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef USE_ATEN_LIB +#include +#endif // USE_ATEN_LIB + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::StridesType; +using executorch::aten::Tensor; +using executorch::aten::TensorList; +using executorch::ET_RUNTIME_NAMESPACE::resize_tensor; +using executorch::runtime::Error; +using executorch::runtime::TensorShapeDynamism; +using executorch::runtime::testing::TensorFactory; +using executorch::runtime::testing::TensorListFactory; + +// The tensor under test will be modified so pass an rvalue ref +void resize_tensor_to_assert_static(Tensor&& t) { + ASSERT_GT(t.numel(), 1) + << "Need to resize to an 1x1 tensor, so the input size should be > 1"; + // Resizing to an 1x1 tensor doesn't work means it is static +#ifdef USE_ATEN_LIB + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); +#else + EXPECT_NE(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); +#endif +} + +// The tensor under test will be modified so pass an rvalue ref +void resize_tensor_to_assert_dynamic_bound(Tensor&& t) { + ASSERT_GT(t.numel(), 1) + << "Need to resize to an 1x1 tensor, so the input size should be > 1"; + ASSERT_LT(t.numel(), 100 * 100) + << "Need to resize to an 100x100 tensor, so the input size should be < 10000"; +#ifdef USE_ATEN_LIB + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); + EXPECT_EQ(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#else + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); + EXPECT_NE(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#endif +} + +// The tensor under test will be modified so pass an rvalue ref +void resize_tensor_to_assert_dynamic_unbound(Tensor&& t) { + ASSERT_GT(t.numel(), 1) + << "Need to resize to an 1x1 tensor, so the input size should be > 1"; + ASSERT_LT(t.numel(), 100 * 100) + << "Need to resize to an 100x100 tensor, so the input size should be < 10000"; + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); + +#ifdef USE_ATEN_LIB + EXPECT_EQ(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#else + // TODO(T175194371): For now, we can't resize past the original capacity. + EXPECT_NE(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#endif +} + +#ifndef USE_ATEN_LIB +using executorch::aten::DimOrderType; +using torch::executor::TensorImpl; +#endif // !USE_ATEN_LIB + +#define CHECK_ARRAY_REF_EQUAL(a1, a2) \ + ET_CHECK_MSG( \ + a1.size() == a2.size(), \ + "Arrays are not equal size." #a1 " size:%zu," #a2 " size:%zu", \ + a1.size(), \ + a2.size()); \ + for (const auto i : c10::irange(a1.size())) { \ + ET_CHECK_MSG( \ + a1[i] == a2[i], \ + "Value mismatch at index %zu, " #a1 \ + "[%zu] = %hd" \ + ", " #a2 "[%zu] = %hd", \ + i, \ + i, \ + a1[i], \ + i, \ + a2[i]); \ + } + +// +// Tests for TensorFactory +// + +class TensorFactoryTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorFactoryTest, MakeIntTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {1, 2, 3, 4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test Float as a proxy for non-Int dtypes. Don't test as thoroughly as Int, +// which we use for the bulk of the test coverage. +TEST_F(TensorFactoryTest, MakeFloatTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 3.3, 4.4}); + + // A Tensor created manually, that should be identical to `actual`. + float data[] = {1.1, 2.2, 3.3, 4.4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Float)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Float, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Also test Bool, which is a bit of a special case because the factory uses +// `uint8_t` instead of `bool` as the underlying C type. +TEST_F(TensorFactoryTest, MakeBoolTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = + tf.make(/*sizes=*/{2, 2}, /*data=*/{true, false, true, false}); + + // A Tensor created manually, that should be identical to `actual`. + bool data[] = {true, false, true, false}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Bool)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Bool, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, DataIsCopied) { + TensorFactory tf; + + // Create two tensors using the same input data vector. + std::vector data = {1, 2, 3, 4}; + Tensor t1 = tf.make(/*sizes=*/{2, 2}, data); + Tensor t2 = tf.make(/*sizes=*/{2, 2}, data); + + // Demonstrate that they start out identical. + EXPECT_TENSOR_EQ(t1, t2); + + // Modify data in one of them. + t1.mutable_data_ptr()[0] = 99; + + // If they shared the same underlying data, they would still be identical, + // but since they use copies they should now be different. + EXPECT_TENSOR_NE(t1, t2); +} + +TEST_F(TensorFactoryTest, DefaultStridesAreContiguous) { + TensorFactory tf; + + // Create a Tensor with prime number dimensions to more clearly show how the + // strides will be constructed. 30 is 2 * 3 * 5. + Tensor t1 = + tf.make(/*sizes=*/{2, 3, 5}, /*data=*/std::vector(30, 99)); + + // Get the strides into a vector for easy comparison. + std::vector actual_strides(t1.strides().begin(), t1.strides().end()); + + // TensorFactory should have generated a strides list for contiguous data. + // sizes: {D, H, W} + // strides: {H*W, W, 1} + // expected: {3*5, 5, 1} + std::vector expected_strides = {15, 5, 1}; + + EXPECT_EQ(expected_strides, actual_strides); +} + +TEST_F(TensorFactoryTest, StridesForEmptyTensor) { + TensorFactory tf; + + // Create a Tensor with some dim = 0 to clearly demonstrate how the tf.make + // handle empty tensors. + Tensor t1 = + tf.make(/*sizes=*/{2, 0, 3, 0, 5}, /*data=*/std::vector()); + + // Get the strides into a vector for easy comparison. + std::vector actual_strides(t1.strides().begin(), t1.strides().end()); + + // When calculating stride for empty data, TensorFactory should take dim whose + // length equals to zero as equals to one. So the t1's stride should be same + // as tensor(size=(2, 1, 3, 1, 5)) + // expected: {5*1*3*1, 5*1*3, 5*1, 5, 1} -> {15, 15, 5, 5, 1} + std::vector expected_strides = {15, 15, 5, 5, 1}; + + EXPECT_EQ(expected_strides, actual_strides); +} + +TEST_F(TensorFactoryTest, StridesForZeroDimTensor) { + TensorFactory tf; + + // Create a Tensor with zero dimension to clearly demonstrate how the tf.make + // handle zero dim tensors. + Tensor t1 = tf.make( + /*sizes=*/{}, + /*data=*/{1}); + + // Get the strides into a vector for easy comparison. + std::vector actual_strides(t1.strides().begin(), t1.strides().end()); + + // Zero dimension tensor should have zero dimension stride + // expected: {} + std::vector expected_strides = {}; + + EXPECT_EQ(expected_strides, actual_strides); +} + +TEST_F(TensorFactoryTest, NotEnoughDataDies) { + TensorFactory tf; + + // Provide three data elements when the tensor needs four. + ET_EXPECT_DEATH(tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3}), ""); +} + +TEST_F(TensorFactoryTest, TooMuchDataDies) { + TensorFactory tf; + + // Provide five data elements when the tensor needs four. + ET_EXPECT_DEATH(tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4, 5}), ""); +} + +// +// Tests for TensorFactory::make() +// + +// Test if factory can produce strided incontiguous int tensors. +TEST_F(TensorFactoryTest, MakeStridedIntTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{1, 2, 3, 4}, + /*strides=*/{1, 2} /*incontiguous tensor*/); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {1, 2, 3, 4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + std::vector strides = {1, 2}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Int, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {1, 0}; + int32_t strides[dim] = {1, 2}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test if factory can produce strided incontiguous float tensors. +TEST_F(TensorFactoryTest, MakeStridedFloatTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{1.1, 2.2, 3.3, 4.4}, + /*strides=*/{1, 2} /*incontiguous tensor*/); + + // A Tensor created manually, that should be identical to `actual`. + float data[] = {1.1, 2.2, 3.3, 4.4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + std::vector strides = {1, 2}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Float, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {1, 0}; + int32_t strides[dim] = {1, 2}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Float, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test if factory can produce incontiguous strided bool tensors. +TEST_F(TensorFactoryTest, MakeStridedBoolTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{true, false, true, false}, + /*strides=*/{1, 2} /*incontiguous tensor*/); + + // A Tensor created manually, that should be identical to `actual`. + bool data[] = {true, false, true, false}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + std::vector strides = {1, 2}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Bool, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {1, 0}; + int32_t strides[dim] = {1, 2}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Bool, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test if factory can test the legitimacy of given `strides`, when `strides` +// contains multiple zeros and ones. +TEST_F(TensorFactoryTest, MakeStridedSameStrideTensorSupported) { + TensorFactory tf; + + // A Tensor created by the factory. + // actual = tensor(size=(2, 0 ,3, 0, 0, 0, 1, 5, 0, 1, 2)).permute(0, 6, 8, 2, + // 7, 10, 9, 3, 5, 4, 1) + Tensor actual = tf.make( + /*sizes=*/{2, 1, 0, 3, 5, 2, 1, 0, 0, 0, 0}, + /*data=*/{}, + /*strides=*/ + {30, 10, 2, 10, 2, 1, 2, 10, 10, 10, 30} /*incontiguous tensor*/); + +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 1, 0, 3, 5, 2, 1, 0, 0, 0, 0}; + std::vector strides = {30, 10, 2, 10, 2, 1, 2, 10, 10, 10, 30}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Bool, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); +#else // !USE_ATEN_LIB + constexpr size_t dim = 11; + int32_t sizes[dim] = {2, 1, 0, 3, 5, 2, 1, 0, 0, 0, 0}; + uint8_t dim_order[dim] = {0, 10, 1, 3, 7, 8, 9, 2, 4, 6, 5}; + int32_t strides[dim] = { + 30, 10, 2, 10, 2, 1, 2, 10, 10, 10, 30}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Bool, dim, sizes, {}, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, MakeStridedDataIsCopied) { + TensorFactory tf; + + // Create two tensors using the same input data and strided vector. + std::vector data = {1, 2, 3, 4}; + std::vector strides = {1, 2}; + Tensor t1 = tf.make(/*sizes=*/{2, 2}, data, strides); + Tensor t2 = tf.make(/*sizes=*/{2, 2}, data, strides); + + // Demonstrate that they start out identical. + EXPECT_TENSOR_EQ(t1, t2); + + // Modify data in one of them. + t1.mutable_data_ptr()[0] = 99; + + // If they shared the same underlying data, they would still be identical, + // but since they use copies they should now be different. + EXPECT_TENSOR_NE(t1, t2); +} + +TEST_F(TensorFactoryTest, MakeStridedEmptyDataSupported) { + TensorFactory tf; + + Tensor actual = tf.make( + /*sizes=*/{2, 0, 3, 0, 5}, /*data=*/{}, /*strides=*/{15, 15, 5, 5, 1}); +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 0, 3, 0, 5}; + std::vector strides = {15, 15, 5, 5, 1}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Int, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); +#else // !USE_ATEN_LIB + constexpr size_t dim = 5; + int32_t sizes[dim] = {2, 0, 3, 0, 5}; + uint8_t dim_order[dim] = {0, 1, 2, 3, 4}; + int32_t strides[dim] = {15, 15, 5, 5, 1}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, /*data=*/{}, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, MakeStridedZeroDimSupported) { + TensorFactory tf; + + // Provide three data elements when the tensor needs four. + Tensor actual = tf.make(/*sizes=*/{}, /*data=*/{1}, /*strides=*/{}); + int32_t data[] = {1}; + +#ifdef USE_ATEN_LIB + std::vector sizes = {}; + std::vector strides = {}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Int, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 0; + int32_t sizes[dim] = {}; + uint8_t dim_order[dim] = {}; + int32_t strides[dim] = {}; + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, MakeStridedNotEnoughDataDie) { + TensorFactory tf; + + // Provide three data elements when the tensor needs four. + ET_EXPECT_DEATH( + tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3}, /*strides=*/{1, 2}), ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooMuchDataDie) { + TensorFactory tf; + + // Provide five data elements when the tensor needs four. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4, 5}, /*strides=*/{1, 2}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedNotEnoughStrideDie) { + TensorFactory tf; + + // Provide one stride when the tensor needs two. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, + /*data=*/{1, 2, 3, 4}, + /*strides=*/{1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooMuchStrideDie) { + TensorFactory tf; + + // Provide three strides when the tensor needs two. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{1, 2, 1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooLargeStrideDie) { + TensorFactory tf; + + // Stride is too large. e.g. [0, 1] is the 4th element of data, which jump out + // the bounds [0, 3] + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{1, 4}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooSmalleStrideDie) { + TensorFactory tf; + + // Stride is too small (only 0th element can be accessed). + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{1, 1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedNonPositiveStrideDie) { + TensorFactory tf; + + // Stride shall be positive. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{2, -1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedWrongStrideForEmptyDataDie) { + TensorFactory tf; + + // When calculating strides based on sizes, we need to treat the size of + // dimension equals to zero as one. + ET_EXPECT_DEATH( + tf.make(/*sizes=*/{0, 2, 2}, /*data=*/{}, /*strides=*/{0, 2, 1}), ""); +} + +TEST_F(TensorFactoryTest, MakeStridedWrongStrideForZeroDimDataDie) { + TensorFactory tf; + + // Stride should be empty + ET_EXPECT_DEATH(tf.make(/*sizes=*/{}, /*data=*/{1}, /*strides=*/{0}), ""); +} + +TEST_F(TensorFactoryTest, Full) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.full(/*sizes=*/{2, 2}, 5); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {5, 5, 5, 5}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Use Float as a proxy for demonstrating that full/zeros/ones works for non-Int +// dtypes. +TEST_F(TensorFactoryTest, FullFloat) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.full(/*sizes=*/{2, 2}, 5.5); + + // A Tensor created manually, that should be identical to `actual`. + float data[] = {5.5f, 5.5f, 5.5f, 5.5f}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Float)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Float, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, Zeros) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.zeros(/*sizes=*/{2, 2}); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {0, 0, 0, 0}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, Ones) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.ones(/*sizes=*/{2, 2}); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {1, 1, 1, 1}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, ZeroDimensionalTensor) { + TensorFactory tf; + + // Demonstrate that we can create a zero-dimensional tensor in various ways. + { + Tensor t = tf.make({}, {7}); + EXPECT_EQ(t.dim(), 0); + EXPECT_EQ(t.nbytes(), sizeof(int32_t)); + EXPECT_EQ(t.numel(), 1); + EXPECT_EQ(t.const_data_ptr()[0], 7); + } + { + Tensor t = tf.zeros({}); + EXPECT_EQ(t.dim(), 0); + EXPECT_EQ(t.nbytes(), sizeof(int32_t)); + EXPECT_EQ(t.numel(), 1); + EXPECT_EQ(t.const_data_ptr()[0], 0); + } + { + Tensor t = tf.ones({}); + EXPECT_EQ(t.dim(), 0); + EXPECT_EQ(t.nbytes(), sizeof(int32_t)); + EXPECT_EQ(t.numel(), 1); + EXPECT_EQ(t.const_data_ptr()[0], 1); + } +} + +TEST_F(TensorFactoryTest, EmptyTensor) { + TensorFactory tf; + + // Demonstrate that we can create a completely empty tensor by providing + // a zero-width dimension. + { + Tensor t = tf.make({0}, {}); + EXPECT_EQ(t.dim(), 1); + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + } + { + Tensor t = tf.zeros({0}); + EXPECT_EQ(t.dim(), 1); + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + } + { + Tensor t = tf.ones({0}); + EXPECT_EQ(t.dim(), 1); + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + } +} + +void run_zeros_like_test(Tensor input) { + // Demonstrate that we can create a new tensor filled by 0 with same size as + // the given tensor input. + TensorFactory tf; + std::vector input_sizes_64 = { + input.sizes().begin(), input.sizes().end()}; + Tensor actual = tf.zeros_like(input); + + // A Tensor created manually, that should be identical to `actual`. + std::vector expected_data; + for (const auto i : c10::irange(input.numel())) { + expected_data.push_back(0); + } +#ifdef USE_ATEN_LIB + Tensor expected = + at::zeros(at::IntArrayRef(input_sizes_64), at::dtype(ScalarType::Int)); + if (input.numel()) { + // memcpy shouldn't be done if input tensor is empty tensor. Memcpy doesn't + // allow copy null ptr, even if size is 0. + memcpy( + expected.mutable_data_ptr(), + expected_data.data(), + sizeof(int32_t) * input.numel()); + } +#else // !USE_ATEN_LIB + TensorImpl impl = TensorImpl( + ScalarType::Int, + input.dim(), + // static shape tensor so const_cast is fine. + /*sizes=*/const_cast(input.sizes().data()), + /*data=*/expected_data.data(), + /*dim_order=*/const_cast(input.dim_order().data()), + /*strides=*/const_cast(input.strides().data())); + Tensor expected(&impl); +#endif + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, ZerosLike) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{3, 2, 1}, /*data=*/{1, 2, 3, 4, 5, 6}); + run_zeros_like_test(input); +} + +TEST_F(TensorFactoryTest, ZerosLikeZeroDimensionalTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{}, /*data=*/{1}); + run_zeros_like_test(input); +} + +TEST_F(TensorFactoryTest, ZerosLikeEmptyTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{0}, /*data=*/{}); + run_zeros_like_test(input); +} + +void run_ones_like_test(Tensor input) { + // Demonstrate that we can create a new tensor filled by 1 with same size as + // the given tensor input. + TensorFactory tf; + std::vector input_sizes_64 = { + input.sizes().begin(), input.sizes().end()}; + Tensor actual = tf.ones_like(input); + + // A Tensor created manually, that should be identical to `actual`. + std::vector expected_data; + for (const auto i : c10::irange(input.numel())) { + expected_data.push_back(1); + } +#ifdef USE_ATEN_LIB + Tensor expected = + at::zeros(at::IntArrayRef(input_sizes_64), at::dtype(ScalarType::Int)); + if (input.numel()) { + // memcpy shouldn't be done if input tensor is empty tensor. Memcpy doesn't + // allow copy null ptr, even if size is 0. + memcpy( + expected.mutable_data_ptr(), + expected_data.data(), + sizeof(int32_t) * input.numel()); + } +#else // !USE_ATEN_LIB + TensorImpl impl = TensorImpl( + ScalarType::Int, + input.dim(), + // static shape tensor so const_cast is fine. + /*sizes=*/const_cast(input.sizes().data()), + /*data=*/expected_data.data(), + /*dim_order=*/const_cast(input.dim_order().data()), + /*strides=*/const_cast(input.strides().data())); + Tensor expected(&impl); +#endif + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, OnesLike) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{3, 2, 1}, /*data=*/{1, 2, 3, 4, 5, 6}); + run_ones_like_test(input); +} + +TEST_F(TensorFactoryTest, OnesLikeZeroDimensionalTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{}, /*data=*/{2}); + run_ones_like_test(input); +} + +TEST_F(TensorFactoryTest, OnesLikeEmptyTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{0}, /*data=*/{}); + run_ones_like_test(input); +} + +// +// Tests for TensorListFactory +// + +TEST(TensorListFactoryTest, ZerosLike) { + TensorFactory tf; + TensorListFactory tlf; + + // Some templates with different shapes and non-zero element values. + std::vector templates = { + tf.make(/*sizes=*/{1}, /*data=*/{1}), + tf.make(/*sizes=*/{1, 2}, /*data=*/{2, 3}), + tf.make(/*sizes=*/{2, 2, 2}, /*data=*/{4, 5, 6, 7, 8, 9, 10, 11}), + }; + + TensorList actual = tlf.zeros_like(templates); + + // Should have the same shapes as the templates, but all elements should be + // zero. + std::vector expected = { + tf.zeros(/*sizes=*/{1}), + tf.zeros(/*sizes=*/{1, 2}), + tf.zeros(/*sizes=*/{2, 2, 2}), + }; + + EXPECT_TENSOR_LISTS_EQ(actual, expected); +} + +TEST(TensorListFactoryTest, ZerosLikeMixedDtypes) { + TensorFactory tf_byte; + TensorFactory tf_short; + TensorFactory tf_float; + + TensorFactory tf_int; + TensorListFactory tlf; + + // Some templates with different shapes and non-zero element values, and + // different dtypes than the TensorListFactory. Demonstrates that the template + // dtypes don't matter, only the shapes. + std::vector templates = { + tf_byte.make(/*sizes=*/{1}, /*data=*/{1}), + tf_short.make(/*sizes=*/{1, 2}, /*data=*/{2, 3}), + tf_float.make(/*sizes=*/{2, 2, 2}, /*data=*/{4, 5, 6, 7, 8, 9, 10, 11}), + }; + + TensorList actual = tlf.zeros_like(templates); + + // Should have the same shapes as the templates, but all elements should be + // zero, and the dtypes should all be Int. + std::vector expected = { + tf_int.zeros(/*sizes=*/{1}), + tf_int.zeros(/*sizes=*/{1, 2}), + tf_int.zeros(/*sizes=*/{2, 2, 2}), + }; + + EXPECT_TENSOR_LISTS_EQ(actual, expected); +} + +TEST(TensorListFactoryTest, ZerosLikeEmpty) { + TensorListFactory tlf; + + // Empty templates list. + std::vector templates = {}; + + TensorList actual = tlf.zeros_like(templates); + + // Should produce an empty TensorList. + std::vector expected = {}; + + EXPECT_TENSOR_LISTS_EQ(actual, expected); +} + +TEST_F(TensorFactoryTest, ZerosDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static(tf.zeros({2, 2}, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.zeros({2, 2}, TensorShapeDynamism::STATIC), + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.zeros({2, 2}, TensorShapeDynamism::STATIC), + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, ZerosLikeDynamismParameter) { + TensorFactory tf; + Tensor zeros = tf.zeros({2, 2}); + resize_tensor_to_assert_static( + tf.zeros_like(zeros, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.zeros_like(zeros, TensorShapeDynamism::STATIC), + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.zeros_like(zeros, TensorShapeDynamism::STATIC), + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, OnesDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static(tf.ones({2, 2}, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.ones({2, 2}, TensorShapeDynamism::STATIC), + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.ones({2, 2}, TensorShapeDynamism::STATIC), + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, OnesLikeDynamismParameter) { + TensorFactory tf; + Tensor ones = tf.ones({2, 2}); + resize_tensor_to_assert_static( + tf.ones_like(ones, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.ones_like(ones, TensorShapeDynamism::STATIC), + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.ones_like(ones, TensorShapeDynamism::STATIC), + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, FullDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static( + tf.full({2, 2}, 1, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.full({2, 2}, 1, TensorShapeDynamism::STATIC), + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.full({2, 2}, 1, TensorShapeDynamism::STATIC), + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, MakeDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::STATIC), + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::STATIC), + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +#if !defined(USE_ATEN_LIB) +TEST_F(TensorFactoryTest, FullDynamic) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor out = tf.full(/*sizes=*/{2, 2}, 5); + int32_t new_sizes[2] = {1, 1}; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + out = tf.full( + /*sizes=*/{2, 2}, 5, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); +} + +TEST_F(TensorFactoryTest, MakeIntTensorDynamic) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor out = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}); + + int32_t new_sizes[2] = {1, 1}; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + std::vector data = {1, 2, 3, 4}; + out = tf.make( + /*sizes=*/{2, 2}, data, {}, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); +} + +TEST_F(TensorFactoryTest, MakeZerosDynamic) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor out = tf.zeros(/*sizes=*/{2, 2}); + + int32_t new_sizes[2] = {1, 1}; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + out = tf.zeros( + /*sizes=*/{2, 2}, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + Tensor out_like = tf.zeros_like(out); + new_sizes[0] = 1; + new_sizes[1] = 1; + ET_EXPECT_DEATH(torch::executor::resize(out_like, new_sizes), ""); + + out = tf.zeros_like(out, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); +} + +TEST_F(TensorFactoryTest, DimOrderToStrideTest) { + TensorFactory tf; + // A Tensor created by the factory. + Tensor out = tf.zeros(/*sizes=*/{2, 2}); + std::vector dim_order; + + dim_order.resize(2); + dim_order[0] = 0; + dim_order[1] = 1; + executorch::aten::ArrayRef dim_order_ref( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, out.dim_order()); + + out = tf.zeros(/*sizes=*/{1, 2, 5}); + dim_order.resize(out.sizes().size()); + dim_order[0] = 0; + dim_order[1] = 1; + dim_order[2] = 2; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, out.dim_order()); + + std::vector::ctype> data(10); + Tensor strided_out = tf.make({1, 2, 5}, data, {10, 1, 2}); + dim_order.resize(out.sizes().size()); + dim_order[0] = 0; + dim_order[1] = 2; + dim_order[2] = 1; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); + + data.resize(12); + strided_out = tf.make({3, 2, 2}, data, {1, 6, 3}); + dim_order.resize(out.sizes().size()); + dim_order[0] = 1; + dim_order[1] = 2; + dim_order[2] = 0; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); +} + +TEST_F(TensorFactoryTest, AmbgiuousDimOrderToStrideTest) { + TensorFactory tf; + std::vector::ctype> data(10); + Tensor strided_out = tf.make({1, 2, 5}, data, {1, 1, 2}); + std::vector dim_order(strided_out.sizes().size()); + dim_order[0] = 2; + dim_order[1] = 0; + dim_order[2] = 1; + // Note that above strides of {1, 1, 2} can also be + // interpreter as dim_order = {2, 1, 0}, however when converting + // strides to dim order we preseve dimension order, + // using stable_sort when converting strides to dim_order, + // see dim_order_from_stride in TensorFactorh.h, + // and hence valid dim_order = {2, 0, 1} + // Since strides can give ambiguous dimension order when crossing + // boundary from strides land to dim order land, we have to resolve + // such ambiguity in a deterministic way. + // In dim order land, it is less ambiguous + auto dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); + + strided_out = tf.make({1, 2, 5}, data, {1, 1, 2}); + dim_order.resize(strided_out.sizes().size()); + dim_order[0] = 2; + dim_order[1] = 0; + dim_order[2] = 1; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); +} +#endif // !USE_ATEN_LIB diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp new file mode 100644 index 0000000..b8069e2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp @@ -0,0 +1,848 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::aten::TensorImpl; +using executorch::aten::TensorList; +using executorch::runtime::testing::IsCloseTo; +using executorch::runtime::testing::IsDataCloseTo; +using executorch::runtime::testing::IsDataEqualTo; +using executorch::runtime::testing::IsEqualTo; +using executorch::runtime::testing::IsListCloseTo; +using executorch::runtime::testing::IsListEqualTo; +using executorch::runtime::testing::tensor_data_is_close; +using executorch::runtime::testing::tensor_lists_are_close; +using executorch::runtime::testing::TensorFactory; +using executorch::runtime::testing::tensors_are_close; + +// Exhaustively test all of our comparison functions every time. Also flip the +// params around to demonstrate that the underlying checks are commutative. + +#define EXPECT_TENSORS_CLOSE_AND_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensors_are_close((t1__), (t2__))); \ + EXPECT_TRUE(tensors_are_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsCloseTo((t1__))); \ + EXPECT_TENSOR_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), IsEqualTo(t2__)); \ + EXPECT_THAT((t2__), IsEqualTo(t1__)); \ + EXPECT_TENSOR_EQ((t1__), (t2__)); \ + EXPECT_TENSOR_EQ((t2__), (t1__)); \ + ASSERT_TENSOR_EQ((t1__), (t2__)); \ + ASSERT_TENSOR_EQ((t2__), (t1__)) + +#define EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensors_are_close((t1__), (t2__))); \ + EXPECT_TRUE(tensors_are_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsCloseTo((t1__))); \ + EXPECT_TENSOR_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsEqualTo(t1__))); \ + EXPECT_TENSOR_NE((t1__), (t2__)); \ + EXPECT_TENSOR_NE((t2__), (t1__)); \ + ASSERT_TENSOR_NE((t1__), (t2__)); \ + ASSERT_TENSOR_NE((t2__), (t1__)) + +#define EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(t1__, t2__) \ + EXPECT_FALSE(tensors_are_close((t1__), (t2__))); \ + EXPECT_FALSE(tensors_are_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), Not(IsCloseTo((t2__)))); \ + EXPECT_THAT((t2__), Not(IsCloseTo((t1__)))); \ + EXPECT_TENSOR_NOT_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_NOT_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_NOT_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_NOT_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsEqualTo(t1__))); \ + EXPECT_TENSOR_NE((t1__), (t2__)); \ + EXPECT_TENSOR_NE((t2__), (t1__)); \ + ASSERT_TENSOR_NE((t1__), (t2__)); \ + ASSERT_TENSOR_NE((t2__), (t1__)) + +#define EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensor_data_is_close((t1__), (t2__))); \ + EXPECT_TRUE(tensor_data_is_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsDataCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsDataCloseTo((t1__))); \ + EXPECT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), IsDataEqualTo(t2__)); \ + EXPECT_THAT((t2__), IsDataEqualTo(t1__)); \ + EXPECT_TENSOR_DATA_EQ((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_EQ((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_EQ((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_EQ((t2__), (t1__)) + +#define EXPECT_TENSORS_DATA_CLOSE_BUT_NOT_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensor_data_is_close((t1__), (t2__))); \ + EXPECT_TRUE(tensor_data_is_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsDataCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsDataCloseTo((t1__))); \ + EXPECT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsDataEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsDataEqualTo(t1__))); \ + EXPECT_TENSOR_DATA_NE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_NE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_NE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_NE((t2__), (t1__)) + +#define EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1__, t2__) \ + EXPECT_FALSE(tensor_data_is_close((t1__), (t2__))); \ + EXPECT_FALSE(tensor_data_is_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), Not(IsDataCloseTo((t2__)))); \ + EXPECT_THAT((t2__), Not(IsDataCloseTo((t1__)))); \ + EXPECT_TENSOR_DATA_NOT_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_NOT_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_NOT_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_NOT_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsDataEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsDataEqualTo(t1__))); \ + EXPECT_TENSOR_DATA_NE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_NE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_NE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_NE((t2__), (t1__)) + +#define EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1__, list2__) \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list1__).data(), \ + (list1__).size(), \ + (list2__).data(), \ + (list2__).size())); \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list2__).data(), \ + (list2__).size(), \ + (list1__).data(), \ + (list1__).size())); \ + EXPECT_THAT((list1__), IsListCloseTo((list2__))); \ + EXPECT_THAT((list2__), IsListCloseTo((list1__))); \ + EXPECT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + EXPECT_THAT((list1__), IsListEqualTo(list2__)); \ + EXPECT_THAT((list2__), IsListEqualTo(list1__)); \ + EXPECT_TENSOR_LISTS_EQ((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_EQ((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_EQ((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_EQ((list2__), (list1__)) + +#define EXPECT_TENSOR_LISTS_CLOSE_BUT_NOT_EQUAL(list1__, list2__) \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list1__).data(), \ + (list1__).size(), \ + (list2__).data(), \ + (list2__).size())); \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list2__).data(), \ + (list2__).size(), \ + (list1__).data(), \ + (list1__).size())); \ + EXPECT_THAT((list1__), IsListCloseTo((list2__))); \ + EXPECT_THAT((list2__), IsListCloseTo((list1__))); \ + EXPECT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + EXPECT_THAT((list1__), Not(IsListEqualTo(list2__))); \ + EXPECT_THAT((list2__), Not(IsListEqualTo(list1__))); \ + EXPECT_TENSOR_LISTS_NE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_NE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_NE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_NE((list2__), (list1__)) + +#define EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1__, list2__) \ + EXPECT_FALSE(tensor_lists_are_close( \ + (list1__).data(), \ + (list1__).size(), \ + (list2__).data(), \ + (list2__).size())); \ + EXPECT_FALSE(tensor_lists_are_close( \ + (list2__).data(), \ + (list2__).size(), \ + (list1__).data(), \ + (list1__).size())); \ + EXPECT_THAT((list1__), Not(IsListCloseTo((list2__)))); \ + EXPECT_THAT((list2__), Not(IsListCloseTo((list1__)))); \ + EXPECT_TENSOR_LISTS_NOT_CLOSE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_NOT_CLOSE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_NOT_CLOSE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_NOT_CLOSE((list2__), (list1__)); \ + EXPECT_THAT((list1__), Not(IsListEqualTo(list2__))); \ + EXPECT_THAT((list2__), Not(IsListEqualTo(list1__))); \ + EXPECT_TENSOR_LISTS_NE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_NE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_NE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_NE((list2__), (list1__)) + +namespace { +// calculate numel given size +int32_t size_to_numel(std::vector sizes) { + int32_t numel = 1; + for (auto size : sizes) { + numel *= size; + } + return numel; +} + +} // namespace + +// Mismatched shapes/types/strides. + +TEST(TensorUtilTest, DifferentDtypesAreNotCloseOrEqual) { + // Create two tensors with identical shape and data, but different dtypes. + TensorFactory tf_int; + Tensor a = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + TensorFactory tf_long; + Tensor b = tf_long.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, DifferentSizesAreNotCloseOrEqual) { + TensorFactory tf; + + // Create two tensors with identical dtype and data, but different shapes. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + Tensor b = tf.make(/*sizes=*/{4}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, DifferentLayoutsDies) { + TensorFactory tf; + + // Create two tensors with identical dtype, data and shapes, but different + // strides. + Tensor a = tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}, /*strided=*/{1, 2}); + Tensor b = tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}, /*strided=*/{2, 1}); + + // Current `tensors_are_close` does not support comparing two tensors with + // different stride. + // TODO(T132992348): support comparison between tensors of different strides + ET_EXPECT_DEATH(EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b), ""); + ET_EXPECT_DEATH(EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b), ""); +} + +// Int tensors, as a proxy for all non-floating-point types. + +TEST(TensorUtilTest, IntTensorIsCloseAndEqualToItself) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(t, t); +} + +TEST(TensorUtilTest, IdenticalIntTensorsAreCloseAndEqual) { + TensorFactory tf; + + // Create two tensors with identical shape, dtype, and data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +TEST(TensorUtilTest, NonIdenticalIntTensorsAreNotCloseOrEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but different data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{99, 2, 4, 8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, EmptyTensorsAreCloseAndEqual) { + TensorFactory tf; + + // Create two tensors with identical shapes but no data. + Tensor a = tf.make(/*sizes=*/{0, 2}, /*data=*/{}); + EXPECT_EQ(a.numel(), 0); + EXPECT_EQ(a.nbytes(), 0); + Tensor b = tf.make(/*sizes=*/{0, 2}, /*data=*/{}); + EXPECT_EQ(b.numel(), 0); + EXPECT_EQ(b.nbytes(), 0); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +// Float tensors, as a proxy for all floating-point types. + +TEST(TensorUtilTest, FloatTensorIsCloseAndEqualToItself) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(t, t); +} + +TEST(TensorUtilTest, IdenticalFloatTensorsAreCloseAndEqual) { + TensorFactory tf; + + // Create two tensors with identical shape, dtype, and data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +TEST(TensorUtilTest, NearlyIdenticalFloatTensorsAreCloseButNotEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but slightly different + // data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make( + /*sizes=*/{2, 2}, + {// First data element is slightly larger. + std::nextafter(1.1f, 100.0f), + // Remaining data elements are the same. + 2.2, + 4.4, + 8.8}); + + EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(a, b); +} + +TEST(TensorUtilTest, NonIdenticalFloatTensorsAreNotCloseOrEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but different data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{99.99, 2.2, 4.4, 8.8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, FloatNanElementsAreCloseAndEqual) { + TensorFactory tf; + + // Two identical tensors with NaN elements. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +TEST(TensorUtilTest, FloatNanElementsAreNotEqualToNonNan) { + TensorFactory tf; + + // Regression test ensuring that NaN elements are not compared equal to + // non-NaN finite values. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 0.0, 2.2, 0.0}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, FloatInfiniteElementsAreCloseAndEqual) { + constexpr auto kInfinity = std::numeric_limits::infinity(); + + TensorFactory tf; + + // Two identical tensors with infinite elements. + Tensor a = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, 1.1, 2.2, kInfinity}); + Tensor b = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, 1.1, 2.2, kInfinity}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +// Double: less test coverage since Float covers all of the branches, but +// demonstrate that it works. + +TEST(TensorUtilTest, NearlyIdenticalDoubleTensorsAreCloseButNotEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but slightly different + // data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make( + /*sizes=*/{2, 2}, + {// First data element is slightly larger. + std::nextafter(1.1f, 100.0f), + // Remaining data elements are the same. + 2.2, + 4.4, + 8.8}); + + EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(a, b); +} + +TEST(TensorUtilTest, DoubleAndInfinitNanElementsAreCloseAndEqual) { + constexpr auto kInfinity = std::numeric_limits::infinity(); + + TensorFactory tf; + + // Two identical tensors with NaN and infinite elements. + Tensor a = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, NAN, 1.1, kInfinity}); + Tensor b = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, NAN, 1.1, kInfinity}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +// Testing closeness with tolerances + +TEST(TensorUtilTest, TensorsAreCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.099999, 0.0, -0.05}); + Tensor bf = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.099999, 2.0, 0.05, 0.0}); + + EXPECT_TENSOR_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.199, NAN, -9.0}); + Tensor bd = td.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.0, NAN, -10.0}); + + EXPECT_TENSOR_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +TEST(TensorUtilTest, TensorsAreNotCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{3}, /*data=*/{1.00, NAN, -10.0}); + Tensor bf = tf.make(/*sizes=*/{3}, /*data=*/{1.11, NAN, -10.0}); + + EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{3}, /*data=*/{1.0, 0.0, -10.0}); + Tensor bd = td.make(/*sizes=*/{3}, /*data=*/{1.0, 0.0, -9.0}); + + EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); + + // Create two tensors with identical shape and dtype, but different data. + ad = tf.make(/*sizes=*/{3}, /*data=*/{1.0, 2.0, 0.00001}); + bd = tf.make(/*sizes=*/{3}, /*data=*/{1.0, 2.0, 0.0}); + + EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +// +// Tests for shape-agnostic data equality. +// + +// Common testing for EXPECT_TENSOR_DATA_EQ in different input sizes and +// dtypes. +template +void test_data_equal( + std::vector t1_sizes, + std::vector t2_sizes) { + TensorFactory tf; + + // get corresponding ctype for input DTYPEs + using ctype = typename TensorFactory::ctype; + + // Get the size of data of t1 and t2. + // Make sure the two sizes are equal. + auto numel = size_to_numel(t1_sizes); + ASSERT_EQ(numel, size_to_numel(t2_sizes)); + + // Set up data vector for t1 and t2. + // Set them as a same random vector to test them generally. + std::vector t1_data(numel); + std::generate(t1_data.begin(), t1_data.end(), std::rand); + std::vector t2_data(numel); + t2_data = t1_data; + + Tensor t1 = tf.make(t1_sizes, t1_data); + Tensor t2 = tf.make(t2_sizes, t2_data); + + EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1, t2); +} + +TEST(TensorUtilTest, TensorDataEqualSizeEqual) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 4, 5}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, TensorDataEqualSizeUnequal) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 5, 4}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, EmptyTensorsSupported) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 0, 5}, {3, 4, 0, 5}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, ZeroDimTensorsSupported) { +#define TEST_ENTRY(ctype, dtype) test_data_equal({}, {}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +// Common testing for EXPECT_TENSOR_DATA_CLOSE in different input sizes and +// dtypes. +template < + ScalarType DTYPE, + std::enable_if_t< + DTYPE == ScalarType::Float || DTYPE == ScalarType::Double, + bool> = true> +void test_data_close_but_not_equal( + std::vector t1_sizes, + std::vector t2_sizes) { + TensorFactory tf; + + // get corresponding ctype for input DTYPEs + using ctype = typename TensorFactory::ctype; + + // get the size of data of t1 and t2 + // make sure the two sizes are equal + auto numel = size_to_numel(t1_sizes); + ASSERT_EQ(numel, size_to_numel(t2_sizes)); + + // set up data vector for t1 and t2 + // set them as a almost same random vector (only the first element are + // different if the first element exists) to test them generally + std::vector t1_data(numel); + std::generate(t1_data.begin(), t1_data.end(), std::rand); + std::vector t2_data(numel); + t2_data = t1_data; + + // Set the first element of t2 slightly larger than 0 + // the "first element" only work if t2_numel > 0 + // The checking with ctype.max() is to prevent overflow + if (numel > 0) { + if (t2_data[0] < std::numeric_limits::max() - 100) { + t2_data[0] = std::nextafter(t2_data[0], t2_data[0] + 100.0f); + } else { + t2_data[0] = std::nextafter(t2_data[0], t2_data[0] - 100.f); + } + } + + Tensor t1 = tf.make(t1_sizes, t1_data); + Tensor t2 = tf.make(t2_sizes, t2_data); + + EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1, t2); +} + +TEST(TensorUtilTest, TensorDataCloseNotEqualSizeEqual) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 4, 5}); + ET_FORALL_FLOAT_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, TensorDataCloseNotEqualSizeUnequal) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 5, 4}); + ET_FORALL_FLOAT_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +// Common testing for EXPECT_TENSOR_DATA_EQ in different input sizes and +// dtypes. +template +void test_data_equal_but_size_or_dtype_mismatch( + std::vector t1_sizes, + std::vector t2_sizes) { + TensorFactory tf_t1; + TensorFactory tf_t2; + + Tensor t1 = tf_t1.zeros(t1_sizes); + Tensor t2 = tf_t2.zeros(t2_sizes); + + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t2); +} + +TEST(TensorUtilTest, TensorDataTypeMismatched) { + std::vector sizes = {3, 4, 5, 6}; + test_data_equal_but_size_or_dtype_mismatch< + ScalarType::Float, + ScalarType::Double>(sizes, sizes); + test_data_equal_but_size_or_dtype_mismatch< + ScalarType::Int, + ScalarType::Double>(sizes, sizes); +} + +TEST(TensorUtilTest, TensorSizeMismatched) { + std::vector sizes_t1 = {3, 4, 5, 6}; + std::vector sizes_t2 = {3, 4, 5, 7}; + test_data_equal_but_size_or_dtype_mismatch< + ScalarType::Float, + ScalarType::Float>(sizes_t1, sizes_t2); +} + +TEST(TensorUtilTest, TensorDataMismatched) { + TensorFactory tf; + Tensor t1 = tf.make(/*size=*/{3, 2}, /*data=*/{1, 2, 3, 4, 5, 6}); + Tensor t2 = tf.make(/*size=*/{3, 2}, /*data=*/{1, 2, 3, 1, 5, 6}); + Tensor t3 = tf.make(/*size=*/{2, 3}, /*data=*/{1, 2, 3, 1, 5, 6}); + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t2); + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t3); + + Tensor t_zero_dim = tf.make(/*size=*/{}, /*data=*/{0}); + Tensor t_empty = tf.make(/*size=*/{0}, /*data=*/{}); + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t_zero_dim, t_empty); +} + +// Testing data closeness with tolerances + +TEST(TensorUtilTest, TensorDataCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{4, 1}, /*data=*/{1.0, 2.099, 0.0, -0.05}); + Tensor bf = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.0, 0.05, 0.0}); + + EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.199, NAN, -9.0}); + Tensor bd = td.make(/*sizes=*/{4}, /*data=*/{1.0, 2.0, NAN, -10.0}); + + EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +TEST(TensorUtilTest, TensorDataNotCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{3}, /*data=*/{1.00, 0.0, -10.0}); + Tensor bf = tf.make(/*sizes=*/{3, 1}, /*data=*/{1.11, 0.0, -10.0}); + + EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 0.0, -10.0, 0.0}); + Tensor bd = td.make(/*sizes=*/{4}, /*data=*/{1.0, 0.0, -9.0, 0.0}); + + EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); + + // Create two tensors with identical shape and dtype, but different data. + ad = tf.make(/*sizes=*/{1, 4}, /*data=*/{1.0, 2.0, NAN, 0.00001}); + bd = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.0, NAN, 0.0}); + + EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +// +// Tests for TensorList helpers. +// + +TEST(TensorUtilTest, TensorListsCloseAndEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + // Two lists of tensors that should be close and equal. Elements have + // different shapes and dtypes. + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list2(vec2.data(), vec2.size()); + + // Show that we can compare a mix of vectors and TensorLists. + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, list2); + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(vec1, list2); + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, vec2); + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(vec1, vec2); +} + +TEST(TensorUtilTest, EmptyTensorListsAreCloseAndEqual) { + // Two empty lists. + TensorList list1; + EXPECT_EQ(list1.size(), 0); + TensorList list2; + EXPECT_EQ(list2.size(), 0); + + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, list2); +} + +TEST(TensorUtilTest, TensorListsCloseButNotEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + // Two lists of tensors that should be close and equal. Elements have + // different shapes and dtypes. + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list2(vec2.data(), vec2.size()); + + // Tweak a float value slightly. + vec1[1].mutable_data_ptr()[0] = std::nextafter(1.0f, 100.0f); + + // Show that we can compare a mix of vectors and TensorLists. + EXPECT_TENSOR_LISTS_CLOSE_BUT_NOT_EQUAL(list1, list2); +} + +TEST(TensorUtilTest, TensorListsWithDifferentDataAreNotCloseOrEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.zeros(/*sizes=*/{2, 1}), // vs. ones() in the first list. + }; + TensorList list2(vec2.data(), vec2.size()); + + EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1, list2); +} + +TEST(TensorUtilTest, TensorListsWithDifferentLengthsAreNotCloseOrEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + // Missing second element. + }; + TensorList list2(vec2.data(), vec2.size()); + + EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1, list2); +} + +// We don't need to test the ATen operator<<() implementations since they're +// tested elsewhere. +#ifndef USE_ATEN_LIB + +// Printing/formatting helpers. + +TEST(TensorUtilTest, ScalarTypeStreamSmokeTest) { + // Don't test everything, since operator<<(ScalarType) is just a wrapper + // around a separately-tested function. Just demonstrate that the stream + // wrapper works, and gives us a little more information for unknown types. + { + std::stringstream out; + out << ScalarType::Byte; + EXPECT_STREQ(out.str().c_str(), "Byte"); + } + { + std::stringstream out; + out << static_cast(127); + EXPECT_STREQ(out.str().c_str(), "Unknown(127)"); + } +} + +TEST(TensorUtilTest, TensorStreamInt) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + std::stringstream out; + out << t; + EXPECT_STREQ( + out.str().c_str(), "ETensor(sizes={2, 2}, dtype=Int, data={1, 2, 4, 8})"); +} + +TEST(TensorUtilTest, TensorStreamDouble) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + + std::stringstream out; + out << t; + EXPECT_STREQ( + out.str().c_str(), + "ETensor(sizes={2, 2}, dtype=Double, data={1.1, 2.2, 4.4, 8.8})"); +} + +TEST(TensorUtilTest, TensorStreamBool) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{true, false, true, false}); + + std::stringstream out; + out << t; + EXPECT_STREQ( + out.str().c_str(), + "ETensor(sizes={2, 2}, dtype=Bool, data={1, 0, 1, 0})"); +} + +TEST(TensorTest, TestZeroShapeTensorEquality) { + TensorImpl::SizesType sizes[2] = {2, 2}; + TensorImpl::StridesType strides[2] = {2, 1}; + TensorImpl::DimOrderType dim_order[2] = {0, 1}; + + TensorImpl t1(ScalarType::Float, 2, sizes, nullptr, dim_order, strides); + TensorImpl t2(ScalarType::Float, 2, sizes, nullptr, dim_order, strides); + + ET_EXPECT_DEATH({ EXPECT_TENSOR_EQ(Tensor(&t1), Tensor(&t2)); }, ""); + + float data[] = {1.0, 2.0, 3.0, 4.0}; + + t1.set_data(data); + t2.set_data(data); + + EXPECT_TENSOR_EQ(Tensor(&t1), Tensor(&t2)); +} + +#endif // !USE_ATEN_LIB diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/README.md new file mode 100644 index 0000000..910e471 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/README.md @@ -0,0 +1,2 @@ +The targets in this directory are not part of the core `kernel_types` libray, +but are helpful for writing code that uses those types. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/dim_order_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/dim_order_util.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/dim_order_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/dim_order_util.h index ea56827..d01b207 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/dim_order_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/dim_order_util.h @@ -8,13 +8,13 @@ #pragma once +#include #include #include #include #include #include -#include #include #include @@ -24,22 +24,10 @@ namespace runtime { namespace { template bool validate_dim_order(const DimOrderType* dim_order, const size_t dims) { - static_assert( - kTensorDimensionLimit <= 16, - "Bitmask-based validation requires kTensorDimensionLimit <= 16"); - if (dims > kTensorDimensionLimit) { - return false; - } - uint16_t seen = 0; for (const auto i : c10::irange(dims)) { if (dim_order[i] >= static_cast(dims)) { return false; } - const uint16_t mask = 1u << dim_order[i]; - if (seen & mask) { - return false; - } - seen |= mask; } return true; } @@ -162,7 +150,7 @@ ET_NODISCARD inline Error dim_order_to_stride( ET_CHECK_OR_RETURN_ERROR( validate_dim_order(dim_order, dims), InvalidArgument, - "Invalid dim order: values must be a permutation of [0, %zu)", + "Invalid dim order. One of the value is larger than the number of dims %zu", dims); dim_order_to_stride_nocheck(sizes, dim_order, dims, strides); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/scalar_type_util.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/targets.bzl new file mode 100644 index 0000000..ffdfa4f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/targets.bzl @@ -0,0 +1,85 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + exported_preprocessor_flags_ = [] + exported_deps_ = ["//executorch/runtime/core:core"] + if aten_mode: + exported_preprocessor_flags_ += ["-DUSE_ATEN_LIB"] + else: + exported_deps_ += ["//executorch/runtime/core/portable_type:scalar_type"] + + runtime.cxx_library( + name = "scalar_type_util" + aten_suffix, + srcs = [], + exported_headers = [ + "scalar_type_util.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = exported_preprocessor_flags_, + exported_deps = exported_deps_, + exported_external_deps = ["libtorch"] if aten_mode else [], + ) + + runtime.cxx_library( + name = "dim_order_util" + aten_suffix, + srcs = [], + exported_headers = [ + "dim_order_util.h", + ], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + ) + + runtime.cxx_library( + name = "tensor_util" + aten_suffix, + srcs = ["tensor_util_aten.cpp"] if aten_mode else ["tensor_util_portable.cpp"], + exported_headers = [ + "tensor_util.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + ":tensor_dimension_limit", + "//executorch/runtime/core:core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ] + [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + ":scalar_type_util" + aten_suffix, + ":dim_order_util" + aten_suffix, + ], + # WARNING: using a deprecated API to avoid being built into a shared + # library. In the case of dynamically loading so library we don't want + # it to depend on other so libraries because that way we have to + # specify library directory path. + force_static = True, + ) + + runtime.cxx_library( + name = "tensor_shape_to_c_string" + aten_suffix, + srcs = ["tensor_shape_to_c_string.cpp"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit", + ], + exported_headers = ["tensor_shape_to_c_string.h"], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "tensor_dimension_limit", + exported_headers = ["tensor_dimension_limit.h"], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_shape_to_c_string.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_util_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_util_aten.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_util_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_util_aten.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_util_portable.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_util_portable.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/tensor_util_portable.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/tensor_util_portable.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/CMakeLists.txt new file mode 100644 index 0000000..e806419 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs + dim_order_util_test.cpp operator_impl_example_test.cpp + scalar_type_util_test.cpp tensor_shape_to_c_string_test.cpp + tensor_util_test.cpp +) + +et_cxx_test(runtime_core_exec_aten_util_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/dim_order_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/dim_order_util_test.cpp new file mode 100644 index 0000000..fe3c1f6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/dim_order_util_test.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include + +#include + +#include + +using executorch::runtime::dim_order_to_stride; +using executorch::runtime::Error; +using executorch::runtime::is_channels_last_dim_order; +using executorch::runtime::is_contiguous_dim_order; +using executorch::runtime::stride_to_dim_order; + +namespace { +void check_strides_eq( + executorch::aten::ArrayRef strides_a, + executorch::aten::ArrayRef strides_b) { + for (const auto i : c10::irange(strides_a.size())) { + EXPECT_EQ(strides_a[i], strides_b[i]); + } +} + +void check_dim_order_eq( + executorch::aten::ArrayRef dim_order_a, + executorch::aten::ArrayRef dim_order_b) { + for (const auto i : c10::irange(dim_order_a.size())) { + EXPECT_EQ(dim_order_a[i], dim_order_b[i]); + } +} +} // namespace + +TEST(DimOrderUtilTest, DimOrderToStride) { + executorch::aten::SizesType sizes_1[1] = {5}; + executorch::aten::SizesType dim_order_1[1] = {0}; + executorch::aten::SizesType strides_1[1] = {0}; + executorch::aten::SizesType expected_strides_1[1] = {1}; + auto error = dim_order_to_stride(sizes_1, dim_order_1, 1, strides_1); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_1, 1}, {expected_strides_1, 1}); + + executorch::aten::SizesType sizes_2[2] = {2, 5}; + executorch::aten::SizesType dim_order_2[2] = {0, 1}; + executorch::aten::SizesType strides_2[2] = {0, 0}; + executorch::aten::SizesType expected_strides_2[2] = {5, 1}; + error = dim_order_to_stride(sizes_2, dim_order_2, 2, strides_2); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_2, 2}, {expected_strides_2, 2}); + + dim_order_2[0] = 1; + dim_order_2[1] = 0; + expected_strides_2[0] = 1; + expected_strides_2[1] = 2; + error = dim_order_to_stride(sizes_2, dim_order_2, 2, strides_2); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_2, 2}, {expected_strides_2, 2}); + + executorch::aten::SizesType sizes_3[3] = {2, 5, 7}; + executorch::aten::SizesType dim_order_3[3] = {0, 1, 2}; + executorch::aten::SizesType strides_3[3] = {0, 0, 0}; + executorch::aten::SizesType expected_strides_3[3] = {35, 7, 1}; + error = dim_order_to_stride(sizes_3, dim_order_3, 3, strides_3); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3, 3}, {expected_strides_3, 3}); + + // {0, 2, 1} + dim_order_3[0] = 0, dim_order_3[1] = 2, dim_order_3[2] = 1; + // Expected stride {35, 1, 5} + expected_strides_3[0] = 35, expected_strides_3[1] = 1, + expected_strides_3[2] = 5; + error = dim_order_to_stride(sizes_3, dim_order_3, 3, strides_3); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3, 3}, {expected_strides_3, 3}); + + // {2, 5, 7} + // {1, 2, 0} + dim_order_3[0] = 1, dim_order_3[1] = 2, dim_order_3[2] = 0; + // Expected stride {35, 1, 5} + expected_strides_3[0] = 1, expected_strides_3[1] = 14, + expected_strides_3[2] = 2; + error = dim_order_to_stride(sizes_3, dim_order_3, 3, strides_3); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3, 3}, {expected_strides_3, 3}); + + executorch::aten::SizesType sizes_4[4] = {2, 5, 7, 8}; + executorch::aten::SizesType dim_order_4[4] = {0, 1, 2, 3}; + executorch::aten::SizesType strides_4[4] = {0, 0, 0, 0}; + executorch::aten::SizesType expected_strides_4[4] = {280, 56, 8, 1}; + error = dim_order_to_stride(sizes_4, dim_order_4, 4, strides_4); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_4, 4}, {expected_strides_4, 4}); + + // {2, 5, 7, 8} + // {0, 2, 3, 1} + dim_order_4[0] = 0; + dim_order_4[1] = 2; + dim_order_4[2] = 3; + dim_order_4[3] = 1; + // Expected stride {280, 1, 40, 5} + expected_strides_4[0] = 280; + expected_strides_4[1] = 1; + expected_strides_4[2] = 40; + expected_strides_4[3] = 5; + error = dim_order_to_stride(sizes_4, dim_order_4, 4, strides_4); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_4, 4}, {expected_strides_4, 4}); + + // {2, 5, 7, 8} + // {3, 1, 2, 0} + dim_order_4[0] = 3; + dim_order_4[1] = 1; + dim_order_4[2] = 2; + dim_order_4[3] = 0; + // Expected stride {1, 14, 2, 70} + expected_strides_4[0] = 1; + expected_strides_4[1] = 14; + expected_strides_4[2] = 2; + expected_strides_4[3] = 70; + error = dim_order_to_stride(sizes_4, dim_order_4, 4, strides_4); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_4, 4}, {expected_strides_4, 4}); + + executorch::aten::SizesType sizes_5[5] = {2, 5, 7, 8, 9}; + executorch::aten::SizesType dim_order_5[5] = {0, 1, 2, 3, 4}; + executorch::aten::SizesType strides_5[5] = {0, 0, 0, 0, 0}; + executorch::aten::SizesType expected_strides_5[5] = {2520, 504, 72, 9, 1}; + error = dim_order_to_stride(sizes_5, dim_order_5, 5, strides_5); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_5, 5}, {expected_strides_5, 5}); + + // {2, 5, 7, 8, 9} + // {0, 2, 3, 4, 1} + dim_order_5[0] = 0; + dim_order_5[1] = 2; + dim_order_5[2] = 3; + dim_order_5[3] = 4; + dim_order_5[4] = 1; + // Expected stride {2520, 1, 360, 45, 5} + expected_strides_5[0] = 2520; + expected_strides_5[1] = 1; + expected_strides_5[2] = 360; + expected_strides_5[3] = 45; + expected_strides_5[4] = 5; + error = dim_order_to_stride(sizes_5, dim_order_5, 5, strides_5); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_5, 5}, {expected_strides_5, 5}); + + // {2, 5, 7, 8, 9} + // {4, 2, 0, 3, 1} + dim_order_5[0] = 4; + dim_order_5[1] = 2; + dim_order_5[2] = 0; + dim_order_5[3] = 3; + dim_order_5[4] = 1; + // Expected stride {40, 1, 80, 5, 560} + expected_strides_5[0] = 40; + expected_strides_5[1] = 1; + expected_strides_5[2] = 80; + expected_strides_5[3] = 5; + expected_strides_5[4] = 560; + error = dim_order_to_stride(sizes_5, dim_order_5, 5, strides_5); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_5, 5}, {expected_strides_5, 5}); + + // Check 0 sized dims + executorch::aten::SizesType sizes_3_zero[3] = {2, 5, 0}; + executorch::aten::SizesType dim_order_3_zero[3] = {0, 1, 2}; + executorch::aten::SizesType strides_3_zero[3] = {0, 0, 0}; + executorch::aten::SizesType expected_strides_3_zero[3] = {5, 1, 1}; + error = + dim_order_to_stride(sizes_3_zero, dim_order_3_zero, 3, strides_3_zero); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3_zero, 3}, {expected_strides_3_zero, 3}); + + // {0, 2, 1} + // {2, 0, 5} + dim_order_3_zero[0] = 0, dim_order_3_zero[1] = 2, dim_order_3_zero[2] = 1; + // Expected stride {5, 5, 1} + expected_strides_3_zero[0] = 5, expected_strides_3_zero[1] = 1, + expected_strides_3_zero[2] = 5; + error = + dim_order_to_stride(sizes_3_zero, dim_order_3_zero, 3, strides_3_zero); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3_zero, 3}, {expected_strides_3_zero, 3}); + + // {2, 0, 1} + // {0, 2, 5} + dim_order_3_zero[0] = 2, dim_order_3_zero[1] = 0, dim_order_3_zero[2] = 1; + // Expected stride {10, 5, 1} + expected_strides_3_zero[0] = 5, expected_strides_3_zero[1] = 1, + expected_strides_3_zero[2] = 10; + error = + dim_order_to_stride(sizes_3_zero, dim_order_3_zero, 3, strides_3_zero); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3_zero, 3}, {expected_strides_3_zero, 3}); +} + +TEST(DimOrderUtilTest, StrideToDimOrder) { + executorch::aten::SizesType strides[3] = {5, 1, 15}; + executorch::aten::DimOrderType dim_order[3] = {0, 0, 0}; + + auto error = stride_to_dim_order(strides, 3, dim_order); + + EXPECT_EQ(error, Error::Ok); + + executorch::aten::DimOrderType expected_dim_order[3] = {2, 0, 1}; + check_dim_order_eq(dim_order, expected_dim_order); +} + +TEST(DimOrderUtilTest, StrideToDimOrderSameStrides) { + executorch::aten::SizesType strides[4] = {4, 3, 1, 1}; + executorch::aten::DimOrderType dim_order[4] = {0, 0, 0, 0}; + + auto error = stride_to_dim_order(strides, 4, dim_order); + EXPECT_EQ(error, Error::Ok); + + executorch::aten::DimOrderType expected_dim_order[4] = {0, 1, 2, 3}; + check_dim_order_eq(dim_order, expected_dim_order); +} + +TEST(DimOrderUtilTest, IsDefaultDimOrderTest) { + for (const auto i : c10::irange(1, 7)) { + std::vector dim_order(i); + std::iota(dim_order.begin(), dim_order.end(), 0); + + EXPECT_TRUE(is_contiguous_dim_order(dim_order.data(), dim_order.size())); + + // As a bonus, check that is_channels_last returns false + EXPECT_FALSE( + is_channels_last_dim_order(dim_order.data(), dim_order.size())); + } +} + +TEST(DimOrderUtilTest, IsDefaultDimOrderFailCasesTest) { + // Dims is default order but have two elements swapped + for (const auto i : c10::irange(3, 8)) { + std::vector dim_order(i); + std::iota(dim_order.begin(), dim_order.end(), 0); + std::swap(dim_order[0], dim_order[1]); + + EXPECT_FALSE(is_contiguous_dim_order(dim_order.data(), dim_order.size())); + } + + // Dims is default order but shifted by 1 + for (const auto i : c10::irange(3, 8)) { + std::vector dim_order(i); + for (const auto d : c10::irange(i)) { + dim_order[d] = (d + 1) % i; + } + + EXPECT_FALSE(is_contiguous_dim_order(dim_order.data(), dim_order.size())); + } +} + +TEST(DimOrderUtilTest, IsChannelsLastDimOrderTest) { + executorch::aten::DimOrderType dim_order_4d[4] = {0, 2, 3, 1}; + executorch::aten::DimOrderType dim_order_5d[5] = {0, 2, 3, 4, 1}; + + EXPECT_TRUE(is_channels_last_dim_order(dim_order_4d, 4)); + EXPECT_TRUE(is_channels_last_dim_order(dim_order_5d, 5)); + + // As a bonus, check that is_default returns false + EXPECT_FALSE(is_contiguous_dim_order(dim_order_4d, 4)); + EXPECT_FALSE(is_contiguous_dim_order(dim_order_5d, 5)); +} + +TEST(DimOrderUtilTest, IsChannelsLastDimOrderFailCasesTest) { + // Non 4D and 5D dim order returns false + executorch::aten::DimOrderType dim_order_3d[4] = {1, 2, 0}; + executorch::aten::DimOrderType dim_order_6d[6] = {0, 2, 3, 4, 5, 1}; + + EXPECT_FALSE(is_channels_last_dim_order(dim_order_3d, 3)); + EXPECT_FALSE(is_channels_last_dim_order(dim_order_6d, 6)); + + executorch::aten::DimOrderType dim_order_4d[4] = {0, 3, 2, 1}; + executorch::aten::DimOrderType dim_order_5d[5] = {4, 3, 2, 0, 1}; + + EXPECT_FALSE(is_channels_last_dim_order(dim_order_4d, 4)); + EXPECT_FALSE(is_channels_last_dim_order(dim_order_5d, 5)); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp new file mode 100644 index 0000000..d9d285c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @file + * + * Demonstrates the implementation of a simple operator using the utilities in + * this package. + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::testing::TensorFactory; + +// +// A sample implementation of a PyTorch operator using the utilities in this +// package. +// + +/** + * Adds the elements of `a` and `b`, overwriting `out`. + * + * Assumes that the tensors are contiguous, are the same shape, and have the + * same dtype. CTYPE should be the C type (like `float` or `int`) that matches + * the dtype of the tensors. + */ +template +void add_tensors_impl(const Tensor& a, const Tensor& b, Tensor& out) { + ET_DCHECK(a.numel() == b.numel() && b.numel() == out.numel()); + const size_t n = a.numel(); + const auto data_a = a.const_data_ptr(); + const auto data_b = b.const_data_ptr(); + auto data_out = out.mutable_data_ptr(); + for (const auto i : c10::irange(n)) { + data_out[i] = data_a[i] + data_b[i]; + } +} + +/** + * Element-wise sum of `a` and `b`, overwriting `out`. + * + * Asserts if the tensors are not all the same dtype and shape. + */ +Tensor& add_tensors_op(const Tensor& a, const Tensor& b, Tensor& out) { + ET_CHECK_SAME_SHAPE_AND_DTYPE3(a, b, out); + +// ET_FORALL_REAL_TYPES() will call this macro for every ScalarType backed by a +// real-number C type. `ctype` will be that C type (e.g. `float`), and `dtype` +// will be the unqualified ScalarType enumeration name (e.g., `Float`). +// +// Use this to create a switch statement that dispatches to the impl template +// based on the types of the provided tensors. +#define ADD_TENSORS(ctype, dtype) \ + case ScalarType::dtype: \ + add_tensors_impl(a, b, out); \ + break; + + switch (a.scalar_type()) { + ET_FORALL_REAL_TYPES(ADD_TENSORS) + default: + ET_CHECK_MSG(false, "Unhandled dtype %hhd", a.scalar_type()); + } + +#undef ADD_TENSORS + + return out; +} + +// +// Some basic unit tests demonstrating that the operator implementation works as +// expected. +// + +TEST(OperatorImplExampleTest, AddIntTensors) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + // Destination for the sum. + Tensor out = tf.zeros(sizes); + + // Add two tensors. + add_tensors_op(tf.make(sizes, /*data=*/{1, 2, 4, 8}), tf.ones(sizes), out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf.make(sizes, /*data=*/{2, 3, 5, 9})); +} + +TEST(OperatorImplExampleTest, AddDoubleTensors) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + // Destination for the sum. + Tensor out = tf.zeros(sizes); + + // Add two tensors. + add_tensors_op( + tf.make(sizes, /*data=*/{1.1, 2.2, 4.4, 8.8}), tf.ones(sizes), out); + + // Check that it matches the expected output. + EXPECT_TENSOR_CLOSE(out, tf.make(sizes, /*data=*/{2.1, 3.2, 5.4, 9.8})); +} + +TEST(OperatorImplExampleTest, UnhandledDtypeDies) { + // add_tensors_op() doesn't handle Bool. + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + // Addends. + Tensor a = tf.make(sizes, /*data=*/{false, true, false, true}); + Tensor b = tf.make(sizes, /*data=*/{true, false, true, false}); + + // Destination for the sum. + Tensor out = tf.zeros(sizes); + + // Adding the two boolean tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} + +TEST(OpAddOutKernelTest, MismatchedInputDimsDies) { + TensorFactory tf; + + // Addends with the same number of elements but different dimensions. + Tensor a = tf.ones(/*sizes=*/{4}); + Tensor b = tf.ones(/*sizes=*/{2, 2}); + + // Destination for the sum; matches the shape of one of the inputs. + Tensor out = tf.zeros(/*sizes=*/{4}); + + // Adding the two mismatched tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} + +TEST(OpAddOutKernelTest, MismatchedInputDtypesDies) { + TensorFactory tf_int; + TensorFactory tf_float; + + const std::vector sizes = {2, 2}; + + // Addends with the same shape but different dtypes. + Tensor a = tf_int.ones(sizes); + Tensor b = tf_float.ones(sizes); + + // Destination for the sum; matches the dtype of one of the inputs. + Tensor out = tf_float.zeros(sizes); + + // Adding the two mismatched tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} + +TEST(OpAddOutKernelTest, MixingUnhandledDtypeDies) { + TensorFactory tf_int; + TensorFactory tf_bool; + + const std::vector sizes = {2, 2}; + + // Addends with the same shape but different dtypes, one of which (bool) is + // not supported by add_tensors_op(). + Tensor a = tf_int.ones(sizes); + Tensor b = tf_bool.ones(sizes); + + // Destination for the sum; matches the input with a valid dtype. + Tensor out = tf_int.zeros(sizes); + + // Adding the two mismatched tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp new file mode 100644 index 0000000..e884947 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include +#include + +using namespace ::testing; +using executorch::aten::complex; +using executorch::aten::ScalarType; +using executorch::runtime::elementSize; +using executorch::runtime::isValid; +using executorch::runtime::toString; + +TEST(ScalarTypeUtilTest, ToString) { + // Some known types. + EXPECT_STREQ(toString(ScalarType::Int), "Int"); + EXPECT_STREQ(toString(ScalarType::ComplexHalf), "ComplexHalf"); + + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + EXPECT_STREQ(toString(ScalarType::Undefined), "Undefined"); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + EXPECT_STREQ(toString(ScalarType::NumOptions), "UNKNOWN_SCALAR"); + EXPECT_STREQ(toString(static_cast(127)), "UNKNOWN_SCALAR"); + EXPECT_STREQ(toString(static_cast(-1)), "UNKNOWN_SCALAR"); +} + +TEST(ScalarTypeUtilTest, ElementSize) { + struct TestCase { + ScalarType type; + size_t expected_size; + }; + std::vector test_cases = { + {ScalarType::Byte, sizeof(uint8_t)}, + {ScalarType::Char, sizeof(int8_t)}, + {ScalarType::Short, sizeof(int16_t)}, + {ScalarType::Int, sizeof(int32_t)}, + {ScalarType::Long, sizeof(int64_t)}, + {ScalarType::Half, sizeof(executorch::aten::Half)}, + {ScalarType::Float, sizeof(float)}, + {ScalarType::Double, sizeof(double)}, + {ScalarType::ComplexHalf, + sizeof(::executorch::aten::complex<::executorch::aten::Half>)}, + {ScalarType::ComplexFloat, sizeof(::executorch::aten::complex)}, + {ScalarType::ComplexDouble, sizeof(::executorch::aten::complex)}, + {ScalarType::Bool, sizeof(bool)}, + {ScalarType::QInt8, sizeof(::executorch::aten::qint8)}, + {ScalarType::QUInt8, sizeof(::executorch::aten::quint8)}, + {ScalarType::QInt32, sizeof(::executorch::aten::qint32)}, + {ScalarType::BFloat16, sizeof(::executorch::aten::BFloat16)}, + {ScalarType::QUInt4x2, sizeof(::executorch::aten::quint4x2)}, + {ScalarType::QUInt2x4, sizeof(::executorch::aten::quint2x4)}, + }; + for (const auto& test_case : test_cases) { + EXPECT_EQ(elementSize(test_case.type), test_case.expected_size); + } +} + +TEST(ScalarTypeUtilTest, IsValidTrue) { + // Some valid types. + EXPECT_TRUE(isValid(ScalarType::Byte)); + EXPECT_TRUE(isValid(ScalarType::Float)); + EXPECT_TRUE(isValid(ScalarType::ComplexFloat)); + EXPECT_TRUE(isValid(ScalarType::Bits16)); +} + +TEST(ScalarTypeUtilTest, IsValidFalse) { + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + EXPECT_FALSE(isValid(ScalarType::Undefined)); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + EXPECT_FALSE(isValid(ScalarType::NumOptions)); + EXPECT_FALSE(isValid(static_cast(127))); + EXPECT_FALSE(isValid(static_cast(-1))); +} + +TEST(ScalarTypeUtilTest, UnknownTypeElementSizeDies) { + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + ET_EXPECT_DEATH(elementSize(ScalarType::Undefined), ""); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + ET_EXPECT_DEATH(elementSize(ScalarType::NumOptions), ""); + ET_EXPECT_DEATH(elementSize(static_cast(127)), ""); + ET_EXPECT_DEATH(elementSize(static_cast(-1)), ""); +} + +TEST(ScalarTypeUtilTest, canCastTest) { + using executorch::aten::ScalarType; + using executorch::runtime::canCast; + + // Check some common cases + + // complex to non-complex fails + ET_CHECK(!canCast(ScalarType::ComplexFloat, ScalarType::Float)); + ET_CHECK(!canCast(ScalarType::ComplexDouble, ScalarType::Double)); + + // non-complex to complex is fine + ET_CHECK(canCast(ScalarType::Float, ScalarType::ComplexFloat)); + ET_CHECK(canCast(ScalarType::Float, ScalarType::ComplexDouble)); + ET_CHECK(canCast(ScalarType::Int, ScalarType::ComplexDouble)); + + // float to integral fails + ET_CHECK(!canCast(ScalarType::Float, ScalarType::Int)); + ET_CHECK(!canCast(ScalarType::Double, ScalarType::Long)); + + // integral to float in fine + ET_CHECK(canCast(ScalarType::Int, ScalarType::Float)); + ET_CHECK(canCast(ScalarType::Long, ScalarType::Float)); + + // non-bool to bool fails + ET_CHECK(!canCast(ScalarType::Byte, ScalarType::Bool)); + ET_CHECK(!canCast(ScalarType::Int, ScalarType::Bool)); + + // bool to non-bool is fine + ET_CHECK(canCast(ScalarType::Bool, ScalarType::Byte)); + ET_CHECK(canCast(ScalarType::Bool, ScalarType::Int)); + ET_CHECK(canCast(ScalarType::Bool, ScalarType::Float)); +} + +TEST(ScalarTypeUtilTest, promoteTypesTest) { + using executorch::aten::ScalarType; + using executorch::runtime::promoteTypes; + + // Check some common cases + + EXPECT_EQ( + promoteTypes(ScalarType::Float, ScalarType::Double), ScalarType::Double); + EXPECT_EQ( + promoteTypes(ScalarType::Float, ScalarType::Short), ScalarType::Float); + + EXPECT_EQ( + promoteTypes(ScalarType::Float, ScalarType::Int), ScalarType::Float); + EXPECT_EQ( + promoteTypes(ScalarType::Long, ScalarType::Float), ScalarType::Float); + + EXPECT_EQ(promoteTypes(ScalarType::Bool, ScalarType::Bool), ScalarType::Bool); + + EXPECT_EQ(promoteTypes(ScalarType::Byte, ScalarType::Int), ScalarType::Int); + EXPECT_EQ(promoteTypes(ScalarType::Char, ScalarType::Bool), ScalarType::Char); + EXPECT_EQ(promoteTypes(ScalarType::Bool, ScalarType::Int), ScalarType::Int); + + EXPECT_EQ( + promoteTypes(ScalarType::BFloat16, ScalarType::Half), ScalarType::Float); + EXPECT_EQ( + promoteTypes(ScalarType::BFloat16, ScalarType::Bool), + ScalarType::BFloat16); +} + +template +struct promote_types_is_valid + : std::integral_constant< + bool, + (std::is_same::value || + (!executorch::runtime::is_qint_type::value && + !executorch::runtime::is_qint_type::value && + !executorch::runtime::is_bits_type::value && + !executorch::runtime::is_bits_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_barebones_unsigned_type::value && + !executorch::runtime::is_barebones_unsigned_type::value))> {}; + +template +struct CompileTimePromoteTypesTestCase { + static void testAll() { +#define CALL_TEST_ONE(cpp_type, scalar_type) \ + testOne::value>(); + ET_FORALL_SCALAR_TYPES(CALL_TEST_ONE) +#undef CALL_TEST_ONE + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + auto actual = executorch::runtime::CppTypeToScalarType< + typename executorch::runtime::promote_types:: + type>::value; + const auto scalarType1 = + executorch::runtime::CppTypeToScalarType::value; + const auto scalarType2 = + executorch::runtime::CppTypeToScalarType::value; + auto expected = executorch::runtime::promoteTypes( + scalarType1, scalarType2, half_to_float); + EXPECT_EQ(actual, expected) + << "promoting " << (int)scalarType1 << " to " << (int)scalarType2 + << " (half to float: " << half_to_float << ')'; + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + // Skip invalid case + } +}; + +TEST(ScalarTypeUtilTest, compileTypePromoteTypesTest) { +#define INSTANTIATE_TYPE_TEST(cpp_type, scalar_type) \ + CompileTimePromoteTypesTestCase::testAll(); \ + CompileTimePromoteTypesTestCase::testAll(); + + ET_FORALL_SCALAR_TYPES(INSTANTIATE_TYPE_TEST); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/targets.bzl new file mode 100644 index 0000000..2507755 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/targets.bzl @@ -0,0 +1,60 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "scalar_type_util_test", + srcs = ["scalar_type_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + ) + + runtime.cxx_test( + name = "operator_impl_example_test", + srcs = ["operator_impl_example_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "dim_order_util_test", + srcs = ["dim_order_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + runtime.cxx_test( + name = "tensor_util_test" + aten_suffix, + srcs = ["tensor_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "tensor_shape_to_c_string_test", + srcs = ["tensor_shape_to_c_string_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp new file mode 100644 index 0000000..8059360 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +#include + +#include +#include +#include +#include + +using executorch::runtime::kTensorDimensionLimit; +using executorch::runtime::Span; +using executorch::runtime::tensor_shape_to_c_string; +using executorch::runtime::internal::kMaximumPrintableTensorShapeElement; + +TEST(TensorShapeToCStringTest, Basic) { + std::array sizes = {123, 456, 789}; + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + EXPECT_STREQ(str.data(), "(123, 456, 789)"); + + std::array one_size = {1234567890}; + str = tensor_shape_to_c_string(Span( + one_size.data(), one_size.size())); + EXPECT_STREQ(str.data(), "(1234567890)"); +} + +TEST(TensorShapeToCStringTest, NegativeItems) { + std::array sizes = {-1, -3, -2, 4}; + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + EXPECT_STREQ(str.data(), "(ERR, ERR, ERR, 4)"); + + std::array one_size = {-1234567890}; + str = tensor_shape_to_c_string(Span( + one_size.data(), one_size.size())); + if constexpr (std::numeric_limits::is_signed) { + EXPECT_STREQ(str.data(), "(ERR)"); + } else { + EXPECT_EQ(str.data(), "(" + std::to_string(one_size[0]) + ")"); + } +} +TEST(TensorShapeToCStringTest, MaximumElement) { + std::array sizes = { + 123, std::numeric_limits::max(), 789}; + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + std::ostringstream expected; + expected << '('; + for (const auto elem : sizes) { + expected << elem << ", "; + } + auto expected_str = expected.str(); + expected_str.pop_back(); + expected_str.back() = ')'; + EXPECT_EQ(str.data(), expected_str); +} + +TEST(TensorShapeToCStringTest, MaximumLength) { + std::array sizes; + std::fill(sizes.begin(), sizes.end(), kMaximumPrintableTensorShapeElement); + + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + + std::ostringstream expected; + expected << '(' << kMaximumPrintableTensorShapeElement; + for (int ii = 0; ii < kTensorDimensionLimit - 1; ++ii) { + expected << ", " << kMaximumPrintableTensorShapeElement; + } + expected << ')'; + auto expected_str = expected.str(); + + EXPECT_EQ(expected_str, str.data()); +} + +TEST(TensorShapeToCStringTest, ExceedsDimensionLimit) { + std::array sizes; + std::fill(sizes.begin(), sizes.end(), kMaximumPrintableTensorShapeElement); + + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + + EXPECT_STREQ(str.data(), "(ERR: tensor ndim exceeds limit)"); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_util_test.cpp new file mode 100644 index 0000000..842f234 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/exec_aten/util/test/tensor_util_test.cpp @@ -0,0 +1,608 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::extract_scalar_tensor; +using executorch::runtime::testing::TensorFactory; + +class TensorUtilTest : public ::testing::Test { + protected: + // Factories for tests to use. These will be torn down and recreated for each + // test case. + TensorFactory tf_byte_; + TensorFactory tf_int_; + TensorFactory tf_float_; + TensorFactory tf_double_; + TensorFactory tf_bool_; + + void SetUp() override { + // As some of these tests cause ET_LOG to be called, the PAL must be + // initialized first by calling runtime_init(); + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorUtilTest, IdentityChecks) { + Tensor t = tf_byte_.ones({2, 2}); + + // A tensor is the same shape as itself. + ET_CHECK_SAME_SHAPE2(t, t); + ET_CHECK_SAME_SHAPE3(t, t, t); + + // A tensor is the same dtype as itself. + ET_CHECK_SAME_DTYPE2(t, t); + ET_CHECK_SAME_DTYPE3(t, t, t); + + // A tensor is the same shape and dtype as itself. + ET_CHECK_SAME_SHAPE_AND_DTYPE2(t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE3(t, t, t); +} + +TEST_F(TensorUtilTest, SameShapesDifferentDtypes) { + // Three different tensors with the same shape but different dtypes. + Tensor a = tf_byte_.ones({2, 2}); + Tensor b = tf_int_.ones({2, 2}); + Tensor c = tf_float_.ones({2, 2}); + + // The tensors have the same shapes. + ET_CHECK_SAME_SHAPE2(a, b); + ET_CHECK_SAME_SHAPE3(a, b, c); + + // Not the same dtypes. Check both positions. + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE2(b, a), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(b, a), ""); + + // Test with a mismatching tensor in all positions, where the other two agree. + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE3(a, b, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE3(b, a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE3(b, b, a), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(a, b, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, b, a), ""); +} + +TEST_F(TensorUtilTest, DifferentShapesSameDtypes) { + // Two different tensors with different shapes but the same dtypes, + // dimensions, and number of elements. + Tensor a = tf_int_.ones({1, 4}); + Tensor b = tf_int_.ones({2, 2}); + // A third tensor with the same shape and dtype as b. + Tensor b2 = tf_int_.ones({2, 2}); + + // The different tensors are not the same shape. Check both positions. + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE2(b, a), ""); + + // Test with the different tensor in all positions. + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE3(a, b, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE3(b, a, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE3(b, b2, a), ""); + + // They are the same dtypes. + ET_CHECK_SAME_DTYPE2(a, b); + ET_CHECK_SAME_DTYPE2(b, a); + ET_CHECK_SAME_DTYPE3(a, b, b2); + ET_CHECK_SAME_DTYPE3(b, a, b2); + ET_CHECK_SAME_DTYPE3(b, b2, a); + + // But not the same shape-and-dtype. + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(b, a), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(a, b, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, a, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, b2, a), ""); +} + +TEST_F(TensorUtilTest, ZeroDimensionalTensor) { + // Create a zero-dimensional tensor. + Tensor t = tf_int_.ones({}); + + // Demonstrate that the tensor has zero dimensions. + EXPECT_EQ(t.dim(), 0); + + // Make sure nothing blows up when the tensor has zero dimensions. + ET_CHECK_SAME_SHAPE2(t, t); + ET_CHECK_SAME_SHAPE3(t, t, t); + ET_CHECK_SAME_DTYPE2(t, t); + ET_CHECK_SAME_DTYPE3(t, t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE2(t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE3(t, t, t); +} + +TEST_F(TensorUtilTest, EmptyTensor) { + // Create a tensor with no elements by providing a zero-width dimension. + Tensor t = tf_int_.ones({0}); + + // Demonstrate that the tensor has no elements. + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + + // Make sure nothing blows up when the tensor has no elements. + ET_CHECK_SAME_SHAPE2(t, t); + ET_CHECK_SAME_SHAPE3(t, t, t); + ET_CHECK_SAME_DTYPE2(t, t); + ET_CHECK_SAME_DTYPE3(t, t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE2(t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE3(t, t, t); +} + +TEST_F(TensorUtilTest, GetLeadingDimsSmokeTest) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // getLeadingDims(t, 1) => t.size(0) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 1), 2); + + // getLeadingDims(t, 2) => t.size(0) * t.size(1) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 2), 6); + + // getLeadingDims(t, 3) => t.size(0) * t.size(1) * t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 3), 24); +} + +TEST_F(TensorUtilTest, GetLeadingDimsInputOutOfBoundDies) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // dim needs to be in the range [0, t.dim()] + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, -2), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, -1), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 4), ""); +} + +TEST_F(TensorUtilTest, GetTrailingDimsSmokeTest) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // getTrailingDims(t, 1) => t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 1), 4); + + // getTrailingDims(t, 0) => t.size(1) * t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 0), 12); + + // getTrailingDims(t, -1) => t.size(0) * t.size(1) * t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, -1), 24); +} + +TEST_F(TensorUtilTest, GetTrailingDimsInputOutOfBoundDies) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // dim needs to be in the range [-1, t.dim() - 1) + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, -2), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 3), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 4), ""); +} + +TEST_F(TensorUtilTest, ContiguousCheckSupported) { + std::vector data = {1, 2, 3, 4, 5, 6}; + std::vector sizes = {1, 2, 3}; + + Tensor t_contiguous = tf_float_.make(sizes, data); + + // t_incontiguous = tf.make(sizes=(1, 2, 3)).permute(2, 0, 1) + // {3, 1, 2} + // changed stride {1, 3, 1} => {2, 1, 2} because {1, 3, 1} is not + // the right value. + Tensor t_incontiguous = tf_float_.make(sizes, data, /*strides=*/{2, 1, 2}); + + // Assert t_contiguous is contiguous. + ET_CHECK_CONTIGUOUS(t_contiguous); + + // Assert t_incontiguous is incontiguous. + ET_EXPECT_DEATH(ET_CHECK_CONTIGUOUS(t_incontiguous), ""); +} + +TEST_F(TensorUtilTest, CheckSameContiguousStrideSupported) { + // Tensors in the following list share same stride. + std::vector same_stride_tensor_list = { + tf_float_.ones(/*sizes=*/{1, 2, 3, 4}), + tf_byte_.ones(/*sizes=*/{4, 2, 3, 4}), + tf_int_.ones(/*sizes=*/{10, 2, 3, 4}), + tf_float_.make( + /*sizes=*/{0, 2, 3, 4}, /*data=*/{}, /*strides=*/{24, 12, 4, 1})}; + + // different_stride = tensor(size=(0,2,3,4)).permute(0, 2, 3, 1) + // {0, 3, 4, 2} + // stride for (0, 2, 3, 4) with permute = (24, 1, 8, 2) + // So change stride from {24, 3, 1, 6} => {24, 1, 8, 2} + Tensor different_stride = tf_float_.make( + /*sizes=*/{0, 2, 3, 4}, /*data=*/{}, /*strides=*/{24, 1, 8, 2}); + + // Any two tensors in `same_stride_tensor_list` have same strides. The two + // could contain duplicate tensors. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + for (const auto j : c10::irange(i, same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + auto tj = same_stride_tensor_list[j]; + ET_CHECK_SAME_STRIDES2(ti, tj); + } + } + + // Any tensor in `same_stride_tensor_list` shall not have same stride with + // `different_stride`. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + ET_EXPECT_DEATH(ET_CHECK_SAME_STRIDES2(ti, different_stride), ""); + } + + // Any three tensors in same_stride_tensor_list have same strides. The three + // could contain duplicate tensors. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + for (const auto j : c10::irange(i, same_stride_tensor_list.size())) { + for (const auto k : c10::irange(j, same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + auto tj = same_stride_tensor_list[j]; + auto tk = same_stride_tensor_list[k]; + ET_CHECK_SAME_STRIDES3(ti, tj, tk); + } + } + } + + // Any two tensors in same_stride_tensor_list shall not have same strides with + // `different_stride`. The two could contain duplicate tensors. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + for (const auto j : c10::irange(i, same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + auto tj = same_stride_tensor_list[j]; + ET_EXPECT_DEATH(ET_CHECK_SAME_STRIDES3(ti, tj, different_stride), ""); + } + } +} + +TEST_F(TensorUtilTest, ExtractIntScalarTensorSmoke) { + Tensor t = tf_int_.ones({1}); + bool ok; +#define CASE_INT_DTYPE(ctype, unused) \ + ctype out_##ctype; \ + ok = extract_scalar_tensor(t, &out_##ctype); \ + ASSERT_TRUE(ok); \ + EXPECT_EQ(out_##ctype, 1); + + ET_FORALL_INT_TYPES(CASE_INT_DTYPE); +#undef CASE_INT_DTYPE +} + +TEST_F(TensorUtilTest, ExtractFloatScalarTensorFloatingTypeSmoke) { + Tensor t = tf_float_.ones({1}); + bool ok; +#define CASE_FLOAT_DTYPE(ctype, unused) \ + ctype out_##ctype; \ + ok = extract_scalar_tensor(t, &out_##ctype); \ + ASSERT_TRUE(ok); \ + EXPECT_EQ(out_##ctype, 1.0); + + ET_FORALL_FLOAT_TYPES(CASE_FLOAT_DTYPE); +#undef CASE_FLOAT_DTYPE +} + +TEST_F(TensorUtilTest, ExtractFloatScalarTensorIntegralTypeSmoke) { + Tensor t = tf_int_.ones({1}); + bool ok; +#define CASE_FLOAT_DTYPE(ctype, unused) \ + ctype out_##ctype; \ + ok = extract_scalar_tensor(t, &out_##ctype); \ + ASSERT_TRUE(ok); \ + EXPECT_EQ(out_##ctype, 1.0); + + ET_FORALL_INT_TYPES(CASE_FLOAT_DTYPE); +#undef CASE_FLOAT_DTYPE +} + +TEST_F(TensorUtilTest, ExtractBoolScalarTensorSmoke) { + Tensor t = tf_bool_.ones({1}); + bool out; + bool ok; + ok = extract_scalar_tensor(t, &out); + ASSERT_TRUE(ok); + EXPECT_EQ(out, true); +} + +TEST_F(TensorUtilTest, FloatScalarTensorStressTests) { + float value; + bool ok; + + // Case: Positive Infinity + Tensor t_pos_inf = tf_double_.make({1}, {INFINITY}); + ok = extract_scalar_tensor(t_pos_inf, &value); + EXPECT_TRUE(ok); + EXPECT_TRUE(std::isinf(value)); + + // Case: Negative Infinity + Tensor t_neg_inf = tf_double_.make({1}, {-INFINITY}); + ok = extract_scalar_tensor(t_neg_inf, &value); + EXPECT_TRUE(ok); + EXPECT_TRUE(std::isinf(value)); + + // Case: Not a Number (NaN) - ex: sqrt(-1.0) + Tensor t_nan = tf_double_.make({1}, {NAN}); + ok = extract_scalar_tensor(t_nan, &value); + EXPECT_TRUE(ok); + EXPECT_TRUE(std::isnan(value)); +} + +TEST_F(TensorUtilTest, IntScalarTensorNotIntegralTypeFails) { + Tensor t = tf_float_.ones({1}); + int64_t out; + // Fails since tensor is floating type but attempting to extract integer + // value. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, FloatScalarTensorNotFloatingTypeFails) { + Tensor t = tf_bool_.ones({1}); + double out; + // Fails since tensor is boolean type but attempting to extract float value. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, IntTensorNotScalarFails) { + Tensor t = tf_int_.ones({2, 3}); + int64_t out; + // Fails since tensor has multiple dims and values. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, FloatTensorNotScalarFails) { + Tensor t = tf_float_.ones({2, 3}); + double out; + // Fails since tensor has multiple dims and values. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, IntTensorOutOfBoundFails) { + Tensor t = tf_int_.make({1}, {256}); + int8_t out; + // Fails since 256 is out of bounds for `int8_t` (-128 to 127). + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, FloatTensorOutOfBoundFails) { + Tensor t = tf_double_.make({1}, {1.0}); // Placeholder value. + float out; + bool ok; + +#define CASE_FLOAT(value) \ + t = tf_double_.make({1}, {value}); \ + ok = extract_scalar_tensor(t, &out); \ + EXPECT_FALSE(ok); + + // Float tensor can't handle double's largest negative value (note the use of + // `lowest` rather than `min`). + CASE_FLOAT(std::numeric_limits::lowest()); + + // Float tensor can't handle double's largest positive value. + CASE_FLOAT(std::numeric_limits::max()); + +#undef CASE_FLOAT +} + +TEST_F(TensorUtilTest, BoolScalarTensorNotBooleanTypeFails) { + Tensor c = tf_byte_.ones({1}); + bool out; + // Fails since tensor is integral type but attempting to extract boolean + // value. + bool ok = extract_scalar_tensor(c, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, BoolTensorNotScalarFails) { + Tensor c = tf_bool_.ones({2, 3}); + bool out; + // Fails since tensor has multiple dims and values. + bool ok = extract_scalar_tensor(c, &out); + EXPECT_FALSE(ok); +} + +// +// Tests for utility functions that check tensor attributes +// + +TEST_F(TensorUtilTest, TensorIsRankTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensor_is_rank; + Tensor a = tf_float_.ones({2, 3, 5}); + + EXPECT_TRUE(tensor_is_rank(a, 3)); + EXPECT_FALSE(tensor_is_rank(a, 0)); + EXPECT_FALSE(tensor_is_rank(a, 5)); +} + +TEST_F(TensorUtilTest, TensorHasDimTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensor_has_dim; + Tensor a = tf_float_.ones({2, 3, 5}); + + EXPECT_TRUE(tensor_has_dim(a, 2)); + EXPECT_TRUE(tensor_has_dim(a, 1)); + EXPECT_TRUE(tensor_has_dim(a, 0)); + EXPECT_TRUE(tensor_has_dim(a, -1)); + EXPECT_TRUE(tensor_has_dim(a, -2)); + EXPECT_TRUE(tensor_has_dim(a, -3)); + + EXPECT_FALSE(tensor_has_dim(a, -4)); + EXPECT_FALSE(tensor_has_dim(a, 3)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameDtypeTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_dtype; + Tensor a = tf_float_.ones({2, 3}); + Tensor b = tf_float_.ones({2, 3}); + Tensor c = tf_float_.ones({3, 3}); + Tensor d = tf_int_.ones({4, 3}); + + EXPECT_TRUE(tensors_have_same_dtype(a, b)); + EXPECT_FALSE(tensors_have_same_dtype(a, d)); + EXPECT_TRUE(tensors_have_same_dtype(a, b, c)); + EXPECT_FALSE(tensors_have_same_dtype(a, b, d)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameSizeAtDimTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_size_at_dims; + Tensor a = tf_float_.ones({2, 3, 4, 5}); + Tensor b = tf_float_.ones({5, 4, 3, 2}); + + EXPECT_TRUE(tensors_have_same_size_at_dims(a, 0, b, 3)); + EXPECT_TRUE(tensors_have_same_size_at_dims(a, 1, b, 2)); + EXPECT_FALSE(tensors_have_same_size_at_dims(a, 1, b, 0)); + EXPECT_FALSE(tensors_have_same_size_at_dims(a, 4, b, 0)); + EXPECT_FALSE(tensors_have_same_size_at_dims(a, 2, b, 3)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameShapeTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_shape; + Tensor a = tf_float_.ones({2, 3}); + Tensor b = tf_int_.ones({2, 3}); + Tensor c = tf_byte_.ones({2, 3}); + Tensor d = tf_double_.ones({3, 2}); + Tensor e = tf_bool_.ones({3, 2}); + + EXPECT_TRUE(tensors_have_same_shape(a, b)); + EXPECT_FALSE(tensors_have_same_shape(a, d)); + EXPECT_TRUE(tensors_have_same_shape(d, e)); + EXPECT_TRUE(tensors_have_same_shape(a, b, c)); + EXPECT_FALSE(tensors_have_same_shape(a, b, d)); + EXPECT_FALSE(tensors_have_same_shape(a, d, e)); + + Tensor scalar_a = tf_float_.ones({1, 1}); + Tensor scalar_b = tf_double_.ones({1}); + Tensor scalar_c = tf_int_.ones({1, 1, 1, 1}); + + EXPECT_TRUE(tensors_have_same_shape(scalar_a, scalar_b)); + EXPECT_TRUE(tensors_have_same_shape(scalar_a, scalar_b, scalar_c)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameShapeAndDtypeTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_shape_and_dtype; + Tensor a = tf_float_.ones({2, 3}); + Tensor b = tf_float_.ones({2, 3}); + Tensor c = tf_float_.ones({2, 3}); + Tensor d = tf_double_.ones({2, 3}); + Tensor e = tf_float_.ones({3, 2}); + + EXPECT_TRUE(tensors_have_same_shape_and_dtype(a, b)); + EXPECT_FALSE(tensors_have_same_shape_and_dtype(a, d)); + EXPECT_TRUE(tensors_have_same_shape_and_dtype(a, b, c)); + EXPECT_FALSE(tensors_have_same_shape_and_dtype(a, b, d)); + EXPECT_FALSE(tensors_have_same_shape_and_dtype(a, d, e)); + + Tensor scalar_a = tf_float_.ones({1, 1}); + Tensor scalar_b = tf_float_.ones({1}); + Tensor scalar_c = tf_float_.ones({1, 1, 1, 1}); + + EXPECT_TRUE(tensors_have_same_shape_and_dtype(scalar_a, scalar_b)); + EXPECT_TRUE(tensors_have_same_shape_and_dtype(scalar_a, scalar_b, scalar_c)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameStridesTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_strides; + Tensor a = tf_float_.full_channels_last({4, 5, 2, 3}, 1); + Tensor b = tf_float_.full_channels_last({4, 5, 2, 3}, 2); + Tensor c = tf_float_.full_channels_last({4, 5, 2, 3}, 3); + Tensor d = tf_double_.ones({4, 5, 2, 3}); + Tensor e = tf_float_.ones({4, 5, 2, 3}); + + EXPECT_TRUE(tensors_have_same_strides(a, b)); + EXPECT_FALSE(tensors_have_same_strides(a, d)); + EXPECT_TRUE(tensors_have_same_strides(a, b, c)); + EXPECT_FALSE(tensors_have_same_strides(a, b, d)); + EXPECT_FALSE(tensors_have_same_strides(a, d, e)); +} + +TEST_F(TensorUtilTest, TensorIsContiguous) { + using executorch::ET_RUNTIME_NAMESPACE::tensor_is_contiguous; + // Note that the strides.size() == 0 case is not tested, since + Tensor a = tf_float_.full_channels_last({4, 5, 2, 3}, 1); + Tensor b = tf_float_.ones({4, 5, 2, 3}); + Tensor c = tf_float_.full_channels_last({1, 1, 1, 1}, 1); + Tensor d = tf_float_.ones({}); + + EXPECT_FALSE(tensor_is_contiguous(a)); + EXPECT_TRUE(tensor_is_contiguous(b)); + EXPECT_TRUE(tensor_is_contiguous(c)); + EXPECT_TRUE(tensor_is_contiguous(d)); +} + +TEST_F(TensorUtilTest, ResizeZeroDimTensor) { + Tensor a = tf_float_.ones({}); + + EXPECT_EQ( + executorch::ET_RUNTIME_NAMESPACE::resize_tensor(a, {}), + executorch::runtime::Error::Ok); + EXPECT_EQ(a.dim(), 0); +} + +TEST_F(TensorUtilTest, SameDimOrderContiguous) { + using namespace torch::executor; + // Three different tensors with the same shape and same dim order + // ([0, 1, 2, 3]), but different dtypes and contents. + std::vector sizes = {3, 5, 2, 1}; + Tensor a = tf_byte_.ones(sizes); + Tensor b = tf_int_.zeros(sizes); + Tensor c = tf_float_.full(sizes, 0.1); + + // The tensors have the same dim order, should pass the following checks. + EXPECT_TRUE(tensors_have_same_dim_order(a, b)); + EXPECT_TRUE(tensors_have_same_dim_order(b, a)); + EXPECT_TRUE(tensors_have_same_dim_order(a, b, c)); + EXPECT_TRUE(tensors_have_same_dim_order(b, c, a)); + EXPECT_TRUE(tensors_have_same_dim_order(c, a, b)); +} + +TEST_F(TensorUtilTest, SameDimOrderChannelsLast) { + using namespace torch::executor; + // Three different tensors with the same shape and same dim order + // ([0, 2, 3, 1]), but different dtypes and contents. + std::vector sizes = {3, 5, 2, 1}; + Tensor a = tf_byte_.full_channels_last(sizes, 1); + Tensor b = tf_int_.full_channels_last(sizes, 0); + Tensor c = tf_float_.full_channels_last(sizes, 0.1); + + // The tensors have the same dim order, should pass the following checks. + EXPECT_TRUE(tensors_have_same_dim_order(a, b)); + EXPECT_TRUE(tensors_have_same_dim_order(b, a)); + EXPECT_TRUE(tensors_have_same_dim_order(a, b, c)); + EXPECT_TRUE(tensors_have_same_dim_order(b, c, a)); + EXPECT_TRUE(tensors_have_same_dim_order(c, a, b)); +} + +TEST_F(TensorUtilTest, SameShapesDifferentDimOrder) { + using namespace torch::executor; + // Three different tensors with the same shape but different dtypes and + // contents, where b and c have the same dim order ([0, 2, 3, 1]) while a is + // different ([0, 1, 2, 3]). + std::vector sizes = {3, 5, 2, 1}; + Tensor a = tf_byte_.ones(sizes); + Tensor b = tf_int_.full_channels_last(sizes, 0); + Tensor c = tf_float_.full_channels_last(sizes, 0.1); + + // Not the same dim order. Chec + EXPECT_FALSE(tensors_have_same_dim_order(a, b)); + EXPECT_FALSE(tensors_have_same_dim_order(b, a)); + + // Test with a mismatching tensor in all positions, where the other two agree. + EXPECT_FALSE(tensors_have_same_dim_order(a, b, c)); + EXPECT_FALSE(tensors_have_same_dim_order(a, c, b)); + EXPECT_FALSE(tensors_have_same_dim_order(c, b, a)); +} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/freeable_buffer.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/freeable_buffer.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/freeable_buffer.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/freeable_buffer.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/function_ref.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/function_ref.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/function_ref.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/function_ref.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/hierarchical_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/hierarchical_allocator.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/hierarchical_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/hierarchical_allocator.h index d41b98f..c5dd624 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/hierarchical_allocator.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/hierarchical_allocator.h @@ -9,7 +9,6 @@ #pragma once #include -#include #include #include @@ -59,9 +58,8 @@ class HierarchicalAllocator final { size_t offset_bytes, size_t size_bytes) { // Check for integer overflow in offset_bytes + size_bytes. - size_t end_bytes = 0; ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows(offset_bytes, size_bytes, &end_bytes), + size_bytes <= SIZE_MAX - offset_bytes, InvalidArgument, "Integer overflow in offset_bytes (%" ET_PRIsize_t ") + size_bytes (%" ET_PRIsize_t ")", @@ -75,7 +73,7 @@ class HierarchicalAllocator final { buffers_.size()); Span buffer = buffers_[memory_id]; ET_CHECK_OR_RETURN_ERROR( - end_bytes <= buffer.size(), + offset_bytes + size_bytes <= buffer.size(), MemoryAllocationFailed, "offset_bytes (%" ET_PRIsize_t ") + size_bytes (%" ET_PRIsize_t ") >= allocator size (%" ET_PRIsize_t diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/memory_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/memory_allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/memory_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/memory_allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/named_data_map.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/named_data_map.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/named_data_map.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/named_data_map.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/bfloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/bfloat16.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/bfloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/bfloat16.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/bfloat16_math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/bfloat16_math.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/bfloat16_math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/bfloat16_math.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/bits_types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/bits_types.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/bits_types.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/bits_types.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/README.md new file mode 100644 index 0000000..c0fa01d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/README.md @@ -0,0 +1,20 @@ +This directory contains header files from `c10` in PyTorch core that +need to be used in ExecuTorch core. They are copied here rather than +being found through the torch pip package to keep the core build +hermetic for embedded use cases. The headers should be exact copies +from PyTorch core; if they are out of sync, please send a PR! + +We added an extra c10 directory so that `runtime/core/portable_type/c10` +can be the directory to put on your include path, rather than +`runtime/core/portable_type`, because using `runtime/core/portable_type` +would cause all headers in that directory to be includeable with +`#include `. In particular, that includes +`runtime/core/portable_type/complex.h`, which would shadow the C99 +`complex.h` standard header. + +`torch/headeronly` has been added as an extra "even more bottom of +stack" directory in PyTorch, so we have to add it to our sync +here. The extra "stutter" c10 directory causing `c10/torch/standlone` +is unfortunately awkward; perhaps we can rename the top-level +directory to `pytorch_embedded_mirror` when we have extra time to work +through CI failures. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/macros/Export.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/targets.bzl new file mode 100644 index 0000000..33a5580 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/targets.bzl @@ -0,0 +1,139 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def get_preprocessor_flags(is_fbcode): + flags = ["-DSTANDALONE_TORCH_HEADER"] + if runtime.is_oss: + return flags + # AT_BUILD_ARM_VEC256_WITH_SLEEF is off on Windows because Sleef + # is off on Windows per get_sleef_deps below. + arm64_flags = select({ + "DEFAULT": [ + "-DCPU_CAPABILITY_DEFAULT", + "-DAT_BUILD_ARM_VEC256_WITH_SLEEF", + ], + "ovr_config//os:windows": ["-DCPU_CAPABILITY_DEFAULT"], + }) + + x86_avx2_flags = [ + "-DCPU_CAPABILITY_AVX2", + "-DHAVE_AVX2_CPU_DEFINITION", + ] + default_flags = [ + "-DCPU_CAPABILITY_DEFAULT", + ] + fbcode_flags = select({ + "ovr_config//cpu:x86_64": x86_avx2_flags, + "ovr_config//cpu:arm64": arm64_flags, + "DEFAULT": default_flags, + }) + non_fbcode_flags = select({ + "ovr_config//cpu/x86:avx2": x86_avx2_flags, + "ovr_config//cpu:arm64": arm64_flags, + "DEFAULT": default_flags, + }) + return flags + ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"] + (fbcode_flags if is_fbcode else non_fbcode_flags) + +def get_sleef_deps(): + if runtime.is_oss: + return [] + return select({ + "DEFAULT": select({ + "DEFAULT": [], + "ovr_config//cpu:x86_64": [ + "fbsource//third-party/sleef:sleef", + ], + "ovr_config//cpu:arm64": [ + "fbsource//third-party/sleef:sleef", + ], + }), + "ovr_config//os:windows": [ + "fbsource//third-party/sleef:sleef", + ], + }) + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "aten_headers_for_executorch", + srcs = [], + visibility = ["PUBLIC"], + # select() on ovr_config//runtime:fbcode does not work + # properly in all cases. I have seen + # //xplat/executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch + # pass such a select in (at least) arvr mode. Going back to + # fbcode_exported_deps accordingly. + exported_deps = select({ + "DEFAULT": [], + "ovr_config//cpu:arm64": [ + "fbsource//third-party/sleef:sleef", + ] if not runtime.is_oss else [], + }), + xplat_exported_deps = [ + "fbsource//xplat/caffe2:aten_header", + "fbsource//xplat/caffe2/c10:c10_headers", + ] + select({ + "DEFAULT": ["fbsource//xplat/caffe2:generated_aten_config_header"], + "ovr_config//build_mode:arvr_mode": ["fbsource//xplat/caffe2:ovrsource_aten_Config.h"], + }) + get_sleef_deps(), + fbcode_exported_deps = ([ + "//caffe2:aten-headers-cpu", + "//caffe2:generated-config-header", + "//caffe2/c10:c10_headers", + ] + get_sleef_deps()) if not runtime.is_oss else [], + exported_preprocessor_flags = get_preprocessor_flags(is_fbcode=False) + + ([] if runtime.is_oss else ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"]), + fbcode_exported_preprocessor_flags = get_preprocessor_flags(is_fbcode=True) + + ([] if runtime.is_oss else ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"]), + ) + + if runtime.is_oss: + runtime.cxx_library( + name = "c10", + header_namespace = "c10", + exported_headers = [ + "macros/Export.h", + "macros/Macros.h", + "util/BFloat16.h", + "util/BFloat16-inl.h", + "util/BFloat16-math.h", + "util/Half.h", + "util/Half-inl.h", + "util/TypeSafeSignMath.h", + "util/bit_cast.h", + "util/complex.h", + "util/complex_math.h", + "util/complex_utils.h", + "util/floating_point_utils.h", + "util/irange.h", + "util/llvmMathExtras.h", + "util/overflows.h", + "util/safe_numerics.h", + ], + exported_preprocessor_flags = [ + "-DC10_USING_CUSTOM_GENERATED_MACROS", + ] + ([] if runtime.is_oss else [ + "-DC10_USE_GLOG", + "-DC10_USE_MINIMAL_GLOG", + ]), + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/torch/headeronly:torch_headeronly", + ] + select({ + "DEFAULT": [], + # Half-inl.h depends on vec_half.h from ATen, but only when building for x86. + "ovr_config//cpu:x86_64": [ + ":aten_headers_for_executorch", + ], + }), + ) + else: + runtime.cxx_library( + name = "c10", + exported_deps = [":aten_headers_for_executorch"], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16-math.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/BFloat16.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/Half-inl.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/Half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/bit_cast.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/complex_math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/complex_math.h similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/complex_math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/complex_math.h index d369df5..2b59102 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/complex_math.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/complex_math.h @@ -86,41 +86,6 @@ C10_HOST_DEVICE inline c10::complex pow( #endif } -// Regression in ROCm 7.2. See https://github.com/ROCm/rocm-libraries/pull/3836. -// Specialized version for complex on AMD GPUs to use FMA-based -// multiplication -#if defined(__HIPCC__) -namespace detail { -// FMA-aware complex multiplication for float precision on AMD GPUs. -// This prevents SLP vectorizer from breaking FMA formation, which causes -// numerical precision loss in complex arithmetic. -// The issue occurs when vectorizer packs scalar multiplies before backend -// can form FMA instructions, resulting in double rounding instead of single. -C10_HOST_DEVICE inline thrust::complex complex_mul_fma( - thrust::complex a, - thrust::complex b) { - // Complex multiplication: (a.r + a.i*i) * (b.r + b.i*i) - // = (a.r*b.r - a.i*b.i) + (a.r*b.i + a.i*b.r)*i - // Using __builtin_fmaf ensures FMA at source level: - // real: a.r*b.r + (-(a.i*b.i)) = FMA(a.r, b.r, -(a.i*b.i)) - // imag: a.i*b.r + a.r*b.i = FMA(a.r, b.i, a.i*b.r) - float real_part = __builtin_fmaf(a.real(), b.real(), -(a.imag() * b.imag())); - float imag_part = __builtin_fmaf(a.real(), b.imag(), a.imag() * b.real()); - return thrust::complex(real_part, imag_part); -} -} // namespace detail - -template <> -C10_HOST_DEVICE inline c10::complex pow( - const c10::complex& x, - const c10::complex& y) { - auto log_x = thrust::log(static_cast>(x)); - auto y_log_x = - detail::complex_mul_fma(static_cast>(y), log_x); - return static_cast>(thrust::exp(y_log_x)); -} -#endif - template C10_HOST_DEVICE inline c10::complex pow( const c10::complex& x, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/complex_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/complex_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/complex_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/complex_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/floating_point_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/irange.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/overflows.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/overflows.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/overflows.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/overflows.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/safe_numerics.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/safe_numerics.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/c10/util/safe_numerics.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/c10/util/safe_numerics.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/TARGETS new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/TARGETS @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/macros/Export.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/macros/Export.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h index 14b26c1..8dd2541 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/macros/Export.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h @@ -130,6 +130,14 @@ #define TORCH_CUDA_CU_API C10_IMPORT #endif +#if defined(TORCH_HIP_BUILD_MAIN_LIB) +#define TORCH_HIP_CPP_API C10_EXPORT +#define TORCH_HIP_API C10_EXPORT +#else +#define TORCH_HIP_CPP_API C10_IMPORT +#define TORCH_HIP_API C10_IMPORT +#endif + #if defined(TORCH_XPU_BUILD_MAIN_LIB) #define TORCH_XPU_API C10_EXPORT #else diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h index cef99df..63aa0d2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h @@ -325,88 +325,41 @@ constexpr uint32_t CUDA_THREADS_PER_BLOCK_FALLBACK = 256; #define C10_HIP_HOST_DEVICE #endif +#if defined(USE_ROCM) // C10_WARP_SIZE is only allowed for device code. -// Host code dynamically-sized launch configs _must_ use at::cuda::warp_size(). -// Host or device statically-sized arrays _must_ use either -// C10_WARP_SIZE_UPPER_BOUND or C10_WARP_SIZE_LOWER_BOUND, as needed. -// +// Host code _must_ use at::cuda::warp_size() // HIP header used to define warpSize as a constexpr that was either 32 or 64 // depending on the target device, and then always set it to 64 for host code. -// For a time, that allowed C10_WARP_SIZE to be defined like so: -// -// #ifdef USE_ROCM -// #define C10_WARP_SIZE warpSize -// #else -// #define C10_WARP_SIZE 32 -// #endif -// -// In ROCm 7, warpSize is no longer constexpr, matching CUDA behavior. -// We can now only use warpSize for C10_WARP_SIZE in device code and this is -// enforced by using __device__ in its definition. In host code where -// C10_WARP_SIZE was previously used as a compile-time constant, this will now -// cause a compile-time error. -// -// If an array was previously expected to be sized at compile-time using -// C10_WARP_SIZE, users must now use either C10_WARP_SIZE_UPPER_BOUND or -// C10_WARP_SIZE_LOWER_BOUND depending on the situation. -// -// If C10_WARP_SIZE was previously used to determine kernel launch sizes, users -// must now use at::cuda::warp_size() for the dynamic runtime query. -// -// Unfortunately, C10_WARP_SIZE has been public and available for both host and -// device since approximately 2019, so forcing it to be device-only would break -// existing code in the wild. -#if defined(USE_ROCM) +// Host pass of HIP compiler needs C10_WARP_SIZE defined to _something_ so we +// set it to something unreasonable to trigger obvious host code errors. + namespace at::cuda { TORCH_CUDA_CPP_API int warp_size(); } -#if defined(__HIPCC__) -static __host__ inline int C10_WARP_SIZE_INTERNAL() { +#ifdef __HIPCC__ +static inline int __host__ C10_WARP_SIZE_INTERNAL() { return at::cuda::warp_size(); } -// NOTE: __device__ C10_WARP_SIZE_INTERNAL -// For __SPIRV__, we must use dynamic warpSize. When not targeting __SPIRV__, -// we can use constexpr. This matches prior behavior. We preserve this for -// backward compatibility instead of forcing old code to use dynamic warpSize -// and losing constexpr. However, compiling for --offload-arch=amdgcnspirv -// could expose where C10_WARP_SIZE was used incorrectly where the dynamic -// warpSize is not allowed. -#if defined(__SPIRV__) -static __device__ inline int C10_WARP_SIZE_INTERNAL() { - return warpSize; -} -#else // __SPIRV__ -static __device__ inline constexpr int C10_WARP_SIZE_INTERNAL() { + +static inline constexpr int __device__ C10_WARP_SIZE_INTERNAL() { #if defined(__GFX9__) return 64; #else // __GFX9__ return 32; #endif // __GFX9__ } -#endif // __SPIRV__ -#if defined(__SPIRV__) -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 64 -#elif defined(__GFX9__) -#define C10_WARP_SIZE_LOWER_BOUND 64 -#define C10_WARP_SIZE_UPPER_BOUND 64 -#else -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 32 -#endif -#else // !__HIPCC__ +#else // __HIPCC__ static inline int C10_WARP_SIZE_INTERNAL() { return at::cuda::warp_size(); } -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 64 #endif // __HIPCC__ + #define C10_WARP_SIZE (C10_WARP_SIZE_INTERNAL()) -#else // !USE_ROCM +#define C10_WARP_SIZE_STATIC 64 + +#else // defined(USE_ROCM) #define C10_WARP_SIZE 32 -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 32 -#endif // USE_ROCM +#endif #if defined(_MSC_VER) && _MSC_VER <= 1900 #define __func__ __FUNCTION__ @@ -676,7 +629,7 @@ __host__ __device__ // This macro is used to find older C++ compilers // that don't support move optimization for return values. -#if (defined(__GNUC__) && __GNUC__ < 13 && __cplusplus < 202002L) || \ +#if (defined(__GNUC__) && __GNUC__ < 13) || \ (defined(__clang_major__) && __clang_major__ < 13) #define C10_RETURN_MOVE_IF_OLD_COMPILER 1 #else diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/targets.bzl new file mode 100644 index 0000000..0ddce72 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/targets.bzl @@ -0,0 +1,14 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "torch_headeronly", + exported_headers = glob(["**/*.h"]), + header_namespace = "torch/headeronly", + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h index 9aa08c2..64479ba 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h @@ -12,7 +12,7 @@ #include #include -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) #include #endif @@ -46,7 +46,7 @@ struct alignas(2) BFloat16 { /* implicit */ inline C10_HOST_DEVICE BFloat16(float value); inline C10_HOST_DEVICE operator float() const; -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) inline C10_HOST_DEVICE BFloat16(const __nv_bfloat16& value); explicit inline C10_HOST_DEVICE operator __nv_bfloat16() const; #endif @@ -124,9 +124,8 @@ C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") /// Constructors inline C10_HOST_DEVICE BFloat16::BFloat16(float value) : -#if defined(__CUDACC__) && \ - (!defined(USE_ROCM) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 || \ - defined(USE_ROCM) && (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) && defined(__CUDA_ARCH__) && \ + __CUDA_ARCH__ >= 800 x(__bfloat16_as_ushort(__float2bfloat16(value))) #elif defined(__SYCL_DEVICE_ONLY__) && \ defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) @@ -140,7 +139,7 @@ inline C10_HOST_DEVICE BFloat16::BFloat16(float value) /// Implicit conversions inline C10_HOST_DEVICE BFloat16::operator float() const { -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) return __bfloat162float(*reinterpret_cast(&x)); #elif defined(__SYCL_DEVICE_ONLY__) && \ defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) @@ -150,7 +149,7 @@ inline C10_HOST_DEVICE BFloat16::operator float() const { #endif } -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) inline C10_HOST_DEVICE BFloat16::BFloat16(const __nv_bfloat16& value) { x = *reinterpret_cast(&value); } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/Half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/Half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/Half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/Half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/device.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/device.h similarity index 57% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/device.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/device.h index 41a8c6b..d789df8 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/device.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/device.h @@ -8,42 +8,38 @@ #pragma once -#include -#include +#include namespace executorch { namespace runtime { namespace etensor { -/// Represents the type of compute device. -/// Note: ExecuTorch Device is distinct from PyTorch Device. +/// Denotes the specific genre of compute device. +/// Subset of https://github.com/pytorch/pytorch/blob/main/c10/core/Device.h enum class DeviceType : int8_t { CPU = 0, - CUDA = 1, }; -/// Total number of device types, used for fixed-size registry arrays. -constexpr size_t kNumDeviceTypes = 2; - -/// An index representing a specific device; e.g. GPU 0 vs GPU 1. +/// An index representing a specific device; For cpu it should always be -1 or 0 using DeviceIndex = int8_t; /** * An abstraction for the compute device on which a tensor is located. + * ExecuTorch doesn't allow dynamic dispatching based on device, so this type is + * just a skeleton to allow certain kernels that expect device as an + * argument to still be run. * - * Tensors carry a Device to express where their underlying data resides - * (e.g. CPU host memory vs CUDA device memory). The runtime uses this to - * dispatch memory allocation to the appropriate device allocator. + * In ExecuTorch this is always expected to be CPU. */ struct Device final { using Type = DeviceType; /// Constructs a new `Device` from a `DeviceType` and an optional device /// index. - /* implicit */ Device(DeviceType type, DeviceIndex index = 0) + /* implicit */ Device(DeviceType type, DeviceIndex index = -1) : type_(type), index_(index) {} - /// Returns the type of device the tensor data resides on. + /// Returns the type of device this is. Only CPU is supported. DeviceType type() const noexcept { return type_; } @@ -53,22 +49,15 @@ struct Device final { return type_ == DeviceType::CPU; } - /// Returns the device index. + /// Returns the device index. Always 0 if specified or -1 if not provided. DeviceIndex index() const noexcept { + ET_CHECK(index_ == 0 || index_ == -1); return index_; } - bool operator==(const Device& other) const noexcept { - return type_ == other.type_ && index_ == other.index_; - } - - bool operator!=(const Device& other) const noexcept { - return !(*this == other); - } - private: DeviceType type_; - DeviceIndex index_ = 0; + DeviceIndex index_ = -1; }; } // namespace etensor diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/optional.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/optional.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/optional.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/optional.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/qint_types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/qint_types.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/qint_types.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/qint_types.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/scalar.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/scalar.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/scalar.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/scalar.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/scalar_type.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/scalar_type.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/scalar_type.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/scalar_type.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/string_view.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/string_view.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/string_view.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/string_view.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/targets.bzl new file mode 100644 index 0000000..5b6e67f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/targets.bzl @@ -0,0 +1,67 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Internal target for executor tensor. Clients should depend on + # :kernel_types below to be flexible with ATen Tensor and executor Tensor. + runtime.cxx_library( + name = "portable_type", + srcs = ["tensor_impl.cpp"], + exported_headers = [ + "tensor_options.h", + "optional.h", + "scalar.h", + "tensor.h", + "tensor_impl.h", + "string_view.h", + "device.h", + ], + # Only should be depended on by kernel_types:kernel_types, but various suffixes like Android and Static + # mean I cant just expose visibility to a single rule. + visibility = [ + "//executorch/backends/...", + "//executorch/extension/fb/dynamic_shim/...", + "//executorch/kernels/portable/cpu/...", + "//executorch/runtime/core/exec_aten/...", + "//executorch/runtime/core/portable_type/test/...", + ], + deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + exported_deps = [ + ":scalar_type", + "//executorch/runtime/core:core", + "//executorch/runtime/core:tensor_shape_dynamism", + "//executorch/runtime/core/exec_aten/util:dim_order_util", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/core:tag", + ], + ) + + # Set up a specific exported library for scalar_type to avoid circle dependency in ScalarTypeUtil.h + runtime.cxx_library( + name = "scalar_type", + exported_headers = [ + "bfloat16.h", + "bfloat16_math.h", + "complex.h", + "half.h", + "scalar_type.h", + "qint_types.h", + "bits_types.h", + ], + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + visibility = [ + "//executorch/extension/...", + "//executorch/runtime/core/exec_aten/util/...", + "//executorch/kernels/...", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_impl.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_impl.cpp similarity index 79% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_impl.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_impl.cpp index 113a1f0..64ecb73 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_impl.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_impl.cpp @@ -39,33 +39,9 @@ ssize_t compute_numel(const TensorImpl::SizesType* sizes, ssize_t dim) { "Size must be non-negative, got %zd at dimension %zd", static_cast(sizes[i]), i); - numel *= sizes[i]; - } - return numel; -} - -::executorch::runtime::Result safe_numel( - const TensorImpl::SizesType* sizes, - ssize_t dim) { - ET_CHECK_OR_RETURN_ERROR( - dim == 0 || sizes != nullptr, - InvalidArgument, - "Sizes must be provided for non-scalar tensors"); - ssize_t numel = 1; - for (const auto i : c10::irange(dim)) { - ET_CHECK_OR_RETURN_ERROR( - sizes[i] >= 0, - InvalidArgument, - "Size must be non-negative, got %zd at dimension %zd", - static_cast(sizes[i]), - i); - ssize_t next_numel; - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(numel, static_cast(sizes[i]), &next_numel), - InvalidArgument, - "Overflow computing numel at dimension %zd", - i); - numel = next_numel; + bool overflow = + c10::mul_overflows(numel, static_cast(sizes[i]), &numel); + ET_CHECK_MSG(!overflow, "numel overflowed"); } return numel; } @@ -77,9 +53,7 @@ TensorImpl::TensorImpl( void* data, DimOrderType* dim_order, StridesType* strides, - TensorShapeDynamism dynamism, - DeviceType device_type, - DeviceIndex device_index) + TensorShapeDynamism dynamism) : sizes_(sizes), dim_order_(dim_order), strides_(strides), @@ -88,15 +62,18 @@ TensorImpl::TensorImpl( numel_(compute_numel(sizes, dim)), numel_bound_(numel_), type_(type), - shape_dynamism_(dynamism), - device_(device_type, device_index) { + shape_dynamism_(dynamism) { ET_CHECK_MSG( isValid(type_), "Invalid type %" PRId8, static_cast(type_)); ET_CHECK_MSG(dim_ >= 0, "Dimension must be non-negative, got %zd", dim_); } size_t TensorImpl::nbytes() const { - return numel_ * elementSize(type_); + size_t result; + bool overflow = c10::mul_overflows( + static_cast(numel_), elementSize(type_), &result); + ET_CHECK_MSG(!overflow, "nbytes overflowed"); + return result; } // Return the size of one element of the tensor @@ -147,11 +124,7 @@ Error TensorImpl::internal_resize_contiguous(ArrayRef new_sizes) { // TODO(T175194371): Unbounded dynamic tensor resizing is not yet // supported: treat them as upper-bounded. case TensorShapeDynamism::DYNAMIC_UNBOUND: { - auto new_numel_result = safe_numel(new_sizes.data(), dim_); - if (!new_numel_result.ok()) { - return new_numel_result.error(); - } - const auto new_numel = new_numel_result.get(); + const auto new_numel = compute_numel(new_sizes.data(), dim_); ET_CHECK_OR_RETURN_ERROR( static_cast(new_numel) <= numel_bound_, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_impl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_impl.h similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_impl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_impl.h index b01d8fa..1e2b362 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_impl.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_impl.h @@ -10,11 +10,8 @@ #include #include -#include #include -#include #include -#include // Forward declaration of a helper that provides access to internal resizing // methods of TensorImpl. Real definition is in @@ -102,8 +99,6 @@ class TensorImpl { * @param strides Strides of the tensor at each dimension. Must contain `dim` * entries. * @param dynamism The mutability of the shape of the tensor. - * @param device_type The type of device where tensor data resides. - * @param device_index The device index for multi-device scenarios. */ TensorImpl( ScalarType type, @@ -112,9 +107,7 @@ class TensorImpl { void* data = nullptr, DimOrderType* dim_order = nullptr, StridesType* strides = nullptr, - TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC, - DeviceType device_type = DeviceType::CPU, - DeviceIndex device_index = 0); + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC); /** * Returns the size of the tensor in bytes. @@ -183,21 +176,6 @@ class TensorImpl { return shape_dynamism_; } - /// Returns the device where tensor data resides. - Device device() const { - return device_; - } - - /// Returns the type of device where tensor data resides. - DeviceType device_type() const { - return device_.type(); - } - - /// Returns the device index, or 0 if default/unspecified. - DeviceIndex device_index() const { - return device_.index(); - } - /// Returns a pointer of type T to the constant underlying data blob. template inline const T* data() const { @@ -283,9 +261,6 @@ class TensorImpl { /// Specifies the mutability of the shape of the tensor. const TensorShapeDynamism shape_dynamism_; - - /// Device where tensor data resides (CPU, CUDA, etc.) - Device device_; }; /** @@ -295,16 +270,6 @@ ssize_t compute_numel( const ::executorch::runtime::etensor::TensorImpl::SizesType* sizes, ssize_t dim); -/** - * Compute the number of elements based on the sizes of a tensor. - * Returns Error::InvalidArgument if any intermediate multiplication would - * overflow ssize_t, or if a size is negative. Prefer this over compute_numel() - * for paths that can propagate an Error upward. - */ -::executorch::runtime::Result safe_numel( - const ::executorch::runtime::etensor::TensorImpl::SizesType* sizes, - ssize_t dim); - /// Appropriate format specifier for the result of calling /// size(). Must be used instead of using zd directly to support ATen /// mode. @@ -334,7 +299,6 @@ namespace executor { // TODO(T197294990): Remove these deprecated aliases once all users have moved // to the new `::executorch` namespaces. using ::executorch::runtime::etensor::compute_numel; -using ::executorch::runtime::etensor::safe_numel; using ::executorch::runtime::etensor::TensorImpl; } // namespace executor } // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_options.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_options.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_options.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/tensor_options.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/CMakeLists.txt new file mode 100644 index 0000000..b1f57a9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs + bfloat16_test.cpp + dont_shadow_complex_test.c + half_test.cpp + optional_test.cpp + scalar_test.cpp + tensor_impl_test.cpp + tensor_test.cpp +) + +et_cxx_test(runtime_core_portable_type_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/bfloat16_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/bfloat16_test.cpp new file mode 100644 index 0000000..505f80e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/bfloat16_test.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include + +using executorch::runtime::etensor::BFloat16; +using executorch::runtime::etensor::internal::f32_from_bits; +using executorch::runtime::etensor::internal::round_to_nearest_even; + +namespace { +float float_from_bytes(uint32_t sign, uint32_t exponent, uint32_t fraction) { + // NOLINTNEXTLINE(cppcoreguidelines-init-variables) + uint32_t bytes; + bytes = 0; + bytes |= sign; + bytes <<= 8; + bytes |= exponent; + bytes <<= 23; + bytes |= fraction; + + // NOLINTNEXTLINE(cppcoreguidelines-init-variables) + float res; + std::memcpy(&res, &bytes, sizeof(res)); + return res; +} + +// Opposite of f32_from_bits. +uint16_t bits_from_f32(float src) { + uint32_t res = 0; + std::memcpy(&res, &src, sizeof(res)); + return res >> 16; +} + +TEST(BFloat16Conversion, FloatToBFloat16AndBack) { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float in[100]; + for (const auto i : c10::irange(100)) { + // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-avoid-magic-numbers) + in[i] = i + 1.25; + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + BFloat16 bfloats[100]; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float out[100]; + + for (const auto i : c10::irange(100)) { + bfloats[i].x = bits_from_f32(in[i]); + out[i] = f32_from_bits(bfloats[i].x); + + // The relative error should be less than 1/(2^7) since BFloat16 + // has 7 bits mantissa. + EXPECT_LE(std::fabs(out[i] - in[i]) / in[i], 1.0 / 128); + } +} + +TEST(BFloat16Conversion, FloatToBFloat16RNEAndBack) { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float in[100]; + for (const auto i : c10::irange(100)) { + // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-avoid-magic-numbers) + in[i] = i + 1.25; + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + BFloat16 bfloats[100]; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float out[100]; + + for (const auto i : c10::irange(100)) { + bfloats[i].x = round_to_nearest_even(in[i]); + out[i] = f32_from_bits(bfloats[i].x); + + // The relative error should be less than 1/(2^7) since BFloat16 + // has 7 bits mantissa. + EXPECT_LE(std::fabs(out[i] - in[i]) / in[i], 1.0 / 128); + } +} + +TEST(BFloat16Conversion, NaN) { + float inNaN = float_from_bytes(0, 0xFF, 0x7FFFFF); + EXPECT_TRUE(std::isnan(inNaN)); + + BFloat16 a = BFloat16(inNaN); + float out = f32_from_bits(a.x); + + EXPECT_TRUE(std::isnan(out)); +} + +TEST(BFloat16Conversion, Inf) { + float inInf = float_from_bytes(0, 0xFF, 0); + EXPECT_TRUE(std::isinf(inInf)); + + BFloat16 a = BFloat16(inInf); + float out = f32_from_bits(a.x); + + EXPECT_TRUE(std::isinf(out)); +} + +TEST(BFloat16Conversion, SmallestDenormal) { + float in = std::numeric_limits::denorm_min(); // The smallest non-zero + // subnormal number + BFloat16 a = BFloat16(in); + float out = f32_from_bits(a.x); + + EXPECT_FLOAT_EQ(in, out); +} + +TEST(BFloat16Math, Addition) { + // This test verifies that if only first 7 bits of float's mantissa are + // changed after addition, we should have no loss in precision. + + // input bits + // S | Exponent | Mantissa + // 0 | 10000000 | 10010000000000000000000 = 3.125 + float input = float_from_bytes(0, 0, 0x40480000); + + // expected bits + // S | Exponent | Mantissa + // 0 | 10000001 | 10010000000000000000000 = 6.25 + float expected = float_from_bytes(0, 0, 0x40c80000); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + BFloat16 b; + b.x = bits_from_f32(input); + b = b + b; + + float res = f32_from_bits(b.x); + EXPECT_EQ(res, expected); +} + +TEST(BFloat16Math, Subtraction) { + // This test verifies that if only first 7 bits of float's mantissa are + // changed after subtraction, we should have no loss in precision. + + // input bits + // S | Exponent | Mantissa + // 0 | 10000001 | 11101000000000000000000 = 7.625 + float input = float_from_bytes(0, 0, 0x40f40000); + + // expected bits + // S | Exponent | Mantissa + // 0 | 10000000 | 01010000000000000000000 = 2.625 + float expected = float_from_bytes(0, 0, 0x40280000); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + BFloat16 b; + b.x = bits_from_f32(input); + b = b - 5; + + float res = f32_from_bits(b.x); + EXPECT_EQ(res, expected); +} + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +TEST(BFloat16Math, NextAfterZero) { + const BFloat16 zero{0}; + + auto check_nextafter = [](BFloat16 from, BFloat16 to, BFloat16 expected) { + BFloat16 actual = std::nextafter(from, to); + // Check for bitwise equality! + ASSERT_EQ(actual.x ^ expected.x, uint16_t{0}); + }; + check_nextafter(zero, zero, /*expected=*/zero); + check_nextafter(zero, -zero, /*expected=*/-zero); + check_nextafter(-zero, zero, /*expected=*/zero); + check_nextafter(-zero, -zero, /*expected=*/-zero); +} + +float BinaryToFloat(uint32_t bytes) { + // NOLINTNEXTLINE(cppcoreguidelines-init-variables) + float res; + std::memcpy(&res, &bytes, sizeof(res)); + return res; +} + +struct BFloat16TestParam { + uint32_t input; + uint16_t rne; +}; + +class BFloat16Test : public ::testing::Test, + public ::testing::WithParamInterface {}; + +TEST_P(BFloat16Test, BFloat16RNETest) { + float value = BinaryToFloat(GetParam().input); + uint16_t rounded = round_to_nearest_even(value); + EXPECT_EQ(GetParam().rne, rounded); +} + +INSTANTIATE_TEST_SUITE_P( + BFloat16TestInstantiation, + BFloat16Test, + ::testing::Values( + BFloat16TestParam{0x3F848000, 0x3F84}, + BFloat16TestParam{0x3F848010, 0x3F85}, + BFloat16TestParam{0x3F850000, 0x3F85}, + BFloat16TestParam{0x3F858000, 0x3F86}, + BFloat16TestParam{0x3FFF8000, 0x4000})); + +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/dont_shadow_complex_test.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/dont_shadow_complex_test.c new file mode 100644 index 0000000..5654216 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/dont_shadow_complex_test.c @@ -0,0 +1,9 @@ +// This include statement should get the C99 standard header +// complex.h. At one point we messed up our c10 include setup such +// that it instead included runtime/core/portable_type/complex.h. This +// is a regression test for that issue. +#include + +#ifndef complex +#warning "complex.h does not define complex" +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/half_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/half_test.cpp new file mode 100644 index 0000000..0d5dca0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/half_test.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +using executorch::runtime::etensor::Half; + +namespace { + +/** + * According to the precision limitations listed here: + * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Precision_limitations + * The max precision error for a half in the range [2^n, 2^(n+1)] is 2^(n-10) + */ +float toleranceFloat16(float f) { + return pow(2, static_cast(log2(fabs(f))) - 10); +} + +bool closeEnoughFloat16(float a, float b) { + return fabs(a - b) <= toleranceFloat16(fmax(fabs(a), fabs(b))); +} + +} // namespace + +/// Arithmetic with Halfs + +TEST(HalfTest, ArithmeticHalfAdd) { + float af = 104.35; + Half ah(af); + float bf = 72.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah + bh, af + bf)); + ah += bh; + af += bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +TEST(HalfTest, ArithmeticHalfSub) { + float af = 31.4; + Half ah(af); + float bf = 20.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah - bh, af - bf)); + ah -= bh; + af -= bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +TEST(HalfTest, ArithmeticHalfMul) { + float af = 85.5; + Half ah(af); + float bf = 17.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah * bh, af * bf)); + ah *= bh; + af *= bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +TEST(HalfTest, ArithmeticHalfDiv) { + float af = 96.9; + Half ah(af); + float bf = 12.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah / bh, af / bf)); + ah /= bh; + af /= bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +/// Arithmetic with floats + +TEST(HalfTest, ArithmeticFloatAdd) { + float af = 104.35; + Half ah(af); + float b = 72.5; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticFloatSub) { + float af = 31.4; + Half ah(af); + float b = 20.5; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticFloatMul) { + float af = 85.5; + Half ah(af); + float b = 17.5; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticFloatDiv) { + float af = 96.9; + Half ah(af); + float b = 12.5; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} + +/// Arithmetic with doubles + +TEST(HalfTest, ArithmeticDoubleAdd) { + float af = 104.35; + Half ah(af); + double b = 72.5; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticDoubleSub) { + float af = 31.4; + Half ah(af); + double b = 20.5; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticDoubleMul) { + float af = 85.5; + Half ah(af); + double b = 17.5; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticDoubleDiv) { + float af = 96.9; + Half ah(af); + double b = 12.5; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} + +/// Arithmetic with ints + +TEST(HalfTest, ArithmeticInt32Add) { + float af = 104.35; + Half ah(af); + int32_t b = 72; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticInt32Sub) { + float af = 31.4; + Half ah(af); + int32_t b = 20; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticInt32Mul) { + float af = 85.5; + Half ah(af); + int32_t b = 17; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticInt32Div) { + float af = 96.9; + Half ah(af); + int32_t b = 12; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} + +//// Arithmetic with int64_t + +TEST(HalfTest, ArithmeticInt64Add) { + float af = 104.35; + Half ah(af); + int64_t b = 72; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticInt64Sub) { + float af = 31.4; + Half ah(af); + int64_t b = 20; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticInt64Mul) { + float af = 85.5; + Half ah(af); + int64_t b = 17; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticInt64Div) { + float af = 96.9; + Half ah(af); + int64_t b = 12; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/optional_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/optional_test.cpp new file mode 100644 index 0000000..60d835d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/optional_test.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::etensor::nullopt; +using executorch::runtime::etensor::optional; + +// Test that optional::value_type matches the template parameter type. +static_assert( + std::is_same::value_type, int32_t>::value, + "Unexpected optional::value_type"); +static_assert( + std::is_same::value_type, std::string>::value, + "Unexpected optional::value_type"); + +TEST(TestOptional, DefaultHasNoValue) { + optional o; + EXPECT_FALSE(o.has_value()); +} + +TEST(TestOptional, NulloptHasNoValue) { + optional o(nullopt); + EXPECT_FALSE(o.has_value()); +} + +TEST(TestOptional, ValueOfEmptyOptionalShouldThrow) { + optional o; + EXPECT_FALSE(o.has_value()); + + EXPECT_THROW({ (void)o.value(); }, std::bad_optional_access); +} + +TEST(TestOptional, IntValue) { + optional o(15); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), 15); +} + +TEST(TestOptional, NonTrivialValueType) { + optional o("hey"); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), "hey"); +} + +TEST(TestOptional, ConstValue) { + const optional o("hey"); + auto s = o.value(); // If this compiles, we're good. + EXPECT_EQ(o.value(), "hey"); +} + +TEST(TestOptional, CopyCtorWithValue) { + optional o1(15); + optional o2(o1); + + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), 15); +} + +TEST(TestOptional, CopyCtorWithNoValue) { + optional o1; + optional o2(o1); + + EXPECT_FALSE(o2.has_value()); +} + +TEST(TestOptional, CopyAssignTrivial) { + optional o1(1); + optional o2(2); + o1 = o2; + + EXPECT_EQ(o1.value(), 2); +} + +TEST(TestOptional, CopyAssignNonTrivial) { + optional o1("abcde"); + optional o2("foo"); + o1 = o2; + + EXPECT_EQ(o1.value(), "foo"); +} + +TEST(TestOptional, CopyAssignNone) { + optional o1(2); + optional o2; + o1 = o2; + EXPECT_FALSE(o1.has_value()); +} + +TEST(TestOptional, MoveCtorWithNoValue) { + optional o1; + optional o2(std::move(o1)); + + EXPECT_FALSE(o2.has_value()); +} + +TEST(TestOptional, MoveCtorWithValue) { + optional o1(15); + optional o2(std::move(o1)); + + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), 15); +} + +TEST(TestOptional, MoveCtorNonTrivialType) { + optional o1("abc"); + optional o2(std::move(o1)); + + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), "abc"); +} + +optional function_returning_optional_of(int32_t value) { + return value; +} + +TEST(TestOptional, ImplicitReturnOfValue) { + auto o = function_returning_optional_of(21); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), 21); +} + +optional function_returning_nullopt() { + return nullopt; +} + +TEST(TestOptional, ImplicitReturnOfNullopt) { + auto o = function_returning_nullopt(); + EXPECT_FALSE(o.has_value()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/scalar_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/scalar_test.cpp new file mode 100644 index 0000000..fd211f9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/scalar_test.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +using executorch::runtime::etensor::Scalar; + +TEST(ScalarTest, ToScalarType) { + Scalar s_d((double)3.141); + EXPECT_EQ(s_d.to(), 3.141); + Scalar s_i((int64_t)3); + EXPECT_EQ(s_i.to(), 3); + Scalar s_b(true); + EXPECT_EQ(s_b.to(), true); +} + +TEST(ScalarTest, ToIntForFalseScalarPasses) { + Scalar s_b(false); + EXPECT_FALSE(s_b.isIntegral(/*includeBool=*/false)); + EXPECT_TRUE(s_b.isIntegral(/*includeBool=*/true)); + EXPECT_EQ(s_b.to(), 0); +} + +TEST(ScalarTest, ToIntForTrueScalarPasses) { + Scalar s_b(true); + EXPECT_FALSE(s_b.isIntegral(/*includeBool=*/false)); + EXPECT_TRUE(s_b.isIntegral(/*includeBool=*/true)); + EXPECT_EQ(s_b.to(), 1); +} + +TEST(ScalarTest, IntConstructor) { + int int_val = 1; + Scalar s_int(int_val); + int32_t int32_val = 1; + Scalar s_int32(int32_val); + int64_t int64_val = 1; + Scalar s_int64(int64_val); + EXPECT_EQ(s_int.to(), s_int32.to()); + EXPECT_EQ(s_int32.to(), s_int64.to()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/targets.bzl new file mode 100644 index 0000000..d8e82a1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/targets.bzl @@ -0,0 +1,58 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "bfloat16_test", + srcs = ["bfloat16_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "optional_test", + srcs = ["optional_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "tensor_test", + srcs = ["tensor_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "half_test", + srcs = ["half_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "scalar_test", + srcs = ["scalar_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "tensor_impl_test", + srcs = ["tensor_impl_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/util:tensor_util", + "//executorch/runtime/core/portable_type:portable_type", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_impl_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_impl_test.cpp new file mode 100644 index 0000000..08b26c6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_impl_test.cpp @@ -0,0 +1,460 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace ::testing; + +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::TensorShapeDynamism; +using executorch::runtime::etensor::ScalarType; +using executorch::runtime::etensor::TensorImpl; +using SizesType = TensorImpl::SizesType; +using DimOrderType = TensorImpl::DimOrderType; +using StridesType = TensorImpl::StridesType; +using executorch::runtime::internal::resize_tensor_impl; + +class TensorImplTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorImplTest, TestCtorAndGetters) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data, dim_order, strides); + + EXPECT_EQ(t.numel(), 6); + EXPECT_EQ(t.nbytes(), 6 * 4); // 6 4 byte floats + EXPECT_EQ(t.dim(), 2); + EXPECT_EQ(t.scalar_type(), ScalarType::Float); + EXPECT_EQ(t.element_size(), 4); + EXPECT_EQ(t.data(), data); + EXPECT_EQ(t.mutable_data(), data); + EXPECT_EQ(t.sizes().data(), sizes); + EXPECT_EQ(t.sizes().size(), 2); + EXPECT_EQ(t.strides().data(), strides); + EXPECT_EQ(t.strides().size(), 2); +} + +// Verify that contig means stride[0] >= stride[1] >= ... stride[size-1] == 1 +TEST_F(TensorImplTest, TestSetSizesContigContract) { + const int RANK = 5; + std::default_random_engine generator; + std::uniform_int_distribution distribution(1, 100); + SizesType sizes[RANK] = {100, 100, 100, 100, 100}; + DimOrderType dim_order[RANK] = {0, 1, 2, 3, 4}; + StridesType strides[RANK] = {100000000, 1000000, 10000, 100, 1}; + float* data = nullptr; + TensorImpl t( + ScalarType::Float, + RANK, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + SizesType new_sizes[RANK] = {0, 0, 0, 0, 0}; + // assign random sizes between 1 and 100 + for (const auto i : c10::irange(RANK)) { + new_sizes[i] = distribution(generator); + } + Error err = resize_tensor_impl(&t, {new_sizes, RANK}); + EXPECT_EQ(err, Error::Ok); + + auto strides_ref = t.strides(); + StridesType prev = strides_ref[0]; + for (auto stride : strides_ref) { + EXPECT_LE(stride, prev); + } + EXPECT_EQ(t.strides()[strides_ref.size() - 1], 1); +} + +TEST_F(TensorImplTest, TestSetSizesContigZeroSizes) { + SizesType sizes[3] = {2, 0, 3}; + DimOrderType dim_order[3] = {0, 1, 2}; + StridesType strides[3] = {3, 3, 1}; + float* data = nullptr; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + SizesType new_sizes_1[3] = {1, 0, 2}; + Error err = resize_tensor_impl(&t, {new_sizes_1, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 0); + + // Treat 0 dimensions as size 1 for stride calculation as thats what aten does + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 2); + EXPECT_EQ(strides_ref[2], 1); + + // Numel is 0 for tensors with a 0 sized dimension + EXPECT_EQ(t.numel(), 0); +} + +TEST_F(TensorImplTest, TestSetSizesContigStatic) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data, dim_order, strides); + + SizesType new_sizes_1[2] = {3, 2}; + Error err = resize_tensor_impl(&t, {new_sizes_1, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 2); + + // strides shouldnt change + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_2[2] = {2, 2}; + // Can't change size of a StaticShape Tensor + err = resize_tensor_impl(&t, {new_sizes_2, 2}); + EXPECT_NE(err, Error::Ok); + + SizesType new_sizes_3[1] = {2}; + // Can't change rank of any Tensor + err = resize_tensor_impl(&t, {new_sizes_3, 1}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestSetSizesContigUpperBounded) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t( + ScalarType::Float, + 2, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + SizesType new_sizes_1[2] = {1, 1}; + // Can resize down + Error err = resize_tensor_impl(&t, {new_sizes_1, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 1); + + // strides contiguous + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 1); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_2[2] = {3, 2}; + // Can resize back up + err = resize_tensor_impl(&t, {new_sizes_2, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 2); + + // Back to original strides + strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_3[2] = {4, 2}; + // Can't execeed capacity of UpperBounded Tensor + err = resize_tensor_impl(&t, {new_sizes_3, 2}); + EXPECT_NE(err, Error::Ok); + + SizesType new_sizes_4[1] = {4}; + // Can't change rank of any Tensor + err = resize_tensor_impl(&t, {new_sizes_4, 1}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestZeroDimSetEmptySizesContig) { + SizesType sizes[0] = {}; + DimOrderType dim_order[0] = {}; + StridesType strides[0] = {}; + float data[1] = {1.0}; + TensorImpl t( + ScalarType::Float, + 0, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + ArrayRef new_sizes_empty{}; + // Can resize with empty sizes + Error err = resize_tensor_impl(&t, new_sizes_empty); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 0); + + SizesType new_sizes_1[1] = {1}; + // Can't change rank of tensor + err = resize_tensor_impl(&t, {new_sizes_1, 1}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestSetSizesContigUnbounded) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t( + ScalarType::Float, + 2, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_UNBOUND); + + SizesType new_sizes_1[2] = {1, 1}; + // Can resize down + Error err = resize_tensor_impl(&t, {new_sizes_1, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 1); + + // strides contiguous + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 1); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_2[2] = {3, 2}; + // Can resize back up + err = resize_tensor_impl(&t, {new_sizes_2, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 2); + + // Back to original strides + strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_4[1] = {4}; + // Can't change rank of any Tensor + err = resize_tensor_impl(&t, {new_sizes_4, 1}); + EXPECT_NE(err, Error::Ok); + + // TODO(T175194371): For now, we can't resize past the original capacity. + // Once we can, this test should check for that ability. + + SizesType new_sizes_3[2] = {4, 2}; + // Can't execeed original capacity. + err = resize_tensor_impl(&t, {new_sizes_3, 2}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestDynamicTensorNoStridesDimOrder) { + SizesType sizes[3] = {2, 3, 4}; + float data[24] = {0}; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.numel(), 24); + EXPECT_EQ(t.nbytes(), 24 * sizeof(float)); + + SizesType new_sizes[3] = {3, 2, 4}; + Error err = resize_tensor_impl(&t, {new_sizes, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.size(0), 3); + EXPECT_EQ(t.size(1), 2); + EXPECT_EQ(t.size(2), 4); + EXPECT_EQ(t.numel(), 3 * 2 * 4); + + const float* y = t.data(); + EXPECT_EQ(y, data); +} + +TEST_F(TensorImplTest, TestDynamicTensorNoStridesDimOrderResizeDown) { + SizesType sizes[3] = {4, 4, 4}; + float data[64] = {0}; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.numel(), 64); + EXPECT_EQ(t.nbytes(), 64 * sizeof(float)); + + SizesType new_sizes[3] = {2, 2, 2}; + Error err = resize_tensor_impl(&t, {new_sizes, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.size(0), 2); + EXPECT_EQ(t.size(1), 2); + EXPECT_EQ(t.size(2), 2); + EXPECT_EQ(t.numel(), 2 * 2 * 2); + + const float* y = t.data(); + EXPECT_EQ(y, data); +} + +TEST_F(TensorImplTest, TestDynamicTensorNoStridesDimOrderResizeZeroDim) { + SizesType sizes[3] = {4, 4, 4}; + float data[64] = {0}; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.numel(), 64); + EXPECT_EQ(t.nbytes(), 64 * sizeof(float)); + + SizesType new_sizes[3] = {0, 4, 4}; + Error err = resize_tensor_impl(&t, {new_sizes, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.size(0), 0); + EXPECT_EQ(t.size(1), 4); + EXPECT_EQ(t.size(2), 4); + EXPECT_EQ(t.numel(), 0); + + const float* y = t.data(); + EXPECT_EQ(y, data); +} + +TEST_F(TensorImplTest, TestWriteRead) { + SizesType sizes[1] = {1}; + DimOrderType dim_order[1] = {0}; + StridesType strides[1] = {1}; + float data[1] = {1.0}; + TensorImpl t(ScalarType::Float, 1, sizes, data, dim_order, strides); + + const float* y = t.data(); + EXPECT_EQ(y[0], 1.0); + + float* x = t.mutable_data(); + x[0] = 22.0; + + EXPECT_EQ(y[0], 22.0); +} + +TEST_F(TensorImplTest, TestInvalidScalarType) { + SizesType sizes[2] = {3, 2}; + ET_EXPECT_DEATH(TensorImpl t(static_cast(-1), 2, sizes), ""); +} + +TEST_F(TensorImplTest, TestNegativeDimension) { + SizesType sizes[2] = {3, 2}; + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, -1, sizes), ""); +} + +TEST_F(TensorImplTest, TestNullSizesNonZeroDim) { + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, 2, nullptr), ""); +} + +TEST_F(TensorImplTest, TestNonNegativeSizes) { + SizesType sizes[2] = {3, -2}; + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, 2, sizes), ""); +} + +TEST_F(TensorImplTest, TestEmptyTensor) { + SizesType sizes[2] = {0, 0}; + TensorImpl t(ScalarType::Float, 2, sizes); + EXPECT_EQ(t.numel(), 0); + EXPECT_EQ(t.data(), nullptr); +} + +TEST_F(TensorImplTest, TestTensorWithNoElementsButAllocatedMemory) { + SizesType sizes[2] = {0, 0}; + float data[1] = {1.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data); + EXPECT_EQ(t.numel(), 0); + EXPECT_EQ(t.data(), data); +} + +TEST_F(TensorImplTest, TestTensorWithShapeButNoMemory) { + SizesType sizes[2] = {3, 2}; + TensorImpl t(ScalarType::Float, 2, sizes); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), nullptr); +} + +TEST_F(TensorImplTest, TestNormalTensor) { + SizesType sizes[2] = {3, 2}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), data); +} + +TEST_F(TensorImplTest, TestResizingTensorToZeroAndBack) { + SizesType sizes[2] = {3, 2}; + TensorImpl t( + ScalarType::Float, + 2, + sizes, + nullptr, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + t.set_data(data); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), data); + + SizesType zero_sizes[2] = {0, 0}; + t.set_sizes_contiguous({zero_sizes, 2}); + EXPECT_EQ(t.numel(), 0); + EXPECT_EQ(t.data(), data); + + SizesType new_sizes[2] = {3, 2}; + t.set_sizes_contiguous({new_sizes, 2}); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), data); +} + +TEST_F(TensorImplTest, TestNbytesOverflow) { + SizesType sizes[3] = { + static_cast(1 << 21), + static_cast(1 << 21), + static_cast(1 << 21)}; + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, 3, sizes), ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_test.cpp new file mode 100644 index 0000000..714cdc2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/portable_type/test/tensor_test.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +using executorch::runtime::etensor::ScalarType; +using executorch::runtime::etensor::Tensor; +using executorch::runtime::etensor::TensorImpl; + +class TensorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorTest, InvalidScalarType) { + TensorImpl::SizesType sizes[1] = {1}; + + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + ET_EXPECT_DEATH({ TensorImpl y(ScalarType::Undefined, 1, sizes); }, ""); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + ET_EXPECT_DEATH({ TensorImpl y(ScalarType::NumOptions, 1, sizes); }, ""); + ET_EXPECT_DEATH( + { TensorImpl y(static_cast(127), 1, sizes); }, ""); + ET_EXPECT_DEATH({ TensorImpl y(static_cast(-1), 1, sizes); }, ""); +} + +TEST_F(TensorTest, SetData) { + TensorImpl::SizesType sizes[1] = {5}; + TensorImpl::DimOrderType dim_order[1] = {0}; + int32_t data[5] = {0, 0, 1, 0, 0}; + auto a_impl = TensorImpl(ScalarType::Int, 1, sizes, data, dim_order, nullptr); + auto a = Tensor(&a_impl); + EXPECT_EQ(a.const_data_ptr(), data); + a.set_data(nullptr); + EXPECT_EQ(a.const_data_ptr(), nullptr); +} + +TEST_F(TensorTest, Strides) { + TensorImpl::SizesType sizes[2] = {2, 2}; + TensorImpl::DimOrderType dim_order[2] = {0, 1}; + int32_t data[4] = {0, 0, 1, 1}; + TensorImpl::StridesType strides[2] = {2, 1}; + auto a_impl = TensorImpl(ScalarType::Int, 2, sizes, data, dim_order, strides); + Tensor a(&a_impl); + + EXPECT_EQ(a_impl.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.const_data_ptr()[0], 0); + EXPECT_EQ(a.const_data_ptr()[0 + a.strides()[0]], 1); +} + +TEST_F(TensorTest, ModifyDataOfConstTensor) { + TensorImpl::SizesType sizes[1] = {1}; + TensorImpl::DimOrderType dim_order[2] = {0}; + int32_t data[1] = {1}; + auto a_impl = TensorImpl(ScalarType::Int, 1, sizes, data, dim_order); + const Tensor a(&a_impl); + a.mutable_data_ptr()[0] = 0; + + EXPECT_EQ(a_impl.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.const_data_ptr()[0], 0); +} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/result.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/result.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/result.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/result.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/span.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/span.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/span.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/span.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tag.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tag.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tag.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tag.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tag.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tag.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tag.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tag.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/targets.bzl new file mode 100644 index 0000000..2c13cdb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/targets.bzl @@ -0,0 +1,157 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def event_tracer_enabled(): + return native.read_config("executorch", "event_tracer_enabled", "false") == "true" + +def get_event_tracer_flags(): + event_tracer_flags = [] + if event_tracer_enabled(): + event_tracer_flags += ["-DET_EVENT_TRACER_ENABLED"] + elif not runtime.is_oss: + event_tracer_flags += select ({ + "DEFAULT": [], + "fbsource//xplat/executorch/tools/buck/constraints:event-tracer-enabled" : ["-DET_EVENT_TRACER_ENABLED"] + }) + return event_tracer_flags + +def build_sdk(): + return native.read_config("executorch", "build_sdk", "false") == "true" + +def get_sdk_flags(): + sdk_flags = [] + if build_sdk(): + sdk_flags += ["-DEXECUTORCH_BUILD_DEVTOOLS"] + return sdk_flags + +def enable_enum_strings(): + return native.read_config("executorch", "enable_enum_strings", "true") == "true" + +def get_core_flags(): + core_flags = [] + core_flags += ["-DET_ENABLE_ENUM_STRINGS=" + ("1" if enable_enum_strings() else "0")] + return core_flags + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "core", + exported_headers = [ + "array_ref.h", # TODO(T157717874): Migrate all users to span and then move this to portable_type + "data_loader.h", + "defines.h", + "error.h", + "freeable_buffer.h", + "function_ref.h", + "result.h", + "span.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = get_core_flags(), + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_library( + name = "tensor_shape_dynamism", + exported_headers = [ + "tensor_shape_dynamism.h", + ], + visibility = [ + "//executorch/runtime/core/exec_aten/...", + "//executorch/runtime/core/portable_type/...", + ], + ) + + runtime.cxx_library( + name = "memory_allocator", + exported_headers = [ + "hierarchical_allocator.h", + "memory_allocator.h", + ], + exported_deps = [ + ":core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + visibility = ["PUBLIC"], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + runtime.cxx_library( + name = "evalue" + aten_suffix, + exported_headers = [ + "evalue.h", + ], + srcs = ["evalue.cpp"], + visibility = ["PUBLIC"], + exported_deps = [ + ":core", + ":tag", + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "event_tracer" + aten_suffix, + exported_headers = [ + "event_tracer.h", + "event_tracer_hooks.h", + "event_tracer_hooks_delegate.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = get_event_tracer_flags() + get_sdk_flags(), + exported_deps = [ + "//executorch/runtime/platform:platform", + "//executorch/runtime/core:evalue" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "named_data_map" + aten_suffix, + exported_headers = [ + "named_data_map.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + ":tensor_layout" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + ], + ) + + + runtime.cxx_library( + name = "tensor_layout" + aten_suffix, + srcs = ["tensor_layout.cpp"], + exported_headers = ["tensor_layout.h"], + deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + exported_deps = [ + ":core", + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + ], + visibility = ["//executorch/..."], + ) + + runtime.cxx_library( + name = "tag", + srcs = ["tag.cpp"], + exported_headers = [ + "tag.h", + ], + exported_deps = [ + ":core", + "//executorch/runtime/platform:compiler", + ], + visibility = [ + "//executorch/...", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tensor_layout.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tensor_layout.cpp similarity index 77% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tensor_layout.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tensor_layout.cpp index 97abe0b..d33f79f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tensor_layout.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tensor_layout.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -20,25 +19,15 @@ namespace { Result calculate_nbytes( const Span& sizes, const executorch::aten::ScalarType& scalar_type) { - size_t n = 1; + ssize_t n = 1; for (const auto i : c10::irange(sizes.size())) { if (sizes[i] < 0) { return Error::InvalidArgument; } - size_t next = 0; - if (c10::mul_overflows(n, static_cast(sizes[i]), &next)) { - return Error::InvalidArgument; - } - n = next; + n *= sizes[i]; } // Use the full namespace to disambiguate from c10::elementSize. - const size_t elem_size = - static_cast(executorch::runtime::elementSize(scalar_type)); - size_t total = 0; - if (c10::mul_overflows(n, elem_size, &total)) { - return Error::InvalidArgument; - } - return total; + return n * executorch::runtime::elementSize(scalar_type); } } // namespace diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tensor_layout.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tensor_layout.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tensor_layout.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tensor_layout.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tensor_shape_dynamism.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tensor_shape_dynamism.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tensor_shape_dynamism.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/tensor_shape_dynamism.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/CMakeLists.txt new file mode 100644 index 0000000..bdc427b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs + array_ref_test.cpp + error_handling_test.cpp + evalue_test.cpp + event_tracer_test.cpp + freeable_buffer_test.cpp + function_ref_test.cpp + hierarchical_allocator_test.cpp + memory_allocator_test.cpp + span_test.cpp +) + +et_cxx_test(runtime_core_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/array_ref_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/array_ref_test.cpp new file mode 100644 index 0000000..7fb8ee2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/array_ref_test.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; + +TEST(TestArrayRef, ImplicitTypeConversion) { + ArrayRef oneElement_1 = {1}; + EXPECT_EQ(oneElement_1.size(), 1); + + ArrayRef oneElement_2 = 1; + EXPECT_EQ(oneElement_2.size(), 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/error_handling_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/error_handling_test.cpp new file mode 100644 index 0000000..c1d48c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/error_handling_test.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include +#include +#include + +using executorch::runtime::Error; +using executorch::runtime::Result; + +static void* test_ptr = static_cast((uintptr_t*)0xDEADBEEF); + +Result get_abs(int64_t num) { + if (num >= 0) { + return static_cast(num); + } else { + return Error::InvalidArgument; + } +} + +Result get_op_name(int64_t op) { + auto abs_result = get_abs(op); + if (!abs_result.ok()) { + return abs_result.error(); + } + auto unsigned_op = abs_result.get(); + + switch (unsigned_op) { + case 0: + return std::string("Zero"); + case 1: + return std::string("One"); + default: + return Error::Internal; + } +} + +Result get_ptr(int64_t value) { + switch (value) { + case 0: + return nullptr; + case 1: + return test_ptr; + default: + return Error::InvalidArgument; + } +} + +class Uncopiable { + public: + explicit Uncopiable(uint32_t value) : value_(value) {} + Uncopiable(Uncopiable&& rhs) noexcept = default; + ~Uncopiable() = default; + + uint32_t getValue() const { + return value_; + } + + private: + // Delete other rule-of-five methods. + Uncopiable(const Uncopiable& rhs) = delete; + Uncopiable& operator=(Uncopiable&& rhs) noexcept = delete; + Uncopiable& operator=(const Uncopiable& rhs) = delete; + + uint32_t value_; +}; + +Result get_no_copy(uint32_t value) { + return Uncopiable(value); +} + +// A non-trivially-movable type. +class Movable { + public: + explicit Movable(size_t nbytes) : buffer_(malloc(nbytes)) {} + Movable(Movable&& rhs) noexcept : buffer_(rhs.buffer_) { + rhs.buffer_ = nullptr; + } + + ~Movable() { + // This will fail with a double-free if it wasn't moved properly. + free(buffer_); + } + + const void* buffer() const { + return buffer_; + } + + private: + // Delete other rule-of-five methods. + Movable(const Movable& rhs) = delete; + Movable& operator=(Movable&& rhs) noexcept = delete; + Movable& operator=(const Movable& rhs) = delete; + + mutable void* buffer_; +}; + +TEST(ErrorHandlingTest, ResultBasic) { + Result r(1); + ASSERT_TRUE(r.ok()); + ASSERT_EQ(r.error(), Error::Ok); + ASSERT_EQ(r.get(), 1); + ASSERT_EQ(*r, 1); +} + +TEST(ErrorHandlingTest, OkErrorNotPossible) { + executorch::runtime::runtime_init(); + Result r(Error::Ok); + ASSERT_FALSE(r.ok()); + ASSERT_NE(r.error(), Error::Ok); +} + +TEST(ErrorHandlingTest, ResultWithPrimitive) { + auto res = get_abs(100); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + + uint64_t unsigned_result = res.get(); + ASSERT_EQ(unsigned_result, 100); + unsigned_result = *res; + ASSERT_EQ(unsigned_result, 100); + + auto res2 = get_abs(-3); + ASSERT_FALSE(res2.ok()); + ASSERT_EQ(res2.error(), Error::InvalidArgument); +} + +TEST(ErrorHandlingTest, ResultWithCompound) { + auto res = get_op_name(0); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_EQ(res.get(), "Zero"); + ASSERT_EQ(*res, "Zero"); + + auto res2 = get_op_name(1); + ASSERT_TRUE(res2.ok()); + ASSERT_EQ(res2.error(), Error::Ok); + ASSERT_EQ(res2.get(), "One"); + ASSERT_EQ(*res2, "One"); + + auto res3 = get_op_name(2); + ASSERT_FALSE(res3.ok()); + ASSERT_EQ(res3.error(), Error::Internal); +} + +TEST(ErrorHandlingTest, ResultWithPointer) { + auto res = get_ptr(0); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_EQ(res.get(), nullptr); + ASSERT_EQ(*res, nullptr); + + auto res2 = get_ptr(1); + ASSERT_TRUE(res2.ok()); + ASSERT_EQ(res2.error(), Error::Ok); + ASSERT_EQ(res2.get(), test_ptr); + ASSERT_EQ(*res2, test_ptr); + + auto res3 = get_ptr(2); + ASSERT_FALSE(res3.ok()); + ASSERT_EQ(res3.error(), Error::InvalidArgument); +} + +TEST(ErrorHandlingTest, ResultUnwrap) { + auto res = get_op_name(-1); + ASSERT_FALSE(res.ok()); + ASSERT_EQ(res.error(), Error::InvalidArgument); +} + +TEST(ErrorHandlingTest, ResultNoCopy) { + auto res = get_no_copy(2); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_EQ(res.get().getValue(), 2); + ASSERT_EQ(res->getValue(), 2); + + auto res2 = std::move(res); + ASSERT_TRUE(res2.ok()); + ASSERT_EQ(res2.error(), Error::Ok); + ASSERT_EQ(res2.get().getValue(), 2); + ASSERT_EQ(res2->getValue(), 2); + + Uncopiable& uc = *res2; + ASSERT_EQ(uc.getValue(), 2); +} + +TEST(ErrorHandlingTest, ResultMove) { + executorch::runtime::runtime_init(); + + Result res = Movable(2); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_NE(res.get().buffer(), nullptr); + ASSERT_NE(res->buffer(), nullptr); + + const void* buffer = res->buffer(); + + // Move the value. + Movable m = std::move(*res); + // The target should point to the same buffer as the source originally did. + ASSERT_EQ(m.buffer(), buffer); + // The source inside the Result should no longer point to the buffer. + ASSERT_EQ(res->buffer(), nullptr); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/evalue_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/evalue_test.cpp new file mode 100644 index 0000000..9e91ad7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/evalue_test.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include +#include + +using namespace ::testing; + +using executorch::aten::ScalarType; +using executorch::runtime::BoxedEvalueList; +using executorch::runtime::EValue; +using executorch::runtime::Tag; +using executorch::runtime::testing::TensorFactory; + +class EValueTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +// An utility class used in tests to simulate objects that manage Tensors. +// The overloaded operator*() is used to return the underlying Tensor, mimicking +// behavior of smart pointers. +class TensorWrapper { + public: + explicit TensorWrapper(executorch::aten::Tensor tensor) + : tensor_(std::make_unique(std::move(tensor))) { + } + + executorch::aten::Tensor& operator*() { + return *tensor_; + } + + const executorch::aten::Tensor& operator*() const { + return *tensor_; + } + + operator bool() const { + return static_cast(tensor_); + } + + bool operator==(std::nullptr_t) const { + return tensor_ == nullptr; + } + + bool operator!=(std::nullptr_t) const { + return tensor_ != nullptr; + } + + private: + std::unique_ptr tensor_; +}; + +TEST_F(EValueTest, CopyTrivialType) { + EValue a; + EValue b(true); + EXPECT_TRUE(a.isNone()); + a = b; + EXPECT_TRUE(a.isBool()); + EXPECT_EQ(a.to(), true); + EXPECT_EQ(b.to(), true); +} + +TEST_F(EValueTest, CopyTensor) { + TensorFactory tf; + EValue a(tf.ones({3, 2})); + EValue b(tf.ones({1})); + EXPECT_EQ(a.toTensor().dim(), 2); + a = b; + EXPECT_EQ(a.toTensor().dim(), 1); +} + +TEST_F(EValueTest, TypeMismatchFatals) { + ET_EXPECT_DEATH( + { + auto e = EValue(true); + e.toInt(); + }, + ""); +} + +TEST_F(EValueTest, NoneByDefault) { + EValue e; + EXPECT_TRUE(e.isNone()); +} + +TEST_F(EValueTest, ToOptionalInt) { + EValue e((int64_t)5); + EXPECT_TRUE(e.isInt()); + EXPECT_FALSE(e.isNone()); + + std::optional o = e.toOptional(); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), 5); +} + +TEST_F(EValueTest, NoneToOptionalInt) { + EValue e; + EXPECT_TRUE(e.isNone()); + + std::optional o = e.toOptional(); + EXPECT_FALSE(o.has_value()); +} + +TEST_F(EValueTest, ToOptionalScalar) { + executorch::aten::Scalar s((double)3.141); + EValue e(s); + EXPECT_TRUE(e.isScalar()); + EXPECT_FALSE(e.isNone()); + + std::optional o = + e.toOptional(); + EXPECT_TRUE(o.has_value()); + EXPECT_TRUE(o.value().isFloatingPoint()); + EXPECT_EQ(o.value().to(), 3.141); +} + +TEST_F(EValueTest, ScalarToType) { + executorch::aten::Scalar s_d((double)3.141); + EXPECT_EQ(s_d.to(), 3.141); + executorch::aten::Scalar s_i((int64_t)3); + EXPECT_EQ(s_i.to(), 3); + executorch::aten::Scalar s_b(true); + EXPECT_EQ(s_b.to(), true); +} + +TEST_F(EValueTest, NoneToOptionalScalar) { + EValue e; + EXPECT_TRUE(e.isNone()); + + std::optional o = + e.toOptional(); + EXPECT_FALSE(o.has_value()); +} + +TEST_F(EValueTest, NoneToOptionalTensor) { + EValue e; + EXPECT_TRUE(e.isNone()); + + std::optional o = + e.toOptional(); + EXPECT_FALSE(o.has_value()); +} + +TEST_F(EValueTest, ToScalarType) { + EValue e((int64_t)4); + auto o = e.toScalarType(); + EXPECT_EQ(o, executorch::aten::ScalarType::Long); + EValue f((int64_t)4); + auto o2 = e.toOptional(); + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), executorch::aten::ScalarType::Long); +} + +TEST_F(EValueTest, toString) { + auto string_ref = + std::make_unique>("foo", 3); + const EValue e(string_ref.get()); + EXPECT_TRUE(e.isString()); + EXPECT_FALSE(e.isNone()); + + std::string_view x = e.toString(); + EXPECT_EQ(x, "foo"); +} + +TEST_F(EValueTest, MemoryFormat) { + const EValue e((int64_t)0); + EXPECT_TRUE(e.isInt()); + const executorch::aten::MemoryFormat m = + e.to(); + EXPECT_EQ(m, executorch::aten::MemoryFormat::Contiguous); +} + +TEST_F(EValueTest, Layout) { + const EValue e((int64_t)0); + EXPECT_TRUE(e.isInt()); + const executorch::aten::Layout l = e.to(); + EXPECT_EQ(l, executorch::aten::Layout::Strided); +} + +TEST_F(EValueTest, Device) { + const EValue e((int64_t)0); + EXPECT_TRUE(e.isInt()); + const executorch::aten::Device d = e.to(); + EXPECT_TRUE(d.is_cpu()); +} + +TEST_F(EValueTest, BoxedEvalueList) { + // create fake values table to point to + EValue values[3] = { + EValue((int64_t)1), EValue((int64_t)2), EValue((int64_t)3)}; + // create wrapped and unwrapped lists + EValue* values_p[3] = {&values[0], &values[1], &values[2]}; + int64_t storage[3] = {0, 0, 0}; + // Create Object List and test + BoxedEvalueList x{values_p, storage, 3}; + auto unwrapped = x.get(); + EXPECT_EQ(unwrapped.size(), 3); + EXPECT_EQ(unwrapped[0], 1); + EXPECT_EQ(unwrapped[1], 2); + EXPECT_EQ(unwrapped[2], 3); +} + +TEST_F(EValueTest, toOptionalTensorList) { + // create list, empty evalue ctor gets tag::None + EValue values[2] = {EValue(), EValue()}; + EValue* values_p[2] = {&values[0], &values[1]}; + std::optional storage[2]; + // wrap in array ref + auto boxed_list = std::make_unique< + BoxedEvalueList>>( + values_p, storage, 2); + + // create Evalue + EValue e(boxed_list.get()); + e.tag = Tag::ListOptionalTensor; + EXPECT_TRUE(e.isListOptionalTensor()); + + // Convert back to list + executorch::aten::ArrayRef> x = + e.toListOptionalTensor(); + EXPECT_EQ(x.size(), 2); + EXPECT_FALSE(x[0].has_value()); + EXPECT_FALSE(x[1].has_value()); +} + +TEST_F(EValueTest, ConstructFromUniquePtr) { + TensorFactory tf; + auto tensor_ptr = std::make_unique(tf.ones({2, 3})); + + EValue evalue(std::move(tensor_ptr)); + + EXPECT_TRUE(evalue.isTensor()); + EXPECT_EQ(evalue.toTensor().dim(), 2); + EXPECT_EQ(evalue.toTensor().numel(), 6); + + EValue evalue2(std::make_unique(tf.ones({4, 5}))); + + EXPECT_TRUE(evalue2.isTensor()); + EXPECT_EQ(evalue2.toTensor().dim(), 2); + EXPECT_EQ(evalue2.toTensor().numel(), 20); +} + +TEST_F(EValueTest, ConstructFromSharedPtr) { + TensorFactory tf; + auto tensor_ptr = std::make_shared(tf.ones({4, 5})); + + EValue evalue(tensor_ptr); + + EXPECT_TRUE(evalue.isTensor()); + EXPECT_EQ(evalue.toTensor().dim(), 2); + EXPECT_EQ(evalue.toTensor().numel(), 20); +} + +TEST_F(EValueTest, ConstructFromTensorWrapper) { + TensorFactory tf; + TensorWrapper tensor_wrapper(tf.ones({4, 5})); + + EValue evalue(tensor_wrapper); + + EXPECT_TRUE(evalue.isTensor()); + EXPECT_EQ(evalue.toTensor().dim(), 2); + EXPECT_EQ(evalue.toTensor().numel(), 20); +} + +TEST_F(EValueTest, ConstructFromNullPtrAborts) { + std::unique_ptr null_ptr; + + ET_EXPECT_DEATH({ EValue evalue(null_ptr); }, ""); +} + +TEST_F(EValueTest, StringConstructorNullCheck) { + executorch::aten::ArrayRef* null_string_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_string_ptr); }, ""); +} + +TEST_F(EValueTest, BoolListConstructorNullCheck) { + executorch::aten::ArrayRef* null_bool_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_bool_list_ptr); }, ""); +} + +TEST_F(EValueTest, DoubleListConstructorNullCheck) { + executorch::aten::ArrayRef* null_double_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_double_list_ptr); }, ""); +} + +TEST_F(EValueTest, IntListConstructorNullCheck) { + BoxedEvalueList* null_int_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_int_list_ptr); }, ""); +} + +TEST_F(EValueTest, TensorListConstructorNullCheck) { + BoxedEvalueList* null_tensor_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_tensor_list_ptr); }, ""); +} + +TEST_F(EValueTest, OptionalTensorListConstructorNullCheck) { + BoxedEvalueList>* + null_optional_tensor_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_optional_tensor_list_ptr); }, ""); +} + +TEST_F(EValueTest, BoxedEvalueListConstructorNullChecks) { + std::array storage = {0, 0, 0}; + std::array values = { + EValue((int64_t)1), EValue((int64_t)2), EValue((int64_t)3)}; + std::array values_p = {&values[0], &values[1], &values[2]}; + + // Test null wrapped_vals + ET_EXPECT_DEATH( + { BoxedEvalueList list(nullptr, storage.data(), 3); }, ""); + + // Test null unwrapped_vals + ET_EXPECT_DEATH( + { BoxedEvalueList list(values_p.data(), nullptr, 3); }, ""); + + // Test negative size + ET_EXPECT_DEATH( + { BoxedEvalueList list(values_p.data(), storage.data(), -1); }, + ""); +} + +TEST_F(EValueTest, toListOptionalTensorTypeCheck) { + // Create an EValue that's not a ListOptionalTensor + EValue e((int64_t)42); + EXPECT_TRUE(e.isInt()); + EXPECT_FALSE(e.isListOptionalTensor()); + + // Should fail type check + ET_EXPECT_DEATH({ e.toListOptionalTensor(); }, ""); +} + +TEST_F(EValueTest, toStringNullPointerCheck) { + // Create an EValue with String tag but null pointer + EValue e; + e.tag = Tag::String; + e.payload.copyable_union.as_string_ptr = nullptr; + + // Should pass isString() check but fail null pointer check + EXPECT_TRUE(e.isString()); + ET_EXPECT_DEATH({ e.toString(); }, ""); +} + +TEST_F(EValueTest, toIntListNullPointerCheck) { + // Create an EValue with ListInt tag but null pointer + EValue e; + e.tag = Tag::ListInt; + e.payload.copyable_union.as_int_list_ptr = nullptr; + + // Should pass isIntList() check but fail null pointer check + EXPECT_TRUE(e.isIntList()); + ET_EXPECT_DEATH({ e.toIntList(); }, ""); +} + +TEST_F(EValueTest, toBoolListNullPointerCheck) { + // Create an EValue with ListBool tag but null pointer + EValue e; + e.tag = Tag::ListBool; + e.payload.copyable_union.as_bool_list_ptr = nullptr; + + // Should pass isBoolList() check but fail null pointer check + EXPECT_TRUE(e.isBoolList()); + ET_EXPECT_DEATH({ e.toBoolList(); }, ""); +} + +TEST_F(EValueTest, toDoubleListNullPointerCheck) { + // Create an EValue with ListDouble tag but null pointer + EValue e; + e.tag = Tag::ListDouble; + e.payload.copyable_union.as_double_list_ptr = nullptr; + + // Should pass isDoubleList() check but fail null pointer check + EXPECT_TRUE(e.isDoubleList()); + ET_EXPECT_DEATH({ e.toDoubleList(); }, ""); +} + +TEST_F(EValueTest, toTensorListNullPointerCheck) { + // Create an EValue with ListTensor tag but null pointer + EValue e; + e.tag = Tag::ListTensor; + e.payload.copyable_union.as_tensor_list_ptr = nullptr; + + // Should pass isTensorList() check but fail null pointer check + EXPECT_TRUE(e.isTensorList()); + ET_EXPECT_DEATH({ e.toTensorList(); }, ""); +} + +TEST_F(EValueTest, toListOptionalTensorNullPointerCheck) { + // Create an EValue with ListOptionalTensor tag but null pointer + EValue e; + e.tag = Tag::ListOptionalTensor; + e.payload.copyable_union.as_list_optional_tensor_ptr = nullptr; + + // Should pass isListOptionalTensor() check but fail null pointer check + EXPECT_TRUE(e.isListOptionalTensor()); + ET_EXPECT_DEATH({ e.toListOptionalTensor(); }, ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/event_tracer_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/event_tracer_test.cpp new file mode 100644 index 0000000..1c9e1a4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/event_tracer_test.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +// Enable flag for test +#define ET_EVENT_TRACER_ENABLED +#include +#include + +using executorch::aten::Tensor; +using executorch::runtime::AllocatorID; +using executorch::runtime::ArrayRef; +using executorch::runtime::ChainID; +using executorch::runtime::DebugHandle; +using executorch::runtime::DelegateDebugIntId; +using executorch::runtime::EValue; +using executorch::runtime::EventTracer; +using executorch::runtime::EventTracerDebugLogLevel; +using executorch::runtime::EventTracerEntry; +using executorch::runtime::EventTracerFilterBase; +using executorch::runtime::kUnsetChainId; +using executorch::runtime::kUnsetDebugHandle; +using executorch::runtime::kUnsetDelegateDebugIntId; +using executorch::runtime::LoggedEValueType; +using executorch::runtime::Result; + +class DummyEventTracer : public EventTracer { + public: + DummyEventTracer() {} + + ~DummyEventTracer() override {} + + void create_event_block(const char* name) override { + (void)name; + return; + } + + EventTracerEntry start_profiling( + const char* name, + ChainID chain_id = kUnsetChainId, + DebugHandle debug_handle = kUnsetDebugHandle) override { + (void)chain_id; + (void)debug_handle; + ET_CHECK(strlen(name) + 1 < sizeof(event_name_)); + memcpy(event_name_, name, strlen(name) + 1); + return EventTracerEntry(); + } + + void end_profiling(EventTracerEntry prof_entry) override { + (void)prof_entry; + memset(event_name_, 0, sizeof(event_name_)); + return; + } + + void track_allocation(AllocatorID id, size_t size) override { + (void)id; + (void)size; + return; + } + + AllocatorID track_allocator(const char* name) override { + (void)name; + return 0; + } + + EventTracerEntry start_profiling_delegate( + const char* name, + DelegateDebugIntId delegate_debug_id) override { + (void)name; + (void)delegate_debug_id; + return EventTracerEntry(); + } + + void end_profiling_delegate( + ET_UNUSED EventTracerEntry event_tracer_entry, + ET_UNUSED const void* metadata, + ET_UNUSED size_t metadata_len) override { + (void)event_tracer_entry; + (void)metadata; + (void)metadata_len; + } + + void set_delegation_intermediate_output_filter( + EventTracerFilterBase* event_tracer_filter) override { + (void)event_tracer_filter; + } + + void log_profiling_delegate( + const char* name, + DelegateDebugIntId delegate_debug_id, + et_timestamp_t start_time, + et_timestamp_t end_time, + const void* metadata, + size_t metadata_len = 0) override { + (void)name; + (void)delegate_debug_id; + (void)start_time; + (void)end_time; + (void)metadata; + (void)metadata_len; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const Tensor& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const ArrayRef output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const int& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const bool& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const double& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + Result log_evalue(const EValue& evalue, LoggedEValueType evalue_type) + override { + logged_evalue_ = evalue; + logged_evalue_type_ = evalue_type; + return true; + } + + EValue logged_evalue() { + return logged_evalue_; + } + + LoggedEValueType logged_evalue_type() { + return logged_evalue_type_; + } + + char* get_event_name() { + return event_name_; + } + + void reset_logged_value() { + logged_evalue_ = EValue(false); + } + + private: + EValue logged_evalue_ = EValue(false); + LoggedEValueType logged_evalue_type_; + char event_name_[1024]; +}; + +/** + * Exercise all the event_tracer API's for a basic sanity check. + */ +void RunSimpleTracerTest(EventTracer* event_tracer) { + using executorch::runtime::internal::event_tracer_begin_profiling_event; + using executorch::runtime::internal::event_tracer_create_event_block; + using executorch::runtime::internal::event_tracer_end_profiling_event; + using executorch::runtime::internal::event_tracer_track_allocation; + using executorch::runtime::internal::event_tracer_track_allocator; + using executorch::runtime::internal::EventTracerProfileInstructionScope; + using executorch::runtime::internal::EventTracerProfileMethodScope; + + event_tracer_create_event_block(event_tracer, "ExampleEvent"); + event_tracer_create_event_block(event_tracer, "ExampleEvent"); + EventTracerEntry event_entry = + event_tracer_begin_profiling_event(event_tracer, "ExampleEvent"); + event_tracer_end_profiling_event(event_tracer, event_entry); + { + EventTracerProfileMethodScope event_tracer_profile_scope( + event_tracer, "ExampleScope"); + } + { + EventTracerProfileInstructionScope event_tracer_profile_instruction_scope( + event_tracer, 0, 1); + } + AllocatorID allocator_id = + event_tracer_track_allocator(event_tracer, "AllocatorName"); + event_tracer_track_allocation(event_tracer, allocator_id, 64); +} + +TEST(TestEventTracer, SimpleEventTracerTest) { + // Call all the EventTracer macro's with a valid pointer to an event tracer + // and also with a null pointer (to test that the null case works). + DummyEventTracer dummy; + std::vector dummy_event_tracer_arr = {&dummy, nullptr}; + for (const auto i : c10::irange(dummy_event_tracer_arr.size())) { + RunSimpleTracerTest(&dummy); + RunSimpleTracerTest(nullptr); + } +} + +/** + * Exercise all the event_tracer API's for delegates as a basic sanity check. + */ +void RunSimpleTracerTestDelegate(EventTracer* event_tracer) { + EventTracerEntry event_tracer_entry = event_tracer_start_profiling_delegate( + event_tracer, "test_event", kUnsetDelegateDebugIntId); + event_tracer_end_profiling_delegate( + event_tracer, event_tracer_entry, nullptr); + event_tracer_start_profiling_delegate(event_tracer, nullptr, 1); + event_tracer_end_profiling_delegate( + event_tracer, event_tracer_entry, "test_metadata"); + event_tracer_log_profiling_delegate( + event_tracer, "test_event", kUnsetDelegateDebugIntId, 0, 1, nullptr); + event_tracer_log_profiling_delegate(event_tracer, nullptr, 1, 0, 1, nullptr); +} + +TEST(TestEventTracer, SimpleEventTracerTestDelegate) { + // Call all the EventTracer macro's with a valid pointer to an event tracer + // and also with a null pointer (to test that the null case works). + DummyEventTracer dummy; + std::vector dummy_event_tracer_arr = {&dummy, nullptr}; + for (const auto i : c10::irange(dummy_event_tracer_arr.size())) { + RunSimpleTracerTestDelegate(&dummy); + RunSimpleTracerTestDelegate(nullptr); + } +} + +TEST(TestEventTracer, SimpleEventTracerTestLogging) { + using executorch::runtime::internal::event_tracer_log_evalue; + using executorch::runtime::internal::event_tracer_log_evalue_output; + + EValue test_eval(true); + + { + // By default there should be no logging enabled. + DummyEventTracer dummy; + event_tracer_log_evalue(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), false); + } + + { + // Enable only program outputs to be logged. So event_tracer_log_evalue + // should have no effect but event_tracer_log_evalue_output should work. + DummyEventTracer dummy; + dummy.set_event_tracer_debug_level( + EventTracerDebugLogLevel::kProgramOutputs); + event_tracer_log_evalue(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), false); + event_tracer_log_evalue_output(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), true); + EXPECT_EQ(dummy.logged_evalue_type(), LoggedEValueType::kProgramOutput); + } + + { + // Enable all outputs to be logged. So event_tracer_log_evalue and + // event_tracer_log_evalue_output should both work. + DummyEventTracer dummy; + dummy.set_event_tracer_debug_level( + EventTracerDebugLogLevel::kIntermediateOutputs); + event_tracer_log_evalue(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), true); + EXPECT_EQ( + dummy.logged_evalue_type(), LoggedEValueType::kIntermediateOutput); + dummy.reset_logged_value(); + event_tracer_log_evalue_output(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), true); + EXPECT_EQ(dummy.logged_evalue_type(), LoggedEValueType::kProgramOutput); + } + + // Test with nullptr's to make sure it goes through smoothly. + event_tracer_log_evalue(nullptr, test_eval); + event_tracer_log_evalue_output(nullptr, test_eval); +} + +// TODO(T163645377): Add more test coverage to log and verify events passed into +// DummyTracer. +TEST(TestEventTracer, EventTracerProfileOpControl) { + DummyEventTracer dummy; + // Op profiling is enabled by default. Test that it works. + { + { + executorch::runtime::internal::EventTracerProfileOpScope + event_tracer_op_scope(&dummy, "ExampleOpScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), "ExampleOpScope"), 0); + } + EXPECT_EQ(strcmp(dummy.get_event_name(), ""), 0); + + // Normal profiling should still work. + { + executorch::runtime::internal::EventTracerProfileMethodScope + event_tracer_profiler_scope(&dummy, "ExampleProfilerScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), "ExampleProfilerScope"), 0); + } + + dummy.set_event_tracer_profiling_level( + executorch::runtime::EventTracerProfilingLevel::kProfileMethodOnly); + + // Op profiling should be disabled now. + { + executorch::runtime::internal::EventTracerProfileOpScope + event_tracer_op_scope(&dummy, "ExampleOpScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), ""), 0); + } + + // Normal profiling should still work. + { + executorch::runtime::internal::EventTracerProfileMethodScope + event_tracer_profiler_scope(&dummy, "1ExampleProfilerScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), "1ExampleProfilerScope"), 0); + } + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/freeable_buffer_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/freeable_buffer_test.cpp new file mode 100644 index 0000000..2848a6b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/freeable_buffer_test.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +using namespace ::testing; + +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; + +struct FreeCallArgs { + size_t calls; + std::variant data; + size_t size; +}; + +void RecordFree(void* context, void* data, size_t size) { + auto* call = reinterpret_cast(context); + call->calls++; + call->data = data; + call->size = size; +} + +void RecordInt64Free(void* context, uint64_t data, size_t size) { + auto* call = reinterpret_cast(context); + call->calls++; + call->data = data; + call->size = size; +} + +TEST(FreeableBufferTest, EmptyTest) { + FreeableBuffer fb; + EXPECT_EQ(fb.data(), nullptr); + EXPECT_EQ(fb.data_safe().error(), Error::Ok); + EXPECT_EQ(fb.data_safe().get(), nullptr); + EXPECT_EQ(fb.size(), 0); +} + +TEST(FreeableBufferTest, DataAndSizeTest) { + int i; + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/nullptr); + + // It should return the ctor params unmodified. + EXPECT_EQ(fb.size(), sizeof(i)); + EXPECT_EQ(fb.data(), &i); + EXPECT_EQ(fb.data_safe().error(), Error::Ok); + EXPECT_EQ(fb.data_safe().get(), &i); + + // Freeing should clear them, even though free_fn is nullptr. + fb.Free(); + EXPECT_EQ(fb.size(), 0); + EXPECT_EQ(fb.data(), nullptr); + EXPECT_EQ(fb.data_safe().error(), Error::Ok); + EXPECT_EQ(fb.data_safe().get(), nullptr); + + // Use uint64_t constructor. + const uint64_t i64 = 1; + FreeableBuffer fb2( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/nullptr); + + // It should return the ctor params unmodified. + EXPECT_EQ(fb2.size(), sizeof(i64)); + EXPECT_EQ(fb2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb2.data_uint64_type().get(), i64); + + // Freeing should clear them, even though free_fn is nullptr. + fb2.Free(); + EXPECT_EQ(fb2.size(), 0); + EXPECT_EQ(fb2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb2.data_uint64_type().get(), 0); +} + +TEST(FreeableBufferTest, FreeTest) { + // Updated when RecordFree() is called. + FreeCallArgs call = {}; + + { + // Create a FreeableBuffer with a free_fn that records when it's called. + int i; + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/RecordFree, + /*free_fn_context=*/&call); + + // Not called during construction. + EXPECT_EQ(call.calls, 0); + + // Called once during Free() with the expected data/size. + fb.Free(); + EXPECT_EQ(call.calls, 1); + EXPECT_EQ(std::get(call.data), &i); + EXPECT_EQ(call.size, sizeof(i)); + + // A second call to Free() should not call the function again. + fb.Free(); + EXPECT_EQ(call.calls, 1); + } + + // The destructor should not have called the function again. + EXPECT_EQ(call.calls, 1); + + // Test with uint64_t constructor and free function. + FreeCallArgs call2 = {}; + { + uint64_t i64 = 1; + FreeableBuffer fb( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/RecordInt64Free, + /*free_fn_context=*/&call2); + + // Not called during construction. + EXPECT_EQ(call2.calls, 0); + + // Called once during Free() with the expected data/size. + fb.Free(); + EXPECT_EQ(call2.calls, 1); + EXPECT_EQ(std::get(call2.data), i64); + EXPECT_EQ(call2.size, sizeof(i64)); + + // A second call to Free() should not call the function again. + fb.Free(); + EXPECT_EQ(call2.calls, 1); + } + EXPECT_EQ(call2.calls, 1); +} + +TEST(FreeableBufferTest, DestructorTest) { + // Updated when RecordFree() is called. + FreeCallArgs call = {}; + int i; + + { + // Create a FreeableBuffer with a free_fn that records when it's called. + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/RecordFree, + /*free_fn_context=*/&call); + + // Not called during construction. + EXPECT_EQ(call.calls, 0); + } + + // The destructor should have freed the data. + EXPECT_EQ(call.calls, 1); + EXPECT_EQ(std::get(call.data), &i); + EXPECT_EQ(call.size, sizeof(i)); + + // Test with uint64_t constructor and free function. + FreeCallArgs call2 = {}; + uint64_t i64 = 1; + { + FreeableBuffer fb2( + /*data_uint64=*/i64, + /*size=*/sizeof(i), + /*free_fn=*/RecordInt64Free, + /*free_fn_context=*/&call2); + EXPECT_EQ(call2.calls, 0); + } + // The destructor should have freed the data. + EXPECT_EQ(call2.calls, 1); + EXPECT_EQ(std::get(call2.data), i64); + EXPECT_EQ(call2.size, sizeof(i)); +} + +TEST(FreeableBufferTest, MoveTest) { + // Updated when RecordFree() is called. + FreeCallArgs call = {}; + int i; + + // Create a FreeableBuffer with some data. + FreeableBuffer fb_src( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/RecordFree, + /*free_fn_context=*/&call); + EXPECT_EQ(fb_src.size(), sizeof(i)); + EXPECT_EQ(fb_src.data(), &i); + + // Move it into a second FreeableBuffer. + FreeableBuffer fb_dst(std::move(fb_src)); + + // The source FreeableBuffer should now be empty. + EXPECT_EQ(fb_src.size(), 0); // NOLINT(bugprone-use-after-move) + EXPECT_EQ(fb_src.data(), nullptr); // NOLINT(bugprone-use-after-move) + + // The destination FreeableBuffer should have the data. + EXPECT_EQ(fb_dst.size(), sizeof(i)); + EXPECT_EQ(fb_dst.data(), &i); + // Freeing the source FreeableBuffer should not call the free function. + fb_src.Free(); + EXPECT_EQ(call.calls, 0); + + // Freeing the destination FreeableBuffer should call the free function. + fb_dst.Free(); + EXPECT_EQ(call.calls, 1); + EXPECT_EQ(call.size, sizeof(i)); + + // Test with uint64_t constructor and free function. + FreeCallArgs call2 = {}; + const uint64_t i64 = 1; + FreeableBuffer fb_src2( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/RecordInt64Free, + /*free_fn_context=*/&call2); + EXPECT_EQ(fb_src2.size(), sizeof(i64)); + EXPECT_EQ(fb_src2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb_src2.data_uint64_type().get(), i64); + + // Move it into a second FreeableBuffer. + FreeableBuffer fb_dst2(std::move(fb_src2)); + + // The source FreeableBuffer should now be empty. + EXPECT_EQ(fb_src2.size(), 0); // NOLINT(bugprone-use-after-move) + EXPECT_EQ( + fb_src2.data_uint64_type().error(), + Error::Ok); // NOLINT(bugprone-use-after-move) + EXPECT_EQ( + fb_src2.data_uint64_type().get(), 0); // NOLINT(bugprone-use-after-move) + + // The destination FreeableBuffer should have the data. + EXPECT_EQ(fb_dst2.size(), sizeof(i64)); + EXPECT_EQ(fb_dst2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb_dst2.data_uint64_type().get(), i64); + // Freeing the source FreeableBuffer should not call the free function. + fb_src2.Free(); + EXPECT_EQ(call2.calls, 0); + + // Freeing the destination FreeableBuffer should call the free function. + fb_dst2.Free(); + EXPECT_EQ(call2.calls, 1); + EXPECT_EQ(call2.size, sizeof(i64)); +} + +TEST(FreeableBufferTest, APIMisuseDeathTest) { + executorch::runtime::pal_init(); + int i; + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/nullptr); + EXPECT_EQ(fb.data_uint64_type().error(), Error::InvalidType); + + uint64_t i64 = 1; + FreeableBuffer fb2( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/nullptr); + EXPECT_EQ(fb2.data_safe().error(), Error::InvalidType); + ET_EXPECT_DEATH(fb2.data(), ".*"); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/function_ref_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/function_ref_test.cpp new file mode 100644 index 0000000..beef008 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/function_ref_test.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; + +using ::executorch::runtime::FunctionRef; + +namespace { +void one(int32_t& i) { + i = 1; +} + +} // namespace + +TEST(FunctionRefTest, CapturingLambda) { + auto one = 1; + auto f = [&](int32_t& i) { i = one; }; + int32_t val = 0; + FunctionRef{f}(val); + EXPECT_EQ(val, 1); + // ERROR: + // Item item1(0, f); + // Item item2(0, [&](int32_t& i) { i = 2; }); + // FunctionRef ref([&](int32_t&){}); +} + +TEST(FunctionRefTest, NonCapturingLambda) { + int32_t val = 0; + FunctionRef ref([](int32_t& i) { i = 1; }); + ref(val); + EXPECT_EQ(val, 1); + + val = 0; + auto lambda = [](int32_t& i) { i = 1; }; + FunctionRef ref1(lambda); + ref1(val); + EXPECT_EQ(val, 1); +} + +TEST(FunctionRefTest, FunctionPointer) { + int32_t val = 0; + FunctionRef ref(one); + ref(val); + EXPECT_EQ(val, 1); + + val = 0; + FunctionRef ref2(one); + ref2(val); + EXPECT_EQ(val, 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/hierarchical_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/hierarchical_allocator_test.cpp new file mode 100644 index 0000000..e25e1eb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/hierarchical_allocator_test.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::HierarchicalAllocator; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +class HierarchicalAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(HierarchicalAllocatorTest, Smoke) { + constexpr size_t n_buffers = 2; + constexpr size_t size0 = 4; + constexpr size_t size1 = 8; + uint8_t mem0[size0]; + uint8_t mem1[size1]; + Span buffers[n_buffers]{ + {mem0, size0}, + {mem1, size1}, + }; + + HierarchicalAllocator allocator({buffers, n_buffers}); + + // get_offset_address() success cases + { + // Total size is 4, so off=0 + size=2 fits. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem0); + } + { + // Total size is 8, so off=4 + size=4 fits exactly. + Result address = allocator.get_offset_address( + /*memory_id=*/1, /*offset_bytes=*/4, /*size_bytes=*/4); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem1 + 4); + } + + // get_offset_address() failure cases + { + // Total size is 4, so off=0 + size=5 is too large. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/4, /*size_bytes=*/5); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // Total size is 4, so off=8 + size=0 is off the end. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/8, /*size_bytes=*/0); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // ID too large; only two zero-indexed entries in the allocator. + Result address = allocator.get_offset_address( + /*memory_id=*/2, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } +} + +// TODO(T162089316): Tests the deprecated API. Remove this when removing the +// API. +TEST_F(HierarchicalAllocatorTest, DEPRECATEDSmoke) { + constexpr size_t n_allocators = 2; + constexpr size_t size0 = 4; + constexpr size_t size1 = 8; + uint8_t mem0[size0]; + uint8_t mem1[size1]; + MemoryAllocator allocators[n_allocators]{ + MemoryAllocator(size0, mem0), MemoryAllocator(size1, mem1)}; + + HierarchicalAllocator allocator(n_allocators, allocators); + + // get_offset_address() success cases + { + // Total size is 4, so off=0 + size=2 fits. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem0); + } + { + // Total size is 8, so off=4 + size=4 fits exactly. + Result address = allocator.get_offset_address( + /*memory_id=*/1, /*offset_bytes=*/4, /*size_bytes=*/4); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem1 + 4); + } + + // get_offset_address() failure cases + { + // Total size is 4, so off=0 + size=5 is too large. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/4, /*size_bytes=*/5); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // Total size is 4, so off=8 + size=0 is off the end. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/8, /*size_bytes=*/0); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // ID too large; only two zero-indexed entries in the allocator. + Result address = allocator.get_offset_address( + /*memory_id=*/2, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/memory_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/memory_allocator_test.cpp new file mode 100644 index 0000000..fee95a6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/memory_allocator_test.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::MemoryAllocator; + +struct TestType8 { + char data[8]; +}; +static_assert(sizeof(TestType8) == 8); + +struct TestType1024 { + char data[1024]; +}; +static_assert(sizeof(TestType1024) == 1024); + +class MemoryAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(MemoryAllocatorTest, MemoryAllocator) { + constexpr size_t mem_size = 16; + uint8_t mem_pool[mem_size]; + MemoryAllocator allocator(mem_size, mem_pool); + ASSERT_NE(nullptr, allocator.allocate(7)); + ASSERT_NE(nullptr, allocator.allocate(6)); + ASSERT_EQ(nullptr, allocator.allocate(3)); + + allocator.reset(); + ASSERT_EQ(mem_pool, allocator.allocate(0)); + ASSERT_NE(nullptr, allocator.allocate(16)); +} + +TEST_F(MemoryAllocatorTest, MemoryAllocatorAlignment) { + constexpr size_t arr_size = 6; + size_t allocation[arr_size] = {7, 6, 3, 76, 4, 1}; + size_t alignment[arr_size] = { + MemoryAllocator::kDefaultAlignment, + MemoryAllocator::kDefaultAlignment, + 4, + 32, + 128, + 2}; + + for (const auto i : c10::irange(arr_size)) { + auto align_size = alignment[i]; + constexpr size_t mem_size = 1000; + uint8_t mem_pool[mem_size]; + MemoryAllocator allocator = MemoryAllocator(mem_size, mem_pool); + for (const auto j : c10::irange(arr_size)) { + auto size = allocation[j]; + void* start = allocator.allocate(size, align_size); + EXPECT_ALIGNED(start, align_size); + } + } +} + +TEST_F(MemoryAllocatorTest, MemoryAllocatorNonPowerOfTwoAlignment) { + constexpr size_t mem_size = 128; + uint8_t mem_pool[mem_size]; + MemoryAllocator allocator(mem_size, mem_pool); + + size_t alignment[5] = {0, 5, 6, 12, 34}; + for (const auto i : c10::irange(5)) { + ASSERT_EQ(nullptr, allocator.allocate(8, alignment[i])); + } +} + +TEST_F(MemoryAllocatorTest, MemoryAllocatorTooLargeFailButSucceedAfterwards) { + constexpr size_t kPoolSize = 10; + uint8_t mem_pool[kPoolSize]; + MemoryAllocator allocator(kPoolSize, mem_pool); + // Align to 1 byte so the entire pool is used. The default alignment could + // skip over the first few bytes depending on the alignment of `mem_pool`. + ASSERT_EQ(nullptr, allocator.allocate(kPoolSize + 2, /*alignment=*/1)); + ASSERT_NE(nullptr, allocator.allocate(kPoolSize - 1, /*alignment=*/1)); +} + +template +static void test_allocate_instance() { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Default alignment + auto p = allocator.allocateInstance(); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignof(T)); + memset(p, 0x55, sizeof(T)); + + // Override alignment + constexpr size_t kHigherAlignment = 64; + EXPECT_GT(kHigherAlignment, alignof(T)); + p = allocator.allocateInstance(kHigherAlignment); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kHigherAlignment); + memset(p, 0x55, sizeof(T)); +} + +TEST_F(MemoryAllocatorTest, AllocateInstance) { + test_allocate_instance(); + test_allocate_instance(); + test_allocate_instance(); + test_allocate_instance(); + test_allocate_instance(); + + struct StructWithPointer { + void* p; + int i; + }; + test_allocate_instance(); + + struct StructWithLargestType { + std::max_align_t max; + int i; + }; + test_allocate_instance(); +} + +TEST_F(MemoryAllocatorTest, AllocateInstanceFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + auto p = allocator.allocateInstance(); + EXPECT_EQ(p, nullptr); +} + +template +static void test_allocate_list() { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Default alignment + constexpr size_t kNumElem = 5; + auto p = allocator.allocateList(kNumElem); + ASSERT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignof(T)); + memset(p, 0x55, kNumElem * sizeof(T)); + + // Override alignment + constexpr size_t kHigherAlignment = 64; + EXPECT_GT(kHigherAlignment, alignof(T)); + p = allocator.allocateList(kNumElem, kHigherAlignment); + ASSERT_NE(p, nullptr); + EXPECT_ALIGNED(p, kHigherAlignment); + memset(p, 0x55, kNumElem * sizeof(T)); +} + +TEST_F(MemoryAllocatorTest, AllocateList) { + test_allocate_list(); + test_allocate_list(); + test_allocate_list(); + test_allocate_list(); + test_allocate_list(); + + struct StructWithPointer { + void* p; + char c; + }; + test_allocate_instance(); + + struct StructWithLargestType { + std::max_align_t max; + int i; + }; + test_allocate_instance(); +} + +TEST_F(MemoryAllocatorTest, AllocateListFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + auto p = allocator.allocateList(10); + EXPECT_EQ(p, nullptr); +} + +class HelperMacrosTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +/** + * An Error value that doesn't map to anything defined in Error.h. Helps + * demonstrate that the code here is being executed, and that the macro isn't + * returning a canned Error value. + */ +static const Error kTestFailureValue = static_cast(12345); + +TEST_F(HelperMacrosTest, TryAllocateSuccess) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate less memory than the allocator provides, which should succeed. + void* p = allocator.allocate(allocator.size() / 2); + EXPECT_NE(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + void* p = allocator.allocate(allocator.size() * 2); + EXPECT_EQ(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateInstanceSuccess) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate less memory than the allocator provides, which should succeed. + TestType8* p = allocator.allocateInstance(); + EXPECT_NE(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateInstanceFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + TestType1024* p = allocator.allocateInstance(); + EXPECT_EQ(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateListSuccess) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate less memory than the allocator provides, which should succeed. + void* p = allocator.allocateList(allocator.size() / 2); + EXPECT_NE(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateListFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + void* p = allocator.allocateList(allocator.size() * 2); + EXPECT_EQ(p, nullptr); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/span_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/span_test.cpp new file mode 100644 index 0000000..51063b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/span_test.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; +using executorch::runtime::Span; + +TEST(SpanTest, Ctors) { + int64_t x[2] = {1, 2}; + + Span span_range = {x, x + 2}; + Span span_array = {x}; + + EXPECT_EQ(span_range.size(), 2); + EXPECT_EQ(span_array.size(), 2); + + EXPECT_EQ(span_range.begin(), x); + EXPECT_EQ(span_range.end(), x + 2); + + EXPECT_EQ(span_array.begin(), x); + EXPECT_EQ(span_array.end(), x + 2); +} + +TEST(SpanTest, MutableElements) { + int64_t x[2] = {1, 2}; + Span span = {x, 2}; + EXPECT_EQ(span.size(), 2); + EXPECT_EQ(span[0], 1); + span[0] = 2; + EXPECT_EQ(span[0], 2); +} + +TEST(SpanTest, Empty) { + int64_t x[2] = {1, 2}; + Span span_full = {x, 2}; + Span span_empty = {x, (size_t)0}; + + EXPECT_FALSE(span_full.empty()); + EXPECT_TRUE(span_empty.empty()); +} + +TEST(SpanTest, Data) { + int64_t x[2] = {1, 2}; + Span span = {x, 2}; + EXPECT_EQ(span.data(), x); +} + +TEST(SpanTest, TriviallyCopyable) { + int64_t x[2] = {1, 2}; + Span span = {x, 2}; + Span span_copy = span; + EXPECT_EQ(span.data(), span_copy.data()); + EXPECT_EQ(span.size(), span_copy.size()); + EXPECT_TRUE(std::is_trivially_copyable>::value); +} + +TEST(SpanTest, SingleElementConstructor) { + int64_t single_value = 42; + Span span = single_value; + + EXPECT_EQ(span.size(), 1); + EXPECT_EQ(span.data(), &single_value); + EXPECT_EQ(span[0], 42); + EXPECT_EQ(*span.begin(), 42); + EXPECT_EQ(span.end(), span.begin() + 1); + + // Test that modifying through span affects original value + span[0] = 100; + EXPECT_EQ(single_value, 100); + EXPECT_EQ(span[0], 100); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tag_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tag_test.cpp new file mode 100644 index 0000000..00800df --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tag_test.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::kTagNameBufferSize; +using executorch::runtime::Tag; +using executorch::runtime::tag_to_string; + +// The behavior of tag_to_string depends on the value of ET_ENABLE_ENUM_STRINGS. +// If it is not set, tag_to_string will return a string representation of the +// enum index value. As this behavior is compile-time gated, tests must also +// be compile-time gated. +#if ET_ENABLE_ENUM_STRINGS +TEST(TagToString, TagValues) { + std::array name; + + tag_to_string(Tag::Tensor, name.data(), name.size()); + EXPECT_STREQ("Tensor", name.data()); + + tag_to_string(Tag::Int, name.data(), name.size()); + EXPECT_STREQ("Int", name.data()); + + tag_to_string(Tag::Double, name.data(), name.size()); + EXPECT_STREQ("Double", name.data()); + + tag_to_string(Tag::Bool, name.data(), name.size()); + EXPECT_STREQ("Bool", name.data()); +} + +TEST(TagToString, PrintTag) { + const char* name = tag_to_string(Tag::Tensor); + EXPECT_STREQ("Tensor", name); + + name = tag_to_string(Tag::Int); + EXPECT_STREQ("Int", name); + + name = tag_to_string(Tag::Double); + EXPECT_STREQ("Double", name); + + name = tag_to_string(Tag::Bool); + EXPECT_STREQ("Bool", name); +} + +TEST(TagToString, TagNameBufferSize) { + // Validate that kTagNameBufferSize is large enough to hold the all tag + // strings without truncation. + std::array name; + + // Note that the return value of tag_to_string does not include the null + // terminator. + size_t longest = 0; + +#define TEST_CASE(tag) \ + auto tag##_len = tag_to_string(Tag::tag, name.data(), name.size()); \ + EXPECT_LT(tag##_len, kTagNameBufferSize) \ + << "kTagNameBufferSize is too small to hold " #tag; \ + longest = std::max(longest, tag##_len); + + EXECUTORCH_FORALL_TAGS(TEST_CASE) +#undef TEST_CASE + + EXPECT_EQ(longest + 1, kTagNameBufferSize) + << "kTagNameBufferSize has incorrect value, expected " << longest + 1; +} + +TEST(TagToString, FitsExact) { + std::array name; + + auto ret = tag_to_string(Tag::Int, name.data(), name.size()); + + EXPECT_EQ(3, ret); + EXPECT_STREQ("Int", name.data()); +} + +TEST(TagToString, Truncate) { + std::array name; + std::fill(name.begin(), name.end(), '-'); + + auto ret = tag_to_string(Tag::Double, name.data(), name.size()); + EXPECT_EQ(6, ret); + EXPECT_TRUE(name[name.size() - 1] == 0); + EXPECT_STREQ("Doubl", name.data()); +} +#endif // ET_ENABLE_ENUM_STRINGS diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/targets.bzl new file mode 100644 index 0000000..1ad0940 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/targets.bzl @@ -0,0 +1,130 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "span_test", + srcs = ["span_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "tensor_layout_test", + srcs = ["tensor_layout_test.cpp"], + deps = [ + "//executorch/runtime/core:tensor_layout", + ], + ) + + runtime.cxx_test( + name = "error_handling_test", + srcs = [ + "error_handling_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "function_ref_test", + srcs = [ + "function_ref_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "event_tracer_test", + srcs = [ + "event_tracer_test.cpp", + ], + deps = [ + "//executorch/runtime/core:event_tracer", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "freeable_buffer_test", + srcs = [ + "freeable_buffer_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "array_ref_test", + srcs = ["array_ref_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "memory_allocator_test", + srcs = [ + "memory_allocator_test.cpp", + ], + deps = [ + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "hierarchical_allocator_test", + srcs = [ + "hierarchical_allocator_test.cpp", + ], + deps = [ + "//executorch/runtime/core:memory_allocator", + ], + ) + + runtime.cxx_test( + name = "tag_test", + srcs = [ + "tag_test.cpp", + ], + deps = [ + "//executorch/runtime/core:tag", + ], + preprocessor_flags = [ + "-DET_ENABLE_ENUM_STRINGS" + ], + ) + + if True in get_aten_mode_options(): + runtime.cxx_test( + name = "tensor_shape_dynamism_test_aten", + srcs = ["tensor_shape_dynamism_test_aten.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib_aten", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util_aten", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_test( + name = "evalue_test" + aten_suffix, + srcs = ["evalue_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/testing_util:tensor_util" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_layout_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_layout_test.cpp new file mode 100644 index 0000000..0039745 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_layout_test.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::runtime::Error; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorLayout; + +TEST(TestTensorLayout, Ctor) { + std::array sizes = {1, 2}; + std::array dim_order = {0, 1}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_TRUE(layout_res.ok()); + + TensorLayout layout = layout_res.get(); + EXPECT_EQ(layout.scalar_type(), ScalarType::Float); + + EXPECT_EQ(layout.sizes().size(), sizes_span.size()); + EXPECT_EQ(layout.sizes()[0], sizes_span[0]); + EXPECT_EQ(layout.sizes()[1], sizes_span[1]); + + EXPECT_EQ(layout.dim_order().size(), dim_order_span.size()); + EXPECT_EQ(layout.dim_order()[0], dim_order_span[0]); + EXPECT_EQ(layout.dim_order()[1], dim_order_span[1]); + + EXPECT_EQ(layout.nbytes(), 8); +} + +TEST(TestTensorLayout, Ctor_InvalidDimOrder) { + std::array sizes = {2}; + std::array dim_order = {1}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_EQ(layout_res.error(), Error::InvalidArgument); +} + +TEST(TestTensorLayout, Ctor_InvalidSizes) { + std::array sizes = {-1}; + std::array dim_order = {0}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_EQ(layout_res.error(), Error::InvalidArgument); +} + +TEST(TestTensorLayout, Ctor_SizesDimOrderMismatch) { + std::array sizes = {2}; + std::array dim_order = {0, 1}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_EQ(layout_res.error(), Error::InvalidArgument); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_shape_dynamism_test_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_shape_dynamism_test_aten.cpp new file mode 100644 index 0000000..509efee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/test/tensor_shape_dynamism_test_aten.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; +using executorch::runtime::TensorShapeDynamism; + +TEST(TensorShapeDynamismTest, CanBuildInATenMode) { + // Demonstrate that aten mode can include the header and see the enum. If this + // builds, the test passes. + +#ifndef USE_ATEN_LIB +#error "This test should only be built in aten mode" +#endif + + EXPECT_NE(TensorShapeDynamism::STATIC, TensorShapeDynamism::DYNAMIC_BOUND); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.cpp new file mode 100644 index 0000000..27a340a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +namespace executorch { +namespace runtime { + +// This needs to be defined in the SAME namespace that defines Error. +// C++'s look-up rules rely on that. +void PrintTo(const Error& error, std::ostream* os) { + *os << ::executorch::runtime::to_string(error); +} + +} // namespace runtime +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.h new file mode 100644 index 0000000..9522030 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/error_matchers.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @file + * Testing utilities for working with `executorch::runtime::Result` and + * `executorch::runtime::Error`. Provides matchers similar to `absl::StatusOr` + * and `absl::Status`. + * + * Defines the following utilities: + * + * =============== + * `IsOkAndHolds(m)` + * =============== + * + * This gMock matcher matches a Result value whose error is Ok + * and whose inner value matches matcher m. Example: + * + * ``` + * using ::testing::MatchesRegex; + * using ::executorch::runtime::testing::IsOkAndHolds; + * ... + * executorch::runtime::Result maybe_name = ...; + * EXPECT_THAT(maybe_name, IsOkAndHolds(MatchesRegex("John .*"))); + * ``` + * + * =============== + * `ErrorIs(Error::error_code)` + * =============== + * + * This gMock matcher matches a Result value whose error matches + * the given error matcher. Example: + * + * ``` + * using ::executorch::runtime::testing::ErrorIs; + * ... + * executorch::runtime::Result maybe_name = ...; + * EXPECT_THAT(maybe_name, ErrorIs(Error::InvalidArgument)); + * ``` + * + * =============== + * `IsOk()` + * =============== + * + * Matches an `executorch::runtime::Result` value whose error value + * is `executorch::runtime::Error::Ok`. + * + * Example: + * ``` + * using ::executorch::runtime::testing::IsOk; + * ... + * executorch::runtime::Result maybe_name = ...; + * EXPECT_THAT(maybe_name, IsOk()); + * ``` + */ + +#pragma once + +#include +#include + +#include +#include + +#include +#include + +/** + * Unwrap a Result to obtain its value. If the Result contains an error, + * fail the test with ASSERT_TRUE. + * + * This macro is useful for test code where you want to extract the value + * from a Result and fail the test if the Result contains an error. + * + * Example usage: + * ``` + * Result maybe_value = GetSomeValue(); + * int value = ASSERT_OK_AND_UNWRAP(maybe_value); + * // Use value... + * ``` + * + * @param[in] result__ Expression yielding the Result to unwrap. + */ +#define ASSERT_OK_AND_UNWRAP(result__) \ + ({ \ + auto&& et_result__ = (result__); \ + ASSERT_TRUE(et_result__.ok()); \ + std::move(*et_result__); \ + }) + +namespace executorch { +namespace runtime { +namespace testing { +namespace internal { + +// Helper function to get the error from a Result +template +inline Error GetError(const Result& result) { + return result.error(); +} + +// Helper function to get the error from a raw Error (identity function) +inline Error GetError(const Error& error) { + return error; +} + +//////////////////////////////////////////////////////////// +// Implementation of IsOkAndHolds(). + +// Monomorphic implementation of matcher IsOkAndHolds(m). ResultType is a +// reference to Result. +template +class IsOkAndHoldsMatcherImpl : public ::testing::MatcherInterface { + public: + typedef + typename std::remove_reference::type::value_type value_type; + + template + explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher) + : inner_matcher_(::testing::SafeMatcherCast( + std::forward(inner_matcher))) {} + + void DescribeTo(std::ostream* os) const override { + *os << "is OK and has a value that "; + inner_matcher_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "isn't OK or has a value that "; + inner_matcher_.DescribeNegationTo(os); + } + + bool MatchAndExplain( + ResultType actual_value, + ::testing::MatchResultListener* result_listener) const override { + if (!actual_value.ok()) { + *result_listener << "which has error " + << ::executorch::runtime::to_string( + GetError(actual_value)); + return false; + } + + // Call through to the inner matcher. + return inner_matcher_.MatchAndExplain(*actual_value, result_listener); + } + + private: + const ::testing::Matcher inner_matcher_; +}; + +// Implements IsOkAndHolds(m) as a polymorphic matcher. +template +class IsOkAndHoldsMatcher { + public: + explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher) + : inner_matcher_(std::forward(inner_matcher)) {} + + // Converts this polymorphic matcher to a monomorphic matcher of the + // given type. ResultType can be either Result or a + // reference to Result. + template + operator ::testing::Matcher() const { // NOLINT + return ::testing::Matcher( + new IsOkAndHoldsMatcherImpl(inner_matcher_)); + } + + private: + const InnerMatcher inner_matcher_; +}; + +//////////////////////////////////////////////////////////// +// Implementation of IsOk(). + +// Monomorphic implementation of matcher IsOk() for a given type T. +// T can be Result, Error, or references to either. +template +class MonoIsOkMatcherImpl : public ::testing::MatcherInterface { + public: + void DescribeTo(std::ostream* os) const override { + *os << "is OK"; + } + void DescribeNegationTo(std::ostream* os) const override { + *os << "is not OK"; + } + bool MatchAndExplain( + T actual_value, + ::testing::MatchResultListener* result_listener) const override { + const Error error = GetError(actual_value); + if (error != Error::Ok) { + *result_listener << "which has error " + << ::executorch::runtime::to_string(error); + return false; + } + return true; + } +}; + +// Implements IsOk() as a polymorphic matcher. +class IsOkMatcher { + public: + template + operator ::testing::Matcher() const { // NOLINT + return ::testing::Matcher(new MonoIsOkMatcherImpl()); + } +}; + +//////////////////////////////////////////////////////////// +// Implementation of ErrorIs(). + +// Monomorphic implementation of matcher ErrorIs() for a given type T. +// T can be Result or a reference to Result. +template +class MonoErrorIsMatcherImpl : public ::testing::MatcherInterface { + public: + explicit MonoErrorIsMatcherImpl(::testing::Matcher error_matcher) + : error_matcher_(std::move(error_matcher)) {} + + void DescribeTo(std::ostream* os) const override { + *os << "has an error that "; + error_matcher_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not have an error that "; + error_matcher_.DescribeNegationTo(os); + } + + bool MatchAndExplain( + T actual_value, + ::testing::MatchResultListener* result_listener) const override { + Error actual_error = GetError(actual_value); + *result_listener << "which has error " + << ::executorch::runtime::to_string(actual_error); + return error_matcher_.MatchAndExplain(actual_error, result_listener); + } + + private: + const ::testing::Matcher error_matcher_; +}; + +// Implements ErrorIs() as a polymorphic matcher. +template +class ErrorIsMatcher { + public: + explicit ErrorIsMatcher(ErrorMatcher error_matcher) + : error_matcher_(std::forward(error_matcher)) {} + + // Converts this polymorphic matcher to a monomorphic matcher of the + // given type. T can be Result or a reference to Result. + template + operator ::testing::Matcher() const { // NOLINT + return ::testing::Matcher(new MonoErrorIsMatcherImpl( + ::testing::MatcherCast(error_matcher_))); + } + + private: + const ErrorMatcher error_matcher_; +}; + +} // namespace internal + +// Returns a gMock matcher that matches a Result<> whose error is +// OK and whose value matches the inner matcher. +template +internal::IsOkAndHoldsMatcher::type> +IsOkAndHolds(InnerMatcherT&& inner_matcher) { + return internal::IsOkAndHoldsMatcher< + typename std::decay::type>( + std::forward(inner_matcher)); +} + +// Returns a gMock matcher that matches a Result<> whose error matches +// the given error matcher. +template +internal::ErrorIsMatcher::type> ErrorIs( + ErrorMatcherT&& error_matcher) { + return internal::ErrorIsMatcher::type>( + std::forward(error_matcher)); +} + +// Returns a gMock matcher that matches a Result<> which is OK. +inline internal::IsOkMatcher IsOk() { + return internal::IsOkMatcher(); +} + +} // namespace testing +} // namespace runtime +} // namespace executorch + +namespace executorch { +namespace runtime { + +// This needs to be defined in the SAME namespace that defines Error. +// C++'s look-up rules rely on that. +void PrintTo(const Error& error, std::ostream* os); + +} // namespace runtime +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/targets.bzl new file mode 100644 index 0000000..dbab597 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/targets.bzl @@ -0,0 +1,25 @@ + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_library( + name = "error_matchers", + srcs = [ + "error_matchers.cpp", + ], + exported_headers = [ + "error_matchers.h", + ], + visibility = ["PUBLIC"], + exported_external_deps = [ + "gmock", + ], + exported_deps = [ + "//executorch/runtime/core:core", + ] + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/TARGETs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/TARGETs new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/TARGETs @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/targets.bzl new file mode 100644 index 0000000..ebfbe35 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/targets.bzl @@ -0,0 +1,19 @@ + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "test_error_matchers", + srcs = [ + "test_error_matchers.cpp", + ], + visibility = ["//executorch/..."], + deps = [ + "//executorch/runtime/core/testing_util:error_matchers", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/test_error_matchers.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/test_error_matchers.cpp new file mode 100644 index 0000000..4e320cc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/core/testing_util/test/test_error_matchers.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +#include +#include + +namespace executorch::runtime::testing { +namespace { + +using ::executorch::runtime::Error; +using ::executorch::runtime::Result; +using ::executorch::runtime::testing::ErrorIs; +using ::executorch::runtime::testing::IsOk; +using ::executorch::runtime::testing::IsOkAndHolds; +using ::testing::AnyOf; +using ::testing::DescribeMatcher; +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::Matcher; +using ::testing::Not; + +TEST(ResultMatchersTest, IsOkMatchesOkResult) { + Result ok_result(42); + EXPECT_THAT(ok_result, IsOk()); +} + +TEST(ResultMatchersTest, IsOkDoesNotMatchErrorResult) { + Result error_result(Error::InvalidArgument); + EXPECT_THAT(error_result, Not(IsOk())); +} + +TEST(ResultMatchersTest, IsOkAndHoldsMatchesOkResultWithMatchingValue) { + Result ok_result(42); + EXPECT_THAT(ok_result, IsOkAndHolds(42)); + EXPECT_THAT(ok_result, IsOkAndHolds(Eq(42))); +} + +TEST(ResultMatchersTest, IsOkAndHoldsDoesNotMatchErrorResult) { + Result error_result(Error::InvalidArgument); + EXPECT_THAT(error_result, Not(IsOkAndHolds(42))); +} + +TEST(ResultMatchersTest, ErrorIsMatchesSpecificError) { + Error error = Error::InvalidArgument; + Result invalid_arg_result(Error::InvalidArgument); + Result ok_result(42); + + EXPECT_THAT(error, ErrorIs(Error::InvalidArgument)); + EXPECT_THAT(invalid_arg_result, ErrorIs(Error::InvalidArgument)); + EXPECT_THAT(invalid_arg_result, Not(ErrorIs(Error::NotFound))); + EXPECT_THAT(ok_result, Not(ErrorIs(Error::InvalidArgument))); +} + +TEST(ResultMatchersTest, ErrorIsWorksWithMatchers) { + Result invalid_arg_result(Error::InvalidArgument); + Result ok_result(42); + + EXPECT_THAT(invalid_arg_result, ErrorIs(Eq(Error::InvalidArgument))); + EXPECT_THAT( + invalid_arg_result, + ErrorIs(AnyOf(Error::InvalidArgument, Error::NotFound))); + EXPECT_THAT( + ok_result, Not(ErrorIs(AnyOf(Error::InvalidArgument, Error::NotFound)))); +} + +TEST(ResultMatchersTest, ErrorIsWorksWithDifferentResultTypes) { + Result string_error_result(Error::InvalidType); + Result double_error_result(Error::MemoryAllocationFailed); + + EXPECT_THAT(string_error_result, ErrorIs(Error::InvalidType)); + EXPECT_THAT(double_error_result, ErrorIs(Error::MemoryAllocationFailed)); + EXPECT_THAT(string_error_result, Not(ErrorIs(Error::MemoryAllocationFailed))); +} + +TEST(ResultMatchersTest, ErrorIsDoesNotMatchOkResult) { + Result ok_result(42); + + EXPECT_THAT(ok_result, Not(ErrorIs(Error::InvalidArgument))); + EXPECT_THAT(ok_result, Not(ErrorIs(Error::NotFound))); + EXPECT_THAT(ok_result, ErrorIs(Error::Ok)); +} + +TEST(ResultMatchersTest, AssertOkAndUnwrapWorksWithOkResult) { + Result ok_result(42); + int value = ASSERT_OK_AND_UNWRAP(Result(42)); + EXPECT_EQ(42, value); +} + +TEST(ResultMatchersTest, AssertOkAndUnwrapWorksWithStringResult) { + std::string value = ASSERT_OK_AND_UNWRAP(Result("hello world")); + EXPECT_EQ("hello world", value); +} + +TEST(ResultMatchersTest, AssertOkAndUnwrapWorksWithMoveOnlyTypes) { + Result> ok_result(std::make_unique(42)); + std::unique_ptr value = ASSERT_OK_AND_UNWRAP(std::move(ok_result)); + EXPECT_EQ(42, *value); +} + +TEST(ResultMatchersTest, MatcherDescriptions) { + Matcher> is_ok_matcher = IsOk(); + Matcher> is_ok_and_holds_matcher = IsOkAndHolds(42); + Matcher> error_is_matcher = ErrorIs(Error::InvalidArgument); + + EXPECT_EQ("is OK", DescribeMatcher>(is_ok_matcher)); + EXPECT_EQ("is not OK", DescribeMatcher>(is_ok_matcher, true)); + EXPECT_THAT( + DescribeMatcher>(is_ok_and_holds_matcher), + HasSubstr("is OK and has a value that")); + EXPECT_THAT( + DescribeMatcher>(is_ok_and_holds_matcher, true), + HasSubstr("isn't OK or has a value that")); + EXPECT_THAT( + DescribeMatcher>(error_is_matcher), + HasSubstr("has an error that")); + EXPECT_THAT( + DescribeMatcher>(error_is_matcher, true), + HasSubstr("does not have an error that")); +} + +} // namespace +} // namespace executorch::runtime::testing diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/memory_manager.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/memory_manager.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/memory_manager.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/memory_manager.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/merged_data_map.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/merged_data_map.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/merged_data_map.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/merged_data_map.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method.cpp similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method.cpp index 8eb4848..a830c2e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include // @donotremove #include @@ -38,20 +37,6 @@ namespace ET_RUNTIME_NAMESPACE { using internal::PlatformMemoryAllocator; -// Maximum number of instructions that Method::execute() will run before -// returning an error. Prevents infinite loops caused by malformed programs -// (e.g., JumpFalseCall instructions whose destination_instruction points to -// themselves). Override at compile time via -DET_MAX_INSTRUCTIONS=. -#ifndef ET_MAX_INSTRUCTIONS -#define ET_MAX_INSTRUCTIONS 10000000 -#endif -static_assert( - (ET_MAX_INSTRUCTIONS) > 0, - "ET_MAX_INSTRUCTIONS must be positive. 0 would reject every program on " - "its first instruction; negative values wrap to SIZE_MAX when assigned " - "to size_t, silently disabling the infinite-loop guard."); -static constexpr size_t kMaxInstructions = ET_MAX_INSTRUCTIONS; - /** * Runtime state for a backend delegate. */ @@ -101,17 +86,14 @@ class BackendDelegate final { } // Parse compilation specs from program - CompileSpec* compile_specs = nullptr; - size_t num_compile_specs = 0; - if (delegate.compile_specs() != nullptr) { - Error err = PopulateCompileSpecs( - delegate.compile_specs(), backend_init_context, &compile_specs); - if (err != Error::Ok) { - ET_LOG(Error, "Failed to get compile specs for backend %s", backend_id); - return err; - } - num_compile_specs = delegate.compile_specs()->size(); + CompileSpec* compile_specs; + Error err = PopulateCompileSpecs( + delegate.compile_specs(), backend_init_context, &compile_specs); + if (err != Error::Ok) { + ET_LOG(Error, "Failed to get compile specs for backend %s", backend_id); + return err; } + size_t num_compile_specs = delegate.compile_specs()->size(); out->backend_ = backend; out->handle_ = nullptr; @@ -428,7 +410,6 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { const size_t n_value = flatbuffer_values->size(); values_ = memory_manager_->method_allocator()->allocateList(n_value); if (values_ == nullptr) { - ET_LOG(Error, "Failed to allocate values array of size %zu", n_value); return Error::MemoryAllocationFailed; } const size_t n_input = inputs_size(); @@ -436,7 +417,6 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { input_set_ = memory_manager_->method_allocator()->allocateList(n_input); if (input_set_ == nullptr) { - ET_LOG(Error, "Failed to allocate input_set array of size %zu", n_input); return Error::MemoryAllocationFailed; } for (size_t i = 0; i < n_input; ++i) { @@ -460,10 +440,6 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { memory_manager_->method_allocator()->allocateList( max_external_constants.get()); if (external_constants_ == nullptr) { - ET_LOG( - Error, - "Failed to allocate external_constants array of size %zu", - max_external_constants.get()); return Error::MemoryAllocationFailed; } Error err = parse_external_constants(external_data_map); @@ -802,19 +778,8 @@ Error Method::resolve_operator( } // Find a kernel with the matching name and tensor meta. - // Try method-scoped registry first (if provided), then fall back to global. - auto resolve_op_function = [&]() -> Result { - if (!kernel_registry_.empty()) { - Result method_scoped_op_function = - get_op_function_from_registry( - operator_name, {meta, count}, kernel_registry_); - if (method_scoped_op_function.ok()) { - return method_scoped_op_function; - } - } - return get_op_function_from_registry(operator_name, {meta, count}); - }; - Result op_function = resolve_op_function(); + Result op_function = + get_op_function_from_registry(operator_name, {meta, count}); if (!op_function.ok()) { ET_LOG( Error, @@ -841,25 +806,21 @@ Result Method::load( const Program* program, MemoryManager* memory_manager, EventTracer* event_tracer, - const NamedDataMap* external_data_map, - const LoadBackendOptionsMap* backend_options, - Span kernel_registry) { + const NamedDataMap* external_data_map) { MemoryAllocator* temp_allocator = memory_manager->temp_allocator(); if (temp_allocator == nullptr) { PlatformMemoryAllocator* platform_allocator = memory_manager->method_allocator() ->allocateInstance(); if (platform_allocator == nullptr) { - ET_LOG(Error, "Failed to allocate PlatformMemoryAllocator"); return Error::MemoryAllocationFailed; } new (platform_allocator) PlatformMemoryAllocator(); temp_allocator = platform_allocator; } - Method method( - program, memory_manager, event_tracer, temp_allocator, kernel_registry); + Method method(program, memory_manager, event_tracer, temp_allocator); ET_LOG(Debug, "Loading method: %s.", s_plan->name()->c_str()); - Error err = method.init(s_plan, external_data_map, backend_options); + Error err = method.init(s_plan, external_data_map); if (err != Error::Ok) { return err; } else { @@ -868,20 +829,11 @@ Result Method::load( } } -/// Validate that a value index from a FlatBuffer instruction is in bounds. -#define ET_CHECK_VALID_VALUE_INDEX(index, n_value) \ - ET_CHECK_OR_RETURN_ERROR( \ - (index) >= 0 && static_cast(index) < (n_value), \ - InvalidProgram, \ - "Index %zd negative or >= %" ET_PRIsize_t, \ - static_cast(index), \ - (n_value)) - Error Method::init( executorch_flatbuffer::ExecutionPlan* s_plan, - const NamedDataMap* external_data_map, - const LoadBackendOptionsMap* backend_options) { - internal::EventTracerProfileMethodScope event_tracer_scope = + const NamedDataMap* external_data_map) { + EXECUTORCH_SCOPE_PROF("Method::init"); + internal::EventTracerProfileMethodScope event_tracer_profile_scope = internal::EventTracerProfileMethodScope(event_tracer_, "Method::init"); ET_CHECK_OR_RETURN_ERROR( // Don't use !initialized() here because we also want to fail on the @@ -910,8 +862,6 @@ Error Method::init( size_t n_delegate = delegates->size(); delegates_ = method_allocator->allocateList(n_delegate); if (delegates_ == nullptr) { - ET_LOG( - Error, "Failed to allocate delegates array of size %zu", n_delegate); return Error::MemoryAllocationFailed; } @@ -935,7 +885,6 @@ Error Method::init( merged_data_map_ = method_allocator->allocateInstance(); if (merged_data_map_ == nullptr) { - ET_LOG(Error, "Failed to allocate MergedDataMap"); return Error::MemoryAllocationFailed; } new (merged_data_map_) internal::MergedDataMap(std::move(merged.get())); @@ -953,21 +902,11 @@ Error Method::init( for (size_t i = 0; i < n_delegate; ++i) { const auto& delegate = *delegates->Get(i); - - // Get per-delegate runtime specs from the LoadBackendOptionsMap if - // provided - Span delegate_runtime_specs; - if (backend_options != nullptr && delegate.id() != nullptr) { - delegate_runtime_specs = - backend_options->get_options(delegate.id()->c_str()); - } - BackendInitContext backend_init_context( method_allocator, /*event_tracer=*/event_tracer_, /*method_name=*/serialization_plan_->name()->c_str(), - /*named_data_map=*/named_data_map, - /*runtime_specs=*/delegate_runtime_specs); + /*named_data_map=*/named_data_map); Error err = BackendDelegate::Init( delegate, program_, backend_init_context, &delegates_[i]); if (err != Error::Ok) { @@ -988,7 +927,6 @@ Error Method::init( n_chains_ = chains->size(); chains_ = method_allocator->allocateList(n_chains_); if (chains_ == nullptr) { - ET_LOG(Error, "Failed to allocate chains array of size %zu", n_chains_); return Error::MemoryAllocationFailed; } @@ -1008,15 +946,11 @@ Error Method::init( auto chain_instruction_kernels = method_allocator->allocateList(num_instructions); if (chain_instruction_kernels == nullptr) { - ET_LOG( - Error, "Failed to allocate instruction kernels for chain %zu", i); return Error::MemoryAllocationFailed; } auto chain_instruction_arg_lists = method_allocator->allocateList(num_instructions); if (chain_instruction_arg_lists == nullptr) { - ET_LOG( - Error, "Failed to allocate instruction arg lists for chain %zu", i); return Error::MemoryAllocationFailed; } @@ -1086,34 +1020,23 @@ Error Method::init( chain_instruction_arg_lists[instr_idx] = res.get(); } break; case executorch_flatbuffer::InstructionArguments::JumpFalseCall: { + // Validate the index at load time so we can trust it during + // execution. auto index = static_cast( instr_args) ->cond_value_index(); - ET_CHECK_VALID_VALUE_INDEX(index, n_value_); - chain_instruction_arg_lists[instr_idx] = InstructionArgs(); - } break; - case executorch_flatbuffer::InstructionArguments::MoveCall: { - auto move_call = - static_cast(instr_args); - ET_CHECK_VALID_VALUE_INDEX(move_call->move_from(), n_value_); - ET_CHECK_VALID_VALUE_INDEX(move_call->move_to(), n_value_); + ET_CHECK_OR_RETURN_ERROR( + index >= 0 && static_cast(index) < n_value_, + InvalidProgram, + "Index %zd negative or >= %" ET_PRIsize_t, + static_cast(index), + n_value_); chain_instruction_arg_lists[instr_idx] = InstructionArgs(); } break; - case executorch_flatbuffer::InstructionArguments::FreeCall: { - auto index = - static_cast(instr_args) - ->value_index(); - ET_CHECK_VALID_VALUE_INDEX(index, n_value_); + default: { chain_instruction_arg_lists[instr_idx] = InstructionArgs(); } break; - default: { - ET_LOG( - Error, - "Invalid instruction type %hhu", - static_cast(instruction->instr_args_type())); - return Error::InvalidProgram; - } } } chains_[i] = Chain{ @@ -1208,33 +1131,6 @@ Method::set_input(const EValue& input_evalue, size_t input_idx) { input_idx, executorch::runtime::toString(t_dst.scalar_type()), executorch::runtime::toString(t_src.scalar_type())); - - ssize_t numel = 1; - for (ssize_t i = 0; i < t_src.dim(); i++) { - bool overflow = c10::mul_overflows( - numel, static_cast(t_src.size(i)), &numel); - ET_CHECK_OR_RETURN_ERROR( - !overflow, - InvalidArgument, - "Input %" ET_PRIsize_t - ": numel overflowed at dimension %zd with size %zd", - input_idx, - (size_t)i, - (size_t)t_src.size(i)); - } - size_t nbytes; - bool nbytes_overflow = c10::mul_overflows( - static_cast(numel), - executorch::runtime::elementSize(t_src.scalar_type()), - &nbytes); - ET_CHECK_OR_RETURN_ERROR( - !nbytes_overflow, - InvalidArgument, - "Input %" ET_PRIsize_t - ": nbytes overflowed: numel %zd with element size %zu", - input_idx, - numel, - executorch::runtime::elementSize(t_src.scalar_type())); // Reset the shape for the Method's input as the size of forwarded input // tensor for shape dynamism. Also is a safety check if need memcpy. ET_CHECK_OK_OR_RETURN_ERROR( @@ -1579,16 +1475,8 @@ Error Method::execute_instruction() { // We know that instr_args_as_FreeCall is non-null because it was checked // at init time. auto free_call = instruction->instr_args_as_FreeCall(); - auto t = mutable_value(free_call->value_index()).tryToTensor(); - if (!t.ok()) { - ET_LOG( - Error, - "FreeCall target at index %u is not a Tensor", - static_cast(free_call->value_index())); - err = t.error(); - break; - } - internal::reset_data_ptr(t.get()); + auto t = values_[free_call->value_index()].toTensor(); + internal::reset_data_ptr(t); } break; default: ET_LOG( @@ -1718,7 +1606,6 @@ Error Method::execute() { // Chains are executed sequentially today, but future async designs may // branch and run many in parallel or out of order. - size_t instruction_count = 0; for (step_state_.chain_idx = 0; step_state_.chain_idx < n_chains_; ++step_state_.chain_idx) { Chain& chain = chains_[step_state_.chain_idx]; @@ -1732,21 +1619,6 @@ Error Method::execute() { // Loop over instructions step_state_.instr_idx = 0; while (step_state_.instr_idx < chain.s_chain_->instructions()->size()) { - if (instruction_count >= kMaxInstructions) { - ET_LOG( - Error, - "Instruction execution limit (%" ET_PRIsize_t - ") exceeded at chain %" ET_PRIsize_t ", instruction %" ET_PRIsize_t - ". Possible infinite loop detected. If this is a legitimate " - "large model, raise the limit by rebuilding with " - "-DET_MAX_INSTRUCTIONS=.", - kMaxInstructions, - step_state_.chain_idx, - step_state_.instr_idx); - step_state_ = StepState{0, 0}; - return Error::InvalidProgram; - } - ++instruction_count; EXECUTORCH_PROFILE_INSTRUCTION_SCOPE( static_cast(step_state_.chain_idx), static_cast(step_state_.instr_idx)); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method.h index 834325f..cd121a5 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method.h @@ -14,7 +14,6 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif -#include #include #include #include @@ -23,7 +22,6 @@ #include #include #include -#include #include // Forward declare flatbuffer types. This is a public header and must not @@ -83,7 +81,6 @@ class Method final { merged_data_map_(std::move(rhs.merged_data_map_)), external_constants_(rhs.external_constants_), n_external_constants_(rhs.n_external_constants_), - kernel_registry_(rhs.kernel_registry_), init_state_(rhs.init_state_) { // Required: clear out fields that the dtor looks at, so that we don't free // anything twice. @@ -333,8 +330,7 @@ class Method final { const Program* program, MemoryManager* memory_manager, EventTracer* event_tracer, - MemoryAllocator* temp_allocator, - Span kernel_registry = {}) + MemoryAllocator* temp_allocator) : step_state_(), program_(program), memory_manager_(memory_manager), @@ -351,7 +347,6 @@ class Method final { merged_data_map_(nullptr), external_constants_(nullptr), n_external_constants_(0), - kernel_registry_(kernel_registry), init_state_(InitializationState::Uninitialized) {} /// Static factory used by Program. @@ -360,9 +355,7 @@ class Method final { const Program* program, MemoryManager* memory_manager, EventTracer* event_tracer, - const NamedDataMap* named_data_map, - const LoadBackendOptionsMap* backend_options = nullptr, - Span kernel_registry = {}); + const NamedDataMap* named_data_map); /** * Initialize the method from its serialized representation. @@ -371,8 +364,7 @@ class Method final { */ ET_NODISCARD Error init( executorch_flatbuffer::ExecutionPlan* s_plan, - const NamedDataMap* named_data_map, - const LoadBackendOptionsMap* backend_options); + const NamedDataMap* named_data_map); /// Returns true if the Method was successfully initialized. inline bool initialized() const { @@ -408,8 +400,6 @@ class Method final { NamedData* external_constants_; size_t n_external_constants_ = 0; - Span kernel_registry_; - InitializationState init_state_; /** diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method_meta.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method_meta.cpp similarity index 79% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method_meta.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method_meta.cpp index 0af97b3..75dadfd 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method_meta.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method_meta.cpp @@ -6,8 +6,6 @@ * LICENSE file in the root directory of this source tree. */ -#include // @donotremove - #include #include #include @@ -60,20 +58,13 @@ Result calculate_nbytes( executorch::aten::ScalarType scalar_type) { size_t n = 1; for (size_t i = 0; i < sizes.size(); i++) { - ET_CHECK_OR_RETURN_ERROR( - sizes[i] >= 0, - InvalidProgram, - "Invalid size[%zu]: %" PRId32 ". Size must not be negative", - i, - sizes[i]); size_t next_n; bool overflow = c10::mul_overflows(n, static_cast(sizes[i]), &next_n); ET_CHECK_OR_RETURN_ERROR( !overflow, InvalidArgument, - "Invalid size[%zu]: %" PRId32 - ". Potentially overflowed, expect to be 0 or n: %zu", + "Invalid size[%zu]: %d. Potentially overflowed, expect to be 0 or n: %zu", i, sizes[i], n); @@ -195,12 +186,6 @@ Result MethodMeta::input_tensor_meta(size_t index) const { auto input_index = s_plan_->inputs()->Get(index); // input_index was already validated by input_tag(). auto tensor_value = s_plan_->values()->Get(input_index)->val_as_Tensor(); - ET_CHECK_OR_RETURN_ERROR( - tensor_value != nullptr && tensor_value->sizes() != nullptr && - tensor_value->dim_order() != nullptr, - InvalidProgram, - "Null tensor metadata for input %zu", - index); return TensorInfo::create( Span( tensor_value->sizes()->data(), tensor_value->sizes()->size()), @@ -252,12 +237,7 @@ Result MethodMeta::output_tensor_meta(size_t index) const { auto output_index = s_plan_->outputs()->Get(index); // output_index was already validated by output_tag(). auto tensor_value = s_plan_->values()->Get(output_index)->val_as_Tensor(); - ET_CHECK_OR_RETURN_ERROR( - tensor_value != nullptr && tensor_value->sizes() != nullptr && - tensor_value->dim_order() != nullptr, - InvalidProgram, - "Null tensor metadata for output %zu", - index); + return TensorInfo::create( Span( tensor_value->sizes()->data(), tensor_value->sizes()->size()), @@ -277,10 +257,7 @@ size_t MethodMeta::num_attributes() const { auto value = values->Get(i); if (value->val_type() == executorch_flatbuffer::KernelTypes::Tensor) { auto tensor_value = value->val_as_Tensor(); - if (tensor_value != nullptr && - tensor_value->extra_tensor_info() != nullptr && - tensor_value->extra_tensor_info()->fully_qualified_name() != - nullptr && + if (tensor_value->extra_tensor_info() != nullptr && tensor_value->extra_tensor_info()->fully_qualified_name()->c_str() != nullptr) { ++counter; @@ -297,19 +274,10 @@ Result MethodMeta::attribute_tensor_meta(size_t index) const { auto value = values->Get(i); if (value->val_type() == executorch_flatbuffer::KernelTypes::Tensor) { auto tensor_value = value->val_as_Tensor(); - if (tensor_value != nullptr && - tensor_value->extra_tensor_info() != nullptr && - tensor_value->extra_tensor_info()->fully_qualified_name() != - nullptr && + if (tensor_value->extra_tensor_info() != nullptr && tensor_value->extra_tensor_info()->fully_qualified_name()->c_str() != nullptr) { if (counter == index) { - ET_CHECK_OR_RETURN_ERROR( - tensor_value->sizes() != nullptr && - tensor_value->dim_order() != nullptr, - InvalidProgram, - "Null tensor metadata for attribute %zu", - index); auto t_name = tensor_value->extra_tensor_info()->fully_qualified_name(); // Count constant returns as memory planned @@ -354,50 +322,7 @@ Result MethodMeta::memory_planned_buffer_size(size_t index) const { num_buffers); // Index zero is reserved internally, and we hide it from users. Adjust the // provided index to point to one of the actual buffers. - int64_t size = s_plan_->non_const_buffer_sizes()->Get(index + 1); - ET_CHECK_OR_RETURN_ERROR( - size >= 0, - InvalidProgram, - "memory_planned_buffer_size(%zu) has invalid negative size: %" PRId64, - index, - size); - return size; -} - -Result MethodMeta::memory_planned_buffer_device( - size_t index) const { - auto num_buffers = this->num_memory_planned_buffers(); - ET_CHECK_OR_RETURN_ERROR( - index < num_buffers, - InvalidArgument, - "index %zu out of range. num_buffers: %zu", - index, - num_buffers); - - // The non_const_buffer_device field is optional and only present when the - // program contains non-CPU buffers. For CPU-only programs (or legacy PTE - // files), this field is null and all buffers default to CPU. - auto* buffer_devices = s_plan_->non_const_buffer_device(); - if (buffer_devices == nullptr) { - return etensor::Device{etensor::DeviceType::CPU, 0}; - } - - // The sparse list only contains entries for non-CPU buffers. - // buffer_idx uses the same indexing as non_const_buffer_sizes (1-based, - // with index 0 reserved). The user-facing index is 0-based, so we - // compare against index + 1. - const auto internal_idx = static_cast(index + 1); - for (size_t i = 0; i < buffer_devices->size(); ++i) { - auto entry = buffer_devices->Get(i); - if (entry->buffer_idx() == internal_idx) { - return etensor::Device{ - static_cast(entry->device_type()), - static_cast(entry->device_index())}; - } - } - - // Not found in the sparse list — this buffer is on CPU. - return etensor::Device{etensor::DeviceType::CPU, 0}; + return s_plan_->non_const_buffer_sizes()->Get(index + 1); } bool MethodMeta::uses_backend(const char* backend_name) const { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method_meta.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method_meta.h similarity index 92% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method_meta.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method_meta.h index e0fa16c..79fd05c 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method_meta.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/method_meta.h @@ -9,7 +9,6 @@ #pragma once #include -#include #include #include #include @@ -235,19 +234,6 @@ class MethodMeta final { */ Result memory_planned_buffer_size(size_t index) const; - /** - * Get the device placement for the specified memory-planned buffer. - * - * For CPU-only programs (no non_const_buffer_device in the PTE), all buffers - * default to Device{CPU, 0}. For programs with device annotations, returns - * the device type and index that the buffer should be allocated on. - * - * @param[in] index The index of the buffer to look up (0-based, same - * indexing as memory_planned_buffer_size()). - * @returns The Device on success, or an error on failure. - */ - Result memory_planned_buffer_device(size_t index) const; - /** * Check to see if a backend is used in this method. * diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/platform_memory_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/platform_memory_allocator.h similarity index 85% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/platform_memory_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/platform_memory_allocator.h index 601a4c1..5951f11 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/platform_memory_allocator.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/platform_memory_allocator.h @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -47,20 +46,8 @@ class PlatformMemoryAllocator final : public MemoryAllocator { return nullptr; } - // Check for overflow before computing total allocation size. - // Allocate enough for the node, data, and alignment bump (at most - // alignment - 1 extra bytes to align the data pointer). - size_t alloc_size = 0; - if (c10::add_overflows(sizeof(AllocationNode), size, &alloc_size) || - c10::add_overflows(alloc_size, alignment - 1, &alloc_size)) { - ET_LOG( - Error, - "Allocation size overflow: size %zu, alignment %zu", - size, - alignment); - return nullptr; - } - + // Allocate enough memory for the node, the data and the alignment bump. + size_t alloc_size = sizeof(AllocationNode) + size + alignment; void* node_memory = runtime::pal_allocate(alloc_size); // If allocation failed, log message and return nullptr. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/program.cpp similarity index 76% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/program.cpp index 4c0337e..344e3c7 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/program.cpp @@ -11,11 +11,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -29,14 +27,6 @@ #define ET_ENABLE_PROGRAM_VERIFICATION 1 #endif -/* - * The constant_buffer path is deprecated from ExecuTorch 0.7. Disable it by - * passing -DET_ENABLE_DEPRECATED_CONSTANT_BUFFER=0. - */ -#ifndef ET_ENABLE_DEPRECATED_CONSTANT_BUFFER -#define ET_ENABLE_DEPRECATED_CONSTANT_BUFFER 1 -#endif - namespace executorch { namespace ET_RUNTIME_NAMESPACE { namespace { @@ -59,8 +49,7 @@ Result get_execution_plan( auto execution_plans = program->execution_plan(); for (size_t i = 0; i < execution_plans->size(); i++) { auto plan = execution_plans->GetMutableObject(i); - if (plan != nullptr && plan->name() != nullptr && - std::strcmp(plan->name()->c_str(), method_name) == 0) { + if (std::strcmp(plan->name()->c_str(), method_name) == 0) { return plan; } } @@ -101,12 +90,6 @@ Result get_execution_plan( // is positive (0-value may indicate no segments) if ((segment_data_size == 0 && segment_base_offset == 0) || segment_data_size > 0) { - ET_CHECK_OR_RETURN_ERROR( - segment_base_offset <= SIZE_MAX - segment_data_size, - InvalidProgram, - "segment_base_offset %zu + segment_data_size %zu overflows", - segment_base_offset, - segment_data_size); size_t expected = segment_base_offset == 0 ? program_size : segment_base_offset + segment_data_size; @@ -143,25 +126,6 @@ Result get_execution_plan( } EXECUTORCH_END_PROF(prof_tok); - // The flatbuffer data must start at an aligned address to ensure internal - // alignment of flatbuffer fields. - ET_CHECK_OR_RETURN_ERROR( - IsAligned(program_data->data()), - InvalidArgument, - "Program data 0x%p must be aligned to %zu", - program_data->data(), - kMinimumAlignment); - - // Minimum size: root offset + file identifier (i.e., the flatbuffer header - // before the extended header begins). - constexpr size_t kMinBufferSize = ExtendedHeader::kHeaderOffset; - ET_CHECK_OR_RETURN_ERROR( - program_data->size() >= kMinBufferSize, - InvalidProgram, - "Program data size %zu is too small (minimum %zu)", - program_data->size(), - kMinBufferSize); - // Make sure the magic header matches the expected version. if (!executorch_flatbuffer::ProgramBufferHasIdentifier( program_data->data())) { @@ -173,7 +137,7 @@ Result get_execution_plan( return Error::InvalidProgram; } - // Do verification based on the requested level. + // Do extra verification if requested. if (verification == Verification::InternalConsistency) { #if ET_ENABLE_PROGRAM_VERIFICATION EXECUTORCH_SCOPE_PROF("Program::verify_internal_consistency"); @@ -185,43 +149,21 @@ Result get_execution_plan( ok, InvalidProgram, "Verification failed; data may be truncated or corrupt"); - const executorch_flatbuffer::Program* flatbuffer_program = - executorch_flatbuffer::GetProgram(program_data->data()); - Error err = validate_program(flatbuffer_program); - ET_CHECK_OR_RETURN_ERROR( - err == Error::Ok, - InvalidProgram, - "Program validation failed: likely a corrupt file"); #else ET_LOG( - Info, - "InternalConsistency verification requested but not available; " - "falling back to Minimal verification. " - "Build with ET_ENABLE_PROGRAM_VERIFICATION=1 for full verification."); + Info, "InternalConsistency verification requested but not available"); #endif } - if (verification == Verification::Minimal -#if !ET_ENABLE_PROGRAM_VERIFICATION - || verification == Verification::InternalConsistency -#endif - ) { - // Verify that the root table offset is within bounds. - // In InternalConsistency mode this is done by VerifyProgramBuffer above. - uint32_t root_offset = - flatbuffers::ReadScalar(program_data->data()); - // The root table is at buf + root_offset. It must not point into the - // header (offset + file identifier = 8 bytes) and must leave room for - // at least a vtable offset (soffset_t) at its position. - ET_CHECK_OR_RETURN_ERROR( - root_offset >= kMinBufferSize && - root_offset <= - program_data->size() - sizeof(flatbuffers::soffset_t), - InvalidProgram, - "Root table offset %u is invalid for program size %zu", - root_offset, - program_data->size()); - } + // The flatbuffer data must start at an aligned address to ensure internal + // alignment of flatbuffer fields. + ET_CHECK_OR_RETURN_ERROR( + IsAligned(program_data->data()), + InvalidArgument, + "Program data 0x%p must be aligned to %zu", + program_data->data(), + kMinimumAlignment); + // Get the pointer to the root flatbuffer table. const executorch_flatbuffer::Program* flatbuffer_program = executorch_flatbuffer::GetProgram(program_data->data()); @@ -314,7 +256,6 @@ Result get_execution_plan( // https://docs.pytorch.org/executorch/stable/api-life-cycle.html#deprecation-policy. // For support, contact the PyTorch Edge team or make an issue in: // https://github.com/pytorch/executorch/issues. -#if ET_ENABLE_DEPRECATED_CONSTANT_BUFFER ET_LOG( Error, "!!DEPRECATED!! This branch is deprecated from ExecuTorch 0.7; re-export this PTE file to ensure support on newer runtimes."); @@ -325,13 +266,6 @@ Result get_execution_plan( flatbuffer_program, /*constant_segment_data=*/FreeableBuffer{}, std::move(pte_data_map)); -#else - ET_LOG( - Error, - "PTE file relies on the constant_buffer path, which is disabled in this" - " build (ET_ENABLE_DEPRECATED_CONSTANT_BUFFER=0). Please re-export the PTE file."); - return Error::InvalidProgram; -#endif } } @@ -348,11 +282,6 @@ size_t Program::num_methods() const { Result Program::get_method_name(size_t plan_index) const { if (plan_index >= this->num_methods()) { - ET_LOG( - Error, - "Plan index %zu >= num methods %zu", - plan_index, - this->num_methods()); return Error::InvalidArgument; } auto internal_program = @@ -360,7 +289,6 @@ Result Program::get_method_name(size_t plan_index) const { // We know that the execution plan exists because num_methods() returned > 0. auto name = internal_program->execution_plan()->Get(plan_index)->name(); if (name == nullptr) { - ET_LOG(Error, "Execution plan %zu has null name", plan_index); return Error::InvalidProgram; } return name->c_str(); @@ -370,9 +298,7 @@ Result Program::load_method( const char* method_name, MemoryManager* memory_manager, EventTracer* event_tracer, - const NamedDataMap* named_data_map, - const LoadBackendOptionsMap* backend_options, - Span kernel_registry) const { + const NamedDataMap* named_data_map) const { EXECUTORCH_SCOPE_PROF("Program::load_method"); internal::event_tracer_create_event_block(event_tracer, "Default"); internal::EventTracerProfileMethodScope event_tracer_scope = @@ -390,13 +316,7 @@ Result Program::load_method( return plan.error(); } return Method::load( - plan.get(), - this, - memory_manager, - event_tracer, - named_data_map, - backend_options, - kernel_registry); + plan.get(), this, memory_manager, event_tracer, named_data_map); } Result Program::method_meta(const char* method_name) const { @@ -454,7 +374,7 @@ Result Program::get_constant_buffer_data( size_t size = constant_segment_data_.size(); ET_CHECK_OR_RETURN_ERROR( - offset <= size && nbytes <= size - offset, + offset + nbytes <= size, InvalidArgument, "Constant segment offset %" PRIu64 " + size_bytes %zu invalid for program constant segment size %zu", @@ -467,7 +387,6 @@ Result Program::get_constant_buffer_data( static_cast(constant_segment_data_.data()) + offset); } else { -#if ET_ENABLE_DEPRECATED_CONSTANT_BUFFER // Otherwise, the constant data is stored inside Program.constant_buffer. const auto* constant_buffer_ptr = internal_program->constant_buffer(); size_t num_elems = @@ -482,26 +401,14 @@ Result Program::get_constant_buffer_data( const auto& constant_buffer = *constant_buffer_ptr; const auto* storage = constant_buffer[buffer_index]->storage(); auto storage_size = storage == nullptr ? 0 : storage->size(); - // nbytes (requested from the program) should be less than storage_size - // (size of the constant buffer from PTE), to prevent reading out of bounds. - // in some cases storage size may be larger than nbytes because of padding; - // executorch-tensor-alignment, or 16 by default. ET_CHECK_OR_RETURN_ERROR( - nbytes <= storage_size, + storage_size <= nbytes, InvalidArgument, - "Requested nbytes %zu exceeds constant buffer storage size %zu", - nbytes, - static_cast(storage_size)); + "Constant buffer size %zu larger than allocated nbytes %zu", + static_cast(constant_buffer[buffer_index]->storage()->size()), + nbytes); return storage->data(); -#else - (void)buffer_index; - (void)nbytes; - ET_LOG( - Error, - "constant_buffer path is disabled (ET_ENABLE_DEPRECATED_CONSTANT_BUFFER=0). Please re-export the PTE file."); - return Error::InvalidProgram; -#endif } } @@ -518,17 +425,7 @@ Result Program::get_output_flattening_encoding( if (!plan.ok()) { return plan.error(); } - auto* container_meta_type = plan.get()->container_meta_type(); - ET_CHECK_OR_RETURN_ERROR( - container_meta_type != nullptr, - InvalidProgram, - "Missing container_meta_type in execution plan"); - auto* encoded_out_str = container_meta_type->encoded_out_str(); - ET_CHECK_OR_RETURN_ERROR( - encoded_out_str != nullptr, - InvalidProgram, - "Missing encoded_out_str in container_meta_type"); - return encoded_out_str->c_str(); + return plan.get()->container_meta_type()->encoded_out_str()->c_str(); } Error Program::get_backend_delegate_data( @@ -588,18 +485,8 @@ Result Program::LoadSegment( // Could fail if offset and size are out of bound for the data, or if this // is reading from a file and fails, or for many other reasons depending on // the implementation of the loader. - uint64_t seg_offset = segment->offset(); - uint64_t absolute_offset = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows( - segment_base_offset_, seg_offset, &absolute_offset) && - absolute_offset <= SIZE_MAX, - InvalidProgram, - "segment_base_offset %zu + segment offset %" PRIu64 " overflows", - segment_base_offset_, - seg_offset); return loader_->load( - static_cast(absolute_offset), segment->size(), segment_info); + segment_base_offset_ + segment->offset(), segment->size(), segment_info); } Error Program::load_mutable_subsegment_into( @@ -666,15 +553,8 @@ Error Program::load_mutable_subsegment_into( auto segment = internal_program_->segments()->Get(segment_offsets->segment_index()); - // Check size (with overflow protection) - size_t end_offset = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows(offset, size, &end_offset), - InvalidProgram, - "offset %zu + size %zu overflows", - offset, - size); - if (end_offset > segment->size()) { + // Check size + if (offset + size > segment->size()) { ET_LOG( Error, "offset %zu + size %zu out of range > %" PRIu64, @@ -689,26 +569,9 @@ Error Program::load_mutable_subsegment_into( segment_offsets->segment_index(), nullptr); - // Load the data (with overflow protection on the addition chain) - uint64_t seg_offset = segment->offset(); - uint64_t base_plus_seg_64 = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows( - segment_base_offset_, seg_offset, &base_plus_seg_64) && - base_plus_seg_64 <= SIZE_MAX, - InvalidProgram, - "segment_base_offset %zu + segment offset %" PRIu64 " overflows", - segment_base_offset_, - seg_offset); - size_t base_plus_seg = static_cast(base_plus_seg_64); - size_t total_offset = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows(base_plus_seg, offset, &total_offset), - InvalidProgram, - "segment base+offset %zu + subsegment offset %zu overflows", - base_plus_seg, - offset); - return loader_->load_into(total_offset, size, info, buffer); + // Load the data + return loader_->load_into( + segment_base_offset_ + segment->offset() + offset, size, info, buffer); } } // namespace ET_RUNTIME_NAMESPACE diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/program.h similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/program.h index e1208e5..768928a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/program.h @@ -8,10 +8,10 @@ #pragma once +#include #include #include -#include #include #include #include @@ -21,7 +21,6 @@ #include #include #include -#include #include // Forward declare flatbuffer types. This is a public header and must not @@ -59,15 +58,10 @@ class Program final { */ Minimal, /** - * When ET_ENABLE_PROGRAM_VERIFICATION is enabled, * Do full verification of the data, ensuring that internal pointers are * self-consistent and that the data has not been truncated or obviously * corrupted. May not catch all types of corruption, but should guard * against illegal memory operations during parsing. - * Also performs additional semantic validation such as: - * - Tensor numel overflow checks (ensuring size calculations don't - * overflow) - * - List element type validation * * Will have higher runtime overhead, scaling with the complexity of the * proram data. @@ -141,9 +135,6 @@ class Program final { * @param[in] event_tracer The event tracer to use for this method run. * @param[in] named_data_map An optional map of {name, blob} used to resolve * data that is external to the PTE, if any. - * @param[in] backend_options An optional map of per-backend load-time options - * (RuntimeSpecs). Each backend will receive its corresponding options - * during initialization. * * @returns The loaded method on success, or an error on failure. */ @@ -151,9 +142,7 @@ class Program final { const char* method_name, MemoryManager* memory_manager, EventTracer* event_tracer = nullptr, - const NamedDataMap* named_data_map = nullptr, - const LoadBackendOptionsMap* backend_options = nullptr, - Span kernel_registry = {}) const; + const NamedDataMap* named_data_map = nullptr) const; /** * Gathers metadata for the named method. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/pte_data_map.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/pte_data_map.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/pte_data_map.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/pte_data_map.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/pte_data_map.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/pte_data_map.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/pte_data_map.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/pte_data_map.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/targets.bzl new file mode 100644 index 0000000..28defd6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/targets.bzl @@ -0,0 +1,127 @@ +load("@fbsource//xplat/executorch/build:build_variables.bzl", "PROGRAM_NO_PRIM_OPS_SRCS") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def _program_preprocessor_flags(): + """Returns the preprocessor_flags to use when building Program.cpp""" + + # The code for flatbuffer verification can add ~30k of .text to the binary. + # It's a valuable feature, but make it optional for space-constrained + # systems. + enable_verification = native.read_config( + "executorch", + "enable_program_verification", + # Default value + "true", + ) + if enable_verification == "false": + return ["-DET_ENABLE_PROGRAM_VERIFICATION=0"] + elif enable_verification == "true": + # Enabled by default. + return [] + else: + fail("executorch.enable_program_verification must be one of 'true' or 'false'; saw '" + + enable_verification + "'") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "memory_manager", + exported_headers = [ + "memory_manager.h", + ], + exported_deps = [ + "//executorch/runtime/core:memory_allocator", + ], + visibility = ["PUBLIC"], + ) + + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_library( + name = "pte_data_map" + aten_suffix, + srcs = [ + "pte_data_map.cpp", + ], + exported_headers = [ + "pte_data_map.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:named_data_map" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + ], + deps = [ + "//executorch/schema:program", + ], + exported_preprocessor_flags = [] if runtime.is_oss else ["-DEXECUTORCH_INTERNAL_FLATBUFFERS=1"], + ) + + runtime.cxx_library( + name = "merged_data_map" + aten_suffix, + exported_headers = [ + "merged_data_map.h", + ], + exported_deps = [ + "//executorch/runtime/core:named_data_map" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "program" + aten_suffix, + exported_deps = [ + ":program_no_prim_ops" + aten_suffix, + "//executorch/kernels/prim_ops:prim_ops_registry" + aten_suffix, + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "program_no_prim_ops" + aten_suffix, + srcs = PROGRAM_NO_PRIM_OPS_SRCS + [ + "tensor_parser{}.cpp".format(aten_suffix if aten_mode else "_portable"), + ], + headers = [ + "platform_memory_allocator.h", + ], + exported_headers = [ + "method.h", + "method_meta.h", + "program.h", + "tensor_parser.h", + ], + compiler_flags = select({ + "ovr_config//os:windows": [], + "DEFAULT" :["-Wno-error=deprecated-declarations"] + }), + preprocessor_flags = _program_preprocessor_flags(), + exported_deps = [ + ":memory_manager", + ":pte_data_map" + aten_suffix, + ":merged_data_map" + aten_suffix, + "//executorch/runtime/backend:interface" + aten_suffix, + "//executorch/runtime/core:core", + "//executorch/runtime/core:named_data_map" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/core:event_tracer" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + "//executorch/runtime/kernel:operator_registry" + aten_suffix, + "//executorch/runtime/platform:platform", + "//executorch/schema:extended_header", + ], + deps = [ + "//executorch/schema:program", + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit" + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser.h index d4ab2ff..fae183e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser.h @@ -97,12 +97,8 @@ ET_NODISCARD Result>> parseListOptionalType( InvalidProgram, "Invalid value index %" PRId32 " for ListOptional", index); - auto optional_result = values[index].tryToOptional(); - if (!optional_result.ok()) { - return optional_result.error(); - } new (&optional_tensor_list[output_idx]) - std::optional(std::move(optional_result.get())); + std::optional(values[index].toOptional()); evalp_list[output_idx] = &values[static_cast(index)]; } output_idx++; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_aten.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_aten.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_exec_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_exec_aten.cpp similarity index 87% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_exec_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_exec_aten.cpp index 31ec237..2e91833 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_exec_aten.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_exec_aten.cpp @@ -41,10 +41,6 @@ ET_NODISCARD Result getMemPlannedPtr( const executorch_flatbuffer::AllocationDetails* allocation_info, size_t nbytes, HierarchicalAllocator* allocator) { - ET_CHECK_OR_RETURN_ERROR( - allocator != nullptr, - InvalidState, - "HierarchicalAllocator must not be null for memory-planned tensor"); // Normal non-constant Tensor. Allocate data using mem_id and offset. // TODO(T142455629): make the allocator actually id based and not indexed @@ -102,15 +98,10 @@ ET_NODISCARD Result> parseTensorList( "Invalid value index %" PRId32 " for TensorList", tensor_index); - auto tensor_result = - values[static_cast(tensor_index)].tryToTensor(); - if (!tensor_result.ok()) { - return tensor_result.error(); - } // Placement new as the list elements are not initialized, so calling // copy assignment is not defined if it's non trivial. - new (&tensor_list[output_idx]) - executorch::aten::Tensor(std::move(tensor_result.get())); + new (&tensor_list[output_idx]) executorch::aten::Tensor( + values[static_cast(tensor_index)].toTensor()); evalp_list[output_idx] = &values[static_cast(tensor_index)]; output_idx++; } @@ -138,12 +129,6 @@ ET_NODISCARD Error validateTensorLayout( "Dim mismatch. Expected %d, got %zu.", dim, expected_layout.sizes().size()); - ET_CHECK_OR_RETURN_ERROR( - s_tensor->dim_order()->size() == static_cast(dim), - InvalidExternalData, - "Dim order size mismatch. Expected %d, got %u.", - dim, - s_tensor->dim_order()->size()); for (int i = 0; i < dim; i++) { ET_CHECK_OR_RETURN_ERROR( s_tensor->sizes()->Get(i) == expected_layout.sizes()[i], @@ -174,14 +159,6 @@ NamedData* get_data_by_key(const char* key, Span entries) { return nullptr; } -// Suppress a GCC 11 false positive -Wstringop-overread triggered by -// flatbuffers' GetPointer inlining into string_view construction. -// Guarded to GCC >= 11 since the warning doesn't exist on older GCC or Clang. -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 11 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstringop-overread" -#endif - ET_NODISCARD Result getTensorDataPtr( const executorch_flatbuffer::Tensor* s_tensor, const Program* program, @@ -193,13 +170,6 @@ ET_NODISCARD Result getTensorDataPtr( const executorch_flatbuffer::AllocationDetails* allocation_info = s_tensor->allocation_info(); - if (allocation_info != nullptr) { - ET_CHECK_OR_RETURN_ERROR( - allocator != nullptr, - InvalidState, - "HierarchicalAllocator is null but tensor has allocation_info requiring memory-planned buffers"); - } - // External tensors. if (s_tensor->extra_tensor_info() != nullptr && s_tensor->extra_tensor_info()->location() == @@ -289,10 +259,6 @@ ET_NODISCARD Result getTensorDataPtr( } } -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 11 -#pragma GCC diagnostic pop -#endif - } // namespace deserialization } // namespace ET_RUNTIME_NAMESPACE } // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_portable.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_portable.cpp similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_portable.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_portable.cpp index 2fc9a2d..02cb019 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_portable.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/tensor_parser_portable.cpp @@ -147,18 +147,6 @@ Result parseTensor( Internal, "dim_order_to_stride returned invalid status"); - // Extract device info from serialized tensor metadata. - // Defaults to CPU/0 for backward compatibility when extra_tensor_info is - // absent (e.g., older PTE files without device annotations). - auto device_type = executorch::runtime::etensor::DeviceType::CPU; - executorch::runtime::etensor::DeviceIndex device_index = 0; - if (s_tensor->extra_tensor_info() != nullptr) { - device_type = static_cast( - s_tensor->extra_tensor_info()->device_type()); - device_index = static_cast( - s_tensor->extra_tensor_info()->device_index()); - } - auto* tensor_impl = method_allocator->allocateInstance(); if (tensor_impl == nullptr) { return Error::MemoryAllocationFailed; @@ -173,9 +161,7 @@ Result parseTensor( /*data=*/nullptr, dim_order, strides, - dynamism, - device_type, - device_index); + dynamism); // Now that we know how big the tensor is, find and assign its memory. Result data_ptr = getTensorDataPtr( diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/CMakeLists.txt new file mode 100644 index 0000000..5477831 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/CMakeLists.txt @@ -0,0 +1,194 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + # Use a wrapper script to set up the environment for MSVC to make Dynamo + # export work. + set(_export_program_cmd + powershell + ${EXECUTORCH_ROOT}/kernels/test/export_test_model.ps1 + -Modules + "\"ModuleAdd,ModuleAddHalf,ModuleAddMul,ModuleDynamicCatUnallocatedIO,ModuleIndex,ModuleMultipleEntry,ModuleSimpleTrain,ModuleStateful\"" + -outDir + "${CMAKE_CURRENT_BINARY_DIR}" + -CondaEnv + $ENV{CONDA_DEFAULT_ENV} + ) +else() + set(_export_program_cmd + ${PYTHON_EXECUTABLE} + -m + test.models.export_program + --modules + "ModuleAdd,ModuleAddHalf,ModuleAddMul,ModuleDynamicCatUnallocatedIO,ModuleIndex,ModuleMultipleEntry,ModuleSimpleTrain,ModuleStateful" + --outdir + "${CMAKE_CURRENT_BINARY_DIR}" + ) +endif() + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddHalf.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMul.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.ptd" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleDynamicCatUnallocatedIO.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleIndex.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleMultipleEntry.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleSimpleTrain.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleStateful.pte" + "${CMAKE_CURRENT_BINARY_DIR}/delegated/ModuleAddMul.pte" + COMMAND ${_export_program_cmd} + COMMAND + ${PYTHON_EXECUTABLE} -m test.models.export_program --modules "ModuleAddMul" + --external-constants --outdir "${CMAKE_CURRENT_BINARY_DIR}" + COMMAND + ${PYTHON_EXECUTABLE} -m test.models.export_delegated_program --modules + "ModuleAddMul" --backend_id "StubBackend" --outdir + "${CMAKE_CURRENT_BINARY_DIR}/delegated/" + WORKING_DIRECTORY ${EXECUTORCH_ROOT} +) + +add_custom_target( + generated_pte_files + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddHalf.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMul.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.ptd" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleDynamicCatUnallocatedIO.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleIndex.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleMultipleEntry.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleSimpleTrain.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleStateful.pte" +) + +set(test_env + "DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH=${EXECUTORCH_ROOT}/test/models/deprecated/ModuleLinear-no-constant-segment.pte" + "ET_MODULE_ADD_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + "ET_MODULE_ADD_HALF_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddHalf.pte" + "ET_MODULE_ADD_MUL_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMul.pte" + "ET_MODULE_ADD_MUL_PROGRAM_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.pte" + "ET_MODULE_ADD_MUL_DATA_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.ptd" + "ET_MODULE_DYNAMIC_CAT_UNALLOCATED_IO_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleDynamicCatUnallocatedIO.pte" + "ET_MODULE_INDEX_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleIndex.pte" + "ET_MODULE_MULTI_ENTRY_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleMultipleEntry.pte" + "ET_MODULE_SIMPLE_TRAIN_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleSimpleTrain.pte" + "ET_MODULE_STATEFUL_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleStateful.pte" + "ET_MODULE_ADD_MUL_DELEGATED_PATH=${CMAKE_CURRENT_BINARY_DIR}/delegated/ModuleAddMul.pte" +) + +et_cxx_test( + runtime_executor_test SOURCES executor_test.cpp EXTRA_LIBS portable_ops_lib + portable_kernels +) +add_dependencies(runtime_executor_test generated_pte_files) +set_property(TEST runtime_executor_test PROPERTY ENVIRONMENT ${test_env}) + +et_cxx_test( + allocation_failure_stress_test + SOURCES + allocation_failure_stress_test.cpp + EXTRA_LIBS + portable_ops_lib + portable_kernels + extension_data_loader + extension_runner_util +) +add_dependencies(allocation_failure_stress_test generated_pte_files) +set_property( + TEST allocation_failure_stress_test PROPERTY ENVIRONMENT ${test_env} +) + +et_cxx_test( + method_test + SOURCES + method_test.cpp + EXTRA_LIBS + portable_ops_lib + portable_kernels + extension_data_loader + extension_flat_tensor + extension_runner_util +) +add_dependencies(method_test generated_pte_files) +set_property(TEST method_test PROPERTY ENVIRONMENT ${test_env}) + +# TODO(T191569140): Enable this test. et_cxx_test(method_meta_test SOURCES +# method_meta_test.cpp EXTRA_LIBS extension_data_loader) + +# TODO(T191569140): Enable this test. et_cxx_test( program_test SOURCES +# program_test.cpp EXTRA_LIBS extension_data_loader ) + +# target_include_directories( program_test PRIVATE +# "${CMAKE_INSTALL_PREFIX}/schema/include" +# "${EXECUTORCH_ROOT}/third-party/flatbuffers/include" ) + +et_cxx_test( + kernel_resolution_test SOURCES kernel_resolution_test.cpp EXTRA_LIBS + extension_data_loader +) +add_dependencies(kernel_resolution_test generated_pte_files) +set_property(TEST kernel_resolution_test PROPERTY ENVIRONMENT ${test_env}) + +et_cxx_test( + kernel_integration_test SOURCES kernel_integration_test.cpp EXTRA_LIBS + extension_data_loader extension_runner_util +) +add_dependencies(kernel_integration_test generated_pte_files) +set_property(TEST kernel_integration_test PROPERTY ENVIRONMENT ${test_env}) + +# TODO(T191569140): Enable this test. et_cxx_test( backend_integration_test +# SOURCES backend_integration_test.cpp EXTRA_LIBS extension_data_loader +# extension_runner_util ) + +et_cxx_test(memory_manager_test SOURCES memory_manager_test.cpp) +add_dependencies(memory_manager_test generated_pte_files) +set_property(TEST memory_manager_test PROPERTY ENVIRONMENT ${test_env}) + +et_cxx_test( + tensor_parser_test + SOURCES + tensor_parser_test.cpp + EXTRA_LIBS + portable_ops_lib + portable_kernels + extension_data_loader + extension_runner_util + program_schema +) +add_dependencies(tensor_parser_test generated_pte_files) +set_property(TEST tensor_parser_test PROPERTY ENVIRONMENT ${test_env}) + +target_include_directories( + tensor_parser_test + PRIVATE "${CMAKE_INSTALL_PREFIX}/schema/include" + "${EXECUTORCH_ROOT}/third-party/flatbuffers/include" +) + +list(TRANSFORM _test_backend_compiler_lib__srcs PREPEND "${EXECUTORCH_ROOT}/") +add_library( + test_backend_compiler_lib STATIC ${_test_backend_compiler_lib__srcs} +) + +target_link_libraries(test_backend_compiler_lib PUBLIC executorch_core) + +executorch_target_link_options_shared_lib(test_backend_compiler_lib) + +install(TARGETS test_backend_compiler_lib DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/TARGETS new file mode 100644 index 0000000..a6c52d1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets(is_fbcode = True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/allocation_failure_stress_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/allocation_failure_stress_test.cpp new file mode 100644 index 0000000..37f3a51 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/allocation_failure_stress_test.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::Tensor; +using executorch::extension::FileDataLoader; +using executorch::extension::prepare_input_tensors; +using executorch::runtime::Error; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::MemoryManager; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::testing::ManagedMemoryManager; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class AllocationFailureStressTest : public ::testing::Test { + protected: + void SetUp() override { + executorch::runtime::runtime_init(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + } + + private: + // Must outlive program_, but tests shouldn't need to touch it. + std::unique_ptr loader_; + + protected: + std::unique_ptr program_; +}; + +/** + * Slowly increases the amount of available runtime memory until load_method() + * and execute() succeed. This should cause every runtime allocation to fail at + * some point, exercising every allocation failure path reachable by the test + * model. + */ +TEST_F(AllocationFailureStressTest, End2EndIncreaseRuntimeMemUntilSuccess) { + size_t runtime_mem_bytes = 0; + Error err = Error::Internal; + size_t num_load_failures = 0; + while (runtime_mem_bytes < kDefaultRuntimeMemBytes && err != Error::Ok) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, runtime_mem_bytes); + + // Loading should fail several times from allocation failures. + Result method = program_->load_method("forward", &mmm.get()); + if (method.error() != Error::Ok) { + runtime_mem_bytes += sizeof(size_t); + num_load_failures++; + continue; + } + + // Execution does not use the runtime allocator, so it should always succeed + // once load was successful. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + err = method->execute(); + ASSERT_EQ(err, Error::Ok); + } + EXPECT_GT(num_load_failures, 0) << "Expected at least some failures"; + EXPECT_EQ(err, Error::Ok) + << "Did not succeed after increasing runtime_mem_bytes to " + << runtime_mem_bytes; +} + +/** + * Slowly increases the amount of available non-constant memory until + * load_method() and execute() succeed. This should cause every non-const + * allocation to fail at some point, exercising every allocation failure path + * reachable by the test model. + */ +TEST_F(AllocationFailureStressTest, End2EndNonConstantMemUntilSuccess) { + size_t non_constant_mem_bytes = 0; + Error err = Error::Internal; + size_t num_load_failures = 0; + while (non_constant_mem_bytes < kDefaultNonConstMemBytes && + err != Error::Ok) { + ManagedMemoryManager mmm(non_constant_mem_bytes, kDefaultRuntimeMemBytes); + + // Loading should fail several times from allocation failures. + Result method = program_->load_method("forward", &mmm.get()); + if (method.error() != Error::Ok) { + non_constant_mem_bytes += sizeof(size_t); + num_load_failures++; + continue; + } + + // Execution does not use the runtime allocator, so it should always succeed + // once load was successful. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + err = method->execute(); + ASSERT_EQ(err, Error::Ok); + } + EXPECT_GT(num_load_failures, 0) << "Expected at least some failures"; + EXPECT_EQ(err, Error::Ok) + << "Did not succeed after increasing non_constant_mem_bytes to " + << non_constant_mem_bytes; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_data_separation_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_data_separation_test.cpp new file mode 100644 index 0000000..f6af25c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_data_separation_test.cpp @@ -0,0 +1,116 @@ + +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::FlatTensorDataMap; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class BackendDataSeparationTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Make sure that the backend has been registered. Safe to call multiple + // times. Doing this at runtime ensures that it's only registered if these + // tests are run. + ASSERT_EQ(example::register_executor_backend(), Error::Ok); + + // Create data loaders. + Result linear_program_loader = FileDataLoader::from( + std::getenv("ET_MODULE_LINEAR_DELEGATE_PROGRAM_PATH")); + ASSERT_EQ(linear_program_loader.error(), Error::Ok); + linear_program_loader_ = std::make_unique( + std::move(linear_program_loader.get())); + + Result linear_data_loader = + FileDataLoader::from(std::getenv("ET_MODULE_LINEAR_DATA_PATH")); + ASSERT_EQ(linear_data_loader.error(), Error::Ok); + linear_data_loader_ = + std::make_unique(std::move(linear_data_loader.get())); + + // Create programs. + Result linear_program = Program::load( + linear_program_loader_.get(), + Program::Verification::InternalConsistency); + ASSERT_EQ(linear_program.error(), Error::Ok); + linear_program_ = + std::make_unique(std::move(linear_program.get())); + + Result linear_data_map = + FlatTensorDataMap::load(linear_data_loader_.get()); + EXPECT_EQ(linear_data_map.error(), Error::Ok); + linear_data_map_ = + std::make_unique(std::move(linear_data_map.get())); + + ET_LOG( + Info, + "setup done, named_data_map_ = %lu", + linear_data_map_->get_num_keys().get()); + } + + private: + std::unique_ptr linear_program_loader_; + std::unique_ptr linear_data_loader_; + + protected: + std::unique_ptr linear_program_; + std::unique_ptr linear_data_map_; +}; + +TEST_F(BackendDataSeparationTest, TestSeparation) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = linear_program_->load_method( + "forward", + &mmm.get(), + /*event_tracer=*/nullptr, + /*named_data_map=*/linear_data_map_.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[1] = {3}; + uint8_t dim_order[1] = {0}; + int32_t strides[1] = {1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 1, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_integration_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_integration_test.cpp new file mode 100644 index 0000000..c55269d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/backend_integration_test.cpp @@ -0,0 +1,745 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::runtime::BackendExecutionContext; +using executorch::runtime::BackendInitContext; +using executorch::runtime::BackendInterface; +using executorch::runtime::CompileSpec; +using executorch::runtime::DataLoader; +using executorch::runtime::DelegateHandle; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +/** + * A backend class whose methods can be overridden individually. + */ +class StubBackend final : public BackendInterface { + public: + // Function signature types that match the BackendInterface methods. + using IsAvailableFn = std::function; + using InitFn = std::function( + FreeableBuffer*, + ArrayRef, + BackendInitContext&)>; + using ExecuteFn = std::function< + Error(BackendExecutionContext&, DelegateHandle*, Span)>; + using DestroyFn = std::function; + + // Default name that this backend is registered as. + static constexpr char kName[] = "StubBackend"; + + void install_is_available(IsAvailableFn fn) { + is_available_fn_ = fn; + } + + bool is_available() const override { + if (is_available_fn_) { + return is_available_fn_.value()(); + } + // Return a benign value otherwise. + return true; + } + + void install_init(InitFn fn) { + init_fn_ = fn; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + if (init_fn_) { + return init_fn_.value()(processed, compile_specs, context); + } + // Return a benign value otherwise. + return nullptr; + } + + void install_execute(ExecuteFn fn) { + execute_fn_ = fn; + } + + Error execute( + BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + if (execute_fn_) { + return execute_fn_.value()(context, handle, args); + } + // Return a benign value otherwise. + return Error::Ok; + } + + void install_destroy(DestroyFn fn) { + destroy_fn_ = fn; + } + + void destroy(DelegateHandle* handle) const override { + if (destroy_fn_) { + destroy_fn_.value()(handle); + } + } + + /** + * Resets to the original constructed state. + */ + void reset() { + is_available_fn_.reset(); + init_fn_.reset(); + execute_fn_.reset(); + destroy_fn_.reset(); + } + + /** + * Registers the singleton instance if not already registered. + * + * Note that this can be used to install the stub as the implementation for + * any export-time backend by passing in the right name, as long as no other + * backend with that name has been registered yet. + */ + static Error register_singleton(const char* name = kName) { + if (!registered_) { + registered_ = true; + return executorch::runtime::register_backend({name, &singleton_}); + } + return Error::Ok; + } + + /** + * Returns the instance that was added to the backend registry. + */ + static StubBackend& singleton() { + return singleton_; + } + + private: + static bool registered_; + static StubBackend singleton_; + + std::optional is_available_fn_; + std::optional init_fn_; + std::optional execute_fn_; + std::optional destroy_fn_; +}; + +bool StubBackend::registered_ = false; +StubBackend StubBackend::singleton_; + +/** + * A DataLoader that wraps a real DataLoader and records the operations + * performed on it and the FreeableBuffers it loads. + */ +class DataLoaderSpy final : public DataLoader { + public: + /// A record of an operation performed on this DataLoader. + struct Operation { + enum { Load, Free } op; + size_t offset; // Set for Load; zero for Free. + void* data; // Set for Free; nullptr for Load. + size_t size; // Set for Load and Free. + std::unique_ptr + segment_info; // Set for Load; nullptr for Free. + }; + + explicit DataLoaderSpy(DataLoader* delegate) : delegate_(delegate) {} + + Result load( + size_t offset, + size_t size, + const SegmentInfo& segment_info) const override { + Result buf = delegate_->load(offset, size, segment_info); + if (!buf.ok()) { + return buf.error(); + } + + auto segment_info_cpy = + std::make_unique(segment_info); + operations_.push_back( + {Operation::Load, + offset, + /*data=*/nullptr, + size, + /*segment_info=*/std::move(segment_info_cpy)}); + auto* context = new SpyContext(&operations_, std::move(buf.get())); + // Use context->buffer since buf has been moved. + return FreeableBuffer( + context->buffer.data(), context->buffer.size(), FreeBuffer, context); + } + + Result size() const override { + return delegate_->size(); + } + + /** + * Returns records of the operations performed on this DataLoader and the + * FreeableBuffers it returned, in order they were performed. + */ + const std::vector& operations() const { + return operations_; + } + + /** + * Returns true if the DataLoader::load() method was called with the correct + * segment info. + */ + bool UsedLoad( + DataLoader::SegmentInfo::Type segment_type, + const char* descriptor = nullptr) const { + for (const auto& op : operations_) { + if (op.op != Operation::Load) { + continue; + } + // We have a load op. + if (op.segment_info->segment_type == segment_type) { + if (segment_type != DataLoader::SegmentInfo::Type::Backend) { + // For non-backend segments, the descriptor is irrelevant / a nullptr. + return true; + } else { + if (strcmp(op.segment_info->descriptor, descriptor) == 0) { + return true; + } + } + } + } + return false; + } + + /** + * Returns true if the operations list shows that the provided data pointer + * was freed. + */ + bool WasFreed(const void* data) const { + for (const auto& op : operations_) { + if (op.op == Operation::Free && op.data == data) { + return true; + } + } + return false; + } + + private: + struct SpyContext { + SpyContext(std::vector* operations, FreeableBuffer&& buffer) + : operations(operations), buffer(std::move(buffer)) {} + std::vector* operations; + FreeableBuffer buffer; + }; + + static void FreeBuffer(void* context, void* data, size_t size) { + auto* sc = reinterpret_cast(context); + sc->operations->push_back( + {Operation::Free, /*offset=*/0, data, size, /*segment_info=*/nullptr}); + delete sc; + } + + /// The real loader to delegate to. + DataLoader* delegate_; + + mutable std::vector operations_; +}; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024; + +class BackendIntegrationTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Make sure that the backend has been registered. Safe to call multiple + // times. Doing this at runtime ensures that it's only registered if these + // tests are run. + ASSERT_EQ(StubBackend::register_singleton(), Error::Ok); + + // Paths to the test program files. + program_path_ = std::getenv("ET_MODULE_ADD_MUL_DELEGATED_PATH"); + ASSERT_FALSE(program_path_.empty()); + program_nosegments_path_ = std::getenv("ET_MODULE_ADD_MUL_NOSEGMENTS_PATH"); + ASSERT_FALSE(program_nosegments_path_.empty()); + } + + void TearDown() override { + // Clean up any modifications to the singleton. + StubBackend::singleton().reset(); + } + + /** + * Returns true if program_path() returns a file with extracted segments. + */ + bool using_segments() const { + return GetParam(); + } + + /** + * Returns tha path to the program to load. May or may not have extracted + * segments, depending on the return value of using_segments(). + */ + const char* program_path() const { + if (using_segments()) { + return program_path_.c_str(); + } else { + return program_nosegments_path_.c_str(); + } + } + + private: + std::string program_path_; + std::string program_nosegments_path_; +}; + +TEST_P(BackendIntegrationTest, BackendIsPresent) { + BackendInterface* backend = + executorch::runtime::get_backend_class(StubBackend::kName); + ASSERT_EQ(backend, &StubBackend::singleton()); +} + +// Demonstrate that installed StubBackend initializes successfully by default. +TEST_P(BackendIntegrationTest, BasicInitSucceeds) { + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + + Result program = Program::load(&loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + auto method_meta = program->method_meta("forward"); + EXPECT_EQ(method_meta->uses_backend(StubBackend::kName), true); + EXPECT_EQ(method_meta->uses_backend("INVALID_BACKEND_NAME"), false); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_EQ(method_res.error(), Error::Ok); +} + +TEST_P(BackendIntegrationTest, GetBackendNamesSuccess) { + // Load the program from file. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + + Result program = Program::load(&loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // Get method metadata for the "forward" method. + auto method_meta = program->method_meta("forward"); + + // Ensure the StubBackend is used. + EXPECT_TRUE(method_meta->uses_backend(StubBackend::kName)); + + // Retrieve the number of backends. + const size_t num_backends = method_meta->num_backends(); + EXPECT_GT(num_backends, 0u); + + // Iterate through each backend and verify its name. + for (size_t i = 0; i < num_backends; ++i) { + auto backend_name_result = method_meta->get_backend_name(i); + ASSERT_TRUE(backend_name_result.ok()); + const char* name = backend_name_result.get(); + // For this test, we expect that the only backend is StubBackend. + EXPECT_STREQ(name, StubBackend::kName); + } + // Check that an out-of-range index returns an error. + auto out_of_range_result = method_meta->get_backend_name(num_backends); + EXPECT_FALSE(out_of_range_result.ok()); +} + +TEST_P(BackendIntegrationTest, FreeingProcessedBufferSucceeds) { + // Install an init() implementation that frees its processed buffer, and lets + // us know that it was actually called by setting init_called. + bool init_called = false; + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + init_called = true; + processed_data = processed->data(); + processed->Free(); + return nullptr; + }); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_EQ(method_res.error(), Error::Ok); + + // Demonstrate that our installed init was called. + EXPECT_TRUE(init_called); + + // See if the processed data was freed. + bool processed_was_freed = spy_loader.WasFreed(processed_data); + if (using_segments()) { + // Used the loader to create the FreeableBuffer that was passed to the + // backend, so we can see its Free() call. + EXPECT_TRUE(processed_was_freed); + } else { + // Didn't use the loader to create the FreeableBuffer that was passed to the + // backend, so we can't see its Free() call. + EXPECT_FALSE(processed_was_freed); + } +} + +TEST_P(BackendIntegrationTest, EndToEndTestWithProcessedAsHandle) { + // Install an init() implementation that does not free its processed buffer, + // and returns the FreeableBuffer as the delegate handle. + FreeableBuffer* init_processed = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + init_processed = processed; + return processed; + }); + + // Install an execute() that expects the handle to be the processed + // FreeableBuffer. + DelegateHandle* execute_handle = nullptr; + StubBackend::singleton().install_execute( + [&](ET_UNUSED BackendExecutionContext& backend_execution_context, + DelegateHandle* handle, + ET_UNUSED Span args) -> Error { + execute_handle = handle; + auto* processed = reinterpret_cast(handle); + + // Read the data, which will tend to cause an ASAN error if it's not + // valid. + auto copy = std::make_unique(processed->size()); + std::memcpy(copy.get(), processed->data(), processed->size()); + + return Error::Ok; + }); + + // Install a destroy() that expects the handle to be the processed + // FreeableBuffer. + DelegateHandle* destroy_handle = nullptr; + StubBackend::singleton().install_destroy( + [&](DelegateHandle* handle) -> void { destroy_handle = handle; }); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + + // Hold onto the address of the processed buffer so we can compare against + // it after the FreeableBuffer has been destroyed. + const void* processed_data; + + // Add a scope so we can watch executor be destroyed. + { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method_res.ok()); + + // Demonstrate that our installed init was called. + EXPECT_NE(init_processed, nullptr); + // Not freed yet. + EXPECT_GT(init_processed->size(), 0); + EXPECT_NE(init_processed->data(), nullptr); + processed_data = init_processed->data(); + + // The processed data should not have been freed during init. + EXPECT_FALSE(spy_loader.WasFreed(init_processed->data())); + auto method(std::move(method_res.get())); + // Execute the model. + auto input_cleanup = executorch::extension::prepare_input_tensors(method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto err = method.execute(); + EXPECT_EQ(err, Error::Ok); + + // Check that the processed buffer was passed to execute() as the handle. + EXPECT_EQ(init_processed, execute_handle); + + // The processed data should not have been freed during execution. + EXPECT_FALSE(spy_loader.WasFreed(init_processed->data())); + } + + // `executor` has now been destroyed, which should have freed the processed + // data. + bool processed_was_freed = spy_loader.WasFreed(processed_data); + if (using_segments()) { + // Used the loader to create the FreeableBuffer that was passed to the + // backend, so we can see its Free() call. + EXPECT_TRUE(processed_was_freed); + } else { + // Didn't use the loader to create the FreeableBuffer that was passed to the + // backend, so we can't see its Free() call. + EXPECT_FALSE(processed_was_freed); + } + + // And it should have destroyed the backend handle. + EXPECT_EQ(execute_handle, destroy_handle); +} + +/** + * Tests that the DataLoader's load is receiving the correct segment info for + * different types of segments. + */ +TEST_P(BackendIntegrationTest, SegmentInfoIsPassedIntoDataLoader) { + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + processed_data = processed->data(); + processed->Free(); + return nullptr; + }); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + // Expect that load was called correctly on program segments. + bool program_load_was_called = + spy_loader.UsedLoad(DataLoader::SegmentInfo::Type::Program, nullptr); + + // Load a method. + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_EQ(method_res.error(), Error::Ok); + + // Expect that load was called correctly on a backend segment. + bool backend_load_was_called = spy_loader.UsedLoad( + DataLoader::SegmentInfo::Type::Backend, + "StubBackend"); // This backend id is taken from the StubBackend defined + // in export_delegated_program.py. + + EXPECT_TRUE(program_load_was_called); + EXPECT_EQ(backend_load_was_called, using_segments()); +} + +TEST_P(BackendIntegrationTest, GetMethodNameDuringInitSuccess) { + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + auto method_name = backend_init_context.get_method_name(); + // Ensure that we can get the method name during init via context + EXPECT_STREQ(method_name, "forward"); + processed_data = processed->data(); + return nullptr; + }); + Result program = Program::load(&loader.get()); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method.ok()); + ASSERT_EQ(program.error(), Error::Ok); +} + +TEST_P(BackendIntegrationTest, GetMethodNameDuringExecuteSuccess) { + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + StubBackend::singleton().install_execute( + [&](BackendExecutionContext& backend_execution_context, + ET_UNUSED DelegateHandle* handle, + ET_UNUSED Span args) -> Error { + // Ensure that we can get the method name during execution via context + auto method_name = backend_execution_context.get_method_name(); + EXPECT_STREQ(method_name, "forward"); + return Error::Ok; + }); + Result program = Program::load(&loader.get()); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method.ok()); + + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 1); + input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 2); + ASSERT_EQ(input_err, Error::Ok); + + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +// TODO: Add more tests for the runtime-to-backend interface. E.g.: +// - Errors during init() or execute() result in runtime init/execution failures +// - Correct values are passed to init()/execute() +// - Demonstrate use of the runtime allocator +// - ... + +// Run all BackendIntegrationTests multiple times, varying the return value of +// `GetParam()` based on the `testing::Values` list. The tests will interpret +// the boolean as "using segments". +INSTANTIATE_TEST_SUITE_P( + VariedSegments, + BackendIntegrationTest, + testing::Values(false, true)); + +class DelegateDataAlignmentTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Make sure that the backend has been registered. Safe to call multiple + // times. Doing this at runtime ensures that it's only registered if these + // tests are run. + ASSERT_EQ(StubBackend::register_singleton(), Error::Ok); + + // Paths to the test program files. + default_alignment_program_path_ = + std::getenv("ET_MODULE_ADD_MUL_NOSEGMENTS_PATH"); + ASSERT_FALSE(default_alignment_program_path_.empty()); + override_alignment_program_path_ = + std::getenv("ET_MODULE_ADD_MUL_NOSEGMENTS_DA1024_PATH"); + ASSERT_FALSE(override_alignment_program_path_.empty()); + } + + void TearDown() override { + // Clean up any modifications to the singleton. + StubBackend::singleton().reset(); + } + + /** + * Returns the expected minimum alignment of inline tensor data, given + * the testing parameter. + */ + size_t expected_alignment() const { + if (GetParam()) { + // The delegate data inline alignment used by the -da1024 file. + return 1024; + } else { + // Minimum alignment expected by program.cpp. + return alignof(std::max_align_t); + } + } + + /** + * Returns tha path to the program to load. May or may not have an alignment + * override, depending on the return value of expected_alignment(). + */ + const char* program_path() const { + if (GetParam()) { + return override_alignment_program_path_.c_str(); + } else { + return default_alignment_program_path_.c_str(); + } + } + + private: + std::string default_alignment_program_path_; + std::string override_alignment_program_path_; +}; + +TEST_P(DelegateDataAlignmentTest, ExpectedDataAlignment) { + // Install an init() implementation that records the pointer to the delegate + // data blob so we can check its alignment. + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + processed_data = processed->data(); + return nullptr; + }); + + // Create a loader that can satisfy the alignment required by this program. + Result loader = + FileDataLoader::from(program_path(), /*alignment=*/expected_alignment()); + ASSERT_EQ(loader.error(), Error::Ok); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method.ok()); + + // Demonstrate that our installed init was called. + EXPECT_NE(processed_data, nullptr); + + // Check that it had the required alignment. The alignment of 1024 is larger + // than the test file with default alignment, so the default alignment cannot + // accidentally satisfy it. + EXPECT_ALIGNED(processed_data, expected_alignment()); +} + +// Run all DelegateDataAlignmentTests multiple times, varying the return value +// of `GetParam()` based on the `testing::Values` list. The tests will interpret +// the boolean as "was inline delegate data alignment overridden to 1024". +INSTANTIATE_TEST_SUITE_P( + VariedAlignment, + DelegateDataAlignmentTest, + testing::Values(false, true)); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/executor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/executor_test.cpp new file mode 100644 index 0000000..de5597a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/executor_test.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using executorch::aten::IntArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::get_op_function_from_registry; +using executorch::ET_RUNTIME_NAMESPACE::Kernel; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using executorch::ET_RUNTIME_NAMESPACE::OpFunction; +using executorch::ET_RUNTIME_NAMESPACE::register_kernel; +using executorch::ET_RUNTIME_NAMESPACE::registry_has_op_function; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::testing::TensorFactory; + +namespace pytree = ::executorch::extension::pytree; + +class ExecutorTest : public ::testing::Test { + protected: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(ExecutorTest, Tensor) { + TensorFactory tf; + Tensor a = tf.make({2, 2}, {1, 2, 3, 4}); + + auto data_p = a.const_data_ptr(); + ASSERT_EQ(data_p[0], 1); + ASSERT_EQ(data_p[1], 2); + ASSERT_EQ(data_p[2], 3); + ASSERT_EQ(data_p[3], 4); +} + +TEST_F(ExecutorTest, EValue) { + TensorFactory tf; + Tensor a = tf.make({2, 2}, {1, 2, 3, 4}); + + EValue v(a); + ASSERT_TRUE(v.isTensor()); + ASSERT_EQ(v.toTensor().nbytes(), 16); +} + +/** + * According to the precision limitations listed here: + * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Precision_limitations + * The max precision error for a half in the range [2^n, 2^(n+1)] is 2^(n-10) + */ +float toleranceFloat16(float f) { + return pow(2, static_cast(log2(fabs(f))) - 10); +} + +TEST_F(ExecutorTest, TensorHalf) { + TensorFactory tf; + Tensor a = tf.make({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + + ASSERT_EQ(a.nbytes(), 8); + ASSERT_EQ(a.element_size(), 2); + ASSERT_EQ(a.numel(), 4); + ASSERT_EQ(a.scalar_type(), ScalarType::Half); + + auto data_p = a.const_data_ptr(); + ASSERT_NEAR( + data_p[0], 1.0f, toleranceFloat16(fmax(fabs(1.0f), fabs(data_p[0])))); + ASSERT_NEAR( + data_p[1], 2.0f, toleranceFloat16(fmax(fabs(2.0f), fabs(data_p[1])))); +} + +TEST_F(ExecutorTest, RegistryLookupAndCall) { + const char* op_name = "aten::add.out"; + Result func = get_op_function_from_registry(op_name); + ASSERT_EQ(func.error(), Error::Ok); + ASSERT_NE(*func, nullptr); + + TensorFactory tf; + constexpr size_t num_evalues = 4; + EValue evalues[num_evalues] = { + tf.make({2, 2}, {1, 2, 3, 4}), + tf.make({2, 2}, {5, 6, 7, 8}), + Scalar(1), + tf.make({2, 2}, {0, 0, 0, 0}), + }; + + EValue* kernel_args[5]; + for (size_t i = 0; i < num_evalues; i++) { + kernel_args[i] = &evalues[i]; + } + // x and x_out args are same evalue for out variant kernels + kernel_args[4] = &evalues[3]; + + KernelRuntimeContext context{}; + (*func)(context, Span(kernel_args)); + auto c_ptr = evalues[3].toTensor().const_data_ptr(); + ASSERT_EQ(c_ptr[3], 12); +} + +TEST_F(ExecutorTest, IntArrayRefSingleElement) { + // Create an IntArrayRef with a single element. `ref` will contain a pointer + // to `one`, which must outlive the array ref. + const IntArrayRef::value_type one = 1; + IntArrayRef ref(one); + EXPECT_EQ(ref[0], 1); +} + +TEST_F(ExecutorTest, IntArrayRefDataAndLength) { + // Create an IntArrayRef from an array. `ref` will contain a pointer to + // `array`, which must outlive the array ref. + const IntArrayRef::value_type array[4] = {5, 6, 7, 8}; + const IntArrayRef::size_type length = 4; + IntArrayRef ref(array, length); + + EXPECT_EQ(ref.size(), length); + EXPECT_EQ(ref.front(), 5); + EXPECT_EQ(ref.back(), 8); +} + +TEST_F(ExecutorTest, EValueFromScalar) { + Scalar b((bool)true); + Scalar i((int64_t)2); + Scalar d((double)3.0); + + EValue evalue_b(b); + ASSERT_TRUE(evalue_b.isScalar()); + ASSERT_TRUE(evalue_b.isBool()); + ASSERT_EQ(evalue_b.toBool(), true); + + EValue evalue_i(i); + ASSERT_TRUE(evalue_i.isScalar()); + ASSERT_TRUE(evalue_i.isInt()); + ASSERT_EQ(evalue_i.toInt(), 2); + + EValue evalue_d(d); + ASSERT_TRUE(evalue_d.isScalar()); + ASSERT_TRUE(evalue_d.isDouble()); + ASSERT_NEAR(evalue_d.toDouble(), 3.0, 0.01); +} + +TEST_F(ExecutorTest, EValueToScalar) { + EValue v((int64_t)2); + ASSERT_TRUE(v.isScalar()); + + Scalar s = v.toScalar(); + ASSERT_TRUE(s.isIntegral(false)); + ASSERT_EQ(s.to(), 2); +} + +void test_op(KernelRuntimeContext& /*unused*/, Span /*unused*/) {} + +TEST_F(ExecutorTest, OpRegistration) { + auto s1 = register_kernel(Kernel("test", test_op)); + auto s2 = register_kernel(Kernel("test_2", test_op)); + ASSERT_EQ(Error::Ok, s1); + ASSERT_EQ(Error::Ok, s2); + ET_EXPECT_DEATH( + []() { (void)register_kernel(Kernel("test", test_op)); }(), ""); + + ASSERT_TRUE(registry_has_op_function("test")); + ASSERT_TRUE(registry_has_op_function("test_2")); +} + +TEST_F(ExecutorTest, OpRegistrationWithContext) { + auto op = Kernel( + "test_op_with_context", + [](KernelRuntimeContext& context, Span values) { + (void)context; + *(values[0]) = Scalar(100); + }); + auto s1 = register_kernel(op); + ASSERT_EQ(Error::Ok, s1); + + Result func = + get_op_function_from_registry("test_op_with_context"); + ASSERT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} + +TEST_F(ExecutorTest, AddMulAlreadyRegistered) { + ASSERT_TRUE(registry_has_op_function("aten::add.out")); + ASSERT_TRUE(registry_has_op_function("aten::mul.out")); +} + +TEST(PyTreeEValue, List) { + std::string spec = "L2#1#1($,$)"; + + Scalar i((int64_t)2); + Scalar d((double)3.0); + EValue items[2] = {i, d}; + + auto c = pytree::unflatten(spec, items); + ASSERT_TRUE(c.isList()); + ASSERT_EQ(c.size(), 2); + + const auto& child0 = c[0]; + const auto& child1 = c[1]; + + ASSERT_TRUE(child0.isLeaf()); + ASSERT_TRUE(child1.isLeaf()); + + EValue ev_child0 = child0; + ASSERT_TRUE(ev_child0.isScalar()); + ASSERT_TRUE(ev_child0.isInt()); + ASSERT_EQ(ev_child0.toInt(), 2); + + ASSERT_TRUE(child1.leaf().isScalar()); + ASSERT_TRUE(child1.leaf().isDouble()); + ASSERT_NEAR(child1.leaf().toDouble(), 3.0, 0.01); +} + +auto unflatten(EValue* items) { + std::string spec = "D4#1#1#1#1('key0':$,1:$,23:$,123:$)"; + return pytree::unflatten(spec, items); +} + +TEST(PyTreeEValue, DestructedSpec) { + Scalar i0((int64_t)2); + Scalar d1((double)3.0); + Scalar i2((int64_t)4); + Scalar d3((double)5.0); + EValue items[4] = {i0, d1, i2, d3}; + auto c = unflatten(items); + + ASSERT_TRUE(c.isDict()); + ASSERT_EQ(c.size(), 4); + + auto& key0 = c.key(0); + auto& key1 = c.key(1); + + ASSERT_TRUE(key0 == pytree::Key("key0")); + ASSERT_TRUE(key1 == pytree::Key(1)); + + const auto& child0 = c[0]; + const auto& child1 = c[1]; + ASSERT_TRUE(child0.isLeaf()); + ASSERT_TRUE(child1.isLeaf()); + + EValue ev_child0 = child0; + ASSERT_TRUE(ev_child0.isScalar()); + ASSERT_TRUE(ev_child0.isInt()); + ASSERT_EQ(ev_child0.toInt(), 2); + + ASSERT_TRUE(child1.leaf().isScalar()); + ASSERT_TRUE(child1.leaf().isDouble()); + ASSERT_NEAR(child1.leaf().toDouble(), 3.0, 0.01); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_integration_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_integration_test.cpp new file mode 100644 index 0000000..3b5e547 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_integration_test.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Kernel; +using executorch::runtime::KernelKey; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +/** + * Used to control and observe the behavior of a kernel. + */ +struct KernelControl { + public: + // The number of times the kernel has been called. + int call_count = 0; + + // If true, the kernel should call `context.fail(error_to_set)`. If false, + // the kernel should not call `context.fail()`. + bool call_context_fail = true; + + // The error value that the kernel should pass to `context.fail()` before + // returning. + Error fail_value = Error::Ok; + + // If true, the kernel should allocate temporary memory. + bool allocate_temp_memory = false; + + // If true, the kernel should simulate allocating temporary memory. + bool simulate_temp_memory_allocation = false; + + // The size of the temporary memory to allocate. + int temp_memory_size = 0; + + // The total size of all allocations. + int total_allocated_size = 0; + + void reset() { + call_count = 0; + call_context_fail = false; + fail_value = Error::Ok; + allocate_temp_memory = false; + simulate_temp_memory_allocation = false; + temp_memory_size = 0; + total_allocated_size = 0; + } + + /** + * Registers a kernel that uses the singleton instance to record and control + * its behavior. + */ + static void register_singleton() { + if (registered_) { + return; + } + + // This test helper installs itself as aten::add.out: + // + // add.out(Tensor self, Tensor other, *, Scalar alpha=1, Tensor(a!) out) -> + // Tensor(a!) + // + // The arguments are: `self, other, out, out` (we repeat the out argument in + // the program). And since we traced using randn(2, 2), all the args are + // Float with dim order (0, 1) + + // Construct a kernel key with the following meta: + // executorch::aten::DimOrderType contiguous[] = {0, 1}; + // TensorMeta float_contiguous[] = { + // TensorMeta(ScalarType::Float, contiguous), // self + // TensorMeta(ScalarType::Float, contiguous), // other + // TensorMeta(ScalarType::Float, contiguous), // out + // TensorMeta(ScalarType::Float, contiguous)}; // out (repeated) + KernelKey key = + executorch::runtime::KernelKey("v1/6;0,1|6;0,1|6;0,1|6;0,1"); + Kernel kernel = executorch::runtime::Kernel( + "aten::add.out", key, KernelControl::kernel_hook); + Error err = executorch::runtime::register_kernel(kernel); + EXPECT_EQ(err, Error::Ok); + + registered_ = true; + } + + static KernelControl* singleton() { + return &singleton_; + } + + private: + /** + * An OpFunction-compatible function that uses the singleton KernelControl + * to record and determine its behavior. + */ + static void kernel_hook( + KernelRuntimeContext& context, + ET_UNUSED Span args) { + auto* control = KernelControl::singleton(); + control->call_count++; + if (control->call_context_fail) { + context.fail(control->fail_value); + } + + // Allocate temporary memory. + if (control->allocate_temp_memory) { + Result temp_mem_res = + context.allocate_temp(control->temp_memory_size); + if (temp_mem_res.ok()) { + control->total_allocated_size += control->temp_memory_size; + // We actually use the memory, to test default memory allocation was + // successful. + uint8_t* array = (uint8_t*)(temp_mem_res.get()); + for (int i = 0; i < control->temp_memory_size; i++) { + array[i] = i % 256; + } + } + } + + // Simulate allocating temporary memory. We use this, for testing that when + // a temp allocator is provided, the kernel will use it, instead of + // allocating memory with the default platform memory allocator. + // The provided TempMemoryAllocator class in this file, simulates allocating + // memory instead of actually allocating anything. + if (control->simulate_temp_memory_allocation) { + Result temp_mem_res = + context.allocate_temp(control->temp_memory_size); + control->total_allocated_size += control->temp_memory_size; + EXPECT_EQ(temp_mem_res.error(), Error::Ok); + } + } + + static bool registered_; + static KernelControl singleton_; +}; + +bool KernelControl::registered_ = false; +KernelControl KernelControl::singleton_; + +/** + * MemoryAllocator that keeps track of the number/sizes of its allocations, + * to test the case where the user provides a temp allocator. + */ +class TempMemoryAllocator final : public MemoryAllocator { + public: + TempMemoryAllocator() : MemoryAllocator(0, nullptr) {} + + // The number of times allocate() has been called. + int number_of_allocations = 0; + + // The number of times reset() has been called. + int number_of_resets = 0; + + // The amount of memory currently allocated (should go to 0 when reset is + // called). + int currently_allocated_size = 0; + + // The total size of all allocations. + int total_allocated_size = 0; + + void* allocate(size_t size, ET_UNUSED size_t alignment = kDefaultAlignment) + override { + number_of_allocations += 1; + currently_allocated_size += size; + total_allocated_size += size; + // This is a simulation, we don't actually allocate memory. But we need to + // return a non-null pointer, so we return a bad, non-zero address that will + // crash if anyone tries to dereference it. + return (void*)1; + } + + void reset() override { + number_of_resets += 1; + currently_allocated_size = 0; + } +}; + +class KernelIntegrationTest : public ::testing::Test { + protected: + void SetUp() override { + executorch::runtime::runtime_init(); + + // Register the controllable kernel hook. + KernelControl::register_singleton(); + // Ensure that its state is clear. + KernelControl::singleton()->reset(); + // Provide the singleton to the tests. + control_ = KernelControl::singleton(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + + // Load the forward method. + mmm_ = std::make_unique( + kDefaultNonConstMemBytes, + kDefaultRuntimeMemBytes, + temp_allocator_.get()); + Result method = program_->load_method("forward", &mmm_->get()); + ASSERT_EQ(method.error(), Error::Ok); + method_ = std::make_unique(std::move(method.get())); + + // Set up its inputs. + auto inputs_cleanup = + executorch::extension::prepare_input_tensors(*method_); + ASSERT_EQ(inputs_cleanup.error(), Error::Ok); + inputs_cleanup_ = std::make_unique( + std::move(*inputs_cleanup)); + auto input_err = method_->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + } + + void TearDown() override { + inputs_cleanup_.reset(); + } + + private: + // Must outlive program_ + std::unique_ptr loader_; + + // Must outlive method_ + std::unique_ptr program_; + std::unique_ptr mmm_; + std::unique_ptr inputs_cleanup_; + + protected: + // An executable method that will call the kernel associated with control_. + // Its inputs will have been allocated and initialized. + std::unique_ptr method_; + + // The KernelControl associated with method_. + KernelControl* control_; + + // The temp memory allocator provided by the user. By default, none is + // provided. + std::unique_ptr temp_allocator_ = nullptr; +}; + +class KernelTempMemoryAllocatorIntegrationTest : public KernelIntegrationTest { + protected: + void SetUp() override { + // Create a temp allocator for the test before calling the parent SetUp. + temp_allocator_ = std::make_unique(); + KernelIntegrationTest::SetUp(); + } +}; + +TEST_F(KernelIntegrationTest, KernelHookIsCalled) { + // Demonstrate that the kernel hook is called in the default state. + EXPECT_EQ(control_->call_count, 0); + Error err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 1); + + // Calling it again bumps the count. + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 2); +} + +TEST_F(KernelIntegrationTest, FailurePropagates) { + // Tell the kernel to fail. + control_->call_context_fail = true; + + // We should see the error from the kernel. + control_->fail_value = Error::InvalidArgument; + Error err = method_->execute(); + EXPECT_EQ(err, Error::InvalidArgument); + EXPECT_EQ(control_->call_count, 1); + + // Have it fail with a different error to show that it's not a coincidence. + control_->fail_value = Error::MemoryAllocationFailed; + err = method_->execute(); + EXPECT_EQ(err, Error::MemoryAllocationFailed); + EXPECT_EQ(control_->call_count, 2); + + // Returning an Ok does not cause the execution to fail. + control_->fail_value = Error::Ok; + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 3); +} + +TEST_F(KernelIntegrationTest, DefaultPlatformMemoryAllocator) { + // Tell the kernel to allocate memory. Since no temp allocator is provided, + // this will allocate memory using the default platform memory allocator. + control_->allocate_temp_memory = true; + + control_->temp_memory_size = 4; + // This is not a simulation. This actually allocates memory, using the + // default platform memory allocator. + Error err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 1); + EXPECT_EQ(control_->total_allocated_size, 4); + + control_->temp_memory_size = 8; + // This is not a simulation. This actually allocates memory, using the + // default platform memory allocator. + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 2); + EXPECT_EQ(control_->total_allocated_size, 12); +} + +TEST_F(KernelTempMemoryAllocatorIntegrationTest, UsingTempMemoryAllocator) { + // In this test we provide a temp allocator to the method, and tell the kernel + // to allocate memory using it. We want to make sure that the kernel uses the + // temp allocator, and that the temp allocator is reset after the execution. + // Since we are testing that the kernel uses the temp allocator, and not the + // temp allocator itself, we don't need to test the actual allocation of + // memory. Therefore, we set simulate_temp_memory_allocation to true, so that + // the kernel will not actually allocate memory, but will instead simulate + // allocating memory. + // The provided TempMemoryAllocator, simulates allocating memory by increasing + // total_allocated_size and currently_allocated_size by the requested size. + // We simulate resetting the allocator by setting currently_allocated_size + // back to 0. + control_->simulate_temp_memory_allocation = true; + + control_->temp_memory_size = 4; + Error err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 1); + EXPECT_EQ(control_->total_allocated_size, 4); + EXPECT_EQ(temp_allocator_->number_of_allocations, 1); + EXPECT_EQ(temp_allocator_->total_allocated_size, 4); + // The temp allocator should have been reset after the execution and before + // method execution. + EXPECT_EQ(temp_allocator_->number_of_resets, 2); + EXPECT_EQ(temp_allocator_->currently_allocated_size, 0); + + control_->temp_memory_size = 8; + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 2); + EXPECT_EQ(control_->total_allocated_size, 12); + EXPECT_EQ(temp_allocator_->number_of_allocations, 2); + EXPECT_EQ(temp_allocator_->total_allocated_size, 12); + // The temp allocator should have been reset after the execution. + EXPECT_EQ(temp_allocator_->number_of_resets, 4); + EXPECT_EQ(temp_allocator_->currently_allocated_size, 0); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_resolution_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_resolution_test.cpp new file mode 100644 index 0000000..d3861ad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/kernel_resolution_test.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Kernel; +using executorch::runtime::KernelKey; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::register_kernel; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorMeta; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class KernelResolutionTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + } + + std::unique_ptr loader_; + std::unique_ptr program_; +}; + +/** + * Test if the program can initialize properly. + */ +TEST_F(KernelResolutionTest, InitExecutionPlanSuccess) { + // register kernel with fallback kernel key + Kernel kernel_1 = Kernel( + "aten::add.out", + {}, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + auto s1 = register_kernel(kernel_1); + EXPECT_EQ(s1, executorch::runtime::Error::Ok); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + auto method = program_->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); +} + +/** + * Test if we can resolve the kernel key correctly. + */ +TEST_F(KernelResolutionTest, ResolveKernelKeySuccess) { + // getting all these TensorMeta from args to this kernel_call in the program. + // particularly for aten::add.out: + // add.out(Tensor self, Tensor other, *, Scalar alpha=1, Tensor(a!) out) -> + // Tensor(a!) The arguments are: `self, other, out, out` (we repeat out + // argument in the program) Also since we traced using randn(2, 2), all the + // args are Float with dim order (0, 1) + + // Construct a kernel key with the following meta: + // executorch::aten::DimOrderType contiguous[] = {0, 1}; + // TensorMeta float_contiguous[] = { + // TensorMeta(ScalarType::Float, contiguous), + // TensorMeta(ScalarType::Float, contiguous), + // TensorMeta(ScalarType::Float, contiguous), + // TensorMeta(ScalarType::Float, contiguous)}; + KernelKey key = KernelKey("v1/6;0,1|6;0,1|6;0,1|6;0,1"); + Kernel kernel_1 = Kernel( + "aten::add.out", + key, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + auto s1 = register_kernel(kernel_1); + EXPECT_EQ(s1, executorch::runtime::Error::Ok); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + auto method = program_->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/managed_memory_manager.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/managed_memory_manager.h new file mode 100644 index 0000000..a010915 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/managed_memory_manager.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace executorch { +namespace runtime { +namespace testing { + +/** + * Creates and owns a MemoryManager and the allocators that it points to. Easier + * to manage than creating the allocators separately. + */ +class ManagedMemoryManager { + public: + ManagedMemoryManager( + size_t planned_memory_bytes, + size_t method_allocator_bytes, + MemoryAllocator* temp_allocator = nullptr) + : planned_memory_buffer_(new uint8_t[planned_memory_bytes]), + planned_memory_span_( + planned_memory_buffer_.get(), + planned_memory_bytes), + planned_memory_({&planned_memory_span_, 1}), + method_allocator_pool_(new uint8_t[method_allocator_bytes]), + method_allocator_(method_allocator_bytes, method_allocator_pool_.get()), + memory_manager_(&method_allocator_, &planned_memory_, temp_allocator) {} + + MemoryManager& get() { + return memory_manager_; + } + + private: + std::unique_ptr planned_memory_buffer_; + Span planned_memory_span_; + HierarchicalAllocator planned_memory_; + + std::unique_ptr method_allocator_pool_; + MemoryAllocator method_allocator_; + + MemoryManager memory_manager_; +}; + +} // namespace testing +} // namespace runtime +} // namespace executorch + +namespace torch { +namespace executor { +namespace testing { +// TODO(T197294990): Remove these deprecated aliases once all users have moved +// to the new `::executorch` namespaces. +using ::executorch::runtime::testing::ManagedMemoryManager; +} // namespace testing +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/memory_manager_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/memory_manager_test.cpp new file mode 100644 index 0000000..ecbb60f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/memory_manager_test.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::HierarchicalAllocator; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::MemoryManager; + +TEST(MemoryManagerTest, MinimalCtor) { + MemoryAllocator method_allocator(0, nullptr); + + MemoryManager mm(&method_allocator); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), nullptr); + EXPECT_EQ(mm.temp_allocator(), nullptr); +} + +TEST(MemoryManagerTest, CtorWithPlannedMemory) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + + MemoryManager mm(&method_allocator, &planned_memory); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), &planned_memory); + EXPECT_EQ(mm.temp_allocator(), nullptr); +} + +TEST(MemoryManagerTest, CtorWithPlannedMemoryAndTemp) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator temp_allocator(0, nullptr); + + MemoryManager mm(&method_allocator, &planned_memory, &temp_allocator); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), &planned_memory); + EXPECT_EQ(mm.temp_allocator(), &temp_allocator); +} + +TEST(MemoryManagerTest, DEPRECATEDCtor) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator temp_allocator(0, nullptr); + MemoryAllocator const_allocator(0, nullptr); + + // NOLINTNEXTLINE(facebook-hte-Deprecated) + MemoryManager mm( + /*constant_allocator=*/&const_allocator, + /*non_constant_allocator=*/&planned_memory, + /*runtime_allocator=*/&method_allocator, + /*temporary_allocator=*/&temp_allocator); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), &planned_memory); + EXPECT_EQ(mm.temp_allocator(), &temp_allocator); +} + +TEST(MemoryManagerTest, DeprecatedCtorWithSameAllocator) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator const_allocator(0, nullptr); + ET_EXPECT_DEATH( + MemoryManager( + /*constant_allocator=*/&const_allocator, + /*non_constant_allocator=*/&planned_memory, + /*runtime_allocator=*/&method_allocator, + /*temp_allocator=*/&method_allocator), + ""); +} + +TEST(MemoryManagerTest, CtorWithSameAllocator) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator const_allocator(0, nullptr); + ET_EXPECT_DEATH( + MemoryManager( + /*runtime_allocator=*/&method_allocator, + /*non_constant_allocator=*/&planned_memory, + /*temp_allocator=*/&method_allocator), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/merged_data_map_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/merged_data_map_test.cpp new file mode 100644 index 0000000..c9d1d51 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/merged_data_map_test.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::FileDataLoader; +using executorch::extension::FlatTensorDataMap; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::NamedDataMap; +using executorch::runtime::Result; +using executorch::runtime::TensorLayout; +using executorch::runtime::internal::MergedDataMap; + +class MergedDataMapTest : public ::testing::Test { + protected: + void load_flat_tensor_data_map(const char* path, const char* module_name) { + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + Result data_map = + FlatTensorDataMap::load(loaders_[module_name].get()); + EXPECT_EQ(data_map.error(), Error::Ok); + + data_maps_.insert( + {module_name, + std::make_unique(std::move(data_map.get()))}); + } + + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Load FlatTensor data maps. + // The eager addmul and linear models are defined at: + // //executorch/test/models/export_program.py + load_flat_tensor_data_map( + std::getenv("ET_MODULE_ADD_MUL_DATA_PATH"), "addmul"); + load_flat_tensor_data_map( + std::getenv("ET_MODULE_LINEAR_DATA_PATH"), "linear"); + } + + private: + // Must outlive data_maps_, but tests shouldn't need to touch it. + std::unordered_map> loaders_; + + protected: + std::unordered_map> data_maps_; +}; + +// Check that two tensor layouts are equivalent. +void check_tensor_layout(TensorLayout& layout1, TensorLayout& layout2) { + EXPECT_EQ(layout1.scalar_type(), layout2.scalar_type()); + EXPECT_EQ(layout1.nbytes(), layout2.nbytes()); + EXPECT_EQ(layout1.sizes().size(), layout2.sizes().size()); + for (size_t i = 0; i < layout1.sizes().size(); i++) { + EXPECT_EQ(layout1.sizes()[i], layout2.sizes()[i]); + } + EXPECT_EQ(layout1.dim_order().size(), layout2.dim_order().size()); + for (size_t i = 0; i < layout1.dim_order().size(); i++) { + EXPECT_EQ(layout1.dim_order()[i], layout2.dim_order()[i]); + } +} + +// Given that ndm is part of merged, check that all the API calls on ndm produce +// the same results as merged. +void compare_ndm_api_calls( + const NamedDataMap* ndm, + const NamedDataMap* merged) { + uint32_t num_keys = ndm->get_num_keys().get(); + for (uint32_t i = 0; i < num_keys; i++) { + auto key = ndm->get_key(i).get(); + + // Compare get_tensor_layout. + auto ndm_meta = ndm->get_tensor_layout(key).get(); + auto merged_meta = merged->get_tensor_layout(key).get(); + check_tensor_layout(ndm_meta, merged_meta); + + // Coompare get_data. + auto ndm_data = ndm->get_data(key); + auto merged_data = merged->get_data(key); + EXPECT_EQ(ndm_data.get().size(), merged_data.get().size()); + for (size_t j = 0; j < ndm_meta.nbytes(); j++) { + EXPECT_EQ( + ((uint8_t*)ndm_data.get().data())[j], + ((uint8_t*)merged_data.get().data())[j]); + } + ndm_data->Free(); + merged_data->Free(); + } +} + +TEST_F(MergedDataMapTest, LoadNullDataMap) { + Result merged_map = MergedDataMap::load(nullptr, nullptr); + EXPECT_EQ(merged_map.error(), Error::InvalidArgument); +} + +TEST_F(MergedDataMapTest, LoadMultipleDataMaps) { + Result merged_map = MergedDataMap::load( + data_maps_["addmul"].get(), data_maps_["linear"].get()); + EXPECT_EQ(merged_map.error(), Error::Ok); +} + +TEST_F(MergedDataMapTest, LoadDuplicateDataMapsFail) { + Result merged_map = MergedDataMap::load( + data_maps_["addmul"].get(), data_maps_["addmul"].get()); + EXPECT_EQ(merged_map.error(), Error::InvalidArgument); +} + +TEST_F(MergedDataMapTest, CheckDataMapContents) { + Result merged_map = MergedDataMap::load( + data_maps_["addmul"].get(), data_maps_["linear"].get()); + EXPECT_EQ(merged_map.error(), Error::Ok); + + // Num keys. + size_t addmul_num_keys = data_maps_["addmul"]->get_num_keys().get(); + size_t linear_num_keys = data_maps_["linear"]->get_num_keys().get(); + EXPECT_EQ( + merged_map->get_num_keys().get(), addmul_num_keys + linear_num_keys); + + // Load data into is not implemented for the merged data map. + void* memory_block = malloc(10); + ASSERT_EQ( + Error::NotImplemented, merged_map->load_data_into("a", memory_block, 10)); + free(memory_block); + + // API calls produce equivalent results. + compare_ndm_api_calls(data_maps_["addmul"].get(), &merged_map.get()); + compare_ndm_api_calls(data_maps_["linear"].get(), &merged_map.get()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_meta_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_meta_test.cpp new file mode 100644 index 0000000..e4ef2e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_meta_test.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::MethodMeta; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorInfo; +using torch::executor::util::FileDataLoader; + +namespace executorch { +namespace runtime { +namespace testing { +// Provides access to private TensorInfo methods. +class TensorInfoTestFriend final { + public: + ET_NODISCARD static TensorInfo get( + Span sizes, + Span dim_order, + executorch::aten::ScalarType scalar_type, + const bool is_memory_planned, + executorch::aten::string_view name) { + return TensorInfo::create( + Span(sizes.data(), sizes.size()), + Span(dim_order.data(), dim_order.size()), + scalar_type, + is_memory_planned, + name) + .get(); + } +}; +} // namespace testing +} // namespace runtime +} // namespace executorch + +class MethodMetaTest : public ::testing::Test { + protected: + void load_program(const char* path, const char* module_name) { + // Create a loader for the serialized program. + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + // Use it to load the program. + Result program = Program::load( + loaders_[module_name].get(), + Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + programs_.insert( + {module_name, std::make_unique(std::move(program.get()))}); + } + + void SetUp() override { + load_program(std::getenv("ET_MODULE_ADD_PATH"), "add"); + load_program(std::getenv("ET_MODULE_STATEFUL_PATH"), "stateful"); + } + + private: + // Must outlive program_, but tests shouldn't need to touch it. + std::unordered_map> loaders_; + + protected: + std::unordered_map> programs_; +}; + +namespace { + +// Check TensorInfo against hard coded values from AddModule. +void check_tensor(const TensorInfo& tensor_info) { + auto sizes = tensor_info.sizes(); + auto dim_order = tensor_info.dim_order(); + EXPECT_EQ(sizes.size(), 2); + EXPECT_EQ(sizes[0], 2); + EXPECT_EQ(sizes[1], 2); + EXPECT_EQ(tensor_info.scalar_type(), executorch::aten::ScalarType::Float); + EXPECT_EQ(dim_order.size(), 2); + EXPECT_EQ(dim_order[0], 0); + EXPECT_EQ(dim_order[1], 1); + EXPECT_EQ(tensor_info.is_memory_planned(), true); + EXPECT_EQ(tensor_info.nbytes(), 16); +} +} // namespace + +TEST_F(MethodMetaTest, MethodMetaApi) { + Result method_meta = programs_["add"]->method_meta("forward"); + ASSERT_EQ(method_meta.error(), Error::Ok); + + // Appropriate amount of inputs + EXPECT_EQ(method_meta->num_inputs(), 3); + + // Appropriate amount of outputs + EXPECT_EQ(method_meta->num_outputs(), 1); + + // Appropriate amount of planned buffers + EXPECT_EQ(method_meta->num_memory_planned_buffers(), 1); + EXPECT_EQ(method_meta->num_non_const_buffers(), 1); // Deprecated API + + // Appropriate size of planned buffer + EXPECT_EQ(method_meta->memory_planned_buffer_size(0).get(), 48); + EXPECT_EQ(method_meta->non_const_buffer_size(0).get(), 48); // Deprecated API + + // Invalid index Errors + EXPECT_EQ( + method_meta->memory_planned_buffer_size(1).error(), + Error::InvalidArgument); + EXPECT_EQ( + method_meta->non_const_buffer_size(1).error(), + Error::InvalidArgument); // Deprecated API + + // Number instructions in method is nonzero + EXPECT_NE(method_meta->num_instructions(), 0); + + // Missing method fails + EXPECT_EQ( + programs_["add"]->method_meta("not_a_method").error(), + Error::InvalidArgument); +} + +TEST_F(MethodMetaTest, TensorInfoApi) { + Result method_meta = programs_["add"]->method_meta("forward"); + ASSERT_EQ(method_meta.error(), Error::Ok); + + // Input 1 + Result in_1 = method_meta->input_tensor_meta(0); + ASSERT_TRUE(in_1.ok()); + check_tensor(in_1.get()); + + // Input 2 + Result in_2 = method_meta->input_tensor_meta(1); + ASSERT_TRUE(in_2.ok()); + check_tensor(in_2.get()); + + // Output 1 + Result out_1 = method_meta->output_tensor_meta(0); + ASSERT_TRUE(out_1.ok()); + check_tensor(out_1.get()); + + // Copyable + Result info = method_meta->input_tensor_meta(0); + TensorInfo info_copy_ctor(info.get()); + TensorInfo info_copy_assign(out_1.get()); + info_copy_assign = info.get(); + check_tensor(info_copy_ctor); + check_tensor(info_copy_assign); + + // Move-able + TensorInfo info_move_ctor(std::move(info.get())); + check_tensor(info_move_ctor); + + // Errors + EXPECT_EQ(method_meta->input_tensor_meta(3).error(), Error::InvalidArgument); + EXPECT_EQ(method_meta->input_tensor_meta(-1).error(), Error::InvalidArgument); + EXPECT_EQ(method_meta->output_tensor_meta(3).error(), Error::InvalidArgument); + EXPECT_EQ( + method_meta->output_tensor_meta(-1).error(), Error::InvalidArgument); +} + +TEST_F(MethodMetaTest, MethodMetaAttribute) { + Result method_meta = + programs_["stateful"]->method_meta("forward"); + ASSERT_EQ(method_meta.error(), Error::Ok); + + ASSERT_EQ(method_meta->num_attributes(), 1); + auto state = method_meta->attribute_tensor_meta(0); + ASSERT_TRUE(state.ok()); + + ASSERT_EQ(state->name(), "state"); + ASSERT_FALSE(state->is_memory_planned()); + + auto bad_access = method_meta->attribute_tensor_meta(1); + ASSERT_EQ(bad_access.error(), Error::InvalidArgument); +} + +TEST_F(MethodMetaTest, TensorInfoSizeOverflow) { + // Create sizes that will cause overflow when multiplied + std::vector overflow_sizes = { + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + }; + + // Create a minimal dim_order + std::vector dim_order = {0, 1, 2, 3}; + + // Create a TensorInfo with the overflow sizes and expect it to fail. + ET_EXPECT_DEATH( + executorch::runtime::testing::TensorInfoTestFriend::get( + Span(overflow_sizes.data(), overflow_sizes.size()), + Span(dim_order.data(), dim_order.size()), + executorch::aten::ScalarType::Float, + false, // is_memory_planned + executorch::aten::string_view{nullptr, 0}), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_test.cpp new file mode 100644 index 0000000..a60740f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/method_test.cpp @@ -0,0 +1,547 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::extension::FlatTensorDataMap; +using executorch::extension::prepare_input_tensors; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class MethodTest : public ::testing::Test { + protected: + void load_program(const char* path, const char* module_name) { + // Create a loader for the serialized program. + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + // Use it to load the program. + Result program = Program::load( + loaders_[module_name].get(), + Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + programs_.insert( + {module_name, std::make_unique(std::move(program.get()))}); + } + + void load_data_map(const char* path, const char* module_name) { + // Create a loader for the serialized data map. + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + Result data_map = + FlatTensorDataMap::load(loaders_[module_name].get()); + EXPECT_EQ(data_map.error(), Error::Ok); + + data_maps_.insert( + {module_name, + std::make_unique(std::move(data_map.get()))}); + } + + void SetUp() override { + executorch::runtime::runtime_init(); + + load_program(std::getenv("ET_MODULE_ADD_PATH"), "add"); + load_program(std::getenv("ET_MODULE_INDEX_PATH"), "index"); + load_program( + std::getenv("ET_MODULE_DYNAMIC_CAT_UNALLOCATED_IO_PATH"), "cat"); + load_program(std::getenv("ET_MODULE_ADD_MUL_PATH"), "add_mul"); + load_program(std::getenv("ET_MODULE_STATEFUL_PATH"), "stateful"); + load_program( + std::getenv("DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH"), + "linear_constant_buffer"); + + load_program( + std::getenv("ET_MODULE_ADD_MUL_PROGRAM_PATH"), "add_mul_program"); + load_data_map(std::getenv("ET_MODULE_ADD_MUL_DATA_PATH"), "add_mul_data"); + } + + private: + // Must outlive program_, but tests shouldn't need to touch it. + std::unordered_map> loaders_; + + protected: + std::unordered_map> programs_; + std::unordered_map> + data_maps_; +}; + +TEST_F(MethodTest, MoveTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set dummy inputs. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); + + // Move into a new Method. + Method new_method(std::move(method.get())); + + // Can't execute the old method. + err = method->execute(); + ASSERT_NE(err, Error::Ok); + + // Can execute the new method. + err = new_method.execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, GetInputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_inputs = method->inputs_size(); + ASSERT_GT(num_inputs, 0); + + // In-range inputs should succeed without aborting. + method->get_input(0); + method->get_input(num_inputs - 1); + + // Out-of-range inputs should abort. + ET_EXPECT_DEATH(method->get_input(num_inputs), ""); + ET_EXPECT_DEATH(method->get_input(num_inputs + 1), ""); +} + +TEST_F(MethodTest, MutableInputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_inputs = method->inputs_size(); + ASSERT_GT(num_inputs, 0); + + // In-range inputs should succeed without aborting. + method->mutable_input(0); + method->mutable_input(num_inputs - 1); + + // Out-of-range inputs should abort. + ET_EXPECT_DEATH(method->mutable_input(num_inputs), ""); + ET_EXPECT_DEATH(method->mutable_input(num_inputs + 1), ""); +} + +TEST_F(MethodTest, GetOutputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_outputs = method->outputs_size(); + ASSERT_GT(num_outputs, 0); + + // In-range outputs should succeed without aborting. + method->get_output(0); + method->get_output(num_outputs - 1); + + // Out-of-range outputs should abort. + ET_EXPECT_DEATH(method->get_output(num_outputs), ""); + ET_EXPECT_DEATH(method->get_output(num_outputs + 1), ""); +} + +TEST_F(MethodTest, MutableOutputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_outputs = method->outputs_size(); + ASSERT_GT(num_outputs, 0); + + // In-range outputs should succeed without aborting. + method->mutable_output(0); + method->mutable_output(num_outputs - 1); + + // Out-of-range outputs should abort. + ET_EXPECT_DEATH(method->mutable_output(num_outputs), ""); + ET_EXPECT_DEATH(method->mutable_output(num_outputs + 1), ""); +} + +TEST_F(MethodTest, SetPrimInputTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Can execute the method. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + + // The args to the method are x, y, alpha. x and y are tensors handled above + // alpha is a prim. + + // Traced prim input was '1.0' so 3.0 should error. + auto input_err = method->set_input(EValue(3.0), 2); + EXPECT_EQ(input_err, Error::InvalidArgument); + + // Traced prim input was '1.0' so '1.0' should be ok. + input_err = method->set_input(EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + Error err = method->execute(); + EXPECT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, MethodMetaTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto method_meta = method->method_meta(); + + EXPECT_EQ(method_meta.num_inputs(), method->inputs_size()); + EXPECT_EQ(method_meta.num_outputs(), method->outputs_size()); +} + +TEST_F(MethodTest, AliasedIOTest) { + // TODO(T163238401) + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["cat"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set up io. Input and Output should share the same memory. + constexpr int buffer_size = 16; + float buffer[buffer_size]; // Initial input is (2,4) we then cat a (1,4) to it + // twice for a final shape of (4,4) + for (int i = 0; i < buffer_size; ++i) { + buffer[i] = 0.f; + } + int32_t sizes[2] = {2, 4}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {4, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + buffer, + dim_order, + strides); + + auto input_err = + method->set_input(EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + auto output_err = method->set_output_data_ptr(buffer, sizeof(buffer), 0); + ASSERT_EQ(output_err, Error::Ok); + ASSERT_EQ(method->get_output(0).toTensor().const_data_ptr(), buffer); + + // Execute the method once. Cat a 1x4 to a 2x4. + auto execute_error = method->execute(); + ASSERT_EQ(execute_error, Error::Ok); + + auto output = method->get_output(0); + ASSERT_TRUE(output.isTensor()); + EXPECT_EQ(output.toTensor().sizes()[0], 3); + EXPECT_EQ(output.toTensor().sizes()[1], 4); + // Original input should be 0. + for (size_t i = 0; i < 2 * 4; i++) { + EXPECT_FLOAT_EQ(output.toTensor().const_data_ptr()[i], 0.f); + } + // Section that was cat on should be 1. + for (size_t i = 0; i < 1 * 4; i++) { + EXPECT_FLOAT_EQ( + output.toTensor().const_data_ptr()[(2 * 4) + i], 1.f); + } + + // Set the input again to update the size. + sizes[0] = output.toTensor().sizes()[0]; + executorch::aten::TensorImpl impl_2( + executorch::aten::ScalarType::Float, + 2, + sizes, + buffer, + dim_order, + strides); + input_err = method->set_input(EValue(executorch::aten::Tensor(&impl_2)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Execute the method again. Cat a 1x4 to a 3x4. + execute_error = method->execute(); + ASSERT_EQ(execute_error, Error::Ok); + + output = method->get_output(0); + EXPECT_EQ(output.toTensor().sizes()[0], 4); + EXPECT_EQ(output.toTensor().sizes()[1], 4); + // Original input should be 0. + for (size_t i = 0; i < 2 * 4; i++) { + EXPECT_FLOAT_EQ(output.toTensor().const_data_ptr()[i], 0.f); + } + // Previous section and the new one that were cat on should be 1. + for (size_t i = 0; i < 2 * 4; i++) { + EXPECT_FLOAT_EQ( + output.toTensor().const_data_ptr()[(2 * 4) + i], 1.f); + } +} + +TEST_F(MethodTest, ConstantSegmentTest) { + // Execute model with constants stored in segment. + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["add_mul"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, ConstantBufferTest) { + // Execute model with constants stored in the program flatbuffer. + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["linear_constant_buffer"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, ProgramDataSeparationTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add_mul_program"]->load_method( + "forward", &mmm.get(), nullptr, data_maps_["add_mul_data"].get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, MethodGetAttributeTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["stateful"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto res = method->get_attribute("state"); + ASSERT_TRUE(res.ok()); + // expect data to be empty + EXPECT_EQ(res->const_data_ptr(), nullptr); + + int32_t data = 0; + res->set_data(&data); + + // expect data to be set + EXPECT_EQ(res->const_data_ptr(), &data); + + // Set a dummy input. + int32_t sizes[1] = {1}; + uint8_t dim_order[1] = {0}; + int32_t strides[1] = {1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 1, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); + + // Expect the state to be incremented + EXPECT_EQ(res->const_data_ptr()[0], 1); +} + +TEST_F(MethodTest, InProgressInitialState) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + EXPECT_FALSE(method->in_progress()); +} + +TEST_F(MethodTest, InProgressDuringStepExecution) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["add_mul"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + + Error err = method->step(); + ASSERT_EQ(err, Error::Ok); + + EXPECT_TRUE(method->in_progress()); + + while (err != Error::EndOfMethod) { + err = method->step(); + ASSERT_TRUE(err == Error::Ok || err == Error::EndOfMethod); + } + + EXPECT_FALSE(method->in_progress()); +} + +TEST_F(MethodTest, ExecuteFailsWhenInProgress) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["add_mul"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + + Error err = method->step(); + ASSERT_EQ(err, Error::Ok); + ASSERT_TRUE(method->in_progress()); + + err = method->execute(); + EXPECT_EQ(err, Error::InvalidState); +} + +TEST_F(MethodTest, ExecuteSucceedsAfterReset) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + Error err = Error::Ok; + while (err != Error::EndOfMethod) { + err = method->step(); + ASSERT_TRUE(err == Error::Ok || err == Error::EndOfMethod); + } + + err = method->reset_execution(); + ASSERT_EQ(err, Error::Ok); + EXPECT_FALSE(method->in_progress()); + + err = method->execute(); + EXPECT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, ExecuteResetsOnError) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + Error err = method->execute(); + EXPECT_NE(err, Error::Ok); + + EXPECT_FALSE(method->in_progress()); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + err = method->execute(); + EXPECT_EQ(err, Error::Ok); +} + +/* + * TODO(T161163608): Test is disabled due to a resize bug in tensor_index_out of + * the portable op lib + +TEST_F(MethodTest, OptionalTensorListDeserialization) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, + kDefaultRuntimeMemBytes); Result method = + index_program_->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Can execute the method. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); + + EXPECT_EQ(method->inputs_size(), 1); + + auto outputs = method->get_output(0); + EXPECT_EQ(outputs.toTensor().dim(), 3); + EXPECT_EQ(outputs.toTensor().size(0), 5); + EXPECT_EQ(outputs.toTensor().size(1), 2); + EXPECT_EQ(outputs.toTensor().size(2), 10); +} +*/ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/program_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/program_test.cpp new file mode 100644 index 0000000..3afb71b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/program_test.cpp @@ -0,0 +1,595 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Program; +using executorch::runtime::Result; +using torch::executor::util::BufferDataLoader; +using torch::executor::util::FileDataLoader; + +// Verification level to use for tests not specifically focused on verification. +// Use the highest level to exercise it more. +constexpr Program::Verification kDefaultVerification = + Program::Verification::InternalConsistency; + +class ProgramTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Load the serialized ModuleAdd data. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + + // This file should always be compatible. + Result header = loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(header->data(), header->size()), + Program::HeaderStatus::CompatibleVersion); + + add_loader_ = std::make_unique(std::move(loader.get())); + + // Load the serialized ModuleMultiEntry data. + path = std::getenv("ET_MODULE_MULTI_ENTRY_PATH"); + Result multi_loader = FileDataLoader::from(path); + ASSERT_EQ(multi_loader.error(), Error::Ok); + + // This file should always be compatible. + Result multi_header = multi_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(multi_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(multi_header->data(), multi_header->size()), + Program::HeaderStatus::CompatibleVersion); + + multi_loader_ = + std::make_unique(std::move(multi_loader.get())); + } + + std::unique_ptr add_loader_; + std::unique_ptr multi_loader_; +}; + +namespace executorch { +namespace runtime { +namespace testing { +// Provides access to private Program methods. +class ProgramTestFriend final { + public: + ET_NODISCARD static Result LoadSegment( + const Program* program, + const DataLoader::SegmentInfo& segment_info) { + return program->LoadSegment(segment_info); + } + + ET_NODISCARD static Error load_mutable_subsegment_into( + const Program* program, + size_t mutable_data_segments_index, + size_t offset_index, + size_t size, + void* buffer) { + return program->load_mutable_subsegment_into( + mutable_data_segments_index, offset_index, size, buffer); + } + + const static executorch_flatbuffer::Program* GetInternalProgram( + const Program* program) { + return program->internal_program_; + } +}; +} // namespace testing +} // namespace runtime +} // namespace executorch + +using executorch::runtime::testing::ProgramTestFriend; + +TEST_F(ProgramTest, DataParsesWithMinimalVerification) { + // Parse the Program from the data. + Result program = + Program::load(add_loader_.get(), Program::Verification::Minimal); + + // Should have succeeded. + EXPECT_EQ(program.error(), Error::Ok); +} + +TEST_F(ProgramTest, DataParsesWithInternalConsistencyVerification) { + // Parse the Program from the data. + Result program = Program::load( + add_loader_.get(), Program::Verification::InternalConsistency); + + // Should have succeeded. + EXPECT_EQ(program.error(), Error::Ok); +} + +TEST_F(ProgramTest, BadMagicFailsToLoad) { + // Make a local copy of the data. + size_t data_len = add_loader_->size().get(); + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Corrupt the magic value. + EXPECT_EQ(data[4], 'E'); + data[4] = 'X'; + EXPECT_EQ(data[5], 'T'); + data[5] = 'Y'; + + // Wrap the modified data in a loader. + BufferDataLoader data_loader(data.get(), data_len); + + { + // Parse the Program from the data. Use minimal verification to show that + // even this catches the header problem. + Result program = + Program::load(&data_loader, Program::Verification::Minimal); + + // Should fail. + ASSERT_EQ(program.error(), Error::InvalidProgram); + } + + // Fix the data. + data[4] = 'E'; + data[5] = 'T'; + + { + // Parse the Program from the data again. + Result program = + Program::load(&data_loader, Program::Verification::Minimal); + + // Should now succeed. + ASSERT_EQ(program.error(), Error::Ok); + } +} + +TEST_F(ProgramTest, VerificationCatchesTruncation) { + // Get the program data. + size_t full_data_len = add_loader_->size().get(); + Result full_data = add_loader_->load( + /*offset=*/0, + full_data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(full_data.error(), Error::Ok); + + // Make a loader that only exposes half of the data. + BufferDataLoader half_data_loader(full_data->data(), full_data_len / 2); + + // Loading with full verification should fail. + Result program = Program::load( + &half_data_loader, Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::InvalidProgram); +} + +TEST_F(ProgramTest, VerificationCatchesCorruption) { + // Make a local copy of the data. + size_t data_len = add_loader_->size().get(); + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Corrupt the second half of the data. + std::memset(&data[data_len / 2], 0x55, data_len - (data_len / 2)); + + // Wrap the corrupted data in a loader. + BufferDataLoader data_loader(data.get(), data_len); + + // Should fail to parse corrupted data when using full verification. + Result program = + Program::load(&data_loader, Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::InvalidProgram); +} + +TEST_F(ProgramTest, UnalignedProgramDataFails) { + // Make a local copy of the data, on an odd alignment. + size_t data_len = add_loader_->size().get(); + auto data = std::make_unique(data_len + 1); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get() + 1, src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Wrap the offset data in a loader. + BufferDataLoader data_loader(data.get() + 1, data_len); + + // Should refuse to accept unaligned data. + Result program = + Program::load(&data_loader, Program::Verification::Minimal); + ASSERT_NE(program.error(), Error::Ok); +} + +TEST_F(ProgramTest, LoadSegmentWithNoSegments) { + // Load a program with no appended segments. + Result program = + Program::load(add_loader_.get(), kDefaultVerification); + EXPECT_EQ(program.error(), Error::Ok); + + // Loading a non-program segment should fail. + const auto segment_info = DataLoader::SegmentInfo( + DataLoader::SegmentInfo::Type::Backend, + /*segment_index=*/0, + "some-backend"); + Result segment = + ProgramTestFriend::LoadSegment(&program.get(), segment_info); + EXPECT_NE(segment.error(), Error::Ok); +} + +TEST_F(ProgramTest, ShortDataHeader) { + Result header = add_loader_->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(header.error(), Error::Ok); + + // Provide less than the required amount of data. + EXPECT_EQ( + Program::check_header(header->data(), Program::kMinHeadBytes - 1), + Program::HeaderStatus::ShortData); +} + +TEST_F(ProgramTest, IncompatibleHeader) { + // Make a local copy of the header. + size_t data_len = Program::kMinHeadBytes; + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Change the number part of the magic value to a different value. + EXPECT_EQ(data[4], 'E'); + EXPECT_EQ(data[5], 'T'); + EXPECT_TRUE(std::isdigit(data[6])) << "Not a digit: " << data[6]; + EXPECT_TRUE(std::isdigit(data[7])) << "Not a digit: " << data[7]; + + // Modify the tens digit. + if (data[6] == '9') { + data[6] = '0'; + } else { + data[6] += 1; + } + EXPECT_TRUE(std::isdigit(data[6])) << "Not a digit: " << data[6]; + + // Should count as present but incompatible. + EXPECT_EQ( + Program::check_header(data.get(), data_len), + Program::HeaderStatus::IncompatibleVersion); +} + +TEST_F(ProgramTest, HeaderNotPresent) { + // Make a local copy of the header. + size_t data_len = Program::kMinHeadBytes; + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Corrupt the magic value. + EXPECT_EQ(data[4], 'E'); + data[4] = 'X'; + EXPECT_EQ(data[5], 'T'); + data[5] = 'Y'; + + // The header is not present. + EXPECT_EQ( + Program::check_header(data.get(), data_len), + Program::HeaderStatus::NotPresent); +} + +TEST_F(ProgramTest, getMethods) { + // Parse the Program from the data. + Result program_res = + Program::load(multi_loader_.get(), kDefaultVerification); + EXPECT_EQ(program_res.error(), Error::Ok); + + Program program(std::move(program_res.get())); + + // Method calls should succeed without hitting ET_CHECK. + EXPECT_EQ(program.num_methods(), 2); + auto res = program.get_method_name(0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(strcmp(res.get(), "forward"), 0); + auto res2 = program.get_method_name(1); + EXPECT_TRUE(res2.ok()); + EXPECT_EQ(strcmp(res2.get(), "forward2"), 0); +} + +TEST_F(ProgramTest, GetNamedDataMap_Fail) { + Result program = + Program::load(add_loader_.get(), kDefaultVerification); + ASSERT_EQ(program.error(), Error::Ok); + + // Get the named data map. Expect to fail, as add.pte does not have any + // named data segments. + Result named_data_map = + program->get_named_data_map(); + EXPECT_EQ(named_data_map.error(), Error::NotFound); +} + +// Test that the deprecated Load method (capital 'L') still works. +TEST_F(ProgramTest, DEPRECATEDLoad) { + // Parse the Program from the data. + // NOLINTNEXTLINE(facebook-hte-Deprecated) + Result program_res = Program::Load(multi_loader_.get()); + EXPECT_EQ(program_res.error(), Error::Ok); +} + +TEST_F(ProgramTest, LoadConstantSegmentWithNoConstantSegment) { + Result program = + Program::load(add_loader_.get(), kDefaultVerification); + ASSERT_EQ(program.error(), Error::Ok); + + // Load constant segment data should fail. + const auto segment_info = DataLoader::SegmentInfo( + DataLoader::SegmentInfo::Type::Constant, + /*segment_index=*/0); + Result segment = + ProgramTestFriend::LoadSegment(&program.get(), segment_info); + EXPECT_NE(segment.error(), Error::Ok); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // The constant buffer should be empty. + EXPECT_EQ(flatbuffer_program->constant_buffer()->size(), 0); + + // Expect 1 constant segment, placeholder for non-const tensors. + EXPECT_EQ(flatbuffer_program->segments()->size(), 1); +} + +TEST_F(ProgramTest, LoadConstantSegment) { + // Load the serialized ModuleAddMul data, with constants in the segment. + const char* linear_path = std::getenv("ET_MODULE_ADD_MUL_PATH"); + Result linear_loader = FileDataLoader::from(linear_path); + ASSERT_EQ(linear_loader.error(), Error::Ok); + + // This file should always be compatible. + Result linear_header = linear_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(linear_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(linear_header->data(), linear_header->size()), + Program::HeaderStatus::CompatibleVersion); + + Result program = Program::load(&linear_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // Load constant segment data, which is currently always in segment index + // zero. + const auto segment_info = DataLoader::SegmentInfo( + DataLoader::SegmentInfo::Type::Constant, + /*segment_index=*/0); + Result segment = + ProgramTestFriend::LoadSegment(&program.get(), segment_info); + EXPECT_EQ(segment.error(), Error::Ok); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // Expect one segment containing the constants. + EXPECT_EQ(flatbuffer_program->segments()->size(), 1); + + // The constant buffer should be empty. + EXPECT_EQ(flatbuffer_program->constant_buffer()->size(), 0); + + // Check constant segment offsets. + EXPECT_EQ(flatbuffer_program->constant_segment()->segment_index(), 0); + EXPECT_GE(flatbuffer_program->constant_segment()->offsets()->size(), 1); +} + +TEST_F(ProgramTest, LoadConstantSegmentWhenConstantBufferExists) { + // Load the serialized ModuleAddMul data, with constants in the flatbuffer and + // no constants in the segment. + const char* linear_path = + std::getenv("DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH"); + Result linear_loader = FileDataLoader::from(linear_path); + ASSERT_EQ(linear_loader.error(), Error::Ok); + + // This file should always be compatible. + Result linear_header = linear_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(linear_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(linear_header->data(), linear_header->size()), + Program::HeaderStatus::CompatibleVersion); + + Result program = Program::load(&linear_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // Expect no segments. + EXPECT_EQ(flatbuffer_program->segments()->size(), 0); + + // The constant buffer should exist. + EXPECT_GE(flatbuffer_program->constant_buffer()->size(), 1); +} + +TEST_F(ProgramTest, LoadFromMutableSegment) { + // Load the serialized ModuleSimpleTrain data. + auto path = std::getenv("ET_MODULE_SIMPLE_TRAIN_PATH"); + Result training_loader = FileDataLoader::from(path); + ASSERT_EQ(training_loader.error(), Error::Ok); + + // This file should always be compatible. + Result training_header = training_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(training_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(training_header->data(), training_header->size()), + Program::HeaderStatus::CompatibleVersion); + + Result program = Program::load(&training_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // dummy buffers to load into + uint8_t buffer[1] = {0}; + uint8_t buffer2[1] = {0}; + + // Load some mutable segment data + Error err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 0, 1, 1, buffer); + EXPECT_EQ(err, Error::Ok); + + // Check that the data loaded correctly, and then mutate it + EXPECT_EQ(buffer[0], 232); // 232 comes from inspecting the file itself. The + // file is seeded so this value should be stable. + buffer[0] = 0; + + // Load the same mutable segment data from file into a different buffer. + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), + 0, // mutable_data_segments_index + 1, // offset_index + 1, // size + buffer2); + EXPECT_EQ(err, Error::Ok); + + // Check that new data loaded from the file does not reflect the change to + // buffer. + EXPECT_EQ(buffer2[0], 232); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // Expect 2 segments. 1 mutable segment and 1 constant segment. + EXPECT_EQ(flatbuffer_program->segments()->size(), 2); + + // Expect a mutable data segment. + EXPECT_EQ(flatbuffer_program->mutable_data_segments()->size(), 1); + + // Expect the 0 index to be reserved and the offsets for weight and bias of + // linear to be indices 1 and 2. + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->size(), + 3); + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->Get(0), + 0); + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->Get(1), + 0); + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->Get(2), + 36); + + // Loading beyond file should fail + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 0, 1, 500, buffer); + EXPECT_NE(err, Error::Ok); + + // Loading beyond offsets should fail + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 0, 500, 1, buffer); + EXPECT_NE(err, Error::Ok); + + // Loading beyond segments should fail + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 500, 1, 1, buffer); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(ProgramTest, LoadAndCheckPTESize) { + // Load the serialized ModuleAddMul data, with constants in the segment. + const char* linear_path = std::getenv("ET_MODULE_ADD_MUL_PATH"); + Result linear_loader = FileDataLoader::from(linear_path); + ASSERT_EQ(linear_loader.error(), Error::Ok); + Result program = Program::load(&linear_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // Create a truncated file. + Result truncated_file = linear_loader->load( + 0, 200, DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(truncated_file.error(), Error::Ok); + + BufferDataLoader truncated_loader = + BufferDataLoader(truncated_file->data(), 200); + Result truncated_program = Program::load(&truncated_loader); + ASSERT_EQ(truncated_program.error(), Error::InvalidProgram); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/pte_data_map_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/pte_data_map_test.cpp new file mode 100644 index 0000000..5b13191 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/pte_data_map_test.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::FileDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; +using executorch::runtime::internal::PteDataMap; + +class PteDataMapTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Create a sample Program with only named_data and segments. Technically + // not a valid Program; only used to test the PteDataMap. + // Create named data. + std::array, 4> + named_data_arr = { + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key0", /*segment_index=*/0), + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key1", /*segment_index=*/1), + // Note: key2 points to the same segment as key0. + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key2", /*segment_index=*/0), + // This is invalid, as segment_index=10 is out of range when the + // number of segments is 2. + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key_invalid", /*segment_index=*/10), + }; + const auto named_data = + builder_.CreateVector(named_data_arr.data(), named_data_arr.size()); + + // Create segments. + std::array, 2> + segment_arr = {// @lint-ignore CLANGTIDY facebook-hte-BadArgumentComment + executorch_flatbuffer::CreateDataSegment( + builder_, /*offset=*/0, /*size=*/kSegmentSizes[0]), + // @lint-ignore CLANGTIDY facebook-hte-BadArgumentComment + executorch_flatbuffer::CreateDataSegment( + builder_, + /*offset=*/kSegmentAlignment * 2, + /*size=*/kSegmentSizes[1])}; + const auto segments = + builder_.CreateVector(segment_arr.data(), segment_arr.size()); + + // Create Program. + const auto program = executorch_flatbuffer::CreateProgram( + builder_, 0, 0, 0, 0, segments, 0, 0, named_data); + + builder_.Finish(program); + program_ = executorch_flatbuffer::GetProgram(builder_.GetBufferPointer()); + + // Create sample segment data. + for (int i = 0; i < kSegmentSizes[0]; i++) { + sample_data_[i] = 1; + } + for (int i = kSegmentOffsets[1]; i < kSegmentOffsets[1] + kSegmentSizes[1]; + i++) { + sample_data_[i] = 2; + } + TempFile tf(sample_data_.data(), sizeof(sample_data_)); + + // Wrap the sample data in a loader. + Result loader = + FileDataLoader::from(tf.path().c_str(), kSegmentAlignment); + ASSERT_EQ(loader.error(), Error::Ok); + data_map_loader_ = + std::make_unique(std::move(loader.get())); + } + + // Program builder constants. + static constexpr int kSegmentAlignment = 16; + static constexpr std::array kSegmentSizes{17, 8}; + static constexpr std::array kSegmentOffsets{0, kSegmentAlignment * 2}; + std::array sample_data_; + + // Program builder. + flatbuffers::FlatBufferBuilder builder_; + const executorch_flatbuffer::Program* program_; + + // Data loader for the sample data. + std::unique_ptr data_map_loader_; +}; + +TEST_F(PteDataMapTest, Load) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); +} + +TEST_F(PteDataMapTest, LoadFail) { + Result data_map = PteDataMap::create( + /*loader=*/nullptr, + /*segment_base_offset=*/0, + program_->named_data(), + program_->segments()); + EXPECT_EQ(data_map.error(), Error::InvalidArgument); +} + +TEST_F(PteDataMapTest, UnimplementedMethods) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ; + + // Check get_tensor_layout is not implemented. + auto result = data_map->get_tensor_layout("sample_key"); + EXPECT_EQ(result.error(), Error::NotImplemented); + + // Check load_data_into is not implemented. + auto err = data_map->load_data_into("sample_key", nullptr, 0); + EXPECT_EQ(err, Error::NotImplemented); +} + +TEST_F(PteDataMapTest, Keys) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + // Check get_num_keys. + auto num_keys = data_map->get_num_keys(); + EXPECT_EQ(num_keys.error(), Error::Ok); + EXPECT_EQ(num_keys.get(), 4); + + // Check get_key_at. + auto key0 = data_map->get_key(0); + EXPECT_EQ(strcmp(key0.get(), "key0"), 0); + auto key1 = data_map->get_key(1); + EXPECT_EQ(strcmp(key1.get(), "key1"), 0); + auto key2 = data_map->get_key(2); + EXPECT_EQ(strcmp(key2.get(), "key2"), 0); + + // This key is invalid because it points to a segment_index=10, which is out + // of range for this example with segment size=2. + // Note: practically, a PTE should not have invalid keys. + auto key_invalid = data_map->get_key(3); + EXPECT_EQ(strcmp(key_invalid.get(), "key_invalid"), 0); + + // Returns an error on non-existent key. + auto nonexistent_key = data_map->get_key(10); + EXPECT_EQ(nonexistent_key.error(), Error::InvalidArgument); +} + +TEST_F(PteDataMapTest, GetData) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + Result data0 = data_map->get_data("key0"); + EXPECT_EQ(data0.error(), Error::Ok); + EXPECT_EQ(data0.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data0.get().data(), sample_data_.data(), data0.get().size()), 0); + + Result data1 = data_map->get_data("key1"); + EXPECT_EQ(data1.error(), Error::Ok); + EXPECT_EQ(data1.get().size(), kSegmentSizes[1]); + EXPECT_EQ( + memcmp( + data1.get().data(), + sample_data_.data() + kSegmentOffsets[1], + data1.get().size()), + 0); + + Result data2 = data_map->get_data("key2"); + EXPECT_EQ(data2.error(), Error::Ok); + // Expect the same values as data0, as key0 and key2 point to the same + // segment. + EXPECT_EQ(data2.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data2.get().data(), sample_data_.data(), data2.get().size()), 0); + + // Free data. + data0->Free(); + data1->Free(); + data2->Free(); + + // Returns an error, as key_invalid contains segment_index=10, which + // is out of range for segments.size()=2. + Result data_invalid = data_map->get_data("key_invalid"); + EXPECT_EQ(data_invalid.error(), Error::InvalidArgument); + + // Returns an error on nonexistent key. + Result data_nonexistent = + data_map->get_data("nonexistent_key"); + EXPECT_EQ(data_nonexistent.error(), Error::NotFound); +} + +TEST_F(PteDataMapTest, FreeAndReload) { + // Load a key, free it, and then load it again, and ensure that the + // core data map can return a new FreeableBuffer with the same data. + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + // Load data0. + Result data0 = data_map->get_data("key0"); + EXPECT_EQ(data0.error(), Error::Ok); + EXPECT_EQ(data0.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data0.get().data(), sample_data_.data(), data0.get().size()), 0); + data0->Free(); + + // Reload data0, ensure that the core data map can return a new + // FreeableBuffer with the same data. + Result data0_reload = data_map->get_data("key0"); + EXPECT_EQ(data0_reload.error(), Error::Ok); + EXPECT_EQ(data0_reload.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp( + data0_reload.get().data(), + sample_data_.data(), + data0_reload.get().size()), + 0); + data0_reload->Free(); +} + +TEST_F(PteDataMapTest, ReloadAndFree) { + // Load the same key multiple times, and then free one and ensure that the + // data in the other is still valid. + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + // Load data0. + Result data0 = data_map->get_data("key0"); + EXPECT_EQ(data0.error(), Error::Ok); + EXPECT_EQ(data0.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data0.get().data(), sample_data_.data(), data0.get().size()), 0); + + // Reload data0. + Result data0_reload = data_map->get_data("key0"); + EXPECT_EQ(data0_reload.error(), Error::Ok); + EXPECT_EQ(data0_reload.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp( + data0_reload.get().data(), + sample_data_.data(), + data0_reload.get().size()), + 0); + + // Free data0 and check that data0_reload is still valid. + data0->Free(); + EXPECT_EQ(data0_reload.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp( + data0_reload.get().data(), + sample_data_.data(), + data0_reload.get().size()), + 0); + + // Free data_reload0. + data0_reload->Free(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/targets.bzl new file mode 100644 index 0000000..0fac69b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/targets.bzl @@ -0,0 +1,300 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(is_fbcode = False): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "test_backend_compiler_lib" + aten_suffix, + srcs = [ + "test_backend_compiler_lib.cpp", + ], + visibility = [ + "//executorch/exir/backend/test/...", + "//executorch/runtime/backend/...", + "//executorch/extension/pybindings/...", + "//executorch/devtools/fb/runners/...", + "//executorch/test/...", + "//executorch/examples/...", + ], + # registration of backends is done through a static global + compiler_flags = ["-Wno-global-constructors"], + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + "//executorch/runtime/backend:interface" + aten_suffix, + ], + # TestBackendCompilerLib.cpp needs to compile with executor as whole + # @lint-ignore BUCKLINT: Avoid `link_whole=True` (https://fburl.com/avoid-link-whole) + link_whole = True, + ) + + runtime.cxx_library( + name = "test_backend_with_delegate_mapping" + aten_suffix, + srcs = [ + "test_backend_with_delegate_mapping.cpp", + ], + visibility = [ + "//executorch/exir/backend/test/...", + "//executorch/runtime/backend/...", + "//executorch/extension/pybindings/...", + "//executorch/devtools/fb/runners/...", + "//executorch/test/...", + "//executorch/examples/...", + ], + # registration of backends is done through a static global + compiler_flags = ["-Wno-global-constructors"], + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + "//executorch/runtime/backend:interface" + aten_suffix, + ], + # TestBackendCompilerLib.cpp needs to compile with executor as whole + # @lint-ignore BUCKLINT: Avoid `link_whole=True` (https://fburl.com/avoid-link-whole) + link_whole = True, + ) + + runtime.cxx_test( + name = "executor_test" + aten_suffix, + srcs = [ + "executor_test.cpp", + ], + deps = [ + "//executorch/extension/pytree:pytree", + "//executorch/kernels/portable:generated_lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/testing_util:tensor_util" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + "//executorch/runtime/kernel:operator_registry" + aten_suffix, + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_library( + name = "managed_memory_manager", + srcs = [], + exported_headers = [ + "managed_memory_manager.h", + ], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/executor:memory_manager", + ], + ) + + runtime.cxx_test( + name = "pte_data_map_test", + srcs = [ + "pte_data_map_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/testing_util:temp_file", + "//executorch/runtime/executor:pte_data_map", + "//executorch/schema:program", + ], + ) + + # TODO(dbort): Find a way to make these run for ANDROID/APPLE in xplat. The + # android and ios test determinators don't like the reference to the model + # file in fbcode. See https://fburl.com/9esapdmd + if not runtime.is_oss and is_fbcode: + modules_env = { + # Deprecated model that still works with ExecuTorch runtime. + "DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH": "$(location fbcode//executorch/test/models/deprecated:ModuleLinear-no-constant-segment.pte)", + # The tests use this var to find the program file to load. This uses + # an fbcode target path because the authoring/export tools + # intentionally don't work in xplat (since they're host-only tools). + "ET_MODULE_ADD_HALF_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAddHalf.pte])", + "ET_MODULE_ADD_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAdd.pte])", + "ET_MODULE_DYNAMIC_CAT_UNALLOCATED_IO_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleDynamicCatUnallocatedIO.pte])", + "ET_MODULE_INDEX_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleIndex.pte])", + "ET_MODULE_ADD_MUL_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAddMul.pte])", + "ET_MODULE_MULTI_ENTRY_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleMultipleEntry.pte])", + "ET_MODULE_SIMPLE_TRAIN_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleSimpleTrain.pte])", + "ET_MODULE_STATEFUL_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleStateful.pte])", + "ET_MODULE_ADD_MUL_PROGRAM_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleAddMul.pte])", + "ET_MODULE_ADD_MUL_DATA_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleAddMul.ptd])", + "ET_MODULE_LINEAR_DATA_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleLinear.ptd])", + } + + runtime.cxx_test( + name = "allocation_failure_stress_test", + srcs = [ + "allocation_failure_stress_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/kernels/portable:generated_lib", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/runner_util:inputs", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "merged_data_map_test", + srcs = [ + "merged_data_map_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/flat_tensor:flat_tensor_data_map", + "//executorch/runtime/executor:merged_data_map", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "method_test", + srcs = [ + "method_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:merged_data_map", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/flat_tensor:flat_tensor_data_map", + "//executorch/extension/runner_util:inputs", + "//executorch/kernels/portable:generated_lib", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "method_meta_test", + srcs = [ + "method_meta_test.cpp", + ], + deps = [ + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "program_test", + srcs = [ + "program_test.cpp", + ], + deps = [ + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:buffer_data_loader", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/schema:program", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "kernel_resolution_test", + srcs = [ + "kernel_resolution_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/runtime/kernel:operator_registry", + "//executorch/extension/data_loader:file_data_loader", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "kernel_integration_test", + srcs = [ + "kernel_integration_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/runner_util:inputs", + "//executorch/runtime/core:core", + "//executorch/runtime/executor:program", + "//executorch/runtime/kernel:kernel_runtime_context", + "//executorch/runtime/kernel:operator_registry", + "//executorch/runtime/platform:platform", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "backend_integration_test", + srcs = [ + "backend_integration_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/backend:interface", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:buffer_data_loader", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/runner_util:inputs", + ], + env = { + # The tests use these vars to find the program files to load. + # Uses an fbcode target path because the authoring/export tools + # intentionally don't work in xplat (since they're host-only + # tools). + "ET_MODULE_ADD_MUL_NOSEGMENTS_DA1024_PATH": "$(location fbcode//executorch/test/models:exported_delegated_add_mul[ModuleAddMul-nosegments-da1024.pte])", + "ET_MODULE_ADD_MUL_NOSEGMENTS_PATH": "$(location fbcode//executorch/test/models:exported_delegated_add_mul[ModuleAddMul-nosegments.pte])", + "ET_MODULE_ADD_MUL_DELEGATED_PATH": "$(location fbcode//executorch/test/models:exported_delegated_add_mul[ModuleAddMul.pte])", + }, + ) + + runtime.cxx_test( + name = "backend_data_separation_test", + srcs = [ + "backend_data_separation_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/exir/backend/test/demos/rpc:executor_backend", + "//executorch/exir/backend/test/demos/rpc:executor_backend_register", + "//executorch/extension/flat_tensor:flat_tensor_data_map", + ], + env = { + # The tests use these vars to find the program files to load. + # Uses an fbcode target path because the authoring/export tools + # intentionally don't work in xplat (since they're host-only + # tools). + "ET_MODULE_LINEAR_DELEGATE_PROGRAM_PATH": "$(location fbcode//executorch/test/models:exported_executor_backend_program_and_data[ModuleLinear-e.pte])", + "ET_MODULE_LINEAR_DATA_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleLinear.ptd])", + }, + ) + runtime.cxx_test( + name = "memory_manager_test", + srcs = [ + "memory_manager_test.cpp", + ], + deps = [ + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/executor:memory_manager", + ], + ) + + runtime.cxx_test( + name = "tensor_parser_test", + srcs = [ + "tensor_parser_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/kernels/portable:generated_lib", + "//executorch/schema:program", + ], + env = modules_env, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/tensor_parser_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/tensor_parser_test.cpp new file mode 100644 index 0000000..b193ab2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/tensor_parser_test.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::deserialization::parseTensor; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class TensorParserTest : public ::testing::Test { + protected: + void SetUp() override { + // Load the serialized ModuleAdd data. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result float_loader = FileDataLoader::from(path); + ASSERT_EQ(float_loader.error(), Error::Ok); + float_loader_ = + std::make_unique(std::move(float_loader.get())); + + // Load the serialized ModuleAddHalf data. + const char* half_path = std::getenv("ET_MODULE_ADD_HALF_PATH"); + Result half_loader = FileDataLoader::from(half_path); + ASSERT_EQ(half_loader.error(), Error::Ok); + half_loader_ = + std::make_unique(std::move(half_loader.get())); + } + + std::unique_ptr float_loader_; + std::unique_ptr half_loader_; +}; + +namespace executorch { +namespace runtime { +namespace testing { +// Provides access to private Program methods. +class ProgramTestFriend final { + public: + const static executorch_flatbuffer::Program* GetInternalProgram( + const Program* program) { + return program->internal_program_; + } +}; +} // namespace testing +} // namespace runtime +} // namespace executorch + +using executorch::runtime::testing::ProgramTestFriend; + +void test_module_add( + std::unique_ptr& loader, + ScalarType scalar_type, + int type_size) { + Result program = + Program::load(loader.get(), Program::Verification::Minimal); + EXPECT_EQ(program.error(), Error::Ok); + + const Program* program_ = &program.get(); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + const executorch_flatbuffer::Program* internal_program = + ProgramTestFriend::GetInternalProgram(program_); + executorch_flatbuffer::ExecutionPlan* execution_plan = + internal_program->execution_plan()->GetMutableObject(0); + auto flatbuffer_values = execution_plan->values(); + + int tensor_count = 0; + int double_count = 0; + for (size_t i = 0; i < flatbuffer_values->size(); ++i) { + auto serialization_value = flatbuffer_values->Get(i); + if (serialization_value->val_type() == + executorch_flatbuffer::KernelTypes::Tensor) { + tensor_count++; + Result tensor = parseTensor( + program_, &mmm.get(), serialization_value->val_as_Tensor()); + Tensor t = tensor.get(); + ASSERT_EQ(scalar_type, t.scalar_type()); + ASSERT_EQ(2, t.dim()); // [2, 2] + ASSERT_EQ(4, t.numel()); + ASSERT_EQ(type_size * t.numel(), t.nbytes()); + } else if ( + serialization_value->val_type() == + executorch_flatbuffer::KernelTypes::Double) { + double_count++; + ASSERT_EQ(1.0, serialization_value->val_as_Double()->double_val()); + } + } + ASSERT_EQ(3, tensor_count); // input x2, output + ASSERT_EQ(2, double_count); // alpha x2 +} + +TEST_F(TensorParserTest, TestModuleAddFloat) { + test_module_add(float_loader_, ScalarType::Float, sizeof(float)); +} + +TEST_F(TensorParserTest, TestModuleAddHalf) { + test_module_add( + half_loader_, ScalarType::Half, sizeof(executorch::aten::Half)); +} + +TEST_F(TensorParserTest, TestMutableState) { + // Load the serialized ModuleSimpleTrain data. + const char* path = std::getenv("ET_MODULE_SIMPLE_TRAIN_PATH"); + Result train_loader = FileDataLoader::from(path); + ASSERT_EQ(train_loader.error(), Error::Ok); + + Result program = + Program::load(&train_loader.get(), Program::Verification::Minimal); + EXPECT_EQ(program.error(), Error::Ok); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + ManagedMemoryManager mmm_copy( + kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + const executorch_flatbuffer::Program* internal_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + executorch_flatbuffer::ExecutionPlan* execution_plan = + internal_program->execution_plan()->GetMutableObject(0); + auto flatbuffer_values = execution_plan->values(); + + size_t num_mutable_tensors = 0; + for (size_t i = 0; i < flatbuffer_values->size(); ++i) { + auto serialization_value = flatbuffer_values->Get(i); + if (serialization_value->val_type() == + executorch_flatbuffer::KernelTypes::Tensor && + serialization_value->val_as_Tensor()->allocation_info() != nullptr && + serialization_value->val_as_Tensor()->data_buffer_idx() > 0) { + num_mutable_tensors++; + Result tensor = parseTensor( + &program.get(), &mmm.get(), serialization_value->val_as_Tensor()); + torch::executor::Tensor t = tensor.get(); + float loaded_value = t.const_data_ptr()[0]; + ASSERT_NE(nullptr, t.const_data_ptr()); + ASSERT_NE(t.mutable_data_ptr()[0], 0.5); + t.mutable_data_ptr()[0] = 0.5; + ASSERT_EQ( + t.mutable_data_ptr()[0], + 0.5); // 0.5 can be represented perfectly by float so EQ and NE work + // fine here. Any power of 2 rational can be perfectly + // represented. See dyadic rationals for more info. + + // Load the same tensor using the same mem manager and show the value is + // updated again. + Result tensor1_alias = parseTensor( + &program.get(), &mmm.get(), serialization_value->val_as_Tensor()); + torch::executor::Tensor t2 = tensor.get(); + ASSERT_NE(t2.mutable_data_ptr()[0], 0.5); + + // Show the tensors are equivalent + ASSERT_EQ(t.const_data_ptr(), t2.const_data_ptr()); + // Set mutable tensor value back to 0.5 since it got overwritten by second + // parse. + t.mutable_data_ptr()[0] = 0.5; + + // Load the same tensor using a different mem manager and show the value + // is not the same as t. + Result tensor_new = parseTensor( + &program.get(), + &mmm_copy.get(), + serialization_value->val_as_Tensor()); + torch::executor::Tensor t3 = tensor_new.get(); + ASSERT_NE(t3.mutable_data_ptr()[0], 0.5); + ASSERT_NE(t3.const_data_ptr(), t.const_data_ptr()); + ASSERT_EQ(loaded_value, t3.const_data_ptr()[0]); + } + } + ASSERT_EQ(num_mutable_tensors, 2); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_compiler_lib.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_compiler_lib.cpp new file mode 100644 index 0000000..8ad48e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_compiler_lib.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include /* strtol */ + +using executorch::ET_RUNTIME_NAMESPACE::Backend; +using executorch::ET_RUNTIME_NAMESPACE::BackendExecutionContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInitContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInterface; +using executorch::ET_RUNTIME_NAMESPACE::CompileSpec; +using executorch::ET_RUNTIME_NAMESPACE::DelegateHandle; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +struct DemoOp { + const char* name; + long int numel; + const char* dtype; + long int debug_handle; +}; + +struct DemoOpList { + DemoOp* ops; + size_t numops; +}; + +class BackendWithCompiler final : public BackendInterface { + int max_shape = 4; + + public: + ~BackendWithCompiler() override = default; + + bool is_available() const override { + return true; + } + + // The delegate blob schema will be a list of instruction: + // {op: {str}, numel: {long}, dtype: {type}}n + // Instruction will be separated by #, for example: + // 'op:demo::mul.Tensor, numel:4, dtype:torch.float322\ + // #op:demo::add.Tensor, numel:4, dtype:torch.float324#' + void parse_delegate(const char* str, const char* sub, DemoOp* op_list) const { + const char* kOpLiteral = "op:"; + const char* kNumelLiteral = "numel:"; + const char* kDtypeliteral = "dtype:"; + const char* kDebugHandleLiteral = ""; + + const char* kComma = ","; + + int cnt = 0; + const char* left = str; + const char* right; + + // iter 0: + // op:demo::sin.default, numel:1, dtype:torch.float321# + // |<--left right-->| + // iter 1: + // op:demo::add.Tensor, numel:4, dtype:torch.float324# + // |<--left right-->| + while ((right = strstr(left, sub))) { + // Get operator name + const char* op_start = strstr(left, kOpLiteral) + strlen(kOpLiteral); + const char* op_end = strstr(op_start, kComma); + + op_list[cnt].name = op_start; + + // Get numel + const char* numel_start = + strstr(op_end, kNumelLiteral) + strlen(kNumelLiteral); + char* numel_end = const_cast(strstr(numel_start, kComma)); + op_list[cnt].numel = strtol(numel_start, &numel_end, 10); + + // Get dtype + const char* dtype_start = + strstr(numel_end, kDtypeliteral) + strlen(kDtypeliteral); + const char* dtype_end = strstr(dtype_start, kDebugHandleLiteral); + op_list[cnt].dtype = dtype_start; + + // Get debug handle + const char* debug_handle_start = + strstr(dtype_end, kDebugHandleLiteral) + strlen(kDebugHandleLiteral); + char* debug_end = const_cast(strstr(debug_handle_start, kComma)); + op_list[cnt].debug_handle = strtol(debug_handle_start, &debug_end, 10); + + // Move left pointer to the start of next instruction + left = right + 1; + cnt++; + } + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + MemoryAllocator* runtime_allocator = context.get_runtime_allocator(); + int shape = *(int*)(compile_specs.at(0).value.buffer); + ET_CHECK_OR_RETURN_ERROR( + shape <= max_shape, + InvalidArgument, + "The input number is %d and it's larger than the max number %d " + "supported by this backend.", + shape, + max_shape); + + const char* kSignLiteral = "#"; + // The first number is the number of total instruction + const char* start = static_cast(processed->data()); + + const char* kVersion = "version:"; + const long int kRuntimeVersion = 0; + char* version_start = + const_cast(strstr(start, kVersion)) + strlen(kVersion); + char* version_end; + char* instruction_set_start = + const_cast(strstr(start, kSignLiteral)); + + long int version = strtol(version_start, &version_end, 10); + ET_CHECK_OR_RETURN_ERROR( + version == kRuntimeVersion, + DelegateInvalidCompatibility, + "The version of BackendWithCompiler runtime is %ld, but received an incompatible version %ld instead.", + kRuntimeVersion, + version); + char* instruction_number_end; + long int instruction_number = strtol(start, &instruction_number_end, 10); + + ET_CHECK_OR_RETURN_ERROR( + instruction_number >= 0, + InvalidArgument, + "Instruction count must be non-negative: %ld", + instruction_number); + + auto op_list = runtime_allocator->allocateInstance(); + if (op_list == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->ops = runtime_allocator->allocateList(instruction_number); + if (op_list->ops == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->numops = static_cast(instruction_number); + + parse_delegate(instruction_set_start + 1, kSignLiteral, op_list->ops); + + // Can't call `processed->Free()` because op_list points into it. + + return op_list; + } + + // Function that actually executes the model in the backend. Here there is + // nothing to dispatch to, so the backend is implemented locally within + // execute and it only supports add, subtract, and constant. In a non toy + // backend you can imagine how this function could be used to actually + // dispatch the inputs to the relevant backend/device. + Error execute( + ET_UNUSED BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + EXECUTORCH_SCOPE_PROF("BackendWithCompiler::execute"); + + // example: [('prim::Constant#1', 14), ('aten::add', 15)] + auto op_list = static_cast(handle); + + const char* kDemoAdd = "demo::aten.add.Tensor"; + const char* kDemoMul = "demo::aten.mm.default"; + const char* kDemoSin = "demo::aten.sin.default"; + const char* kTorchFloat32 = "torch.float32"; + + for (size_t index = 0; index < op_list->numops; index++) { + auto instruction = op_list->ops[index]; + ET_CHECK_OR_RETURN_ERROR( + strncmp(instruction.dtype, kTorchFloat32, strlen(kTorchFloat32)) == 0, + NotSupported, + "BackendWithCompiler only support float and doesn't support %s, " + "debug handle is: %ld", + instruction.dtype, + instruction.debug_handle); + if (strncmp(instruction.name, kDemoAdd, strlen(kDemoAdd)) == 0) { + // z = z + b + const float* b_ptr = args[2]->toTensor().const_data_ptr(); + float* z_ptr = args[3]->toTensor().mutable_data_ptr(); + for (size_t j = 0; j < instruction.numel; j++) { + z_ptr[j] = b_ptr[j] + z_ptr[j]; + } + } else if (strncmp(instruction.name, kDemoMul, strlen(kDemoMul)) == 0) { + ET_CHECK_OR_RETURN_ERROR( + instruction.numel == 4, + NotSupported, + "BackendWithCompiler only support 2 x 2 matrix multiplication, " + "debug handle is %ld", + instruction.debug_handle); + // z = a * x + const float* a_ptr = args[0]->toTensor().const_data_ptr(); + const float* x_ptr = args[1]->toTensor().const_data_ptr(); + float* z_ptr = args[3]->toTensor().mutable_data_ptr(); + + z_ptr[0] = a_ptr[0] * x_ptr[0] + a_ptr[1] * x_ptr[2]; + z_ptr[1] = a_ptr[0] * x_ptr[1] + a_ptr[1] * x_ptr[3]; + z_ptr[2] = a_ptr[2] * x_ptr[0] + a_ptr[3] * x_ptr[2]; + z_ptr[3] = a_ptr[2] * x_ptr[1] + a_ptr[3] * x_ptr[3]; + } else if (strncmp(instruction.name, kDemoSin, strlen(kDemoSin)) == 0) { + const float* x_ptr = args[0]->toTensor().const_data_ptr(); + float* y_ptr = args[1]->toTensor().mutable_data_ptr(); + // Taylor series: an approximation of sin x around the point x = 0 + // sin(x) = x - x^3 / 3! + x^5 / 5! - x^7 / 7! ... + // Use the first two items as proof of concept + for (size_t j = 0; j < instruction.numel; j++) { + y_ptr[j] = x_ptr[j] - x_ptr[j] * x_ptr[j] * x_ptr[j] / 6.0; + } + } + } + return Error::Ok; + } +}; + +namespace { +auto cls = BackendWithCompiler(); +Backend backend{"BackendWithCompilerDemo", &cls}; +static auto success_with_compiler = register_backend(backend); +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_with_delegate_mapping.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_with_delegate_mapping.cpp new file mode 100644 index 0000000..feeff88 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/executor/test/test_backend_with_delegate_mapping.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include /* strtol */ +#include + +using executorch::ET_RUNTIME_NAMESPACE::Backend; +using executorch::ET_RUNTIME_NAMESPACE::BackendExecutionContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInitContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInterface; +using executorch::ET_RUNTIME_NAMESPACE::CompileSpec; +using executorch::ET_RUNTIME_NAMESPACE::DelegateHandle; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +struct DemoOp { + const char* name; + long int debug_handle; +}; + +struct DemoOpList { + DemoOp* ops; + size_t numops; +}; + +class BackendWithDelegateMapping final : public BackendInterface { + public: + ~BackendWithDelegateMapping() override = default; + + bool is_available() const override { + return true; + } + + // The delegate blob schema will be a list of instruction: + // {op_name:{str},delegate debug identifier:{int}} + // Instructions will be separated by #, for example: + // `op_name:demo_linear,delegate debug + // identifier:0#op_name:mm_decomp_from_addmm,\ delegate debug + // identifier:1#op_name:mm_decomp_from_addmm,delegate debug identifier:2` + Error parse_delegate( + const char* str, + DemoOpList* op_list, + MemoryAllocator* runtime_allocator) const { + char* op_name; + char* delegate_debug_identifier; + size_t num_ops = 0; + char* copy = strdup(str); + + while (true) { + char* saveptr = nullptr; + op_name = strtok_r(copy, ",", &saveptr); + delegate_debug_identifier = strtok_r(nullptr, ",", &saveptr); + + if (op_name == nullptr || delegate_debug_identifier == nullptr) { + break; + } + + if (op_name != nullptr && delegate_debug_identifier != nullptr) { + char* op_name_mem = + (char*)runtime_allocator->allocate(strlen(op_name) + 1); + if (op_name_mem == nullptr) { + return Error::MemoryAllocationFailed; + } + memcpy(op_name_mem, op_name, strlen(op_name) + 1); + op_list->ops[num_ops].name = op_name_mem; + op_list->ops[num_ops].debug_handle = atoi(delegate_debug_identifier); + } + + num_ops += 1; + if (num_ops == op_list->numops) { + break; + } + copy = nullptr; + } + + free(copy); + return Error::Ok; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + MemoryAllocator* runtime_allocator = context.get_runtime_allocator(); + (void)compile_specs; + const char* kSignLiteral = "#"; + // The first number is the number of total instruction + const char* start = static_cast(processed->data()); + char* instruction_number_end = + const_cast(strstr(start, kSignLiteral)); + long int instruction_number = strtol(start, &instruction_number_end, 10); + ET_CHECK_OR_RETURN_ERROR( + instruction_number >= 0, + InvalidArgument, + "Instruction count must be non-negative: %ld", + instruction_number); + + auto op_list = runtime_allocator->allocateInstance(); + if (op_list == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->ops = runtime_allocator->allocateList(instruction_number); + if (op_list->ops == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->numops = static_cast(instruction_number); + + Error error = + parse_delegate(instruction_number_end + 1, op_list, runtime_allocator); + if (error != Error::Ok) { + return error; + } + + return op_list; + } + + // This function doesn't actually execute the op but just prints out the op + // name and the corresponding delegate debug identifier. + Error execute( + ET_UNUSED BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + (void)args; + // example: [('prim::Constant#1', 14), ('aten::add', 15)] + auto op_list = static_cast(handle); + + for (size_t index = 0; index < op_list->numops; index++) { + ET_LOG( + Info, + "Op name = %s Delegate debug index = %ld", + op_list->ops[index].name, + op_list->ops[index].debug_handle); + event_tracer_log_profiling_delegate( + context.event_tracer(), + nullptr, + op_list->ops[index].debug_handle, + 0, + 1); + /** + If you used string based delegate debug identifiers then the profiling + call would be as below. + event_tracer_log_profiling_delegate( + context.event_tracer(), + pointer_to_delegate_debug_string, + -1, + 0, + 1); + */ + } + + return Error::Ok; + } +}; + +namespace { +auto cls = BackendWithDelegateMapping(); +Backend backend{"BackendWithDelegateMappingDemo", &cls}; +static auto success_with_compiler = register_backend(backend); +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/kernel_includes.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/kernel_includes.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/kernel_includes.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/kernel_includes.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/kernel_runtime_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/kernel_runtime_context.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/kernel_runtime_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/kernel_runtime_context.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/operator_registry.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/operator_registry.cpp similarity index 82% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/operator_registry.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/operator_registry.cpp index a5803cd..3738f82 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/operator_registry.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/operator_registry.cpp @@ -20,27 +20,14 @@ namespace ET_RUNTIME_NAMESPACE { namespace { // Maximum number of operators and their associated kernels that can be -// registered. Resolution order: -// 1. User-defined -DMAX_KERNEL_NUM wins. -// 2. Otherwise, if selective build generated selected_max_kernel_num.h and -// it defines EXECUTORCH_SELECTED_MAX_KERNEL_NUM, use that. (When a -// selective-build YAML opts into all operators the header is emitted -// without the define, and we fall through.) -// 3. Otherwise, fall back to a conservative default of 2000 slots. -#if defined(MAX_KERNEL_NUM) +// registered. +#ifdef MAX_KERNEL_NUM constexpr uint32_t kMaxRegisteredKernels = MAX_KERNEL_NUM; #else -#if __has_include() -#include -#endif -#if defined(EXECUTORCH_SELECTED_MAX_KERNEL_NUM) -constexpr uint32_t kMaxRegisteredKernels = EXECUTORCH_SELECTED_MAX_KERNEL_NUM; -#else constexpr uint32_t kMaxOperators = 250; constexpr uint32_t kMaxKernelsPerOp = 8; constexpr uint32_t kMaxRegisteredKernels = kMaxOperators * kMaxKernelsPerOp; #endif -#endif // Data that backs the kernel table. Since Kernel has a custom default // constructor (implicitly, because it contains KernelKey, which has a custom @@ -101,13 +88,6 @@ Error register_kernels_internal(const Span kernels) { kernel.kernel_key_ == k.kernel_key_) { ET_LOG(Error, "Re-registering %s, from %s", k.name_, lib_name); ET_LOG_KERNEL_KEY(k.kernel_key_); - ET_CHECK_MSG( - false, - "Kernel registration failed with error %" PRIu32 - ", Re-registering %s, from %s", - static_cast(Error::RegistrationAlreadyRegistered), - k.name_, - lib_name); return Error::RegistrationAlreadyRegistered; } } @@ -249,8 +229,7 @@ bool registry_has_op_function( Result get_op_function_from_registry( const char* name, - Span meta_list, - Span kernel_list) { + Span meta_list) { std::array key_string; Error err = internal::make_kernel_key_string( meta_list, key_string.data(), key_string.size()); @@ -261,31 +240,24 @@ Result get_op_function_from_registry( KernelKey kernel_key = KernelKey(key_string.data()); int32_t fallback_idx = -1; - for (size_t idx = 0; idx < kernel_list.size(); idx++) { - if (strcmp(kernel_list[idx].name_, name) == 0) { - if (kernel_list[idx].kernel_key_ == kernel_key) { - return kernel_list[idx].op_; + for (size_t idx = 0; idx < num_registered_kernels; idx++) { + if (strcmp(registered_kernels[idx].name_, name) == 0) { + if (registered_kernels[idx].kernel_key_ == kernel_key) { + return registered_kernels[idx].op_; } - if (kernel_list[idx].kernel_key_.is_fallback()) { + if (registered_kernels[idx].kernel_key_.is_fallback()) { fallback_idx = idx; } } } if (fallback_idx != -1) { - return kernel_list[fallback_idx].op_; + return registered_kernels[fallback_idx].op_; } ET_LOG(Error, "kernel '%s' not found.", name); ET_LOG_TENSOR_META(meta_list); return Error::OperatorMissing; } -Result get_op_function_from_registry( - const char* name, - Span meta_list) { - return get_op_function_from_registry( - name, meta_list, get_registered_kernels()); -} - Span get_registered_kernels() { return {registered_kernels, num_registered_kernels}; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/operator_registry.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/operator_registry.h similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/operator_registry.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/operator_registry.h index 4f69bb7..dfae7c2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/operator_registry.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/operator_registry.h @@ -123,14 +123,14 @@ struct KernelKey { * for all input tensor dtypes and dim orders if the specialized kernel is not * registered. */ - constexpr KernelKey() = default; + KernelKey() = default; /** * Creates a specialized (non-fallback) kernel key that matches a specific * set of input tensor dtypes and dim orders. See the class comment for the * expected format of `kernel_key_data`. */ - /* implicit */ constexpr KernelKey(const char* kernel_key_data) + /* implicit */ KernelKey(const char* kernel_key_data) : kernel_key_data_(kernel_key_data) {} bool operator==(const KernelKey& other) const { @@ -188,13 +188,12 @@ struct Kernel { * itself, we require the lifetime of the operator name to be at least as long * as the operator registry. */ - constexpr explicit Kernel(const char* name, OpFunction func) - : name_(name), op_(func) {} + explicit Kernel(const char* name, OpFunction func) : name_(name), op_(func) {} - constexpr explicit Kernel(const char* name, KernelKey key, OpFunction func) + explicit Kernel(const char* name, KernelKey key, OpFunction func) : name_(name), kernel_key_(key), op_(func) {} - constexpr Kernel() : name_(nullptr), op_(nullptr) {} + Kernel() {} }; namespace internal { @@ -233,15 +232,6 @@ ::executorch::runtime::Result get_op_function_from_registry( const char* name, Span meta_list = {}); -/** - * Returns the operator with a given name and TensorMeta list from the provided - * kernel list instead of the global registry. - */ -::executorch::runtime::Result get_op_function_from_registry( - const char* name, - Span meta_list, - Span kernel_list); - /** * Returns all registered kernels. */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/targets.bzl new file mode 100644 index 0000000..123dc1a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/targets.bzl @@ -0,0 +1,97 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def _operator_registry_preprocessor_flags(): + max_kernel_num = native.read_config("executorch", "max_kernel_num", None) + if max_kernel_num != None: + return select({ + "DEFAULT": ["-DMAX_KERNEL_NUM=" + max_kernel_num], + "ovr_config//build_mode/constraints:arvr_is_host_platform": [] + }) + elif not runtime.is_oss: + return select({ + "DEFAULT": [], + "fbsource//xplat/executorch/tools/buck/constraints:executorch-max-kernel-num-256": ["-DMAX_KERNEL_NUM=256"], + "fbsource//xplat/executorch/tools/buck/constraints:executorch-max-kernel-num-128": ["-DMAX_KERNEL_NUM=128"], + "fbsource//xplat/executorch/tools/buck/constraints:executorch-max-kernel-num-64": ["-DMAX_KERNEL_NUM=64"], + }) + else: + return [] + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "operator_registry_MAX_NUM_KERNELS_TEST_ONLY", + srcs = ["operator_registry.cpp"], + exported_headers = ["operator_registry.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:evalue", + ], + preprocessor_flags = ["-DMAX_KERNEL_NUM=1"], + ) + + runtime.cxx_library( + name = "thread_parallel_interface", + exported_headers = ["thread_parallel_interface.h"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + "//executorch/runtime/platform:platform", + ], + # Don't depend on this target, depend on //executorch/extension/threadpool:threadpool. + visibility = [ + "//executorch/extension/threadpool/...", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_library( + name = "operator_registry" + aten_suffix, + srcs = ["operator_registry.cpp"], + exported_headers = ["operator_registry.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:evalue" + aten_suffix, + ], + preprocessor_flags = _operator_registry_preprocessor_flags(), + ) + + runtime.cxx_library( + name = "kernel_runtime_context" + aten_suffix, + exported_headers = [ + "kernel_runtime_context.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/core:event_tracer" + aten_suffix, + # TODO(T147221312): This will eventually depend on exec_aten + # once KernelRuntimeContext support tensor resizing, which is + # why this target supports aten mode. + ], + ) + + runtime.cxx_library( + name = "kernel_includes" + aten_suffix, + exported_headers = [ + "kernel_includes.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + ":kernel_runtime_context" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/CMakeLists.txt new file mode 100644 index 0000000..a816601 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +add_executable(operator_registry_test operator_registry_test.cpp) +target_link_libraries( + operator_registry_test GTest::gtest GTest::gtest_main GTest::gmock + executorch_core +) +target_include_directories(operator_registry_test PRIVATE ${EXECUTORCH_ROOT}/..) +add_test(operator_registry_test operator_registry_test) + +add_executable(kernel_runtime_context_test kernel_runtime_context_test.cpp) +target_link_libraries( + kernel_runtime_context_test GTest::gtest GTest::gtest_main GTest::gmock + executorch_core +) +target_include_directories( + kernel_runtime_context_test PRIVATE ${EXECUTORCH_ROOT}/.. +) +add_test(kernel_runtime_context_test kernel_runtime_context_test) + +add_executable( + operator_registry_max_kernel_num_test + operator_registry_max_kernel_num_test.cpp +) +target_link_libraries( + operator_registry_max_kernel_num_test GTest::gtest GTest::gtest_main + GTest::gmock executorch_core +) +target_compile_definitions( + operator_registry_max_kernel_num_test PRIVATE "-DMAX_KERNEL_NUM=1" +) +# TODO: This is currently not working! +# add_test(operator_registry_max_kernel_num_test +# operator_registry_max_kernel_num_test) + +# TODO: Migrate kernel_double_registration_test and +# test_kernel_manual_registration. Make sure dtype selective build is working. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/functions.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/functions.yaml new file mode 100644 index 0000000..81f0e5f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/functions.yaml @@ -0,0 +1,13 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. + +- func: add.out(Tensor self, Tensor other, *, Scalar alpha=1, Tensor(a!) out) -> Tensor(a!) + type_alias: + T0: [Double] + dim_order_alias: + D0: [0, 1, 2, 3] + kernels: + - arg_meta: + self: [T0, D0] + other: [T0 , D0] + out: [T0, D0] + kernel_name: torch::executor::add_out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_double_registration_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_double_registration_test.cpp new file mode 100644 index 0000000..11026fd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_double_registration_test.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +using namespace ::testing; + +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Kernel; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::register_kernels; +using executorch::runtime::Span; + +class KernelDoubleRegistrationTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(KernelDoubleRegistrationTest, Basic) { + Kernel kernels[] = {Kernel( + "aten::add.out", + "v1/7;0,1,2,3|7;0,1,2,3|7;0,1,2,3", + [](KernelRuntimeContext&, Span) {})}; + Error err = Error::RegistrationAlreadyRegistered; + + ET_EXPECT_DEATH( + { (void)register_kernels({kernels}); }, + std::to_string(static_cast(err))); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_runtime_context_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_runtime_context_test.cpp new file mode 100644 index 0000000..2c3b536 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/kernel_runtime_context_test.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include + +using namespace ::testing; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using executorch::runtime::Error; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; + +class KernelRuntimeContextTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +class TestMemoryAllocator : public MemoryAllocator { + public: + TestMemoryAllocator(uint32_t size, uint8_t* base_address) + : MemoryAllocator(size, base_address), last_seen_alignment(0) {} + void* allocate(size_t size, size_t alignment) override { + last_seen_alignment = alignment; + return MemoryAllocator::allocate(size, alignment); + } + size_t last_seen_alignment; +}; + +TEST_F(KernelRuntimeContextTest, FailureStateDefaultsToOk) { + KernelRuntimeContext context; + + EXPECT_EQ(context.failure_state(), Error::Ok); +} + +TEST_F(KernelRuntimeContextTest, FailureStateReflectsFailure) { + KernelRuntimeContext context; + + // Starts off Ok. + EXPECT_EQ(context.failure_state(), Error::Ok); + + // Failing should update the failure state. + context.fail(Error::MemoryAllocationFailed); + EXPECT_EQ(context.failure_state(), Error::MemoryAllocationFailed); + + // State can be overwritten. + context.fail(Error::Internal); + EXPECT_EQ(context.failure_state(), Error::Internal); + + // And can be cleared. + context.fail(Error::Ok); + EXPECT_EQ(context.failure_state(), Error::Ok); +} + +TEST_F(KernelRuntimeContextTest, FailureNoMemoryAllocatorProvided) { + KernelRuntimeContext context; + Result allocated_memory = context.allocate_temp(4); + EXPECT_EQ(allocated_memory.error(), Error::NotFound); +} + +TEST_F(KernelRuntimeContextTest, SuccessfulMemoryAllocation) { + constexpr size_t temp_memory_allocator_pool_size = 4; + auto temp_memory_allocator_pool = + std::make_unique(temp_memory_allocator_pool_size); + MemoryAllocator temp_allocator( + temp_memory_allocator_pool_size, temp_memory_allocator_pool.get()); + KernelRuntimeContext context(nullptr, &temp_allocator); + Result allocated_memory = context.allocate_temp(4); + EXPECT_EQ(allocated_memory.ok(), true); +} + +TEST_F(KernelRuntimeContextTest, FailureMemoryAllocationInsufficientSpace) { + constexpr size_t temp_memory_allocator_pool_size = 4; + auto temp_memory_allocator_pool = + std::make_unique(temp_memory_allocator_pool_size); + MemoryAllocator temp_allocator( + temp_memory_allocator_pool_size, temp_memory_allocator_pool.get()); + KernelRuntimeContext context(nullptr, &temp_allocator); + Result allocated_memory = context.allocate_temp(8); + EXPECT_EQ(allocated_memory.error(), Error::MemoryAllocationFailed); +} + +TEST_F(KernelRuntimeContextTest, MemoryAllocatorAlignmentPassed) { + constexpr size_t temp_memory_allocator_pool_size = 4; + auto temp_memory_allocator_pool = + std::make_unique(temp_memory_allocator_pool_size); + TestMemoryAllocator temp_allocator( + temp_memory_allocator_pool_size, temp_memory_allocator_pool.get()); + KernelRuntimeContext context(nullptr, &temp_allocator); + Result allocated_memory = context.allocate_temp(4, 2); + EXPECT_EQ(allocated_memory.ok(), true); + EXPECT_EQ(temp_allocator.last_seen_alignment, 2); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp new file mode 100644 index 0000000..627638d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Kernel; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::register_kernels; +using executorch::runtime::registry_has_op_function; +using executorch::runtime::Span; + +class OperatorRegistryMaxKernelNumTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +// Register one kernel when max_kernel_num=1; success +TEST_F(OperatorRegistryMaxKernelNumTest, RegisterOneOp) { + Kernel kernels[] = { + Kernel("foo", [](KernelRuntimeContext&, Span) {})}; + auto s1 = register_kernels({kernels}); + EXPECT_EQ(s1, Error::Ok); + EXPECT_FALSE(registry_has_op_function("fpp")); + EXPECT_TRUE(registry_has_op_function("foo")); +} + +// Register two kernels when max_kernel_num=1; fail +TEST_F(OperatorRegistryMaxKernelNumTest, RegisterTwoOpsFail) { + Kernel kernels[] = { + Kernel("foo1", [](KernelRuntimeContext&, Span) {}), + Kernel("foo2", [](KernelRuntimeContext&, Span) {})}; + ET_EXPECT_DEATH( + { (void)register_kernels({kernels}); }, + "The total number of kernels to be registered is larger than the limit 1"); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_test.cpp new file mode 100644 index 0000000..b06633d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/operator_registry_test.cpp @@ -0,0 +1,517 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::get_op_function_from_registry; +using executorch::runtime::Kernel; +using executorch::runtime::KernelKey; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::OpFunction; +using executorch::runtime::register_kernels; +using executorch::runtime::registry_has_op_function; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorMeta; +using executorch::runtime::internal::kKernelKeyBufSize; +using executorch::runtime::testing::make_kernel_key; + +// +// Tests for make_kernel_key_string +// + +// Helper for testing make_kernel_key_string. +void test_make_kernel_key_string( + const std::vector>>& tensors, + const char* expected_key) { + const size_t min_buf_size = strlen(expected_key) + 1; + + // Sweep across too-small buffer sizes, exercising all possible failure + // checks. Rely on ASAN to detect buffer overflows. + for (size_t buf_size = 0; buf_size < min_buf_size; buf_size++) { + std::vector actual_key(buf_size, 0x55); + Error err = make_kernel_key( + tensors, + // nullptr should be valid for buf_size == 0 because it won't be written + // to. + buf_size == 0 ? nullptr : actual_key.data(), + actual_key.size()); + EXPECT_NE(err, Error::Ok); + } + + // Demonstrate that it succeeds for buffers of exactly the right size or + // larger. + for (size_t buf_size = min_buf_size; buf_size < min_buf_size + 1; + buf_size++) { + std::vector actual_key(buf_size, 0x55); + Error err = make_kernel_key(tensors, actual_key.data(), actual_key.size()); + ASSERT_EQ(err, Error::Ok); + EXPECT_STREQ(actual_key.data(), expected_key); + } +} + +TEST(MakeKernelKeyStringTest, ZeroTensorSuccessWithNullBuffer) { + Error err = make_kernel_key({}, nullptr, 0); + EXPECT_EQ(err, Error::Ok); +} + +TEST(MakeKernelKeyStringTest, ZeroTensorSuccessMakesEmptyString) { + char buf = 0x55; + Error err = make_kernel_key({}, &buf, 1); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(buf, '\0'); +} + +TEST(MakeKernelKeyStringTest, OneTensorSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 1, 2, 3}}}, "v1/4;0,1,2,3"); +} + +TEST(MakeKernelKeyStringTest, TwoTensorSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 1, 2, 3}}, {ScalarType::Double, {3, 2, 1, 0}}}, + "v1/4;0,1,2,3|7;3,2,1,0"); +} + +TEST(MakeKernelKeyStringTest, ThreeTensorSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 1, 2, 3}}, + {ScalarType::Double, {3, 2, 1, 0}}, + {ScalarType::Byte, {2, 1, 3, 0}}}, + "v1/4;0,1,2,3|7;3,2,1,0|0;2,1,3,0"); +} + +TEST(MakeKernelKeyStringTest, TwoDigitDimOrderSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 10, 2, 99}}}, "v1/4;0,10,2,99"); +} + +TEST(MakeKernelKeyStringTest, ThreeDigitDimOrderFailure) { + std::vector actual_key(1024, 0x55); // Large enough for any key. + Error err = make_kernel_key( + // Cannot represent a dim order entry with more than two digits. + {{ScalarType::Long, {0, 100, 2, 255}}}, + actual_key.data(), + actual_key.size()); + EXPECT_NE(err, Error::Ok); +} + +TEST(MakeKernelKeyStringTest, NegativeScalarTypeFailure) { + std::vector actual_key(1024, 0x55); // Large enough for any key. + Error err = make_kernel_key( + // Cannot represent a ScalarType (aka int8_t) with a negative value. + {{(ScalarType)-1, {0, 1, 2, 3}}}, + actual_key.data(), + actual_key.size()); + EXPECT_NE(err, Error::Ok); +} + +TEST(MakeKernelKeyStringTest, KeyBufSizeMeetsAssumptions) { + // Create the longest key that fits in the assupmtions of kKernelKeyBufSize: + // 16 tensors, 16 dims, with two-digit ScalarTypes. + std::vector>> + tensors; + tensors.reserve(16); + for (int i = 0; i < 16; i++) { + std::vector dims; + dims.reserve(16); + for (int j = 0; j < 16; j++) { + dims.emplace_back(j); + } + tensors.emplace_back((ScalarType)10, dims); + } + + std::vector actual_key(kKernelKeyBufSize, 0x55); + Error err = make_kernel_key(tensors, actual_key.data(), actual_key.size()); + ASSERT_EQ(err, Error::Ok); + EXPECT_STREQ( + actual_key.data(), + "v1/" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"); + EXPECT_LE(strlen(actual_key.data()) + 1, kKernelKeyBufSize); +} + +// +// Tests for public operator registry APIs +// + +class OperatorRegistryTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(OperatorRegistryTest, Basic) { + Kernel kernels[] = { + Kernel("foo", [](KernelRuntimeContext&, Span) {})}; + Span kernels_span(kernels); + Error err = register_kernels(kernels_span); + ASSERT_EQ(err, Error::Ok); + EXPECT_FALSE(registry_has_op_function("fpp")); + EXPECT_TRUE(registry_has_op_function("foo")); +} + +TEST_F(OperatorRegistryTest, RegisterOpsMoreThanOnceDie) { + Kernel kernels[] = { + Kernel("foo", [](KernelRuntimeContext&, Span) {}), + Kernel("foo", [](KernelRuntimeContext&, Span) {})}; + Span kernels_span = Span(kernels); + ET_EXPECT_DEATH({ (void)register_kernels(kernels_span); }, ""); +} + +TEST_F(OperatorRegistryTest, KernelKeyEquals) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey long_contiguous = KernelKey(buf_long_contiguous.data()); + + KernelKey long_key_1 = KernelKey(long_contiguous); + + KernelKey long_key_2 = KernelKey(long_contiguous); + + EXPECT_EQ(long_key_1, long_key_2); + + std::array buf_float_contiguous; + err = make_kernel_key( + {{ScalarType::Float, {0, 1, 2, 3}}}, + buf_float_contiguous.data(), + buf_float_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey float_key = KernelKey(buf_float_contiguous.data()); + + EXPECT_NE(long_key_1, float_key); + + std::array buf_channel_first; + err = make_kernel_key( + {{ScalarType::Long, {0, 3, 1, 2}}}, + buf_channel_first.data(), + buf_channel_first.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey long_key_3 = KernelKey(buf_channel_first.data()); + + EXPECT_NE(long_key_1, long_key_3); +} + +TEST_F(OperatorRegistryTest, GetOpFailsForLongKernelKey) { + // Looking up a way-too-long kernel key should fail with an error. + std::vector>> + tensors; + // 1000 is a lot of tensors. + tensors.reserve(1000); + for (int i = 0; i < 1000; i++) { + std::vector dims; + dims.reserve(16); + for (int j = 0; j < 16; j++) { + dims.emplace_back(j); + } + tensors.emplace_back((ScalarType)10, dims); + } + std::vector meta; + for (auto& t : tensors) { + Span dim_order( + t.second.data(), t.second.size()); + meta.emplace_back(t.first, dim_order); + } + Span metadata(meta.data(), meta.size()); + + auto op = get_op_function_from_registry("test::not-real", metadata); + EXPECT_NE(op.error(), Error::Ok); + EXPECT_NE(op.error(), Error::OperatorMissing); + // The lookup failed, but not because the operator is missing. +} + +TEST_F(OperatorRegistryTest, RegisterKernels) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::boo", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + err = register_kernels({&kernel_1, 1}); + ASSERT_EQ(err, Error::Ok); + + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key(meta); + + // no fallback kernel is registered + EXPECT_FALSE(registry_has_op_function("test::boo", {})); + Result fallback_func = + get_op_function_from_registry("test::boo", {}); + EXPECT_NE(fallback_func.error(), Error::Ok); + + EXPECT_TRUE(registry_has_op_function("test::boo", user_kernel_key)); + Result func = + get_op_function_from_registry("test::boo", user_kernel_key); + EXPECT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} + +TEST_F(OperatorRegistryTest, RegisterTwoKernels) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key_1 = KernelKey(buf_long_contiguous.data()); + + std::array buf_float_contiguous; + err = make_kernel_key( + {{ScalarType::Float, {0, 1, 2, 3}}}, + buf_float_contiguous.data(), + buf_float_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key_2 = KernelKey(buf_float_contiguous.data()); + Kernel kernel_1 = Kernel( + "test::bar", + key_1, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + Kernel kernel_2 = Kernel( + "test::bar", + key_2, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(50); + }); + Kernel kernels[] = {kernel_1, kernel_2}; + err = register_kernels(kernels); + ASSERT_EQ(err, Error::Ok); + + // has both kernels + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key_1(meta); + + TensorMeta meta_2[] = {TensorMeta(ScalarType::Float, dim_order_type)}; + Span user_kernel_key_2(meta_2); + + // no fallback kernel is registered + EXPECT_FALSE(registry_has_op_function("test::bar", {})); + Result fallback_func = + get_op_function_from_registry("test::bar", {}); + EXPECT_NE(fallback_func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* evalues[1]; + evalues[0] = &values[0]; + KernelRuntimeContext context{}; + + // test kernel_1 + EXPECT_TRUE(registry_has_op_function("test::bar", user_kernel_key_1)); + Result func_1 = + get_op_function_from_registry("test::bar", user_kernel_key_1); + EXPECT_EQ(func_1.error(), Error::Ok); + (*func_1)(context, Span(evalues)); + + auto val_1 = values[0].toScalar().to(); + ASSERT_EQ(val_1, 100); + + // test kernel_2 + EXPECT_TRUE(registry_has_op_function("test::bar", user_kernel_key_2)); + Result func_2 = + get_op_function_from_registry("test::bar", user_kernel_key_2); + EXPECT_EQ(func_2.error(), Error::Ok); + values[0] = Scalar(0); + (*func_2)(context, Span(evalues)); + + auto val_2 = values[0].toScalar().to(); + ASSERT_EQ(val_2, 50); +} + +TEST_F(OperatorRegistryTest, DoubleRegisterKernelsDies) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::baz", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + Kernel kernel_2 = Kernel( + "test::baz", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(50); + }); + Kernel kernels[] = {kernel_1, kernel_2}; + // clang-tidy off + ET_EXPECT_DEATH({ (void)register_kernels(kernels); }, ""); + // clang-tidy on +} + +TEST_F(OperatorRegistryTest, ExecutorChecksKernel) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::qux", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + err = register_kernels({&kernel_1, 1}); + ASSERT_EQ(err, Error::Ok); + + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key_1(meta); + EXPECT_TRUE(registry_has_op_function("test::qux", user_kernel_key_1)); + + Tensor::DimOrderType dims_channel_first[] = {0, 3, 1, 2}; + auto dim_order_type_channel_first = + Span(dims_channel_first, 4); + TensorMeta meta_channel_first[] = { + TensorMeta(ScalarType::Long, dim_order_type_channel_first)}; + Span user_kernel_key_2(meta_channel_first); + EXPECT_FALSE(registry_has_op_function("test::qux", user_kernel_key_2)); + + TensorMeta meta_float[] = {TensorMeta(ScalarType::Float, dim_order_type)}; + Span user_kernel_key_3(meta_float); + EXPECT_FALSE(registry_has_op_function("test::qux", user_kernel_key_3)); +} + +TEST_F(OperatorRegistryTest, ExecutorUsesKernel) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::quux", + key, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + err = register_kernels({&kernel_1, 1}); + ASSERT_EQ(err, Error::Ok); + + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key_1(meta); + + EXPECT_TRUE(registry_has_op_function("test::quux", user_kernel_key_1)); + Result func = + get_op_function_from_registry("test::quux", user_kernel_key_1); + EXPECT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} + +TEST_F(OperatorRegistryTest, ExecutorUsesFallbackKernel) { + Kernel kernel_1 = Kernel( + "test::corge", + KernelKey{}, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + Error err = register_kernels({&kernel_1, 1}); + EXPECT_EQ(err, Error::Ok); + + EXPECT_TRUE(registry_has_op_function("test::corge")); + EXPECT_TRUE(registry_has_op_function("test::corge", {})); + + Result func = get_op_function_from_registry("test::corge", {}); + EXPECT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/targets.bzl new file mode 100644 index 0000000..4b3ed0f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/targets.bzl @@ -0,0 +1,116 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "operator_registry_test", + srcs = [ + "operator_registry_test.cpp", + ], + headers = ["test_util.h"], + deps = [ + "//executorch/runtime/kernel:operator_registry", + "//executorch/runtime/kernel:kernel_runtime_context", + ], + ) + + runtime.cxx_test( + name = "operator_registry_max_kernel_num_test", + srcs = [ + "operator_registry_max_kernel_num_test.cpp", + ], + deps = [ + "//executorch/runtime/kernel:operator_registry_MAX_NUM_KERNELS_TEST_ONLY", + "//executorch/runtime/kernel:kernel_runtime_context", + ], + ) + + et_operator_library( + name = "executorch_all_ops", + include_all_operators = True, + define_static_targets = True, + ) + + runtime.export_file( + name = "functions.yaml", + ) + + executorch_generated_lib( + name = "specialized_kernel_generated_lib", + deps = [ + ":executorch_all_ops", + "//executorch/kernels/portable:operators", + ], + functions_yaml_target = ":functions.yaml", + visibility = [ + "//executorch/...", + ], + ) + + runtime.cxx_test( + name = "kernel_double_registration_test", + srcs = [ + "kernel_double_registration_test.cpp", + ], + deps = [ + "//executorch/runtime/kernel:operator_registry", + ":specialized_kernel_generated_lib", + ], + ) + + executorch_generated_lib( + name = "test_manual_registration_lib", + deps = [ + ":executorch_all_ops", + "//executorch/kernels/portable:operators", + ], + functions_yaml_target = "//executorch/kernels/portable:functions.yaml", + manual_registration = True, + visibility = [ + "//executorch/...", + ], + ) + + runtime.cxx_test( + name = "test_kernel_manual_registration", + srcs = [ + "test_kernel_manual_registration.cpp", + ], + deps = [ + "//executorch/runtime/kernel:operator_registry", + ":test_manual_registration_lib", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_test( + name = "kernel_runtime_context_test" + aten_suffix, + srcs = [ + "kernel_runtime_context_test.cpp", + ], + deps = [ + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + ":specialized_kernel_generated_lib", + ], + ) + + if aten_mode: + # Make sure we can depend on both generated_lib and generated_lib_aten + # in the same binary. + runtime.cxx_test( + name = "test_generated_lib_and_aten", + srcs = ["test_generated_lib_and_aten.cpp"], + deps = [ + "//executorch/kernels/portable:generated_lib", + "//executorch/kernels/portable:generated_lib_aten", + "//executorch/runtime/kernel:operator_registry_aten", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_generated_lib_and_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_generated_lib_and_aten.cpp new file mode 100644 index 0000000..f9bfebc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_generated_lib_and_aten.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::runtime::Error; +using executorch::runtime::EValue; + +class GeneratedLibAndAtenTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(GeneratedLibAndAtenTest, GetKernelsFromATenRegistry) { + // Check if the kernel exists in the ATen registry + bool has_kernel = + executorch::runtime::aten::registry_has_op_function("aten::add.out"); + EXPECT_TRUE(has_kernel) + << "Kernel 'aten::add.out' not found in ATen registry"; + + // Get the kernel from the ATen registry + auto result = + executorch::runtime::aten::get_op_function_from_registry("aten::add.out"); + EXPECT_EQ(result.error(), Error::Ok) + << "Failed to get kernel from ATen registry"; + EXPECT_NE(*result, nullptr) << "Kernel function from ATen registry is null"; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_kernel_manual_registration.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_kernel_manual_registration.cpp new file mode 100644 index 0000000..de8853c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_kernel_manual_registration.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::registry_has_op_function; + +class KernelManualRegistrationTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(KernelManualRegistrationTest, ManualRegister) { + // Before registering, we can't find the add operator. + EXPECT_FALSE(registry_has_op_function("aten::add.out")); + + // Call the generated registration function. + Error result = torch::executor::register_all_kernels(); + EXPECT_EQ(result, Error::Ok); + + // We can now find the registered add operator. + EXPECT_TRUE(registry_has_op_function("aten::add.out")); + + // We can't find a random other operator. + EXPECT_FALSE(registry_has_op_function("fpp")); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_util.h new file mode 100644 index 0000000..be77df1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/test/test_util.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include + +namespace executorch { +namespace runtime { + +namespace testing { + +inline Error make_kernel_key( + const std::vector>>& tensors, + char* buf, + size_t buf_size) { + std::vector meta; + for (auto& t : tensors) { + Span dim_order( + const_cast(t.second.data()), t.second.size()); + meta.emplace_back(t.first, dim_order); + } + Span metadata(meta.data(), meta.size()); + return internal::make_kernel_key_string(metadata, buf, buf_size); +} + +} // namespace testing + +} // namespace runtime +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/thread_parallel_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/thread_parallel_interface.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/thread_parallel_interface.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/kernel/thread_parallel_interface.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/abort.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/abort.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/abort.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/abort.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/abort.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/abort.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/abort.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/abort.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/assert.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/assert.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/assert.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/assert.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/clock.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/clock.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/clock.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/clock.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/compat_unistd.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/compat_unistd.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/compat_unistd.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/compat_unistd.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/compiler.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/compiler.h similarity index 99% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/compiler.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/compiler.h index edd340d..ab2f45f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/compiler.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/compiler.h @@ -179,7 +179,7 @@ #endif // ifndef // Define size_t and ssize_t. -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__ARMCC_VERSION) #include #else #include diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/android.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/android.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/android.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/android.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/minimal.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/minimal.cpp similarity index 53% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/minimal.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/minimal.cpp index 720922c..8236f99 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/minimal.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/minimal.cpp @@ -10,32 +10,23 @@ * @file * Fallback PAL implementations that do not depend on any assumptions about * capabililties of the system. - * - * Each et_pal_* fallback is marked ET_WEAK directly on its definition, - * not just on the declaration in platform.h. The weak attribute is a - * property of a specific symbol *definition* in the ELF symbol table — - * it is not transitively inherited from a forward declaration. GCC - * 13/14/15 and armclang 6.24 follow that rule: a definition without an - * explicit weak attribute emits a STB_GLOBAL (strong) symbol, even if - * the matching declaration was weak. (Older GCCs were laxer about this; - * the current behaviour is the standards-aligned one.) Without the - * direct ET_WEAK on each definition, a downstream consumer that - * supplies its own et_pal_* override hits a multi-def link error - * against this fallback. */ +// This cpp file will provide weak implementations of the symbols declared in +// Platform.h. Client users can strongly define any or all of the functions to +// override them. #define ET_INTERNAL_PLATFORM_WEAKNESS ET_WEAK #include #include -ET_WEAK void et_pal_init(void) {} +void et_pal_init(void) {} -ET_WEAK ET_NORETURN void et_pal_abort(void) { +ET_NORETURN void et_pal_abort(void) { __builtin_trap(); } -ET_WEAK et_timestamp_t et_pal_current_ticks(void) { +et_timestamp_t et_pal_current_ticks(void) { // This file cannot make any assumptions about the presence of functions that // return the current time, so all users should provide a strong override for // it. To help make it more obvious when this weak version is being used, @@ -43,12 +34,12 @@ ET_WEAK et_timestamp_t et_pal_current_ticks(void) { return 11223344; } -ET_WEAK et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) { +et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) { // Since we don't define a tick rate, return a conversion ratio of 1. return {1, 1}; } -ET_WEAK void et_pal_emit_log_message( +void et_pal_emit_log_message( ET_UNUSED et_timestamp_t timestamp, ET_UNUSED et_pal_log_level_t level, ET_UNUSED const char* filename, @@ -57,8 +48,8 @@ ET_WEAK void et_pal_emit_log_message( ET_UNUSED const char* message, ET_UNUSED size_t length) {} -ET_WEAK void* et_pal_allocate(ET_UNUSED size_t size) { +void* et_pal_allocate(ET_UNUSED size_t size) { return nullptr; } -ET_WEAK void et_pal_free(ET_UNUSED void* ptr) {} +void et_pal_free(ET_UNUSED void* ptr) {} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/posix.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/posix.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/posix.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/posix.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/zephyr.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/zephyr.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/zephyr.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/default/zephyr.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.bzl new file mode 100644 index 0000000..04a3de1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.bzl @@ -0,0 +1,22 @@ +def et_logging_enabled(): + return native.read_config("executorch", "enable_et_log", "true") == "true" + +def et_log_level(): + raw_level = native.read_config("executorch", "log_level", "Info").lower() + if raw_level == "debug": + return "Debug" + elif raw_level == "info": + return "Info" + elif raw_level == "error": + return "Error" + elif raw_level == "fatal": + return "Fatal" + else: + fail("Unknown log level '{}'. Expected one of 'Debug', 'Info', 'Error', or 'Fatal'.".format(raw_level)) + +def get_et_logging_flags(): + if et_logging_enabled(): + # On by default. + return ["-DET_MIN_LOG_LEVEL=" + et_log_level()] + else: + return ["-DET_LOG_ENABLED=0"] diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/log.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/log.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/log.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/log.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/log.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/platform.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/platform.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/platform.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/platform.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/platform.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/platform.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/platform.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/platform.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/profiler.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/profiler.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/profiler.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/profiler.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/profiler.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/profiler.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/profiler.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/profiler.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/runtime.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/runtime.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/runtime.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/runtime.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/runtime.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/runtime.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/runtime.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/runtime.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/system.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/system.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/system.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/system.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/targets.bzl new file mode 100644 index 0000000..65d92b1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/targets.bzl @@ -0,0 +1,120 @@ +load("@fbsource//xplat/executorch/build:build_variables.bzl", "PLATFORM_SRCS") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load(":log.bzl", "get_et_logging_flags") + +def _select_pal(dict_): + """Returns an element of `dict_` based on the value of the + `executorch.pal_default` build config value. Fails if no corresponding entry + exists. + """ + pal_default = native.read_config("executorch", "pal_default", "posix") + if not pal_default in dict_: + fail("Missing key for executorch.pal_default value '{}' in dict '{}'".format(pal_default, dict_)) + return dict_[pal_default] + +def profiling_enabled(): + return native.read_config("executorch", "prof_enabled", "false") == "true" + +def get_profiling_flags(): + profiling_flags = [] + if profiling_enabled(): + profiling_flags += ["-DPROFILING_ENABLED"] + prof_buf_size = native.read_config("executorch", "prof_buf_size", None) + if prof_buf_size != None: + if not profiling_enabled(): + fail("Cannot set profiling buffer size without enabling profiling first.") + profiling_flags += ["-DMAX_PROFILE_EVENTS={}".format(prof_buf_size), "-DMAX_MEM_PROFILE_EVENTS={}".format(prof_buf_size)] + num_prof_blocks = native.read_config("executorch", "num_prof_blocks", None) + if num_prof_blocks != None: + if not profiling_enabled(): + fail("Cannot configure number of profiling blocks without enabling profiling first.") + profiling_flags += ["-DMAX_PROFILE_BLOCKS={}".format(num_prof_blocks)] + return profiling_flags + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Default implementations of pal functions. These are weak symbols, so + # client defined implementations will overide them. + runtime.cxx_library( + name = "platform_private", + srcs = select({ + "ovr_config//os:android": ["default/android.cpp"], + "DEFAULT": _select_pal({ + "minimal": ["default/minimal.cpp"], + "posix": ["default/posix.cpp"], + })}), + deps = [ + ":pal_interface", + ], + external_deps = ["log"], + visibility = [ + "//executorch/core/...", + ], + # WARNING: using a deprecated API to avoid being built into a shared + # library. In the case of dynamically loading .so library we don't want + # it to depend on other .so libraries because that way we have to + # specify library directory path. + force_static = True, + ) + + # Interfaces for executorch users + runtime.cxx_library( + name = "platform", + exported_headers = [ + "abort.h", + "assert.h", + "clock.h", + "log.h", + "profiler.h", + "runtime.h", + "compat_unistd.h", + ], + srcs = PLATFORM_SRCS, + exported_preprocessor_flags = get_profiling_flags() + get_et_logging_flags(), + exported_deps = [ + "//executorch/runtime/platform:pal_interface", + ":compiler", + ":platform_private", + ], + visibility = ["PUBLIC"], + # WARNING: using a deprecated API to avoid being built into a shared + # library. In the case of dynamically loading so library we don't want + # it to depend on other so libraries because that way we have to + # specify library directory path. + force_static = True, + ) + + # Library for backend implementers to define implementations against. + runtime.cxx_library( + name = "pal_interface", + exported_headers = [ + "platform.h", + "system.h", + "types.h", + ], + exported_deps = [ + ":compiler", + ], + exported_preprocessor_flags = select( + { + "DEFAULT": [], + "ovr_config//os:linux": ["-DET_USE_LIBDL"], + "ovr_config//os:macos": ["-DET_USE_LIBDL"], + }, + ), + visibility = ["PUBLIC"], + ) + + # Common compiler directives such as 'unlikely' or 'deprecated' + runtime.cxx_library( + name = "compiler", + exported_headers = [ + "compiler.h", + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/CMakeLists.txt new file mode 100644 index 0000000..dd480ee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +et_cxx_test(platform_test SOURCES executor_pal_test.cpp) + +et_cxx_test( + platform_runtime_override_test SOURCES executor_pal_runtime_override_test.cpp + stub_platform.cpp +) + +et_cxx_test( + platform_static_runtime_override_test SOURCES + executor_pal_static_runtime_override_test.cpp +) + +# TODO: Re-enable this test on OSS +# +# et_cxx_test(platform_death_test SOURCES executor_pal_death_test.cpp) + +# No weak function symbols on Windows/MSVC, thus PAL intercept doesn't work. +# Skip logging tests in Release mode. +if(NOT WIN32 AND NOT CMAKE_BUILD_TYPE STREQUAL "Release") + et_cxx_test(logging_test SOURCES logging_test.cpp stub_platform.cpp) + set_source_files_properties( + logging_test.cpp PROPERTIES COMPILE_DEFINITIONS "ET_MIN_LOG_LEVEL=Debug" + ) +endif() + +# TODO: Re-enable this test on OSS +# +# et_cxx_test(clock_test SOURCES clock_test.cpp stub_platform.cpp) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/clock_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/clock_test.cpp new file mode 100644 index 0000000..396a4a4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/clock_test.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +using namespace ::testing; + +class PalSpy : public PlatformIntercept { + public: + et_tick_ratio_t ticks_to_ns_multiplier() override { + return tick_ns_multiplier; + } + + et_tick_ratio_t tick_ns_multiplier = {1, 1}; +}; + +TEST(ClockTest, ConvertTicksToNsSanity) { + PalSpy spy; + InterceptWith iw(spy); + + spy.tick_ns_multiplier = {3, 2}; + auto ns = executorch::runtime::ticks_to_ns(10); + ASSERT_EQ(15, ns); // 10 ticks * 3/2 = 15 ns + + spy.tick_ns_multiplier = {2, 7}; + ns = executorch::runtime::ticks_to_ns(14); + ASSERT_EQ(4, ns); // 14 ticks * 2/7 = 4 ns +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_death_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_death_test.cpp new file mode 100644 index 0000000..dba38ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_death_test.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +TEST(ExecutorPalTest, UninitializedPalDeath) { + // Check for assertion failure on debug builds. + +#ifndef NDEBUG + + ET_EXPECT_DEATH({ et_pal_current_ticks(); }, ""); + + ET_EXPECT_DEATH( + { + et_pal_emit_log_message( + 0, et_pal_log_level_t::kFatal, "", "", 0, "", 0); + }, + ""); + +#endif // !defined(NDEBUG) +} + +/// Override the default weak main declaration. +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + // Purposefully do not initialize the PAL. + return RUN_ALL_TESTS(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_override_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_override_test.cpp new file mode 100644 index 0000000..07cf749 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_override_test.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::LogLevel; + +// Demonstrate what would happen if we didn't intercept the PAL calls. +TEST(ExecutorPalOverrideTest, DiesIfNotIntercepted) { + ET_EXPECT_DEATH( + executorch::runtime::runtime_init(), + "et_pal_init call was not intercepted"); +} + +TEST(ExecutorPalOverrideTest, InitIsRegistered) { + PalSpy spy; + InterceptWith iw(spy); + + EXPECT_EQ(spy.init_call_count, 0); + executorch::runtime::runtime_init(); + EXPECT_EQ(spy.init_call_count, 1); +} + +#if ET_LOG_ENABLED +TEST(ExecutorPalOverrideTest, LogSmokeTest) { + PalSpy spy; + InterceptWith iw(spy); + + EXPECT_EQ(spy.current_ticks_call_count, 0); + EXPECT_EQ(spy.emit_log_message_call_count, 0); + + // Use the highest log level, which isn't likely to be disabled. + ASSERT_GE(LogLevel::Fatal, LogLevel::ET_MIN_LOG_LEVEL); + ET_LOG(Fatal, "Test log"); + + EXPECT_EQ(spy.emit_log_message_call_count, 1); + // Logging a message should also cause et_pal_current_ticks to be called once. + EXPECT_EQ(spy.current_ticks_call_count, 1); + + const auto& args = spy.last_log_message_args; + EXPECT_EQ(args.timestamp, PalSpy::kTimestamp); + EXPECT_EQ(args.level, et_pal_log_level_t::kFatal); + // Ignore filename/function/line to avoid fragility. + EXPECT_EQ(args.message, "Test log"); + EXPECT_EQ(args.length, sizeof("Test log") - 1); +} + +TEST(ExecutorPalOverrideTest, LogLevels) { + PalSpy spy; + InterceptWith iw(spy); + const auto& args = spy.last_log_message_args; + + // Test all log levels. Demonstrates the mapping between LogLevel and + // et_pal_log_level_t. + if (LogLevel::Debug >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Debug, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kDebug); + } + + if (LogLevel::Info >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Info, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kInfo); + } + + if (LogLevel::Error >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Error, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kError); + } + + if (LogLevel::Fatal >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Fatal, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kFatal); + } + + // An invalid LogLevel should map to kUnknown. + ET_LOG(NumLevels, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kUnknown); +} + +TEST(ExecutorPalOverrideTest, TickToNsMultiplier) { + PalSpy spy; + InterceptWith iw(spy); + + // Validate that tick to ns multipliers are overridden. + spy.tick_ns_multiplier = {2, 3}; + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().numerator, 2); + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().denominator, 3); + + spy.tick_ns_multiplier = {3, 1}; + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().numerator, 3); + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().denominator, 1); +} + +TEST(ExecutorPalOverrideTest, AllocateSmokeTest) { + PalSpy spy; + InterceptWith iw(spy); + + // Validate that et_pal_allocate is overridden. + EXPECT_EQ(spy.allocate_call_count, 0); + EXPECT_EQ(spy.last_allocated_ptr, nullptr); + et_pal_allocate(4); + EXPECT_EQ(spy.allocate_call_count, 1); + EXPECT_EQ(spy.last_allocated_size, 4); + EXPECT_EQ(spy.last_allocated_ptr, (void*)0x1234); +} + +TEST(ExecutorPalOverrideTest, FreeSmokeTest) { + PalSpy spy; + InterceptWith iw(spy); + + et_pal_allocate(4); + EXPECT_EQ(spy.last_allocated_size, 4); + EXPECT_EQ(spy.last_allocated_ptr, (void*)0x1234); + + // Validate that et_pal_free is overridden. + EXPECT_EQ(spy.free_call_count, 0); + EXPECT_EQ(spy.last_freed_ptr, nullptr); + et_pal_free(spy.last_allocated_ptr); + EXPECT_EQ(spy.free_call_count, 1); + EXPECT_EQ(spy.last_freed_ptr, (void*)0x1234); +} + +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_runtime_override_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_runtime_override_test.cpp new file mode 100644 index 0000000..ee0526a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_runtime_override_test.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +namespace { +PalSpy* active_spy; + +void pal_init(void) { + active_spy->init(); +} + +et_timestamp_t pal_current_ticks(void) { + return active_spy->current_ticks(); +} + +et_tick_ratio_t pal_ticks_to_ns_multiplier(void) { + return active_spy->ticks_to_ns_multiplier(); +} + +void pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + ET_UNUSED const char* function, + size_t line, + const char* message, + ET_UNUSED size_t length) { + active_spy->emit_log_message( + timestamp, level, filename, function, line, message, length); +} + +void* pal_allocate(size_t size) { + return active_spy->allocate(size); +} + +void pal_free(void* ptr) { + active_spy->free(ptr); +} +} // namespace + +class RuntimePalOverrideTest : public ::testing::Test { + protected: + void SetUp() override { + // Capture the current PAL implementation so that it can be restored + // after the test. + _original_pal_impl = *executorch::runtime::get_pal_impl(); + } + + void TearDown() override { + // Restore the original PAL implementation. + + // This is a slightly hacky way to allow this test to exist alongside + // the executor_pal_override_test, which provides a build-time override + // for et_pal_init. This implementation asserts that an intercept exists. + // Since register_pal calls init, we need to make sure that an intercept + // is registered. It will be deregistered when it goes out of scope, + // allowing the tests to run in any order. + InterceptWith iw(_spy); + auto success = executorch::runtime::register_pal(_original_pal_impl); + if (!success) { + throw std::runtime_error("Failed to restore PAL implementation."); + } + } + + void RegisterSpy() { + active_spy = &_spy; + + executorch::runtime::register_pal(executorch::runtime::PalImpl::create( + pal_init, + nullptr, // abort + pal_current_ticks, + pal_ticks_to_ns_multiplier, + pal_emit_log_message, + pal_allocate, + pal_free, + __FILE__)); + } + + PalSpy _spy; + + private: + // The PAL implementation at the time of setup. + executorch::runtime::PalImpl _original_pal_impl; +}; + +TEST_F(RuntimePalOverrideTest, SmokeTest) { + EXPECT_EQ(_spy.init_call_count, 0); + EXPECT_EQ(_spy.current_ticks_call_count, 0); + EXPECT_EQ(_spy.allocate_call_count, 0); + EXPECT_EQ(_spy.free_call_count, 0); + + RegisterSpy(); + + // Expect register to call init. + EXPECT_EQ(_spy.init_call_count, 1); + + EXPECT_EQ(executorch::runtime::pal_current_ticks(), 1234); + EXPECT_EQ(_spy.current_ticks_call_count, 1); + + et_tick_ratio_t ticks_to_ns_multiplier = + executorch::runtime::pal_ticks_to_ns_multiplier(); + EXPECT_EQ(ticks_to_ns_multiplier.numerator, 1); + EXPECT_EQ(ticks_to_ns_multiplier.denominator, 1); + + executorch::runtime::pal_emit_log_message( + 5, kError, "test.cpp", "test_function", 6, "test message", 7); + EXPECT_EQ(_spy.emit_log_message_call_count, 1); + EXPECT_EQ(_spy.last_log_message_args.timestamp, 5); + EXPECT_EQ(_spy.last_log_message_args.level, kError); + EXPECT_EQ(_spy.last_log_message_args.filename, "test.cpp"); + EXPECT_EQ(_spy.last_log_message_args.function, "test_function"); + EXPECT_EQ(_spy.last_log_message_args.line, 6); + EXPECT_EQ(_spy.last_log_message_args.message, "test message"); + EXPECT_EQ(_spy.last_log_message_args.length, 7); + + executorch::runtime::pal_allocate(16); + EXPECT_EQ(_spy.allocate_call_count, 1); + + executorch::runtime::pal_free(nullptr); + EXPECT_EQ(_spy.free_call_count, 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_static_runtime_override_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_static_runtime_override_test.cpp new file mode 100644 index 0000000..baf5da5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_static_runtime_override_test.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +namespace { +PalSpy spy = PalSpy(); + +void pal_init(void) { + spy.init(); +} + +et_timestamp_t pal_current_ticks(void) { + return spy.current_ticks(); +} + +et_tick_ratio_t pal_ticks_to_ns_multiplier(void) { + return spy.ticks_to_ns_multiplier(); +} + +void pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + ET_UNUSED const char* function, + size_t line, + const char* message, + ET_UNUSED size_t length) { + spy.emit_log_message( + timestamp, level, filename, function, line, message, length); +} + +void* pal_allocate(size_t size) { + return spy.allocate(size); +} + +void pal_free(void* ptr) { + spy.free(ptr); +} + +// Statically register PAL impleementation. +bool registration_result = + executorch::runtime::register_pal(executorch::runtime::PalImpl::create( + pal_init, + nullptr, // abort + pal_current_ticks, + pal_ticks_to_ns_multiplier, + pal_emit_log_message, + pal_allocate, + pal_free, + __FILE__)); +} // namespace + +TEST(RuntimePalOverrideTest, SmokeTest) { + EXPECT_EQ(spy.current_ticks_call_count, 0); + EXPECT_EQ(spy.allocate_call_count, 0); + EXPECT_EQ(spy.free_call_count, 0); + + // Expect registration to call init. + EXPECT_EQ(spy.init_call_count, 1); + + EXPECT_EQ(executorch::runtime::pal_current_ticks(), 1234); + EXPECT_EQ(spy.current_ticks_call_count, 1); + + et_tick_ratio_t ticks_to_ns_multiplier = + executorch::runtime::pal_ticks_to_ns_multiplier(); + EXPECT_EQ(ticks_to_ns_multiplier.numerator, 1); + EXPECT_EQ(ticks_to_ns_multiplier.denominator, 1); + + executorch::runtime::pal_emit_log_message( + 5, kError, "test.cpp", "test_function", 6, "test message", 7); + EXPECT_EQ(spy.emit_log_message_call_count, 1); + EXPECT_EQ(spy.last_log_message_args.timestamp, 5); + EXPECT_EQ(spy.last_log_message_args.level, kError); + EXPECT_EQ(spy.last_log_message_args.filename, "test.cpp"); + EXPECT_EQ(spy.last_log_message_args.function, "test_function"); + EXPECT_EQ(spy.last_log_message_args.line, 6); + EXPECT_EQ(spy.last_log_message_args.message, "test message"); + EXPECT_EQ(spy.last_log_message_args.length, 7); + + executorch::runtime::pal_allocate(16); + EXPECT_EQ(spy.allocate_call_count, 1); + + executorch::runtime::pal_free(nullptr); + EXPECT_EQ(spy.free_call_count, 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_test.cpp new file mode 100644 index 0000000..51a0aaf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/executor_pal_test.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +TEST(ExecutorPalTest, Initialization) { + /* + * Ensure `et_pal_init` can be called multiple times. + * It has already been called once in the main() function. + */ + et_pal_init(); +} + +TEST(ExecutorPalTest, TimestampCoherency) { + et_pal_init(); + + et_timestamp_t time_a = et_pal_current_ticks(); + ASSERT_TRUE(time_a >= 0); + + et_timestamp_t time_b = et_pal_current_ticks(); + ASSERT_TRUE(time_b >= time_a); +} + +TEST(ExecutorPalTest, TickRateRatioSanity) { + auto tick_ns_ratio = et_pal_ticks_to_ns_multiplier(); + ASSERT_TRUE(tick_ns_ratio.numerator > 0); + ASSERT_TRUE(tick_ns_ratio.denominator > 0); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/logging_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/logging_test.cpp new file mode 100644 index 0000000..3ddc506 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/logging_test.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include + +using namespace executorch::runtime; + +class LoggingTest : public ::testing::Test {}; + +TEST_F(LoggingTest, LogLevels) { + PalSpy spy; + InterceptWith iw(spy); + + ET_LOG(Debug, "Debug log."); + EXPECT_EQ(spy.last_log_message_args.message, "Debug log."); + + ET_LOG(Info, "Info log."); + EXPECT_EQ(spy.last_log_message_args.message, "Info log."); + + ET_LOG(Error, "Error log."); + EXPECT_EQ(spy.last_log_message_args.message, "Error log."); + + ET_LOG(Fatal, "Fatal log."); + EXPECT_EQ(spy.last_log_message_args.message, "Fatal log."); +} + +TEST_F(LoggingTest, LogFormatting) { + PalSpy spy; + InterceptWith iw(spy); + + ET_LOG(Info, "Sample log with integer: %u", 100); + EXPECT_EQ(spy.last_log_message_args.message, "Sample log with integer: 100"); +} + +static std::string get_prefix(std::size_t length, bool use_multibyte) { + if (!use_multibyte) { + return std::string(length, 'A'); + } + std::ostringstream result; + result << std::string(length % 4, 'A'); + std::size_t remaining = length - (length % 4); + while (remaining > 0) { + result << "\xF0\x9F\x91\x8D"; + remaining -= 4; + } + return result.str(); +} + +TEST_F(LoggingTest, Utf8Truncation) { + PalSpy spy; + InterceptWith iw(spy); + + const char euro[] = "\xE2\x82\xAC"; + const char thumbs_up[] = "\xF0\x9F\x91\x8D"; + const char e_acute[] = "\xC3\xA9"; + const char capital_a_tilde[] = "\xC3\x83"; + + struct TruncCase { + size_t prefix_length; + const char* codepoint; + }; + const TruncCase cases[] = { + {253, euro}, + {252, thumbs_up}, + {254, e_acute}, + {254, capital_a_tilde}, + }; + for (bool use_multibyte_prefix : {false, true}) { + for (const auto& c : cases) { + const std::string prefix = + get_prefix(c.prefix_length, use_multibyte_prefix); + const std::string suffix = "_SHOULD_BE_CUT"; + ET_LOG(Info, "%s%s%s", prefix.c_str(), c.codepoint, suffix.c_str()); + EXPECT_EQ(spy.last_log_message_args.message, prefix); + EXPECT_EQ(spy.last_log_message_args.length, prefix.size()); + } + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/pal_spy.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/pal_spy.h new file mode 100644 index 0000000..5831ba1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/pal_spy.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include + +class PalSpy : public PlatformIntercept { + public: + PalSpy() = default; + + void init() override { + ++init_call_count; + } + + static constexpr et_timestamp_t kTimestamp = 1234; + + et_timestamp_t current_ticks() override { + ++current_ticks_call_count; + return kTimestamp; + } + + et_tick_ratio_t ticks_to_ns_multiplier() override { + return tick_ns_multiplier; + } + + void emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + const char* function, + size_t line, + const char* message, + size_t length) override { + ++emit_log_message_call_count; + last_log_message_args.timestamp = timestamp; + last_log_message_args.level = level; + last_log_message_args.filename = filename; + last_log_message_args.function = function; + last_log_message_args.line = line; + last_log_message_args.message = message; + last_log_message_args.length = length; + } + + void* allocate(size_t size) override { + ++allocate_call_count; + last_allocated_size = size; + last_allocated_ptr = (void*)0x1234; + return nullptr; + } + + void free(void* ptr) override { + ++free_call_count; + last_freed_ptr = ptr; + } + + virtual ~PalSpy() = default; + + size_t init_call_count = 0; + size_t current_ticks_call_count = 0; + size_t emit_log_message_call_count = 0; + et_tick_ratio_t tick_ns_multiplier = {1, 1}; + size_t allocate_call_count = 0; + size_t free_call_count = 0; + size_t last_allocated_size = 0; + void* last_allocated_ptr = nullptr; + void* last_freed_ptr = nullptr; + + /// The args that were passed to the most recent call to emit_log_message(). + struct { + et_timestamp_t timestamp; + et_pal_log_level_t level; + std::string filename; // Copy of the char* to avoid lifetime issues. + std::string function; + size_t line; + std::string message; + size_t length; + } last_log_message_args = {}; +}; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.cpp new file mode 100644 index 0000000..8cee404 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +/** + * @file + * An implementation of the PAL to help with testing. + */ + +static PlatformIntercept* platform_intercept; + +void InterceptWith::install(PlatformIntercept* pi) { + platform_intercept = pi; +} + +/// Prints a message and aborts if an intercept is not installed. +#define ASSERT_INTERCEPT_INSTALLED() \ + ({ \ + if (platform_intercept == nullptr) { \ + fprintf(stderr, "%s call was not intercepted\n", ET_FUNCTION); \ + fflush(stderr); \ + __builtin_trap(); \ + } \ + }) + +extern "C" { + +void et_pal_init(void) { + ASSERT_INTERCEPT_INSTALLED(); + platform_intercept->init(); +} + +ET_NORETURN void et_pal_abort(void) { + ASSERT_INTERCEPT_INSTALLED(); + // We can't properly intercept this since it's marked NORETURN. + fprintf(stderr, "StubPlatform et_pal_abort called\n"); + fflush(stderr); + __builtin_trap(); +} + +et_timestamp_t et_pal_current_ticks(void) { + ASSERT_INTERCEPT_INSTALLED(); + return platform_intercept->current_ticks(); +} + +et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) { + ASSERT_INTERCEPT_INSTALLED(); + return platform_intercept->ticks_to_ns_multiplier(); +} + +void et_pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + ET_UNUSED const char* function, + size_t line, + const char* message, + ET_UNUSED size_t length) { + ASSERT_INTERCEPT_INSTALLED(); + platform_intercept->emit_log_message( + timestamp, level, filename, function, line, message, length); +} + +void* et_pal_allocate(size_t size) { + ASSERT_INTERCEPT_INSTALLED(); + return platform_intercept->allocate(size); +} + +void et_pal_free(void* ptr) { + ASSERT_INTERCEPT_INSTALLED(); + platform_intercept->free(ptr); +} + +} // extern "C" + +#include + +// Use a version of main() that does not call runtime_init(). +// +// By default, executorch tests are built with a main() that calls +// runtime_init(), and ultimately et_pal_init(). The StubPlatform override of +// et_pal_init() will fail if it isn't intercepted, so we can't call it at start +// time. +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + // Purposefully do not initialize the PAL. + return RUN_ALL_TESTS(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.h new file mode 100644 index 0000000..de5599b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/stub_platform.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include + +/** + * An interface for intercepting calls to the PAL layer. + */ +class PlatformIntercept { + public: + PlatformIntercept() = default; + + /// Called when et_pal_init() is called. + virtual void init() {} + + // We can't intercept et_pal_abort() since it's marked NORETURN. + + /// Called when et_pal_current_ticks() is called. + virtual et_timestamp_t current_ticks() { + return 0; + } + + virtual et_tick_ratio_t ticks_to_ns_multiplier() { + return {1, 1}; + } + + /// Called when et_pal_emit_log_message() is called. + virtual void emit_log_message( + ET_UNUSED et_timestamp_t timestamp, + ET_UNUSED et_pal_log_level_t level, + ET_UNUSED const char* filename, + ET_UNUSED const char* function, + ET_UNUSED size_t line, + ET_UNUSED const char* message, + ET_UNUSED size_t length) {} + + virtual void* allocate(ET_UNUSED size_t size) { + return nullptr; + } + + virtual void free(ET_UNUSED void* ptr) {} + + virtual ~PlatformIntercept() = default; +}; + +/** + * RAII type to install a PlatformIntercept for the duration of a test case. + */ +class InterceptWith { + public: + explicit InterceptWith(PlatformIntercept& pi) { + InterceptWith::install(&pi); + } + + ~InterceptWith() { + InterceptWith::install(nullptr); + } + + private: + /** + * Installs the PlatformIntercept to forward to when et_pal_* functions are + * called. To uninstall, pass in `nullptr`. + */ + static void install(PlatformIntercept* pi); +}; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/targets.bzl new file mode 100644 index 0000000..a5d77ef --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/test/targets.bzl @@ -0,0 +1,109 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "platform_test", + srcs = [ + "executor_pal_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_test( + name = "platform_death_test", + srcs = [ + "executor_pal_death_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + # This is an example of a target that provides a PAL implementation. Note + # the `link_whole = True` parameter, which is necessary to ensure that the + # symbols make their way into the top-level binary. If this target were to + # be added to a library instead of directly to a binary, it would need to be + # in that library's `exported_deps`. + runtime.cxx_library( + name = "stub_platform", + srcs = [ + "stub_platform.cpp", + ], + exported_headers = [ + "pal_spy.h", + "stub_platform.h", + ], + deps = [ + "//executorch/runtime/platform:compiler", + "//executorch/runtime/platform:platform", + "//executorch/test/utils:utils", # gtest.h + ], + visibility = [], + ) + + runtime.cxx_test( + name = "platform_override_test", + srcs = [ + "executor_pal_override_test.cpp", + ], + deps = [ + # This must come first to ensure that the weak platform + # calls are overriden. + # buildifier: do not sort + ":stub_platform", + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_test( + name = "runtime_platform_override_test", + srcs = [ + "executor_pal_runtime_override_test.cpp", + ], + deps = [ + ":stub_platform", + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_test( + name = "logging_test", + srcs = [ + "logging_test.cpp", + ], + deps = [ + ":stub_platform", + "//executorch/runtime/platform:platform", + ], + compiler_flags = [ + # Turn on debug logging. + "-DET_MIN_LOG_LEVEL=Debug", + ], + ) + + runtime.cxx_test( + name = "clock_test", + srcs = [ + "clock_test.cpp", + ], + deps = [ + # This must come first to ensure that the weak platform + # calls are overriden. + # buildifier: do not sort + ":stub_platform", + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/types.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/types.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/runtime/platform/types.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/extended_header.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/extended_header.cpp similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/extended_header.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/extended_header.cpp index 2645fb1..bd923bb 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/extended_header.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/extended_header.cpp @@ -70,11 +70,6 @@ uint64_t GetUInt64LE(const uint8_t* data) { const void* data, size_t size) { if (size < ExtendedHeader::kNumHeadBytes) { - ET_LOG( - Error, - "Extended header data size %zu < minimum %zu", - size, - ExtendedHeader::kNumHeadBytes); return Error::InvalidArgument; } const uint8_t* header = diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/extended_header.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/extended_header.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/extended_header.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/extended_header.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/program.fbs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/program.fbs similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/program.fbs rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/program.fbs index aa191e0..7308cc6 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/program.fbs +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/program.fbs @@ -1,5 +1,4 @@ // Copyright (c) Meta Platforms, Inc. and affiliates. -// Copyright 2026 Arm Limited and/or its affiliates. // // See README.md before modifying this file. @@ -62,13 +61,6 @@ enum TensorDataLocation : byte { EXTERNAL = 1, } -// Device type enum indicating where a tensor resides or should be allocated. -// Please keep this in sync with executorch/runtime/core/portable_type/device.h -enum DeviceType : byte { - CPU = 0, - CUDA = 1, -} - // Table to put additional information about tensors in that is not applicable // to the vast majority of tensors in the vast majority of programs. table ExtraTensorInfo { @@ -87,14 +79,6 @@ table ExtraTensorInfo { // must be non-empty, and is used as a key to find the tensor's external // data. Tensor.data_buffer_idx is ignored. location: TensorDataLocation; - - // [Optional] The device type where this tensor resides or should be allocated. - // Defaults to CPU for backward compatibility with existing PTE files. - device_type: DeviceType = CPU; - - // [Optional] The device index for multi-device scenarios (e.g., cuda:0, cuda:1). - // Defaults to 0 (the first device of the given type). - device_index: byte = 0; } table Tensor { @@ -125,7 +109,7 @@ table Tensor { // Overall, a Tensor is either constant or mutable. At method load time // constant tensors receive a dataptr into the serialized program. Mutable - // tensors can either receive a pointer from the hierarchical allocator or a + // tensors can either receive a pointer from the heirarchical allocator or a // nullptr if they will receive a data pointer at execution time (inputs // and control flow placeholders can be like this). Mutable tensors may or // may not also have an initial value in the serialized program. @@ -402,34 +386,9 @@ table ExecutionPlan { // constants memory buffer size, and ignore non_const_buffer_sizes[0]. non_const_buffer_sizes: [int64]; - // [Optional] Per-buffer device mapping, parallel to non_const_buffer_sizes. - // Each entry maps a non-constant buffer to the device where it should be - // allocated. For CPU-only programs, this field is absent and all buffers - // default to CPU, ensuring zero regression. - non_const_buffer_device: [NonConstBufferDevice]; - -} - -// Maps a non-constant buffer to the device where it should be allocated. -// When present as part of ExecutionPlan.non_const_buffer_device, each entry -// describes the device placement for the corresponding planned memory buffer. -// For CPU-only programs, this table is absent (all buffers default to CPU). -table NonConstBufferDevice { - // Index into the non_const_buffer_sizes list. - buffer_idx: int; - - // The device type for this buffer (CPU, CUDA, etc.). - device_type: DeviceType = CPU; - - // The device index for multi-device scenarios (e.g., cuda:0, cuda:1). - device_index: byte = 0; } // Constant tensor data stored directly in the flatbuffer. -// NOTE: If you change Buffer or BackendDelegateInlineData fields, update the -// custom packers in exir/_serialize/_flatbuffer_program.py -// (_pack_buffer and _pack_backend_delegate_inline_data); -// they override the flatc-generated packers. table Buffer { // During serialization, this alignment may be rewritten to a larger value. // The magic "@executorch-tensor-alignment" comment tells EXIR which lines to @@ -440,10 +399,6 @@ table Buffer { // Delegate data stored directly in the flatbuffer. This is a different type // than Buffer because tensors and delegates can have different alignment // requirements. -// NOTE: If you change Buffer or BackendDelegateInlineData fields, update the -// custom packers in exir/_serialize/_flatbuffer_program.py -// (_pack_buffer and _pack_backend_delegate_inline_data); -// they override the flatc-generated packers. table BackendDelegateInlineData { // During serialization, this alignment may be rewritten to a larger value. // The magic "@executorch-delegate-alignment" comment tells EXIR which lines diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/program_generated.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/program_generated.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/program_generated.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/program_generated.h index bb37bbe..f1659af 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/program_generated.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/program_generated.h @@ -104,9 +104,6 @@ struct ChainBuilder; struct ExecutionPlan; struct ExecutionPlanBuilder; -struct NonConstBufferDevice; -struct NonConstBufferDeviceBuilder; - struct Buffer; struct BufferBuilder; @@ -188,36 +185,6 @@ inline const char *EnumNameTensorDataLocation(TensorDataLocation e) { return EnumNamesTensorDataLocation()[index]; } -enum class DeviceType : int8_t { - CPU = 0, - CUDA = 1, - MIN = CPU, - MAX = CUDA -}; - -inline const DeviceType (&EnumValuesDeviceType())[2] { - static const DeviceType values[] = { - DeviceType::CPU, - DeviceType::CUDA - }; - return values; -} - -inline const char * const *EnumNamesDeviceType() { - static const char * const names[3] = { - "CPU", - "CUDA", - nullptr - }; - return names; -} - -inline const char *EnumNameDeviceType(DeviceType e) { - if (::flatbuffers::IsOutRange(e, DeviceType::CPU, DeviceType::CUDA)) return ""; - const size_t index = static_cast(e); - return EnumNamesDeviceType()[index]; -} - enum class KernelTypes : uint8_t { NONE = 0, Null = 1, @@ -603,9 +570,7 @@ struct ExtraTensorInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_MUTABLE_DATA_SEGMENTS_IDX = 4, VT_FULLY_QUALIFIED_NAME = 6, - VT_LOCATION = 8, - VT_DEVICE_TYPE = 10, - VT_DEVICE_INDEX = 12 + VT_LOCATION = 8 }; uint64_t mutable_data_segments_idx() const { return GetField(VT_MUTABLE_DATA_SEGMENTS_IDX, 0); @@ -625,26 +590,12 @@ struct ExtraTensorInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { bool mutate_location(executorch_flatbuffer::TensorDataLocation _location = static_cast(0)) { return SetField(VT_LOCATION, static_cast(_location), 0); } - executorch_flatbuffer::DeviceType device_type() const { - return static_cast(GetField(VT_DEVICE_TYPE, 0)); - } - bool mutate_device_type(executorch_flatbuffer::DeviceType _device_type = static_cast(0)) { - return SetField(VT_DEVICE_TYPE, static_cast(_device_type), 0); - } - int8_t device_index() const { - return GetField(VT_DEVICE_INDEX, 0); - } - bool mutate_device_index(int8_t _device_index = 0) { - return SetField(VT_DEVICE_INDEX, _device_index, 0); - } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_MUTABLE_DATA_SEGMENTS_IDX, 8) && VerifyOffset(verifier, VT_FULLY_QUALIFIED_NAME) && verifier.VerifyString(fully_qualified_name()) && VerifyField(verifier, VT_LOCATION, 1) && - VerifyField(verifier, VT_DEVICE_TYPE, 1) && - VerifyField(verifier, VT_DEVICE_INDEX, 1) && verifier.EndTable(); } }; @@ -662,12 +613,6 @@ struct ExtraTensorInfoBuilder { void add_location(executorch_flatbuffer::TensorDataLocation location) { fbb_.AddElement(ExtraTensorInfo::VT_LOCATION, static_cast(location), 0); } - void add_device_type(executorch_flatbuffer::DeviceType device_type) { - fbb_.AddElement(ExtraTensorInfo::VT_DEVICE_TYPE, static_cast(device_type), 0); - } - void add_device_index(int8_t device_index) { - fbb_.AddElement(ExtraTensorInfo::VT_DEVICE_INDEX, device_index, 0); - } explicit ExtraTensorInfoBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -683,14 +628,10 @@ inline ::flatbuffers::Offset CreateExtraTensorInfo( ::flatbuffers::FlatBufferBuilder &_fbb, uint64_t mutable_data_segments_idx = 0, ::flatbuffers::Offset<::flatbuffers::String> fully_qualified_name = 0, - executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT, - executorch_flatbuffer::DeviceType device_type = executorch_flatbuffer::DeviceType::CPU, - int8_t device_index = 0) { + executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT) { ExtraTensorInfoBuilder builder_(_fbb); builder_.add_mutable_data_segments_idx(mutable_data_segments_idx); builder_.add_fully_qualified_name(fully_qualified_name); - builder_.add_device_index(device_index); - builder_.add_device_type(device_type); builder_.add_location(location); return builder_.Finish(); } @@ -699,17 +640,13 @@ inline ::flatbuffers::Offset CreateExtraTensorInfoDirect( ::flatbuffers::FlatBufferBuilder &_fbb, uint64_t mutable_data_segments_idx = 0, const char *fully_qualified_name = nullptr, - executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT, - executorch_flatbuffer::DeviceType device_type = executorch_flatbuffer::DeviceType::CPU, - int8_t device_index = 0) { + executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT) { auto fully_qualified_name__ = fully_qualified_name ? _fbb.CreateString(fully_qualified_name) : 0; return executorch_flatbuffer::CreateExtraTensorInfo( _fbb, mutable_data_segments_idx, fully_qualified_name__, - location, - device_type, - device_index); + location); } struct Tensor FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { @@ -2444,8 +2381,7 @@ struct ExecutionPlan FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { VT_CHAINS = 14, VT_OPERATORS = 16, VT_DELEGATES = 18, - VT_NON_CONST_BUFFER_SIZES = 20, - VT_NON_CONST_BUFFER_DEVICE = 22 + VT_NON_CONST_BUFFER_SIZES = 20 }; const ::flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -2501,12 +2437,6 @@ struct ExecutionPlan FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { ::flatbuffers::Vector *mutable_non_const_buffer_sizes() { return GetPointer<::flatbuffers::Vector *>(VT_NON_CONST_BUFFER_SIZES); } - const ::flatbuffers::Vector<::flatbuffers::Offset> *non_const_buffer_device() const { - return GetPointer> *>(VT_NON_CONST_BUFFER_DEVICE); - } - ::flatbuffers::Vector<::flatbuffers::Offset> *mutable_non_const_buffer_device() { - return GetPointer<::flatbuffers::Vector<::flatbuffers::Offset> *>(VT_NON_CONST_BUFFER_DEVICE); - } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NAME) && @@ -2531,9 +2461,6 @@ struct ExecutionPlan FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { verifier.VerifyVectorOfTables(delegates()) && VerifyOffset(verifier, VT_NON_CONST_BUFFER_SIZES) && verifier.VerifyVector(non_const_buffer_sizes()) && - VerifyOffset(verifier, VT_NON_CONST_BUFFER_DEVICE) && - verifier.VerifyVector(non_const_buffer_device()) && - verifier.VerifyVectorOfTables(non_const_buffer_device()) && verifier.EndTable(); } }; @@ -2569,9 +2496,6 @@ struct ExecutionPlanBuilder { void add_non_const_buffer_sizes(::flatbuffers::Offset<::flatbuffers::Vector> non_const_buffer_sizes) { fbb_.AddOffset(ExecutionPlan::VT_NON_CONST_BUFFER_SIZES, non_const_buffer_sizes); } - void add_non_const_buffer_device(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> non_const_buffer_device) { - fbb_.AddOffset(ExecutionPlan::VT_NON_CONST_BUFFER_DEVICE, non_const_buffer_device); - } explicit ExecutionPlanBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -2593,10 +2517,8 @@ inline ::flatbuffers::Offset CreateExecutionPlan( ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> chains = 0, ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> operators = 0, ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> delegates = 0, - ::flatbuffers::Offset<::flatbuffers::Vector> non_const_buffer_sizes = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> non_const_buffer_device = 0) { + ::flatbuffers::Offset<::flatbuffers::Vector> non_const_buffer_sizes = 0) { ExecutionPlanBuilder builder_(_fbb); - builder_.add_non_const_buffer_device(non_const_buffer_device); builder_.add_non_const_buffer_sizes(non_const_buffer_sizes); builder_.add_delegates(delegates); builder_.add_operators(operators); @@ -2619,8 +2541,7 @@ inline ::flatbuffers::Offset CreateExecutionPlanDirect( const std::vector<::flatbuffers::Offset> *chains = nullptr, const std::vector<::flatbuffers::Offset> *operators = nullptr, const std::vector<::flatbuffers::Offset> *delegates = nullptr, - const std::vector *non_const_buffer_sizes = nullptr, - const std::vector<::flatbuffers::Offset> *non_const_buffer_device = nullptr) { + const std::vector *non_const_buffer_sizes = nullptr) { auto name__ = name ? _fbb.CreateString(name) : 0; auto values__ = values ? _fbb.CreateVector<::flatbuffers::Offset>(*values) : 0; auto inputs__ = inputs ? _fbb.CreateVector(*inputs) : 0; @@ -2629,7 +2550,6 @@ inline ::flatbuffers::Offset CreateExecutionPlanDirect( auto operators__ = operators ? _fbb.CreateVector<::flatbuffers::Offset>(*operators) : 0; auto delegates__ = delegates ? _fbb.CreateVector<::flatbuffers::Offset>(*delegates) : 0; auto non_const_buffer_sizes__ = non_const_buffer_sizes ? _fbb.CreateVector(*non_const_buffer_sizes) : 0; - auto non_const_buffer_device__ = non_const_buffer_device ? _fbb.CreateVector<::flatbuffers::Offset>(*non_const_buffer_device) : 0; return executorch_flatbuffer::CreateExecutionPlan( _fbb, name__, @@ -2640,78 +2560,7 @@ inline ::flatbuffers::Offset CreateExecutionPlanDirect( chains__, operators__, delegates__, - non_const_buffer_sizes__, - non_const_buffer_device__); -} - -struct NonConstBufferDevice FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef NonConstBufferDeviceBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_BUFFER_IDX = 4, - VT_DEVICE_TYPE = 6, - VT_DEVICE_INDEX = 8 - }; - int32_t buffer_idx() const { - return GetField(VT_BUFFER_IDX, 0); - } - bool mutate_buffer_idx(int32_t _buffer_idx = 0) { - return SetField(VT_BUFFER_IDX, _buffer_idx, 0); - } - executorch_flatbuffer::DeviceType device_type() const { - return static_cast(GetField(VT_DEVICE_TYPE, 0)); - } - bool mutate_device_type(executorch_flatbuffer::DeviceType _device_type = static_cast(0)) { - return SetField(VT_DEVICE_TYPE, static_cast(_device_type), 0); - } - int8_t device_index() const { - return GetField(VT_DEVICE_INDEX, 0); - } - bool mutate_device_index(int8_t _device_index = 0) { - return SetField(VT_DEVICE_INDEX, _device_index, 0); - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField(verifier, VT_BUFFER_IDX, 4) && - VerifyField(verifier, VT_DEVICE_TYPE, 1) && - VerifyField(verifier, VT_DEVICE_INDEX, 1) && - verifier.EndTable(); - } -}; - -struct NonConstBufferDeviceBuilder { - typedef NonConstBufferDevice Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_buffer_idx(int32_t buffer_idx) { - fbb_.AddElement(NonConstBufferDevice::VT_BUFFER_IDX, buffer_idx, 0); - } - void add_device_type(executorch_flatbuffer::DeviceType device_type) { - fbb_.AddElement(NonConstBufferDevice::VT_DEVICE_TYPE, static_cast(device_type), 0); - } - void add_device_index(int8_t device_index) { - fbb_.AddElement(NonConstBufferDevice::VT_DEVICE_INDEX, device_index, 0); - } - explicit NonConstBufferDeviceBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - return o; - } -}; - -inline ::flatbuffers::Offset CreateNonConstBufferDevice( - ::flatbuffers::FlatBufferBuilder &_fbb, - int32_t buffer_idx = 0, - executorch_flatbuffer::DeviceType device_type = executorch_flatbuffer::DeviceType::CPU, - int8_t device_index = 0) { - NonConstBufferDeviceBuilder builder_(_fbb); - builder_.add_buffer_idx(buffer_idx); - builder_.add_device_index(device_index); - builder_.add_device_type(device_type); - return builder_.Finish(); + non_const_buffer_sizes__); } struct Buffer FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/scalar_type.fbs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/scalar_type.fbs similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/scalar_type.fbs rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/scalar_type.fbs index 47e3386..e9c830b 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/scalar_type.fbs +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/scalar_type.fbs @@ -21,7 +21,6 @@ enum ScalarType : byte { QINT8 = 12, QUINT8 = 13, QINT32 = 14, - BFLOAT16 = 15, QUINT4X2 = 16, QUINT2X4 = 17, BITS16 = 22, @@ -36,6 +35,7 @@ enum ScalarType : byte { // COMPLEXHALF = 8, // COMPLEXFLOAT = 9, // COMPLEXDOUBLE = 10, + // BFLOAT16 = 15, // BITS1x8 = 18, // BITS2x4 = 19, // BITS4x2 = 20, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/scalar_type_generated.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/scalar_type_generated.h similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/scalar_type_generated.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/scalar_type_generated.h index 06b7460..56f5062 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/scalar_type_generated.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/executorch/schema/scalar_type_generated.h @@ -28,7 +28,6 @@ enum class ScalarType : int8_t { QINT8 = 12, QUINT8 = 13, QINT32 = 14, - BFLOAT16 = 15, QUINT4X2 = 16, QUINT2X4 = 17, BITS16 = 22, @@ -43,7 +42,7 @@ enum class ScalarType : int8_t { MAX = UINT64 }; -inline const ScalarType (&EnumValuesScalarType())[23] { +inline const ScalarType (&EnumValuesScalarType())[22] { static const ScalarType values[] = { ScalarType::BYTE, ScalarType::CHAR, @@ -57,7 +56,6 @@ inline const ScalarType (&EnumValuesScalarType())[23] { ScalarType::QINT8, ScalarType::QUINT8, ScalarType::QINT32, - ScalarType::BFLOAT16, ScalarType::QUINT4X2, ScalarType::QUINT2X4, ScalarType::BITS16, @@ -89,7 +87,7 @@ inline const char * const *EnumNamesScalarType() { "QINT8", "QUINT8", "QINT32", - "BFLOAT16", + "", "QUINT4X2", "QUINT2X4", "", diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/array.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/array.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/array.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/array.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/base.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/base.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/base.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/base.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/buffer.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/buffer.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/buffer.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/buffer.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/buffer_ref.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/buffer_ref.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/buffer_ref.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/buffer_ref.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/code_generator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/code_generator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/code_generator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/code_generator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/code_generators.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/code_generators.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/code_generators.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/code_generators.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/default_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/default_allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/default_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/default_allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/detached_buffer.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/detached_buffer.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/detached_buffer.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/detached_buffer.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/file_manager.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/file_manager.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/file_manager.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/file_manager.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flatbuffer_builder.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flatbuffer_builder.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flatbuffer_builder.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flatbuffer_builder.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flatbuffers.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flatbuffers.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flatbuffers.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flatbuffers.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flatc.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flatc.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flatc.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flatc.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flex_flat_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flex_flat_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flex_flat_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flex_flat_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flexbuffers.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flexbuffers.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/flexbuffers.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/flexbuffers.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/grpc.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/grpc.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/grpc.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/grpc.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/hash.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/hash.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/hash.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/hash.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/idl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/idl.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/idl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/idl.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/minireflect.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/minireflect.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/minireflect.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/minireflect.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/pch/flatc_pch.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/pch/flatc_pch.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/pch/flatc_pch.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/pch/flatc_pch.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/pch/pch.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/pch/pch.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/pch/pch.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/pch/pch.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/reflection.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/reflection.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/reflection.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/reflection.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/reflection_generated.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/reflection_generated.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/reflection_generated.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/reflection_generated.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/registry.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/registry.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/registry.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/registry.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/stl_emulation.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/stl_emulation.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/stl_emulation.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/stl_emulation.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/string.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/string.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/string.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/string.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/struct.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/struct.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/struct.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/struct.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/table.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/table.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/table.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/table.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/vector.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/vector.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/vector.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/vector.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/vector_downward.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/vector_downward.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/vector_downward.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/vector_downward.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/verifier.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/verifier.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/flatbuffers/verifier.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/flatbuffers/verifier.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/TARGETS new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/TARGETS @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/macros/Export.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/macros/Export.h index 14b26c1..8dd2541 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/macros/Export.h @@ -130,6 +130,14 @@ #define TORCH_CUDA_CU_API C10_IMPORT #endif +#if defined(TORCH_HIP_BUILD_MAIN_LIB) +#define TORCH_HIP_CPP_API C10_EXPORT +#define TORCH_HIP_API C10_EXPORT +#else +#define TORCH_HIP_CPP_API C10_IMPORT +#define TORCH_HIP_API C10_IMPORT +#endif + #if defined(TORCH_XPU_BUILD_MAIN_LIB) #define TORCH_XPU_API C10_EXPORT #else diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/macros/Macros.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/macros/Macros.h similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/macros/Macros.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/macros/Macros.h index cef99df..63aa0d2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/macros/Macros.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/macros/Macros.h @@ -325,88 +325,41 @@ constexpr uint32_t CUDA_THREADS_PER_BLOCK_FALLBACK = 256; #define C10_HIP_HOST_DEVICE #endif +#if defined(USE_ROCM) // C10_WARP_SIZE is only allowed for device code. -// Host code dynamically-sized launch configs _must_ use at::cuda::warp_size(). -// Host or device statically-sized arrays _must_ use either -// C10_WARP_SIZE_UPPER_BOUND or C10_WARP_SIZE_LOWER_BOUND, as needed. -// +// Host code _must_ use at::cuda::warp_size() // HIP header used to define warpSize as a constexpr that was either 32 or 64 // depending on the target device, and then always set it to 64 for host code. -// For a time, that allowed C10_WARP_SIZE to be defined like so: -// -// #ifdef USE_ROCM -// #define C10_WARP_SIZE warpSize -// #else -// #define C10_WARP_SIZE 32 -// #endif -// -// In ROCm 7, warpSize is no longer constexpr, matching CUDA behavior. -// We can now only use warpSize for C10_WARP_SIZE in device code and this is -// enforced by using __device__ in its definition. In host code where -// C10_WARP_SIZE was previously used as a compile-time constant, this will now -// cause a compile-time error. -// -// If an array was previously expected to be sized at compile-time using -// C10_WARP_SIZE, users must now use either C10_WARP_SIZE_UPPER_BOUND or -// C10_WARP_SIZE_LOWER_BOUND depending on the situation. -// -// If C10_WARP_SIZE was previously used to determine kernel launch sizes, users -// must now use at::cuda::warp_size() for the dynamic runtime query. -// -// Unfortunately, C10_WARP_SIZE has been public and available for both host and -// device since approximately 2019, so forcing it to be device-only would break -// existing code in the wild. -#if defined(USE_ROCM) +// Host pass of HIP compiler needs C10_WARP_SIZE defined to _something_ so we +// set it to something unreasonable to trigger obvious host code errors. + namespace at::cuda { TORCH_CUDA_CPP_API int warp_size(); } -#if defined(__HIPCC__) -static __host__ inline int C10_WARP_SIZE_INTERNAL() { +#ifdef __HIPCC__ +static inline int __host__ C10_WARP_SIZE_INTERNAL() { return at::cuda::warp_size(); } -// NOTE: __device__ C10_WARP_SIZE_INTERNAL -// For __SPIRV__, we must use dynamic warpSize. When not targeting __SPIRV__, -// we can use constexpr. This matches prior behavior. We preserve this for -// backward compatibility instead of forcing old code to use dynamic warpSize -// and losing constexpr. However, compiling for --offload-arch=amdgcnspirv -// could expose where C10_WARP_SIZE was used incorrectly where the dynamic -// warpSize is not allowed. -#if defined(__SPIRV__) -static __device__ inline int C10_WARP_SIZE_INTERNAL() { - return warpSize; -} -#else // __SPIRV__ -static __device__ inline constexpr int C10_WARP_SIZE_INTERNAL() { + +static inline constexpr int __device__ C10_WARP_SIZE_INTERNAL() { #if defined(__GFX9__) return 64; #else // __GFX9__ return 32; #endif // __GFX9__ } -#endif // __SPIRV__ -#if defined(__SPIRV__) -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 64 -#elif defined(__GFX9__) -#define C10_WARP_SIZE_LOWER_BOUND 64 -#define C10_WARP_SIZE_UPPER_BOUND 64 -#else -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 32 -#endif -#else // !__HIPCC__ +#else // __HIPCC__ static inline int C10_WARP_SIZE_INTERNAL() { return at::cuda::warp_size(); } -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 64 #endif // __HIPCC__ + #define C10_WARP_SIZE (C10_WARP_SIZE_INTERNAL()) -#else // !USE_ROCM +#define C10_WARP_SIZE_STATIC 64 + +#else // defined(USE_ROCM) #define C10_WARP_SIZE 32 -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 32 -#endif // USE_ROCM +#endif #if defined(_MSC_VER) && _MSC_VER <= 1900 #define __func__ __FUNCTION__ @@ -676,7 +629,7 @@ __host__ __device__ // This macro is used to find older C++ compilers // that don't support move optimization for return values. -#if (defined(__GNUC__) && __GNUC__ < 13 && __cplusplus < 202002L) || \ +#if (defined(__GNUC__) && __GNUC__ < 13) || \ (defined(__clang_major__) && __clang_major__ < 13) #define C10_RETURN_MOVE_IF_OLD_COMPILER 1 #else diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/targets.bzl new file mode 100644 index 0000000..0ddce72 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/targets.bzl @@ -0,0 +1,14 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "torch_headeronly", + exported_headers = glob(["**/*.h"]), + header_namespace = "torch/headeronly", + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/BFloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/BFloat16.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/BFloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/BFloat16.h index 9aa08c2..64479ba 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/BFloat16.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/BFloat16.h @@ -12,7 +12,7 @@ #include #include -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) #include #endif @@ -46,7 +46,7 @@ struct alignas(2) BFloat16 { /* implicit */ inline C10_HOST_DEVICE BFloat16(float value); inline C10_HOST_DEVICE operator float() const; -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) inline C10_HOST_DEVICE BFloat16(const __nv_bfloat16& value); explicit inline C10_HOST_DEVICE operator __nv_bfloat16() const; #endif @@ -124,9 +124,8 @@ C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") /// Constructors inline C10_HOST_DEVICE BFloat16::BFloat16(float value) : -#if defined(__CUDACC__) && \ - (!defined(USE_ROCM) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 || \ - defined(USE_ROCM) && (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) && defined(__CUDA_ARCH__) && \ + __CUDA_ARCH__ >= 800 x(__bfloat16_as_ushort(__float2bfloat16(value))) #elif defined(__SYCL_DEVICE_ONLY__) && \ defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) @@ -140,7 +139,7 @@ inline C10_HOST_DEVICE BFloat16::BFloat16(float value) /// Implicit conversions inline C10_HOST_DEVICE BFloat16::operator float() const { -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) return __bfloat162float(*reinterpret_cast(&x)); #elif defined(__SYCL_DEVICE_ONLY__) && \ defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) @@ -150,7 +149,7 @@ inline C10_HOST_DEVICE BFloat16::operator float() const { #endif } -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) inline C10_HOST_DEVICE BFloat16::BFloat16(const __nv_bfloat16& value) { x = *reinterpret_cast(&value); } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/Half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/Half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/Half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/Half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/TypeSafeSignMath.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/TypeSafeSignMath.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/TypeSafeSignMath.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/TypeSafeSignMath.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/bit_cast.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/bit_cast.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/bit_cast.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/bit_cast.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/floating_point_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/floating_point_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/torch/headeronly/util/floating_point_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/include/torch/headeronly/util/floating_point_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/meta/selected_operators.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/meta/selected_operators.yaml new file mode 100644 index 0000000..8c194d7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/meta/selected_operators.yaml @@ -0,0 +1,23 @@ +build_features: [] +custom_classes: [] +et_kernel_metadata: + quantized_decomposed::dequantize_per_tensor.out: + - v1/1;0,1,2,3|6;0,1,2,3|6;0,1,2,3 + quantized_decomposed::quantize_per_tensor.out: + - v1/6;0,1,2,3|1;0,1,2,3|1;0,1,2,3 +include_all_non_op_selectives: false +include_all_operators: false +kernel_metadata: {} +operators: + quantized_decomposed::dequantize_per_tensor.out: + debug_info: + - /workspace2/model/ethos_u_minimal_example.pte + include_all_overloads: false + is_root_operator: true + is_used_for_training: true + quantized_decomposed::quantize_per_tensor.out: + debug_info: + - /workspace2/model/ethos_u_minimal_example.pte + include_all_overloads: false + is_root_operator: true + is_used_for_training: true diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/CMakeLists.txt new file mode 100644 index 0000000..0ffa6f1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/CMakeLists.txt @@ -0,0 +1,115 @@ +# Copyright 2023, 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +cmake_minimum_required(VERSION 3.19) +project(arm_backend) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) + +set(_common_include_directories + ${EXECUTORCH_ROOT}/.. ${EXECUTORCH_ROOT}/runtime/core/portable_type/c10 +) +add_compile_definitions(C10_USING_CUSTOM_GENERATED_MACROS) + +# bare metal backend builds +if(EXECUTORCH_BUILD_ARM_BAREMETAL) + + add_compile_options("-Wall" "-Werror") + + # Third-party folder and Ethos-U driver inclued + set(THIRD_PARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/third-party") + set(DRIVER_ETHOSU_INCLUDE_DIR + "${THIRD_PARTY_ROOT}/ethos-u-core-driver/include" + ) + include_directories(${DRIVER_ETHOSU_INCLUDE_DIR}) + + set(_arm_baremetal_sources backends/arm/runtime/EthosUBackend.cpp + backends/arm/runtime/VelaBinStream.cpp + ) + list(TRANSFORM _arm_baremetal_sources PREPEND "${EXECUTORCH_ROOT}/") + + add_library(executorch_delegate_ethos_u STATIC ${_arm_baremetal_sources}) + target_link_libraries( + executorch_delegate_ethos_u PUBLIC executorch_core ethosu_core_driver + ) + + install(TARGETS executorch_delegate_ethos_u EXPORT ExecuTorchTargets) + + # end config for bare metal builds +endif() + +# VGF backend builds +if(EXECUTORCH_BUILD_VGF) + set(VULKAN_THIRD_PARTY_PATH ${EXECUTORCH_ROOT}/backends/vulkan/third-party) + set(VULKAN_HEADERS_PATH ${VULKAN_THIRD_PARTY_PATH}/Vulkan-Headers/include) + set(VOLK_HEADERS_PATH ${VULKAN_THIRD_PARTY_PATH}/volk) + + if(EXISTS + "${EXECUTORCH_ROOT}/examples/arm/arm-scratch/ml-sdk-for-vulkan-manifest/" + ) + message(STATUS "libvgf sourced from local scratch tree") + + # Legacy layout: libvgf sourced from local scratch tree + set(LIBVGF_PATH + "${EXECUTORCH_ROOT}/examples/arm/arm-scratch/ml-sdk-for-vulkan-manifest/sw/vgf-lib/" + ) + set(LIBVGF_STATIC "${LIBVGF_PATH}/build/src/libvgf.a") + else() + message(STATUS "libvgf installed from pip package") + + set(Python3_FIND_VIRTUALENV FIRST) + if(EXECUTORCH_ROOT AND EXISTS "${EXECUTORCH_ROOT}/env") + set(Python3_EXECUTABLE "${EXECUTORCH_ROOT}/env/bin/python3") + endif() + + find_package(Python3 REQUIRED COMPONENTS Interpreter) + + # Prefer arch-specific site-packages if present, else pure + set(_vgf_site_arch "${Python3_SITEARCH}/vgf_lib/binaries") + set(_vgf_site_pure "${Python3_SITELIB}/vgf_lib/binaries") + if(EXISTS "${_vgf_site_arch}") + set(LIBVGF_PATH "${_vgf_site_arch}") + else() + set(LIBVGF_PATH "${_vgf_site_pure}") + endif() + + set(LIBVGF_STATIC "${LIBVGF_PATH}/lib/libvgf.a") + endif() + + set(LIBVGF_INCLUDE "${LIBVGF_PATH}/include/") + + add_library(vgf STATIC IMPORTED) + set_property(TARGET vgf PROPERTY IMPORTED_LOCATION "${LIBVGF_STATIC}") + target_include_directories(vgf INTERFACE "${LIBVGF_INCLUDE}") + + # Add backend delegate for VGF + set(_vgf_backend_sources backends/arm/runtime/VGFBackend.cpp + backends/arm/runtime/VGFSetup.cpp + ) + + # vgf backend + list(TRANSFORM _vgf_backend_sources PREPEND "${EXECUTORCH_ROOT}/") + add_library(vgf_backend ${_vgf_backend_sources}) + install(TARGETS vgf_backend EXPORT ExecuTorchTargets) + target_include_directories( + vgf_backend PRIVATE ${_common_include_directories} ${VULKAN_HEADERS_PATH} + ${VOLK_HEADERS_PATH} + ) + target_compile_options( + vgf_backend PRIVATE -DUSE_VULKAN_WRAPPER -DUSE_VULKAN_VOLK + ) + + target_link_libraries(vgf_backend PRIVATE executorch_core) + target_link_libraries(vgf_backend PRIVATE vgf) + executorch_target_link_options_shared_lib(vgf_backend) + + # end config for VGF builds +endif() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/MODELS.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/MODELS.md new file mode 100644 index 0000000..aab801d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/MODELS.md @@ -0,0 +1,20 @@ +# The following file contains all models that have been confirmed to be functional and tested for the Arm backend: +- Conformer +- Deit Tiny +- DeepLab v3 (DL3) +- Inception v3 (IC3) +- Llama +- Long Short-Term Memory (LSTM) +- MobileNet v2 (MV2) +- MobileNet v3 (MV3) +- Some popular torch.nn.functional models (NN functional) +- Some popular torch.nn.modules models (NN modules) +- Some popular torch ops (Torch Functions) +- Neural Super Sampler (NSS) +- ResNet 18 +- Wav2Letter (W2L) +- Stable Diffusion: + * CLIP Text Encoder (CLIP Text with Projection) + * Stable Diffusion 3 Transformer (SD3 Transformer) + * T5 Encoder + * VAE Encoder/Decoder (VAE) \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/README.md new file mode 100644 index 0000000..2e314ca --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/README.md @@ -0,0 +1,237 @@ +# ExecuTorch Arm® Backend + +This subtree contains the Arm® Backend implementation for ExecuTorch. +It supports multiple targets using a common infrastructure, that lowers +PyTorch models to a TOSA representation. This representation is used to +deploy to the following targets: + +- **Arm® Ethos™-U55/65/85** - Compiled using the Ethos-U Vela compiler. +- **VGF Format, for ML extensions for Vulkan®** – a format containing SPIR-V™ ML operators for Vulkan-capable devices. + +The backend provides an ahead-of-time (AOT) flow, that produces a PTE file for your +chosen target. The AOT flow supports the following development operating systems: + +- Linux aarch64 +- Linux x86_64 +- macOS™ with Apple® Silicon + +In addition, the following deployment paths are supported by this backend: + +- Bare metal build of a reference runtime for Arm® Cortex®-M with Ethos-U acceleration: + - Full testing is available in tree using Corstone™ Fixed Virtual Platforms (FVP). +- Linux target support for VGF capable targets, using the executor_runner. + +More information on TOSA can be found here: https://www.mlplatform.org/tosa/tosa_spec.html. + +## Directory Layout + +Below is an overview of the key folder and files in this directory: + +``` +backends/arm/ +│ +├── _passes/ # Graph transformation passes +│ ├── arm_pass_manager.py # Defines ordering of graph transformations +│ └── *_pass.py # Graph transformation implementation +│ +├── common/ # Common functionality used across the backend +│ +├── debug/ # Debugging schema and functionality +│ +├── ethosu/ # Implementations of EthosUPartitioner and EthosUBackend +│ +├── operator_support/ # Checks if operators can be partitioned +│ +├── operators/ # ATen → TOSA serialization +│ ├── node_visitor.py # Defines base class for ATen → TOSA node visitors +│ └── op_*.py # Lowering implementations for individual operators +│ +├── quantizer/ # Quantization-related logic +│ ├── arm_quantizer.py # EthosUQuantizer and VGFQuantizer definitions +│ └── quantization_annotator.py # Defines how operators are annotated for quantization +│ +├── runtime/ # Backends for running inference on target devices +│ ├── ArmEthosUBackend.cpp +│ └── VGFBackend.cpp +│ +├── scripts/ # Auxiliary build, dependency installation and utility scripts +│ +├── test/ # Unit tests for the backend +│ ├── ops/ # Operator level unit tests +│ ├── models/ # Model level unit tests +│ └── tester/ # Testing harnesses and utilities +│ +├── third-party/ # External dependencies +│ +├── tosa/ # Shared TOSA backend implementation and dialect +│ +└── vgf/ # Implementations of VgfPartitioner and VgfBackend +``` + +## Building + +The Arm backend can be built using the following command: + +``` +./install_executorch.sh +``` + +One of the following commands should also be run once to gather the necessary dependencies for your chosen target(s): + +For the Ethos-U target: + +``` +./examples/arm/setup.sh --i-agree-to-the-contained-eula +``` + +For the VGF target: + +``` +./examples/arm/setup.sh --disable-ethos-u-deps --enable-mlsdk-deps +``` + +For both Ethos-U & VGF targets: + +``` +./examples/arm/setup.sh --i-agree-to-the-contained-eula --enable-mlsdk-deps +``` + +**NOTE:** While developing, it can be convenient to use`./install_executorch.sh --editable`, which creates an editable installation of ExecuTorch. + +## Testing + +There are two approaches for running the tests for the Arm backend. This section will explain these two approaches: + +### Using test_arm_baremetal.sh + +The backend provides a script `backends/arm/test/test_arm_baremetal.sh`, which is used in the `trunk` CI workflow. +This approach is useful for checking your change against this workflow on your own machine. +These scripts also install the necessary dependencies to run the tests. +Below is an overview of some of the testing options this script provides: + +| Command | Description | +| ---------------------------------------------------- | ------------------------------------------------------------ | +| `test_arm_baremetal.sh test_pytest_ops_no_target` | Runs operator unit tests for non-target specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_no_target` | Runs model unit tests for non-target specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_tosa` | Runs operator unit tests for TOSA specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_tosa` | Runs model unit tests for TOSA specific use-cases. | +| `test_arm_baremetal.sh test_run_tosa` | Runs end-to-end unit tests for TOSA specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_ethos_u55` | Runs operator unit tests for Ethos-U55 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_ethos_u55` | Runs model unit tests for Ethos-U55 specific use-cases. | +| `test_arm_baremetal.sh test_run_ethos_u55` | Runs end-to-end unit tests for Ethos-U55 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_ethos_u85` | Runs operator unit tests for Ethos-U85 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_ethos_u85` | Runs model unit tests for Ethos-U85 specific use-cases. | +| `test_arm_baremetal.sh test_run_ethos_u85` | Runs end-to-end unit tests for Ethos-U85 specific use-cases. | +| `test_arm_baremetal.sh test_pytest_ops_vkml` | Runs operator unit tests for VGF specific use-cases. | +| `test_arm_baremetal.sh test_pytest_models_vkml` | Runs model unit tests for VGF specific use-cases. | +| `test_arm_baremetal.sh test_run_vkml` | Runs end-to-end unit tests for VGF specific use-cases. | +| `test_arm_baremetal.sh test_model_smollm2-135M` | Runs some models with Corstone FVP. | +| `test_arm_baremetal.sh test_smaller_stories_llama` | Runs E2E model tests on Corstone FVP. | +| `test_arm_baremetal.sh test_memory_allocation` | Runs memory allocation tests for Ethos-U specific targets | + +For more information, please refer to the `backends/arm/test/test_arm_baremetal.sh` script. + +### Using pytest + +The Arm backend uses `pytest` to run the unit test suite in `backends/arm/test`. +This option offers flexibility, allowing a specific test or a particular subset of the testsuite to be run. +Below provides some examples of how to use it: + +- To run all the unit tests run the following command: + + ``` + pytest -v -n auto backends/arm/test/ + ``` + +- To run a specific test in a file: + + ``` + pytest -v backends/arm/test/ops/test_add.py -k test_add_tensor_tosa_INT_3 + ``` + +#### Testing Dependencies + +Some tests, with `u55`, `u85` and `vgf` in the name require external dependencies to run if you use `pytest`: + +- When a test contains `u55` or `u85`, you must run the following to setup the executor_runner: + ``` + ./backends/arm/scripts/build_executorch.sh + ./backends/arm/test/setup_testing.sh + ``` +- When a test contains `vgf`, you must run the following to install the ML SDK: + ``` + ./backends/arm/scripts/build_executorch.sh + ./backends/arm/test/setup_testing_vkml.sh + ``` + +In addition, some model tests in the Arm backend require third-party libraries or packages. +To run these tests, you need to install the required dependencies by running the script `examples/arm/setup.sh` with the flag `--setup-test-dependency`. + +Please note that installing model test dependencies is a standalone process. When using the `--setup-test-dependency` flag, +the script will install only the necessary dependencies for model tests, skipping all other setup procedures. + +## Using pre-commit + +A pre-commit script is available in the backend to help developers. Follow the steps below to enable it: + +``` +cp backends/arm/scripts/pre-commit .git/hooks/ +``` + +## Notes on model specific and optional passes + +The current TOSA version does not support int64. However, int64 is commonly used in many models. In order to lower the operators with int64 inputs and/or outputs to TOSA, a few passes have been developed to handle the int64-related issues. The main idea behind these passes is to replace the uses of int64 with int32 where feasible. + +- For floating-point models, these passes need to run very early in the lowering process and can be passed in to the to_edge_transform_and_lower() function call as an optional parameter. +- For quantized models, these transformations will be automatically handled during annotation before the export stage. + +List of model specific and optional passes: + +- ConvertInt64ConstOpsToInt32Pass + - Functionalities: + - Rewrites constant-producing ops that output int64 to instead output int32, when values are within int32 bounds. + - Supported Ops: + - `torch.full`, `torch.arange`, `torch.eye`, `torch.linspace`, `torch.tensor` + - Example usage: + - backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py + - backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py + +- ConvertInt64OutputOpsToInt32Pass + - Overview: + - Rewrites or removes operations that produce int64 outputs, converting them to int32 where possible. + - Overflow checks are applied selectively; for ops without such checks, users need to ensure values fit within the int32 range. + - Functionalities: + 1. Handling casting to int64: + - (1) int32 -> int64: + - Removes the cast and redirect uses of int64 to int32 + - (2) other types -> int64: + - Rewrites the cast to other types -> int32 + - Supported Ops: + - torch.ops.aten.to.\[dtype|dtype_layout\] + - exir_ops.edge.dim_order_ops.\_to_dim_order_copy.default + 2. Post-process argmax outputs: + - Inserts an int64->int32 cast after the argmax operations that produce int64 outputs: + - Supported Ops: + - torch.ops.aten.argmax.default + - exir_ops.edge.aten.argmax.default + - Example usage: + - (Functionality 1) backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py + - (Functionality 2) backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py + +- InsertInt32CastsAfterInt64PlaceholdersPass + - Functionalities: + - Inserts an int64 -> int32 cast immediately after each int64 placeholder (graph input). + - Redirects all uses of each int64 placeholder to its int32 cast output. + - Inserts local int32 -> int64 casts at call sites where an operator requires int64 inputs, e.g. `torch.nn.functional.one_hot` + - Pass ordering: + - When used with `ConvertInt64ConstOpsToInt32Pass` and `ConvertInt64OutputOpsToInt32Pass`, run this pass last. + - Rationale: Those passes may cause retracing to re-infer some int64 placeholders as int32. Running this pass last casts only inputs that remain int64, minimizing inserted casts. + - Example usage: + - backends/arm/test/models/test_llama.py + - backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py + - backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py + +## Help & Improvements + +If you have problems or questions, or have suggestions for ways to improve the Arm backend, please reach out +to the Arm team developing this backend, or create an issue on [here](https://www.github.com/pytorch/executorch/issues) and add the "partner: arm" label. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/TARGETS new file mode 100644 index 0000000..6e81adf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/TARGETS @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @noautodeps +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "constants", + srcs = [ + "constants.py", + ], + deps = [ + "//executorch/exir/dialects:lib", + ], +) +runtime.python_library( + name = "common", + srcs = glob(["common/*.py"]), + deps = [ + "fbsource//third-party/tosa_tools:serializer", + "//caffe2:torch", + "//executorch/exir:lib", + ], +) + +runtime.python_library( + name = "arm_compile_spec", + srcs = [ + "common/arm_compile_spec.py", + ], + deps = [ + "fbsource//third-party/pypi/flatbuffers:flatbuffers", + "fbsource//third-party/pypi/ml-dtypes:ml-dtypes", + "fbsource//third-party/tosa_tools:serializer", + "fbsource//third-party/tosa_tools:tosa", + ":process_node", + "//executorch/exir/backend:compile_spec_schema", + "//executorch/backends/arm/operators:lib", + "//executorch/backends/arm/operators:node_visitor", + "//executorch/backends/arm/_passes:passes", + ], +) +runtime.python_library( + name = "ethosu", + srcs = [ + "ethosu/__init__.py", + "ethosu/backend.py", + "ethosu/compile_spec.py", + "ethosu/partitioner.py", + ], + deps = [ + ":arm_compile_spec", + ":arm_vela", + "//executorch/backends/arm/tosa:specification", + "//executorch/backends/arm/tosa:partitioner", + ], +) + +runtime.python_library( + name = "vgf", + srcs = [ + "vgf/__init__.py", + "vgf/backend.py", + "vgf/compile_spec.py", + "vgf/model_converter.py", + "vgf/partitioner.py", + ], + deps = [ + ":arm_compile_spec", + "//executorch/backends/arm/tosa:specification", + "//executorch/backends/arm/tosa:partitioner", + ], +) + +runtime.python_library( + name = "process_node", + srcs = ["process_node.py"], + deps = [ + "fbsource//third-party/tosa_tools:tosa", + "//executorch/backends/arm/operators:node_visitor", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm/tosa:utils", + "//executorch/exir:lib", + ], +) +runtime.python_library( + name = "arm_vela", + srcs = [ + "arm_vela.py", + ], + deps = [ + "fbsource//third-party/pypi/ethos-u-vela:ethos-u-vela", + ], +) +runtime.python_library( + name = "arm_model_evaluator", + srcs = [ + "util/arm_model_evaluator.py", + ], + deps = [ + "//caffe2:torch", + ] +) +runtime.python_library( + name = "_factory", + srcs = [ + "util/_factory.py" + ], + deps = [ + ":ethosu", + ":vgf", + ":arm_compile_spec", + "//executorch/backends/arm/quantizer:lib", + "//executorch/exir/backend:operator_support", + "//executorch/exir/backend:compile_spec_schema", + ] +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/TARGETS new file mode 100644 index 0000000..a75c63f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/TARGETS @@ -0,0 +1,19 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "passes", + srcs = glob(["*.py"]), + deps = [ + "//executorch/backends/arm:common", + "//executorch/backends/arm:constants", + "//executorch/backends/arm/tosa:utils", + "//executorch/backends/arm/tosa/dialect:lib", + "//executorch/backends/transforms:fuse_view_copy", + "//executorch/backends/transforms:remove_getitem_op", + "//executorch/backends/transforms:replace_scalar_with_tensor", + "//executorch/backends/xnnpack/_passes:xnnpack_passes", + "//executorch/exir:lib", + "//executorch/backends/transforms:utils", + "//executorch/backends/transforms:decompose_sdpa", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/__init__.py new file mode 100644 index 0000000..76e00bc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/__init__.py @@ -0,0 +1,134 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from . import arm_pass_utils # noqa +from .arm_pass import ArmPass # noqa # usort: skip +from .annotate_decomposed_matmul import AnnotateDecomposedMatmulPass # noqa +from .annotate_output_dim_order_pass import AnnotateOutputDimOrderPass # noqa +from .broadcast_args_pass import BroadcastArgsPass # noqa +from .cast_int64_pass import CastInt64BuffersToInt32Pass # noqa +from .cast_to_int32_pass import CastToInt32Pass # noqa +from .conv1d_unsqueeze_pass import Conv1dUnsqueezePass # noqa +from .convert_elu_params import ConvertELUParamsPass # noqa +from .convert_expand_copy_to_repeat import ConvertExpandCopyToRepeatPass # noqa +from .convert_full_like_to_full_pass import ConvertFullLikeToFullPass # noqa +from .convert_int64_const_ops_to_int32 import ConvertInt64ConstOpsToInt32Pass # noqa +from .convert_int64_output_ops_to_int32 import ConvertInt64OutputOpsToInt32Pass # noqa +from .convert_minmax_pass import ConvertMinMaxPass # noqa +from .convert_permute_singleton_to_view_pass import ( # noqa + ConvertPermuteSingletonToViewPass, +) +from .convert_split_to_slice import ConvertSplitToSlicePass # noqa +from .convert_squeezes_to_view import ConvertSqueezesToViewPass # noqa +from .convert_to_clamp_pass import ConvertToClampPass # noqa +from .decompose_acosh_pass import DecomposeAcoshPass # noqa +from .decompose_adaptive_avg_pool2d_pass import DecomposeAdaptiveAvgPool2dPass # noqa +from .decompose_add_sub_alpha_pass import DecomposeAddSubAlphaPass # noqa +from .decompose_addmm_pass import DecomposeAddmmPass # noqa +from .decompose_any_pass import DecomposeAnyPass # noqa +from .decompose_asin_and_acos_pass import DecomposeAsinAndAcosPass # noqa +from .decompose_asinh_pass import DecomposeAsinhPass # noqa +from .decompose_atan_pass import DecomposeAtanPass # noqa +from .decompose_atanh_pass import DecomposeAtanhPass # noqa +from .decompose_avg_pool2d_pass import DecomposeAvgPool2dPass # noqa +from .decompose_batch_norm_no_stats import DecomposeBatchNormNoStatsPass # noqa +from .decompose_cosh_pass import DecomposeCoshPass # noqa +from .decompose_cosine_similarity_pass import DecomposeCosineSimilarityPass # noqa +from .decompose_cumsum_pass import DecomposeCumsumPass # noqa +from .decompose_div_pass import DecomposeDivPass # noqa +from .decompose_div_tensor_mode import DecomposeDivTensorModePass # noqa +from .decompose_elu_pass import DecomposeEluPass # noqa +from .decompose_embedding_pass import DecomposeEmbeddingPass # noqa # noqa +from .decompose_expm1_pass import DecomposeExpm1Pass # noqa +from .decompose_floor_divide_pass import DecomposeFloorDividePass # noqa +from .decompose_gelu_pass import DecomposeGeluPass # noqa +from .decompose_glu_pass import DecomposeGluPass # noqa +from .decompose_grouped_conv_pass import DecomposeGroupedConvPass # noqa +from .decompose_groupnorm_pass import DecomposeGroupNormPass # noqa +from .decompose_int16_activation_conv_pass import ( # noqa + DecomposeConvWithInt16ActivationPass, +) +from .decompose_int_pow_pass import DecomposeIntPowPass # noqa +from .decompose_layernorm_pass import DecomposeLayerNormPass # noqa +from .decompose_leaky_relu_pass import DecomposeLeakyReLUPass # noqa +from .decompose_linalg_vector_norm_pass import DecomposeLinalgVectorNormPass # noqa +from .decompose_linear_pass import DecomposeLinearPass # noqa +from .decompose_log1p_pass import DecomposeLog1pPass # noqa +from .decompose_logit_pass import DecomposeLogitPass # noqa +from .decompose_masked_fill_pass import DecomposeMaskedFillPass # noqa +from .decompose_maxpool2d_with_dilation_pass import DecomposeMaxPool2dPass # noqa +from .decompose_meandim_pass import DecomposeMeanDimPass # noqa +from .decompose_ne_pass import DecomposeNotEqualPass # noqa +from .decompose_quant_nodes import DecomposeQuantNodesPass # noqa +from .decompose_remainder_pass import DecomposeRemainderPass # noqa +from .decompose_round_pass import DecomposeRoundPass # noqa +from .decompose_sdpa_pass import DecomposeScaledDotProductAttentionPass # noqa +from .decompose_select import DecomposeSelectPass # noqa +from .decompose_select_scatter_pass import DecomposeSelectScatterPass # noqa +from .decompose_sign_pass import DecomposeSignPass # noqa +from .decompose_silu_pass import DecomposeSiluPass # noqa +from .decompose_sinh_pass import DecomposeSinhPass # noqa +from .decompose_softmax_pass import DecomposeSoftmaxPass # noqa +from .decompose_softmax_unstable_pass import DecomposeSoftmaxUnstablePass # noqa +from .decompose_sqrt_pass import DecomposeSqrtPass # noqa +from .decompose_sum_pass import DecomposeSumPass # noqa +from .decompose_tan_pass import DecomposeTanPass # noqa +from .decompose_tosa_unsupported_clamp_pass import ( # noqa + DecomposeTOSAUnsupportedClampPass, +) +from .decompose_var_pass import DecomposeVarPass # noqa +from .decorate_fp32_to_int32_casting_pass import DecorateFp32toInt32CastingPass # noqa +from .fold_qdq_with_annotated_qparams_pass import ( # noqa + FoldAndAnnotateQParamsPass, + QuantizeClampArgumentsPass, +) +from .fuse_batch_norm2d_pass import FuseBatchNorm2dPass # noqa +from .fuse_constant_ops_pass import ( # noqa + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, +) +from .fuse_duplicate_users_pass import FuseDuplicateUsersPass # noqa +from .fuse_equal_placeholders_pass import FuseEqualPlaceholdersPass # noqa +from .fuse_quantized_activation_pass import FuseQuantizedActivationPass # noqa +from .fuse_view_copy_transform_pass import FuseViewCopyTransformPass # noqa +from .insert_int32_casts_after_int64_placeholders import ( # noqa + InsertInt32CastsAfterInt64PlaceholdersPass, +) +from .insert_rescales_pass import ( # noqa + InsertControlFlowRescalesPass, + InsertRescaleInt32Pass, + InsertRescalePass, +) +from .insert_table_ops import InsertTableOpsPass # noqa +from .match_arg_dtype_pass import MatchArgDtypePass # noqa +from .match_arg_ranks_pass import MatchArgRanksPass # noqa +from .mm_to_bmm_pass import ConvertMmToBmmPass # noqa +from .normalize_while_initial_args_pass import NormalizeWhileInitialArgsPass # noqa +from .promote_bool_operands_pass import PromoteBoolOperandsPass # noqa +from .remove_getitem_pass import RemoveGetItemPass # noqa +from .remove_graph_asserts_pass import RemoveGraphAssertsPass # noqa +from .remove_noop_pass import RemoveNoopPass # noqa +from .replace_scalar_with_tensor_pass import ( # noqa + ReplaceScalarWithTensorByProfilePass, +) +from .rewrite_bool_bitwise_not_to_logical_not_pass import ( # noqa + RewriteBoolBitwiseNotToLogicalNotPass, +) +from .rewrite_bool_to_fp32_cast_via_int8_pass import ( # noqa + RewriteBoolToFp32CastViaInt8Pass, +) +from .rewrite_conv_pass import RewriteConvPass # noqa +from .rewrite_matmul import RewriteMatmulPass # noqa +from .rewrite_upsample import RewriteUpsamplePass # noqa +from .scalars_to_attribute_pass import ScalarsToAttributePass # noqa +from .size_adjust_input_pass import SizeAdjustInputPass # noqa +from .to_tosa_memory_format_pass import ToTosaMemoryFormatPass # noqa +from .unsqueeze_before_repeat_pass import UnsqueezeBeforeRepeatPass # noqa +from .unsqueeze_scalar_placeholders_pass import UnsqueezeScalarPlaceholdersPass # noqa +from .replace_inf_and_limit_values_pass import ( # noqa # usort: skip + ReplaceInfAndLimitValuesPass, +) +from .arm_pass_manager import ArmPassManager # noqa # usort: skip diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/_debug_passes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/_debug_passes.py new file mode 100644 index 0000000..caaaec8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/_debug_passes.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import inspect +import os +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.devtools.visualization.visualization_utils import visualize_graph +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule + + +class VisualizePass(ArmPass): + """ + This pass visualizes the graph at the point of insertion in the pass manager + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram) -> None: + super().__init__() + self.exported_program = exported_program + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + visualize_graph(graph_module, self.exported_program) + return PassResult(graph_module, False) + + +class PrintGraphModuleCodePass(ArmPass): + """ + This pass prints the graph module's code to stdout for debugging purposes. + + Example output: + + [arm_pass_manager.py:305] + def forward(self, x, y): + x, y, = fx_pytree.tree_flatten_spec(([x, y], {}), self._in_spec) + remainder = torch.ops.aten.remainder.Scalar(x, 0.25); x = None + return pytree.tree_unflatten((remainder,), self._out_spec) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, label: str | None = None): + super().__init__() + caller_frame = inspect.stack()[1] + origin = f"{os.path.basename(caller_frame.filename)}:{caller_frame.lineno}" + self.label = f"[{label}]" if label is not None else f"[{origin}]" + + def call(self, graph_module: GraphModule) -> PassResult: + gm_code = graph_module.code.strip() + print(f"\n{self.label}\n{gm_code}") + return PassResult(graph_module, False) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_decomposed_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_decomposed_matmul.py new file mode 100644 index 0000000..c8be7c7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_decomposed_matmul.py @@ -0,0 +1,127 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import itertools +import operator +from typing import cast, List, Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + FoldAndAnnotateQParamsPass, +) + +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule +from torch.fx.passes.utils.source_matcher_utils import get_source_partitions + + +class AnnotateDecomposedMatmulPass(ArmPass): + """ + torch.matmul and it's equivalent operator @ can be decomposed in many ways, for instance: + dq -> matmul -> q can become + dq -> repeat -> view -> bmm -> view -> dq which makes quantization folding + difficult. This helper function find all matmul partitions and annotate its + matmul-op (can be mm or bmm). + """ + + _passes_required_after: Set[Type[ExportPass]] = {FoldAndAnnotateQParamsPass} + + def _match_partition_to_node( + self, node: torch.fx.Node, partitioned_inputs: List[torch.fx.Node] + ) -> torch.fx.Node: + """ + The partition.input_nodes order is not guaranteed. Compare these + with the matmul node inputs coming in and return the nodes + in the correct order. + """ + if not node or node in partitioned_inputs or node.op == "placeholder": + return node + else: + return self._match_partition_to_node( + node.all_input_nodes[0], partitioned_inputs + ) + raise RuntimeError(f"Cannot find an input node which matches, {node}.") + + def call(self, graph_module: GraphModule) -> PassResult: + matmul_partitions_map = get_source_partitions( + graph_module.graph, + [ + torch.matmul, + operator.matmul, + ], + None, + ) + matmul_partitions = list( + itertools.chain.from_iterable(matmul_partitions_map.values()) + ) + matmul_targets = { + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.mm.default, + } + for partition in matmul_partitions: + quantized_input = all( + input_node.target in DQ_OPS for input_node in partition.input_nodes + ) + matmul_node = [ + node for node in partition.nodes if node.target in matmul_targets + ][0] + + if quantized_input and not all( + input_node.target in DQ_OPS + for input_node in matmul_node.all_input_nodes + ): + matmul_args = matmul_node.all_input_nodes + for node in matmul_args: + # Find the dq-node connected to this mm/bmm arg + input_node = self._match_partition_to_node( + node, partition.input_nodes + ) + # Insert new dq-node just before the mm/bmm with input_node's qparams + with graph_module.graph.inserting_before(matmul_node): + # Create new dq-node before matmul + dq_node = create_node( + graph=graph_module.graph, + op_target=cast(EdgeOpOverload, input_node.target), + ) + dq_node.args = (node, *input_node.args[1:]) + matmul_node.replace_input_with(node, dq_node) + + for partition_input in partition.input_nodes: + # Remove partition input dq-node + partition_input.replace_all_uses_with( + partition_input.all_input_nodes[0] + ) + graph_module.graph.erase_node(partition_input) + + partition_output = list(partition.output_nodes[0].users)[0] + quantized_output = partition_output.target in Q_OPS + if quantized_output and not all( + user.target in Q_OPS for user in matmul_node.users + ): + with graph_module.graph.inserting_after(matmul_node): + # Create q-node after matmul + q_node = create_node( + graph=graph_module.graph, + op_target=cast(EdgeOpOverload, partition_output.target), + ) + matmul_node.replace_all_uses_with(q_node) + q_node.args = (matmul_node, *partition_output.args[1:]) + # Remove partition output q-node + partition_output.replace_all_uses_with( + partition_output.all_input_nodes[0] + ) + graph_module.graph.erase_node(partition_output) + + # retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + + graph_module.recompile() + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_output_dim_order_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_output_dim_order_pass.py new file mode 100644 index 0000000..8dc1332 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/annotate_output_dim_order_pass.py @@ -0,0 +1,26 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_output_dim_orders +from executorch.exir.pass_base import ExportPass, PassResult + + +class AnnotateOutputDimOrderPass(ArmPass): + """ + Stores the current output dim_orders in the meta dict of the output node. This is used + for verifying that the dim order does not change unexpectedly in later passes. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module): + output_node = graph_module.graph.output_node() + output_node.meta["original_dim_orders"] = get_output_dim_orders(graph_module) + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass.py new file mode 100644 index 0000000..8148204 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass.py @@ -0,0 +1,95 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import traceback +from abc import abstractmethod +from typing import Any, List, Optional, Set, Type + +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from executorch.exir.pass_base import ExportPass, NodeMetadata +from torch.fx import GraphModule +from torch.fx.passes.infra.pass_base import PassResult + + +class ArmPass(ExportPass): + """Base class for Arm passes""" + + def __init__(self, tfa_pass: bool = False, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.submodule_depth = 0 + self.is_tfa_pass = tfa_pass + + def allowed_to_transform(self, meta: NodeMetadata | dict[str, Any]) -> bool: + if not self.is_tfa_pass: + return True + + if isinstance(meta, NodeMetadata): + meta_dict = meta.data + else: + meta_dict = meta + + disallow_tfa = meta_dict.get(DISALLOW_TFA_META_KEY, False) + + return not disallow_tfa + + @property + @abstractmethod + def _passes_required_after(self) -> Set[Type[ExportPass]]: + """The subclass defines passes that must run after it""" + pass + + @staticmethod + def get_required_passes(pass_) -> List[str]: + """ + Returns the list of passes that must be run after this pass, sorted by name. + """ + if hasattr(pass_, "_passes_required_after"): + return sorted([ArmPass.get_name(p) for p in pass_._passes_required_after]) + else: + return [] + + @staticmethod + def get_name(pass_) -> str: + """ + Returns the name of the pass. + """ + if isinstance(pass_, ExportPass): + return pass_.__class__.__name__ + elif hasattr(pass_, "__name__"): + return pass_.__name__ + else: + raise ValueError( + f"Cannot get name for pass: {pass_}. It must be an instance of ExportPass or have a __name__ attribute." + ) + + def call_operator(self, op, args, kwargs, meta, updated: Optional[bool] = False): + if not updated: + return super().call_operator(op, args, kwargs, meta) + + # if updated we should update metadata + new_meta = {} + keys = meta.data.keys() + for key in keys: + new_meta[key] = meta[key] + old_stack_trace = new_meta.get("stack_trace", "") + new_meta["stack_trace"] = f"{old_stack_trace}\n{traceback.format_stack()[-2]}" + return super().call_operator(op, args, kwargs, NodeMetadata(new_meta)) + + def call_submodule( + self, graph_module: GraphModule, inputs: tuple[Any, ...] + ) -> PassResult: + self.submodule_depth += 1 + if self.submodule_depth == 1: + result = super().call_submodule(graph_module, inputs) + else: + # When we trace a submodule, we don't want to apply the calling pass. + # Temporarily replace call_operator to avoid this. + _call_operator_fn = self.call_operator + self.call_operator = super().call_operator # type: ignore + result = super().call_submodule(graph_module, inputs) + self.call_operator = _call_operator_fn # type: ignore + self.submodule_depth -= 1 + return result diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_manager.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_manager.py new file mode 100644 index 0000000..ba67f60 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_manager.py @@ -0,0 +1,462 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from collections import defaultdict +from collections.abc import Sequence + +import executorch.backends.arm.tosa.dialect # noqa: unused +from executorch.backends.arm._passes import ( + AnnotateDecomposedMatmulPass, + AnnotateOutputDimOrderPass, + BroadcastArgsPass, + CastInt64BuffersToInt32Pass, + CastToInt32Pass, + ComputeConstantOpsAOTPass, + Conv1dUnsqueezePass, + ConvertELUParamsPass, + ConvertExpandCopyToRepeatPass, + ConvertFullLikeToFullPass, + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, + ConvertMinMaxPass, + ConvertMmToBmmPass, + ConvertPermuteSingletonToViewPass, + ConvertSplitToSlicePass, + ConvertSqueezesToViewPass, + ConvertToClampPass, + DecomposeAcoshPass, + DecomposeAdaptiveAvgPool2dPass, + DecomposeAddmmPass, + DecomposeAddSubAlphaPass, + DecomposeAnyPass, + DecomposeAsinAndAcosPass, + DecomposeAsinhPass, + DecomposeAtanhPass, + DecomposeAtanPass, + DecomposeAvgPool2dPass, + DecomposeBatchNormNoStatsPass, + DecomposeConvWithInt16ActivationPass, + DecomposeCoshPass, + DecomposeCosineSimilarityPass, + DecomposeCumsumPass, + DecomposeDivPass, + DecomposeDivTensorModePass, + DecomposeEluPass, + DecomposeEmbeddingPass, + DecomposeExpm1Pass, + DecomposeFloorDividePass, + DecomposeGeluPass, + DecomposeGluPass, + DecomposeGroupedConvPass, + DecomposeGroupNormPass, + DecomposeIntPowPass, + DecomposeLayerNormPass, + DecomposeLeakyReLUPass, + DecomposeLinalgVectorNormPass, + DecomposeLinearPass, + DecomposeLog1pPass, + DecomposeLogitPass, + DecomposeMaskedFillPass, + DecomposeMaxPool2dPass, + DecomposeMeanDimPass, + DecomposeNotEqualPass, + DecomposeQuantNodesPass, + DecomposeRemainderPass, + DecomposeRoundPass, + DecomposeScaledDotProductAttentionPass, + DecomposeSelectPass, + DecomposeSelectScatterPass, + DecomposeSignPass, + DecomposeSiluPass, + DecomposeSinhPass, + DecomposeSoftmaxPass, + DecomposeSoftmaxUnstablePass, + DecomposeSqrtPass, + DecomposeSumPass, + DecomposeTanPass, + DecomposeTOSAUnsupportedClampPass, + DecomposeVarPass, + DecorateFp32toInt32CastingPass, + FoldAndAnnotateQParamsPass, + FuseBatchNorm2dPass, + FuseConstantArgsPass, + FuseDuplicateUsersPass, + FuseEqualPlaceholdersPass, + FuseQuantizedActivationPass, + FuseViewCopyTransformPass, + InsertControlFlowRescalesPass, + InsertInt32CastsAfterInt64PlaceholdersPass, + InsertRescaleInt32Pass, + InsertRescalePass, + InsertTableOpsPass, + MatchArgDtypePass, + MatchArgRanksPass, + NormalizeWhileInitialArgsPass, + PromoteBoolOperandsPass, + QuantizeClampArgumentsPass, + RemoveGetItemPass, + RemoveGraphAssertsPass, + RemoveNoopPass, + ReplaceInfAndLimitValuesPass, + ReplaceScalarWithTensorByProfilePass, + RewriteBoolBitwiseNotToLogicalNotPass, + RewriteBoolToFp32CastViaInt8Pass, + RewriteConvPass, + RewriteMatmulPass, + RewriteUpsamplePass, + ScalarsToAttributePass, + SizeAdjustInputPass, + ToTosaMemoryFormatPass, + UnsqueezeBeforeRepeatPass, + UnsqueezeScalarPlaceholdersPass, +) +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( + ArmPassPipelineConfig, + FuseDuplicateUsersConfig, + SoftmaxDecompositionConfig, +) +from executorch.backends.arm.tosa.specification import ( + tosa_spec_in_set, + TosaLoweringContext, + TosaSpecification, +) +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass +from executorch.exir.pass_manager import PassManager +from torch.fx import GraphModule +from torch.fx.passes.infra.pass_base import PassResult +from torch.nn.modules import Module + +logger = logging.getLogger(__name__) + + +class ArmPassManager(PassManager): + def __init__(self, compile_spec: ArmCompileSpec) -> None: + self.compile_spec = compile_spec + self.tosa_spec = compile_spec.tosa_spec + self._skip_pass_types: tuple[type, ...] = () + super().__init__() + self.configure_skip_passes() + + def configure_skip_passes( + self, + override_config: ArmPassPipelineConfig | None = None, + ) -> tuple[type, ...]: + """ + Configures the pass manager to skip certain passes based on the ArmPassPipelineConfig class + found in the compile spec. + """ + skip_set: set[type] = set() + + config = override_config or self.compile_spec.get_pass_pipeline_config() + logger.debug(f"Skip Config: {config}") + + match config.softmax: + case SoftmaxDecompositionConfig.MASKED: + skip_set.add(DecomposeSoftmaxUnstablePass) + case SoftmaxDecompositionConfig.UNSTABLE: + skip_set.add(DecomposeSoftmaxPass) + skip_set.add(DecomposeMaskedFillPass) + + if config.fuse_duplicate_users is FuseDuplicateUsersConfig.DISABLED: + skip_set.add(FuseDuplicateUsersPass) + + self._skip_pass_types = tuple(skip_set) + skip_names = [skipped_pass.__name__ for skipped_pass in self._skip_pass_types] + logger.debug(f"Passes in skip list: {skip_names}") + + return self._skip_pass_types + + def validate_constraints_mandatory(self): + """ + Validates that necessary passes have run before transforming to backend. + + Note that this differs from the original validate_constraints function, which + only checks the order of passes. + """ + passes_to_run = defaultdict(list) + + for current_pass in self.passes: + current_pass_name = ArmPass.get_name(current_pass) + for required_pass_name in ArmPass.get_required_passes(current_pass): + passes_to_run[required_pass_name].append(current_pass_name) + + passes_to_run.pop(current_pass_name, None) + + if len(passes_to_run) > 0: + error_msg = "The following constraints for passes are not met:\n" + for required_pass, requiring_passes in passes_to_run.items(): + for requiring_pass in requiring_passes: + error_msg += ( + f" - {required_pass} must run after {requiring_pass}\n" + ) + + raise RuntimeError(error_msg) + + def add_passes(self, passes: Sequence[ExportPass | None]): + for p in passes: + if p is not None: + self.add_pass(p) + + def _transform(self, graph_module: GraphModule): + with TosaLoweringContext(self.tosa_spec): + return self(graph_module).graph_module + + def add_pass(self, pipeline_pass): + if type(pipeline_pass) in self._skip_pass_types: + return + super().add_pass(pipeline_pass) + + def _tosa_pipeline( + self, exported_program: ExportedProgram, graph_module: GraphModule + ) -> GraphModule: + # Preprocessing passes + self.add_pass(AnnotateOutputDimOrderPass()) + + # Node transformation passes (pre q/dq folding) + self.add_passes( + [ + FuseQuantizedActivationPass(), + RewriteBoolBitwiseNotToLogicalNotPass(), + RewriteBoolToFp32CastViaInt8Pass(), + ConvertToClampPass(), + DecomposeTOSAUnsupportedClampPass(), + DecomposeGroupNormPass(), + DecomposeLayerNormPass(), + DecomposeVarPass(), + DecomposeMeanDimPass(exported_program.graph_module, self.tosa_spec), + AnnotateDecomposedMatmulPass(), + ConvertELUParamsPass(), + NormalizeWhileInitialArgsPass(use_exir_clone=True), + ] + ) + + # Fold Q/DQ nodes, insert INT8/INT32 rescales, decompose quantization nodes. + self.add_passes( + [ + FoldAndAnnotateQParamsPass(exported_program), + FuseDuplicateUsersPass(), + # TODO: DecomposeLinearPass should run after InsertRescaleInt32Pass or + # before FoldAndAnnotateQParamsPass but is unable to at the moment. + # Ticket: MLETORCH-1539 + DecomposeLinearPass(), + InsertRescaleInt32Pass(), + InsertControlFlowRescalesPass(), + DecomposeQuantNodesPass(), + ] + ) + + # Node transformation passes (post q/dq folding) + self.add_passes( + [ + ConvertSplitToSlicePass(), + QuantizeClampArgumentsPass(), + RemoveGetItemPass(), + DecomposeBatchNormNoStatsPass(), + DecomposeLogitPass(), + DecomposeMaskedFillPass(), + DecomposeRoundPass(), + DecomposeAcoshPass(), + DecomposeAsinhPass(), + DecomposeCoshPass(), + DecomposeAsinAndAcosPass(), + DecomposeSqrtPass(), + DecomposeAtanPass(), + DecomposeAtanhPass(), + DecomposeTanPass(), + DecomposeAddmmPass(), + DecomposeEluPass(), + DecomposeExpm1Pass(), + DecomposeIntPowPass(), + DecomposeLog1pPass(), + PromoteBoolOperandsPass(), + DecomposeSinhPass(), + DecomposeSignPass(), + DecomposeFloorDividePass(), + DecomposeGeluPass(), + DecomposeAddSubAlphaPass(), + DecomposeGroupedConvPass(), + Conv1dUnsqueezePass(), + ] + ) + + # Scalars -> tensors, match tensor dtypes and ranks. + self.add_passes( + [ + ReplaceScalarWithTensorByProfilePass(), + ConvertFullLikeToFullPass(), + MatchArgDtypePass(), + UnsqueezeScalarPlaceholdersPass(exported_program), + # TODO: Move DecomposeNotEqualPass to before or after this block of + # passes. Ticket: MLETORCH-1540 + DecomposeNotEqualPass(), + MatchArgRanksPass(exported_program), + ] + ) + + # Node transformation passes (post scalar-removal) + self.add_passes( + [ + DecomposeRemainderPass(), + DecomposeDivTensorModePass(), + DecomposeEmbeddingPass(), + FuseBatchNorm2dPass(exported_program), + ConvertMmToBmmPass(), + DecomposeGluPass(), + DecomposeLeakyReLUPass(), + DecomposeDivPass(), + DecomposeSoftmaxPass(), + ConvertMinMaxPass(), + DecomposeAnyPass(), + DecomposeAdaptiveAvgPool2dPass(), + DecomposeAvgPool2dPass(), + DecorateFp32toInt32CastingPass(), + ComputeConstantOpsAOTPass(exported_program), + FuseConstantArgsPass(exported_program), + ConvertExpandCopyToRepeatPass(), + UnsqueezeBeforeRepeatPass(), + DecomposeCumsumPass(exported_program), + DecomposeMaxPool2dPass(), + SizeAdjustInputPass(), + DecomposeSelectPass(), + ConvertSqueezesToViewPass(), + CastToInt32Pass(), + BroadcastArgsPass(), + ConvertPermuteSingletonToViewPass(), + FuseViewCopyTransformPass(), + DecomposeConvWithInt16ActivationPass(), + DecomposeSumPass(), + InsertTableOpsPass(exported_program), + ] + ) + + # Aten -> TOSA transformation passes + self.add_passes( + [ + RewriteUpsamplePass(), + RewriteConvPass(exported_program), + RewriteMatmulPass(), + ] + ) + + # Postprocessing/cleanup passes + self.add_passes( + [ + CastInt64BuffersToInt32Pass(exported_program), + FuseEqualPlaceholdersPass(exported_program), + ToTosaMemoryFormatPass(exported_program), + RemoveNoopPass(), + InsertRescalePass(), + ] + ) + + self.validate_constraints_mandatory() + return self._transform(graph_module) + + def transform_to_backend_pipeline( + self, exported_program: ExportedProgram, graph_module: GraphModule + ): + """Apply passes before transforming program to backend""" + + if not tosa_spec_in_set( + self.tosa_spec, + { + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + }, + ): + raise RuntimeError( + f"No pass pipeline found for TOSA specification: {self.tosa_spec}" + ) + + return self._tosa_pipeline(exported_program, graph_module) + + def transform_for_annotation_pipeline(self, graph_module: GraphModule): + # Preprocessing passes + self.add_pass(RemoveGraphAssertsPass(tfa_pass=True)) + + # Transformation passes (pre scalar -> tensor) + self.add_passes( + [ + DecomposeSelectScatterPass(tfa_pass=True), + ConvertInt64ConstOpsToInt32Pass(tfa_pass=True), + ConvertInt64OutputOpsToInt32Pass(tfa_pass=True), + InsertInt32CastsAfterInt64PlaceholdersPass(tfa_pass=True), + DecomposeEmbeddingPass(tfa_pass=True), + DecomposeScaledDotProductAttentionPass(tfa_pass=True), + DecomposeRoundPass(tfa_pass=True), + DecomposeLogitPass(tfa_pass=True), + PromoteBoolOperandsPass(tfa_pass=True), + DecomposeSignPass(tfa_pass=True), + DecomposeAddmmPass(tfa_pass=True), + DecomposeRemainderPass(tfa_pass=True), + DecomposeFloorDividePass(tfa_pass=True), + DecomposeDivTensorModePass(tfa_pass=True), + ] + ) + + # Scalars -> tensors + self.add_passes( + [ + ReplaceScalarWithTensorByProfilePass(tfa_pass=True), + ScalarsToAttributePass(tfa_pass=True), + ] + ) + + # Transformation passes (post scalar removal) + self.add_passes( + [ + NormalizeWhileInitialArgsPass(use_exir_clone=False, tfa_pass=True), + DecomposeAddSubAlphaPass(tfa_pass=True), + DecomposeGroupNormPass(tfa_pass=True), + DecomposeLayerNormPass(tfa_pass=True), + DecomposeVarPass(tfa_pass=True), + DecomposeMeanDimPass(graph_module, self.tosa_spec, tfa_pass=True), + DecomposeNotEqualPass(tfa_pass=True), + DecomposeCosineSimilarityPass(tfa_pass=True), + DecomposeGluPass(tfa_pass=True), + DecomposeDivPass(tfa_pass=True), + DecomposeLeakyReLUPass(tfa_pass=True), + DecomposeLinalgVectorNormPass(tfa_pass=True), + DecomposeSqrtPass(tfa_pass=True), + DecomposeSiluPass(tfa_pass=True), + DecomposeAvgPool2dPass(tfa_pass=True), + DecomposeSoftmaxUnstablePass(tfa_pass=True), + DecomposeSoftmaxPass(tfa_pass=True), + ConvertMinMaxPass(tfa_pass=True), + ] + ) + + # Postprocessing passes + self.add_passes( + [ + ReplaceInfAndLimitValuesPass(tfa_pass=True), + DecomposeMaskedFillPass(tfa_pass=True), + ] + ) + + return self._transform(graph_module) + + def __call__(self, module: Module) -> PassResult: + try: + return super().__call__(module) + except Exception as e: + first_exception = e.__cause__ or e.__context__ or e + import re + + message = e.args[0] + m = re.search(r"An error occurred when running the '([^']+)' pass", message) + if m: + pass_name = m.group(1) + first_exception.args = ( + f"{pass_name}: {first_exception.args[0]}", + *first_exception.args[1:], + ) + raise first_exception diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_utils.py new file mode 100644 index 0000000..006d4ff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/arm_pass_utils.py @@ -0,0 +1,281 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import traceback +from inspect import isclass +from typing import Optional, Sequence + +import torch +import torch.fx +from executorch.backends.arm.common.debug import get_node_debug_info +from executorch.backends.arm.common.type import ensure_type +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload + +from torch._export.utils import ( + get_buffer, + get_lifted_tensor_constant, + get_param, + is_buffer, + is_lifted_tensor_constant, + is_param, +) +from torch._ops import OpOverload +from torch._subclasses.fake_tensor import FakeTensor +from torch.export.graph_signature import InputKind + + +def is_submodule_node(node: torch.fx.Node): + if node.op not in ("get_attr", "placeholder"): + return False + try: + node.graph.owning_module.get_submodule(node.target) + except AttributeError: + return False + return True + + +def is_get_attr_node(node: torch.fx.Node) -> bool: + """ + Returns true if the given node is a get attr node for a tensor of the model. + """ + return ( + isinstance(node, torch.fx.Node) + and node.op == "get_attr" + and not is_submodule_node(node) + ) + + +def is_param_node(exp_prog: ExportedProgram, node: torch.fx.Node) -> bool: + return ( + is_get_attr_node(node) + or is_param(exp_prog, node) + or is_buffer(exp_prog, node) + or is_lifted_tensor_constant(exp_prog, node) + ) + + +def get_constant_placeholder_kind( + exp_prog: ExportedProgram, node: torch.fx.Node +) -> InputKind: + if is_param(exp_prog, node): + return InputKind.PARAMETER + if is_buffer(exp_prog, node): + return InputKind.BUFFER + if is_lifted_tensor_constant(exp_prog, node): + return InputKind.CONSTANT_TENSOR + + raise RuntimeError("Node is neither PARAMETER, BUFFER nor CONSTANT_TENSOR") + + +def is_persistent_buffer(exp_prog: ExportedProgram, node: torch.fx.Node) -> bool | None: + if is_buffer(exp_prog, node): + buffer_name = exp_prog.graph_signature.inputs_to_buffers[node.name] + if buffer_name in exp_prog.graph_signature.non_persistent_buffers: + return False + else: + return True + + return None + + +def get_param_tensor( + exp_prog: ExportedProgram, node: torch.fx.Node +) -> Optional[torch.Tensor]: + if node is None: + return None + elif is_param(exp_prog, node): + return get_param(exp_prog, node) + elif is_buffer(exp_prog, node): + return get_buffer(exp_prog, node) + elif is_lifted_tensor_constant(exp_prog, node): + return get_lifted_tensor_constant(exp_prog, node) + elif is_get_attr_node(node): + target_node = ensure_type(str, node.target) + # This is a hack to support both lifted and unlifted graph + try: + return getattr(node.graph.owning_module, target_node) + except AttributeError: + return getattr(exp_prog.graph_module, target_node) + raise RuntimeError(f"unsupported param type, {node.op}.") + + +def expand_around_channel(param: Sequence[int] | int, spatial_rank: int) -> list[int]: + """ + Expand a scalar or 1-D parameter around the channel dimension into a broadcastable + shape while preserving the channel location. + """ + if isinstance(param, int): + return [param] * spatial_rank + + param_list = list(param) + if len(param_list) == 1 and spatial_rank > 1: + param_list = param_list * spatial_rank + return param_list + + +def create_node( + graph: torch.fx.Graph, + op_target: OpOverload | EdgeOpOverload, + args: tuple = (), + kwargs: Optional[dict] = None, + quantize: bool = False, + q_params: Optional[tuple] = None, + from_node: Optional[torch.fx.Node] = None, + inherit_qparams: bool = False, +): + """ + Adds a node to 'graph'. graph.inserting_before/after() should be used before the call to decide where to insert the node. + If quantize is true and q_params is not None, a q dq pair is inserted after the newly created node. + """ + + node = graph.create_node( + "call_function", + op_target, + args=args, + kwargs=kwargs or {}, + ) + + new_meta = {} + if from_node: + keys = from_node.meta.keys() + for key in keys: + new_meta[key] = from_node.meta[key] + if not inherit_qparams: + if "input_qparams" in new_meta: + new_meta["input_qparams"] = {} + if "output_qparams" in new_meta: + new_meta["output_qparams"] = {} + elif inherit_qparams: + raise ValueError("inherit_qparams is only valid when from_node is given") + + old_stack_trace = new_meta.get("stack_trace", "") + new_meta["stack_trace"] = f"{old_stack_trace}\n{traceback.format_stack()[-2]}" + node.meta = new_meta + + if quantize and q_params: + return insert_q_dq_pair(graph, node, q_params, from_node) + return node + + +def insert_q_dq_pair( + graph: torch.fx.Graph, + anchor: torch.fx.Node, + q_params: tuple, + from_node: Optional[torch.fx.Node] = None, +): + """ + Inserts a q dq node pair after the node 'anchor'. + """ + + with graph.inserting_after(anchor): + q = create_node( + graph=graph, + op_target=exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + args=(), # We add the argument last + from_node=from_node if from_node else anchor, + ) + q.meta = anchor.meta + with graph.inserting_after(q): + dq = create_node( + graph=graph, + op_target=exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + args=(q,) + q_params, + from_node=from_node if from_node else anchor, + ) + dq.meta = q.meta + anchor.replace_all_uses_with(dq) + # We add this last so the replace all uses above does not replace the quantized + # node's first use + q.args = (anchor,) + q_params + return dq + + +def get_first_fake_tensor(node: torch.fx.Node) -> FakeTensor: + """ + Returns a FakeTensor from the meta field of 'node'. + If the node contains many fake tensors, return the first one. + """ + if isinstance( + node.meta["val"], (Sequence, torch.fx.immutable_collections.immutable_list) + ): + fake_tensor = node.meta["val"][0] + else: + fake_tensor = node.meta["val"] + + if not isinstance(fake_tensor, FakeTensor): + raise TypeError( + f'Expected a FakeTensor in meta["val"] of node {node}, but got ' + f"{type(fake_tensor).__name__}\n" + f"{get_node_debug_info(node)}" + ) + + return fake_tensor + + +def get_node_arg(args: list | dict, key: int | str | type, default_value=None): + """ + Help-function for getting a value from node.args/ kwargs, three cases: + 1. By position in node.args - Returns arg at given position or default_value if index is one out of bounds + 2. By key in node.kwargs - Returns kwarg with given key or default_value if it deos not exist + 3. By type in node.args - Returns first arg of args of given type. Useful for cases where arg postions may differ but types are unique. + """ + if isinstance(key, int): + if 0 <= key < len(args): + return args[key] + elif key == len(args): + if default_value is not None: + return default_value + else: + raise RuntimeError(f"No defult value given for index {key}") + else: + raise RuntimeError( + f"Out of bounds index {key} for getting value in args (of size {len(args)})" + ) + elif isinstance(key, str): + return args.get(key, default_value) # type: ignore[union-attr] + elif isclass(key): + for arg in args: + if isinstance(arg, key): + return arg + if default_value is not None: + return default_value + else: + raise RuntimeError(f"No arg of type {key}") + else: + raise RuntimeError("Invalid type") + + +def set_node_arg(node: torch.fx.Node, i: int | str, value): + """ + Help-function for setting a value in node.args/ kwargs. If the index is one larger than the list size, the value is instead appended to the list. + """ + if isinstance(i, int): + if 0 <= i < len(node.args): + args = list(node.args) + args[i] = value + node.args = tuple(args) + return + elif i == len(node.args): + node.args = node.args + (value,) + else: + raise RuntimeError( + f"Out of bounds index {i} for setting value in {node} args (of size {len(node.args)})" + ) + elif isinstance(i, str): + kwargs = dict(node.kwargs) + kwargs[i] = value + node.kwargs = kwargs + else: + raise RuntimeError("Invalid type") + + +def get_output_dim_orders(graph_module): + output_node = graph_module.graph.output_node() + return [get_first_fake_tensor(node).dim_order() for node in output_node.args[0]] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/broadcast_args_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/broadcast_args_pass.py new file mode 100644 index 0000000..d11fb77 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/broadcast_args_pass.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm.tosa.specification import get_context_spec + +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +class BroadcastArgsPass(ArmPass): + """ + Pass to manually broadcast arguments by inserting repeats. + This is done when more than one arg needs broadcasting. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = { + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + # mul is indirectly targeting div as div is decompsed to reciprocal + mul + exir_ops.edge.aten.mul.Tensor, + } + + def call(self, graph_module: GraphModule) -> PassResult: + tosa_spec = get_context_spec() + if not tosa_spec.is_U55_subset: + return PassResult(graph_module, False) + for node in graph_module.graph.nodes: + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + output_shape = get_first_fake_tensor(node).shape + nbr_of_broacasts = 0 + for arg in node.args: + if not isinstance(arg, Node): + continue + + shape = get_first_fake_tensor(arg).shape + if shape != output_shape: + nbr_of_broacasts += 1 + if nbr_of_broacasts > 1: + multiples = [ + int(output_shape[d] / shape[d]) + for d in range(len(output_shape)) + ] + with graph_module.graph.inserting_before(node): + repeat = create_node( + graph_module.graph, + exir_ops.edge.aten.repeat.default, + args=(arg, multiples), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + node.replace_input_with(arg, repeat) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_int64_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_int64_pass.py new file mode 100644 index 0000000..535da39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_int64_pass.py @@ -0,0 +1,70 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.pass_base import ExportPass, PassResult +from torch._export.utils import is_buffer +from torch.export import ExportedProgram + +logger = logging.getLogger(__name__) + + +class CastInt64BuffersToInt32Pass(ArmPass): + """ + Cast int64 buffers to int32 if the int64 data is in int32 range. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def _assert_within_int32(self, tensor: torch.Tensor, node: torch.fx.Node): + if torch.min(tensor) < torch.iinfo(torch.int32).min: + raise RuntimeError( + f"Node {node.name} has value < {torch.iinfo(torch.int32).min}" + ) + if torch.max(tensor) > torch.iinfo(torch.int32).max: + raise RuntimeError( + f"Node {node.name} has value > {torch.iinfo(torch.int32).max}" + ) + + def _to_int32(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if len(node.users) == 0: + continue + if "val" not in node.meta: + continue + fake_tensor = node.meta["val"] + if not isinstance(fake_tensor, torch._subclasses.fake_tensor.FakeTensor): + continue + if fake_tensor.dtype != torch.int64: + continue + if is_buffer(self.exported_program, node): + node.meta["val"] = fake_tensor.to(torch.int32) + buffer_name = self.exported_program.graph_signature.inputs_to_buffers[ + node.name + ] + buffer = self.exported_program.state_dict[buffer_name] + self._assert_within_int32(buffer, node) + logger.warning( + f"Casting buffer {node.name} from torch.int64 to torch.int32" + f" defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + buffer_int32 = buffer.to(torch.int32) + self.exported_program.state_dict[buffer_name] = buffer_int32 + continue + + def call(self, graph_module: torch.fx.GraphModule): + self._to_int32(graph_module) + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_to_int32_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_to_int32_pass.py new file mode 100644 index 0000000..40f7e34 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/cast_to_int32_pass.py @@ -0,0 +1,67 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass + +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class CastToInt32Pass(ArmPass): + """Casts the input to int32 if it is not already and casts back the output to the original input dtype.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = { + exir_ops.edge.aten.bitwise_left_shift.Tensor, + exir_ops.edge.aten.bitwise_right_shift.Tensor, + } + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + tosa_spec = get_context_spec() + if not tosa_spec.is_U55_subset: + return PassResult(graph_module, False) + return super().call(graph_module) + + def call_operator(self, op, args, kwargs, meta): + if op not in self.targeted_ops: + return super().call_operator(op, args, kwargs, meta) + + new_args: list = [] + did_cast = False + for arg in args: + if arg.data.dtype != torch.int32: + new_args.append( + super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (arg,), + {"dtype": torch.int32}, + meta, + ) + ) + did_cast = True + else: + new_args.append(arg) + + output = super().call_operator( + op, + tuple(new_args), + {}, + meta, + ) + + if did_cast: + output = super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (output,), + {"dtype": args[0].data.dtype}, + meta, + ) + return output diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/conv1d_unsqueeze_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/conv1d_unsqueeze_pass.py new file mode 100644 index 0000000..f0b1026 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/conv1d_unsqueeze_pass.py @@ -0,0 +1,98 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class Conv1dUnsqueezePass(ArmPass): + """ + This pass is used to change conv1d ops into conv2d since TOSA only + supports 2d and 3d convolution. This is done by modifying the graph to do the + following: + 1a) unsqueeze the convolution's input from 3d to 4d + 1b) unsqueeze the convolution's weight from 3d to 4d + 2) perform a conv2d (with a modified version of the original conv1d args) + 3) squeeze the output back down to 3d. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + RewriteConvPass, + SizeAdjustInputPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op != exir_ops.edge.aten.convolution.default: + return super().call_operator(op, args, kwargs, meta) + stride = list(args[3]) + if len(stride) != 1: + return super().call_operator(op, args, kwargs, meta) + + x_meta = meta.copy() + x_meta.data["input_qparams"] = {} + x_meta.data["output_qparams"] = {} + + x = args[0] + x_unsqueezed_shape = list(x.data.shape) + [1] + x = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x, x_unsqueezed_shape), + {}, + x_meta, + updated=True, + ) + + w_meta = meta.copy() + w_meta.data["input_qparams"] = {} + w_meta.data["output_qparams"] = {} + + w = args[1] + w_unsqueezed_shape = list(w.data.shape) + [1] + w = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (w, w_unsqueezed_shape), + {}, + w_meta, + updated=True, + ) + + new_args = ( + x, + w, + args[2], + args[3] + [1], # stride + args[4] + [0], # padding + args[5] + [1], # dilation + args[6], + args[7] + [0], + args[8], + ) + x = super().call_operator( + exir_ops.edge.aten.convolution.default, new_args, kwargs, meta, updated=True + ) + + x_squeezed_meta = meta.copy() + x_squeezed_meta.data["input_qparams"] = {} + x_squeezed_meta.data["output_qparams"] = {} + x_squeezed_shape = list(x.data.shape)[:-1] + x = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x, x_squeezed_shape), + {}, + x_squeezed_meta, + updated=True, + ) + + return x diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_elu_params.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_elu_params.py new file mode 100644 index 0000000..10c6a28 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_elu_params.py @@ -0,0 +1,67 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm.constants import DQ_OPS +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class ConvertELUParamsPass(ArmPass): + """ + Pass to convert the input_scale kwarg of ELU operator from float to + int. + + It has been set to 2 as the outputs seem to stay the same regardless of what + the value of input_scale is, as long as that value is not 1. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + graph = graph_module.graph + node_list = graph.find_nodes( + op="call_function", target=exir_ops.edge.aten.elu.default + ) + for node in node_list: + input_node = node.all_input_nodes[0] + is_quantized = ( + input_node.op == "call_function" and input_node.target in DQ_OPS + ) + if not is_quantized or not self.allowed_to_transform(node.meta): + continue + with graph.inserting_after(node): + replace_node = create_node( + graph, exir_ops.edge.aten.elu.default, from_node=node + ) + old_args = list(node.args) + + alpha = old_args[1] if len(old_args) > 1 else 1.0 + scale = 1.0 + input_scale = 2.0 + + replace_node.args = (old_args[0],) + + updated_kwargs = dict(node.kwargs) + updated_kwargs["alpha"] = int(alpha) + updated_kwargs["scale"] = int(scale) + updated_kwargs["input_scale"] = int(input_scale) + + replace_node.kwargs = updated_kwargs + + node.replace_all_uses_with(replace_node) + graph.erase_node(node) + + modified_graph = True + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_expand_copy_to_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_expand_copy_to_repeat.py new file mode 100644 index 0000000..0cd3060 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_expand_copy_to_repeat.py @@ -0,0 +1,77 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import cast, Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.unsqueeze_before_repeat_pass import ( + UnsqueezeBeforeRepeatPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +logger = logging.getLogger(__name__) + + +def calculate_multiples(args): + """Returns expand args converted to repeat args, and whether the expand changes the rank""" + input_node_or_tensor = args[0] + + if isinstance(input_node_or_tensor, torch.fx.node.Node): + input_data = input_node_or_tensor.meta["val"] + else: + input_data = input_node_or_tensor.data + + input_shape = input_data.shape + + multiples = cast(list[int], args[1]) + expanded_rank = len(multiples) + + # Expanded shape is 'input_shape' front-padded with ones. + padding = expanded_rank - len(input_shape) + extended_shape = [ + input_shape[i] if i >= 0 else 1 for i in range(-padding, len(input_shape)) + ] + + # To convert expand arg to repeat arg, non-repeated dims should have + # multiples[dim] = 1. Passing -1 to expand arg means + # not changing the size of that dimension. + multiples = [ + multiples[i] if multiples[i] != -1 and extended_shape[i] == 1 else 1 + for i in range(expanded_rank) + ] + return multiples, expanded_rank != len(input_shape) + + +class ConvertExpandCopyToRepeatPass(ArmPass): + """ + Replace expand copy with repeat since it is a repeat that can only repeat singleton dimensions. + """ + + _passes_required_after: Set[Type[ExportPass]] = {UnsqueezeBeforeRepeatPass} + + expand_copy = exir_ops.edge.aten.expand_copy.default + repeat = exir_ops.edge.aten.repeat.default + + def call_operator(self, op, args, kwargs, meta): + if op != self.expand_copy: + return super().call_operator(op, args, kwargs, meta) + + multiples, changes_rank = calculate_multiples(args) + + if all((x == 1 for x in multiples)) and not changes_rank: + # All dimensions/repetitions occur only once. Remove node + # altogether since it's in practice just a copy. + logger.warning("Found redundant expand node (no-op). Removing it.") + + return args[0] + + return super().call_operator( + op=self.repeat, args=(args[0], multiples), kwargs=kwargs, meta=meta + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_full_like_to_full_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_full_like_to_full_pass.py new file mode 100644 index 0000000..becb0b7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_full_like_to_full_pass.py @@ -0,0 +1,42 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class ConvertFullLikeToFullPass(ArmPass): + """As per the full_like pytorch documentation, + `torch.full_like(input, fill_value)` is equivalent to + `torch.full(input.size(), + fill_value, + dtype=input.dtype, + layout=input.layout, + device=input.device + )` + Skip layout and device since it's not relevant for our backend. + """ + + _passes_required_after: Set[Type[ExportPass]] = {ComputeConstantOpsAOTPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in [ + exir_ops.edge.aten.full_like.default, + ]: + return super().call_operator(op, args, kwargs, meta) + + tensor = args[0].data + full_args = (list(tensor.shape), args[1]) + full_kwargs = {"dtype": tensor.dtype} + return super().call_operator( + exir_ops.edge.aten.full.default, full_args, full_kwargs, meta + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_const_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_const_ops_to_int32.py new file mode 100644 index 0000000..85fcf71 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_const_ops_to_int32.py @@ -0,0 +1,81 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.exir.pass_base import ExportPass, PassResult + + +logger = logging.getLogger(__name__) +INT32_MIN = torch.iinfo(torch.int32).min +INT32_MAX = torch.iinfo(torch.int32).max + + +class ConvertInt64ConstOpsToInt32Pass(ArmPass): + """ + Rewrite constant ops that produce int64 to int32 where safe. + + List of supported operatos: + 1. `torch.full` + 2. `torch.arange` + 3. `torch.eye` + 4. `torch.linspace` + 5. `torch.tensor` + """ + + _passes_required_after: Set[Type[ExportPass]] = {ComputeConstantOpsAOTPass} + + torch_ops = [ + torch.ops.aten.full.default, + torch.ops.aten.arange.default, + torch.ops.aten.arange.start, + torch.ops.aten.arange.start_step, + torch.ops.aten.eye.default, + torch.ops.aten.linspace.default, + ] + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + + if ( + node.target + not in ComputeConstantOpsAOTPass.targeted_ops + self.torch_ops + ): + continue + + data = node.target(*node.args, **node.kwargs) + if data.dtype is not torch.int64: + continue + + min_val, max_val = torch.min(data), torch.max(data) + if INT32_MIN <= min_val and max_val <= INT32_MAX: + logger.warning( + f"Casting {node.name} from torch.int64 to torch.int32" + f" defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + node.update_kwarg("dtype", torch.int32) + modified = True + else: + logger.warning( + f"[{node.name}] has values: min={min_val}, max={max_val}, which exceeds int32 range " + f"([{INT32_MIN}, {INT32_MAX}]); not converting dtype to int32." + ) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_output_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_output_ops_to_int32.py new file mode 100644 index 0000000..0482191 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_int64_output_ops_to_int32.py @@ -0,0 +1,155 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, + set_node_arg, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +logger = logging.getLogger(__name__) + + +class ConvertInt64OutputOpsToInt32Pass(ArmPass): + """ + Rewrites or removes operations that produce int64 outputs, converting them + to int32 where possible. + + + Currently, this pass handles casting and argmax operators: + 1. int32 -> int64: + removes the cast and redirects all uses to the original int32 value. + 2. other types -> int64: + rewrites the cast to produce int32 instead of int64. + 3. torch.argmax() + insert an int64->int32 cast after the argmax node + + Future extensions may include operators that return int64 outputs by default + (e.g., `argmin`), rewriting them or inserting an int64 -> int32 cast to yield + int32 results. + + Note: Overflow checks are applied selectively in this pass. For operators without + such checks, it is the user's responsibility to ensure that values fit within + the int32 range. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + aten_cast_ops = ( + torch.ops.aten.to.dtype, + torch.ops.aten.to.dtype_layout, + ) + edge_cast_ops = (exir_ops.edge.dim_order_ops._to_dim_order_copy.default,) + + aten_argmax_ops = (torch.ops.aten.argmax.default,) + edge_argmax_ops = (exir_ops.edge.aten.argmax.default,) + + aten_ops = aten_cast_ops + aten_argmax_ops + edge_ops = edge_cast_ops + edge_argmax_ops + + # dtype is specified in args + cast_ops_args = ( + torch.ops.aten.to.dtype, # to_2: node.args: (gt, torch.int64) node.kwargs: {} + ) + # dtype is specified in kwargs + cast_ops_kwargs = ( + torch.ops.aten.to.dtype_layout, # to_1: node.args: (unsqueeze,) node.kwargs: {'dtype': torch.int64, 'layout': torch.strided, 'device': device(type='cpu')} + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, # node.args: (aten_gt_scalar,) node.kwargs: {'dtype': torch.int64, 'dim_order': [0, 1]} + ) + + def _get_decomposition(self, op): + if op in self.edge_ops: + return exir_ops.edge.dim_order_ops._to_dim_order_copy.default + + if op in self.aten_ops: + return torch.ops.dim_order_ops._to_dim_order_copy.default + + raise RuntimeError( + f"[{self.__class__.__name__}] Can't get decomposition for op {op}" + ) + + def _convert_casting_operators(self, node: torch.fx.Node): + input_node = node.all_input_nodes[0] + input_dtype = get_first_fake_tensor(input_node).dtype + # Case 1: int32 -> int64 - removes the ops + if input_dtype == torch.int32: + users = [user for user in node.users if node != user] + for user in users: + logger.warning( + f"Removing int32->int64 casting node {node.name} defined in" + f" {node.meta.get('stack_trace','[no stack trace found]')}" + ) + user.replace_input_with(node, input_node) + # Case 2: other types -> int64 - rewrites to cast to int32 + else: + if node.target in self.cast_ops_kwargs: + set_node_arg(node, "dtype", torch.int32) + elif node.target in self.cast_ops_args: + set_node_arg(node, 1, torch.int32) + else: + raise RuntimeError(f"Unexpected target {node.target} in {node.name}") + output_dtype = get_first_fake_tensor(node).dtype + logger.warning( + f"Converting casting node {node.name} from {input_dtype}->{output_dtype} to" + f" {input_dtype}->torch.int32 defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + + def _convert_argmax_operators(self, node: torch.fx.Node, graph: torch.fx.Graph): + output_tensor = node + to_copy_op = self._get_decomposition(node.target) + with graph.inserting_after(node): + cast_after = create_node( + graph, + to_copy_op, + args=(output_tensor,), + kwargs={ + "dtype": torch.int32, + }, + ) + users = [user for user in node.users if user != cast_after] + for user in users: + user.replace_input_with(output_tensor, cast_after) + logger.warning( + f"Inserting a casting node {cast_after.name} after {node.name} to cast int64 output" + f" to int32 for {node.name} defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + graph = graph_module.graph + for node in list(graph.nodes): + if node.op != "call_function": + continue + if node.target not in self.aten_ops + self.edge_ops: + continue + output_dtype = get_first_fake_tensor(node).dtype + if output_dtype != torch.int64: + continue + + if node.target in self.aten_cast_ops + self.edge_cast_ops: + self._convert_casting_operators(node) + elif node.target in self.aten_argmax_ops + self.edge_argmax_ops: + # TODO: Add range check based on the input tensor shape before casting the output + self._convert_argmax_operators(node, graph) + else: + raise RuntimeError(f"Unexpected target {node.target} in {node.name}") + + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_minmax_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_minmax_pass.py new file mode 100644 index 0000000..caedbbf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_minmax_pass.py @@ -0,0 +1,166 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.convert_squeezes_to_view import ( + ConvertSqueezesToViewPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class ConvertMinMaxPass(ArmPass): + """ + Converts min/max to amin/amax and unrolls multi-dimensional reduction and keep-dims arg to be + TOSA compliant. + + The difference between max/min and amax/amin is (from pytorch docs): + - amax/amin supports reducing on multiple dimensions, + - amax/amin does not return indices, + - amax/amin evenly distributes gradient between equal values, while max(dim)/min(dim) + propagates gradient only to a single index in the source tensor. + Since we do not care about gradients post training, convert min/max ops to amin/amax as long as + the indices are not used. + + Original: + amax([dim1, dim2], keepdim = False) + After pass: + amax(dim1, keepdim = True) + amax(dim2, keepdim = True) + squeeze(dim = [dim1, dim2]) + """ + + _passes_required_after: Set[Type[ExportPass]] = {ConvertSqueezesToViewPass} + + _TARGET_OPS = { + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + exir_ops.edge.aten.max.dim, + exir_ops.edge.aten.min.dim, + torch.ops.aten.max.dim, + torch.ops.aten.min.dim, + } + + def check_argmax(self, node): + """ + Raises a RuntimeError if the argmax value returned by the min/max op is used in the graph. + """ + if node.target in [torch.ops.aten.max.dim, torch.ops.aten.min.dim]: + no_argmax = len(node.users) == 1 + no_argmax_users = (len(node.users) == 2) and ( + len(list(node.users)[1].users) == 0 + ) + if not (no_argmax or no_argmax_users): + raise RuntimeError("Argmax is not supported by the arm_quantizer") + + def get_variables(self, node): + """Returns variables specific for each op handled by the pass.""" + if node.target in [ + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + ]: + replace_node = node + op = node.target + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + elif node.target == exir_ops.edge.aten.max.dim: + replace_node = list(node.users)[0] + op = exir_ops.edge.aten.amax.default + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + elif node.target == exir_ops.edge.aten.min.dim: + replace_node = list(node.users)[0] + op = exir_ops.edge.aten.amin.default + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + elif node.target == torch.ops.aten.max.dim: + replace_node = list(node.users)[0] + op = torch.ops.aten.amax.default + squeeze_op = torch.ops.aten.squeeze.dims + elif node.target == torch.ops.aten.min.dim: + replace_node = list(node.users)[0] + op = torch.ops.aten.amin.default + squeeze_op = torch.ops.aten.squeeze.dims + else: + raise RuntimeError( + f"{node.name} is not an accepted target for ConvertMinMaxPass()" + ) + + return (replace_node, op, squeeze_op) + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in ConvertMinMaxPass._TARGET_OPS + or not self.allowed_to_transform(node.meta) + ): + continue + + self.check_argmax( + node + ) # TODO: MLETORCH-718 : Quantization of indices in arm_quantizer + replace_node, op, squeeze_op = self.get_variables(node) + + # Unwrap args + if len(node.args) == 1: + # If dims is unspecified, min/max over all dims. + input_node = cast(torch.fx.Node, node.args[0]) + input_shape = get_first_fake_tensor(input_node).shape + dims = range(len(input_shape)) + keepdims = False + elif len(node.args) == 2: + input_node, dims = node.args + keepdims = False + elif len(node.args) == 3: + input_node, dims, keepdims = node.args + else: + raise RuntimeError( + f"Unexpected arg size {len(node.args)} in {node.name}" + ) + + try: + iter(dims) # type:ignore[assignment] + except Exception: + dims = [dims] # type:ignore[assignment] + else: + dims = list(dims) # type:ignore[assignment] + + # Unroll multi-dimensional reduction and keep-dims arg + with graph_module.graph.inserting_before(node): + + for dim in dims: + args = (input_node, dim, True) + input_node = create_node( + graph=graph_module.graph, + op_target=op, + args=args, + kwargs={}, + from_node=node, + ) + + if not keepdims: + input_node = create_node( + graph=graph_module.graph, + op_target=squeeze_op, + args=(input_node, dims), + kwargs={}, + from_node=node, + ) + + replace_node.replace_all_uses_with(input_node) + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_permute_singleton_to_view_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_permute_singleton_to_view_pass.py new file mode 100644 index 0000000..fe4697b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_permute_singleton_to_view_pass.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Sequence, Set, Tuple, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +from torch._ops import OpOverload + + +_PERMUTE_TARGETS: Tuple[OpOverload, ...] = ( + exir_ops.edge.aten.permute.default, + exir_ops.edge.aten.permute_copy.default, +) + + +class ConvertPermuteSingletonToViewPass(ArmPass): + """Replace permutations that only move singleton axes with a reshape. + + Examples: + x = rand(1,1,1,4) + y = permute(x, (0,3,1,2)) + + becomes: + x = rand(1,1,1,4) + y = view_copy(x, (1,4,1,1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in _PERMUTE_TARGETS: + return super().call_operator(op, args, kwargs, meta) + + input_tensor = args[0].data + permutation = args[1] + if not is_singleton_permutation(input_tensor.shape, permutation): + return super().call_operator(op, args, kwargs, meta) + + output_shape = meta["val"].shape + view_args = (args[0], output_shape) + return super().call_operator( + exir_ops.edge.aten.view_copy.default, view_args, kwargs, meta + ) + + +def is_singleton_permutation(shape: Sequence[int], permutation: Sequence[int]) -> bool: + """ + Treat as a view only when non-singleton axes keep their order; singleton + axes may move freely since they carry no data volume. + """ + rank = len(shape) + normalized_perm = [d % rank for d in permutation] + + non_singleton_axes = [i for i, size in enumerate(shape) if size != 1] + permuted_non_singleton_axes = [axis for axis in normalized_perm if shape[axis] != 1] + + return permuted_non_singleton_axes == non_singleton_axes diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_split_to_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_split_to_slice.py new file mode 100644 index 0000000..5006c30 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_split_to_slice.py @@ -0,0 +1,132 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch.fx +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class ConvertSplitToSlicePass(ArmPass): + """ + Replace a split operation with many slice operations. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + split_ops = ( + exir_ops.edge.aten.split_with_sizes_copy.default, + exir_ops.edge.aten.split_copy.Tensor, + ) + slice = exir_ops.edge.aten.slice_copy.Tensor + + def call(self, graph_module: torch.fx.GraphModule): + graph = graph_module.graph + for node in graph.nodes: + if node.target not in self.split_ops: + continue + + # Get useful variables + split_node = node + input_node = split_node.all_input_nodes[0] + output_nodes = split_node.users.copy() + shape = get_first_fake_tensor(input_node).shape + rank = len(shape) + split_lengths = split_node.args[1] + dim = split_node.args[2] if len(split_node.args) > 2 else 0 + dim = (dim + rank) % rank + + # Validate that split lengths cover the entire dimension + + dim_size = shape[dim] + if isinstance(split_lengths, int): + if split_lengths <= 0: + raise ValueError( + f"Split size must be positive, got {split_lengths}" + ) + full_chunks, remainder = divmod(dim_size, split_lengths) + split_lengths = [split_lengths] * full_chunks + if remainder: + split_lengths.append(remainder) + else: + length_sum = sum(split_lengths) + if length_sum != dim_size: + raise ValueError( + f"Split sizes {split_lengths} sum to {length_sum}, " + f"but dimension {dim} has size {dim_size}" + ) + + # Convert split argument 'split_lengths' to slice arguments start and end. + starts = [0] * len(split_lengths) + ends = [0] * len(split_lengths) + start = 0 + end = 0 + for i, split_length in enumerate(split_lengths): + end = start + split_length + starts[i] = start + ends[i] = end + start = end + + # Output nodes are of type getitem + # Replace them with one slice node for each output node. + with graph_module.graph.inserting_before(split_node): + for output_node in output_nodes: + index = output_node.args[1] + slice_node = create_node( + graph, + self.slice, + (input_node, dim, starts[index], ends[index]), + from_node=node, + ) + slice_node.meta = _copy_user_node_qparams( + split_node, output_node, index + ) + output_node.replace_all_uses_with(slice_node) + graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) + + +def _copy_user_node_qparams( + split_node: torch.fx.Node, output_node: torch.fx.Node, index: int +) -> dict: + """ + Construct metadata for the slice node that will replace the split output. + + Note that output quantization parameters are copied from the user nodes + of the split node. The split node itself does not have output quantization + parameters. + + Args: + split_node: The split node being replaced. + output_node: The getitem node that is user of the split node. + index: The index of the output being processed. + Returns: + Updated metadata dictionary for the slice node. + """ + + def _select_index(value): + if isinstance(value, (list, tuple)): + return value[index] + return value + + meta = split_node.meta.copy() + if "val" in meta: + meta["val"] = _select_index(meta["val"]) + if "tensor_meta" in meta: + meta["tensor_meta"] = _select_index(meta["tensor_meta"]) + if "input_qparams" in meta: + meta["input_qparams"] = dict(meta["input_qparams"]) + if "output_qparams" in meta: + meta["output_qparams"] = dict(output_node.meta["output_qparams"]) + return meta diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_squeezes_to_view.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_squeezes_to_view.py new file mode 100644 index 0000000..9d185a8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_squeezes_to_view.py @@ -0,0 +1,36 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.fuse_view_copy_transform_pass import ( + FuseViewCopyTransformPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class ConvertSqueezesToViewPass(ArmPass): + """ + Replaces squeeze/unsqueeze operators with view. These are simply special cases of the view op, so removing them gives us less cases to handle in the node visitiors. + """ + + _passes_required_after: Set[Type[ExportPass]] = {FuseViewCopyTransformPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in [ + exir_ops.edge.aten.squeeze_copy.dims, + exir_ops.edge.aten.unsqueeze_copy.default, + ]: + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + shape = meta["val"].size() + view_args = (x, list(shape)) + return super().call_operator( + exir_ops.edge.aten.view_copy.default, view_args, kwargs, meta + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_to_clamp_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_to_clamp_pass.py new file mode 100644 index 0000000..effb46f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/convert_to_clamp_pass.py @@ -0,0 +1,45 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Tuple, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + QuantizeClampArgumentsPass, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_operators = { + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.relu.default, +} + + +def get_clamp_params(op, args) -> Tuple[float | None, float | None]: + if op == exir_ops.edge.aten.hardtanh.default: + return args[1], args[2] + elif op == exir_ops.edge.aten.relu.default: + return 0.0, None + else: + raise ValueError(f"Getting clamp parameters for op {op} is not implemented.") + + +class ConvertToClampPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {QuantizeClampArgumentsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_operators or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + return super().call_operator( + exir_ops.edge.aten.clamp.default, + (args[0], *get_clamp_params(op, args)), + {}, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_acosh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_acosh_pass.py new file mode 100644 index 0000000..1d29986 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_acosh_pass.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass # noqa +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_acosh_op = exir_ops.edge.aten.acosh.default + + +class DecomposeAcoshPass(ArmPass): + """ + Decomposes acosh to supported TOSA-operations. + This decomposition is based on the mathematical identity: + acosh(x) = log(x + sqrt((x-1)(x+1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta, updated=False): + + if op is not edge_acosh_op: + return super().call_operator(op, args, kwargs, meta, updated) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta, updated) + + log_op, sqrt_op, mul_op, sub_op, add_op, add_op_scalar = ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.add.Scalar, + ) + + x = args[0] + + # (x-1)(x+1) + sub = super().call_operator(sub_op, (x, 1.0), {}, meta, True) + add = super().call_operator(add_op_scalar, (x, 1.0), {}, meta, True) + mul = super().call_operator(mul_op, (sub, add), {}, meta, True) + + # sqrt((x-1)(x+1)) + sqrt = super().call_operator(sqrt_op, (mul,), {}, meta, True) + + # x + sqrt((x-1)(x+1)) + add = super().call_operator(add_op, (x, sqrt), {}, meta, True) + + # out = ln(x + sqrt((x-1)(x+1)) + out = super().call_operator(log_op, (add,), {}, meta, True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py new file mode 100644 index 0000000..5905e8f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_adaptive_avg_pool2d_pass.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from math import ceil, floor +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_avg_pool2d_pass import ( + DecomposeAvgPool2dPass, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, NodeMetadata + +edge_ops = (exir_ops.edge.aten._adaptive_avg_pool2d.default,) +aten_ops = (torch.ops.aten.adaptive_avg_pool2d.default,) + + +def _get_decomposition(op) -> tuple: + if op in edge_ops: + return ( + exir_ops.edge.aten.avg_pool2d.default, + exir_ops.edge.aten.slice_copy.Tensor, + exir_ops.edge.aten.cat.default, + ) + if op in aten_ops: + return ( + torch.ops.aten.avg_pool2d.default, + torch.ops.aten.slice_copy.Tensor, + torch.ops.aten.cat.default, + ) + raise RuntimeError(f"Unable to get decomposition for op {op}") + + +class DecomposeAdaptiveAvgPool2dPass(ArmPass): + """ + Decomposes AdaptiveAvgPool2d into AvgPool2d operations. + + An input tensor of shape (N, C, H, W) is transformed into an output tensor + of shape (N, C, output_size_h, output_size_w). + + The output is of size output_size_h x output_size_w for any input. + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeAvgPool2dPass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op not in (edge_ops + aten_ops): + return super().call_operator(op, args, kwargs, meta, updated) + + avg_pool2d_op, slice_op, cat_op = _get_decomposition(op) + + x = args[0] + _, _, input_size_h, input_size_w = x.data.shape + + (output_size_h, output_size_w) = args[1] + + # Vela currently only allows a stride in the interval of [1,3] for AvgPool2d. + # To accommodate this, the AvgPool2d op is applied to pooling regions and the results are concatenated. + + # Slices and concats does not require quantization parameters + metadata_dict = dict(meta.data) + metadata_dict["input_qparams"] = {} + metadata_dict["output_qparams"] = {} + meta_with_no_qparams = NodeMetadata(metadata_dict) + res = [] + for out_i in range(output_size_h): + row = [] + for out_j in range(output_size_w): + # Calculate pooling regions + start_h = floor(out_i * input_size_h / output_size_h) + end_h = ceil((out_i + 1) * input_size_h / output_size_h) + start_w = floor(out_j * input_size_w / output_size_w) + end_w = ceil((out_j + 1) * input_size_w / output_size_w) + + # Slice along H + x_h = super().call_operator( + slice_op, (x, 2, start_h, end_h), kwargs, meta_with_no_qparams, True + ) + # Slice along W + x_hw = super().call_operator( + slice_op, + (x_h, 3, start_w, end_w), + kwargs, + meta_with_no_qparams, + True, + ) + + # Apply avg pooling with kernel size equal to the pooling region + kernel_h = end_h - start_h + kernel_w = end_w - start_w + pool_args = (x_hw, (kernel_h, kernel_w), (1, 1), (0, 0)) + pooled = super().call_operator( + avg_pool2d_op, pool_args, kwargs, meta, True + ) + row.append(pooled) + + # Concatenate row results along width (dim=3) + row_tensor = super().call_operator( + cat_op, (row, 3), kwargs, meta_with_no_qparams, True + ) + res.append(row_tensor) + + # Concatenate all rows along height (dim=2) + out = super().call_operator( + cat_op, (res, 2), kwargs, meta_with_no_qparams, True + ) + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_add_sub_alpha_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_add_sub_alpha_pass.py new file mode 100644 index 0000000..e59fb54 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_add_sub_alpha_pass.py @@ -0,0 +1,98 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +import numbers +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +_ADD_OPS = ( + exir_ops.edge.aten.add.Tensor, + torch.ops.aten.add.Tensor, +) + +_SUB_OPS = ( + exir_ops.edge.aten.sub.Tensor, + torch.ops.aten.sub.Tensor, +) + + +def _get_ops(op): + if op in _ADD_OPS: + if op is exir_ops.edge.aten.add.Tensor: + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + ) + return ( + torch.ops.aten.mul.Tensor, + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + ) + if op in _SUB_OPS: + if op is exir_ops.edge.aten.sub.Tensor: + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.sub.Tensor, + ) + return ( + torch.ops.aten.mul.Tensor, + torch.ops.aten.full.default, + torch.ops.aten.sub.Tensor, + ) + raise RuntimeError(f"Unsupported operator {op}") + + +def _should_decompose(alpha) -> bool: + if isinstance(alpha, numbers.Number): + return alpha != 1 + return False + + +class DecomposeAddSubAlphaPass(ArmPass): + """Rewrite add/sub with alpha into a mul followed by add/sub.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta, updated: bool | None = False): + if op not in _ADD_OPS + _SUB_OPS: + return super().call_operator(op, args, kwargs, meta, updated) + + alpha = kwargs.get("alpha", 1) + if not _should_decompose(alpha): + return super().call_operator(op, args, kwargs, meta, updated) + + mul_op, full_op, binary_op = _get_ops(op) + lhs, rhs = args + + alpha_full = super().call_operator( + full_op, + ((1,), float(alpha)), + {"device": meta["val"].device}, + meta, + updated=True, + ) + scaled_rhs = super().call_operator( + mul_op, + (rhs, alpha_full), + {}, + meta, + updated=True, + ) + return super().call_operator( + binary_op, + (lhs, scaled_rhs), + {}, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_addmm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_addmm_pass.py new file mode 100644 index 0000000..f709aca --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_addmm_pass.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.mm_to_bmm_pass import ConvertMmToBmmPass # noqa +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For MI case +edge_addmm = exir_ops.edge.aten.addmm.default +# For BI case +aten_addmm = torch.ops.aten.addmm.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_addmm: + return ( + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Tensor, + ) + elif op == aten_addmm: + return ( + torch.ops.aten.mm.default, + torch.ops.aten.mul.Scalar, + torch.ops.aten.add.Tensor, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeAddmmPass(ArmPass): + """Decomposes the addmm operator into tensor multiplication and addition.""" + + _passes_required_after: Set[Type[ExportPass]] = { + ConvertMmToBmmPass, + MatchArgRanksPass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in [edge_addmm, aten_addmm] or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + input, mat1, mat2 = args + beta = kwargs.get("beta", 1.0) + alpha = kwargs.get("alpha", 1.0) + + mul_op, mul_scalar_op, add_op = get_ops(op) + + mul = super().call_operator(mul_op, (mat1, mat2), {}, meta, updated=True) + mul_alpha = super().call_operator( + mul_scalar_op, (mul, alpha), {}, meta, updated=True + ) + + input_beta = super().call_operator( + mul_scalar_op, (input, beta), {}, meta, updated=True + ) + + return super().call_operator( + add_op, (mul_alpha, input_beta), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_any_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_any_pass.py new file mode 100644 index 0000000..a0487e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_any_pass.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.exir.dialects._ops import ( # type: ignore[import-not-found] + ops as exir_ops, +) +from executorch.exir.pass_base import ( # type: ignore[import-not-found] + ExportPass, + PassResult, +) + + +class DecomposeAnyPass(ArmPass): + """ + Converts any.default, any.dim and any.dims to a sequence of any.dim by + unrolling multi-dimensional reductions with keepdim=True. If keepdim=False + was requested, the final shape adjustment is implemented with a + view_copy.default to the reduced shape. + + Example 1 + Original: + any.dim() # x.shape: [dim1, dim2, ..., dimn] + After pass: + any.dim(dim1, keepdim = True) + any.dim(dim2, keepdim = True) + ... + any.dim(dimn, keepdim = True) + view_copy(shape = squeezed_shape) + + Example 2 + Original: + any.dim(dim1, keepdim = False) + After pass: + any.dim(dim1, keepdim = True) + view_copy(shape = squeezed_shape) + + Example 3 + Original: + any.dims([dim1, dim2], keepdim = False) + After pass: + any.dim(dim1, keepdim = True) + any.dim(dim2, keepdim = True) + view_copy(shape = squeezed_shape) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target not in [ + exir_ops.edge.aten.any.default, + exir_ops.edge.aten.any.dim, + exir_ops.edge.aten.any.dims, + ]: + continue + + if len(node.args) == 1: + # any.default(input) + input_node = (node.args)[0] + dims_to_reduce = range(len(input_node.meta["val"].shape)) + keepdim = False + elif len(node.args) == 2: + # any.dim/dims(input, dims=dims) + input_node, dims_to_reduce = node.args + keepdim = False + elif len(node.args) == 3: + # any.dim/dims(input, dims=dims, keepdim=keepdim) + input_node, dims_to_reduce, keepdim = node.args + else: + raise RuntimeError( + f"Unexpected arg size {len(node.args)} in {node.name}" + ) + try: + iter(dims_to_reduce) + except: + dims_to_reduce = [dims_to_reduce] # type: ignore[assignment] + else: + dims_to_reduce = list(dims_to_reduce) # type: ignore[assignment] + + # Unroll multi-dimensional reduction and keep-dims arg + with graph_module.graph.inserting_before(node): + for dim in dims_to_reduce: + args = (input_node, dim, True) + input_node = graph_module.graph.create_node( + "call_function", exir_ops.edge.aten.any.dim, args, node.kwargs + ) + + if not keepdim: + output_shape = list(get_first_fake_tensor(node).shape) + input_node = graph_module.graph.create_node( + "call_function", + exir_ops.edge.aten.view_copy.default, + (input_node, output_shape), + ) + + node.replace_all_uses_with(input_node) + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asin_and_acos_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asin_and_acos_pass.py new file mode 100644 index 0000000..e0da9eb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asin_and_acos_pass.py @@ -0,0 +1,236 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from math import pi +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_full_like_to_full_pass import ( + ConvertFullLikeToFullPass, +) +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_asin_op = (exir_ops.edge.aten.asin.default,) +edge_acos_op = (exir_ops.edge.aten.acos.default,) + + +def get_decomposition(op) -> tuple: + if op in (edge_asin_op + edge_acos_op): + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.div.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.neg.default, + ) + + raise RuntimeError(f"Can't get decomposition for op {op}") + + +class DecomposeAsinAndAcosPass(ArmPass): + """ + This pass decomposes asin and acos into a rational approximation for small values + and a transformed rational approximation for large values. + + The decomposition is based on the following mathematical identities: + if abs(x) < 0.5: + asin(x) = x + P(x^2) / Q(x^2) + acos(x) = π/2 - asin(x) + else: + asin(x) = π/2 - 2 * (s + s^3 * Q(z) / P(z)) + acos(x) = 2 * (s + s^3 * Q(z) / P(z)) + where P and Q are polynomials defined in the function and s is the square root of z. + + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + DecomposeDivPass, + ConvertFullLikeToFullPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + def _build_polynomial( + self, coefficients: list[float], variable: torch.Tensor, meta: dict[str, str] + ) -> torch.Tensor: + """ + Helper function to build polynomial from coefficients and variable. + """ + full_like_op, add_op, mul_op_scalar, mul_op = ( + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.mul.Tensor, + ) + result = super().call_operator( + full_like_op, (variable, coefficients[0]), {}, meta, True + ) + for coeff in coefficients[1:]: + result = super().call_operator( + add_op, + ( + result, + super().call_operator( + mul_op_scalar, (variable, coeff), {}, meta, True + ), + ), + {}, + meta, + ) + variable = super().call_operator( + mul_op, (variable, variable), {}, meta, True + ) + return result + + def _combine_branches( + self, + bool_op, + bool_args: tuple[torch.Tensor, float], + branches: tuple[torch.Tensor, torch.Tensor], + meta: dict[str, str], + ) -> torch.Tensor: + where_op = exir_ops.edge.aten.where.self + mask = super().call_operator(bool_op, bool_args, {}, meta, True) + branch_true, branch_false = branches + return super().call_operator( + where_op, (mask, branch_true, branch_false), {}, meta, True + ) + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_asin_op + edge_acos_op): + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + logging.info( + f"Approximating {op}. This may introduce small numerical errors. For details, see {__file__}." + ) + x = args[0] + half = 0.5 + one = 1.0 + neg_half = -0.5 + two = 2.0 + pi_over_2 = pi / 2.0 + zero = 0.0 + neg_one = -1.0 + + ( + mul_op, + add_op, + mul_op_scalar, + sqrt_op, + abs_op, + sub_op_scalar, + div_op, + gt_op, + lt_op, + sub_op, + full_like_op, + neg_op, + ) = get_decomposition(op) + + # Coefficients for the rational approximation, calculated with the Minimax (Remez) method + p_coefficients = [ + 1.6666667163e-01, + -3.2556581497e-01, + 2.0121252537e-01, + -4.0055535734e-02, + 7.9153501429e-04, + ] + + q_coefficients = [1.0, -2.4033949375e00, 2.0209457874e00, -6.8828397989e-01] + + x_abs = super().call_operator(abs_op, (x,), {}, meta, True) + + # Step 1: compute asin_small - rational approximation for [0,0.5] + y = super().call_operator(mul_op, (x_abs, x_abs), {}, meta, True) + x3 = super().call_operator(mul_op, (x_abs, y), {}, meta, True) + + P = self._build_polynomial(p_coefficients, x_abs, meta) + Q = self._build_polynomial(q_coefficients, x_abs, meta) + numer = super().call_operator(mul_op, (x3, P), {}, meta, True) + r_small = super().call_operator(div_op, (numer, Q), {}, meta, True) + asin_small = super().call_operator(add_op, (x_abs, r_small), {}, meta, True) + + # Step 2: Compute the transformed approximation for large values + # Calculate z = -0.5 * (|x| - 1) + tmp_ones = super().call_operator(full_like_op, (x_abs, one), {}, meta, True) + tmp = super().call_operator(sub_op, (x_abs, tmp_ones), {}, meta, True) + z = super().call_operator(mul_op_scalar, (tmp, neg_half), {}, meta, True) + + # Calculate s-terms + s = super().call_operator(sqrt_op, (z,), {}, meta, True) + s2 = super().call_operator(mul_op, (s, s), {}, meta, True) + s3 = super().call_operator(mul_op, (s2, s), {}, meta, True) + + Pz = self._build_polynomial(p_coefficients, z, meta) + Qz = self._build_polynomial(q_coefficients, z, meta) + + numer = super().call_operator(mul_op, (s3, Pz), {}, meta, True) + + # Calculate r_large = P(z) / Q(z) + r_large = super().call_operator(div_op, (numer, Qz), {}, meta, True) + + # Calculate asin_large = pi/2 - 2 * (s + s^3 * Q(z) / P(z)) + t1 = super().call_operator(add_op, (s, r_large), {}, meta, True) + t2 = super().call_operator(mul_op_scalar, (t1, two), {}, meta, True) + + diff = super().call_operator(sub_op_scalar, (t2, pi_over_2), {}, meta, True) + tmp_neg_ones = super().call_operator( + full_like_op, (diff, neg_one), {}, meta, True + ) + asin_large = super().call_operator(mul_op, (diff, tmp_neg_ones), {}, meta, True) + + asin_unsigned = self._combine_branches( + gt_op, (x_abs, half), (asin_large, asin_small), meta + ) + + # Handle x < 0 + negated_asin = super().call_operator(neg_op, (asin_unsigned,), {}, meta, True) + asin = self._combine_branches( + lt_op, (x, zero), (negated_asin, asin_unsigned), meta + ) + + if op in edge_acos_op: + # If x <= 0.5: acos(x) = pi/2 - asin(x) + const_tensor = super().call_operator( + full_like_op, (x, pi_over_2), {}, meta, True + ) + acos_small = super().call_operator( + sub_op, (const_tensor, asin), {}, meta, True + ) + # If x > 0.5, acos(x) = 2 * (s + s^3 * Q(z) / P(z)) = t2 + acos = self._combine_branches(gt_op, (x, half), (t2, acos_small), meta) + return acos + + return asin diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asinh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asinh_pass.py new file mode 100644 index 0000000..1131fee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_asinh_pass.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_asinh_op = (exir_ops.edge.aten.asinh.default,) + + +class DecomposeAsinhPass(ArmPass): + """ + Decomposes asinh to supported TOSA-operations. + This decomposition is based on the mathematical identity: + asinh(x) = log(x + sqrt(x^2 + 1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_asinh_op: + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + log_op, sqrt_op, mul_op, add_op_scalar, add_op = ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.add.Tensor, + ) + + x = args[0] + + # calculate t1 = x^2 + 1 + x2 = super().call_operator(mul_op, (x, x), {}, meta, True) + t1 = super().call_operator(add_op_scalar, (x2, 1.0), {}, meta, True) + + # t2 = sqrt(t1) + t2 = super().call_operator(sqrt_op, (t1,), {}, meta, True) + + # t3 = x + t2 + t3 = super().call_operator(add_op, (x, t2), {}, meta, True) + + # out = ln(t3) + out = super().call_operator(log_op, (t3,), {}, meta, True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atan_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atan_pass.py new file mode 100644 index 0000000..a3b4081 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atan_pass.py @@ -0,0 +1,142 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from math import pi +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_atan = exir_ops.edge.aten.atan.default # MI case + + +def _get_atan_ops(op): + """Return the primitive ops required..""" + if op is not edge_atan: + raise RuntimeError(f"Can't decompose atan for op {op}") + + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.neg.default, + ) + + +class DecomposeAtanPass(ArmPass): + """Decomposes the atan operator into a rational (Padé) approximation.""" + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + def _rational_approximation(self, z, ops, meta): + """Creates a (2,1) Padé approximation for atan(x) on [-1, 1].""" + + op_mul, op_mul_scalar, op_add, op_add_scalar, _, _, _, op_recip, _, _ = ops + + # Coefficients calculated using minimax on the interval [-1, 1]. + a1 = 0.3529666667 + a2 = -0.0287666667 + b1 = 0.6863 + + z2 = super().call_operator(op_mul, (z, z), {}, meta, updated=True) + z4 = super().call_operator(op_mul, (z2, z2), {}, meta, updated=True) + + num1 = super().call_operator(op_mul_scalar, (z2, a1), {}, meta, updated=True) + num2 = super().call_operator(op_mul_scalar, (z4, a2), {}, meta, updated=True) + num = super().call_operator(op_add_scalar, (num1, 1.0), {}, meta, updated=True) + num = super().call_operator(op_add, (num, num2), {}, meta, updated=True) + + den1 = super().call_operator(op_mul_scalar, (z2, b1), {}, meta, updated=True) + den = super().call_operator(op_add_scalar, (den1, 1.0), {}, meta, updated=True) + + inv_den = super().call_operator(op_recip, (den,), {}, meta, updated=True) + + prod = super().call_operator(op_mul, (num, inv_den), {}, meta, updated=True) + return super().call_operator(op_mul, (z, prod), {}, meta, updated=True) + + def call_operator(self, op, args, kwargs, meta): + if op is not edge_atan: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + logging.info( + f"Approximating atan. This may introduce small numerical errors. For details, see {__file__}." + ) + + ops = _get_atan_ops(op) + ( + _, + op_mul_scalar, + _, + op_add_scalar, + op_sub, + op_abs, + op_gt, + op_recip, + op_where, + op_neg, + ) = ops + + x = args[0] + + # |x| > 1 is reduced to [0, 1] using atan(x) = pi/2 - atan(1/x) and atan(-x) = -atan(x). + + abs_x = super().call_operator(op_abs, (x,), {}, meta, updated=True) + mask_hi = super().call_operator(op_gt, (abs_x, 1.0), {}, meta, updated=True) + + inv_x = super().call_operator(op_recip, (abs_x,), {}, meta, updated=True) + z = super().call_operator( + op_where, (mask_hi, inv_x, abs_x), {}, meta, updated=True + ) + + atan_z = self._rational_approximation(z, ops, meta) + + zero_tensor = super().call_operator( + op_mul_scalar, (x, 0.0), {}, meta, updated=True + ) + half_pi_tensor = super().call_operator( + op_add_scalar, (zero_tensor, pi / 2), {}, meta, updated=True + ) + + diff = super().call_operator( + op_sub, (half_pi_tensor, atan_z), {}, meta, updated=True + ) + atan_abs = super().call_operator( + op_where, (mask_hi, diff, atan_z), {}, meta, updated=True + ) + + mask_pos = super().call_operator(op_gt, (x, 0.0), {}, meta, updated=True) + neg_val = super().call_operator(op_neg, (atan_abs,), {}, meta, updated=True) + + return super().call_operator( + op_where, (mask_pos, atan_abs, neg_val), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atanh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atanh_pass.py new file mode 100644 index 0000000..789dafe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_atanh_pass.py @@ -0,0 +1,86 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_atanh = exir_ops.edge.aten.atanh.default # MI case + + +def _get_atanh_ops(op): + """Return the primitive ops required..""" + if op is not edge_atanh: + raise RuntimeError(f"Can't decompose atanh for op {op}") + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.neg.default, + ) + + +class DecomposeAtanhPass(ArmPass): + """ + Decomposes the atanh operator into primitive ops. + atanh(x) = 0.5 * log((1 + x) / (1 - x)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op is not edge_atanh: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + ops = _get_atanh_ops(op) + ( + op_mul_tensor, + op_mul_scalar, + op_add_scalar, + op_reciprocal, + op_log, + op_neg, + ) = ops + + x = args[0] + + nom = super().call_operator(op_add_scalar, (x, 1.0), {}, meta, updated=True) + + neg_x = super().call_operator(op_neg, (x,), {}, meta, updated=True) + denom = super().call_operator( + op_add_scalar, (neg_x, 1.0), {}, meta, updated=True + ) + recip = super().call_operator(op_reciprocal, (denom,), {}, meta, updated=True) + + log_input = super().call_operator( + op_mul_tensor, (nom, recip), {}, meta, updated=True + ) + log = super().call_operator(op_log, (log_input,), {}, meta, updated=True) + + return super().call_operator(op_mul_scalar, (log, 0.5), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_avg_pool2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_avg_pool2d_pass.py new file mode 100644 index 0000000..c46a54b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_avg_pool2d_pass.py @@ -0,0 +1,154 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_div_ops = (exir_ops.edge.aten.avg_pool2d.default,) +aten_div_ops = (torch.ops.aten.avg_pool2d.default,) + + +def get_decomposition(op) -> tuple: + if op in edge_div_ops: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.avg_pool2d.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in aten_div_ops: + return ( + torch.ops.aten.full.default, + torch.ops.aten.cat.default, + torch.ops.aten.avg_pool2d.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get avg_pool2d decomposition for op {op}") + + +class DecomposeAvgPool2dPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {ComputeConstantOpsAOTPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_div_ops + aten_div_ops) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + full_op, cat_op, avgpool_op, mul_op = get_decomposition(op) + + x = args[0] + full_kwargs = {"device": x.data.device} + kernel_h, kernel_w = args[1] + kernel_size = kernel_h * kernel_w + if len(args) > 2 and args[2] is not None: + stride_h, stride_w = args[2] + else: + stride_h, stride_w = kernel_h, kernel_w + pad_h, pad_w = new_pad_h, new_pad_w = args[3] if len(args) > 3 else (0, 0) + ceil_mode = args[4] if len(args) > 4 else False + count_include_pad = args[5] if len(args) > 5 else True + divisor_override = args[6] if len(args) > 6 else None + + n, c, h, w = x.data.shape + post_pad_w, post_pad_h = (0, 0) + + # Count_include_pad == False means that we use a different divisor for edge elements + # When divisor_override is set, this will be overriden anyways. + # It is easier to replace a constant divisor, so set count_include_pad == True + if divisor_override is not None: + count_include_pad = True + + # Add width padding manually if count_include_pad + if count_include_pad and pad_w > 0: + pre_pad_shape = [n, c, h, pad_w] + pre_pad = super().call_operator( + full_op, (pre_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + + if ceil_mode and divisor_override is None: + post_pad_w = pad_w + else: + post_pad_w = adjust_pooling_pad_if_needed( + w, kernel_w, stride_w, pad_w, ceil_mode + ) + + if post_pad_w > 0: + post_pad_shape = [n, c, h, post_pad_w] + post_pad = super().call_operator( + full_op, (post_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + cat_nodes = [pre_pad, x, post_pad] + else: + cat_nodes = [pre_pad, x] + + x = super().call_operator( + cat_op, (cat_nodes, 3), kwargs, meta, updated=True + ) + new_pad_w = 0 + + # Add height padding manually if count_include_pad + if count_include_pad and pad_h > 0: + pre_pad_shape = [n, c, pad_h, w + pad_w + post_pad_w] + pre_pad = super().call_operator( + full_op, (pre_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + + if ceil_mode and divisor_override is None: + post_pad_h = pad_h + else: + post_pad_h = adjust_pooling_pad_if_needed( + h, kernel_h, stride_h, pad_h, ceil_mode + ) + + if post_pad_h > 0: + post_pad_shape = [n, c, post_pad_h, w + pad_w + post_pad_w] + post_pad = super().call_operator( + full_op, (post_pad_shape, 0.0), full_kwargs, meta, updated=True + ) + cat_nodes = [pre_pad, x, post_pad] + else: + cat_nodes = [pre_pad, x] + + x = super().call_operator( + cat_op, (cat_nodes, 2), kwargs, meta, updated=True + ) + new_pad_h = 0 + + avgpool_args = ( + x, + args[1], + [stride_h, stride_w], + [new_pad_h, new_pad_w], + ceil_mode, + False, + ) + x = super().call_operator(avgpool_op, avgpool_args, kwargs, meta, updated=True) + + # Multiply by factor (kernel_size / divisor_override) if divisor_override + if divisor_override is not None and divisor_override != kernel_size: + override_multiplier = super().call_operator( + full_op, + ([1, 1, 1, 1], kernel_size / divisor_override), + full_kwargs, + meta, + updated=True, + ) + x = super().call_operator( + mul_op, (x, override_multiplier), kwargs, meta, updated=True + ) + + return x diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_batch_norm_no_stats.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_batch_norm_no_stats.py new file mode 100644 index 0000000..36af927 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_batch_norm_no_stats.py @@ -0,0 +1,233 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) + +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeBatchNormNoStatsPass(ArmPass): + """ + Decompose BatchNorm2d(track_running_stats=False) (aten._native_batch_norm_legit_no_training) + into a sequence of elementwise operations: + + # let input = x, rm = running_mean, rv = running_var, eps: float + rm_view = view(rm, weights_shape) + rv_view = view(rv, weights_shape) + centered = sub(x, rm_view) + eps_full = full(eps_shape, eps) + var_eps = add(rv_view, eps_full) + inv_sqrt = rsqrt(var_eps) + normed = mul(centered, inv_sqrt) + weighted = mul(normed, w_view) + biased = add(weighted, b_view) + + Source: https://pytorch.org/docs/stable/generated/torch.nn.BatchNorm2d.html + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + InsertTableOpsPass, + } + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901 + bn_ops = ( + exir_ops.edge.aten._native_batch_norm_legit.no_stats, + exir_ops.edge.aten._native_batch_norm_legit_no_training.default, + torch.ops.aten._native_batch_norm_legit_no_training.default, + torch.ops.aten.batch_norm.default, + torch.ops.aten.native_batch_norm.default, + ) + + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in bn_ops + or not self.allowed_to_transform(node.meta) + ): + continue + + if node.target in ( + torch.ops.aten.batch_norm.default, + torch.ops.aten.native_batch_norm.default, + ): + # signature: (input, weight, bias, mean, var, training, momentum, eps, cudnn_enabled) + # pos‐arg 5 is training + training = node.kwargs.get("training", False) + if len(node.args) > 5: + training = node.args[5] + if training: + # skip training‐mode batchnorm + continue + + # Extract args + args = node.args + meta = node.meta + + # Default eps + eps: float = torch.finfo().eps + # weight and bias may be None + x = args[0] + weight = args[1] if len(args) > 1 else None + bias = args[2] if len(args) > 2 else None + running_mean = args[3] + running_var = args[4] + if len(args) > 6: + eps = args[6] + + # Determine shapes + val = meta.get("val") + ref_tensor = val[0] if isinstance(val, tuple) else val + shape = tuple(ref_tensor.size()) + dtype = ref_tensor.dtype + rank = len(shape) + + # channel dimension is 1 for BatchNorm2d + channel_axis = 1 + weights_shape = [1] * rank + weights_shape[channel_axis] = shape[channel_axis] + num_features = shape[channel_axis] + + # Ops to use + sub_op = exir_ops.edge.aten.sub.Tensor + view_op = exir_ops.edge.aten.view_copy.default + full_op = exir_ops.edge.aten.full.default + add_op = exir_ops.edge.aten.add.Tensor + rsqrt_op = exir_ops.edge.aten.rsqrt.default + mul_op = exir_ops.edge.aten.mul.Tensor + + # Begin decomposition + with graph_module.graph.inserting_before(node): + # reshape running stats + rm_view = create_node( + graph_module.graph, + view_op, + args=(running_mean, weights_shape), + from_node=node, + ) + rv_view = create_node( + graph_module.graph, + view_op, + args=(running_var, weights_shape), + from_node=node, + ) + # center input + centered = create_node( + graph_module.graph, + sub_op, + args=(x, rm_view), + from_node=node, + ) + # epsilon tensor + eps_shape = [1] * rank + eps_full = create_node( + graph_module.graph, + full_op, + args=(eps_shape, eps), + kwargs={"dtype": dtype}, + from_node=node, + ) + # var + eps + var_eps = create_node( + graph_module.graph, + add_op, + args=(rv_view, eps_full), + from_node=node, + ) + # inverse sqrt + inv_sqrt = create_node( + graph_module.graph, + rsqrt_op, + args=(var_eps,), + from_node=node, + ) + # normalized + normed = create_node( + graph_module.graph, + mul_op, + args=(centered, inv_sqrt), + from_node=node, + ) + + # weight + if weight is None: + one = create_node( + graph_module.graph, + full_op, + args=([num_features], 1), + kwargs={"dtype": dtype}, + from_node=node, + ) + w_view = create_node( + graph_module.graph, + view_op, + args=(one, weights_shape), + from_node=node, + ) + else: + w_view = create_node( + graph_module.graph, + view_op, + args=(weight, weights_shape), + from_node=node, + ) + weighted = create_node( + graph_module.graph, + mul_op, + args=(normed, w_view), + from_node=node, + ) + + # bias + if bias is None: + zero = create_node( + graph_module.graph, + full_op, + args=([num_features], 0), + kwargs={"dtype": dtype}, + from_node=node, + ) + b_view = create_node( + graph_module.graph, + view_op, + args=(zero, weights_shape), + from_node=node, + ) + else: + b_view = create_node( + graph_module.graph, + view_op, + args=(bias, weights_shape), + from_node=node, + ) + final_out = create_node( + graph_module.graph, + add_op, + args=(weighted, b_view), + from_node=node, + ) + + users = [u for u in node.users if u is not node] + node.replace_all_uses_with(final_out) + for u in users: + if u.target == operator.getitem: + u.replace_all_uses_with(final_out) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + + graph_module.recompile() + new_gm = super().call(graph_module).graph_module + return PassResult(new_gm, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosh_pass.py new file mode 100644 index 0000000..fe84f2b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosh_pass.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For MI case +edge_cosh = exir_ops.edge.aten.cosh.default + + +class DecomposeCoshPass(ArmPass): + """ + This pass replaces the cosh operator with a sequence of TOSA-equivalent operations that + compute the hyperbolic cosine using the formula: + + cosh(x) = 0.5 * (e^x + e^(-x)) + + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op is not edge_cosh: + return super().call_operator(op, args, kwargs, meta, updated) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + x = args + + exp_op, mul_op, neg_op, add_op = ( + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.add.Tensor, + ) + + # exp1 = e^x + exp1 = super().call_operator(exp_op, x, {}, meta, updated=True) + + # exp2 = e^(⁻x) + neg_x = super().call_operator(neg_op, x, {}, meta, updated=True) + exp2 = super().call_operator(exp_op, (neg_x,), {}, meta, updated=True) + + # numer = exp1 + exp2 + numer = super().call_operator(add_op, (exp1, exp2), {}, meta, updated=True) + + # out = 0.5 * numer + out = super().call_operator(mul_op, (numer, 0.5), {}, meta, updated=True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosine_similarity_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosine_similarity_pass.py new file mode 100644 index 0000000..1978a40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cosine_similarity_pass.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_full_like_to_full_pass import ( + ConvertFullLikeToFullPass, +) + +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.pass_base import ExportPass + +torch_cosine_similarity = (torch.ops.aten.cosine_similarity.default,) + + +class DecomposeCosineSimilarityPass(ArmPass): + """ + Decomposition of aten.cosine_similarity: + + dot = sum(mul(x1, x2), dims, keepdim=False) + norm = pow( sum(mul(x, x), dims, keepdim=False), 0.5 ) + eps = full( (), eps_scalar ) + n1c = max(norm1, eps) + n2c = max(norm2, eps) + denom = mul(n1c, n2c) + out = div(dot, denom) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeDivPass, + DecomposeSumPass, + ConvertFullLikeToFullPass, + InsertTableOpsPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in torch_cosine_similarity or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x1, x2 = args[0], args[1] + dim = kwargs.get("dim", 1) + eps = kwargs.get("eps", 1e-8) + dims = [dim] if isinstance(dim, int) else list(dim) + + # 1) dot + prod = super().call_operator(torch.ops.aten.mul.Tensor, (x1, x2), {}, meta) + dot = super().call_operator( + torch.ops.aten.sum.dim_IntList, (prod, dims, False), {}, meta + ) + + # 2a) norm1 = pow(sum(x1*x1), 0.5) + x1_sq = super().call_operator(torch.ops.aten.mul.Tensor, (x1, x1), {}, meta) + s1 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (x1_sq, dims, False), {}, meta + ) + norm1 = super().call_operator( + torch.ops.aten.pow.Tensor_Scalar, (s1, 0.5), {}, meta + ) + + # 2b) norm2 = pow(sum(x2*x2), 0.5) + x2_sq = super().call_operator(torch.ops.aten.mul.Tensor, (x2, x2), {}, meta) + s2 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (x2_sq, dims, False), {}, meta + ) + norm2 = super().call_operator( + torch.ops.aten.pow.Tensor_Scalar, (s2, 0.5), {}, meta + ) + + # 3) eps scalar - we need to broadcast ourselves as TOSA dont do this for scalar + eps_t = super().call_operator( + torch.ops.aten.full_like.default, (norm1, eps), {}, meta + ) + + # 4) clamp to avoid zero division + n1c = super().call_operator( + torch.ops.aten.maximum.default, (norm1, eps_t), {}, meta + ) + n2c = super().call_operator( + torch.ops.aten.maximum.default, (norm2, eps_t), {}, meta + ) + + # 5) denom and divide + denom = super().call_operator(torch.ops.aten.mul.Tensor, (n1c, n2c), {}, meta) + out = super().call_operator(torch.ops.aten.div.Tensor, (dot, denom), {}, meta) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cumsum_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cumsum_pass.py new file mode 100644 index 0000000..143d08d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_cumsum_pass.py @@ -0,0 +1,167 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from math import prod +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass + +from executorch.backends.transforms.utils import create_constant_placeholder +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind + + +class DecomposeCumsumPass(ArmPass): + """ + Decomposes cumsum into a 1D convolution with a kernel of ones. + + For example, the cumsum of an input tensor [1, 1] is [1, 1 + 1] = [1, 2]. + To decompose this, take the input tensor and pre-padded with len(input)-1 zeros and + slided over with a kernel [1,1], of length len(input): + + Input: [0, 1, 1] + Kernel: [1, 1] = [1] + [1, 1] = [2] + + Since pytorch only supports symmetric padding, in reality the result will have + an additional 1 calculated at the end, which leads to an required extra slice op. + + To extend this to higher dimensions, the input is reshaped to [N, C, H, W] with + N = + C = 1 + H = + W = + And the convolution is applied over dimension H. + """ + + _passes_required_after: Set[Type[ExportPass]] = {RewriteConvPass} + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def call(self, graph_module): + graph = graph_module.graph + targets = (exir_ops.edge.aten.cumsum.default, torch.ops.aten.cumsum.default) + modified = False + for node in list(graph.nodes): + if node.op != "call_function" or node.target not in targets: + continue + + if len(node.args) != 2: + raise ValueError( + "Cumsum node should have exactly two arguments: input and dim." + ) + + # Get node data + input_node, dim = node.args + val = node.meta.get("val") + original_shape = list(val.shape) + dtype = input_node.meta.get("val").dtype + dim = dim % len(original_shape) + + # Compute shapes + pre_cumsum_dim = prod(original_shape[:dim]) if dim > 0 else 1 + cumsum_dim = original_shape[dim] + post_cumsum_dim = ( + prod(original_shape[dim + 1 :]) if dim < len(original_shape) - 1 else 1 + ) + conv_shape = [ + pre_cumsum_dim, + 1, + cumsum_dim, + post_cumsum_dim, + ] + pad_shape = [original_shape[dim] - 1, 0] + weight_shape = [1, 1, original_shape[dim], 1] + + # Create convolution weight + with graph.inserting_before(list(graph.nodes)[0]): + weight_data = torch.ones(size=weight_shape, dtype=dtype) + weight_node = create_constant_placeholder( + self.exported_program, + graph, + node.name + "_kernel", + InputKind.PARAMETER, + weight_data, + ) + + # Create decomposed nodes + view_op = exir_ops.edge.aten.view_copy.default + conv_op = exir_ops.edge.aten.convolution.default + slice_op = exir_ops.edge.aten.slice_copy.Tensor + with graph.inserting_before(node): + # Reshape to 4D with + view_args = (input_node, conv_shape) + view_node = create_node( + graph, + view_op, + args=view_args, + from_node=node, + inherit_qparams=False, + ) + + conv_args = ( + view_node, + weight_node, + None, + [1, 1], + pad_shape, + [1, 1], + False, + [0], + 1, + ) + conv_node = create_node( + graph, conv_op, args=conv_args, from_node=node, inherit_qparams=True + ) + + # The convolution is inserted after quantization, so we need to set our + # own quantization parameters for the weights here. However since the + # data is ones directly created as int8, they already have correct scale + # and so no scaling needs to be done, i.e. set scale=1.0, zero_point=0.0 + if ( + "input_qparams" in conv_node.meta + and len(conv_node.meta["input_qparams"]) > 0 + ): + qparams = QuantArgs(1.0, 0.0, -128, 127, torch.int8) + conv_node.meta["input_qparams"][1] = qparams + + slice_args = (conv_node, 2, 0, original_shape[dim]) + slice_node = create_node( + graph, + slice_op, + args=slice_args, + from_node=node, + inherit_qparams=False, + ) + + view_original_args = (slice_node, original_shape) + view_original_node = create_node( + graph, + view_op, + args=view_original_args, + from_node=node, + inherit_qparams=False, + ) + + # Replace and remove original + node.replace_all_uses_with(view_original_node) + graph.erase_node(node) + modified = True + + if modified: + # Cleanup + graph.eliminate_dead_code() + graph_module.recompile() + # Apply any operator-level transforms + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_pass.py new file mode 100644 index 0000000..e883fea --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_pass.py @@ -0,0 +1,61 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_div_ops = (exir_ops.edge.aten.div.Tensor,) +aten_div_ops = (torch.ops.aten.div.Tensor, torch.ops.aten.div_.Tensor) + + +def get_div_decomposition(op) -> tuple: + """ + Returns the the (reciprocal_op, mul_op), where the ops depends on if + the div op is in exir_ops torch.ops.aten. + """ + if op in edge_div_ops: + return (exir_ops.edge.aten.reciprocal.default, exir_ops.edge.aten.mul.Tensor) + if op in aten_div_ops: + return (torch.ops.aten.reciprocal.default, torch.ops.aten.mul.Tensor) + raise RuntimeError(f"Can't get div decomposition for op {op}") + + +class DecomposeDivPass(ArmPass): + """ + This pass decomposes div into a mul and a reciprocal node. + + Example: + y = div(a,b) + Becomes: + x = reciprocal(b) + y = mul(a,x) + """ + + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_div_ops + aten_div_ops) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + reciprocal_op, mul_op = get_div_decomposition(op) + + numerator = args[0] + denominator = args[1] + reciprocal = super().call_operator( + reciprocal_op, (denominator,), {}, meta, updated=True + ) + + return super().call_operator( + mul_op, (numerator, reciprocal), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_tensor_mode.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_tensor_mode.py new file mode 100644 index 0000000..39e22c4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_div_tensor_mode.py @@ -0,0 +1,94 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_div_mode_ops = (exir_ops.edge.aten.div.Tensor_mode,) +aten_div_mode_ops = (torch.ops.aten.div.Tensor_mode,) + +edge_unary = { + "div": exir_ops.edge.aten.div.Tensor, + "floor": exir_ops.edge.aten.floor.default, + "ceil": exir_ops.edge.aten.ceil.default, + "full": exir_ops.edge.aten.full.default, + "lt": exir_ops.edge.aten.lt.Tensor, + "where": exir_ops.edge.aten.where.self, +} + +aten_unary = { + "div": torch.ops.aten.div.Tensor, + "floor": torch.ops.aten.floor.default, + "ceil": torch.ops.aten.ceil.default, + "full": torch.ops.aten.full.default, + "lt": torch.ops.aten.lt.Tensor, + "where": torch.ops.aten.where.self, +} + + +def _get_opset(op): + if op in edge_div_mode_ops: + return edge_unary + if op in aten_div_mode_ops: + return aten_unary + raise RuntimeError(f"div.Tensor_mode not supported for op {op}") + + +class DecomposeDivTensorModePass(ArmPass): + """ + Rewrites aten.div.Tensor_mode into + + rounding_mode=None -> div(a, b) + rounding_mode='floor' -> floor(div(a, b)) + rounding_mode='trunc' -> where(div(a,b) < 0, ceil(div(a,b)), floor(div(a,b))) + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + edge_div_mode_ops + aten_div_mode_ops + ) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + opset = _get_opset(op) + + a, b = args[0], args[1] + rounding_mode = kwargs.get("rounding_mode", None) + if rounding_mode is None and len(args) > 2: + rounding_mode = args[2] + + q = super().call_operator(opset["div"], (a, b), {}, meta, updated=True) + + if rounding_mode is None: + return q + + if rounding_mode == "floor": + return super().call_operator(opset["floor"], (q,), {}, meta, updated=True) + + if rounding_mode == "trunc": + zero = super().call_operator( + opset["full"], + args=((1,) * len(meta["val"].size()), 0.0), + kwargs={"dtype": torch.float32, "device": meta["val"].device}, + meta=meta, + updated=True, + ) + lt0 = super().call_operator(opset["lt"], (q, zero), {}, meta, updated=True) + ceilq = super().call_operator(opset["ceil"], (q,), {}, meta, updated=True) + floorq = super().call_operator(opset["floor"], (q,), {}, meta, updated=True) + return super().call_operator( + opset["where"], (lt0, ceilq, floorq), {}, meta, updated=True + ) + + raise RuntimeError( + f"Unsupported rounding_mode for div.Tensor_mode: {rounding_mode!r}" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_elu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_elu_pass.py new file mode 100644 index 0000000..5428465 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_elu_pass.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_elu_ops = (exir_ops.edge.aten.elu.default,) + + +def get_elu_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.elu operation into + its equivalent TOSA-supported operations + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + elu(x, y) → where(greater_or_eq(x, 0), (exp(x)-1), x) + + Returns: + A tuple (expm1_op, ge_op, where_op, mul_op) corresponding to the appropriate operator + overloads for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported elu variant. + """ + + if op in edge_elu_ops: + return ( + exir_ops.edge.aten.expm1.default, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.mul.Scalar, + ) + + raise RuntimeError(f"Can't get elu decomposition for op {op}") + + +class DecomposeEluPass(ArmPass): + """ + A transformation pass that decomposes unsupported 'aten.elu' operations + into a combination of supported TOSA-equivalent operations. + + Since TOSA does not provide a native ELU operator, this pass rewrites: + elu(x) → where(greater_or_eq(x, 0), (alpha*(exp(x)-1)), x) + + Supported input ops: + - exir_ops.edge.aten.elu.Tensor(x) + + These are replaced with: + - exir_ops.edge.aten.expm1.default + - exir_ops.edge.aten.ge.Scalar + - exir_ops.edge.aten.where.self + - exir_ops.edge.aten.mul.Scalar + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_elu_ops: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + ( + expm1_op, + ge_op, + where_op, + mul_op, + ) = get_elu_decomposition(op) + + input = args[0] + alpha = args[1] if len(args) > 1 else 1.0 + + if alpha == 0: + relu_op = exir_ops.edge.aten.clamp.default + return super().call_operator( + relu_op, + ( + input, + 0, + ), + {}, + meta, + updated=True, + ) + + expm1_node = super().call_operator(expm1_op, (input,), {}, meta, updated=True) + mul_node = super().call_operator( + mul_op, (expm1_node, alpha), {}, meta, updated=True + ) + ge_node = super().call_operator(ge_op, (input, 0.0), {}, meta, updated=True) + where_node = super().call_operator( + where_op, (ge_node, input, mul_node), {}, meta, updated=True + ) + + return where_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_embedding_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_embedding_pass.py new file mode 100644 index 0000000..5b1f41f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_embedding_pass.py @@ -0,0 +1,126 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from math import prod +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.fuse_view_copy_transform_pass import ( + FuseViewCopyTransformPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +from .arm_pass_utils import create_node, get_first_fake_tensor + +logger = logging.getLogger(__name__) + + +class DecomposeEmbeddingPass(ArmPass): + """ + This pass decomposes embedding into index_select. + + Example: + o = embedding(w, i) + Becomes: + i = view_copy(i) # flatten indices + o = index_select(w, i) + o = view_copy(o) # reshape back output + Note: + i = indices is expected to be int32 before this pass + """ + + _passes_required_after: Set[Type[ExportPass]] = {FuseViewCopyTransformPass} + + aten_ops = (torch.ops.aten.embedding.default,) + edge_ops = (exir_ops.edge.aten.embedding.default,) + + def get_decomposition(self, op): + if op in self.aten_ops: + return ( + torch.ops.aten.reshape.default, + torch.ops.aten.index_select.default, + ) + + if op in self.edge_ops: + return ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.index_select.default, + ) + raise RuntimeError( + f"[{self.__class__.__name__}] Can't get decomposition for op {op}" + ) + + def call(self, graph_module): + graph = graph_module.graph + modified_graph = False + + for node in graph.nodes: + if node.op != "call_function": + continue + if node.target not in self.aten_ops + self.edge_ops: + continue + if not self.allowed_to_transform(node.meta): + continue + + args = node.args + + weights = args[0] + indices = args[1] + + weights_shape = get_first_fake_tensor(weights).shape + indices_shape = get_first_fake_tensor(indices).shape + + output_shape = torch.Size(list(indices_shape) + [weights_shape[1]]) + if output_shape != get_first_fake_tensor(node).shape: + raise RuntimeError( + f"[{self.__class__.__name__}] Unexpected output shape mismatch {output_shape} " + "!= {get_first_fake_tensor(node).shape}" + ) + + view_copy_op, index_select_op = self.get_decomposition(node.target) + + with graph.inserting_before(node): + reshaped_indices = [prod(list(indices_shape))] + flattened_indices = create_node( + graph=graph, + op_target=view_copy_op, + args=(indices, reshaped_indices), + ) + node.replace_input_with(indices, flattened_indices) + + index_select = create_node( + graph=graph, + op_target=index_select_op, + args=(weights, 0, flattened_indices), + ) + node.replace_all_uses_with(index_select) + graph.erase_node(node) + + with graph.inserting_after(index_select): + restored_output = create_node( + graph, + view_copy_op, + ) + restored_output.args = ( + index_select, + output_shape, + ) + original_users = [ + user for user in index_select.users if user != restored_output + ] + for user in original_users: + user.replace_input_with(index_select, restored_output) + + modified_graph = True + + if modified_graph: + graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_expm1_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_expm1_pass.py new file mode 100644 index 0000000..d2eb908 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_expm1_pass.py @@ -0,0 +1,163 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass +from executorch.backends.arm._passes.decompose_int_pow_pass import DecomposeIntPowPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_expm1_ops = (exir_ops.edge.aten.expm1.default,) # MI case + + +def _get_expm1_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.expm1 operation into + its equivalent TOSA-supported operations + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + expm1(x) → where(and(ge(x, -0.35), le(x, 0.35)), {taylor_series_expansion}, (exp(x)-1)) + + where {taylor_series_expansion} = x + (x^2/2) + (x^3/6) + (x^4/24) + + Returns: + A tuple (op_pow, op_div, op_add, op_exp, op_sub, op_ge, op_where, op_le, op_and) + corresponding to the appropriate operator overloads for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported elu variant. + """ + if op in edge_expm1_ops: + return ( + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.div.Scalar, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.logical_and.default, + ) + + raise RuntimeError(f"Can't get expm1 decomposition for op {op}") + + +class DecomposeExpm1Pass(ArmPass): + """ + A transformation pass that decomposes unsupported 'aten.expm1' operations + into a combination of supported TOSA-equivalent operations. + + Since TOSA does not provide a native expm1 operator, this pass rewrites: + expm1(x) → where(and(ge(x, -0.35), le(x, 0.35)), {taylor_series_expansion}, (exp(x)-1)) + where {taylor_series_expansion} = x + (x^2/2) + (x^3/6) + (x^4/24) + + Supported input ops: + - exir_ops.edge.aten.expm1.default(x) + + These are replaced with: + - exir_ops.edge.aten.pow.Tensor_Scalar, + - exir_ops.edge.aten.div.Scalar, + - exir_ops.edge.aten.add.Tensor, + - exir_ops.edge.aten.exp.default, + - exir_ops.edge.aten.sub.Scalar, + - exir_ops.edge.aten.ge.Scalar, + - exir_ops.edge.aten.where.self, + - exir_ops.edge.aten.le.Scalar, + - exir_ops.edge.aten.logical_and.default + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeIntPowPass, + InsertTableOpsPass, + DecomposeDivPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + MatchArgRanksPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in edge_expm1_ops: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + ( + op_pow, + op_div, + op_add, + op_exp, + op_sub, + op_ge, + op_where, + op_le, + op_and, + ) = _get_expm1_decomposition(op) + + input = args[0] + + cutlo = -0.35 + cuthi = 0.35 + + taylor_term_2_numerator = super().call_operator( + op_pow, (input, 2), {}, meta, updated=False + ) + taylor_term_3_numerator = super().call_operator( + op_pow, (input, 3), {}, meta, updated=False + ) + taylor_term_4_numerator = super().call_operator( + op_pow, (input, 4), {}, meta, updated=False + ) + + taylor_term_2 = super().call_operator( + op_div, (taylor_term_2_numerator, 2), {}, meta, updated=False + ) + taylor_term_3 = super().call_operator( + op_div, (taylor_term_3_numerator, 6), {}, meta, updated=False + ) + taylor_term_4 = super().call_operator( + op_div, (taylor_term_4_numerator, 24), {}, meta, updated=False + ) + + add_terms_1_2 = super().call_operator( + op_add, (input, taylor_term_2), {}, meta, updated=False + ) + add_term_3 = super().call_operator( + op_add, (add_terms_1_2, taylor_term_3), {}, meta, updated=False + ) + taylor_expansion = super().call_operator( + op_add, (add_term_3, taylor_term_4), {}, meta, updated=False + ) + + decomp_exp = super().call_operator(op_exp, (input,), {}, meta, updated=False) + decomp_sub = super().call_operator( + op_sub, (decomp_exp, 1.0), {}, meta, updated=False + ) + + ge = super().call_operator(op_ge, (input, cutlo), {}, meta, updated=False) + le = super().call_operator(op_le, (input, cuthi), {}, meta, updated=False) + + cond_and = super().call_operator(op_and, (ge, le), {}, meta, updated=False) + where = super().call_operator( + op_where, (cond_and, taylor_expansion, decomp_sub), {}, meta, updated=True + ) + + return where diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_floor_divide_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_floor_divide_pass.py new file mode 100644 index 0000000..c2754f4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_floor_divide_pass.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_div_tensor_mode import ( + DecomposeDivTensorModePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_floor_divide_ops = (exir_ops.edge.aten.floor_divide.default,) +aten_floor_divide_ops = (torch.ops.aten.floor_divide.default,) + + +def get_floor_divide_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.floor_div operation into + its equivalent TOSA-supported operations + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + floor_div(x, y) → div_tensor_mode(x, y, rounding_mode="floor") + + Returns: + A tuple (div_op,) corresponding to the appropriate operator overload for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported floor_divide variant. + """ + + if op in edge_floor_divide_ops: + return ( + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.full_like.default, + ) + if op in aten_floor_divide_ops: + return ( + torch.ops.aten.div.Tensor_mode, + torch.ops.aten.full_like.default, + ) + + raise RuntimeError(f"Can't get floor_div decomposition for op {op}") + + +class DecomposeFloorDividePass(ArmPass): + """ + Decomposes aten.floor_divide into aten.div.Tensor_mode with rounding_mode="floor". + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivTensorModePass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_floor_divide_ops + aten_floor_divide_ops): + return super().call_operator(op, args, kwargs, meta, updated=False) + + (div_op, full_op) = get_floor_divide_decomposition(op) + + input = args[0] + other = args[1] + + if isinstance(other, int): + other = super().call_operator( + full_op, (input, other), {}, meta, updated=False + ) + + div_node = super().call_operator( + div_op, (input, other), {"rounding_mode": "floor"}, meta, updated=True + ) + + return div_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_gelu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_gelu_pass.py new file mode 100644 index 0000000..5bf3937 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_gelu_pass.py @@ -0,0 +1,172 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +torch_gelu = (torch.ops.aten.gelu.default,) + +edge_gelu = (exir_ops.edge.aten.gelu.default,) + + +def _get_gelu_ops(op) -> tuple: + """ + Returns the operators needed to decompose GELU + """ + + if op in edge_gelu: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.tanh.default, + exir_ops.edge.aten.erf.default, + ) + if op in torch_gelu: + return ( + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + torch.ops.aten.mul.Tensor, + torch.ops.aten.tanh.default, + torch.ops.aten.erf.default, + ) + raise RuntimeError(f"Can't get GeLU decomposition ops for op {op}") + + +class DecomposeGeluPass(ArmPass): + """ + This pass decomposes the GELU operator into primitive ops. + Aiming to adhere closely to the reference implementations built into + ExecuTorch. Including using the same pre-calculated constants. + + This operator has two formulae depending on the value of the + approximate argument. Examples below include the added full + operators necessary for the initialization for constants used in + each respective formula. + + aten.gelu(x, approximate="none") becomes: + %FULL_0_5 = full() + %FULL_1 = full() + %FULL_SQRT1_2 = full() + %op1 = mul(x, %FULL_SQRT1_2) + %op2 = erf(%op1) + %op3 = add(%op2, %FULL_1) + %op4 = mul(%op3, %FULL_0_5) + %op5 = mul(%x, %op4) + + aten.gelu(x, approximate="tanh") becomes: + %FULL_0_5 = full() + %FULL_1 = full() + %FULL_SQRT2 = full() + %FULL_2_SQRTPI = full() + %FULL_CUBE_COEFF = full() + %SQRT_MUL = mul(%FULL_SQRT2, %FULL_2_SQRTPI) + %SQRT_2_PI = mul(%SQRT_MUL, %FULL_0_5) + %sqr_x = mul(x, x) + %cube_x = mul(sqr_x, x) + %op1 = mul(%cube_x, %FULL_CUBE_COEFF) + %op2 = add(%x, %op1) + %op3 = mul(%op2, %SQRT_2_PI) + %op4 = tanh(%op3) + %op5 = add(%op4, %FULL_1) + %op6 = mul(%x, %op5) + %op7 = mul(%op6, %FULL_0_5) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + InsertTableOpsPass, + MatchArgDtypePass, + MatchArgRanksPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in torch_gelu + edge_gelu: + return super().call_operator(op, args, kwargs, meta) + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + full_op, add_op, mul_op, tanh_op, erf_op = _get_gelu_ops(op) + + input = get_node_arg(args, 0) + # If approximate is default (none) it does not appear in kwargs + approximate = get_node_arg(kwargs, "approximate", "none") + + shape = meta["val"].size() + dtype = meta["val"].dtype + + FULL_0_5 = super().call_operator( + full_op, ([1] * len(shape), 0.5), {"dtype": dtype}, meta + ) + FULL_1 = super().call_operator( + full_op, ([1] * len(shape), 1), {"dtype": dtype}, meta + ) + + if approximate == "none": + # Constant mirrors ExecuTorch implementation for parity. + FULL_SQRT1_2 = super().call_operator( + full_op, ([1] * len(shape), 0.70710678118654752440), {}, meta + ) + + op1 = super().call_operator(mul_op, (input, FULL_SQRT1_2), {}, meta) + op2 = super().call_operator(erf_op, (op1,), {}, meta) + op3 = super().call_operator(add_op, (op2, FULL_1), {}, meta) + op4 = super().call_operator(mul_op, (op3, FULL_0_5), {}, meta) + return super().call_operator(mul_op, (input, op4), {}, meta) + + elif approximate == "tanh": + # Constants mirror ExecuTorch implementation for parity. + FULL_SQRT2 = super().call_operator( + full_op, + ([1] * len(shape), 1.41421356237309504880), + {"dtype": dtype}, + meta, + ) + FULL_2_SQRTPI = super().call_operator( + full_op, + ([1] * len(shape), 1.12837916709551257390), + {"dtype": dtype}, + meta, + ) + FULL_CUBE_COEFF = super().call_operator( + full_op, ([1] * len(shape), 0.044715), {"dtype": dtype}, meta + ) + + # Mirrors ExecuTorch implementations for calculating this value + SQRT_MUL = super().call_operator( + mul_op, (FULL_SQRT2, FULL_2_SQRTPI), {}, meta + ) + SQRT_2_PI = super().call_operator(mul_op, (SQRT_MUL, FULL_0_5), {}, meta) + + # Avoiding using POW in order to reduce pass order reliance. + sqr_x = super().call_operator(mul_op, (input, input), {}, meta) + cube_x = super().call_operator(mul_op, (sqr_x, input), {}, meta) + op1 = super().call_operator(mul_op, (cube_x, FULL_CUBE_COEFF), {}, meta) + op2 = super().call_operator(add_op, (input, op1), {}, meta) + op3 = super().call_operator(mul_op, (op2, SQRT_2_PI), {}, meta) + op4 = super().call_operator(tanh_op, (op3,), {}, meta) + op5 = super().call_operator(add_op, (op4, FULL_1), {}, meta) + op6 = super().call_operator(mul_op, (input, op5), {}, meta) + return super().call_operator(mul_op, (op6, FULL_0_5), {}, meta) + else: + raise RuntimeError( + f"approximate argument expected 'none' or 'tanh' but got {approximate}" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_glu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_glu_pass.py new file mode 100644 index 0000000..2143b5d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_glu_pass.py @@ -0,0 +1,81 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For FP case +edge_glu = exir_ops.edge.aten.glu.default + +# For INT case +aten_glu = torch.ops.aten.glu.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_glu: + return ( + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sigmoid.default, + exir_ops.edge.aten.slice_copy.Tensor, + ) + elif op == aten_glu: + return ( + torch.ops.aten.mul.Tensor, + torch.ops.aten.sigmoid.default, + torch.ops.aten.slice_copy.Tensor, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeGluPass(ArmPass): + """Decomposes the GLU operator into hadamard product and sigmoid.""" + + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in [edge_glu, aten_glu] or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + hadamard_prod, sigmoid, slice_op = get_ops(op) + X = args[0] + + dim = args[1] if len(args) > 1 else kwargs.get("dim", -1) + + if "val" not in X.node.meta: + raise Exception("Could not get dimension metadata in input.") + + if dim < 0: + dim += X.node.meta["val"].dim() + + n = X.node.meta["val"].size(dim) + + if n % 2: + raise RuntimeError( + f"glu expects an even split along dim={dim}, got size {n}" + ) + + middle = n // 2 + + T1 = super().call_operator( + slice_op, (X, dim, 0, middle), {}, meta, updated=True + ) + + T2 = super().call_operator( + slice_op, (X, dim, middle, n), {}, meta, updated=True + ) + + T2_sigmoid = super().call_operator(sigmoid, (T2,), {}, meta, updated=True) + + return super().call_operator( + hadamard_prod, (T1, T2_sigmoid), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_grouped_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_grouped_conv_pass.py new file mode 100644 index 0000000..a0765b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_grouped_conv_pass.py @@ -0,0 +1,185 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from copy import copy +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.conv1d_unsqueeze_pass import Conv1dUnsqueezePass +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeGroupedConvPass(ArmPass): + """ + Splits a grouped convolution which is not supported by TOSA into multiple + convolutions using slice->conv->cat. + + Before pass: + x = conv(input, weight, bias, groups = 2) + + After pass: + input1 = slice(input) + weight1 = slice(weight) + bias1 = slice(bias) + x1 = conv(input1, weight1, bias1) + + input2 = slice(input) + weight2 = slice(weight) + bias2 = slice(bias) + x2 = conv(input2, weight2, bias2) + + x = cat(x1, x2) + """ + + _passes_required_after: Set[Type[ExportPass]] = {Conv1dUnsqueezePass} + + @staticmethod + def _get_decomposition(op): + match op: + case exir_ops.edge.aten.convolution.default: + return ( + exir_ops.edge.aten.slice_copy.Tensor, + exir_ops.edge.aten.convolution.default, + exir_ops.edge.aten.cat.default, + ) + case torch.ops.aten.conv2d.default: + return ( + torch.ops.aten.slice_copy.Tensor, + torch.ops.aten.conv2d.default, + torch.ops.aten.cat.default, + ) + case _: + raise RuntimeError("Invalid op for grouped conv decomposition") + + @staticmethod + def _split_per_channel_qparams(qarg, index, output_slice_size): + if qarg is not None and qarg.per_channel: + start_index = index * output_slice_size + stop_index = (index + 1) * output_slice_size + return QuantArgs( + scale=qarg.scale[start_index:stop_index], + zp=qarg.zp[start_index:stop_index], + qmin=qarg.qmin, + qmax=qarg.qmax, + dtype=qarg.dtype, + axis=qarg.axis, + per_channel=qarg.per_channel, + ) + return qarg + + @staticmethod + def _get_meta_copy(meta, i, output_slice_size): + meta_copy = meta.copy() + if "input_qparams" in meta.data and len(meta.data["input_qparams"]) > 0: + # Handle per-channel quantization by splitting quantization params + # similarly to how activations/weights/biases are split. + new_qparams = meta.data.get("input_qparams").copy() + # Get quantization params of the weights and slice them. + qarg = new_qparams[1] + new_qparams[1] = DecomposeGroupedConvPass._split_per_channel_qparams( + qarg, index=i, output_slice_size=output_slice_size + ) + + meta_copy.data["input_qparams"] = new_qparams + + return meta_copy + + def call_operator(self, op, args, kwargs, meta): + if op == exir_ops.edge.aten.convolution.default: + groups = args[8] + transposed = args[6] + elif op == torch.ops.aten.conv2d.default: + groups = args[6] + transposed = False + else: + return super().call_operator(op, args, kwargs, meta) + + if groups == 1 or transposed: + return super().call_operator(op, args, kwargs, meta) + + input_node = args[0] + if input_node.data.shape[1] == groups: + # This is a depthwise convolution which is handled elsewhere + return super().call_operator(op, args, kwargs, meta) + + weight_node = args[1] + bias_node = args[2] + + input_slice_size = weight_node.data.shape[1] + output_slice_size = weight_node.data.shape[0] // groups + + no_q_dq_meta = copy(meta) + no_q_dq_meta.data = {} + no_q_dq_meta.data = {} + + slice_op, conv_op, cat_op = DecomposeGroupedConvPass._get_decomposition(op) + + input_slices = [] + for i in range(groups): + start_index = i * input_slice_size + stop_index = (i + 1) * input_slice_size + slice_args = (input_node, 1, start_index, stop_index) + + input_slices.append( + super().call_operator( + slice_op, slice_args, kwargs, no_q_dq_meta, updated=True + ) + ) + + filter_slices = [] + for i in range(groups): + start_index = i * output_slice_size + stop_index = (i + 1) * output_slice_size + slice_args = (weight_node, 0, start_index, stop_index) + + filter_slices.append( + super().call_operator( + slice_op, slice_args, kwargs, no_q_dq_meta, updated=True + ) + ) + + bias_slices = [] + for i in range(groups): + if bias_node is None: + bias_slices.append(None) + else: + start_index = i * output_slice_size + stop_index = (i + 1) * output_slice_size + slice_args = (bias_node, 0, start_index, stop_index) + + bias_slices.append( + super().call_operator( + slice_op, slice_args, kwargs, no_q_dq_meta, updated=True + ) + ) + + output_slices = [] + for i, (input_slice, filter_slice, bias_slice) in enumerate( + zip(input_slices, filter_slices, bias_slices) + ): + + meta_copy = DecomposeGroupedConvPass._get_meta_copy( + meta, i, output_slice_size + ) + + if op == exir_ops.edge.aten.convolution.default: + conv_args = (input_slice, filter_slice, bias_slice, *args[3:8], 1) + elif op == torch.ops.aten.conv2d.default: + conv_args = (input_slice, filter_slice, bias_slice, *args[3:6], 1) + else: + raise RuntimeError("Invalid op for grouped conv decomposition") + + output_slices.append( + super().call_operator( + conv_op, conv_args, kwargs, meta_copy, updated=True + ) + ) + + cat_args = (output_slices, 1) + # propagate original metadata (including quantization params) to the concatenated output + return super().call_operator(cat_op, cat_args, kwargs, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_groupnorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_groupnorm_pass.py new file mode 100644 index 0000000..322f694 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_groupnorm_pass.py @@ -0,0 +1,227 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_meandim_pass import DecomposeMeanDimPass +from executorch.backends.arm._passes.decompose_var_pass import DecomposeVarPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +def get_group_norm_decomposition(op) -> tuple: + if op == exir_ops.edge.aten.native_group_norm.default: + return ( + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.var.correction, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.view_copy.default, + ) + if op == torch.ops.aten.group_norm.default: + return ( + torch.ops.aten.mean.dim, + torch.ops.aten.sub.Tensor, + torch.ops.aten.var.correction, + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + torch.ops.aten.rsqrt.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.reshape.default, + ) + raise RuntimeError(f"Can't get group_norm composition for op {op}") + + +class DecomposeGroupNormPass(ArmPass): + """ + groupnorm is defined as: ((x - E[x]) / sqrt(Var[x] + eps)) * weights + bias + Decompose groupnorm(x, weight, bias, N, C, HxW, group, eps) to a sequence of: + mean = op_mean(x, dims) # E[x] + var = op_var(x, dims) # Var[x] + numerator = op_sub(x, mean) # (x - E[x]) + add = op_add(var, eps) # Var[x] + eps + rsqrt = op_rsqrt(add) # 1 / sqrt(Var[x] + eps) + mul = op_mul(numerator, rsqrt) # ((x - E[x]) / sqrt(Var[x] + eps)) + weigths = op_mul(mul, weigths) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias = op_add(weigths, bias) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias + where x can viewed with shape [N, group, C//group, HxW] dims=[C//group, HxW] + + Source: https://pytorch.org/docs/stable/generated/torch.nn.GroupNorm.html + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + DecomposeMeanDimPass, + DecomposeVarPass, + SizeAdjustInputPass, + } + + _TARGET_OPS = { + exir_ops.edge.aten.native_group_norm.default, + torch.ops.aten.group_norm.default, + } + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in DecomposeGroupNormPass._TARGET_OPS + or not self.allowed_to_transform(node.meta) + ): + continue + + # epsilon default value + eps = torch.finfo().eps + weights = None + bias = None + args = node.args + meta = node.meta + if isinstance(meta["val"], tuple): + shape = meta["val"][0].size() + dtype = meta["val"][0].dtype + device = meta["val"][0].device + else: + shape = meta["val"].size() + dtype = meta["val"].dtype + device = meta["val"].device + match len(args): + # MI profile always provides all the args: x, weight, bias, N, C, HxW, group, eps + case 8: + x, weights, bias, N, C, HxW, group, eps = args + # BI profile: affine=[True|False], eps!=1e-5 + case 5: + x, group, weights, bias, eps = args + # BI profile: affine=True, eps=1e-5 + case 4: + x, group, weights, bias = args + # BI profile: affine=False, eps=1e=5 + case 2: + x, group = args + # Unsupported args + case _: + raise ValueError( + f"Unsupported group_norm argument pattern with {len(args)} args" + ) + N = shape[0] + C = shape[1] + HxW = 1 + for dim in shape[2:]: + HxW *= dim + channels_per_group = C // group + grouped_shape = torch.Size([N, group, channels_per_group, HxW]) + dims = [2, 3] + epsilon_reshaped_shape = torch.Size([1] * len(grouped_shape)) + weights_reshaped_shape = torch.Size([1, group, channels_per_group, 1]) + ( + mean_op, + sub_op, + var_op, + full_op, + add_op, + rsqrt_op, + mul_op, + view_op, + ) = get_group_norm_decomposition(node.target) + with graph_module.graph.inserting_before(node): + keepdim = True + x_reshaped = create_node( + graph_module.graph, + view_op, + args=(x, grouped_shape), + from_node=node, + ) + mean = create_node( + graph_module.graph, mean_op, args=(x_reshaped, dims, keepdim) + ) + sub = create_node(graph_module.graph, sub_op, args=(x_reshaped, mean)) + var = create_node( + graph_module.graph, + var_op, + args=(x_reshaped, dims), + kwargs={"correction": 0, "keepdim": keepdim}, + from_node=node, + ) + full = create_node( + graph_module.graph, + full_op, + args=(epsilon_reshaped_shape, eps), + kwargs={"dtype": dtype, "device": device}, + from_node=node, + ) + add0 = create_node( + graph_module.graph, add_op, args=(var, full), from_node=node + ) + rsqrt = create_node( + graph_module.graph, rsqrt_op, args=(add0,), from_node=node + ) + mul0 = create_node( + graph_module.graph, mul_op, args=(sub, rsqrt), from_node=node + ) + if weights is not None: + weights_reshaped = create_node( + graph_module.graph, + view_op, + args=(weights, weights_reshaped_shape), + from_node=node, + ) + mul1 = create_node( + graph_module.graph, + mul_op, + args=( + mul0, + weights_reshaped, + ), + from_node=node, + ) + else: + mul1 = mul0 + if bias is not None: + bias_reshaped_shape = weights_reshaped_shape + bias_reshaped = create_node( + graph_module.graph, + view_op, + args=(bias, bias_reshaped_shape), + from_node=node, + ) + output = create_node( + graph_module.graph, + add_op, + args=(mul1, bias_reshaped), + from_node=node, + ) + else: + output = mul1 + + output_reshaped = create_node( + graph_module.graph, + view_op, + args=(output, shape), + from_node=node, + ) + + users = [user for user in node.users if node != user] + node.replace_all_uses_with(output_reshaped) + for user in users: + if user.target == operator.getitem: + user.replace_all_uses_with(output_reshaped) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + modified = True + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int16_activation_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int16_activation_conv_pass.py new file mode 100644 index 0000000..0a8c5ee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int16_activation_conv_pass.py @@ -0,0 +1,137 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Sequence, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.quant_args import QuantArgs + +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeConvWithInt16ActivationPass(ArmPass): + """ + This pass decomposes a convolution with input dtype int16 and bias + into a convolution without bias followed by an addition of the bias. + We also reshape the 1D bias to [1, C, 1, …] so it broadcasts along the channel + dimension. Since the TOSA op requires the bias to be int48 which is hard to represent + in torch. Instead rescale the int48 output to int16 and add the bias in int16. + """ + + def __init__(self) -> None: + super().__init__() + + _passes_required_after: Set[Type[ExportPass]] = set() + + def bias_view_shape( + self, bias: torch.Tensor, activation_rank: int + ) -> Sequence[int]: + # reshape bias to match convolution output rank so addition broadcasts over channels + return [1, bias.shape[0], *([1] * (activation_rank - 2))] + + def call_operator(self, op, args, kwargs, meta): + if op != exir_ops.edge.aten.convolution.default: + return super().call_operator(op, args, kwargs, meta) + + tosa_spec = get_context_spec() + if not tosa_spec.support_integer(): + return super().call_operator(op, args, kwargs, meta) + + # return if no bias + if args[2] is None: + return super().call_operator(op, args, kwargs, meta) + + activation_tensor = args[0].data + activation_rank = activation_tensor.dim() + + if activation_rank not in (4, 5) or activation_tensor.dtype != torch.int16: + return super().call_operator(op, args, kwargs, meta) + + if not tosa_spec.support_extension("int16"): + raise ValueError( + "int16 activation for convolution requires TOSA int16 extension" + ) + + # convolution with bias and activation is int16 (expected activation rank enforced above) + # The bias is assumed to be quantized with the same quantization parameters as + # the output of the convolution + bias_arg = args[2] + bias_data = bias_arg.data + + no_bias_args = list(args) + no_bias_args[2] = None + # split up to convolution + bias + convolution = super().call_operator(op, tuple(no_bias_args), kwargs, meta) + + # create a copy of the meta without the qparams, to be used with the new nodes + new_meta = meta.copy() + new_meta.data.pop("output_qparams", None) + new_meta.data.pop("input_qparams", None) + + # reshape the tensor to the same rank as the convolution output to add the bias to the channels + channel_bias = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (bias_arg, self.bias_view_shape(bias_data, activation_rank)), + {}, + new_meta, + ) + + output_dtype = meta.data["output_qparams"][0].dtype + + if output_dtype == torch.int16: + # The conv will get the output int48 scaled to int32 in serialization step. + # To be able to add the bias we need to first scale (cast?) the output to int32. + # The resulting i32 sum will then need to be scaled back to the output dtype. + output_qparams = cast(QuantArgs, meta.data["output_qparams"][0]) + conv_output_scale = output_qparams.scale + + bias_qparams = cast(QuantArgs, meta.data["input_qparams"][2]) + per_channel_quant = bias_qparams.per_channel + + if per_channel_quant: + bias_scale = bias_qparams.get_scale_per_channel() + else: + bias_scale = [bias_qparams.get_scale_per_tensor()] + + conv_rescale_factors = [1.0] * len(bias_scale) + final_output_scale = [b / conv_output_scale for b in bias_scale] + + conv_output = super().call_operator( + exir_ops.backend.tosa.RESCALE.default, + (convolution, torch.int32, conv_rescale_factors, 0, 0), + {}, + new_meta, + ) + + add = super().call_operator( + exir_ops.edge.aten.add.Tensor, + (conv_output, channel_bias), + {}, + new_meta, + ) + + res_rescale = super().call_operator( + exir_ops.backend.tosa.RESCALE.default, + ( + add, + output_dtype, + final_output_scale, + 0, + 0, + ), + {}, + new_meta, + ) + + else: + raise NotImplementedError( + f"Decomposition to conv+add only implemented for activation of int16 type, not for {output_dtype}" + ) + + return res_rescale diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int_pow_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int_pow_pass.py new file mode 100644 index 0000000..4db5e45 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_int_pow_pass.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeIntPowPass(ArmPass): + """ + Replaces pow with integer exponent with a series of multiplications. + Only handles pow.Tensor_Scalar and not pow.Tensor_Tensor. + Needs to be run before doing scalar to tensor conversion. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op != exir_ops.edge.aten.pow.Tensor_Scalar: + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + exp = args[1] + + # Handle zero first and return early + if exp == 0: + # return a tensor of ones with the same shape as x + return super().call_operator( + exir_ops.edge.aten.full_like.default, (x, 1), {}, meta, True + ) + + if not isinstance(exp, int): + return super().call_operator(op, args, kwargs, meta) + + # Handle negative exponent + if exp < 0: + x = super().call_operator( + exir_ops.edge.aten.reciprocal.default, (x,), {}, meta, True + ) + exp = -exp + + res = x + + # Consider exponentiation by squaring, if exp turns out to be large. + # Now we just roll out the multiplications. + for _ in range(exp - 1): + res = super().call_operator( + exir_ops.edge.aten.mul.Tensor, (res, x), {}, meta, True + ) + + return res diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_layernorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_layernorm_pass.py new file mode 100644 index 0000000..992b21f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_layernorm_pass.py @@ -0,0 +1,203 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_meandim_pass import DecomposeMeanDimPass +from executorch.backends.arm._passes.decompose_var_pass import DecomposeVarPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +def get_layer_norm_decomposition(op) -> tuple: + if op == exir_ops.edge.aten.native_layer_norm.default: + return ( + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.var.correction, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.view_copy.default, + ) + if op == torch.ops.aten.layer_norm.default: + return ( + torch.ops.aten.mean.dim, + torch.ops.aten.sub.Tensor, + torch.ops.aten.var.correction, + torch.ops.aten.full.default, + torch.ops.aten.add.Tensor, + torch.ops.aten.rsqrt.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.reshape.default, + ) + raise RuntimeError(f"Can't get layer_norm composition for op {op}") + + +class DecomposeLayerNormPass(ArmPass): + """ + layernorm is defined as: ((x - E[x]) / sqrt(Var[x] + eps)) * weights + bias + Decompose layernorm(x, normalized_shape, weights, bias, eps) to a sequence of: + mean = op_mean(x, dims) # E[x] + var = op_var(x, dims) # Var[x] + numerator = op_sub(x, mean) # (x - E[x]) + add = op_add(var, eps) # Var[x] + eps + rsqrt = op_rsqrt(add) # 1 / sqrt(Var[x] + eps) + mul = op_mul(numerator, rsqrt) # ((x - E[x]) / sqrt(Var[x] + eps)) + weigths = op_mul(mul, weigths) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias = op_add(weigths, bias) # ((x - E[x]) / sqrt(Var[x] + eps)) * weigths + bias + + Source: https://pytorch.org/docs/stable/generated/torch.nn.LayerNorm.html + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + DecomposeMeanDimPass, + DecomposeVarPass, + InsertTableOpsPass, + } + + _TARGET_OPS = { + exir_ops.edge.aten.native_layer_norm.default, + torch.ops.aten.layer_norm.default, + } + + def call(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target not in DecomposeLayerNormPass._TARGET_OPS + or not self.allowed_to_transform(node.meta) + ): + continue + + # epsilon default value + epsilon = torch.finfo().eps + weights = None + bias = None + args = node.args + meta = node.meta + match len(args): + case 6: + # torch.ops.aten.layer_norm.default has 6 args: + # (input, normalized_shape, weight, bias, eps, cudnn_enable) + # cudnn_enable is not used in the decomposition + x, normalized_shape, weights, bias, epsilon, _cudnn_enable = args + case 5: + x, normalized_shape, weights, bias, epsilon = args + case 4: + x, normalized_shape, weights, bias = args + case 3: + x, normalized_shape, weights = args + case _: + x, normalized_shape = args + + n_dims = len(normalized_shape) + if isinstance(meta["val"], tuple): + shape = meta["val"][0].size() + dtype = meta["val"][0].dtype + device = meta["val"][0].device + else: + shape = meta["val"].size() + dtype = meta["val"].dtype + device = meta["val"].device + rank = len(shape) + dims = list(range(-1, -1 * (n_dims + 1), -1)) + dims = [dim % rank for dim in dims] + weights_reshaped_shape = [shape[i] if i in dims else 1 for i in range(rank)] + epsilon_reshaped_shape = [1] * rank + + ( + mean_op, + sub_op, + var_op, + full_op, + add_op, + rsqrt_op, + mul_op, + view_op, + ) = get_layer_norm_decomposition(node.target) + with graph_module.graph.inserting_before(node): + keepdim = True + mean = create_node(graph_module.graph, mean_op, args=(x, dims, keepdim)) + sub = create_node(graph_module.graph, sub_op, args=(x, mean)) + var = create_node( + graph_module.graph, + var_op, + args=(x, dims), + kwargs={"correction": 0, "keepdim": keepdim}, + from_node=node, + ) + full = create_node( + graph_module.graph, + full_op, + args=(epsilon_reshaped_shape, epsilon), + kwargs={"dtype": dtype, "device": device}, + from_node=node, + ) + add0 = create_node( + graph_module.graph, add_op, args=(var, full), from_node=node + ) + rsqrt = create_node( + graph_module.graph, rsqrt_op, args=(add0,), from_node=node + ) + mul0 = create_node( + graph_module.graph, mul_op, args=(sub, rsqrt), from_node=node + ) + if weights is not None: + weights_reshaped = create_node( + graph_module.graph, + view_op, + args=(weights, weights_reshaped_shape), + from_node=node, + ) + mul1 = create_node( + graph_module.graph, + mul_op, + args=( + mul0, + weights_reshaped, + ), + from_node=node, + ) + else: + mul1 = mul0 + output = mul1 + if bias is not None: + bias_reshaped_shape = weights_reshaped_shape + bias_reshaped = create_node( + graph_module.graph, + view_op, + args=(bias, bias_reshaped_shape), + from_node=node, + ) + output = create_node( + graph_module.graph, + add_op, + args=(mul1, bias_reshaped), + from_node=node, + ) + + users = [user for user in node.users if node != user] + node.replace_all_uses_with(output) + for user in users: + if user.target == operator.getitem: + user.replace_all_uses_with(output) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_leaky_relu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_leaky_relu_pass.py new file mode 100644 index 0000000..3e52efe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_leaky_relu_pass.py @@ -0,0 +1,76 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_ops = (exir_ops.edge.aten.leaky_relu.default,) +torch_ops = (torch.ops.aten.leaky_relu.default,) + + +def _get_leaky_relu_ops(op) -> tuple: + if op in edge_ops: + return ( + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.add.Tensor, + ) + elif op in torch_ops: + return ( + torch.ops.aten.clamp.default, + torch.ops.aten.full.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.add.Tensor, + ) + else: + raise RuntimeError(f"Can't get decomposition ops for op {op}") + + +class DecomposeLeakyReLUPass(ArmPass): + """ + This pass decomposes Leaky ReLU into primitive operations. + LeakyReLU(x,slope) = max(0,x) + slope * min(0,x) + + Example: + %op1 = clamp(x,0,None) (equivalent to max(0,x)) + %op2 = clamp(x,None,0) (equivalent to min(0,x)) + %op3 = full(x.shape,slope) + %op4 = mul(%op3,%op2) + %op5 = add(%op1,%op4) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_ops + torch_ops) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + slope = args[1] if len(args) > 1 else 0.01 + dtype = x.node.meta["val"].dtype + device = x.node.meta["val"].device + clamp, full, mul, add = _get_leaky_relu_ops(op) + op1 = super().call_operator( + op=clamp, args=(x, 0, None), kwargs=kwargs, meta=meta + ) + op2 = super().call_operator( + op=clamp, args=(x, None, 0), kwargs=kwargs, meta=meta + ) + op3 = super().call_operator( + op=full, + args=(x.node.meta["val"].shape, slope), + kwargs={"dtype": dtype, "device": device}, + meta=meta, + ) + op4 = super().call_operator(op=mul, args=(op3, op2), kwargs=kwargs, meta=meta) + op5 = super().call_operator(op=add, args=(op1, op4), kwargs=kwargs, meta=meta) + return op5 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linalg_vector_norm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linalg_vector_norm_pass.py new file mode 100644 index 0000000..d766866 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linalg_vector_norm_pass.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sqrt_pass import DecomposeSqrtPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.exir.pass_base import ExportPass + + +class DecomposeLinalgVectorNormPass(ArmPass): + """ + This pass decomposes aten.linalg_vector_norm.default into more primitive ops. + We need to add this pass before quantization for graph annotation. + By default, aten.linalg_vector_norm op is decomposed during legalization to Edge IR. + + The decomposition is as follows: + + For p == 1: + out = REDUCE_SUM(ABS(x), dims, keepdim) + + For p == 2: + out = SQRT(REDUCE_SUM(MUL(x, x), dims, keepdim)) + + For arbitrary p: + We dont support arbitrary p, because our decomposition looks like + out = POW(REDUCE_SUM(POW(ABS(x), p), dims, keepdim), 1/p) + In this case we need to wrap p into Tensor and we need to know + dtype prior, but we dont know this from FX graph. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSqrtPass, + DecomposeSumPass, + } + + torch_linalg_vector_norm = (torch.ops.aten.linalg_vector_norm.default,) + + def call_operator(self, op, args, kwargs, meta): + if op not in self.torch_linalg_vector_norm or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + # Extract inputs and optional arguments. + # Expected args: + # args[0]: input tensor + # args[1]: norm order 'p' (optional, default: 2.0) + # args[2]: dimensions to reduce (should be provided) + # args[3]: keepdim flag (optional, default: False) + input_tensor = args[0] + norm_order = args[1] if len(args) > 1 else 2.0 + norm_dim = args[2] if len(args) > 2 else None + keepdim = args[3] if len(args) > 3 else False + + if norm_order not in (1, 2): + raise ValueError( + f"The order of {norm_order}\n" + f"is not supported for linalg_vector_norm operator" + ) + + # Sum over all dimensions if dim is None + if norm_dim is None: + rank = input_tensor.data.dim() + dims = list(range(rank)) + else: + dims = [norm_dim] if isinstance(norm_dim, int) else list(norm_dim) + + # Decomposition based on norm order. + if norm_order == 1: + op1 = super().call_operator( + torch.ops.aten.abs.default, (input_tensor,), {}, meta + ) + op2 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (op1, dims, keepdim), {}, meta + ) + return op2 + + elif norm_order == 2: + # For p == 2, decomposition is sqrt(sum(x * x, dims, keepdim)) + op1 = super().call_operator( + torch.ops.aten.mul.Tensor, (input_tensor, input_tensor), {}, meta + ) + op2 = super().call_operator( + torch.ops.aten.sum.dim_IntList, (op1, dims, keepdim), {}, meta + ) + op3 = super().call_operator(torch.ops.aten.sqrt.default, (op2,), {}, meta) + return op3 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linear_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linear_pass.py new file mode 100644 index 0000000..e1a9cfd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_linear_pass.py @@ -0,0 +1,109 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import numpy as np +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.insert_rescales_pass import InsertRescaleInt32Pass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeLinearPass(ArmPass): + """ + This pass decomposes linear into a Conv2D with the required view operations. + linear(x, weights, bias) becomes: + x_reshaped = view(x) + weights_reshaped = view(weights) + conv2d = conv2d(x_reshaped, weights_reshaped, bias) + output = view(conv2d) + """ + + _passes_required_after: Set[Type[ExportPass]] = {InsertRescaleInt32Pass} + + def call(self, graph_module): + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target != exir_ops.edge.aten.linear.default: + continue + args = node.args + input = args[0] + weights = args[1] + bias = args[2] if len(args) > 2 else None + output_shape = get_first_fake_tensor(node).shape + input_shape = get_first_fake_tensor(input).shape + weights_shape = get_first_fake_tensor(weights).shape + batches = int(np.prod(input_shape[:-1])) if len(input_shape) > 1 else 1 + # input has shape (..., Ci) + input_reshaped_shape = [batches, input_shape[-1], 1, 1] + # weights have shape (Co, Ci) + weights_reshaped_shape = [weights_shape[0], weights_shape[1], 1, 1] + + with graph_module.graph.inserting_before(node): + # Reshape input to 4D with shape (N, Ci, 1, 1) + input_reshaped = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.view_copy.default, + args=(input, input_reshaped_shape), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + + # Reshape weights to 4D with shape (Co, Ci, 1, 1) + weights_reshaped = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.view_copy.default, + args=(weights, weights_reshaped_shape), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + + conv = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.convolution.default, + args=( + input_reshaped, + weights_reshaped, + bias, + [1, 1], # strides + [0, 0], # padding + [1, 1], # dilation + False, # transposed + [0, 0], # output padding + 1, # groups + ), + kwargs={}, + from_node=node, + inherit_qparams=True, + ) + + with graph_module.graph.inserting_after(conv): + # Reshape output to same rank as original input with shape (..., Co) + # No need to insert q/dq pair as Conv2D node above has inserted them if + # required. + output = create_node( + graph=graph_module.graph, + op_target=exir_ops.edge.aten.view_copy.default, + args=(conv, list(output_shape)), + kwargs={}, + from_node=node, + inherit_qparams=False, + ) + + node.replace_all_uses_with(output) + graph_module.graph.erase_node(node) + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_log1p_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_log1p_pass.py new file mode 100644 index 0000000..4531d66 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_log1p_pass.py @@ -0,0 +1,97 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeLog1pPass(ArmPass): + """Decompose log1p into a small polynomial with a log fallback for larger inputs.""" + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + _supported_ops = { + exir_ops.edge.aten.log1p.default, + } + + def _poly(self, x, meta): + # 6-term Taylor: x - x^2/2 + x^3/3 - x^4/4 + x^5/5 - x^6/6 + op_mul = exir_ops.edge.aten.mul.Tensor + op_mul_scalar = exir_ops.edge.aten.mul.Scalar + op_add = exir_ops.edge.aten.add.Tensor + + x2 = super().call_operator(op_mul, (x, x), {}, meta, updated=True) + x3 = super().call_operator(op_mul, (x2, x), {}, meta, updated=True) + x4 = super().call_operator(op_mul, (x3, x), {}, meta, updated=True) + x5 = super().call_operator(op_mul, (x4, x), {}, meta, updated=True) + x6 = super().call_operator(op_mul, (x5, x), {}, meta, updated=True) + + t2 = super().call_operator(op_mul_scalar, (x2, -0.5), {}, meta, updated=True) + t3 = super().call_operator( + op_mul_scalar, (x3, 1.0 / 3.0), {}, meta, updated=True + ) + t4 = super().call_operator(op_mul_scalar, (x4, -0.25), {}, meta, updated=True) + t5 = super().call_operator(op_mul_scalar, (x5, 0.2), {}, meta, updated=True) + t6 = super().call_operator( + op_mul_scalar, (x6, -1.0 / 6.0), {}, meta, updated=True + ) + + acc = super().call_operator(op_add, (x, t2), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t3), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t4), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t5), {}, meta, updated=True) + acc = super().call_operator(op_add, (acc, t6), {}, meta, updated=True) + return acc + + def call_operator(self, op, args, kwargs, meta): + if op not in self._supported_ops: + return super().call_operator(op, args, kwargs, meta, updated=False) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # Quantized log1p should be handled by LUT/table instead of decomposition. + return super().call_operator(op, args, kwargs, meta) + + logging.info("Decomposing log1p via polynomial + log branch for FP profile.") + + x = args[0] + approx = self._poly(x, meta) + + # For x > 1e-3, use log(1+x) directly. + op_add_scalar = exir_ops.edge.aten.add.Scalar + op_gt = exir_ops.edge.aten.gt.Scalar + op_where = exir_ops.edge.aten.where.self + op_log = exir_ops.edge.aten.log.default + + one_plus_x = super().call_operator( + op_add_scalar, (x, 1.0), {}, meta, updated=True + ) + log_branch = super().call_operator( + op_log, (one_plus_x,), {}, meta, updated=True + ) + + mask = super().call_operator(op_gt, (x, 1e-3), {}, meta, updated=True) + result = super().call_operator( + op_where, (mask, log_branch, approx), {}, meta, updated=True + ) + return result diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_logit_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_logit_pass.py new file mode 100644 index 0000000..f469b84 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_logit_pass.py @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For FP case +edge_logit = exir_ops.edge.aten.logit.default +# For INT case +aten_logit = torch.ops.aten.logit.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_logit: + return ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.clamp.default, + ) + elif op == aten_logit: + return ( + torch.ops.aten.log.default, + torch.ops.aten.add.Scalar, + torch.ops.aten.reciprocal.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.mul.Scalar, + torch.ops.aten.clamp.default, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeLogitPass(ArmPass): + """ + Decomposes the `logit` operator into a sequence of primitive operations. + + If `eps` is provided, the input tensor `x` is first clamped to the range + [eps, 1 - eps]. + + The decomposition follows the identity: + + logit(x) = log(x / (1 - x)) + + Examples: + + logit(x) becomes: + log(x * reciprocal((-1) * x + 1)) + + logit(x, eps) becomes: + y = clamp(x, eps, 1 - eps) + log(y * reciprocal((-1) * y + 1)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + MatchArgDtypePass, + ReplaceScalarWithTensorByProfilePass, + } + + _TARGET_OPS = { + edge_logit, + aten_logit, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in DecomposeLogitPass._TARGET_OPS or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + X = args[0] + eps = args[1] if len(args) > 1 else kwargs.get("eps", None) + + ( + log_op, + add_scalar_op, + recip_op, + mul_tensor_op, + mul_scalar_op, + clamp_op, + ) = get_ops(op) + + if eps is not None: + X = super().call_operator( + clamp_op, (X, eps, 1.0 - eps), {}, meta, updated=True + ) + + neg_X = super().call_operator(mul_scalar_op, (X, -1.0), {}, meta, updated=True) + + denom = super().call_operator( + add_scalar_op, (neg_X, 1.0), {}, meta, updated=True + ) + + frac = super().call_operator(recip_op, (denom,), {}, meta, updated=True) + + log_input = super().call_operator( + mul_tensor_op, (X, frac), {}, meta, updated=True + ) + + return super().call_operator(log_op, (log_input,), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_masked_fill_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_masked_fill_pass.py new file mode 100644 index 0000000..49a4bbb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_masked_fill_pass.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_full_like_to_full_pass import ( + ConvertFullLikeToFullPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_ops = (exir_ops.edge.aten.masked_fill.Scalar,) +aten_ops = (torch.ops.aten.masked_fill.Scalar, torch.ops.aten.masked_fill_.Scalar) + + +def _get_decomposition(op) -> tuple: + if op in edge_ops: + return ( + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.full_like.default, + ) + elif op in aten_ops: + return ( + torch.ops.aten.where.self, + torch.ops.aten.full_like.default, + ) + raise RuntimeError(f"Unable to get decomposition for op {op}") + + +class DecomposeMaskedFillPass(ArmPass): + """ + Masked fill takes in a boolean mask, a tensor and a scalar value. + Fills the tensor with the scalar value according to the boolean mask. + Decomposed to a where and a full_like operator. + """ + + _passes_required_after: Set[Type[ExportPass]] = {ConvertFullLikeToFullPass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op not in (*aten_ops, *edge_ops): + return super().call_operator(op, args, kwargs, meta, updated) + + x, mask, scalar = args + + where_op, full_like_op = _get_decomposition(op) + + scalar_tensor = super().call_operator(full_like_op, (x, scalar), {}, meta, True) + + return super().call_operator( + where_op, (mask, scalar_tensor, x), kwargs, meta, True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py new file mode 100644 index 0000000..bf3f6af --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_maxpool2d_with_dilation_pass.py @@ -0,0 +1,218 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import operator +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# We'll decompose only the EXIR edge max_pool2d ops when dilation > 1 +EDGE_MAXPOOL2D = ( + exir_ops.edge.aten.max_pool2d.default, + exir_ops.edge.aten.max_pool2d_with_indices.default, +) + + +class DecomposeMaxPool2dPass(ArmPass): + """ + Decompose dilated max_pool2d (EXIR edge ops) into space-to-batch -> maxpool -> batch-to-space. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + SizeAdjustInputPass, + } + + def call_operator(self, op, args, kwargs, meta): + # Only intercept EXIR edge max_pool2d ops + if op not in EDGE_MAXPOOL2D: + return super().call_operator(op, args, kwargs, meta) + + # detect whether indices variant + is_with_indices = op is exir_ops.edge.aten.max_pool2d_with_indices.default + + # Normalize missing trailing args to their defaults + x = args[0] + kernel_size = args[1] + stride = args[2] + padding = args[3] if len(args) >= 4 else 0 + dilation = args[4] if len(args) >= 5 else 1 + ceil_mode = args[5] if len(args) == 6 else False + + # Normalize attributes + pad_h, pad_w = (padding, padding) if isinstance(padding, int) else padding + d_h, d_w = (dilation, dilation) if isinstance(dilation, int) else dilation + k_h, k_w = ( + (kernel_size, kernel_size) if isinstance(kernel_size, int) else kernel_size + ) + s_h, s_w = (stride, stride) if isinstance(stride, int) else stride + + # If no dilation: call EXIR edge op + if d_h == 1 and d_w == 1: + minimal_args = [x, kernel_size, stride, padding, dilation, ceil_mode] + return super().call_operator(op, tuple(minimal_args), {}, meta) + + # Compute padded and packed dimensions for dilation > 1 + N, C, H, W = x.data.size() + ph, pw = pad_h, pad_w + ph2, pw2 = pad_h, pad_w + H_pad = H + ph + ph2 + W_pad = W + pw + pw2 + H_pack = (H_pad + d_h - 1) // d_h + W_pack = (W_pad + d_w - 1) // d_w + extra_h = 0 if H_pack < k_h else (s_h - ((H_pack - k_h) % s_h)) % s_h + extra_w = 0 if W_pack < k_w else (s_w - ((W_pack - k_w) % s_w)) % s_w + ph2 += extra_h * d_h + pw2 += extra_w * d_w + + meta_with_no_qparams = meta.copy() + meta_with_no_qparams.data["output_qparams"] = {} + meta_with_no_qparams.data["input_qparams"] = {} + meta_with_no_output_qparams = meta.copy() + meta_with_no_output_qparams.data["output_qparams"] = {} + + # 1) Pad via EXIR edge pad (preserves dtype) + pad_edge = exir_ops.edge.aten.constant_pad_nd.default + pads = [pw, pw2, ph, ph2, 0, 0, 0, 0] + x_pad = super().call_operator( + pad_edge, + (x, pads, 0), + {}, + meta_with_no_output_qparams, + ) + + # 2) Space-to-batch: reshape and permute + x2 = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x_pad, [N, C, H_pack, d_h, W_pack, d_w]), + {}, + meta_with_no_qparams, + ) + x2 = super().call_operator( + exir_ops.edge.aten.permute_copy.default, + (x2, [3, 5, 0, 1, 2, 4]), + {}, + meta_with_no_qparams, + ) + x2 = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (x2, [N * d_h * d_w, C, H_pack, W_pack]), + {}, + meta_with_no_qparams, + ) + + # 3) Core pooling on packed tensor + pool_edge_op = ( + exir_ops.edge.aten.max_pool2d_with_indices.default + if is_with_indices + else exir_ops.edge.aten.max_pool2d.default + ) + pool_args = (x2, (k_h, k_w), (s_h, s_w), (0, 0), 1, ceil_mode) + pool_out = super().call_operator( + pool_edge_op, + pool_args, + {}, + meta, + ) + + # Unpack pooled result + if is_with_indices: + pooled_proxy = super().call_operator( + operator.getitem, + (pool_out, 0), + {}, + meta_with_no_qparams, + ) + indices_proxy = super().call_operator( + operator.getitem, + (pool_out, 1), + {}, + meta_with_no_qparams, + ) + pooled_fake, _ = pool_out.data + else: + pooled_proxy = pool_out + pooled_fake = pool_out.data + indices_proxy = None + + _, C_out, H_out, W_out = pooled_fake.shape + + # 4) Batch-to-space: reshape and permute back + out = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (pooled_proxy, [d_h, d_w, N, C_out, H_out, W_out]), + {}, + meta_with_no_qparams, + ) + out = super().call_operator( + exir_ops.edge.aten.permute_copy.default, + (out, [2, 3, 4, 0, 5, 1]), + {}, + meta_with_no_qparams, + ) + # now flatten back into (N, C, H_out*d_h, W_out*d_w) + out = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (out, [N, C_out, H_out * d_h, W_out * d_w]), + {}, + meta_with_no_qparams, + ) + + # 5) Final crop + S_top = ph // d_h + (1 if ph % d_h else 0) + S_left = pw // d_w + (1 if pw % d_w else 0) + S_top = max(0, min(S_top, H_out * d_h - H)) + S_left = max(0, min(S_left, W_out * d_w - W)) + out = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (out, 2, S_top, S_top + H), + {}, + meta_with_no_qparams, + ) + out = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (out, 3, S_left, S_left + W), + {}, + meta_with_no_qparams, + ) + + if is_with_indices: + # Reconstruct indices + idx = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (indices_proxy, [d_h, d_w, N, C_out, H_out, W_out]), + {}, + meta_with_no_qparams, + ) + idx = super().call_operator( + exir_ops.edge.aten.permute_copy.default, + (idx, [2, 3, 4, 0, 5, 1]), + {}, + meta, + ) + idx = super().call_operator( + exir_ops.edge.aten.view_copy.default, + (idx, [N, C_out, H_out * d_h, W_out * d_w]), + {}, + meta_with_no_qparams, + ) + idx = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (idx, 2, S_top, S_top + H), + {}, + meta_with_no_qparams, + ) + idx = super().call_operator( + exir_ops.edge.aten.slice_copy.Tensor, + (idx, 3, S_left, S_left + W), + {}, + meta_with_no_qparams, + ) + return out, idx + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_meandim_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_meandim_pass.py new file mode 100644 index 0000000..a8cac5a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_meandim_pass.py @@ -0,0 +1,283 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from copy import copy +from math import prod +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.size_adjust_input_pass import SizeAdjustInputPass +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.exir.backend.utils import WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def get_meandim_decomposition(op) -> tuple: + if op in (exir_ops.edge.aten.mean.dim, exir_ops.edge.aten.mean.default): + return ( + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in (torch.ops.aten.mean.dim, torch.ops.aten.mean.default): + return ( + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.full.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get meandim decomposition for op {op}") + + +def get_avgpool(op): + if op in (exir_ops.edge.aten.mean.dim, exir_ops.edge.aten.mean.default): + return exir_ops.edge.aten.avg_pool2d.default + if op in (torch.ops.aten.mean.dim, torch.ops.aten.mean.default): + return torch.ops.aten.avg_pool2d.default + raise RuntimeError(f"Can't get meandim decomposition for op {op}") + + +def get_view(op): + if op in (exir_ops.edge.aten.mean.dim, exir_ops.edge.aten.mean.default): + return exir_ops.edge.aten.view_copy.default + if op in (torch.ops.aten.mean.dim, torch.ops.aten.mean.default): + return torch.ops.aten.reshape.default + raise RuntimeError(f"Can't get meandim decomposition for op {op}") + + +def get_quantization(op): + """Returns quant and dequant op of same type (per_channel/ tensor) as op if op is a dequant node, None otherwise.""" + if op in DQ_OPS: + # Input of op can be placeholder, can't use that to get quant node directly. + quant_type_index = DQ_OPS.index(op) + return Q_OPS[quant_type_index], op + return None + + +class DecomposeMeanDimPass(ArmPass): + """ + Decomposes a meandim into avg_pool and/or sum + mul (1/N) depending on which dims the mean is taken for: + h,w -> avg_pool + n,c -> sum + mul(1/N) + For rank < 4, the input is first reshaped to 4D by padding with dim=1 from the left. + + Example: + x = mean_dim(x, (0,2), keepdim=False) # x = (c,h,w) + Becomes: + x = view_copy.default(x, new_shape=(1,c,h,w)) # Reshape to work with avg_pool + x = avg_pool2d.default(x, kernel=(1,w), stride=(1,1)) # Reduce w with avg_pool + x = sum.dim_IntList(x, dim=1, keepdims=True) # Reduce c with sum + x = mul.Tensor(x, 1/c) # Divide by number of channels to get mean + x = view_copy.default(x, new_shape=(h)) # Squeeze dims since keepdims = False + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + DecomposeSumPass, + SizeAdjustInputPass, + } + + def __init__(self, graph_module, tosa_spec, *args, **kwargs): + super().__init__(*args, **kwargs) + self._graph_module = graph_module + self._tosa_spec = tosa_spec + # Lazy import to avoid circular dependency with operator_support + from executorch.backends.arm.operator_support.pool_2d_support import ( + AvgPool2dSupported, + ) + + self._avg_pool_checker = AvgPool2dSupported( + self._tosa_spec, WhyNoPartitionReporter() + ) + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + exir_ops.edge.aten.mean.dim, + torch.ops.aten.mean.dim, + exir_ops.edge.aten.mean.default, + torch.ops.aten.mean.default, + ) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x = get_node_arg(args, 0) + input_shape = list(x.data.shape) + output_shape = list(meta["val"].shape) + dims_to_reduce = get_node_arg(args, 1, range(len(input_shape))) + if dims_to_reduce is None: + dims_to_reduce = range(len(input_shape)) + dims_to_reduce = [dim % len(input_shape) for dim in dims_to_reduce] + dims_to_reduce = [dim for dim in dims_to_reduce if input_shape[dim] != 1] + + dtype = meta["val"].dtype + view_op = get_view(op) + + # Reshape to 4D + if len(input_shape) != 4: + new_shape = copy(input_shape) + + while len(new_shape) < 4: + new_shape.insert(0, 1) + dims_to_reduce = [dim + 1 for dim in dims_to_reduce] + + while len(new_shape) > 4: + i = new_shape.pop(0) + new_shape[0] = new_shape[0] * i + dims_to_reduce = [dim - 1 for dim in dims_to_reduce] + + x = super().call_operator(view_op, (x, new_shape), {}, meta, True) + x = self._maybe_insert_q_dq_after(x, meta) + + # Reduce (h,w) dims by avg pool if possible + x, dims_to_reduce = self._reduce_by_average_pool(op, x, dims_to_reduce, meta) + + # Reshape back to 5D if necessary + if len(input_shape) > 4: + original_dims = input_shape[0:-3] + temp_shape = list(x.data.shape)[1:] + temp_shape = original_dims + temp_shape + dims_to_reduce = [dim + len(original_dims) - 1 for dim in dims_to_reduce] + + x = super().call_operator(view_op, (x, temp_shape), {}, meta, True) + x = self._maybe_insert_q_dq_after(x, meta) + # Reduce remaining dims by sum + x = self._reduce_by_sum(op, x, dims_to_reduce, meta, dtype) + + # Reshape to correct output shape if necessary + if list(x.data.shape) != output_shape: + x = super().call_operator(view_op, (x, output_shape), {}, meta, True) + + return x + + def _reduce_by_sum(self, op, input_node, dims, meta, dtype): + if len(dims) == 0: + return input_node + + input_shape = input_node.data.size() + output_shape = meta["val"].size() + N = prod((n for i, n in enumerate(input_shape) if i in dims)) + sum_op, full_op, mul_op = get_meandim_decomposition(op) + + sum = super().call_operator(sum_op, (input_node, dims, True), {}, meta, True) + full = super().call_operator( + full_op, + ([1] * len(output_shape), 1 / N), + {"dtype": dtype, "device": input_node.data.device}, + meta, + True, + ) + if (quant_ops := get_quantization(input_node.node.target)) is not None: + # Insert Q and DQ nodes after full op. + # Since the value of full is known, we can compute quant params such that dq(q_max_value) + q_op, dq_op = quant_ops + qmax = input_node.node.args[4] + full_quant_args = ( + 1 / (N * qmax), # Scale to map qmax to 1/N + 0, # Zero point + *input_node.node.args[3:], + ) + q_args = (full, *full_quant_args) + full = super().call_operator( + q_op, + q_args, + kwargs={}, + meta=meta, + updated=True, + ) + dq_args = (full, *full_quant_args) + full = super().call_operator( + dq_op, dq_args, kwargs={}, meta=meta, updated=True + ) + + # Insert Q and DQ nodes after sum op. + # Scale needs to be adjusted with N, since it was computed on data after the division with N. + sum_quant_args = (input_node.node.args[1] * N, *input_node.node.args[2:]) + q_args = (sum, *sum_quant_args) + sum = super().call_operator( + q_op, + q_args, + kwargs={}, + meta=meta, + updated=True, + ) + dq_args = (sum, *sum_quant_args) + sum = super().call_operator( + dq_op, dq_args, kwargs={}, meta=meta, updated=True + ) + + return super().call_operator(mul_op, (sum, full), {}, meta, True) + + def _reduce_by_average_pool(self, op, input_node, dims, meta): + dims_to_reduce_by_avgpool = [dim for dim in dims if dim >= 2] + if len(dims_to_reduce_by_avgpool) == 0: + return input_node, dims + + dims_to_reduce_by_sum = [dim for dim in dims if dim < 2] + + avgpool_op = get_avgpool(op) + input_shape = input_node.data.size() + + stride = [1, 1] + if dims_to_reduce_by_avgpool in ([2, 3], [3, 2]): + kernel_size = [input_shape[2], input_shape[3]] + elif dims_to_reduce_by_avgpool == [3]: + kernel_size = [1, input_shape[3]] + elif dims_to_reduce_by_avgpool == [2]: + kernel_size = [input_shape[2], 1] + else: + raise RuntimeError( + f"Bad dims {dims_to_reduce_by_avgpool} for {op} decomposition of mean_dim." + ) + + args = (input_node, kernel_size, stride) + + avg_pool_node = self._graph_module.graph.create_node( + "call_function", avgpool_op, args + ) + is_supported = self._avg_pool_checker.is_node_tosa_supported( + avg_pool_node, self._tosa_spec + ) + + if is_supported: + out = super().call_operator(avgpool_op, args, {}, meta, True) + out = self._maybe_insert_q_dq_after(out, meta) + return ( + out, + dims_to_reduce_by_sum, + ) + + else: + return input_node, dims + + def _maybe_insert_q_dq_after(self, op, meta): + """If the input node of op is a dequant node, insert a q-dq pair after op with identical quantization parameters.""" + + if len(op.node.all_input_nodes) > 1: + raise ValueError( + f"Expected one input to {op.node}, got inputs {op.node.all_input_nodes}" + ) + input_node = op.node.all_input_nodes[0] + if (quant_ops := get_quantization(input_node.target)) is not None: + q_op, dq_op = quant_ops + quant_args = list(input_node.args[1:]) + q_args = (op, *quant_args) + out = super().call_operator( + q_op, + q_args, + kwargs={}, + meta=meta, + updated=True, + ) + dq_args = (out, *quant_args) + return super().call_operator( + dq_op, dq_args, kwargs={}, meta=meta, updated=True + ) + else: + return op diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_ne_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_ne_pass.py new file mode 100644 index 0000000..eff2255 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_ne_pass.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_ne_ops = (exir_ops.edge.aten.ne.Tensor,) +aten_ne_ops = (torch.ops.aten.ne.Tensor, torch.ops.aten.ne_.Tensor) + + +def get_ne_decomposition(op) -> tuple: + """ + Returns the decomposition of the given aten.ne operation into its equivalent + TOSA-supported operations. + + This handles both edge dialect ops and core PyTorch ops. The decomposition strategy + is: + ne(x, y) -> logical_not(eq(x, y)) + + Returns: + A tuple (eq_op, logical_not_op) corresponding to the appropriate operator + overloads for the input op. + + Raises: + RuntimeError: If the provided operator is not a supported ne variant. + """ + if op in edge_ne_ops: + return (exir_ops.edge.aten.eq.Tensor, exir_ops.edge.aten.logical_not.default) + if op in aten_ne_ops: + return (torch.ops.aten.eq.Tensor, torch.ops.aten.logical_not.default) + + raise RuntimeError(f"Can't get ne decomposition for op {op}") + + +class DecomposeNotEqualPass(ArmPass): + """ + A transformation pass that decomposes unsupported `aten.ne` operations into a + combination of supported TOSA-equivalent operations. + + Since TOSA does not provide a native NOT_EQUAL operator, this pass rewrites: + ne(x, y) → logical_not(eq(x, y)) + + Supported input ops: + - aten.ne.Tensor(x, y) + - aten.ne_.Tensor(x, y) + - exir_ops.edge.aten.ne.Tensor(x, y) + + These are replaced with: + - aten.eq.Tensor or exir_ops.edge.aten.eq.Tensor + - followed by aten.logical_not.default or its edge equivalent + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_ne_ops + aten_ne_ops) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + lhs, rhs = args + + eq_op, logical_not_op = get_ne_decomposition(op) + + eq_node = super().call_operator(eq_op, (lhs, rhs), {}, meta, updated=True) + not_node = super().call_operator( + logical_not_op, (eq_node,), {}, meta, updated=True + ) + + return not_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_quant_nodes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_quant_nodes.py new file mode 100644 index 0000000..3cc99e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_quant_nodes.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_round_pass import DecomposeRoundPass +from executorch.backends.arm.constants import DEQUANT_PER_TENSOR_OP, QUANT_PER_TENSOR_OP +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeQuantNodesPass(ArmPass): + """Decomposes quantization nodes into more primitive operations by rewriting the graph + using the two formulas: + + quantized value = clamp(round(fp32_value / scale) + zero point, qmin, qmax) + + fp32_value = (quantized value - zp) * scale + + For quantization nodes, the pass replaces them with: + + 1. Multiplying the input by the inverse of the scale factor. + 2. Rounding the result. + 3. Adding the zero point. + 4. Clamping the result to [qmin, qmax]. + 5. Casting to the target data type. + + For dequantization nodes, the pass replaces them with: + + 1. Casting the input to int32. + 2. Subtracting the zero point. + 3. Casting to float32. + 4. Multiplying by the scale factor. + + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeRoundPass} + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in list(graph_module.graph.nodes): + if node.op != "call_function" or node.target not in ( + QUANT_PER_TENSOR_OP, + DEQUANT_PER_TENSOR_OP, + ): + continue + if node.target == DEQUANT_PER_TENSOR_OP and all( + user.target == QUANT_PER_TENSOR_OP for user in node.users + ): + continue + elif ( + node.target == QUANT_PER_TENSOR_OP + and node.all_input_nodes[0].target == DEQUANT_PER_TENSOR_OP + ): + continue + modified = True + args = node.args + input_rank = args[0].meta["val"].ndim + x, scale, zero_point, qmin, qmax, dtype = args + # Instead of dividing by scale in quantization, we multiply by 1/scale + # when quantizing. + scale = cast(float, scale) + scale = scale if node.target == DEQUANT_PER_TENSOR_OP else 1.0 / scale + with graph_module.graph.inserting_before(node): + scale_const = create_node( + graph_module.graph, + exir_ops.edge.aten.full.default, + args=((1,) * input_rank, scale), + kwargs={"dtype": torch.float32}, + ) + zp_const = create_node( + graph_module.graph, + exir_ops.edge.aten.full.default, + args=((1,) * input_rank, zero_point), + kwargs={ + "dtype": ( + torch.float32 + if node.target == QUANT_PER_TENSOR_OP + else torch.int32 + ) + }, + ) + if node.target == QUANT_PER_TENSOR_OP: + # TODO MLETORCH-1587: Decompose quantization nodes using more integer arithmetic + scaled = create_node( + graph_module.graph, + exir_ops.edge.aten.mul.Tensor, + args=(x, scale_const), + from_node=node, + ) + rounded = create_node( + graph_module.graph, + exir_ops.edge.aten.round.default, + args=(scaled,), + from_node=node, + ) + shifted = create_node( + graph_module.graph, + exir_ops.edge.aten.add.Tensor, + args=(rounded, zp_const), + from_node=node, + ) + clamped = create_node( + graph_module.graph, + exir_ops.edge.aten.clamp.default, + args=(shifted, float(qmin), float(qmax)), + from_node=node, + ) + quantized = create_node( + graph_module.graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + args=(clamped,), + kwargs={"dtype": dtype}, + from_node=node, + ) + output = quantized + else: + input_casted_to_zp_dtype = create_node( + graph_module.graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + args=(x,), + kwargs={"dtype": torch.int32}, + from_node=node, + ) + shifted = create_node( + graph_module.graph, + exir_ops.edge.aten.sub.Tensor, + args=(input_casted_to_zp_dtype, zp_const), + from_node=node, + ) + casted_to_float = create_node( + graph_module.graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + args=(shifted,), + kwargs={"dtype": torch.float32}, + from_node=node, + ) + dequantized = create_node( + graph_module.graph, + exir_ops.edge.aten.mul.Tensor, + args=(casted_to_float, scale_const), + from_node=node, + ) + output = dequantized + node.replace_all_uses_with(output) + graph_module.graph.erase_node(node) + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified=modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_remainder_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_remainder_pass.py new file mode 100644 index 0000000..6c11a7b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_remainder_pass.py @@ -0,0 +1,70 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_div_tensor_mode import ( + DecomposeDivTensorModePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass +from torch._ops import OpOverload + +Op = OpOverload | EdgeOpOverload + +_decomposition_ops: Dict[Op, tuple[Op, Op, Op]] = { + exir_ops.edge.aten.remainder.Scalar: ( + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.sub.Tensor, + ), + torch.ops.aten.remainder.Tensor: ( + torch.ops.aten.div.Tensor_mode, + torch.ops.aten.mul.Tensor, + torch.ops.aten.sub.Tensor, + ), + torch.ops.aten.remainder.Scalar: ( + torch.ops.aten.div.Tensor_mode, + torch.ops.aten.mul.Scalar, + torch.ops.aten.sub.Tensor, + ), + exir_ops.edge.aten.remainder.Tensor: ( + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sub.Tensor, + ), +} + + +class DecomposeRemainderPass(ArmPass): + """ + Decompose the remainder operation into primitive arithmetic: + remainder(x, y) -> x - floor_div(x, y) * y + where floor_div(x, y) == div(x, y, rounding_mode="floor"). + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivTensorModePass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + supported_ops = ( + exir_ops.edge.aten.remainder.Scalar, + exir_ops.edge.aten.remainder.Tensor, + torch.ops.aten.remainder.Scalar, + torch.ops.aten.remainder.Tensor, + ) + if op not in supported_ops: + return super().call_operator(op, args, kwargs, meta, updated) + + div_op, mul_op, sub_op = _decomposition_ops[op] + x, y = args[0], args[1] + + floor_div = super().call_operator( + div_op, (x, y), {"rounding_mode": "floor"}, meta, updated=True + ) + product = super().call_operator(mul_op, (floor_div, y), {}, meta, updated=True) + return super().call_operator(sub_op, (x, product), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_round_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_round_pass.py new file mode 100644 index 0000000..c672e1f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_round_pass.py @@ -0,0 +1,96 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass +from torch._ops import OpOverload + + +Op = OpOverload | EdgeOpOverload + + +def _get_round_decomposition_ops(op) -> tuple[Op, Op, Op, Op, Op, Op, Op]: + """ + Returns the (full_op, ge_op, add_op, sub_op, floor_op, ceil_op, where_op) for the + given round operation. The ops depend on whether the round op is an aten or edge op. + """ + if op == exir_ops.edge.aten.round.default: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.where.self, + ) + elif op == torch.ops.aten.round.default: + return ( + torch.ops.aten.full.default, + torch.ops.aten.ge.Tensor, + torch.ops.aten.add.Scalar, + torch.ops.aten.sub.Scalar, + torch.ops.aten.floor.default, + torch.ops.aten.ceil.default, + torch.ops.aten.where.self, + ) + raise RuntimeError(f"Can't get round decomposition ops for op {op}") + + +class DecomposeRoundPass(ArmPass): + """ + For inputs >= 0, round(x) is equivalent to floor(x + 0.5), and for inputs < 0, + round(x) is equivalent to ceil(x - 0.5). This pass decomposes the round operation into + a sequence of more primitive operations. + Example: + %zero = full((1,), 0.0, dtype=torch.float32) + %is_non_negative = ge(x, %zero) + %plus_half = add(x, 0.5) + %minus_half = sub(x, 0.5) + %floor = floor(%plus_half) + %ceil = ceil(%minus_half) + %result = where(%is_non_negative, %floor, %ceil) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + _TARGET_OPS = { + exir_ops.edge.aten.round.default, + torch.ops.aten.round.default, + } + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op not in DecomposeRoundPass._TARGET_OPS or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta, updated) + x = args[0] + full, ge, add, sub, floor, ceil, where = _get_round_decomposition_ops(op) + zero = super().call_operator( + full, + args=((1,), 0.0), + kwargs={"dtype": torch.float32}, + meta=meta, + updated=True, + ) + is_non_negative = super().call_operator( + ge, (x, zero), kwargs, meta, updated=True + ) + plus_half = super().call_operator(add, (x, 0.5), kwargs, meta, updated=True) + minus_half = super().call_operator(sub, (x, 0.5), kwargs, meta, updated=True) + floor = super().call_operator(floor, (plus_half,), kwargs, meta, updated=True) + ceil = super().call_operator(ceil, (minus_half,), kwargs, meta, updated=True) + return super().call_operator( + where, + (is_non_negative, floor, ceil), + kwargs, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sdpa_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sdpa_pass.py new file mode 100644 index 0000000..28a3bad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sdpa_pass.py @@ -0,0 +1,36 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.transforms import decompose_sdpa +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeScaledDotProductAttentionPass( + ArmPass, decompose_sdpa.DecomposeScaledDotProductAttention +): + """Pass that expands `aten.scaled_dot_product_attention` into primitive ops.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call( + self, graph_module: torch.fx.GraphModule, allow_non_fake_inputs: bool = True + ) -> PassResult: + graph = graph_module.graph + for node in list(graph.nodes): + if node.target != torch.ops.aten.scaled_dot_product_attention.default: + continue + if not self.allowed_to_transform(node.meta): + continue + + # Decompose with the superclass helper to reuse the shared logic. + super()._decompose_sdpa_node(graph_module, node, allow_non_fake_inputs) + + graph.eliminate_dead_code() + graph_module.recompile() + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select.py new file mode 100644 index 0000000..23b100c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.convert_squeezes_to_view import ( + ConvertSqueezesToViewPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class DecomposeSelectPass(ArmPass): + """ + This pass decomposes select into slice + squeeze to ensure that Aten and TOSA outputs has the same rank (input rank -1) + """ + + _passes_required_after: Set[Type[ExportPass]] = {ConvertSqueezesToViewPass} + + def call(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + + if node.op != "call_function": + continue + + if node.target in ( + exir_ops.edge.aten.select.int, + exir_ops.edge.aten.select_copy.int, + ): + slice_op = exir_ops.edge.aten.slice_copy.Tensor + squeeze_op = exir_ops.edge.aten.squeeze_copy.dims + else: + continue + + input_node, dim, index = node.args + + input_tensor = get_first_fake_tensor(input_node) + rank = len(input_tensor.size()) + shape = input_tensor.shape + dim = dim % rank if dim < 0 else dim + index = index % shape[dim] if index < 0 else index + + with graph_module.graph.inserting_before(node): + slice_node = create_node( + graph_module.graph, + slice_op, + (input_node, dim, index, index + 1), + from_node=node, + inherit_qparams=False, + ) + squeeze_node = create_node( + graph_module.graph, + squeeze_op, + (slice_node, [dim]), + from_node=node, + inherit_qparams=True, + ) + + node.replace_all_uses_with(squeeze_node) + graph_module.graph.erase_node(node) + + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select_scatter_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select_scatter_pass.py new file mode 100644 index 0000000..f3c7ae5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_select_scatter_pass.py @@ -0,0 +1,143 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_int64_const_ops_to_int32 import ( + ConvertInt64ConstOpsToInt32Pass, +) +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_scatter_ops = (exir_ops.edge.aten.select_scatter.default,) +aten_scatter_ops = (torch.ops.aten.select_scatter.default,) + + +def get_select_scatter_decomposition(op) -> tuple: + if op in edge_scatter_ops: + return ( + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.unsqueeze_copy.default, + exir_ops.edge.aten.view_copy.default, + ) + if op in aten_scatter_ops: + return ( + torch.ops.aten.arange.start_step, + torch.ops.aten.eq.Scalar, + torch.ops.aten.where.self, + torch.ops.aten.expand_copy.default, + torch.ops.aten.unsqueeze_copy.default, + torch.ops.aten.view_copy.default, + ) + + raise RuntimeError(f"Can't get select_scatter decomposition for op {op}") + + +class DecomposeSelectScatterPass(ArmPass): + """select_scatter is decomposed into other ops during export, however this is only + suppported for the fp profile and for the int profile we need to decompose it here. + + The decomposition is as follows: + - Build a boolean mask the size of x + eq(view(arange(0, dim_size), mask_shape), index) + - Broadcast source to x + expand(unsqueeze(source, dim), shape) + - Route the updated slice while keeping the untouched lanes + where(mask, expanded_source, x) + + This reflects the decomposition for the fp profile implemented in torch._refs + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ReplaceScalarWithTensorByProfilePass, + ConvertInt64ConstOpsToInt32Pass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_scatter_ops + aten_scatter_ops): + return super().call_operator(op, args, kwargs, meta, updated=False) + + ( + arange_op, + eq_op, + where_op, + expand_op, + unsqueeze_op, + view_op, + ) = get_select_scatter_decomposition(op) + + input_tensor = args[0] + src_tensor = args[1] + dim = int(args[2]) + index = int(args[3]) + + shape = input_tensor.data.size() + rank = len(shape) + dim = dim % rank if dim < 0 else dim + dim_size = shape[dim] + if index < 0: + index = index + dim_size + + mask_shape = [1] * rank + mask_shape[dim] = -1 + + arange_node = super().call_operator( + arange_op, + (0, dim_size, 1), + {}, + meta, + updated=False, + ) + + view_node = super().call_operator( + view_op, + (arange_node, mask_shape), + {}, + meta, + updated=False, + ) + + mask_node = super().call_operator( + eq_op, + (view_node, index), + {}, + meta, + updated=False, + ) + + unsqueeze_node = super().call_operator( + unsqueeze_op, + (src_tensor, dim), + {}, + meta, + updated=False, + ) + + expand_node = super().call_operator( + expand_op, + (unsqueeze_node, shape), + {}, + meta, + updated=False, + ) + + where_node = super().call_operator( + where_op, + (mask_node, expand_node, input_tensor), + {}, + meta, + updated=True, + ) + + return where_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sign_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sign_pass.py new file mode 100644 index 0000000..b0cf243 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sign_pass.py @@ -0,0 +1,78 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For MI case +edge_sign = exir_ops.edge.aten.sign.default +# For BI case +aten_sign = torch.ops.aten.sign.default + + +def get_ops(op): + """Returns the appropriate operator functions based on the input operator.""" + if op == edge_sign: + return ( + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.add.Scalar, + ) + elif op == aten_sign: + return ( + torch.ops.aten.gt.Scalar, + torch.ops.aten.lt.Scalar, + torch.ops.aten.where.self, + torch.ops.aten.neg.default, + torch.ops.aten.mul.Scalar, + torch.ops.aten.add.Scalar, + ) + else: + raise ValueError(f"Unsupported operator: {op}") + + +class DecomposeSignPass(ArmPass): + """Decomposes the sign operator into a sequence of operations that are supported by the Arm backend.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in (edge_sign, aten_sign) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + gt_op, lt_op, where_op, neg_op, mul_op, add_op = get_ops(op) + + x = args[0] + + gt_mask = super().call_operator(gt_op, (x, 0.0), {}, meta, updated=True) + lt_mask = super().call_operator(lt_op, (x, 0.0), {}, meta, updated=True) + + zeros = super().call_operator(mul_op, (x, 0.0), {}, meta, updated=True) + ones = super().call_operator(add_op, (zeros, 1.0), {}, meta, updated=True) + neg_ones = super().call_operator(neg_op, (ones,), {}, meta, updated=True) + + negative_tensor = super().call_operator( + where_op, (lt_mask, neg_ones, zeros), {}, meta, updated=True + ) + positive_tensor = super().call_operator( + where_op, (gt_mask, ones, zeros), {}, meta, updated=True + ) + + return super().call_operator( + where_op, + (lt_mask, negative_tensor, positive_tensor), + {}, + meta, + updated=True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_silu_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_silu_pass.py new file mode 100644 index 0000000..bf30271 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_silu_pass.py @@ -0,0 +1,41 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.pass_base import ExportPass + +aten_silu_ops = (torch.ops.aten.silu.default, torch.ops.aten.silu_.default) + + +class DecomposeSiluPass(ArmPass): + """ + This pass decomposes silu into a mul and a sigmoid node. + + Example: + y = silu(a) + Becomes: + x = sigmoid(a) + y = mul(a,x) + """ + + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + if op not in (aten_silu_ops) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + sigmoid_op = torch.ops.aten.sigmoid.default + mul_op = torch.ops.aten.mul.Tensor + + original = args[0] + sigmoid = super().call_operator(sigmoid_op, (original,), {}, meta, updated=True) + + return super().call_operator( + mul_op, (original, sigmoid), {}, meta, updated=True + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sinh_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sinh_pass.py new file mode 100644 index 0000000..731f9a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sinh_pass.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm._passes.match_arg_dtype_pass import MatchArgDtypePass +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass +from executorch.backends.arm._passes.replace_scalar_with_tensor_pass import ( + ReplaceScalarWithTensorByProfilePass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +# For MI case +edge_sinh = exir_ops.edge.aten.sinh.default + + +class DecomposeSinhPass(ArmPass): + """ + A decomposition pass that decomposes Sinh operations into a + combination of supported TOSA-equivalent operations (MI). + + Supported input ops: + - exir_ops.edge.aten.sinh.default + + These are decomposed into exponentials, negation, subtraction, + and scalar multiplication. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + MatchArgRanksPass, + ReplaceScalarWithTensorByProfilePass, + MatchArgDtypePass, + } + + def call_operator(self, op, args, kwargs, meta): + if op is not edge_sinh: + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + x = args + + sub_op, exp_op, neg_op, mul_op = ( + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.mul.Scalar, + ) + + # Exponential 1 + exp1 = super().call_operator(exp_op, x, {}, meta, updated=True) + + # Exponential 2 + neg_x = super().call_operator(neg_op, x, {}, meta, updated=True) + exp2 = super().call_operator(exp_op, (neg_x,), {}, meta, updated=True) + + # Subtraction + sub = super().call_operator(sub_op, (exp1, exp2), {}, meta, updated=True) + + # Multiplication + out = super().call_operator(mul_op, (sub, 0.5), {}, meta, updated=True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_pass.py new file mode 100644 index 0000000..88408ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_pass.py @@ -0,0 +1,93 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For BI case +torch_softmax = ( + torch.ops.aten.softmax.int, + torch.ops.aten._safe_softmax.default, + torch.ops.aten.log_softmax.int, +) +# For MI case +edge_softmax = ( + exir_ops.edge.aten._softmax.default, + exir_ops.edge.aten._log_softmax.default, +) +log_softmax = (torch.ops.aten.log_softmax.int, exir_ops.edge.aten._log_softmax.default) + + +def _get_logsoftmax_ops(op) -> tuple: + """ + Returns the (log_op, sub_op, amax_op, expo_op, sum_op, reciprocal_op), where the ops depends on if + the softmax op is an aten or edge op. + """ + if op in edge_softmax: + return ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in torch_softmax: + return ( + torch.ops.aten.log.default, + torch.ops.aten.sub.Tensor, + torch.ops.aten.amax.default, + torch.ops.aten.exp.default, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.reciprocal.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get logsoftmax decomposition ops for op {op}") + + +class DecomposeSoftmaxPass(ArmPass): + """ + This pass decomposes log_softmax or softmax into more primitive ops. + Example: + %op1 = amax(x) + %op2 = sub(x, %op1) + %op3 = exp(%op2) + %op4 = sum(%op3, dim) + %op5 = reciprocal(%op4) + %op6 = mul(%op3, %op5) + (in logsoftmax case: %op7 = log(%op6)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSumPass, + InsertTableOpsPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in torch_softmax + edge_softmax or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + log_op, sub_op, max_op, exp_op, sum_op, reciprocal_op, mul_op = ( + _get_logsoftmax_ops(op) + ) + _input = args[0] + dim = [args[1]] + op1 = super().call_operator(max_op, (_input, dim, True), {}, meta, updated=True) + op2 = super().call_operator(sub_op, (_input, op1), {}, meta, updated=True) + op3 = super().call_operator(exp_op, (op2,), {}, meta, updated=True) + op4 = super().call_operator(sum_op, (op3, dim, True), {}, meta, updated=True) + op5 = super().call_operator(reciprocal_op, (op4,), {}, meta, updated=True) + op6 = super().call_operator(mul_op, (op3, op5), {}, meta, updated=True) + if op in log_softmax: + op6 = super().call_operator(log_op, (op6,), {}, meta, updated=True) + return op6 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_unstable_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_unstable_pass.py new file mode 100644 index 0000000..7759c7f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_softmax_unstable_pass.py @@ -0,0 +1,86 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +# For BI case +torch_softmax = (torch.ops.aten.softmax.int, torch.ops.aten.log_softmax.int) + +# For MI case +edge_softmax = ( + exir_ops.edge.aten._softmax.default, + exir_ops.edge.aten._log_softmax.default, +) + +log_softmax = (torch.ops.aten.log_softmax.int, exir_ops.edge.aten._log_softmax.default) + + +def get_logsoftmax_ops(op) -> tuple: + """ + Returns the the (log_op, expo_op, sum_op, reciprocal_op), where the ops depends on if + the logsoftmax op is in exir_ops torch.ops.aten. + """ + if op in edge_softmax: + return ( + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.mul.Tensor, + ) + if op in torch_softmax: + return ( + torch.ops.aten.log.default, + torch.ops.aten.exp.default, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.reciprocal.default, + torch.ops.aten.mul.Tensor, + ) + raise RuntimeError(f"Can't get softmax decomposition ops for op {op}") + + +class DecomposeSoftmaxUnstablePass(ArmPass): + """ + This pass decomposes log softmax or softmax into more primitive ops. + + Example: + %op1 = exp(x) + %op2 = sum(%op1, dim) + %op3 = reciprocal(%op2) + %op4 = mul(%op1, %op3) + (in logsoftmax case: %op5 = log(%op4)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + DecomposeSumPass, + InsertTableOpsPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in (torch_softmax + edge_softmax) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + log_op, exp_op, sum_op, reciprocal_op, mul_op = get_logsoftmax_ops(op) + + _input = args[0] + dim = [args[1]] + + op1 = super().call_operator(exp_op, (_input,), {}, meta, True) + op2 = super().call_operator(sum_op, (op1, dim, True), {}, meta, True) + op3 = super().call_operator(reciprocal_op, (op2,), {}, meta, True) + op4 = super().call_operator(mul_op, (op1, op3), {}, meta, True) + if op in log_softmax: + op4 = super().call_operator(log_op, (op4,), {}, meta, True) + return op4 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sqrt_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sqrt_pass.py new file mode 100644 index 0000000..6bde3f5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sqrt_pass.py @@ -0,0 +1,53 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Tuple, Type, Union + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +edge_sqrt_ops = (exir_ops.edge.aten.sqrt.default,) +aten_sqrt_ops = ( + torch.ops.aten.sqrt.default, + torch.ops.aten.sqrt_.default, +) + + +def get_sqrt_decomposition(op) -> Union[Tuple, torch._ops.OpOverload]: + # TODO : "MLETORCH-863 : Replace current sqrt -> pow.Tensor_Scalar workaround with pow.Tensor_Tensor" + if op in edge_sqrt_ops: + return exir_ops.edge.aten.pow.Tensor_Scalar + if op in aten_sqrt_ops: + return torch.ops.aten.pow.Tensor_Scalar + raise RuntimeError(f"Can't get sqrt decomposition for op {op}") + + +class DecomposeSqrtPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {InsertTableOpsPass} + + def call_operator(self, op, args, kwargs, meta): + """ + Decomposes `sqrt(x)` into `pow(x, 0.5)` for backend support. + """ + + if op not in (edge_sqrt_ops + aten_sqrt_ops) or not self.allowed_to_transform( + meta + ): + return super().call_operator(op, args, kwargs, meta) + + is_quantized = ( + len(meta.data.get("input_qparams", {})) > 0 + and len(meta.data.get("output_qparams", {})) > 0 + ) + if is_quantized: + # If quantized, node should be replace by table op + return super().call_operator(op, args, kwargs, meta) + + pow_op = get_sqrt_decomposition(op) + + return super().call_operator(pow_op, (args[0], 0.5), {}, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sum_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sum_pass.py new file mode 100644 index 0000000..0e63ef3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_sum_pass.py @@ -0,0 +1,93 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def _get_sum_decomp(op): + match op: + case exir_ops.edge.aten.sum.dim_IntList: + return ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.sum.dim_IntList, + ) + case torch.ops.aten.sum.dim_IntList: + return (torch.ops.aten.reshape.default, torch.ops.aten.sum.dim_IntList) + case _: + raise RuntimeError("Unvalid op in DecomposeSumPass") + + +class DecomposeSumPass(ArmPass): + """ + In Pytorch, the default behaviour of for example Tensor.sum is to squeeze the + dimension that is summed (keep_dim = False). However, in TOSA, REDUCE_SUM always + preserves the rank of the input (keep_dim = True). To get a 1-1 mapping in the sum + lowering, normalize the keep_dim = False case to keep_dim = True and lower the rank + with a view op. + + Since TOSA can only reduce one dimension at a time, multiple dims are additionally + unrolled into multiple ops. + + Original: + sum((dim_1, dim_2), keep_dim = False) -> squeezed_shape + After pass: + sum(dim_1, keep_dim = True) -> unsqueezed_shape + sum(dim_2, keep_dim = True) -> unsqueezed_shape + view(shape = squeezed_shape) -> squeezed_shape + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in [ + exir_ops.edge.aten.sum.dim_IntList, + torch.ops.aten.sum.dim_IntList, + ]: + return super().call_operator(op, args, kwargs, meta) + + match len(args): + case 3: + ( + input_node, + dims, + keepdims, + ) = args + case 2: + ( + input_node, + dims, + ) = args + keepdims = False + case _: + raise ValueError(f"Invalid number of arguments ({len(args)}) provided.") + + # If dims evaluates to False (None or []), sum over all dimensions + if not dims: + shape = input_node.data.size() + dims = list(range(len(shape))) + + view_op, sum_op = _get_sum_decomp(op) + + for dim in dims: + input_node = super().call_operator( + sum_op, + (input_node, dim, True), + kwargs, + meta, + updated=True, + ) + + if not keepdims: + shape = list(meta["val"].size()) + input_node = super().call_operator( + view_op, (input_node, shape), {}, meta, updated=True + ) + + return input_node diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tan_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tan_pass.py new file mode 100644 index 0000000..3a196b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tan_pass.py @@ -0,0 +1,51 @@ +# Copyright 2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass, DecomposeDivPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +edge_tan_op = exir_ops.edge.aten.tan.default + + +class DecomposeTanPass(ArmPass): + """ + Decomposes tan to sin/cos + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeDivPass} + + def call_operator(self, op, args, kwargs, meta, updated=False): + if op != edge_tan_op: + return super().call_operator(op, args, kwargs, meta, updated) + # Skip quantized tan - it is decomposed as one single table op + if ( + len(meta.data.get("input_qparams", [])) > 0 + and len(meta.data.get("output_qparams", [])) > 0 + ): + return super().call_operator(op, args, kwargs, meta, updated) + if ( + len(meta.data.get("input_qparams", [])) > 0 + or len(meta.data.get("output_qparams", [])) > 0 + ): + raise RuntimeError( + "Mixed quantized and non-quantized inputs/outputs not supported." + ) + + x = args[0] + + sin_op = exir_ops.edge.aten.sin.default + cos_op = exir_ops.edge.aten.cos.default + div_op = exir_ops.edge.aten.div.Tensor + + sin = super().call_operator(sin_op, (x,), {}, meta, True) + cos = super().call_operator(cos_op, (x,), {}, meta, True) + + out = super().call_operator(div_op, (sin, cos), {}, meta, True) + + return out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py new file mode 100644 index 0000000..b467f67 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_tosa_unsupported_clamp_pass.py @@ -0,0 +1,97 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class DecomposeTOSAUnsupportedClampPass(ArmPass): + """Rewrite TOSA unsupported clamp into min/max chain since TOSA lacks int32 clamp support + and only supports scalar min/max values.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + _supported_ops = { + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.clamp.Tensor, + torch.ops.aten.clamp.default, + torch.ops.aten.clamp.Tensor, + } + + def _ensure_tensor( + self, + value, + ref_tensor, + dtype, + rank, + meta, + ): + if value is None: + return None + return super().call_operator( + exir_ops.edge.aten.full.default, + ((1,) * rank, value), + {"dtype": dtype}, + meta, + updated=True, + ) + + def call_operator(self, op, args, kwargs, meta): + val = meta["val"] + + is_scalar_clamp = op in { + exir_ops.edge.aten.clamp.default, + torch.ops.aten.clamp.default, + } + is_tensor_clamp = op in { + exir_ops.edge.aten.clamp.Tensor, + torch.ops.aten.clamp.Tensor, + } + + if op not in self._supported_ops: + return super().call_operator(op, args, kwargs, meta) + + # Only rewrite scalar clamp for int32 + if is_scalar_clamp and val.dtype != torch.int32: + return super().call_operator(op, args, kwargs, meta) + + input_tensor = args[0] + dtype = val.dtype + rank = len(val.shape) + min_arg = args[1] if len(args) > 1 else None + max_arg = args[2] if len(args) > 2 else None + + if is_scalar_clamp: + # Scalar min/max -> make them tensors for min/max ops + min_arg = self._ensure_tensor(min_arg, input_tensor, dtype, rank, meta) + max_arg = self._ensure_tensor(max_arg, input_tensor, dtype, rank, meta) + else: + # Tensor variant: arguments are already tensors; nothing extra to do + if not is_tensor_clamp: + raise RuntimeError( + f"DecomposeTOSAUnsupportedClampPass: unexpected op {op} in tensor clamp branch" + ) + + current = input_tensor + if min_arg is not None: + current = super().call_operator( + exir_ops.edge.aten.maximum.default, + (current, min_arg), + {}, + meta, + updated=True, + ) + if max_arg is not None: + current = super().call_operator( + exir_ops.edge.aten.minimum.default, + (current, max_arg), + {}, + meta, + updated=True, + ) + return current diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_var_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_var_pass.py new file mode 100644 index 0000000..72da356 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decompose_var_pass.py @@ -0,0 +1,109 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.backends.arm._passes.decompose_meandim_pass import DecomposeMeanDimPass +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def get_var_decomposition(op) -> tuple: + if op == exir_ops.edge.aten.var.correction: + return ( + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.full.default, + ) + if op in (torch.ops.aten.var.correction, torch.ops.aten.var.dim): + return ( + torch.ops.aten.mean.dim, + torch.ops.aten.sub.Tensor, + torch.ops.aten.mul.Tensor, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.full, + ) + raise RuntimeError(f"Can't get var decomposition for op {op}") + + +class DecomposeVarPass(ArmPass): + """ + This pass decomposes var.correction and var.dim into smaller ops (see https://pytorch.org/docs/stable/generated/torch.var.html) + + Example: + y = var_correction(x, dim, keepdim, correction) + Becomes: + mean = mean(x, dim) + diff = sub(x, mean) + squared_diff = mul(diff, diff) + sum = sum(squared_diff, dim) + y = div(sum, max(0, N-correction)) + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ComputeConstantOpsAOTPass, + DecomposeMeanDimPass, + DecomposeSumPass, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + exir_ops.edge.aten.var.correction, + torch.ops.aten.var.correction, + torch.ops.aten.var.dim, + ) or not self.allowed_to_transform(meta): + return super().call_operator(op, args, kwargs, meta) + + x = args[0] + input_shape = x.data.size() + shape = list(meta["val"].size()) + if shape == []: + shape = [1 for _ in input_shape] + + dtype = meta["val"].dtype + # Get dim from args based on argument type + dim = get_node_arg(args, key=list, default_value=list(range(len(shape)))) + + if op == torch.ops.aten.var.dim: + keepdim = False + correction = 1 + if len(args) > 2: + correction = int(get_node_arg(args, 2, True)) + if len(args) > 3: + keepdim = get_node_arg(args, 3, False) + else: + correction = get_node_arg(kwargs, "correction", 1) + keepdim = get_node_arg(kwargs, "keepdim", False) + + N = 1 + for d in dim: + N *= input_shape[d] + + mean_op, diff_op, mul_op, sum_op, full_op = get_var_decomposition(op) + mean = super().call_operator(mean_op, (x, dim, True), {}, meta, True) + diff = super().call_operator(diff_op, (x, mean), {}, meta, True) + squared_diff = super().call_operator(mul_op, (diff, diff), {}, meta, True) + sum = super().call_operator( + sum_op, (squared_diff, dim, keepdim), {}, meta, True + ) + full = super().call_operator( + full_op, + ([], 1 / max(0, N - correction)), + {"dtype": dtype, "device": x.data.device}, + meta, + True, + ) + return super().call_operator(mul_op, (sum, full), {}, meta, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py new file mode 100644 index 0000000..0b9c593 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/decorate_fp32_to_int32_casting_pass.py @@ -0,0 +1,88 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_node_arg +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +def _get_decorated_ops(op): + if op in DecorateFp32toInt32CastingPass.targets: + return ( + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.where.self, + ) + else: + raise RuntimeError(f"Can't get decorated ops for op {op}") + + +class DecorateFp32toInt32CastingPass(ArmPass): + """ + To lower pytorch fp32 -> int32 casting to TOSA, + we need to transform the value with Ceil, Floor, and Where. + Before: + output = to_dim_order_copy(x, dtype=torch.int32) + After: + %zero = full((1,), 0.0, dtype=torch.float32) + is_non_negative = x >= %zero + floor_x = floor(x) + ceil_x = ceil(x) + decorated_x = where(is_non_negative, floor_x, ceil_x) + output = to_dim_order_copy(decorated_x, dtype=torch.int32) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targets = [ + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ] + + def call_operator(self, op, args, kwargs, meta): + if op not in self.targets: + return super().call_operator(op, args, kwargs, meta) + + input = get_node_arg(args, 0) + input_dtype = input.node.meta["val"].dtype + output_dtype = meta["val"].dtype + + if not (input_dtype == torch.float32 and output_dtype == torch.int32): + return super().call_operator(op, args, kwargs, meta) + + # For some ops, qparams dtype is inconsistent with fake tensor's dtype. + # Skip decorating if the input is quantized and thus not floating point. + if ( + "output_qparams" in input.node.meta + and len(input.node.meta["output_qparams"]) > 0 + ): + return super().call_operator(op, args, kwargs, meta) + + op_full, op_ge, op_floor, op_ceil, op_where = _get_decorated_ops(op) + + zero = super().call_operator( + op_full, + args=((1,) * len(meta["val"].size()), 0.0), + kwargs={"dtype": torch.float32}, + meta=meta, + updated=True, + ) + + is_non_negative = super().call_operator( + op_ge, (input, zero), {}, meta, updated=True + ) + floor_x = super().call_operator(op_floor, (input,), {}, meta, updated=True) + ceil_x = super().call_operator(op_ceil, (input,), {}, meta, updated=True) + decorated_x = super().call_operator( + op_where, (is_non_negative, floor_x, ceil_x), {}, meta, updated=True + ) + + return super().call_operator(op, (decorated_x,), kwargs, meta, updated=True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py new file mode 100644 index 0000000..0ecb7ff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fold_qdq_with_annotated_qparams_pass.py @@ -0,0 +1,394 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import copy + +from typing import cast, Optional, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + get_param_tensor, + is_param_node, + set_node_arg, +) +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass + +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm._passes.remove_noop_pass import RemoveNoopPass +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.exir import ExportedProgram + +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +def _get_special_dtype(qspec: QuantArgs) -> TosaSpecialDtype | None: + if qspec.dtype == torch.int8: + if qspec.qmax == 7 and qspec.qmin == -7: + return TosaSpecialDtype.INT4 + return None + + +def get_input_qparams(node: Node) -> dict[int, QuantArgs]: + """ + Get the input quantization parameters from a node, set by the 'FoldAndAnnotateQParamsPass'. + Raises a ValueError if the node doesn't have any parameters set. + """ + if "input_qparams" not in node.meta.keys(): + raise ValueError( + f"No input quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + input_qparams = cast(dict[int, QuantArgs], node.meta["input_qparams"]) + if len(input_qparams) == 0: + raise ValueError( + f"No input quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + return input_qparams + + +def get_output_qparams(node: Node) -> dict[int, QuantArgs]: + """ + Get the output quantization parameters from a node, set by the 'FoldAndAnnotateQParamsPass'. + Raises a ValueError if the node doesn't have any parameters set. + """ + if "output_qparams" not in node.meta.keys(): + raise ValueError( + f"No output quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + output_qparams = cast(dict[int, QuantArgs], node.meta["output_qparams"]) + if len(output_qparams) == 0: + raise ValueError( + f"No output quantization parameter found in node {node}\n" + f"original_aten={node.meta.get('original_aten', 'None')}" + ) + return output_qparams + + +class FoldAndAnnotateQParamsPass(ArmPass): + """ + A pass that walks the graph and removes any DQ and Q nodes before and after the target + node. + The quantization parameters from the DQ/Q nodes are stored as meta values to be + accessible for later lowering and serialization passes. + The assumption is that the quantization annotation adds DQ nodes for all tensor + inputs to the target one Q node to the output. + + Example ('executorch_exir_dialects_edge__ops_' prefix removed from operators for readability): + + x_q: "i8[5]" = quantized_decomposed_quantize_per_tensor_default(x, 0.05487706884741783, -128, -128, 127, torch.int8) + + x_dq: "f32[5]" = quantized_decomposed_dequantize_per_tensor_default(x_q, 0.05487706884741783, -128, -128, 127, torch.int8) + aten_add_tensor: "f32[5]" = ops_aten_add_Tensor(x_dq, x_dq) + aten_add_tensor_q: "i8[5]" = quantized_decomposed_quantize_per_tensor_default(aten_add_tensor, 0.05487706884741783, -128, -128, 127, torch.int8) + + output_dq: "f32[5]" = quantized_decomposed_dequantize_per_tensor_default(aten_add_tensor_q, 0.05487706884741783, -128, -128, 127, torch.int8) + + Becomes: + x_q: "i8[5]" = quantized_decomposed_quantize_per_tensor_default(x, 0.05487706884741783, -128, -128, 127, torch.int8) + + aten_add_tensor: "i8[5]" = aten_add_Tensor(x_q, x_q) + + output_dq: "f32[5]" = quantized_decomposed_dequantize_per_tensor_default(aten_add_tensor_q, 0.05487706884741783, -128, -128, 127, torch.int8) + + The quantization parameters for x_dq and aten_add_tensor_q are stored in meta for the aten_add_tensor node. + + """ + + _passes_required_after: Set[Type[ExportPass]] = { + InsertTableOpsPass, + RemoveNoopPass, + } + + def __init__( + self, exported_program: Optional[ExportedProgram] = None, *args, **kwargs + ) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def fold_and_annotate_arg( + self, graph_module: GraphModule, node: Node, arg_list: list[Node], i: int + ) -> None: + input_qparams = None + nodes_to_remove = set() + for arg in arg_list: + if not isinstance(arg, Node): + return + + arg_quant_params = None + if arg.target in DQ_OPS: + args = arg.args + scales = args[1] + if ( + isinstance(args[1], Node) + and self.exported_program is not None + and is_param_node(self.exported_program, args[1]) + ): + scales = get_param_tensor(self.exported_program, args[1]) + zps = args[2] + if ( + isinstance(args[2], Node) + and self.exported_program is not None + and is_param_node(self.exported_program, args[2]) + ): + zps = get_param_tensor(self.exported_program, args[2]) + arg_quant_params = QuantArgs.from_operator( + arg.target, (args[0], scales, zps, *args[3:]) + ) + # add arg to nodes_to_remove to fold the dq-node + nodes_to_remove.add(arg) + if input_qparams is not None and input_qparams != arg_quant_params: + # Two args are quantized differently + raise RuntimeError("Input qparams do not match") + input_qparams = arg_quant_params + if input_qparams is not None: + node.meta["input_qparams"][i] = input_qparams + for n in nodes_to_remove: + if n.target not in DQ_OPS: + raise RuntimeError( + f"Expected one of {DQ_OPS} dq_op, got {n.target}" + ) + + node.replace_input_with(n, cast(Node, n.args[0])) + if len(n.users) == 0: + graph_module.graph.erase_node(n) + special_dtype = _get_special_dtype(input_qparams) + if special_dtype: + node.all_input_nodes[i].meta[ + TosaSpecialDtype.meta_key() + ] = special_dtype + + def _handle_control_flow_node(self, node: Node, graph_module: GraphModule): + """Fold outmost quant nodes inside submodule. + placeholders => qs => dqs => ... => qs => dqs => output + becomes + placeholders => dqs => ... => qs => output, + With output_qparams meta in the placeholders, and input_qparams meta in the output node. + """ + match node.target: + case torch.ops.higher_order.cond: + submodule_nodes = cast(list[Node], node.args[1:3]) + args = cast(list[Node], node.args[-1]) + case torch.ops.higher_order.while_loop: + submodule_nodes = cast(list[Node], node.args[0:2]) + args = cast(list[Node], node.args[-2]) + case _: + raise ValueError(f"Unhandled target {node.target}") + submodules = ( + graph_module.get_submodule(str(submodule_node.target)) + for submodule_node in submodule_nodes + ) + for submodule in submodules: + submodule = cast(GraphModule, submodule) + output_node = submodule.graph.output_node() + output_node.meta["input_qparams"] = {} + nodes_to_remove = [] + arg_id = 0 + for submodule_node in submodule.graph.nodes: + # Remove initial q nodes and ending dq nodes in the module. + submodule_node = cast(Node, submodule_node) + if ( + submodule_node.target in Q_OPS + and list(submodule_node.all_input_nodes)[0].op == "placeholder" + ): + input_node = cast(Node, submodule_node.args[0]) + input_node.meta["val"] = submodule_node.meta["val"] + quant_args = QuantArgs.from_operator( + submodule_node.target, submodule_node.args + ) + input_node.meta["output_qparams"] = {0: quant_args} + + submodule_node.replace_all_uses_with(input_node) + nodes_to_remove.append(submodule_node) + if submodule_node.target in DQ_OPS: + has_non_output_user = False + for user in copy.copy(submodule_node.users): + if user.op != "output": + has_non_output_user = True + else: + input_node = cast(Node, submodule_node.args[0]) + submodule_node.replace_all_uses_with(input_node) + arg_index = cast(list[Node], output_node.args[0]).index( + input_node + ) + quant_args = QuantArgs.from_operator( + submodule_node.target, submodule_node.args + ) + output_node.meta["input_qparams"][arg_index] = quant_args + + # Remove dq node if it only has the output node as its user. + if not has_non_output_user: + nodes_to_remove.append(submodule_node) + # Placeholders without users won't be retraced with correct dtype, do it manually. + # Control flow node input is matched to placeholder nodes in the submodule by index. + # This means it will break if another pass inserts a placeholder before this pass. + if submodule_node.op == "placeholder": + if len(submodule_node.users) == 0: + submodule_node.meta["val"] = args[arg_id].meta["val"] + arg_id += 1 + if arg_id > len(args): + raise RuntimeError( + "Submodule had more placeholders than calling node had inputs." + " This is probably due to a placeholder being inserted in a pass." + ) + for node_to_remove in nodes_to_remove: + submodule.graph.erase_node(node_to_remove) + return + + @staticmethod + def is_foldable(node: Node) -> bool: + if node.op != "call_function": + return False + # Don't fold chains of quant-ops into each other. + if node.target in (*Q_OPS, *DQ_OPS): + return False + + # Always fold q-dq into constant ops. + if node.target in ( + exir_ops.edge.aten.full_like.default, + *ComputeConstantOpsAOTPass.targeted_ops, + ): + return True + + # We should not fold q-dq nodes into non-quantized nodes. + if not ( + ArmAnnotationInfo.CUSTOM_META_KEY in node.meta.get("custom", {}) + and ArmAnnotationInfo( + node.meta["custom"][ArmAnnotationInfo.CUSTOM_META_KEY] + ).quantized + ): + return False + return True + + def call(self, graph_module: GraphModule) -> PassResult: # noqa: C901 + + # Loop over the graph nodes and find any node in the 'targeted_ops' list. + for n in graph_module.graph.nodes: + n = cast(Node, n) + if not FoldAndAnnotateQParamsPass.is_foldable(n): + continue + + # Make sure we haven't already set qparams meta information on the node + if "input_qparams" in n.meta: + raise RuntimeError( + f'Unexpected key "input_qparams" found in meta for node {n}. ' + "input_qparams should not have been set at this point" + ) + if "output_qparams" in n.meta: + raise RuntimeError( + f'Unexpected key "output_qparams" found in meta for node {n}. ' + "output_qparams should not have been set at this point" + ) + + # for the inputs and outputs search the graph for quantization info and + # store the information in a dict with order of the _tensor_ inputs as key, + # ignoring any other arguments to the target node. + n.meta["input_qparams"] = {} + n.meta["output_qparams"] = {} + for i, arg in enumerate(n.args): + if isinstance(arg, (list, tuple)): + self.fold_and_annotate_arg(graph_module, n, arg, i) # type: ignore + + elif isinstance(arg, Node): + self.fold_and_annotate_arg(graph_module, n, [arg], i) + + # Copy the users, since we are modifying it. + users_copy = copy.copy(n.users) + for i, user in enumerate(users_copy): + if user.target not in Q_OPS: + continue + + # quantization node found here, store the quantization parameters in meta value + n.meta["output_qparams"][i] = QuantArgs.from_operator( + user.target, user.args + ) + + user.replace_all_uses_with(n) + graph_module.graph.erase_node(user) + + # Some op(s) contain a "dtype" key in their node kwargs. Set this + # to the type of output qparams. + output_qparams = n.meta["output_qparams"] + if ( + n.target in {exir_ops.edge.aten.sum.dim_IntList} + and len(output_qparams) > 0 + ): + output_dtype = output_qparams[0].dtype + set_node_arg(n, "dtype", output_dtype) + + if n.target in ( + torch.ops.higher_order.cond, + torch.ops.higher_order.while_loop, + ): + self._handle_control_flow_node(n, graph_module) + + # retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + + graph_module.recompile() + return PassResult(graph_module, True) + + +class QuantizeClampArgumentsPass(ArmPass): + """ + This pass makes sure that the arguments to clamp.default are quantized correctly. + More specifically, this pass: + - Makes sure the min and max values to clamp.default are quantized, if it's a quantized operator. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + # Loop over the graph nodes and find full.default nodes. + for n in graph_module.graph.nodes: + n = cast(Node, n) + if n.target not in { + exir_ops.edge.aten.clamp.default, + }: + continue + + try: + output_qparams = get_output_qparams(n) + except ValueError: + continue + if len(output_qparams) == 0: + continue + + # Qparams are stored per user index; use the first entry. + qargs = next(iter(output_qparams.values())) + + if n.target == exir_ops.edge.aten.clamp.default: + # Quantize the min and max arguments of clamp, if they are not None + min_val = n.args[1] + max_val = None if len(n.args) <= 2 else n.args[2] + + if min_val is not None: + quantized_min_val = qargs.quantize_value(min_val).item() + n.update_arg(1, quantized_min_val) + + if max_val is not None: + quantized_max_val = qargs.quantize_value(max_val).item() + n.update_arg(2, quantized_max_val) + + modified = True + + if modified: + # Retrace to refresh fake tensor metadata after updating clamp min/max. + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_batch_norm2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_batch_norm2d_pass.py new file mode 100644 index 0000000..d1b2aa4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_batch_norm2d_pass.py @@ -0,0 +1,241 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm.common.debug import get_node_debug_info +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + delete_constant_placeholder, +) +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch._export.utils import get_buffer, get_param +from torch.export.graph_signature import InputKind +from torch.fx import Node +from torch.nn.utils.fusion import fuse_conv_bn_weights + + +class FuseBatchNorm2dPass(ArmPass): + """Fuses the pattern convolution -> batchnorm by updating + the weights and bias of the convolution and removing the batchnorm. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def get_bias_name(self, weight_node: Node, bias_node: Node | None) -> str: + if bias_node: + return bias_node.name + "_fused_bn" + elif "weight" in weight_node.name: + return weight_node.name.replace("weight", "bias") + "_fused_bn" + else: + return weight_node.name + "_bias_fused_bn" + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901 + modified = False + constant_placeholders_to_delete = set() + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if ( + node.target + != exir_ops.edge.aten._native_batch_norm_legit_no_training.default + ): + continue + + # Get data from batchnorm + input_node = node.all_input_nodes[0] + is_single_user = len(input_node.users) == 1 + bn_weight_node, bn_bias_node, bn_mean_node, bn_var_node = node.args[1:5] + if bn_mean_node is None: + raise RuntimeError( + "BatchNorm mean buffer missing for node: " + f"{get_node_debug_info(node, graph_module)}" + ) + if bn_var_node is None: + raise RuntimeError( + "BatchNorm variance buffer missing for node: " + f"{get_node_debug_info(node, graph_module)}" + ) + + epsilon = node.args[-1] + + bn_weight_tensor = ( + get_param(self.exported_program, bn_weight_node) + if bn_weight_node is not None + else None + ) + bn_bias_tensor = ( + get_param(self.exported_program, bn_bias_node) + if bn_bias_node is not None + else None + ) + + bn_mean_tensor = torch.Tensor( + get_buffer(self.exported_program, bn_mean_node) + ) + bn_var_tensor = torch.Tensor(get_buffer(self.exported_program, bn_var_node)) + + if ( + input_node.target != exir_ops.edge.aten.convolution.default + or not is_single_user + ): + # Insert a transparent conv2d before bn to fuse with if none is present. + shape = get_first_fake_tensor(node) + if len(shape.size()) == 3: + input_weight_tensor = torch.ones((1, 1, 1)) + stride = [1] + padding = [0] + dilation = [1] + output_padding = [0] + else: + input_weight_tensor = torch.ones((1, 1, 1, 1)) + stride = [1, 1] + padding = [0, 0] + dilation = [1, 1] + output_padding = [0, 0] + + with graph_module.graph.inserting_before(bn_weight_node): + input_weight_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + name=node.name + "_conv_weight", + data=input_weight_tensor, + ) + + input_bias_tensor = input_bias_node = None + + with graph_module.graph.inserting_before(node): + channels = bn_mean_tensor.size(0) + conv_args = ( + input_node, + input_weight_node, + input_bias_node, + stride, + padding, + dilation, + False, # Transposed + output_padding, + channels, + ) + new_input_node = create_node( + graph_module.graph, + exir_ops.edge.aten.convolution.default, + conv_args, + ) + node.replace_input_with(input_node, new_input_node) + input_node = new_input_node + else: + input_weight_node, input_bias_node = input_node.args[1:3] + if not ( + isinstance(input_weight_node, Node) + and input_weight_node.op == "placeholder" + ): + raise RuntimeError( + "Parameter weight of convolution must be a placeholder" + ) + if not ( + (input_bias_node is None) + or ( + isinstance(input_weight_node, Node) + and input_weight_node.op == "placeholder" + ) + ): + raise RuntimeError( + "Parameter bias of convolution must be a placeholder or None" + ) + + input_weight_tensor = torch.Tensor( + get_param(self.exported_program, input_weight_node) + ) + + input_bias_tensor = ( + get_param(self.exported_program, input_bias_node) + if input_bias_node is not None + else None + ) + + # Fuse bn weights/bias with input weights/bias + fused_weight, fused_bias = fuse_conv_bn_weights( + input_weight_tensor, + input_bias_tensor, + bn_mean_tensor, + bn_var_tensor, + epsilon, + bn_weight_tensor, + bn_bias_tensor, + ) + + # Create fused weights and bias to conv and replace conv args + with graph_module.graph.inserting_before(input_weight_node): + fused_conv_weight_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + name=input_weight_node.name + "_fused_bn", + data=fused_weight, + ) + + if fused_bias is not None: + fused_input_bias_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + name=self.get_bias_name(input_weight_node, input_bias_node), + data=fused_bias, + ) + else: + fused_input_bias_node = None + + input_node.args = ( + input_node.args[0], + fused_conv_weight_node, + fused_input_bias_node, + *input_node.args[3:], + ) + + # Erasing batch-norm nodes is handled by dead-code elimination. After that we may remove their constant placeholder inputs + for user in node.users: + user.replace_all_uses_with(input_node) + + constant_placeholders_to_delete.update( + [ + bn_weight_node, + bn_bias_node, + bn_mean_node, + bn_var_node, + input_weight_node, + input_bias_node, + ] + ) + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + for constant_placeholder in constant_placeholders_to_delete: + if (constant_placeholder is not None) and ( + len(constant_placeholder.users) == 0 + ): + delete_constant_placeholder( + self.exported_program, constant_placeholder + ) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module=graph_module, modified=modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_constant_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_constant_ops_pass.py new file mode 100644 index 0000000..c29603d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_constant_ops_pass.py @@ -0,0 +1,272 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Set, Type + +import torch._export.utils +import torch.fx +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + get_constant_placeholder_kind, + get_first_fake_tensor, + get_param_tensor, + is_persistent_buffer, +) +from executorch.backends.arm._passes.fuse_equal_placeholders_pass import ( + FuseEqualPlaceholdersPass, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + delete_constant_placeholder, +) +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind + +logger = logging.getLogger(__name__) + + +class FuseConstantArgsPass(ArmPass): + """ + Fuses ops with only placeholder parameters into one placeholder parameter node with the op + pre-calulcated on its data. + + Original: + state_dict = {x_tensor_name : data} + def f(): + return x.view(...) + + After pass: + state_dict = {x_tensor_name_fused_const : data.view(...)} + def f(): + return x + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def _propagate_special_dtype(self, from_nodes, to_node, data): + """Propagate special dtype meta if it exists.""" + special_dtypes = set() + for input_node in from_nodes: + special_type = input_node.meta.get(TosaSpecialDtype.meta_key(), None) + if special_type: + special_dtypes.add(special_type) + if len(special_dtypes) > 1: + logger.warning( + "Propagating mixed special dtypes is not implemented, skipping." + ) + elif len(special_dtypes) == 1: + special_dtype = list(special_dtypes)[0] + # Make sure data is still within special dtype range. + if data.abs().max() <= special_dtype.max(): + to_node.meta[TosaSpecialDtype.meta_key()] = special_dtype + + def _fuse_nodes(self, node) -> bool: + """ + Takes a node with only parameter inputs and replaces it with one constant tensor node with + the operations already carried out on the data. + """ + + input_nodes = list(node.all_input_nodes) + qparams = node.meta.get("input_qparams", None) + + def resolve_arg(arg): + if isinstance(arg, torch.fx.Node) and arg in input_nodes: + idx = input_nodes.index(arg) + t = get_param_tensor(self.exported_program, arg) + # Check if qparams exist for this arg + if qparams and idx in qparams.keys(): + t = qparams[idx].dequantize_value(t) + return t + if isinstance(arg, tuple): + return tuple(resolve_arg(x) for x in arg) + if isinstance(arg, list): + return [resolve_arg(x) for x in arg] + return arg + + new_args = tuple(resolve_arg(a) for a in node.args) + new_kwargs = {k: resolve_arg(v) for k, v in node.kwargs.items()} + + data = node.target(*new_args, **new_kwargs) + + # Only fuse if the tensor does not get bigger. + if data.numel() > get_first_fake_tensor(node).numel(): + return False + + if "output_qparams" in node.meta and len(node.meta["output_qparams"]) > 0: + q_params = node.meta["output_qparams"][0] + data = q_params.quantize_value(data) + + insert_pos = list(node.all_input_nodes)[0] + + # Make new node the same kind as the first constant input + input_kind = get_constant_placeholder_kind(self.exported_program, insert_pos) + persistent_buffer = is_persistent_buffer(self.exported_program, insert_pos) + + # Create new node + with node.graph.inserting_before(insert_pos): + const_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=node.graph, + kind=input_kind, + name=node.name + "_fused_const", + data=data, + persistent_buffer=persistent_buffer, + ) + + self._propagate_special_dtype(input_nodes, const_node, data) + + node.replace_all_uses_with(const_node) + + return True + + def call(self, graph_module): + modified = False + input_nodes_to_maybe_delete = set() + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target in [ + exir_ops.backend.tosa.MATMUL.default, + exir_ops.backend.tosa.RESCALE.default, + exir_ops.backend.tosa.RESIZE.default, + exir_ops.backend.tosa.TABLE.default, + exir_ops.backend.tosa.TRANSPOSE.default, + ]: + continue + + input_nodes = node.all_input_nodes + if len(input_nodes) == 0: + continue + input_nodes_constant = ( + torch._export.utils.is_param(self.exported_program, input_node) + or torch._export.utils.is_lifted_tensor_constant( + self.exported_program, input_node + ) + or torch._export.utils.is_buffer(self.exported_program, input_node) + for input_node in input_nodes + ) + if not all(input_nodes_constant): + continue + + try: + did_fuse = self._fuse_nodes(node) + if did_fuse: + logger.debug( + f"Fused constant op: {node.name} with placeholder inputs:" + f"{[input_node.name for input_node in input_nodes]}" + ) + modified |= did_fuse + graph_module.recompile() # Recompile needed to catch chains of constant ops + input_nodes_to_maybe_delete.update(input_nodes) + except Exception as e: + logger.warning( + f"\nFailed to fuse constant op {node.name} due to exception:\n{str(e)}" + ) + + if modified: + graph_module.graph.eliminate_dead_code() + for input_node in input_nodes_to_maybe_delete: + if len(input_node.users) == 0: + delete_constant_placeholder(self.exported_program, input_node) + + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) + + +class ComputeConstantOpsAOTPass(ArmPass): + """ + Evaluates call_functions that produce constant tensor outputs and replaces them with placeholders. + + Original: + state_dict = {} + def f(): + return torch.arange(0,10) + After pass: + state_dict = {node_name_pre_computed : torch.arange(0,10)} + def f(node_name_pre_computed): + return node_name_pre_computed + """ + + _passes_required_after: Set[Type[ExportPass]] = { + FuseEqualPlaceholdersPass, + FuseConstantArgsPass, + } + + targeted_ops = [ + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.eye.default, + exir_ops.edge.aten.linspace.default, + torch.ops.aten.scalar_tensor.default, + ] + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def compute_node_aot(self, node: torch.fx.Node) -> bool: + """ + Takes a node with only parameter inputs and replaces it with one constant tensor node with + the operations already carried out on the data. + """ + + # Create data from args + output_qparams = node.meta.get("output_qparams", None) + if output_qparams: + # If we have output_qparams, compute data in fp and quantize + data = node.target(*node.args) # type: ignore + output_qparams = output_qparams[0] + data = output_qparams.quantize_value(data) + else: + # If we don't have output_qparams, compute data using kwarg-specified dtype + data = node.target(*node.args, **node.kwargs) # type: ignore + + # Create new node + insert_pos = list(node.graph.nodes)[0] + input_kind = InputKind.BUFFER + persistent_buffer = True + + with node.graph.inserting_before(insert_pos): + const_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=node.graph, + kind=input_kind, + name=node.name + "_pre_computed", + data=data, + persistent_buffer=persistent_buffer, + ) + node.replace_all_uses_with(const_node) + + return True + + def call(self, graph_module): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target not in self.targeted_ops: + continue + try: + modified |= self.compute_node_aot(node) + except Exception as e: + logger.warning( + f"\nFailed to pre-compute op {node.name} due to exception:\n{str(e)}" + ) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_duplicate_users_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_duplicate_users_pass.py new file mode 100644 index 0000000..217d933 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_duplicate_users_pass.py @@ -0,0 +1,165 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from collections import deque +from typing import Any, Deque, Dict, Hashable, List, Set, Tuple, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, PassResult +from torch._ops import OpOverload +from torch.fx import GraphModule, Node +from torch.fx.node import Argument, map_arg + + +class FuseDuplicateUsersPass(ArmPass): + """Fuse identical users of a producer node into a single operation. + + Example: + + y = producer(x) + z0 = torch.add(y, bias) + z1 = torch.add(y, bias) + + becomes a single ``torch.add`` that feeds both consumers. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: GraphModule) -> PassResult: + graph = graph_module.graph + modified = False + + producers: Deque[Node] = deque(node for node in graph.nodes) + + while producers: + producer = producers.popleft() + + if producer.graph is None: + # Node was deleted by a previous rewrite while still queued. + continue + + # Only meaningful if a value is consumed by multiple users. + user_nodes = list(producer.users) + if len(user_nodes) < 2: + continue + + candidate_groups = self._get_candidate_groups(user_nodes) + + signature_to_user: Dict[Tuple[Hashable, ...], Node] = {} + for group in candidate_groups: + for user in group: + signature = self._build_user_signature(user) + if signature is None: + continue + + representative = signature_to_user.get(signature) + if representative is None: + # Check if we already encountered identical node that we can fuse with. + signature_to_user[signature] = user + continue + + if user is representative: + # The queue can enqueue the surviving node again after rewrites. + continue + + user.replace_all_uses_with(representative) + graph.erase_node(user) + modified = True + + # Revisit the current producer and the surviving user so that + # newly formed duplicate chains can be fused in later + # iterations. + producers.append(producer) + producers.append(representative) + + if modified: + graph_module.recompile() + graph_module.graph.lint() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) + + def _get_candidate_groups(self, user_nodes): + users_by_target: Dict[Tuple[str, Hashable], List[Node]] = {} + for user in user_nodes: + if user.graph is None: + # User might already have been removed by a prior rewrite. + continue + + if user.op != "call_function": + continue + + target_key = self._get_target_key(user.target) + target_signature = (user.op, target_key) + users_by_target.setdefault(target_signature, []).append(user) + + candidate_groups = [ + group for group in users_by_target.values() if len(group) > 1 + ] + + return candidate_groups + + def _build_user_signature(self, node: Node) -> Tuple[Hashable, ...] | None: + try: + normalized_args = self._to_hashable( + map_arg(node.args, self._map_leaf_to_key) + ) + normalized_kwargs = self._to_hashable( + {k: map_arg(v, self._map_leaf_to_key) for k, v in node.kwargs.items()} + ) + except TypeError: + return None + + target_key = self._get_target_key(node.target) + + return (node.op, target_key, normalized_args, normalized_kwargs) + + def _map_leaf_to_key(self, node: Node) -> Argument: + return node.name + + def _to_hashable(self, value: Any) -> Hashable: + """Convert arbitrarily nested structures into hashable tuples.""" + + if isinstance(value, (list, tuple)): + return tuple(self._to_hashable(v) for v in value) + if isinstance(value, dict): + normalized_items = [(k, self._to_hashable(v)) for k, v in value.items()] + return tuple(sorted(normalized_items, key=lambda item: repr(item[0]))) + if isinstance(value, set): + hashable_values: List[Hashable] = [self._to_hashable(v) for v in value] + return tuple(sorted(hashable_values, key=repr)) + if isinstance(value, slice): + return ( + "slice", + self._to_hashable(value.start), + self._to_hashable(value.stop), + self._to_hashable(value.step), + ) + if isinstance(value, range): + return ("range", value.start, value.stop, value.step) + if isinstance(value, torch.Size): + return ("size", tuple(value)) + if isinstance(value, torch.dtype): + return ("dtype", str(value)) + if isinstance(value, torch.device): + return ("device", str(value)) + if isinstance(value, torch.memory_format): + return ("memory_format", str(value)) + if isinstance(value, torch.Tensor): + return ( + "tensor", + str(value.dtype), + tuple(value.size()), + value.device.type, + value.requires_grad, + ) + return value + + def _get_target_key(self, target: Any) -> Hashable: + if isinstance(target, (EdgeOpOverload, OpOverload)): + return str(target) + return target diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_equal_placeholders_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_equal_placeholders_pass.py new file mode 100644 index 0000000..37cac8a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_equal_placeholders_pass.py @@ -0,0 +1,104 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import hashlib +from collections import defaultdict +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + get_constant_placeholder_kind, + get_param_tensor, + is_param_node, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + delete_constant_placeholder, +) +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass, PassResult + + +class FuseEqualPlaceholdersPass(ArmPass): + """ + This pass optimizes memory usage by finding constant placeholders + pointing to identical tensors and fusing them to one single placeholder + with multiple users, using a cache for faster comparison. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + modified = False + + # Build a cache of params: mapping hash_key -> list of (node, tensor) + hash_buckets = defaultdict(list) + for node in graph_module.graph.nodes: + if not is_param_node(self.exported_program, node): + continue + tensor = get_param_tensor(self.exported_program, node) + if tensor is None: + continue + # Create a lightweight fingerprint: dtype + shape + SHA1 of raw bytes + # Ensure tensor is on CPU and contiguous + + # ensure we don't merge any special case int48_t tensors with int32_t tensors + # since int48_t tensors needs to be instantiated separately. + is_special_dtype = node.meta.get(TosaSpecialDtype.meta_key(), None) + t_cpu = tensor.detach().cpu().contiguous() + data_bytes = t_cpu.numpy().tobytes() + key = ( + is_special_dtype, + str(t_cpu.dtype), + tuple(t_cpu.shape), + hashlib.sha1(data_bytes, usedforsecurity=False).hexdigest(), + ) + hash_buckets[key].append((node, t_cpu)) + + # For each bucket with more than one entry, fuse: + for nodes_tensors in hash_buckets.values(): + if len(nodes_tensors) < 2: + continue + + # Create a new placeholder from first in list of equal placeholders. + rep_node, rep_tensor = nodes_tensors[0] + common_name = rep_node.name + "_common" + common_kind = get_constant_placeholder_kind(self.exported_program, rep_node) + common_persistent = True + with graph_module.graph.inserting_before(rep_node): + common_node = create_constant_placeholder( + self.exported_program, + graph_module.graph, + common_name, + common_kind, + rep_tensor, + common_persistent, + ) + + # TBD: Find a principled way to merge node.meta across all fused node + # For now, i specifically transfer over the TosaSpecialDtype.meta_key() of the rep_node + if TosaSpecialDtype.meta_key() in rep_node.meta: + common_node.meta[TosaSpecialDtype.meta_key()] = rep_node.meta[ + TosaSpecialDtype.meta_key() + ] + + # Replace uses and delete duplicates + for node, _ in nodes_tensors: + node.replace_all_uses_with(common_node) + delete_constant_placeholder(self.exported_program, node) + modified = True + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module=graph_module, modified=modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_quantized_activation_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_quantized_activation_pass.py new file mode 100644 index 0000000..09e989c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_quantized_activation_pass.py @@ -0,0 +1,80 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.convert_to_clamp_pass import ConvertToClampPass +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + FoldAndAnnotateQParamsPass, +) +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm.constants import Q_OPS +from executorch.backends.transforms.remove_getitem_op import RemoveGetItemPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import Node + + +class FuseQuantizedActivationPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = { + ConvertToClampPass, + FoldAndAnnotateQParamsPass, + RemoveGetItemPass, + } + + @staticmethod + def _is_fuseable_quantized_activation(node: Node): + """Fuse activations that have a 0 lower bound and quantized with a qmin zero-point""" + is_fuseable = node.target == exir_ops.edge.aten.relu.default + if node.target == exir_ops.edge.aten.hardtanh.default: + min_val = node.args[1] + is_fuseable = min_val == 0 + + is_quantized = len(node.users) == 1 and next(iter(node.users)).target in Q_OPS + if is_fuseable and is_quantized: + quant_node = next(iter(node.users)) + quant_args = QuantArgs.from_operator(quant_node.target, quant_node.args) + zp = quant_args.zp + qmin = quant_args.qmin + return zp == qmin + else: + return False + + @staticmethod + def _is_fuseable_input(node: Node): + return ( + node.target + in ( + exir_ops.edge.aten.convolution.default, + exir_ops.edge.aten.linear.default, + ) + and len(node.users) == 1 + ) + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + + if not FuseQuantizedActivationPass._is_fuseable_quantized_activation(node): + continue + + input_node = node.args[0] + if not FuseQuantizedActivationPass._is_fuseable_input(input_node): + continue + + node.replace_all_uses_with(input_node) + graph_module.graph.erase_node(node) + modified = True + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_view_copy_transform_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_view_copy_transform_pass.py new file mode 100644 index 0000000..cef3b40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/fuse_view_copy_transform_pass.py @@ -0,0 +1,14 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.transforms.fuse_view_copy import FuseViewCopyTransform +from executorch.exir.pass_base import ExportPass + + +class FuseViewCopyTransformPass(ArmPass, FuseViewCopyTransform): + _passes_required_after: Set[Type[ExportPass]] = set() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py new file mode 100644 index 0000000..de80d61 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_int32_casts_after_int64_placeholders.py @@ -0,0 +1,130 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.decompose_embedding_pass import ( + DecomposeEmbeddingPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import EdgeOpOverload, ExportPass, PassResult +from torch._subclasses.fake_tensor import FakeTensor + + +logger = logging.getLogger(__name__) + + +class InsertInt32CastsAfterInt64PlaceholdersPass(ArmPass): + """ + Insert an int64->int32 cast after each int64 placeholder. + + Note: Overflow checks are not applied in this pass. It is the user's responsibility to ensure that values fit within + the int32 range. + """ + + _passes_required_after: Set[Type[ExportPass]] = {DecomposeEmbeddingPass} + + # Ops that require i64 inputs → positions of args to upcast. + # Key: op overload; Value: zero-based indices of positional args that must be i64. + I64_INPUT_ARG_POSITIONS = { + torch.ops.aten.one_hot.default: (0,), + torch.ops.aten.index_copy_.default: (2,), + torch.ops.aten.index_copy.default: (2,), + } + + def _insert_callsite_i32_to_i64_casts(self, graph_module: torch.fx.GraphModule): + """ + If an operator requires int64 inputs but dtype propagation (via call_operator) + produced int32, insert a local int32→int64 cast at the call site to satisfy + PyTorch's operator input validation. + """ + modified = False + graph = graph_module.graph + for node in graph.nodes: + if node.op != "call_function": + continue + if node.target not in self.I64_INPUT_ARG_POSITIONS: + continue + + with graph.inserting_before(node): + arg_positions = self.I64_INPUT_ARG_POSITIONS.get(node.target) + args_list = list(node.args) + for pos in arg_positions: # type: ignore[union-attr] + input_arg = args_list[pos] + to_copy_op = self._get_decomposition(graph) + cast_node = graph_module.graph.create_node( + "call_function", + to_copy_op, + (input_arg,), + {"dtype": torch.int64}, + ) + cast_node.meta["val"] = node.meta["val"].to(torch.int64) + args_list[pos] = cast_node + node.args = tuple(args_list) + modified = True + return modified + + def _graph_uses_edge_ops(self, graph: torch.fx.Graph) -> bool: + for n in graph.nodes: + if n.op == "call_function": + if isinstance(n.target, EdgeOpOverload): + return True + return False + + def _get_decomposition(self, graph: torch.fx.Graph): + if self._graph_uses_edge_ops(graph): + return exir_ops.edge.dim_order_ops._to_dim_order_copy.default + else: + return torch.ops.dim_order_ops._to_dim_order_copy.default + + def _is_tensor_of_dtype(self, node_val, dtype: torch.dtype) -> bool: + return isinstance(node_val, FakeTensor) and node_val.dtype == dtype + + def _insert_placeholder_i64_to_i32_casts(self, graph_module: torch.fx.GraphModule): + modified = False + graph = graph_module.graph + for node in graph.nodes: + if node.op != "placeholder": + continue + node_val = node.meta["val"] + if not self._is_tensor_of_dtype(node_val, torch.int64): + continue + + to_copy_op = self._get_decomposition(graph) + with graph.inserting_after(node): + cast_after = create_node( + graph, + to_copy_op, + args=(node,), + kwargs={ + "dtype": torch.int32, + }, + ) + users = [user for user in node.users if user != cast_after] + for user in users: + user.replace_input_with(node, cast_after) + logger.warning( + f"Inserting a casting node {cast_after.name} after {node.name} to cast int64 placeholder" + f" to int32 for {node.name} defined in {node.meta.get('stack_trace','[no stack trace found]')}" + ) + modified = True + return modified + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + modified |= self._insert_placeholder_i64_to_i32_casts(graph_module) + modified |= self._insert_callsite_i32_to_i64_casts(graph_module) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_rescales_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_rescales_pass.py new file mode 100644 index 0000000..9e69a1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_rescales_pass.py @@ -0,0 +1,584 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from copy import copy +from typing import cast, Dict, Optional, Set, Tuple, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node, set_node_arg +from executorch.backends.arm._passes.decompose_sum_pass import DecomposeSumPass +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_output_qparams, +) + +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +class InsertRescalePass(ArmPass): + """Finds patterns of dq -> q, and replaces them + with backend dialect tosa::RESCALE op. + + Does not guarantee that the dtypes and zero points are valid + in TOSA, that is the job of the quantization annotator that + produced the dq and q nodes. The TOSA constraints are validated + in the fake implementation of. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def fold_dq_q_to_rescale(self, node: Node, user: Node, graph_module: GraphModule): + dq_args = QuantArgs.from_operator(node.target, node.args) + q_args = QuantArgs.from_operator(user.target, user.args) + new_scale = dq_args.scale / q_args.scale + + with graph_module.graph.inserting_before(node): + rescale_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.RESCALE.default, + ( + node.all_input_nodes[0], + q_args.dtype, + [new_scale], + dq_args.zp, + q_args.zp, + ), + ) + rescale_node.meta = copy(user.meta) + user.replace_all_uses_with(rescale_node) + graph_module.graph.erase_node(user) + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + node = cast(Node, node) + + if node.target not in DQ_OPS: + continue + # Copy users since we remove them while iterating, modyfing the node.users list. + for user in copy(node.users): + if user.target in Q_OPS: + self.fold_dq_q_to_rescale(node, user, graph_module) + modified = True + if len(node.users) == 0: + graph_module.graph.erase_node(node) + + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + return PassResult(graph_module, modified) + + +class InsertRescaleInt32Pass(ArmPass): + """Numerous TOSA ops require inputs and outputs to be 32-bit integers in their + quantized implementations. This pass treats such operator nodes by + inserting rescale ops before and after them if needed. Note that extra + logic that handles the scales and zero points are in place here because the + affected TOSA ops have naive implementations that do not account for the + quantization parameters. + """ + + # SUM must be decomposed after this pass to prevent insertion of RESCALE + # nodes between each subsequent SUM node after decomposition. RESCALE nodes + # should only be inserted before and after the SUM node prior to its + # decomposition. + _passes_required_after: Set[Type[ExportPass]] = {DecomposeSumPass} + + included_targets = [ + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.sum.dim_IntList, + ] + + def _int32_qargs(self, s): + """Helper creator function for INT32-based QuantArgs""" + + return QuantArgs( + scale=s, + zp=0, + qmin=torch.iinfo(torch.int32).min, + qmax=torch.iinfo(torch.int32).max, + dtype=torch.int32, + ) + + def _get_inputs_rescaled_qparams( + self, target, input_qparams: Dict[int, QuantArgs] + ) -> Dict[int, QuantArgs]: + """Get the qparams for the INT32 operands to the op ``target`` + + Inputs to the INT32-based operator must be rescaled from INT8 to INT32. + This function computes the ``QuantArgs`` for each of the operands and returns + it as a dict, mapping tensor index to ``QuantArgs``. + """ + + if target in [ + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.maximum.default, + ]: + # For these ops, use the smallest scale among the INT8 operands. + min_scale = min( + [qp.get_scale_per_tensor() for qp in input_qparams.values()] + ) + qparams = {i: self._int32_qargs(min_scale) for i in input_qparams.keys()} + elif target in [ + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + ]: + keys = list(input_qparams) + if len(keys) < 2: + raise ValueError(f"Expected two input qparams, got: {input_qparams}.") + if input_qparams[keys[0]].dtype != input_qparams[keys[1]].dtype: + raise ValueError( + f"Mismatch in dtype args: {input_qparams[keys[0]].dtype} != {input_qparams[keys[1]].dtype}" + ) + + # We are handling two INT8 or two INT16 numbers. For INT8, if the + # zero point is non-null, the result will be in the range [-255; + # 255], therefore we need 9 bits for the result. We have a 32-bit + # accumulator, so we can divide the scale by (1 << 20) which is + # equivalent to shifting the INT8 operands 20 bits to the left + # before rescaling them both to 2 * max(lhs, rhs). + # + # For INT16, similary logic can be applied, but we instead end up + # with a left shift of 12. + lhs_scale, rhs_scale = ( + qp.get_scale_per_tensor() for qp in input_qparams.values() + ) + max_scale_2x = 2 * max(lhs_scale, rhs_scale) + + # Select shift based on input dtype. + shift_bits = 12 if input_qparams[keys[0]].dtype == torch.int16 else 20 + + scale = max_scale_2x / (1 << shift_bits) + qparams = {i: self._int32_qargs(scale) for i in input_qparams.keys()} + elif target in [ + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.sum.dim_IntList, + ]: + # The input scales do not need to be adjusted for these ops; they + # can remain the same. + qparams = { + i: self._int32_qargs(qp.get_scale_per_tensor()) + for i, qp in input_qparams.items() + } + else: + raise ValueError(f"Not a valid target: {target}") + + return qparams + + def _get_output_qparams( + self, target, inputs_qparams: Dict[int, QuantArgs] + ) -> Optional[QuantArgs]: + """Given an op ``target`` and the ``QuantArgs`` for each of its inputs, compute + the scale of the output based on how the operator itself affects it.""" + + if target in [ + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.sum.dim_IntList, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + ]: + # The op has not altered the scale; the output scale is equal to + # the operands' scales. + return self._int32_qargs(inputs_qparams[0].get_scale_per_tensor()) + elif target in [ + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.lt.Tensor, + ]: + # Output is bool for these ops and thus no qparams are present + return None + elif target in [exir_ops.edge.aten.mul.Tensor]: + # Mul will cause the scales to also multiply; refer to the formula + # where we compute the output scale S_2: + # + # (Q_2 - ZP_2) * S_2 == ((Q_0 - ZP_0) * S_0) * ((Q_1 - ZP_1) * S_1) + # + # yields: + # + # (Q_2 - ZP_2) == (Q_0 - ZP_0) * (Q_1 - ZP_1) + # S_2 = S_0 * S_1 + output_scale = math.prod( + (qp.get_scale_per_tensor() for qp in inputs_qparams.values()) + ) + return self._int32_qargs(output_scale) + else: + raise ValueError(f"Not a valid target: {target}") + + def _get_rescale_qparams( + self, target, input_qparams: Dict[int, QuantArgs] + ) -> Tuple[Dict[int, QuantArgs], Optional[QuantArgs]]: + """ + Get the quantization parameters of the INT32 inputs/outputs that will + surround the node after the new RESCALE ops have been inserted. + """ + + inputs_rescaled_qparams = self._get_inputs_rescaled_qparams( + target, input_qparams + ) + output_qparams = self._get_output_qparams(target, inputs_rescaled_qparams) + + return (inputs_rescaled_qparams, output_qparams) + + def _rescale_inputs(self, graph, node, rescale_qargs: Dict[int, QuantArgs]) -> bool: + qargs = node.meta["input_qparams"] + + args_copy = list(node.args) + seen_args = set() + modified = False + for i in qargs: + qp = qargs[i] + if qp.dtype not in (torch.int8, torch.int16): + continue + + arg_node = args_copy[i] + if arg_node in seen_args: + continue + seen_args.add(arg_node) + + with graph.inserting_after(arg_node): + rescale_node = create_node( + graph, + exir_ops.backend.tosa.RESCALE.default, + ( + arg_node, + torch.int32, + [ + qp.get_scale_per_tensor() + / rescale_qargs[i].get_scale_per_tensor() + ], # [Old scale / new scale] + qp.get_zp_per_tensor(), # Old zero point + rescale_qargs[i].get_zp_per_tensor(), # New zero point + ), + from_node=node, + ) + + node.replace_input_with(arg_node, rescale_node) + modified = True + + return modified + + def _rescale_outputs(self, graph, node, rescale_qargs: Optional[QuantArgs]) -> bool: + if "output_qparams" not in node.meta or len(node.meta["output_qparams"]) == 0: + return False + + qargs = get_output_qparams(node) + assert len(qargs) == 1 + assert rescale_qargs is not None + + qarg = qargs[0] + if qarg.dtype not in (torch.int8, torch.int16): + return False + + users_copy = list(node.users) + + with graph.inserting_after(node): + rescale_node = create_node( + graph, + exir_ops.backend.tosa.RESCALE.default, + ( + node, + qarg.dtype, + [ + rescale_qargs.get_scale_per_tensor() + / qarg.get_scale_per_tensor() + ], # [Old scale / new scale] + rescale_qargs.get_zp_per_tensor(), # Old zero point + qarg.get_zp_per_tensor(), # New zero point + ), + from_node=node, + ) + + for user in users_copy: + user.replace_input_with(node, rescale_node) + + return True + + def call(self, graph_module: GraphModule) -> PassResult: + graph = graph_module.graph + + modified = False + for node in list(graph.nodes): + node = cast(Node, node) + + if node.op != "call_function" or node.target not in self.included_targets: + continue + + if "input_qparams" not in node.meta or len(node.meta["input_qparams"]) == 0: + continue + input_qparams = node.meta["input_qparams"] + + inputs_rescale_qargs, output_rescale_qargs = self._get_rescale_qparams( + node.target, input_qparams + ) + + inputs_was_rescaled = self._rescale_inputs( + graph, node, inputs_rescale_qargs + ) + outputs_was_rescaled = False + if inputs_was_rescaled: + outputs_was_rescaled = self._rescale_outputs( + graph, node, output_rescale_qargs + ) + modified = True + + # Update node metadata + + if inputs_was_rescaled: + assert len(inputs_rescale_qargs) == len(node.meta["input_qparams"]) + node.meta["input_qparams"] = inputs_rescale_qargs + + if outputs_was_rescaled: + assert len(node.meta["output_qparams"]) == 1 + node.meta["output_qparams"] = {0: output_rescale_qargs} + + # If the output type is specified in the node, change it such + # that it matches the subsequent rescale node(s) that this node + # now has output edges to. + if "dtype" in node.kwargs: + set_node_arg(node, "dtype", torch.int32) + + if modified: + # Retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + + return PassResult(graph_module, modified) + + +class InsertControlFlowRescalesPass(ArmPass): + """The quantization parameters for tensors going into and coming out of a submodule are not guaranteed to + match the quantization parameters for the corresponding tensors inside the submodule. For example, cond has + different annotation on input and output, while the entire graph inside the submodule could be using shared + annotation. This pass solves this by inserting rescales in the beginning and end of the submodule + that transform the tensor from one set of quantization parameters to another. + + The pass is run by the graph_module containing the control flow operator, but requires that the affected nodes + inside the submodule have been q-dq folded and have input/output_qparams meta. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _get_input_nodes(self, graph_module: GraphModule): + return [node for node in graph_module.graph.nodes if node.op == "placeholder"] + + def _insert_rescale( + self, + in_qparams: QuantArgs, + out_qparams: QuantArgs, + from_node: Node, + graph_module: GraphModule, + ): + """Insert a rescale into the graph, inheriting meta from `from_node`. + The node is not connected to anything, that is up to the user.""" + + new_scales = [ + in_qparams.get_scale_per_tensor() / out_qparams.get_scale_per_tensor() + ] + + rescale_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.RESCALE.default, + ( + None, + out_qparams.dtype, + new_scales, + in_qparams.get_zp_per_tensor(), # Old zero point + out_qparams.get_zp_per_tensor(), # New zero point + ), + from_node=from_node, + ) + return rescale_node + + def _rescale_submodule_inputs( + self, submodule: GraphModule, input_qparams_map: Dict[int, QuantArgs] + ) -> bool: + """Insert rescales at the inputs of `submodule` to match the qparams outside the submodule. + Matching the correct qparams gets a bit tricky: + Containing module: | submodule: + ops => cond | => placeholders => ... + + The dq->q qparam pair we want to convert to a rescale is: + (input qparams of op, output qparams of placeholder) + And the rescale is inserted after the placeholder. + + Args: + submodule: GraphModule: the GraphModule in which to rescale the inputs. + input_qparams_map: A map of input indexes mapping to QuantArgs. Not guaranteed to contain a mapping + for every submodule input. + Returns: + True if at least one rescale was inserted, False otherwise. + """ + + modified = False + input_nodes = self._get_input_nodes(submodule) + for qargs_index in input_qparams_map: + input_node = input_nodes[qargs_index] + if len(input_node.users) == 0: + continue + if len(out_qparams_map := input_node.meta.get("output_qparams", {})) != 1: + raise ValueError( + f"Expected submodule input {input_node} to have exactly one output qparam, got {out_qparams_map}" + ) + in_qparams = input_qparams_map[qargs_index] + out_qparams = cast(QuantArgs, out_qparams_map[0]) + + # Remove qparam meta to not confuse folding pass. + del input_node.meta["output_qparams"] + if in_qparams == out_qparams: + continue + with submodule.graph.inserting_after(input_node): + modified = True + rescale_node = self._insert_rescale( + in_qparams, out_qparams, input_node, submodule + ) + input_node.replace_all_uses_with(replace_with=rescale_node) + rescale_node.update_arg(0, input_node) + return modified + + def _rescale_submodule_outputs( + self, submodule: GraphModule, output_qparams_map: Dict[int, QuantArgs] + ) -> bool: + """Insert rescales at the outputs of `submodule` to match the qparams outside the submodule. + Matching the correct qparams gets a bit tricky: + Submodule: | Containing module: + output_nodes => output |=> getitems => ... + + The dq->q qparam pair we want to convert to a rescale is: + (input qparam of output_node, output qparam of getitem) + And the rescale is inserted between op and output. Note that the output qparam of op is called input_qargs, + since the it is the input to the dq-q pair. + + Args: + submodule: GraphModule: the GraphModule in which to rescale the outputs. + output_qparams_map: A map of output indexes mapping to QuantArgs. Not guaranteed to contain a mapping + for every submodule output. + Returns: + True if at least one rescale was inserted, False otherwise. + """ + + modified = False + output_node = submodule.graph.output_node() + output_args = list(cast(tuple[Node], output_node.args[0])) + input_qparams_map = cast( + dict[int, QuantArgs], output_node.meta["input_qparams"] + ) + for qargs_index in output_qparams_map: + output_arg_node = output_args[qargs_index] + in_qparams = input_qparams_map[qargs_index] + out_qparams = output_qparams_map[qargs_index] + if in_qparams == out_qparams: + continue + with submodule.graph.inserting_before(output_node): + modified = True + rescale_node = self._insert_rescale( + in_qparams, out_qparams, output_arg_node, submodule + ) + output_args[qargs_index] = rescale_node + rescale_node.update_arg(0, output_arg_node) + output_node.update_arg(0, tuple(output_args)) + # Remove qparam meta to not confuse folding pass. + del output_node.meta["input_qparams"] + return modified + + def _get_input_qparams_map(self, node: Node, idx: int): + input_qparams_meta = cast( + dict[int, QuantArgs], node.meta.get("input_qparams", None) + ) + if input_qparams_meta: + input_qparams = cast(QuantArgs, input_qparams_meta.get(idx, None)) + if not input_qparams: + raise ValueError( + f"Expected entry with key {idx} in input_qparams meta, got {input_qparams_meta}" + ) + num_inputs = len(cast(list, node.args[idx])) + + # Currently, infra only supports one set of qparams for a list of inputs + # Map all inputs to the same qparams. + input_qparams_map = {i: input_qparams for i in range(num_inputs)} + return input_qparams_map + return None + + def _get_output_qparams_map(self, node: Node): + output_qparams_map: dict[int, QuantArgs] = {} + for getitem_node in node.users: + idx = cast(int, getitem_node.args[1]) + qparam = getitem_node.meta.get("output_qparams", None) + if qparam: + output_qparams_map[idx] = cast(QuantArgs, qparam[0]) + return output_qparams_map + + def _rescale_cond_submodules(self, node: Node, graph_module: GraphModule) -> bool: + modified = False + if_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[1].target)) # type: ignore + else_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[2].target)) # type: ignore + input_qparams_map = self._get_input_qparams_map(node, 3) + if input_qparams_map: + modified |= self._rescale_submodule_inputs(if_graph, input_qparams_map) + modified |= self._rescale_submodule_inputs(else_graph, input_qparams_map) + + output_qparams_map = self._get_output_qparams_map(node) + if output_qparams_map: + modified |= self._rescale_submodule_outputs(if_graph, output_qparams_map) + modified |= self._rescale_submodule_outputs(else_graph, output_qparams_map) + return modified + + def _rescale_while_submodules(self, node: Node, graph_module: GraphModule): + modified = False + cond_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[0].target)) # type: ignore + body_graph: GraphModule = cast(GraphModule, graph_module.get_submodule(node.args[1].target)) # type: ignore + + input_qparams_map = self._get_input_qparams_map(node, 2) + if input_qparams_map: + modified |= self._rescale_submodule_inputs(cond_graph, input_qparams_map) + modified |= self._rescale_submodule_inputs(body_graph, input_qparams_map) + + output_qparams_map = self._get_output_qparams_map(node) + if output_qparams_map: + modified |= self._rescale_submodule_outputs(body_graph, output_qparams_map) + return modified + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + + for node in list(graph_module.graph.nodes): + node = cast(Node, node) + if node.op != "call_function": + continue + + if node.target == torch.ops.higher_order.cond: + modified = self._rescale_cond_submodules(node, graph_module) + if node.target == torch.ops.higher_order.while_loop: + modified = self._rescale_while_submodules(node, graph_module) + + if modified: + # Retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_table_ops.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_table_ops.py new file mode 100644 index 0000000..3daa4b9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/insert_table_ops.py @@ -0,0 +1,305 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from itertools import chain +from typing import Callable, cast, Dict, Iterator, Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.transforms.utils import create_constant_placeholder + +from executorch.exir import ExportedProgram + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind +from torch.fx import GraphModule +from torch.fx.node import Node + + +class TableOps: + """ + Helper class for finding the corresponding table operator for a given Node. + """ + + # Targets that follow a straigtforward one-to-one mapping to their table op + unary_table_ops: Dict[EdgeOpOverload, Callable[[torch.Tensor], torch.Tensor]] = { + exir_ops.edge.aten.ceil.default: torch.ceil, + exir_ops.edge.aten.erf.default: torch.erf, + exir_ops.edge.aten.exp.default: torch.exp, + exir_ops.edge.aten.expm1.default: torch.expm1, + exir_ops.edge.aten.floor.default: torch.floor, + exir_ops.edge.aten.log.default: torch.log, + exir_ops.edge.aten.log1p.default: torch.log1p, + exir_ops.edge.aten.reciprocal.default: torch.reciprocal, + exir_ops.edge.aten.rsqrt.default: torch.rsqrt, + exir_ops.edge.aten.sigmoid.default: torch.sigmoid, + exir_ops.edge.aten.cos.default: torch.cos, + exir_ops.edge.aten.sin.default: torch.sin, + exir_ops.edge.aten.tanh.default: torch.tanh, + exir_ops.edge.aten.atan.default: torch.atan, + exir_ops.edge.aten.atanh.default: torch.atanh, + exir_ops.edge.aten.hardsigmoid.default: torch.nn.functional.hardsigmoid, + exir_ops.edge.aten.hardswish.default: torch.nn.functional.hardswish, + exir_ops.edge.aten.sinh.default: torch.sinh, + exir_ops.edge.aten.acosh.default: torch.acosh, + exir_ops.edge.aten.asin.default: torch.asin, + exir_ops.edge.aten.asinh.default: torch.asinh, + exir_ops.edge.aten.cosh.default: torch.cosh, + exir_ops.edge.aten.acos.default: torch.acos, + exir_ops.edge.aten.tan.default: torch.tan, + } + + # Targets that must be treated explicitly + special_table_ops: Set[EdgeOpOverload] = { + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.gelu.default, + exir_ops.edge.aten.elu.default, + } + + def __init__(self, exported_program: ExportedProgram): + self.exported_program = exported_program + + def __contains__(self, node: Node) -> bool: + return ( + node.target in self.unary_table_ops or node.target in self.special_table_ops + ) + + def __getitem__(self, node: Node): + target = cast(EdgeOpOverload, node.target) + if target in self.unary_table_ops: + return self.unary_table_ops[target] + elif target in self.special_table_ops: + match target: + case exir_ops.edge.aten.pow.Tensor_Scalar: + # Exponent is a constant. Embed it into a lambda. + exp = cast(int, node.args[1]) + return lambda x: torch.pow(x, exp).flatten() + case exir_ops.edge.aten.gelu.default: + # If kwargs not present it is default "none" + approximate = cast( + str, + ( + node.kwargs["approximate"] + if "approximate" in node.kwargs + else "none" + ), + ) + return lambda x: torch.nn.functional.gelu( + x, approximate=approximate + ).flatten() + case exir_ops.edge.aten.elu.default: + input_alpha = cast(int, node.kwargs["alpha"]) + return lambda x: torch.nn.functional.elu( + x, alpha=input_alpha + ).flatten() + case _: + # Op must be handled if it's inside self.special_ops + raise AssertionError("Unhandled table operation") + else: + raise KeyError("Table op for {target} does not exist") + + @staticmethod + def included_ops() -> Iterator[EdgeOpOverload]: + return chain(TableOps.unary_table_ops, TableOps.special_table_ops) + + +class InsertTableOpsPass(ArmPass): + """ + For ops in self.table_ops they need to be serialized as a TOSA TABLE. This pass replaces these + edge ops with a tosa._table(input: Tensor, target_str: str) where target_str == str(node.target). + When lowering the _table node target_str will be used to find the corresponding torch operator + which will be used to produce the table values in operators/op_table.py. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram) -> None: + super().__init__() + self.exported_program = exported_program + self.table_ops = TableOps(exported_program) + + def register_buffer(self, buffer_name: str, buffer: torch.Tensor) -> None: + """ + Add buffer to self.exported_program.state_dict + """ + self.exported_program.state_dict[buffer_name] = buffer + + def generate_8bit_table_values( + self, + torch_op: Callable[[torch.Tensor], torch.Tensor], + in_quantargs: QuantArgs, + out_quantargs: QuantArgs, + ) -> tuple[torch.Tensor, int]: + """Compute LUT values for a INT8 TOSA.TABLE. Also returns 0 since no shifting is required after 8bit table. + The INT8 table is a simple 256 value 1-1 LUT. + """ + + def f(x: torch.Tensor) -> torch.Tensor: + x = in_quantargs.dequantize_value(x) + x = torch_op(x) + return out_quantargs.quantize_value(x) + + return ( + f( + torch.linspace( + start=in_quantargs.qmin, + end=in_quantargs.qmax, + steps=256, + dtype=torch.int8, + ) + ).to(dtype=torch.int8), + 0, + ) + + def generate_16_bit_table_values( + self, + torch_op: Callable[[torch.Tensor], torch.Tensor], + in_quantargs: QuantArgs, + out_quantargs: QuantArgs, + ) -> tuple[torch.Tensor, int]: + """Compute LUT values for a INT16 TOSA.TABLE with 32 bit output. + In practice the output is 23 bits that should be interpreted as 16 'whole' bits and 7 fractional bits, see + the specification: https://www.mlplatform.org/tosa/tosa_spec.html#_table. This means that the output + will interpreted as 2**7=128 times too large unless accounted for by rescaling down the table output. + + Quantization can be either int16 or int32 which means that the op output could be larger than the 23 bits from + the TOSA.TABLE output. In that case, we need to rescale up the output. + + To handle this we need to: + 1) Make sure that our table values fit within 16 bits. + 2) Insert a rescale after the table to handle the x128 from the fractional bits and match the quantization. + + The function returns rescale_lshift which says how much to rescale after the table. This value can negative. + """ + + def f(x: torch.Tensor) -> torch.Tensor: + x = x.clamp(in_quantargs.qmin, in_quantargs.qmax).to( + dtype=in_quantargs.dtype + ) + # Dont use the 7 LSBs. + x = in_quantargs.dequantize_value((x & ~0x7F)) + x = torch_op(x) + return out_quantargs.quantize_value(x) + + lut_values = f( + torch.linspace( + start=in_quantargs.qmin, + end=in_quantargs.qmax + 1, + steps=513, + # use torch.int32 to avoid overflow for end=in_quantargs.qmax + 1. + dtype=torch.int32, + ) + ) + # Calculate how much we need to shift table values to fit in 16 signed bits + # ceil(log2(max absolute table value)) + 1 bit for signedness - 16 + # Example: + # Max value in the table is 70 000. We want to fit it in 16 signed bits. + # 70 000=0b10001000101110000 (17 digits) has ceil(log2(70 000)) = ceil(16.095) = 17 bits. + # If we shift it 17-16=1 bit, we do get 16 bits (0b1000100010111000), + # but due to signedness this is a negative number! So we need to shift it one more bit. + # Note: for out_quantargs.dtype=torch.int16, rshift == 0 and rescale_lshift = -7. + rshift = int(torch.ceil(torch.log2(lut_values.abs().max()))) + 1 - 16 + # The 7 fractional bits are equivalent to a lshift of 7, so subtract 7 from the lshift we do. + rescale_lshift = rshift - 7 + lut_values = lut_values >> rshift + return lut_values.to(dtype=torch.int16), rescale_lshift + + def generate_table_values( + self, + torch_op: Callable[[torch.Tensor], torch.Tensor], + in_quantargs: QuantArgs, + out_quantargs: QuantArgs, + ) -> tuple[torch.Tensor, int]: + match out_quantargs.dtype: + case torch.int8: + return self.generate_8bit_table_values( + torch_op, in_quantargs, out_quantargs + ) + case torch.int16 | torch.int32: + return self.generate_16_bit_table_values( + torch_op, in_quantargs, out_quantargs + ) + case _: + raise ValueError( + f"Unsupported output dtype for table: {out_quantargs.dtype}" + ) + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function" or node not in self.table_ops: + continue + input_qparams = node.meta.get("input_qparams", {}) + output_qparams = node.meta.get("output_qparams", {}) + if len(input_qparams) == 0 or len(output_qparams) == 0: + # We only want to replace the node if it's quantized + continue + # Create table node + insert_pos = list(node.graph.nodes)[0] + with graph_module.graph.inserting_before(insert_pos): + # Expect exactly one quantization parameter for input and output + if len(input_qparams) != 1: + raise ValueError( + f"InsertTableOpsPass expected exactly one input quantization parameter, " + f"got {len(input_qparams)} for node {node.name}" + ) + if len(output_qparams) != 1: + raise ValueError( + f"InsertTableOpsPass expected exactly one output quantization parameter, " + f"got {len(output_qparams)} for node {node.name}" + ) + + # Generate table buffer and how much to lshift the table output. + buffer, lshift = self.generate_table_values( + torch_op=self.table_ops[node], + in_quantargs=input_qparams[0], + out_quantargs=output_qparams[0], + ) + # Register buffer in self.exported_program.state_dict + const_table_node = create_constant_placeholder( + exp_program=self.exported_program, + graph=node.graph, + kind=InputKind.BUFFER, + name=node.name + "_table_constant", + data=buffer, + persistent_buffer=True, + ) + + # Create table node + with graph_module.graph.inserting_before(node): + table_op_node = create_node( + graph=graph_module.graph, + op_target=exir_ops.backend.tosa.TABLE.default, + args=(node.args[0], const_table_node), + ) + output_node = table_op_node + + if lshift != 0: + scale = 2.0**lshift + rescale_node = create_node( + graph=graph_module.graph, + op_target=exir_ops.backend.tosa.RESCALE.default, + args=(table_op_node, output_qparams[0].dtype, [scale], 0, 0), + ) + output_node = rescale_node + + node.replace_all_uses_with(output_node) + graph_module.graph.erase_node(node) + table_op_node.meta["input_qparams"] = input_qparams + table_op_node.meta["output_qparams"] = output_qparams + modified = True + + if modified: + # retrace the graph to update the fake tensor types + graph_module = super().call(graph_module).graph_module + + graph_module.recompile() + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_dtype_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_dtype_pass.py new file mode 100644 index 0000000..f0aaa0c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_dtype_pass.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import create_node, get_node_arg +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +DTYPE_RANK = { + torch.bool: 0, + torch.uint8: 1, + torch.int8: 2, + torch.int16: 3, + torch.int32: 4, + torch.int64: 5, + torch.float16: 6, + torch.float32: 7, + torch.float64: 8, +} + + +def get_largest_dtype(dtype_1, dtype_2): + """Find the largest dtype.""" + return dtype_1 if DTYPE_RANK[dtype_1] > DTYPE_RANK[dtype_2] else dtype_2 + + +class MatchArgDtypePass(ArmPass): + """Pass to match data types of non-condition input tensors. + + Edge dialect allows different data types for non-condition tensors, while TOSA + does not. In cases where they differ a TOSA CAST operator is inserted. + + There is an edge case where one input is `boolean`, which cannot be directly cast + to, for example, float32. When this occurs two CAST operators are added to first + cast to int8 and then to the correct target data type. + + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = {exir_ops.edge.aten.sub.Tensor, exir_ops.edge.aten.where.self} + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + graph = graph_module.graph + + for node in list(graph.nodes): + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + input_ = get_node_arg(node.args, 0) + other_ = get_node_arg(node.args, 1) + + input_dtype = input_.meta["val"].dtype + other_dtype = other_.meta["val"].dtype + target_dtype = input_dtype + if input_dtype != other_dtype: + target_dtype = get_largest_dtype(input_dtype, other_dtype) + + for arg in node.args[1:]: + arg_dtype = arg.meta["val"].dtype + + if arg_dtype != target_dtype: + if arg_dtype == torch.bool: + # Bool is an edge case which cannot necessarily be directly + # converted to the target data type. + with graph.inserting_after(arg): + replace_node_int8 = create_node( + graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ) + replace_node_int8.args = (arg,) + replace_node_int8.kwargs = {"dtype": torch.int8} + + with graph.inserting_after(replace_node_int8): + replace_node_fp32 = create_node( + graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ) + replace_node_fp32.args = (replace_node_int8,) + replace_node_fp32.kwargs = {"dtype": target_dtype} + node.replace_input_with(arg, replace_node_fp32) + else: + with graph.inserting_after(arg): + replace_node = create_node( + graph, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ) + replace_node.args = (arg,) + replace_node.kwargs = {"dtype": target_dtype} + node.replace_input_with(arg, replace_node) + + modified_graph = True + + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_ranks_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_ranks_pass.py new file mode 100644 index 0000000..61dd4ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/match_arg_ranks_pass.py @@ -0,0 +1,114 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.exir import ExportedProgram + +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node + + +class MatchArgRanksPass(ArmPass): + """ + For ops in 'targeted_ops', make sure that the inputs share the same rank. + New dimensions are inserted from the beginning of the inputs that have a + lower rank to match the input with the highest rank. + + Example: + input0 = shape(4, 3, 2) + input1 = shape(2) + input2 = shape(3, 1) + Becomes: + input0 = shape(4, 3, 2) + input1 = shape(1, 1, 2) + input2 = shape(1, 3, 1) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + targeted_ops = [ + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.div.Tensor, + exir_ops.edge.aten.div.Tensor_mode, + 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.ge.Tensor, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.pow.Tensor_Tensor, + exir_ops.edge.aten.remainder.Tensor, + exir_ops.edge.aten.where.self, + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.minimum.default, + ] + + def _match_op_rank(self, graph_module, node, arg, max_rank): + """ + In graph_module, insert a view between arg and node to make the + rank of arg match the other args to node. + """ + shape = get_first_fake_tensor(arg).shape + rank = len(shape) + new_shape = list([1] * (max_rank - rank) + list(shape)) + with graph_module.graph.inserting_before(node): + view = create_node( + graph_module.graph, + exir_ops.edge.aten.view_copy.default, + args=(arg, new_shape), + kwargs={}, + ) + node.replace_input_with(arg, view) + + def call(self, graph_module: GraphModule) -> PassResult: + for node in graph_module.graph.nodes: + node = cast(Node, node) + + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + # Calculate max rank of all inputs to node + max_rank = 0 + for arg in node.args: + if isinstance(arg, Node): + shape = get_first_fake_tensor(arg).shape + max_rank = max(max_rank, len(shape)) + + # Adjust output shape of args if needed. + for arg in node.args: + if not isinstance(arg, Node): + continue + shape = get_first_fake_tensor(arg).shape + rank = len(shape) + if rank == max_rank: + continue + + self._match_op_rank(graph_module, node, arg, max_rank) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/mm_to_bmm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/mm_to_bmm_pass.py new file mode 100644 index 0000000..34634b9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/mm_to_bmm_pass.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.convert_squeezes_to_view import ( + ConvertSqueezesToViewPass, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import Node + + +class ConvertMmToBmmPass(ArmPass): + """ + This pass converts a MM node to a BMM one and turns input and output tensors + from rank 2 to rank 3. The TOSA specification requires rank 3. The graph is + modified to do the following: + 1) Unsqueeze input tensors to rank 3. + 2) Convert MM node to BMM. + 3) Squeeze output tensor to rank 2. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + ConvertSqueezesToViewPass, + } + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + graph = graph_module.graph + node_list = graph.find_nodes( + op="call_function", target=exir_ops.edge.aten.mm.default + ) + for node in node_list: + # Unsqueeze input tensors to rank 3 + for input_node in node.args: + if not isinstance(input_node, Node): + continue + + shape = get_first_fake_tensor(input_node).shape + rank = len(shape) + if rank != 2: + raise RuntimeError(f"Input tensor has rank {rank}, must be 2") + + with graph.inserting_before(node): + unsqueeze_before = create_node( + graph, + exir_ops.edge.aten.unsqueeze_copy.default, + from_node=node, + inherit_qparams=False, + ) + unsqueeze_before.args = ( + input_node, # Input is node's original input + 0, + ) + node.replace_input_with(input_node, unsqueeze_before) + + # Replace mm node with bmm + with graph.inserting_before(node): + bmm_node = create_node( + graph, + exir_ops.edge.aten.bmm.default, + from_node=node, + inherit_qparams=True, + ) + bmm_node.args = node.args + node.replace_all_uses_with(bmm_node) + graph.erase_node(node) + + # Unsqueeze output tensor to rank 3 + with graph.inserting_after(bmm_node): + squeeze_after = create_node( + graph, + exir_ops.edge.aten.squeeze_copy.dims, + from_node=node, + inherit_qparams=False, + ) + squeeze_after.args = ( + bmm_node, + [0], + ) + original_users = [ + user for user in bmm_node.users if user != squeeze_after + ] + for user in original_users: + user.replace_input_with(bmm_node, squeeze_after) + + modified_graph = True + + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/normalize_while_initial_args_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/normalize_while_initial_args_pass.py new file mode 100644 index 0000000..00ccf78 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/normalize_while_initial_args_pass.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +from typing import cast, Sequence, Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass +from torch.fx import GraphModule, Node +from torch.fx.passes.infra.pass_base import PassResult + + +class NormalizeWhileInitialArgsPass(ArmPass): + """ + Normalize ``torch.ops.higher_order.while_loop`` by moving additional_args to carried_args, + making the number of outputs equal to the number of inputs which is required by the TOSA specification. + Example: + def cond(val): + return val.sum() < 10 + + def body(val): + return (val * 2,) + while_loop(cond, body, (val,), additional_args= (buffer,)) + becomes: + def cond(val, buffer): + return val.sum() < 10 + + def body(val, buffer): + return (val * 2, buffer.clone()) + while_loop(cond, body, (val, buffer), ()) + + The clone is neccessary to avoid issues with aliasing. + """ + + def __init__(self, use_exir_clone: bool, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + if use_exir_clone: + self.clone_op = exir_ops.edge.aten.alias_copy.default + else: + self.clone_op = torch.ops.aten.clone.default + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _connect_to_output( + self, body_module: GraphModule, placeholders: Sequence[Node] + ) -> list[Node]: + if not placeholders: + return [] + + cloned_placeholders = [] + with body_module.graph.inserting_after(placeholders[-1]): + for placeholder in placeholders: + clone = body_module.graph.create_node( + "call_function", + self.clone_op, + (placeholder,), + ) + cloned_placeholders.append(clone) + clone.meta = placeholder.meta + output_node = body_module.graph.output_node() + output_values = output_node.args[0] + if not isinstance(output_values, tuple): + raise RuntimeError("Output of a while should be a tuple.") + + output_node.update_arg(0, output_values + tuple(cloned_placeholders)) + body_module.recompile() + return list(cloned_placeholders) + + def _normalize_node(self, graph_module: GraphModule, node: Node) -> bool: + additional_inputs = list(cast(Sequence[Node], node.args[3])) + + if not additional_inputs: + return False + + carried_inputs = list(cast(Sequence[Node], node.args[2])) + new_carried = tuple(carried_inputs + additional_inputs) + node.update_arg(2, new_carried) + node.update_arg(3, ()) + + body_module_name = str(cast(Node, node.args[1]).target) + body_module = cast(GraphModule, graph_module.get_submodule(body_module_name)) # type: ignore + placeholders = [n for n in body_module.graph.nodes if n.op == "placeholder"] + num_inputs = len(placeholders) + old_num_inputs = len(carried_inputs) + if num_inputs != len(new_carried): + raise RuntimeError( + f"Length of loop placeholders {placeholders} is not equal length of carried inputs {new_carried}" + ) + + missing_placeholders = placeholders[old_num_inputs:] + self._connect_to_output(body_module, missing_placeholders) + + return True + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target != torch.ops.higher_order.while_loop: + continue + modified |= self._normalize_node(graph_module, node) + + if modified: + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/promote_bool_operands_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/promote_bool_operands_pass.py new file mode 100644 index 0000000..8c45a80 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/promote_bool_operands_pass.py @@ -0,0 +1,88 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# The TOSA BITWISE_AND, BITWISE_OR, and BITWISE_XOR don't handle bool inputs. +# When a targeted op receives boolean tensors, we promote them to an integer type before +# invocation and cast the result back to the expected dtype afterwards. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class PromoteBoolOperandsPass(ArmPass): + """Promote boolean operands to the appropriate integer dtype for unsupported ops.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = { + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.mul.Tensor, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in self.targeted_ops: + return super().call_operator(op, args, kwargs, meta) + + original_dtypes = [arg.data.dtype for arg in args] + if torch.bool not in original_dtypes: + return super().call_operator(op, args, kwargs, meta) + + # select the first non-bool dtype, or None if all bool + promoted_dtype = next((dt for dt in original_dtypes if dt != torch.bool), None) + + # if we don't have a dtype specified by the op, promote to default choice for the op + if promoted_dtype is None: + if op == exir_ops.edge.aten.mul.Tensor: + # mul as int32 + promoted_dtype = torch.int32 + else: + # bitwise ops can be int8 + promoted_dtype = torch.int8 + + target_dtypes = [] + for dt in original_dtypes: + if dt == torch.bool: + target_dtypes.append(promoted_dtype) + else: + target_dtypes.append(dt) + + new_args = [] + for arg, original_dtype, target_dtype in zip( + args, original_dtypes, target_dtypes + ): + if original_dtype == target_dtype: + new_args.append(arg) + else: + new_args.append( + super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (arg,), + {"dtype": target_dtype}, + meta, + ) + ) + + output = super().call_operator( + op, + tuple(new_args), + kwargs, + meta, + ) + + if all(dtype == torch.bool for dtype in original_dtypes): + output = super().call_operator( + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + (output,), + {"dtype": torch.bool}, + meta, + ) + return output diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/quant_args.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/quant_args.py new file mode 100644 index 0000000..974d6df --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/quant_args.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, cast, NamedTuple + +import torch +from executorch.exir.dialects._ops import ops as exir_ops + +exir_ops = cast(Any, exir_ops) +from executorch.backends.arm.constants import PER_CHANNEL_QDQ_OPS, PER_TENSOR_QDQ_OPS +from torch import Tensor + + +class QuantArgs(NamedTuple): + scale: list[float] | float + zp: list[int] | int + qmin: int + qmax: int + dtype: torch.dtype + axis: int = 0 + per_channel: bool = False + + def quantize_value(self, x: torch.Tensor | float) -> Tensor: + """Quantizes the input tensor or value to a quantized tensor. If the input is + not a tensor, it is converted to a tensor first. If self.per_channel is True, + the quantization is done per channel, otherwise it is done per tensor. + """ + if not isinstance(x, torch.Tensor): + x = torch.Tensor([x]) + x = x.to(torch.float32) + if self.per_channel: + q_op = exir_ops.edge.quantized_decomposed.quantize_per_channel.default + args = ( + x, + torch.tensor(self.scale), + torch.tensor(self.zp), + self.axis, + self.qmin, + self.qmax, + self.dtype, + ) + else: + q_op = exir_ops.edge.quantized_decomposed.quantize_per_tensor.default + args = (x, self.scale, self.zp, self.qmin, self.qmax, self.dtype) # type: ignore[assignment] + return q_op(*args) + + def dequantize_value(self, qx: torch.Tensor) -> torch.Tensor: + """Dequantizes the input tensor or value to a dequantized tensor If the input + is not a tensor, it is converted to a tensor first. If self.per_channel is True, + the dequantization is done per channel, otherwise it is done per tensor. + """ + if self.per_channel: + dq_op = exir_ops.edge.quantized_decomposed.dequantize_per_channel.default + args = ( + qx, + torch.tensor(self.scale), + torch.tensor(self.zp), + self.axis, + self.qmin, + self.qmax, + self.dtype, + ) + else: + dq_op = exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default + args = (qx, self.scale, self.zp, self.qmin, self.qmax, self.dtype) # type: ignore[assignment] + return dq_op(*args) + + @classmethod + def from_operator(cls, op, args): + if op in PER_TENSOR_QDQ_OPS: + return cls( + scale=cast(float, args[1]), + zp=cast(int, args[2]), + qmin=cast(int, args[3]), + qmax=cast(int, args[4]), + dtype=cast(torch.dtype, args[5]), + axis=0, + per_channel=False, + ) + elif op in PER_CHANNEL_QDQ_OPS: + return cls( + scale=cast(list[float], args[1].tolist()), + zp=cast(list[int], args[2].tolist()), + axis=cast(int, args[3]), + qmin=cast(int, args[4]), + qmax=cast(int, args[5]), + dtype=cast(torch.dtype, args[6]), + per_channel=True, + ) + else: + # We're only handling per tensor and per channel quantization + raise NotImplementedError(f"Unsupported quantization operation: {op}") + + def get_scale_per_tensor(self) -> float: + if not isinstance(self.scale, float): + raise TypeError( + f"Expected scale {self.scale} to be a float but found scale of " + f"type {type(self.scale)}" + ) + return self.scale + + def get_zp_per_tensor(self) -> int: + if not isinstance(self.zp, int): + raise TypeError( + f"Expected zero point {self.zp} to be an int but found zp of " + f"type {type(self.zp)}" + ) + return self.zp + + def get_scale_per_channel(self) -> list[float]: + if not isinstance(self.scale, list): + raise TypeError( + f"Expected scale {self.scale} to be a list but found scale of " + f"type {type(self.scale)}" + ) + return self.scale + + def get_zp_per_channel(self) -> list[int]: + if not isinstance(self.zp, list): + raise TypeError( + f"Expected zero point {self.zp} to be a list but found zp of " + f"type {type(self.zp)}" + ) + return self.zp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_getitem_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_getitem_pass.py new file mode 100644 index 0000000..3ce157d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_getitem_pass.py @@ -0,0 +1,14 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.transforms import remove_getitem_op +from executorch.exir.pass_base import ExportPass + + +class RemoveGetItemPass(ArmPass, remove_getitem_op.RemoveGetItemPass): + _passes_required_after: Set[Type[ExportPass]] = set() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_graph_asserts_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_graph_asserts_pass.py new file mode 100644 index 0000000..a462c11 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_graph_asserts_pass.py @@ -0,0 +1,18 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +from executorch.backends.arm._passes.arm_pass import ArmPass + +from executorch.backends.arm._passes.convert_int64_const_ops_to_int32 import ( + ConvertInt64ConstOpsToInt32Pass, +) +from executorch.exir.pass_base import ExportPass +from executorch.exir.passes import remove_graph_asserts_pass + + +class RemoveGraphAssertsPass(remove_graph_asserts_pass.RemoveGraphAssertsPass, ArmPass): + _passes_required_after: Set[Type[ExportPass]] = {ConvertInt64ConstOpsToInt32Pass} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_noop_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_noop_pass.py new file mode 100644 index 0000000..8ac8088 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/remove_noop_pass.py @@ -0,0 +1,40 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +from executorch.backends.arm._passes import ArmPass + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +logger = logging.getLogger(__name__) + + +class RemoveNoopPass(ArmPass): + """Remove no-ops from graph_module""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call_operator(self, op, args, kwargs, meta): + if op not in ( + exir_ops.edge.dim_order_ops._clone_dim_order.default, + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + exir_ops.edge.aten.copy.default, + ): + return super().call_operator(op, args, kwargs, meta) + + input_dtype = args[0].data.dtype + output_dtype = kwargs.get("dtype", input_dtype) + + if input_dtype != output_dtype: + return super().call_operator(op, args, kwargs, meta) + + if op == exir_ops.edge.aten.copy.default: + return args[1] + return args[0] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_inf_and_limit_values_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_inf_and_limit_values_pass.py new file mode 100644 index 0000000..0f1fad5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_inf_and_limit_values_pass.py @@ -0,0 +1,73 @@ +# Copyright (c) Qualcomm Innovation Center, Inc. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This pass is based on backends/qualcomm/_passes/replace_inf_values.py +# with some modification to replaced inf values. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.exir.pass_base import ExportPass, NodeMetadata, PassResult + + +class ReplaceInfAndLimitValuesPass(ArmPass): + """ + Rewrites +inf/-inf and floating-point limit values (e.g., torch.finfo(...).min/max) + to quantization-friendly values (±255 by default), improving quantizer stability + (notably for attention mask paths). + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _allowed_to_transform_named_buffer(self, buf_name, graph_module) -> bool: + attr_nodes = [ + node + for node in graph_module.graph.nodes + if node.op == "get_attr" and node.target == buf_name + ] + + can_transform_buffer = True + for attr_node in attr_nodes: + for user in list(attr_node.users): + if user.op != "call_function": + continue + if not self.allowed_to_transform(NodeMetadata(user.meta)): + can_transform_buffer = False + break + if not can_transform_buffer: + break + + return can_transform_buffer + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + for buf_name, tensor in graph_module.named_buffers(): + if not tensor.is_floating_point(): + continue + if not self._allowed_to_transform_named_buffer(buf_name, graph_module): + continue + + modified = True + # 255 here is mainly for attention_mask in Llama for reasonable quant scale + tensor[tensor == float("inf")] = 255 + tensor[tensor == float("-inf")] = -255 + setattr(graph_module, buf_name, tensor) + + for node in graph_module.graph.nodes: + arg_list = list(node.args) + for index, arg in enumerate(arg_list): + if arg == float("-inf") or arg == torch.finfo(torch.float32).min: + modified = True + arg_list[index] = -255.0 + elif arg == float("inf") or arg == torch.finfo(torch.float32).max: + modified = True + arg_list[index] = +255.0 + node.args = tuple(arg_list) + + if modified: + graph_module.recompile() + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_scalar_with_tensor_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_scalar_with_tensor_pass.py new file mode 100644 index 0000000..df48434 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/replace_scalar_with_tensor_pass.py @@ -0,0 +1,121 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Set, Type, Union + +import torch +from executorch.backends.arm._passes.insert_table_ops import TableOps + +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.backends.transforms.replace_scalar_with_tensor import ( + ReplaceScalarWithTensorArgPass, +) +from executorch.exir.dialects._ops import ops as exir_ops + +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass + +from .arm_pass import ArmPass + + +# Operators that are included for both TOSA profiles +_common_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = { + exir_ops.edge.aten.add.Scalar: exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.sub.Scalar: exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.mul.Scalar: exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.div.Scalar: exir_ops.edge.aten.div.Tensor, + 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.ge.Scalar: exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.lt.Scalar: exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.le.Scalar: exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.ne.Scalar: exir_ops.edge.aten.ne.Tensor, + exir_ops.edge.aten.bitwise_and.Scalar: exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Scalar: exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Scalar: exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.remainder.Scalar: exir_ops.edge.aten.remainder.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, + torch.ops.aten.div.Scalar: torch.ops.aten.div.Tensor, + 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.ge.Scalar: torch.ops.aten.ge.Tensor, + torch.ops.aten.lt.Scalar: torch.ops.aten.lt.Tensor, + torch.ops.aten.le.Scalar: torch.ops.aten.le.Tensor, + torch.ops.aten.ne.Scalar: torch.ops.aten.ne.Tensor, + torch.ops.aten.bitwise_and.Scalar: torch.ops.aten.bitwise_and.Tensor, + torch.ops.aten.bitwise_or.Scalar: torch.ops.aten.bitwise_or.Tensor, + torch.ops.aten.bitwise_xor.Scalar: torch.ops.aten.bitwise_xor.Tensor, + torch.ops.aten.remainder.Scalar: torch.ops.aten.remainder.Tensor, +} + +_fp_profile_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = _common_ops | { + exir_ops.edge.aten.pow.Tensor_Scalar: exir_ops.edge.aten.pow.Tensor_Tensor, +} + +_int_profile_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = _common_ops + +_all_ops: Dict[ + Union[EdgeOpOverload, torch._ops.OpOverload], + Union[EdgeOpOverload, torch._ops.OpOverload], +] = ( + _fp_profile_ops | _int_profile_ops +) + + +class ReplaceScalarWithTensorByProfilePass(ArmPass, ReplaceScalarWithTensorArgPass): + """Profile-aware scalar-to-tensor replacement pass for binary ops.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, tfa_pass=False, *args, **kwargs): + # NOTE diamond heritance for this class, thus MRO is important. + + # Initialize base (ReplaceScalarWithTensorArgPass) with the full + # superset which will make the superclass handle ops in _all_ops. + # Actual selection is done per-call in call_operator. + super().__init__(tfa_pass, _all_ops, *args, **kwargs) + + def call_operator(self, op, args, kwargs, meta): + tosa_spec = get_context_spec() + + included_ops = {} + if tosa_spec.support_integer(): + included_ops |= _int_profile_ops + if tosa_spec.support_float(): + included_ops |= _fp_profile_ops + + if included_ops == {}: + raise ValueError("Profile must support at least INT or FP") + + if op in TableOps.included_ops(): + # Do not handle quantized table ops; forward unchanged. + input_qparams = meta.data.get("input_qparams", {}) + output_qparams = meta.data.get("input_qparams", {}) + if len(input_qparams) > 0 and len(output_qparams) > 0: + # Do not handle; forward unchanged. + return ExportPass.call_operator(self, op, args, kwargs, meta) + + if op in included_ops: + # Include this op based on the current profile. + return super().call_operator(op, args, kwargs, meta) + else: + # Do not handle; forward unchanged. + return ExportPass.call_operator(self, op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py new file mode 100644 index 0000000..734583c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_bitwise_not_to_logical_not_pass.py @@ -0,0 +1,43 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + + +class RewriteBoolBitwiseNotToLogicalNotPass(ArmPass): + """ + Rewrites ``aten.bitwise_not`` on boolean tensors to ``aten.logical_not``. + + TOSA ``bitwise_not`` does not support boolean inputs. On boolean tensors, + ``bitwise_not`` is equivalent to ``logical_not``, so this rewrite preserves + semantics while enabling lowering. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + _TARGET_OPS = { + exir_ops.edge.aten.bitwise_not.default, + } + + def call_operator(self, op, args, kwargs, meta): + if op not in self._TARGET_OPS: + return super().call_operator(op, args, kwargs, meta) + + if meta["val"].dtype == torch.bool: + x = args[0] + return super().call_operator( + exir_ops.edge.aten.logical_not.default, + (x,), + {}, + meta, + ) + + return super().call_operator(op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py new file mode 100644 index 0000000..4f8eeb8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_bool_to_fp32_cast_via_int8_pass.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, + set_node_arg, +) +from executorch.backends.arm.tosa.specification import get_context_spec +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class RewriteBoolToFp32CastViaInt8Pass(ArmPass): + """ + Legalizes unsupported bool->fp32 to_dim_order_copy casts for the Arm TOSA + backend when both integer and float TOSA profiles are enabled. + + For the combined INT+FP profile, this pass rewrites a single bool->fp32 cast + into a bool->int8 cast followed by an int8->fp32 cast, so that each cast + is individually supported by the TOSA INT and FP profiles. For other + profiles (INT-only or FP-only) the pass is a no-op. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + targeted_ops = {exir_ops.edge.dim_order_ops._to_dim_order_copy.default} + + def call(self, graph_module: torch.fx.GraphModule): + modified = False + + tosa_spec = get_context_spec() + if not (tosa_spec.support_integer() and tosa_spec.support_float()): + return PassResult(graph_module, modified) + + graph = graph_module.graph + for node in graph.nodes: + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + + input_node = node.all_input_nodes[0] + input_dtype = get_first_fake_tensor(input_node).dtype + if input_dtype != torch.bool: + continue + + output_dtype = get_first_fake_tensor(node).dtype + if output_dtype != torch.float32: + continue + + set_node_arg(node, "dtype", torch.int8) + + users = list(node.users) + with graph.inserting_after(node): + cast_after = create_node( + graph, + node.target, + args=(node,), + kwargs={ + "dtype": torch.float32, + }, + ) + for user in users: + user.replace_input_with(node, cast_after) + modified = True + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_conv_pass.py new file mode 100644 index 0000000..b20aa22 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_conv_pass.py @@ -0,0 +1,336 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import itertools +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass + +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + expand_around_channel, + get_first_fake_tensor, + get_param_tensor, + is_buffer, + is_param, +) +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.constants import HWCM_ORDER, NHWC_INVERSE_ORDER +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.transforms.utils import create_constant_placeholder +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult +from torch.export.graph_signature import InputKind + + +class RewriteConvPass(ArmPass): + """Rewrites aten.convolution to tosa.CONV2D or tosa.DEPTHWISE_CONV2D.""" + + def __init__(self, exported_program: torch.export.ExportedProgram, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + _passes_required_after: Set[Type[ExportPass]] = set() + + # torch.nn.Conv2d does not require the result of + # `(input + 2 * pad - dilation * (weight - 1) - 1) / stride` + # to be an integer, but tosa currently strictly require this property. + # This function adjusts the pad value to meet the requirement. + def _adjust_pad_if_needed( + self, input_len: int, input_weight: int, stride: int, pad: int, dilation: int + ) -> int: + """Adjust padding to satisfy TOSA's integer output-size requirement. + + Torch ``Conv2d`` does not require the result of + ``(input + 2 * pad - dilation * (weight - 1) - 1) / stride`` to be an + integer, but TOSA does. This helper reduces the provided padding so + that the expression becomes divisible by ``stride``. + + Args: + input_size (int): Spatial input size along the dimension (H or W). + input_weight (int): Kernel size along the same dimension. + stride (int): Stride along the same dimension. + pad (int): Padding value to adjust (bottom or right after duplication). + dilation (int): Dilation along the same dimension. + + Returns: + int: Adjusted padding value that yields an integer output size. + + Raises: + RuntimeError: If the required adjustment exceeds the provided + padding, which should be handled by the ``SizeAdjustInputPass`` + pass instead. + + """ + mod_remainder = ( + input_len + 2 * pad - dilation * (input_weight - 1) - 1 + ) % stride + + # No need to adjust + if mod_remainder == 0: + return pad + + if mod_remainder > pad: + raise RuntimeError( + "This case should be handled by the SizeAdjustInputPass, is it enabled?" + ) + return pad - mod_remainder + + def _is_depthwise_conv2d(self, node: torch.fx.Node) -> bool: + if ( + node.op != "call_function" + or node.target != exir_ops.edge.aten.convolution.default + ): + return False + input_tensor = get_first_fake_tensor(node.all_input_nodes[0]) + if len(input_tensor.shape) != 4: + return False + groups = node.args[-1] + in_channels = input_tensor.shape[1] + out_channels = get_first_fake_tensor(node).shape[1] + return (in_channels == groups) and (out_channels % in_channels) == 0 + + def _is_conv3d(self, rank, groups) -> bool: + if rank == 5: + # A Conv3D is considered depthwise if Group == InChannels and + # Group * N == OutChannels, where N is a possitive integer. + # Currently we do not support depthwise or grouped conv3d. + # @TODO Add grouped/depthwise conv3d support or reject in partitioner. + if groups != 1: + raise RuntimeError( + "CONV3D with groups != 1 is not supported in the Arm backend." + ) + return True + return False + + def _reshape_weights(self, weight_node: torch.fx.Node, in_channels: int) -> None: + """Reshape the weights for depthwise convolution such that when serialized to TOSA, + the weights are in the format [H, W, in_channels, m_length] where + m_length is the number of output channels per input channel. + """ + weight_tensor = get_param_tensor(self.exported_program, weight_node) # type: ignore[arg-type] + if weight_tensor is None: + raise RuntimeError( + f"Weight node {weight_node.name} is not a parameter or buffer" + ) + + reshaped_weight_tensor = ( + weight_tensor.permute(HWCM_ORDER) + .reshape( + weight_tensor.shape[2], + weight_tensor.shape[3], + in_channels, + weight_tensor.shape[0] // in_channels, + ) + .permute(NHWC_INVERSE_ORDER) + ) + + if is_buffer(self.exported_program, weight_node): + param_name = self.exported_program.graph_signature.inputs_to_buffers[ + weight_node.name + ] + reshaped_weight_tensor = torch.nn.Buffer(reshaped_weight_tensor) + elif is_param(self.exported_program, weight_node): + param_name = self.exported_program.graph_signature.inputs_to_parameters[ + weight_node.name + ] + reshaped_weight_tensor = torch.nn.Parameter( + reshaped_weight_tensor, requires_grad=False + ) + else: + raise RuntimeError( + f"Weight node {weight_node.name} is neither a parameter nor a buffer" + ) + + self.exported_program.state_dict[param_name] = reshaped_weight_tensor + weight_node.meta["val"] = weight_node.meta["val"].reshape( + weight_tensor.shape[2], + weight_tensor.shape[0] // in_channels, + weight_tensor.shape[3], + in_channels, + ) + + def _add_bias( + self, + graph_module: torch.fx.GraphModule, + node: torch.fx.Node, + weight_node: torch.fx.Node, + ) -> torch.fx.Node: + output_channels = get_first_fake_tensor(node).shape[1] + # add a node containging zeros if quantized, use int32, otherwise use float32 + if "output_qparams" in node.meta and len(node.meta["output_qparams"]) > 0: + bias_data = torch.zeros(size=(output_channels,), dtype=torch.int32) + else: + bias_data = torch.zeros(size=(output_channels,), dtype=torch.float32) + + with graph_module.graph.inserting_after(weight_node): + bias_node = create_constant_placeholder( + self.exported_program, + graph=graph_module.graph, + kind=InputKind.PARAMETER, + data=bias_data, + persistent_buffer=True, + name=f"{node.name}_bias", + ) + if node.all_input_nodes[0].meta["val"].dtype == torch.int16: + bias_node.meta[TosaSpecialDtype.meta_key()] = TosaSpecialDtype.INT48 + node.update_arg(2, bias_node) + return bias_node + + def insert_output_rescale(self, graph_module, node): + input_qparams = get_input_qparams(node) + output_qparams = get_output_qparams(node)[0] + weight_qparams = input_qparams[1] + input_qparams = input_qparams[0] + is_per_channel = weight_qparams.per_channel + if is_per_channel: + weight_scale = weight_qparams.get_scale_per_channel() + else: + weight_scale = [weight_qparams.get_scale_per_tensor()] + input_scale = input_qparams.get_scale_per_tensor() + post_conv2d_scale = [ + (inp * w) / out + for inp, w, out in zip( + itertools.cycle([input_scale]), + weight_scale, + itertools.cycle([output_qparams.get_scale_per_tensor()]), + ) + ] + with graph_module.graph.inserting_after(node): + rescale_node = create_node( + graph=graph_module.graph, + op_target=exir_ops.backend.tosa.RESCALE.default, + args=( + node, + output_qparams.dtype, + post_conv2d_scale, + 0, + output_qparams.get_zp_per_tensor(), + ), + from_node=node, + ) + return rescale_node + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901 + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target != exir_ops.edge.aten.convolution.default + ): + continue + + modified = True + + ( + x, + weight, + bias, + stride, + pad, + dilation, + _, + _, + group, + ) = node.args + + input_fake_tensor = get_first_fake_tensor(x) + weight_fake_tensor = get_first_fake_tensor(weight) + input_shape = input_fake_tensor.shape + weight_shape = weight_fake_tensor.shape + spatial_rank = len(input_shape) - 2 + stride_list = expand_around_channel(stride, spatial_rank) + dilation_list = expand_around_channel(dilation, spatial_rank) + pad_list = expand_around_channel(pad, spatial_rank) + + pad_attr: list[int] = [] + for value in pad_list: + pad_attr.extend([value, value]) # duplicate pad before/after per axis + + for axis_index in range(spatial_rank): + pad_index = axis_index * 2 + 1 # adjust trailing pad entry + pad_attr[pad_index] = self._adjust_pad_if_needed( + input_shape[axis_index + 2], + weight_shape[axis_index + 2], + stride_list[axis_index], + pad_attr[pad_index], + dilation_list[axis_index], + ) + + stride = tuple(stride_list) + dilation = tuple(dilation_list) + pad = pad_attr + + has_bias = bias is not None + if not has_bias: + bias = self._add_bias(graph_module, node, weight) + + if self._is_conv3d(len(input_shape), group): + target_op = exir_ops.backend.tosa.CONV3D.default + elif self._is_depthwise_conv2d(node): + target_op = exir_ops.backend.tosa.DEPTHWISE_CONV2D.default + # If there are any TOSA.DEPTHWISE_CONV2D nodes using the weights, we've already reshaped them. + if all(user.target != target_op for user in weight.users): + self._reshape_weights(weight, input_fake_tensor.shape[1]) + weight_fake_tensor = get_first_fake_tensor(weight) + else: + target_op = exir_ops.backend.tosa.CONV2D.default + + conv_args = ( + x, + weight, + bias, + stride, + pad, + dilation, + ) + + with graph_module.graph.inserting_after(node): + tosa_op = create_node( + graph=graph_module.graph, + op_target=target_op, + args=conv_args, + from_node=node, + inherit_qparams=True, + ) + bias_fake_tensor = get_first_fake_tensor(bias) if bias else None + tosa_node_fake_tensor = target_op( + input_fake_tensor, + weight_fake_tensor, + bias_fake_tensor, + *conv_args[3:], + ) + + if ( + tosa_node_fake_tensor.dtype == torch.int32 + and input_fake_tensor.dtype == torch.int8 + ): + output_rescale = self.insert_output_rescale(graph_module, tosa_op) + node.replace_all_uses_with(output_rescale) + elif ( + tosa_node_fake_tensor.dtype == torch.int32 + and input_fake_tensor.dtype == torch.int16 + ): + has_bias = len(node.meta["input_qparams"]) > 2 + if not has_bias: + output_rescale = self.insert_output_rescale(graph_module, tosa_op) + node.replace_all_uses_with(output_rescale) + else: + node.replace_all_uses_with(tosa_op) + tosa_op.meta[TosaSpecialDtype.meta_key()] = TosaSpecialDtype.INT48 + else: + node.replace_all_uses_with(tosa_op) + + graph_module.graph.erase_node(node) + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_matmul.py new file mode 100644 index 0000000..298cfd1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_matmul.py @@ -0,0 +1,98 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class RewriteMatmulPass(ArmPass): + """Rewrites aten.bmm to tosa.MATMUL and inserts a tosa.RESCALE op if needed.""" + + _passes_required_after: Set[Type[ExportPass]] = set() + + def _insert_output_rescale(self, graph_module, node, tosa_matmul_node, dtype): + input_qparams = get_input_qparams(node) + output_qparams = get_output_qparams(node)[0] + scale = ( + input_qparams[0].get_scale_per_tensor() + * input_qparams[1].get_scale_per_tensor() + ) / output_qparams.get_scale_per_tensor() + + with graph_module.graph.inserting_after(tosa_matmul_node): + # If the input is int8, we need to cast the output to int32 + rescale_node = create_node( + graph_module.graph, + op_target=exir_ops.backend.tosa.RESCALE.default, + from_node=tosa_matmul_node, + ) + tosa_matmul_node.replace_all_uses_with(rescale_node) + rescale_node.args = ( + tosa_matmul_node, + dtype, + [scale], + 0, + output_qparams.get_zp_per_tensor(), + ) + + def call(self, graph_module): + modified = False + for node in graph_module.graph.nodes: + if ( + node.op != "call_function" + or node.target != exir_ops.edge.aten.bmm.default + ): + continue + modified = True + + x1, x2 = node.args + tosa_matmul_target = exir_ops.backend.tosa.MATMUL.default + with graph_module.graph.inserting_before(node): + tosa_matmul_node = create_node( + graph_module.graph, + op_target=tosa_matmul_target, + args=(x1, x2), + kwargs={}, + from_node=node, + inherit_qparams=True, + ) + node.replace_all_uses_with(tosa_matmul_node) + graph_module.graph.erase_node(node) + + x1_fake_tensor = get_first_fake_tensor(x1) + x2_fake_tensor = get_first_fake_tensor(x2) + output_fake_tensor = tosa_matmul_target(x1_fake_tensor, x2_fake_tensor) + node_output_fake_tensor = get_first_fake_tensor(node) + if ( + output_fake_tensor.dtype == torch.int32 + and node_output_fake_tensor.dtype in (torch.int8, torch.int16) + ): + self._insert_output_rescale( + graph_module, + node, + tosa_matmul_node, + dtype=node_output_fake_tensor.dtype, + ) + if x1_fake_tensor.dtype == torch.int16: + tosa_matmul_node.meta[TosaSpecialDtype.meta_key()] = ( + TosaSpecialDtype.INT48 + ) + + if modified: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_upsample.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_upsample.py new file mode 100644 index 0000000..cff241d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/rewrite_upsample.py @@ -0,0 +1,93 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.backends.arm.tosa.mapping import TosaSpecialDtype +from executorch.backends.arm.tosa.utils import get_resize_parameters +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class RewriteUpsamplePass(ArmPass): + """Rewrite upsample2d nodes to TOSA.RESIZE nodes.""" + + targeted_ops = ( + exir_ops.edge.aten.upsample_nearest2d.vec, + exir_ops.edge.aten.upsample_bilinear2d.vec, + ) + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module): + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function" or node.target not in self.targeted_ops: + continue + modified = True + + if node.target == exir_ops.edge.aten.upsample_bilinear2d.vec: + x, output_size, align_corners, scale_factors = node.args + resize_mode = "bilinear" + else: + x, output_size, scale_factors = node.args + align_corners = False + resize_mode = "nearest" + + with graph_module.graph.inserting_before(node): + tosa_resize_node = create_node( + graph_module.graph, + op_target=exir_ops.backend.tosa.RESIZE.default, + args=(x, output_size, align_corners, scale_factors), + kwargs={"resize_mode": resize_mode}, + from_node=node, + inherit_qparams=True, + ) + node.replace_all_uses_with(tosa_resize_node) + graph_module.graph.erase_node(node) + input_dtype = get_first_fake_tensor(x).dtype + if ( + input_dtype == torch.int8 or input_dtype == torch.int16 + ) and resize_mode == "bilinear": + input_size = get_first_fake_tensor(x).shape + input_size_xy = input_size[2:] + output_size = get_first_fake_tensor(node).shape + output_size_xy = output_size[2:] + scale_n_yx, _, _, _ = get_resize_parameters( + input_size_xy=input_size_xy, + output_size_xy=output_size_xy, + resize_mode=1, + align_corners=align_corners, + ) + output_dtype = get_first_fake_tensor(node).dtype + output_scale = float(1 / (scale_n_yx[0] * scale_n_yx[1])) + with graph_module.graph.inserting_after(tosa_resize_node): + rescale_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.RESCALE.default, + ) + tosa_resize_node.replace_all_uses_with(rescale_node) + if input_dtype == torch.int16: + tosa_resize_node.meta[TosaSpecialDtype.meta_key()] = ( + TosaSpecialDtype.INT48 + ) + + rescale_node.args = ( + tosa_resize_node, + output_dtype, + [output_scale], + 0, # zero point + 0, # zero point + ) + + if modified: + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/scalars_to_attribute_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/scalars_to_attribute_pass.py new file mode 100644 index 0000000..87f5825 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/scalars_to_attribute_pass.py @@ -0,0 +1,97 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Set, Type, Union + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm._passes.match_arg_ranks_pass import MatchArgRanksPass + +from executorch.exir.pass_base import ExportPass, PassResult +from torch.fx import GraphModule, Node +from torchao.quantization.pt2e.utils import get_new_attr_name_with_prefix + + +class ScalarsToAttributePass(ArmPass): + """ + For ops in 'targeted_ops', convert inputs that are scalar values + to attribute Nodes that output the same value. + """ + + _passes_required_after: Set[Type[ExportPass]] = {MatchArgRanksPass} + + targeted_ops = [ + torch.ops.aten.add.Tensor, + torch.ops.aten.add_.Tensor, + torch.ops.aten.sub.Tensor, + torch.ops.aten.sub_.Tensor, + torch.ops.aten.rsub.Scalar, + torch.ops.aten.mul.Tensor, + torch.ops.aten.mul_.Tensor, + torch.ops.aten.div.Tensor, + torch.ops.aten.div_.Tensor, + ] + + def call(self, graph_module: GraphModule) -> PassResult: + for n in graph_module.graph.nodes: + n = cast(Node, n) + if n.op != "call_function" or n.target not in self.targeted_ops: + continue + + biggest_rank = 1 + for arg in n.args: + if isinstance(arg, Node): + shape = get_first_fake_tensor(arg).shape + biggest_rank = max(biggest_rank, len(shape)) + + output_fake_tensor = get_first_fake_tensor(n) + new_args: list[Node | int] = [] + for arg in n.args: + if isinstance(arg, Node): + new_args.append(arg) + continue + if isinstance(arg, int) and not torch.is_floating_point( + output_fake_tensor + ): + new_args.append(arg) + continue + + prefix = "_tensor_constant_" + get_new_attr_name = get_new_attr_name_with_prefix(prefix) + tensor_constant_name = get_new_attr_name(graph_module) + float_tensor = torch.tensor( + float(cast(Union[int, float], arg)), + device=output_fake_tensor.device, + ).reshape((1,) * biggest_rank) + graph_module.register_buffer(tensor_constant_name, float_tensor) + fake_mode = n.meta["val"].fake_mode + + with graph_module.graph.inserting_before(n): + get_attr_node = graph_module.graph.create_node( + "get_attr", tensor_constant_name, (), {} + ) + get_attr_node.meta["val"] = fake_mode.from_tensor( + float_tensor, static_shapes=True + ) + new_args.append(get_attr_node) + n.args = tuple(new_args) + + # Replace rsub.Scalar with sub.Tensor as retracing will fail otherwise + if n.target == torch.ops.aten.rsub.Scalar: + with graph_module.graph.inserting_after(n): + reversed_args = (n.args[1], n.args[0]) + sub = graph_module.graph.create_node( + "call_function", torch.ops.aten.sub.Tensor, reversed_args, {} + ) + n.replace_all_uses_with(sub) + sub.meta["val"] = n.meta["val"] + graph_module.graph.erase_node(n) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/size_adjust_input_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/size_adjust_input_pass.py new file mode 100644 index 0000000..642a249 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/size_adjust_input_pass.py @@ -0,0 +1,227 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import cast, Sequence, Set, Type, TypeAlias + +import torch.fx +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + expand_around_channel, +) +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +Slices: TypeAlias = list[tuple[int, int, int]] + +conv2d_op = exir_ops.edge.aten.convolution.default +max_pooling_op = exir_ops.edge.aten.max_pool2d.default +avg_pooling_op = exir_ops.edge.aten.avg_pool2d.default +slice_op = exir_ops.edge.aten.slice_copy.Tensor + +valid_operators = [conv2d_op, max_pooling_op, avg_pooling_op] + + +def conv_remainder(input_length, pad, dilation, weight, stride) -> int: + """ + Returns the remainder of input_length; given the padding, dilation, stride, + and kernel size. + """ + return (input_length + 2 * pad - dilation * (weight - 1) - 1) % stride + + +def pooling_remainder(input_size, pad, kernel_size, stride) -> int: + """ + Returns the remainder of input_length; given the padding, stride, and + kernel size. + """ + return (input_size + 2 * pad - kernel_size) % stride + + +def get_slices_convolution(conv_node: torch.fx.Node) -> Slices: + slices = [] + + input_node, weight, _, stride_hw, pad_hw, dilation_hw, _, _, _ = conv_node.args + weight_shape = cast(torch.fx.Node, weight).meta["val"].shape + input_shape = cast(torch.fx.Node, input_node).meta["val"].shape + spatial_rank = len(input_shape) - 2 + + strides = expand_around_channel(cast(Sequence[int] | int, stride_hw), spatial_rank) + pads = expand_around_channel(cast(Sequence[int] | int, pad_hw), spatial_rank) + dilations = expand_around_channel( + cast(Sequence[int] | int, dilation_hw), spatial_rank + ) + + for axis_index, (stride, pad, dilation) in enumerate(zip(strides, pads, dilations)): + dim = axis_index + 2 + remainder = conv_remainder( + input_shape[dim], pad, dilation, weight_shape[dim], stride + ) + if remainder > pad: + adjustment = remainder - pad + args = (dim, 0, input_shape[dim] - adjustment) + slices.append(args) + + return slices + + +def get_slices_pooling(pooling_node: torch.fx.Node) -> Slices: + slices = [] + + input_node = pooling_node.args[0] + kernel_size = pooling_node.args[1] + stride = pooling_node.args[2] + padding = pooling_node.args[3] if len(pooling_node.args) >= 4 else 0 + + input_shape = cast(torch.fx.Node, input_node).meta["val"].shape + + kernel_sizes = expand_around_channel(cast(Sequence[int] | int, kernel_size), 2) + strides = expand_around_channel(cast(Sequence[int] | int, stride), 2) + pads = expand_around_channel(cast(Sequence[int] | int, padding), 2) + + for dim, (kernel_length, stride_length, pad_size) in enumerate( + zip(kernel_sizes, strides, pads), start=2 + ): + remainder = pooling_remainder( + input_shape[dim], pad_size, kernel_length, stride_length + ) + if remainder > pad_size: + adjustment = remainder - pad_size + args = (dim, 0, input_shape[dim] - adjustment) + slices.append(args) + + return slices + + +def get_slices(node: torch.fx.Node) -> Slices: + """ + Returns the remainder of input_length; given graph Node. + """ + if node.target == conv2d_op: + return get_slices_convolution(node) + elif node.target == max_pooling_op or node.target == avg_pooling_op: + return get_slices_pooling(node) + else: + raise ValueError(f"Unsupported node target, was expecting {valid_operators}") + + +def is_valid_operator(node: torch.fx.Node) -> bool: + if node.target == conv2d_op: + return True + elif node.target == max_pooling_op: + dilation = node.args[4] if len(node.args) >= 5 else 1 + ceil_mode = node.args[5] if len(node.args) >= 6 else False + + # Dilation should be handled first by DecomposeMaxPool2dPass + if isinstance(dilation, int): + if dilation > 1: + raise ValueError( + "Expected max_pool2d with dilation = 1, has DecomposeMaxPool2dPass been run?" + ) + else: + dilation = cast(list, dilation) + if dilation[0] > 1 or dilation[1] > 1: + raise ValueError( + "Expected max_pool2d with dilation = [1, 1], has DecomposeMaxPool2dPass been run?" + ) + + # If using ceil mode for rounding, the input does not need adjusting + return not ceil_mode + elif node.target == avg_pooling_op: + ceil_mode = node.args[4] if len(node.args) >= 5 else False + count_include_pad = node.args[5] if len(node.args) >= 6 else True + divisor_override = node.args[6] if len(node.args) >= 7 else None + + return not ceil_mode and not count_include_pad and divisor_override is None + + return False + + +class SizeAdjustInputPass(ArmPass): + """ + Adjusts the input size to Conv2D and Pooling operators. PyTorch allows + the input and kernel shape to not "match", in which case the remaining + rows/columns are truncated. However, matching the size is a requirement + in the TOSA specification. In case the input and kernel shape do not + match, the following is performed to meet the specification: + + 1) The padding is truncated (done in the node visitor) + 2) (if neccessary) The input is truncated (done in this pass)." + + A simple example would be a 2x2 kernel (no padding, stride=2) and a 5x5 + input: + + ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ + │ X │ X │ │ │ │ │ │ │ X │ X │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ X │ X │ │ │ │ │ │ │ X │ X │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ -> │ │ │ │ │ │ -> │ X │ X │ │ │ │ -> + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ │ │ │ │ │ │ X │ X │ │ │ │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ + First pass second pass third pass + + ┌───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┐ + │ │ │ │ │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ X │ X │ │ -> │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ X │ X │ │ │ │ │ │ │ - │ + ├───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┤ + │ │ │ │ │ │ │ - │ - │ - │ - │ - │ + └───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┘ + Fourth pass Unvisited cells + + Cells that are never visited are marked with `-` and are never considered + when the kernel traverses over the input, hence they can be removed. + + To match the shape of the kernel (and all parameters) with the input, a + slice op is inserted to remove the remaining edges (rows and columns) of the + input. + """ + + _passes_required_after: Set[Type[ExportPass]] = { + RewriteConvPass, + } + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + graph = graph_module.graph + modified_graph = False + for node in graph.nodes: + if node.op != "call_function": + continue + if not is_valid_operator(node): + continue + + target_node = cast(torch.fx.Node, node) + slice_args = get_slices(target_node) + + if len(slice_args) == 0: + continue + + parent_node = node.args[0] + with graph_module.graph.inserting_before(node): + last_node = cast(torch.fx.Node, parent_node) + for args in slice_args: + slice_node = create_node( + graph, slice_op, (last_node,) + args, from_node=node + ) + last_node = slice_node + node.replace_input_with(cast(torch.fx.Node, parent_node), last_node) + modified_graph = True + + if modified_graph: + graph_module = super().call(graph_module).graph_module + graph.eliminate_dead_code() + graph_module.recompile() + + return PassResult(graph_module, True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/to_tosa_memory_format_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/to_tosa_memory_format_pass.py new file mode 100644 index 0000000..059e271 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/to_tosa_memory_format_pass.py @@ -0,0 +1,454 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.annotate_decomposed_matmul import ( + AnnotateDecomposedMatmulPass, +) +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, + is_param_node, +) +from executorch.backends.arm.constants import NCHW_ORDER, NNCHW_ORDER, NNNCHW_ORDER +from executorch.exir import ExportedProgram +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + +logger = logging.getLogger(__name__) + + +def _is_input(node: torch.fx.Node, exported_program: ExportedProgram) -> bool: + """ + Returns True if the node is an input node, i.e. a placeholder or a parameter. + """ + return node.op == "placeholder" and not is_param_node(exported_program, node) + + +class ToTosaMemoryFormatPass(ArmPass): + """ + Annotates each node with a tosa_dim_order. tosa_dim_order can be seen as a channels-last dim-order + that in most cases will be (0, 2, 3, 1) for nodes with 4D-shapes. The pass also inserts backend.tosa.TRANSPOSE + when a transition between 3D and 4D/5D tensors happen. + The annotated tosa_dim_order is used to permute the node's shape such that it gives a TOSA-compliant shape. + This pass also makes other values aware of spatial dimensions required by future operators by back propogating info as required. + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + @staticmethod + def _channels_last_order(rank: int, spatial_rank: int) -> tuple[int, ...]: + """ + Compute the permutation of tensor dimensions corresponding to a + "channels_last"-style memory layout for an arbitrary tensor rank. + + In standard PyTorch convention: + - "channels_first" order is (N, C, H, W) + - "channels_last" order is (N, H, W, C) + This helper generalizes that concept beyond 4D tensors, producing an index + ordering that moves the channel dimension to the end while preserving the + relative order of batch and spatial dimensions. + + Args: + rank (int): Total number of tensor dimensions (e.g. 4 for NCHW). + spatial_rank (int): Number of spatial dimensions (e.g. 2 for HW, 3 for DHW). + Values outside [0, rank - 2] are clamped to that range. + + Returns: + tuple[int, ...]: A permutation of dimension indices that reorders the + tensor into "channels_last" format. For example: + - rank=4, spatial_rank=2 → (0, 2, 3, 1) # NCHW → NHWC + - rank=5, spatial_rank=3 → (0, 2, 3, 4, 1) # NCDHW → NDHWC + - rank=3, spatial_rank=1 → (0, 2, 1) + + Notes: + If `rank <= 2`, the function returns the identity order since there + are no distinct channel/spatial dimensions. + In practice only rank 4+ tensors will reach this function as the dim order should be fixed for those. + """ + if rank <= 2: + return tuple(range(rank)) + spatial_rank = max(0, min(spatial_rank, rank - 2)) + channel_axis = rank - (spatial_rank + 1) + batch_axes = list(range(channel_axis)) + spatial_axes = list(range(channel_axis + 1, rank)) + return tuple(batch_axes + spatial_axes + [channel_axis]) + + @staticmethod + def _channels_last_inverse_order(rank: int, spatial_rank: int) -> tuple[int, ...]: + """ + Return the inverse permutation of `_channels_last_order`. + + This provides the axis order needed to map a tensor from + "channels_last" layout back to its original layout. + """ + order = ToTosaMemoryFormatPass._channels_last_order(rank, spatial_rank) + inverse = [0] * rank + for idx, axis in enumerate(order): + inverse[axis] = idx + return tuple(inverse) + + def _initial_spatial_rank(self, node: torch.fx.Node) -> int: + """ + Infer the initial spatial rank based on the current rank, input node spatial + ranks and node target. A spatial dimension includes Height, Width or Depth + fields. In most operators this will only ever be Height and Width, but for 3D + operators such as conv3d this would contain 3 spatial dims. + + Spatial rank is the max of any input node spatial ranks and the number of + trailing spatial dims we need to preserve (rank - 2, capped at 3). This + decides which axes must stay channels-last when inserting transposes. + """ + tensor = get_first_fake_tensor(node).data + # Start by assuming 2D when dealing with rank4+ to account for the base case + # of an increasing amount of batch dimensions. + rank = tensor.dim() + if rank >= 4: + spatial_rank = 2 + elif rank == 3: + spatial_rank = 1 + else: + spatial_rank = 0 + + # Look for supported 3D ops and update spatial rank if relevent. + # Currently only Conv3d is supported. + if node.target == exir_ops.backend.tosa.CONV3D.default: + spatial_rank = 3 + + # Check input spatial ranks to know what the previous node spatial ranks were. + input_ranks = [ + input_node.meta.get("tosa_spatial_rank", 0) + for input_node in node.all_input_nodes + ] + if input_ranks: + spatial_rank = max([spatial_rank, *input_ranks]) + + # The max that spatial rank can be is 3. If the current rank not capable of holding + # the current spatial rank, we clamp the max to Rank - (Channels and a singular batch dimension). + # This ensures we revert back to lower spatial ranks after we are finished processing higher spatial ops. + return min(spatial_rank, max(rank - 2, 0)) + + @staticmethod + def memory_format_differs(shape, spatial_rank): + """ + Determine whether a tensor shape would be laid out differently in + channels-first ((N)NCHW) versus channels-last ((N)NHWC) memory format. + """ + if len(shape) <= 2 or spatial_rank <= 0: + return False + channel_idx = len(shape) - (spatial_rank + 1) + channel_idx = max(0, min(channel_idx, len(shape) - 1)) + spatial_dims = shape[channel_idx + 1 :] + if not spatial_dims: + return False + channel_dim = shape[channel_idx] + return channel_dim > 1 and any(dim > 1 for dim in spatial_dims) + + @staticmethod + def is_channel_reshape( + input_shape, output_shape, input_spatial_rank, output_spatial_rank + ): + """ + Check whether a reshape touches the logical channel or consolidated + batch dimensions, which would invalidate dim-order annotations. + """ + + valid_ranks = {4, 5, 6} + + if not (len(input_shape) in valid_ranks and len(output_shape) in valid_ranks): + return False + + def channel_index(shape, spatial_rank): + if len(shape) <= 2: + return len(shape) - 1 + idx = len(shape) - (spatial_rank + 1) + return max(0, min(idx, len(shape) - 1)) + + C_old = input_shape[channel_index(input_shape, input_spatial_rank)] + C_new = output_shape[channel_index(output_shape, output_spatial_rank)] + + def get_batch_prod_dim(shape, spatial_rank): + product = 1 + + for dim in shape[: channel_index(shape, spatial_rank)]: + product = product * dim + + return product + + N_old = get_batch_prod_dim(input_shape, input_spatial_rank) + N_new = get_batch_prod_dim(output_shape, output_spatial_rank) + + return (N_old != N_new) or (C_old != C_new) + + @staticmethod + def insert_input_transpose(node, input_node, graph_module): + """ + Ensure an input tensor is converted to channels-last ordering by + inserting (or folding) a backend `TRANSPOSE` node. + """ + if input_node.target == exir_ops.backend.tosa.TRANSPOSE.default: + pre_permute_node = input_node.all_input_nodes[0] + node.replace_input_with(input_node, pre_permute_node) + return + + rank = len(get_first_fake_tensor(input_node).size()) + spatial_rank = input_node.meta["tosa_spatial_rank"] + mem_format = ToTosaMemoryFormatPass._channels_last_inverse_order( + rank, spatial_rank + ) + # Guard: mem_format must be a true permutation for the current rank + assert sorted(mem_format) == list( + range(rank) + ), f"bad perm {mem_format} for rank {rank} in insert_input_transpose" + + with graph_module.graph.inserting_before(node): + permute_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.TRANSPOSE.default, + args=( + input_node, + list(mem_format), + ), + from_node=node, + ) + node.replace_input_with(input_node, permute_node) + + permute_node.meta["tosa_dim_order"] = tuple( + range(len(input_node.meta["val"].size())) + ) + permute_node.meta["tosa_spatial_rank"] = spatial_rank + + @staticmethod + def insert_output_transpose(node, graph_module): + """ + Convert a producer's output to channels-last by appending a backend + `TRANSPOSE` node and rewiring its users. + """ + + rank = len(get_first_fake_tensor(node).size()) + spatial_rank = node.meta["tosa_spatial_rank"] + mem_format = ToTosaMemoryFormatPass._channels_last_order(rank, spatial_rank) + # Guard: mem_format must be a true permutation for the current rank + assert sorted(mem_format) == list( + range(rank) + ), f"bad perm {mem_format} for rank {rank} in insert_input_transpose" + + with graph_module.graph.inserting_after(node): + permute_node = create_node( + graph_module.graph, + exir_ops.backend.tosa.TRANSPOSE.default, + args=( + node, + list(mem_format), + ), + from_node=node, + ) + + rank = len(get_first_fake_tensor(node).size()) + permute_node.meta["tosa_dim_order"] = mem_format + + node.meta["tosa_dim_order"] = tuple( + range(len(get_first_fake_tensor(node).size())) + ) + permute_node.meta["tosa_spatial_rank"] = spatial_rank + + users = [user for user in node.users if user != permute_node] + for user in users: + user.replace_input_with(node, permute_node) + + @staticmethod + def _insert_view_transpose( + input_shape, output_shape, node, input_node, graph_module + ): + """ + Insert the necessary input/output transposes around reshapes that cross + the (N)NCHW -> (N)NHWC boundary or that touch channel dimensions. + """ + nchw_to_nhwc = len(input_shape) < 4 and len(output_shape) >= 4 + nhwc_to_nchw = len(input_shape) >= 4 and len(output_shape) < 4 + + input_sr = input_node.meta["tosa_spatial_rank"] + output_sr = node.meta["tosa_spatial_rank"] + + channel_reshape = ToTosaMemoryFormatPass.is_channel_reshape( + input_shape, + output_shape, + input_sr, + output_sr, + ) + + if ( + channel_reshape or nhwc_to_nchw + ) and ToTosaMemoryFormatPass.memory_format_differs(input_shape, input_sr): + ToTosaMemoryFormatPass.insert_input_transpose( + node, input_node, graph_module + ) + + if ( + channel_reshape or nchw_to_nhwc + ) and ToTosaMemoryFormatPass.memory_format_differs(output_shape, output_sr): + ToTosaMemoryFormatPass.insert_output_transpose(node, graph_module) + + def insert_tosa_transposes(self, graph_module: torch.fx.GraphModule): + """ + Transposes are needed for operators transforming the input to a different rank, as 4D and 5D-tensors are assumed to be in (N)NHWC-format, whereas all other are in (N)NCHW format. + This is relevant for the following cases: + - view: <4D -> >=4D + - view: >=4D -> <4D + Additionally, a 4D/5D->4D/5D view operation acting on the channel dimension currently needs to be performed in (N)NCHW format, leading to one extra input and output transpose for this case. + + Transposes can be avoided for shapes where there is no difference in actual memory, e.g for + - H == W == 1 + - C == 1 + - 1D/2D tensors + """ + for node in graph_module.graph.nodes: + # call_function and placeholder allowed due to + # index.Tensor being able to come in as both + if node.op != "call_function": + continue + + # Transpose views + elif node.target in ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.index.Tensor, + ): + # For index.Tensor: + # If we want to support 4D indexing tensors this logic + # should be updated. + input_node = node.args[0] + input_shape = input_node.meta["val"].shape + output_shape = node.meta["val"].shape + self._insert_view_transpose( + input_shape, + output_shape, + node, + input_node, + graph_module, + ) + + output_node = graph_module.graph.output_node() + + # Transpose inputs if they are in (N)NCHW format + inputs = [ + n for n in graph_module.graph.nodes if _is_input(n, self.exported_program) + ] + for input_node in inputs: + input_dim_order = get_first_fake_tensor(input_node).dim_order() + if input_dim_order in (NCHW_ORDER, NNCHW_ORDER, NNNCHW_ORDER): + self.insert_output_transpose(input_node, graph_module) + + # Transpose outputs if they are in (N)NCHW format + outputs = output_node.args[0] + if not isinstance(outputs, (list, tuple)): + raise TypeError( + f"Expected output node args to be a list or tuple, got {type(outputs)}" + ) + output_dim_orders = output_node.meta.get("original_dim_orders") + if output_dim_orders is None: + raise RuntimeError( + f"{AnnotateDecomposedMatmulPass.__name__} is required to run at the beginning of the pass pipeline when using {ToTosaMemoryFormatPass.__name__}." + ) + + for output_node_input, output_dim_order in zip( + outputs, output_dim_orders, strict=True + ): + if output_dim_order in ( + NCHW_ORDER, + NNCHW_ORDER, + NNNCHW_ORDER, + ): + self.insert_input_transpose( + output_node, output_node_input, graph_module + ) + + def remove_dim_order_kwargs( + self, graph_module: torch.fx.GraphModule, node: torch.fx.Node + ): + """ + Drop any user-specified `dim_order` keyword arguments so the pass remains + the single source of truth for dim-order annotations. + """ + if node.op != "call_function": + return + + kwargs = dict(node.kwargs) + + if "dim_order" in kwargs: + logger.warning( + f"Ignoring dim_order kwarg '{kwargs['dim_order']}' for '{node.name}'." + ) + del kwargs["dim_order"] + + node.kwargs = kwargs + + def call(self, graph_module: torch.fx.GraphModule): + """ + Entry point for the pass: annotate spatial ranks, compute dim orders, + insert bridging transposes, and forward to child passes. + """ + nodes = list(graph_module.graph.nodes) + for node in nodes: + if "val" not in node.meta: + continue + node.meta["tosa_spatial_rank"] = self._initial_spatial_rank(node) + self.remove_dim_order_kwargs(graph_module, node) + + self._propagate_spatial_ranks(nodes) + + for node in nodes: + if "val" not in node.meta: + continue + node_data = get_first_fake_tensor(node).data + spatial_rank = node.meta["tosa_spatial_rank"] + if _is_input(node, self.exported_program) or node.op == "output": + dim_order = node_data.dim_order() + else: + if node_data.dim() >= 4: + dim_order = self._channels_last_order(node_data.dim(), spatial_rank) + else: + dim_order = tuple(range(node_data.dim())) # type: ignore[assignment] + node.meta["tosa_dim_order"] = dim_order + + # Insert TOSA transposes to convert between (N)NCHW and (N)NHWC format. + # See insert_tosa_transposes for insertion conditions. + self.insert_tosa_transposes(graph_module) + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, True) + + def _propagate_spatial_ranks(self, nodes): + """ + Propagate `tosa_spatial_rank` metadata backwards so earlier nodes learn + about upcoming spatial requirements from future ops. + """ + changed = True + while changed: + changed = False + for node in reversed(nodes): + if "val" not in node.meta: + continue + tensor = get_first_fake_tensor(node) + limit = max(tensor.dim() - 2, 0) + current = node.meta.get("tosa_spatial_rank") + propagated = current + for user in node.users: + user_rank = user.meta.get("tosa_spatial_rank") + if user_rank is None: + continue + propagated = max(propagated, min(user_rank, limit)) + if propagated != current: + node.meta["tosa_spatial_rank"] = propagated + changed = True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_before_repeat_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_before_repeat_pass.py new file mode 100644 index 0000000..ed6aa82 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_before_repeat_pass.py @@ -0,0 +1,66 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Set, Type + +import torch +import torch.fx +from executorch.backends.arm._passes import ArmPass +from executorch.backends.arm._passes.arm_pass_utils import ( + create_node, + get_first_fake_tensor, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, PassResult + + +class UnsqueezeBeforeRepeatPass(ArmPass): + """ + A TOSA TILE op only supports rank(in) == rank(out). + To support Pytorch's repeat which can also add dimensions, + we add an explicit view op before which adds the new dimensions. + New dimensions are appendend at the front, see + https://pytorch.org/docs/stable/generated/torch.Tensor.expand.html + + Original: + repeat(multiples) + After pass: + view(shape = [1]*num_new_dims + old_shape) + repeat(multiples) + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def call(self, graph_module: torch.fx.GraphModule): + modified_graph = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if node.target != exir_ops.edge.aten.repeat.default: + continue + + old_shape = list(get_first_fake_tensor(node.all_input_nodes[0]).shape) + old_rank = len(old_shape) + multiples = node.args[1] + new_rank = len(multiples) + if old_rank == new_rank: + continue + + num_new_dims = new_rank - old_rank + new_shape = [1] * num_new_dims + old_shape + + with graph_module.graph.inserting_before(node): + view_node = create_node( + graph_module.graph, + exir_ops.edge.aten.view_copy.default, + (node.all_input_nodes[0], new_shape), + ) + node.replace_input_with(node.all_input_nodes[0], view_node) + modified_graph = True + + if modified_graph: + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, modified_graph) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py new file mode 100644 index 0000000..573922e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py @@ -0,0 +1,85 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Set, Type + +import torch +from executorch.backends.arm._passes import ArmPass +from executorch.exir import ExportedProgram +from executorch.exir.pass_base import ExportPass, PassResult +from torch._export.utils import is_buffer, is_param +from torch.export.graph_signature import InputKind + + +class UnsqueezeScalarPlaceholdersPass(ArmPass): + """ + Placeholders that have node.meta["val"].shape = () cause issues later in the lowering. + This pass unsqueezes the placeholders to make sure shape is at least (1,). + """ + + _passes_required_after: Set[Type[ExportPass]] = set() + + def __init__(self, exported_program: ExportedProgram, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.exported_program = exported_program + + def call(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if node.op != "placeholder": + continue + rank = node.meta["val"].dim() + if rank == 0: + if is_buffer(self.exported_program, node): + name = self.exported_program.graph_signature.inputs_to_buffers[ + node.name + ] + elif is_param(self.exported_program, node): + name = self.exported_program.graph_signature.inputs_to_parameters[ + node.name + ] + else: + continue + + tensor = self.exported_program.state_dict.get(name) + + # If we have a persistent=False buffer with no entry in state_dict + spec = next( + s + for s in self.exported_program.graph_signature.input_specs + if getattr(s.arg, "name", None) == node.name + ) + is_non_persistent_buffer = ( + spec.kind is InputKind.BUFFER and spec.persistent is False + ) + if tensor is None and is_non_persistent_buffer: + fake = node.meta["val"] + tensor = torch.ones_like(fake) + + # If we have a scalar, unsqueeze it + if tensor.dim() == 0: + tensor = tensor.unsqueeze(0) + + # update or create entry in state_dict, recreate fake + self.exported_program.state_dict[name] = tensor + node.meta["val"] = node.meta["val"].fake_mode.from_tensor( + tensor, static_shapes=True + ) + + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + return PassResult(graph_module, True) + + def ensures(self, graph_module: torch.fx.GraphModule): + for node in graph_module.graph.nodes: + if node.op == "placeholder": + rank = node.meta["val"].dim() + if rank == 0: + if not ( + is_buffer(self.exported_program, node) + or is_param(self.exported_program, node) + ): + continue + raise ValueError("Placeholders of rank 0 are not supported!") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/arm_vela.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/arm_vela.py new file mode 100644 index 0000000..1ecaca3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/arm_vela.py @@ -0,0 +1,137 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import os +import struct +import tempfile + +from typing import List + +import numpy as np + +try: + from ethosu.vela import vela # type: ignore + + has_vela = True +except ImportError: + has_vela = False + + +# Pack either input or output tensor block, compose the related arrays into +# per-io structs to simplify runtime use. +def vela_bin_pack_io(prefix, data): + vela_input_shapes = data[prefix + "_shape"] + # Vela input/output shape is fixed to 6D + vela_io_shape_dims = 6 + + ios = struct.pack(" bytes: + tosaname = "out.tosa" + tosa_path = os.path.join(dir, tosaname) + with open(tosa_path, "wb") as f: + f.write(tosa_flatbuffer) + + # invoke vela + output_dir = os.path.join(dir, "output") + args.append(f"--output-dir={output_dir}") + args.append(tosa_path) + if verbose: + args.append("--verbose-all") + vela.main(" ".join(args).split(" ")) + + if any("ethos-u85" in arg for arg in args) or any( + "debug-force-regor" in arg for arg in args + ): + np_path = os.path.join(dir, "output", "out_vela.npz") + else: + np_path = os.path.join(dir, "output", "out_sg0_vela.npz") + + blocks = b"" + with np.load(np_path, allow_pickle=False) as data: + # Construct our modified output_blocks with data in a form easily + # digested on the device side + bin_blocks = {"vela_bin_stream": b""} + + # copy command data through unmodified + bin_blocks["cmd_data"] = data["cmd_data"].tobytes() + + # copy weight data through unmodified + bin_blocks["weight_data"] = data["weight_data"].tobytes() + + # Add a block for scratch, inputs and outputs; scratch shape is a 1 element + # array giving us size in bytes so extract this and add a block of 0's. + # Currently we preallocated this on the host to provide SRAM for computation. + if not isinstance(data["scratch_shape"][0], np.int64): + raise RuntimeError("Expected scratch to be int64") + block_length = int(data["scratch_shape"][0]) + bin_blocks["scratch_size"] = struct.pack(" None: + if quantized is not None: + resolved = bool(quantized) + + elif isinstance(value, Mapping): + resolved = bool(value.get("quantized", False)) + + else: + raise TypeError( + "ArmAnnotationInfo expects a mapping with a 'quantized' entry or a keyword 'quantized'." + ) + dict.__init__(self, quantized=resolved) + object.__setattr__(self, "quantized", resolved) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/arm_compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/arm_compile_spec.py new file mode 100644 index 0000000..dda2930 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/arm_compile_spec.py @@ -0,0 +1,271 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Main implementation of AoT flow to partition and preprocess for Arm target +# backends. Converts via TOSA as an intermediate form supported by AoT and +# JIT compiler flows. +# + +import json +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from enum import Enum + +from executorch.backends.arm.common.pipeline_config import ArmPassPipelineConfig +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.exir.backend.compile_spec_schema import CompileSpec + + +@dataclass(init=False) +class ArmCompileSpec(ABC): + class DebugMode(Enum): + JSON = 1 + TOSA = 2 + + tosa_spec: TosaSpecification + compiler_flags: list[str] = field(default_factory=list) + path_for_intermediates: str | None = None + tosa_debug_mode: DebugMode | None = None + + _TOSA_SPEC_KEY = "tosa_spec" + _COMPILE_FLAGS_KEY = "compile_flags" + _OUTPUT_FORMAT_KEY = "output_format" + _DEBUG_ARTIFACT_KEY = "debug_artifact_path" + _DEBUG_MODE_KEY = "dump_debug_info" + _OUTPUT_REORDER_KEY = "ouput_reorder_workaround" + _TRANSFORM_PIPELINE_CONFIG_KEY = "transform_pipeline_config" + + def _set_compile_specs( + self, + tosa_spec: TosaSpecification, + compiler_flags: list[str], + path_for_intermediates: str | None = None, + tosa_debug_mode: DebugMode | None = None, + output_order_workaround: bool = True, + pipeline_config: ArmPassPipelineConfig | None = None, + ): + """Set all values of dataclass directly.""" + self.tosa_spec = tosa_spec + self.compiler_flags = compiler_flags + self.path_for_intermediates = path_for_intermediates + self.tosa_debug_mode = tosa_debug_mode + self.output_order_workaround = output_order_workaround + self._pipeline_config = pipeline_config + + @classmethod + def from_list(cls, compile_specs: list[CompileSpec]): # noqa: C901 + tosa_spec: TosaSpecification | None = None + output_format: str | None = None + compiler_flags: list[str] | None = None + path_for_intermediates: str | None = None + tosa_debug_mode: ArmCompileSpec.DebugMode | None = None + output_order_workaround: bool = True + pipeline_config: ArmPassPipelineConfig | None = None + unknown_specs: dict[str, str] = {} + for spec in compile_specs: + key = spec.key + val = ( + spec.value.decode() + if isinstance(spec.value, (bytes, bytearray)) + else spec.value + ) + if key == ArmCompileSpec._TOSA_SPEC_KEY: + if tosa_spec is not None: + raise ValueError("More than one tosa_spec entry in compile spec.") + tosa_spec = TosaSpecification.create_from_string(val) + elif key == ArmCompileSpec._COMPILE_FLAGS_KEY: + if compiler_flags is not None: + raise ValueError( + "More than one compiler flags entry in compile spec." + ) + compiler_flags = val.split(" ") + elif key == ArmCompileSpec._OUTPUT_FORMAT_KEY: + if output_format is not None: + raise ValueError( + "More than one output format entry in compile spec." + ) + output_format = val + elif key == ArmCompileSpec._DEBUG_ARTIFACT_KEY: + if path_for_intermediates is not None: + raise ValueError( + "More than one debug artifact path entry in compile spec." + ) + path_for_intermediates = val + elif key == ArmCompileSpec._DEBUG_MODE_KEY: + if tosa_debug_mode is not None: + raise ValueError( + "More than one tosa_debug_mode entry in compile spec." + ) + tosa_debug_mode = ArmCompileSpec.DebugMode[val] + elif key == ArmCompileSpec._OUTPUT_REORDER_KEY: + output_order_workaround = val # type: ignore[assignment] + elif key == ArmCompileSpec._TRANSFORM_PIPELINE_CONFIG_KEY: + if pipeline_config is not None: + raise ValueError( + "More than one transform pipeline entry in compile spec." + ) + pipeline_config = ArmPassPipelineConfig.from_dict(json.loads(val)) + else: + unknown_specs[key] = val + + if tosa_spec is None: + raise ValueError("No tosa_spec in compile spec.") + if output_format is None: + raise ValueError("No output_format in compile spec.") + if output_format != cls.get_output_format(): + raise ValueError( + f"Incorrect output format '{output_format}' for {cls.__name__}, expected '{cls.get_output_format()}'" + ) + if compiler_flags is None: + compiler_flags = [] + + # Create new object from class, but bypass __init__ and use _set_compile_specs instead. + compile_spec = cls.__new__(cls) + compile_spec._set_compile_specs( + tosa_spec=tosa_spec, + compiler_flags=compiler_flags, + path_for_intermediates=path_for_intermediates, + tosa_debug_mode=tosa_debug_mode, + output_order_workaround=output_order_workaround, + pipeline_config=pipeline_config, + ) + cls.from_list_hook(compile_spec, unknown_specs) + compile_spec.validate() + return compile_spec + + @classmethod + def from_list_hook(cls, compile_spec, specs: dict[str, str]): # noqa: B027 + """Allows subclasses to hook into parsing compile spec lists.""" + pass + + @abstractmethod + def validate(self): + """Throws an error if the compile spec is not valid.""" + + def to_list(self): + """Get the ArmCompileSpec in list form.""" + if not self.tosa_spec: + raise ValueError("tosa_spec must be set before calling to_list()") + + # Always supply a TOSA version + compile_spec = [ + CompileSpec(ArmCompileSpec._TOSA_SPEC_KEY, str(self.tosa_spec).encode()) + ] + + # Add compile flags, these are backend specific, refer to the backend + # documentation. + if len(self.compiler_flags) > 0: + compile_spec += [ + CompileSpec( + ArmCompileSpec._COMPILE_FLAGS_KEY, + " ".join(self.compiler_flags).encode(), + ), + ] + + # Add output format to identify kind of compile spec. + compile_spec.append( + CompileSpec( + ArmCompileSpec._OUTPUT_FORMAT_KEY, self.get_output_format().encode() + ) + ) + + if self.path_for_intermediates is not None: + compile_spec.append( + CompileSpec( + ArmCompileSpec._DEBUG_ARTIFACT_KEY, + self.path_for_intermediates.encode(), + ) + ) + + if self.tosa_debug_mode is not None: + if not self.path_for_intermediates: + raise ValueError( + "dump_debug_info() must be used in conjunction with dump_intermediate_artifacts_to()" + ) + + compile_spec.append( + CompileSpec( + ArmCompileSpec._DEBUG_MODE_KEY, self.tosa_debug_mode.name.encode() + ) + ) + + if not self.output_order_workaround: + compile_spec.append( + CompileSpec( + ArmCompileSpec._OUTPUT_REORDER_KEY, + self.output_order_workaround, + ) + ) + + if self._pipeline_config is not None and not self._pipeline_config.is_default(): + compile_spec.append( + CompileSpec( + ArmCompileSpec._TRANSFORM_PIPELINE_CONFIG_KEY, + self._pipeline_config.serialize(), + ) + ) + return compile_spec + + def get_pass_pipeline_config(self) -> ArmPassPipelineConfig: + """ + Returns configuration that controls how the Arm pass pipeline should behave. + Subclasses may override to tweak defaults for specific targets. + """ + if self._pipeline_config is None: + self._pipeline_config = self._create_default_pipeline_config() + return self._pipeline_config + + def set_pass_pipeline_config(self, config: ArmPassPipelineConfig) -> None: + self._pipeline_config = config + + def _create_default_pipeline_config(self) -> ArmPassPipelineConfig: + config = ArmPassPipelineConfig() + if self.tosa_spec.is_U55_subset: + config.disable_masked_softmax() + return config + + def get_intermediate_path(self) -> str | None: + """ + Gets the path used for dumping intermediate results such as tosa and pte. + + Returns: + Path where intermediate results are saved. + """ + return self.path_for_intermediates + + def dump_intermediate_artifacts_to(self, output_path: str | None): + """ + Sets a path for dumping intermediate results during such as tosa and pte. + + Args: + output_path: Path to dump intermediate results to. + """ + self.path_for_intermediates = output_path + return self + + def dump_debug_info(self, debug_mode: DebugMode | None): + """ + Dump debugging information into the intermediates path. + + Args: + debug_mode: The debug mode to use for dumping debug information. + """ + self.tosa_debug_mode = debug_mode + return self + + def set_output_order_workaround(self, output_order_workaround: bool): + self.output_order_workaround = output_order_workaround + return self + + def get_output_order_workaround(self) -> bool: + return self.output_order_workaround + + @classmethod + @abstractmethod + def get_output_format(cls) -> str: + """Returns a constant string that is the output format of the class.""" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/debug.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/debug.py new file mode 100644 index 0000000..e5c90fe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/debug.py @@ -0,0 +1,79 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from typing import Optional + +import torch + +import tosa_serializer as ts +from executorch.exir.print_program import inspect_node + +logger = logging.getLogger(__name__) + + +def debug_node(node: torch.fx.Node, graph_module: torch.fx.GraphModule): + # Debug output of node information + logger.info(get_node_debug_info(node, graph_module)) + + +def get_node_debug_info( + node: torch.fx.Node, graph_module: torch.fx.GraphModule | None = None +) -> str: + output = ( + f" {inspect_node(graph=graph_module.graph, node=node)}\n" + if graph_module + else "" + "-- NODE DEBUG INFO --\n" + f" Op is {node.op}\n" + f" Name is {node.name}\n" + f" Node target is {node.target}\n" + f" Node args is {node.args}\n" + f" Node kwargs is {node.kwargs}\n" + f" Node users is {node.users}\n" + " Node.meta = \n" + ) + for k, v in node.meta.items(): + if k == "stack_trace": + matches = v.split("\n") + output += " 'stack_trace =\n" + for m in matches: + output += f" {m}\n" + else: + output += f" '{k}' = {v}\n" + + if isinstance(v, list): + for i in v: + output += f" {i}\n" + return output + + +# Output TOSA flatbuffer for debugging +def debug_tosa_dump(tosa_graph: bytes, path: str, suffix: str = ""): + filename = f"output{suffix}.tosa" + + logger.info(f"Emitting debug output to: {path=}, {suffix=}") + + os.makedirs(path, exist_ok=True) + + filepath_tosa_fb = os.path.join(path, filename) + with open(filepath_tosa_fb, "wb") as f: + f.write(tosa_graph) + if not os.path.exists(filepath_tosa_fb): + raise IOError("Failed to write TOSA flatbuffer") + + +def debug_fail( + node, + graph_module, + tosa_graph: Optional[ts.TosaSerializer] = None, + path: Optional[str] = None, +): + logger.warning("Internal error due to poorly handled node:") + if tosa_graph is not None and path: + debug_tosa_dump(tosa_graph.serialize(), path) + logger.warning(f"Debug output captured in '{path}'.") + debug_node(node, graph_module) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/pipeline_config.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/pipeline_config.py new file mode 100644 index 0000000..bbceb3c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/pipeline_config.py @@ -0,0 +1,59 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import json +from dataclasses import dataclass, fields +from enum import auto, Enum +from typing import Any + + +class SoftmaxDecompositionConfig(Enum): + MASKED = auto() + UNSTABLE = auto() + + +class FuseDuplicateUsersConfig(Enum): + ENABLED = auto() + DISABLED = auto() + + +@dataclass +class ArmPassPipelineConfig: + softmax: SoftmaxDecompositionConfig = SoftmaxDecompositionConfig.MASKED + fuse_duplicate_users: FuseDuplicateUsersConfig = FuseDuplicateUsersConfig.ENABLED + + def disable_masked_softmax(self) -> None: + self.softmax = SoftmaxDecompositionConfig.UNSTABLE + + def disable_fuse_duplicate_users(self) -> None: + self.fuse_duplicate_users = FuseDuplicateUsersConfig.DISABLED + + def is_default(self) -> bool: + return ( + self.softmax is SoftmaxDecompositionConfig.MASKED + and self.fuse_duplicate_users is FuseDuplicateUsersConfig.ENABLED + ) + + def to_dict(self) -> dict[str, str]: + return {f.name: getattr(self, f.name).name for f in fields(self)} + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "ArmPassPipelineConfig": + config = cls() + for f in fields(cls): + raw_value = data.get(f.name) + if raw_value is None: + continue + enum_type = f.type + setattr(config, f.name, enum_type[raw_value]) + return config + + def serialize(self) -> bytes: + """Return a serialized representation of this config.""" + return json.dumps(self.to_dict()).encode() + + def __repr__(self): + fields = ", ".join(f"{name}={value!r}" for name, value in self.__dict__.items()) + return f"({fields})" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/type.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/type.py new file mode 100644 index 0000000..e53dc1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/common/type.py @@ -0,0 +1,28 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Type checking utilities.""" + +from typing import TypeVar + +T = TypeVar("T") + + +def ensure_type(expected_type: type[T], arg: object) -> T: + """Ensure that the argument is of the expected type. + + Args: + expected_type (type[T]): The expected type. + arg (object): The argument to check. + + Returns: + T: The argument, if it is of the expected type. + + """ + if isinstance(arg, expected_type): + return arg + + expected_name = getattr(expected_type, "__name__", str(expected_type)) + actual_name = type(arg).__name__ + raise TypeError(f"Expected value of type {expected_name}, got {actual_name!r}") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/constants.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/constants.py new file mode 100644 index 0000000..c0d9c45 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/constants.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, Final + +from executorch.exir.dialects._ops import ops as exir_ops + +exir_ops = cast(Any, exir_ops) + +qd = exir_ops.edge.quantized_decomposed + +QUANT_PER_TENSOR_OP: Final = qd.quantize_per_tensor.default +QUANT_PER_TENSOR_OP_T: Final = qd.quantize_per_tensor.tensor +QUANT_PER_CHANNEL_OP: Final = qd.quantize_per_channel.default + +DEQUANT_PER_TENSOR_OP: Final = qd.dequantize_per_tensor.default +DEQUANT_PER_TENSOR_OP_T: Final = qd.dequantize_per_tensor.tensor +DEQUANT_PER_CHANNEL_OP: Final = qd.dequantize_per_channel.default + +Q_OPS: Final = (QUANT_PER_TENSOR_OP, QUANT_PER_TENSOR_OP_T, QUANT_PER_CHANNEL_OP) +DQ_OPS: Final = (DEQUANT_PER_TENSOR_OP, DEQUANT_PER_TENSOR_OP_T, DEQUANT_PER_CHANNEL_OP) + +PER_TENSOR_QDQ_OPS: Final = ( + QUANT_PER_TENSOR_OP, + QUANT_PER_TENSOR_OP_T, + DEQUANT_PER_TENSOR_OP, + DEQUANT_PER_TENSOR_OP_T, +) +PER_CHANNEL_QDQ_OPS: Final = (QUANT_PER_CHANNEL_OP, DEQUANT_PER_CHANNEL_OP) + +NHWC_ORDER: Final = (0, 2, 3, 1) +NHWC_INVERSE_ORDER: Final = (0, 3, 1, 2) +NNHWC_ORDER: Final = (0, 1, 3, 4, 2) +NNHWC_INVERSE_ORDER: Final = (0, 1, 4, 2, 3) +NNNHWC_ORDER: Final = (0, 1, 2, 4, 5, 3) +NNNHWC_INVERSE_ORDER: Final = (0, 1, 2, 5, 3, 4) + +NCHW_ORDER: Final = (0, 1, 2, 3) +NNCHW_ORDER: Final = (0, 1, 2, 3, 4) +NNNCHW_ORDER: Final = (0, 1, 2, 3, 4, 5) + +HWCM_ORDER: Final = (2, 3, 0, 1) + +MAX_RANK: Final = 6 + +DISALLOW_TFA_META_KEY: Final = "_arm_disallow_tfa" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/TARGETS new file mode 100644 index 0000000..a88e3b0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/TARGETS @@ -0,0 +1,14 @@ +# @noautodeps +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "schema", + srcs = [ + "__init__.py", + "schema.py", + ], + deps = [ + "fbsource//third-party/tosa_tools:serializer", + "//caffe2:torch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/schema.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/schema.py new file mode 100644 index 0000000..d4df228 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/debug/schema.py @@ -0,0 +1,145 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +import json + +from dataclasses import asdict, dataclass +from typing import Any, Optional + +import torch +import tosa_serializer as ts + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec + +from torch.fx.traceback import NodeSource + + +@dataclass +class TosaDebugSchema: + node_name: str + operator_name: str + operator_id: int + + +@dataclass +class ATenDebugSchema: + node_name: str + operator_name: str + + @staticmethod + def from_node(node: torch.fx.Node) -> ATenDebugSchema: + # node.target is Union[Callable[..., Any], str], so we need to access this correctly depending on the type + if callable(node.target): + operator_name = node.target.__name__ + else: + operator_name = node.target + + return ATenDebugSchema(node_name=node.name, operator_name=operator_name) + + +@dataclass +class TorchDebugSchema: + stack_trace: list[str] + node_trace: list[dict[str, Any]] | str + nn_module_stack: dict[str, Any] | str + torch_fn: tuple[str, str] | str + + @staticmethod + def serialize_node_trace(node_trace: list[NodeSource]) -> list[dict[str, Any]]: + """Flatten the from_node dictionary to remove nesting.""" + flattened = [] + node_stack = [] + + for n in node_trace: + node_stack.append((n, -1)) + + while len(node_stack) > 0: + node, parent_id = node_stack.pop() + flattened.append( + { + "name": node.name, + "target": node.target, + "graph_id": node.graph_id, + "pass_name": node.pass_name, + "action": node._get_action_string(), + "parent_graph_id": parent_id, + } + ) + + for n in node.from_node: + node_stack.append((n, node.graph_id)) + + return flattened + + @staticmethod + def from_node(node: torch.fx.Node) -> TorchDebugSchema: + node_trace: str | list[dict[str, Any]] = "No node trace available." + + if "from_node" in node.meta: + # Flatten the node_trace dictionary, so there is no nesting + node_trace = TorchDebugSchema.serialize_node_trace(node.meta["from_node"]) + + return TorchDebugSchema( + stack_trace=node.meta.get("stack_trace", "No stack trace available").split( + "\n" + ), + node_trace=node_trace, + nn_module_stack=node.meta.get( + "nn_module_stack", "No module stack trace available" + ), + torch_fn=node.meta.get("torch_fn", "No torch_fn available"), + ) + + +@dataclass +class DebugSchema: + event_id: int + aten_info: ATenDebugSchema + tosa_info: Optional[TosaDebugSchema] + torch_info: TorchDebugSchema + + def to_dict(self) -> dict[str, Any]: + output = asdict(self) + + if self.tosa_info is None: + output.pop("tosa_info") + + return output + + +class DebugHook: + def __init__(self, debug_mode: ArmCompileSpec.DebugMode) -> None: + self._debug_events: list[DebugSchema] = [] + self.mode = debug_mode + + def add(self, node: torch.fx.Node, tosa_op: Any, tosa_op_id: ts.Op) -> DebugSchema: + tosa_debug_info = None + + # If the debug data is being embedded into the TOSA flatbuffer + # do not collect TOSADebugSchema data, it's redundent + if self.mode != ArmCompileSpec.DebugMode.TOSA: + tosa_debug_info = TosaDebugSchema( + node_name=str(tosa_op), + operator_name=str(tosa_op_id), + operator_id=int(tosa_op_id), + ) + + aten_debug_info = ATenDebugSchema.from_node(node) + torch_debug_info = TorchDebugSchema.from_node(node) + + debug_info = DebugSchema( + event_id=len(self._debug_events), + aten_info=aten_debug_info, + tosa_info=tosa_debug_info, + torch_info=torch_debug_info, + ) + self._debug_events.append(debug_info) + + return debug_info + + def serialize(self) -> str: + return json.dumps([event.to_dict() for event in self._debug_events], indent=4) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/__init__.py new file mode 100644 index 0000000..10b14d4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/__init__.py @@ -0,0 +1,11 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +from .backend import EthosUBackend # noqa: F401 +from .compile_spec import EthosUCompileSpec # noqa: F401 +from .partitioner import EthosUPartitioner # noqa: F401 + +__all__ = ["EthosUBackend", "EthosUPartitioner", "EthosUCompileSpec"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/backend.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/backend.py new file mode 100644 index 0000000..bd6da08 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/backend.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Main implementation of AoT flow to partition and preprocess for Arm target +# backends. Converts via TOSA as an intermediate form supported by AoT and +# JIT compiler flows. +# +"""Ahead-of-time Arm Ethos-U backend built on the shared TOSA pipeline.""" + +import logging +from typing import final, List + +from executorch.backends.arm.arm_vela import vela_compile +from executorch.backends.arm.ethosu.compile_spec import EthosUCompileSpec + +from executorch.backends.arm.tosa.backend import TOSABackend +from executorch.exir.backend.backend_details import BackendDetails, PreprocessResult +from executorch.exir.backend.compile_spec_schema import CompileSpec +from torch.export.exported_program import ExportedProgram + +# debug functionality +logger = logging.getLogger(__name__) + + +@final +class EthosUBackend(BackendDetails): + """BackendDetails subclass for delegation to Ethos-U. + + Deduce the TOSA lowering from the compile spec list by filtering out the + compile spec values that are of interest for the TOSABackend. + + """ + + @staticmethod + def _compile_tosa_flatbuffer( + tosa_flatbuffer: bytes, compile_spec: EthosUCompileSpec + ) -> bytes: + """Compile a TOSA flatbuffer into a target-specific binary stream. + + Args: + tosa_flatbuffer (bytes): Serialized TOSA graph produced by + ``TOSABackend``. + compile_spec (EthosUCompileSpec): Compile specification providing + Vela flags and intermediate paths. + + Returns: + bytes: Target-specific binary stream produced by Vela. + + """ + compile_flags = compile_spec.compiler_flags + + if len(compile_flags) == 0: + # Not testing for compile_flags correctness here, just that they are + # present. The compiler will give errors if they are not valid. + raise RuntimeError( + "compile_flags are required in the CompileSpec list for EthosUBackend" + ) + + # Vela tooling only supports flatbuffers up to 2 GiB. + max_flatbuffer_size = 2 * 1024 * 1024 * 1024 + flatbuffer_size = len(tosa_flatbuffer) + if flatbuffer_size > max_flatbuffer_size: + raise RuntimeError( + "TOSA flatbuffer is too large for Vela " + f"({flatbuffer_size} bytes > {max_flatbuffer_size} bytes limit)." + ) + + # Pass on the TOSA flatbuffer to the vela compiler. + binary = vela_compile( + tosa_flatbuffer, + compile_flags, + verbose=logger.getEffectiveLevel() <= logging.INFO, + intermediate_path=compile_spec.get_intermediate_path(), + ) + return binary + + @staticmethod + def preprocess( + edge_program: ExportedProgram, + compile_specs: List[CompileSpec], + ) -> PreprocessResult: + """Lower the exported program and compile it for an Ethos-U target. + + Args: + edge_program (ExportedProgram): Program to lower to Ethos-U. + compile_specs (List[CompileSpec]): Serialized Ethos-U compile specs + supplied by the frontend. + + Returns: + PreprocessResult: Result containing the compiled Ethos-U binary. + + """ + logger.info(f"{EthosUBackend.__name__} preprocess") + + compile_spec = EthosUCompileSpec.from_list(compile_specs) + # deduce TOSA compile_spec from Ethos-U compile spec. We get a new + # compile spec list, containing only elements relevant for the + # TOSABackend. + tosa_compile_spec = TOSABackend.filter_tosa_compile_specs(compile_spec) + + # Backends doesn't allow inheritance, as stated in comments in exir/backend/backend_api.py + # ('All backend implementation are final...'), so use composition instead. + # preprocess returns the serialized TOSA flatbuffer in .processed_bytes, + # which can be passed on to next compilation step. + tosa_preprocess = TOSABackend._preprocess(edge_program, tosa_compile_spec) + + binary = EthosUBackend._compile_tosa_flatbuffer( + tosa_preprocess.processed_bytes, compile_spec + ) + + return PreprocessResult(processed_bytes=binary) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/compile_spec.py new file mode 100644 index 0000000..1d311cb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/compile_spec.py @@ -0,0 +1,117 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( # noqa: unused + ArmPassPipelineConfig, +) +from executorch.backends.arm.tosa import ( # type: ignore[import-not-found] + TosaSpecification, +) +from executorch.exir.backend.compile_spec_schema import CompileSpec + + +class EthosUCompileSpec(ArmCompileSpec): + """Compile specification for Ethos-U NPU targets.""" + + _TARGET_KEY = "target" + + def __init__( + self, + target: str, + system_config: str | None = None, + memory_mode: str | None = None, + extra_flags: list[str] | None = None, + config_ini: str | None = "Arm/vela.ini", + ): + """Normalise Ethos-U compile configuration and compiler flags. + + Args: + target (str): Ethos-U accelerator configuration (for example, + ``"ethos-u55-128"``). + system_config (str | None): System configuration name from the Vela + config file. Defaults based on ``target`` when omitted. + memory_mode (str | None): Memory mode selection from the Vela config + file. Defaults based on ``target`` when omitted. + extra_flags (list[str] | None): Additional command-line flags for + Vela. + config_ini (str | None): Path to a Vela .ini configuration file. + Defaults to ``"Arm/vela.ini"``. + + """ + self.target = target + # Set vela compiler flags + if config_ini is None: + config_ini = "Arm/vela.ini" + compiler_flags = [] if extra_flags is None else extra_flags + compiler_flags.extend( + [ + f"--accelerator-config={target}", + f"--config={config_ini}", + "--output-format=raw", + "--debug-force-regor", + ] + ) + # default system config and memory mode + target_lower = self.target.lower() + if "ethos-u55" in target_lower: + if system_config is None: + system_config = "Ethos_U55_High_End_Embedded" + if memory_mode is None: + memory_mode = "Shared_Sram" + elif "ethos-u85" in target_lower: + if system_config is None: + system_config = "Ethos_U85_SYS_DRAM_Mid" + if memory_mode is None: + memory_mode = "Sram_Only" + else: + raise RuntimeError(f"Unknown ethos target: {target}") + + compiler_flags.append(f"--system-config={system_config}") + compiler_flags.append(f"--memory-mode={memory_mode}") + + # Set TOSA version. + base_tosa_version = "TOSA-1.0+INT+int16+int4" + if "u55" in target_lower: + # Add the Ethos-U55 extension marker + base_tosa_version += "+u55" + if "u85" in self.target: + base_tosa_version += "+cf" + tosa_spec = TosaSpecification.create_from_string(base_tosa_version) + + self._set_compile_specs(tosa_spec, compiler_flags) + self.validate() + + def to_list(self): + """Return compile specs including the encoded Ethos-U target.""" + compile_specs = super().to_list() + compile_specs.append(CompileSpec(self._TARGET_KEY, self.target.encode())) + return compile_specs + + @classmethod + def from_list_hook(cls, compile_spec, specs: dict[str, str]): + """Restore target-specific metadata from serialized compile specs.""" + compile_spec.target = specs.get(cls._TARGET_KEY, None) + + def validate(self): + """Validate the configuration against supported Ethos-U settings.""" + if len(self.compiler_flags) == 0: + raise ValueError( + "compile_flags are required in the CompileSpec list for EthosUBackend" + ) + if "u55" in self.target and not self.tosa_spec.is_U55_subset: + raise ValueError( + f"Target was {self.target} but tosa spec was not u55 subset." + ) + + @classmethod + def get_output_format(cls) -> str: + """Return the artifact format emitted by this compile spec.""" + return "vela" + + def _create_default_pipeline_config(self) -> ArmPassPipelineConfig: + # Any u55 subset passes are treated as tosa specification configs + # As such, they should be added to the base class default. + return super()._create_default_pipeline_config() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/partitioner.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/partitioner.py new file mode 100644 index 0000000..9acc043 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/ethosu/partitioner.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import final, Optional, Sequence + +from executorch.backends.arm.ethosu import EthosUBackend, EthosUCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.exir.backend.partitioner import DelegationSpec +from torch.fx.passes.operator_support import OperatorSupportBase + + +@final +class EthosUPartitioner(TOSAPartitioner): + """ + Partitions subgraphs supported by the Arm Ethos-U backend. + + Args: + compile_spec: List of CompileSpec objects for Ethos-U backend. + additional_checks: Optional sequence of additional operator support checks. + """ + + def __init__( + self, + compile_spec: EthosUCompileSpec, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + ) -> None: + # Override the delegation spec for Ethos-U + self.delegation_spec = DelegationSpec( + EthosUBackend.__name__, compile_spec.to_list() + ) + self.additional_checks = additional_checks + self.tosa_spec = compile_spec.tosa_spec diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/TARGETS new file mode 100644 index 0000000..8f6721b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/TARGETS @@ -0,0 +1,14 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "operator_support", + srcs = glob(["*.py"]), + deps = [ + "//executorch/backends/arm:constants", + "//executorch/backends/arm/_passes:passes", + "//executorch/backends/arm/tosa:tosa", + "//executorch/backends/transforms:remove_getitem_op", + "//executorch/backends/xnnpack/_passes:xnnpack_passes", + "//executorch/exir:lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/__init__.py new file mode 100644 index 0000000..01d936b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/__init__.py @@ -0,0 +1,23 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from . import ( # noqa + clone_dim_order_support, + control_flow_support, + convolution_support, + embedding_support, + ethos_u55_support, + index_select_support, + index_tensor_support, + minmax_support, + pool_2d_support, + reduce_sum_support, + right_shift_support, + slice_copy_support, + to_dim_order_copy_support, + tosa_supported_operators, + where_support, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/clone_dim_order_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/clone_dim_order_support.py new file mode 100644 index 0000000..ae6445c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/clone_dim_order_support.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for dim-order clone in TOSA. + +This module registers a support check for ``dim_order_ops._clone_dim_order`` +ensuring input/output dtypes match and the value types are FakeTensors. + +""" + +import logging + +import torch +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + + +@register_tosa_support_check +class CloneSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``_clone_dim_order``.""" + + targets = [exir_ops.edge.dim_order_ops._clone_dim_order.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Verify the operator target, the number and types of inputs/outputs, and + check that input and output dtypes match. + + """ + if node.target not in self.targets: + self.reporter.report_reject(node, f"Target {node.target} is not supported.") + return False + + input_node = node.args[0] + if not isinstance(input_node, fx.Node): + self.reporter.report_reject(node, "Non tensor clones are not supported") + return False + + # Check input node + if len(node.all_input_nodes) != 1: + self.reporter.report_reject( + node, f"Expected 1 input node, got {len(node.all_input_nodes)}" + ) + return False + + input_val = node.all_input_nodes[0].meta["val"] + if not isinstance(input_val, torch._subclasses.FakeTensor): + self.reporter.report_reject(node, "Expected input to be a FakeTensor.") + return False + + input_dtype = input_val.dtype + + # Check output node + output_val = node.meta["val"] + if not isinstance(output_val, torch._subclasses.FakeTensor): + self.reporter.report_reject(node, "Expected output to be a FakeTensor.") + return False + + if output_val.dtype != input_dtype: + self.reporter.report_reject( + node, + f"Input dtype {input_val.dtype} does not match {output_val.dtype}.", + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/control_flow_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/control_flow_support.py new file mode 100644 index 0000000..24fa34f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/control_flow_support.py @@ -0,0 +1,162 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import typing +from typing import cast + +import torch +import torch.fx as fx + +from executorch.backends.arm._passes.arm_pass_utils import is_submodule_node +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.specification import Tosa_1_00 +from executorch.exir import ExportedProgram +from executorch.exir.backend.utils import WhyNoPartitionReporter + +from torch.fx.passes.operator_support import OperatorSupportBase + + +def _fully_partitioned(submodule: fx.GraphModule) -> bool: + partition_tag = None + for submodule_node in submodule.graph.nodes: + if submodule_node.op == "call_function": + # Input Q ops and output DQ ops will be de-tagged even if the submodule is fully supported. + if ( + submodule_node.target in Q_OPS + and list(submodule_node.all_input_nodes)[0].op == "placeholder" + ): + continue + if ( + submodule_node.target in DQ_OPS + and list(submodule_node.users)[0].op == "output" + ): + continue + if "delegation_tag" not in submodule_node.meta: + return False + if partition_tag is None: + partition_tag = submodule_node.meta["delegation_tag"] + elif submodule_node.meta["delegation_tag"] != partition_tag: + return False + return True + + +def _submodules_fully_partitioned( + node: fx.Node, exported_program: ExportedProgram +) -> bool: + """Returns whether the submodule arguments to a cond node were fully partitioned. + Updates "val" meta of the submodules if they are. + """ + match node.target: + case torch.ops.higher_order.cond: + submodule_args = node.args[1:3] + case torch.ops.higher_order.while_loop: + submodule_args = node.args[0:2] + case _: + raise ValueError(f"Unexpected target: {node.target}") + cond_submodules = ( + ( + exported_program.graph_module.get_submodule( + str(cast(torch.fx.Node, submodule_node).target) + ), + cast(torch.fx.Node, submodule_node), + ) + for submodule_node in submodule_args + ) + for submodule, submodule_node in cond_submodules: + submodule = cast(torch.fx.GraphModule, submodule) + + if _fully_partitioned(submodule): + submodule_node.meta["val"] = submodule.graph.output_node().meta["val"] + else: + return False + return True + + +def _tosa_spec_supports_cf(tosa_spec: TosaSpecification) -> bool: + if not isinstance(tosa_spec, Tosa_1_00): + return False + return tosa_spec.support_extension("cf") + + +class ControlFlowSubmoduleSupported(OperatorSupportBase): + """Check whether control flow submodule args should be partitioned. + Applies control-flow extension constraints before allowing delegation.""" + + def __init__( + self, + exported_program: ExportedProgram, + tosa_spec: TosaSpecification, + reporter: WhyNoPartitionReporter, + ): + self.exported_program = exported_program + self.reporter = reporter + self.tosa_spec = tosa_spec + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + if is_submodule_node(node): + if not _tosa_spec_supports_cf(self.tosa_spec): + self.reporter.report_reject( + node, + f"TOSA spec {self.tosa_spec} does not support control flow extension.", + ) + return False + for user in node.users: + if user.target not in ControlFlowOpSupported._targeted_ops: + self.reporter.report_reject( + node, f"Submodule had unsupported user {user}" + ) + return False + if not _submodules_fully_partitioned(user, self.exported_program): + self.reporter.report_reject( + node, "One submodule was not fully partitioned" + ) + return False + return True + return False + + +class ControlFlowOpSupported(OperatorSupportBase): + """Check whether control flow ops should be partitioned. + Applies control-flow extension constraints before allowing delegation.""" + + _targeted_ops = { + torch.ops.higher_order.cond, + torch.ops.higher_order.while_loop, + } + + def __init__( + self, + exported_program: ExportedProgram, + tosa_spec: TosaSpecification, + reporter: WhyNoPartitionReporter, + ): + self.exported_program = exported_program + self.reporter = reporter + self.tosa_spec = tosa_spec + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + if node.target in self._targeted_ops: + if not _tosa_spec_supports_cf(self.tosa_spec): + self.reporter.report_reject( + node, + f"TOSA spec {self.tosa_spec} does not support control flow extension.", + ) + return False + + if not _submodules_fully_partitioned(node, self.exported_program): + self.reporter.report_reject( + node, "Submodule was not fully partitioned." + ) + return False + return True + + return False diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/convolution_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/convolution_support.py new file mode 100644 index 0000000..f335c50 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/convolution_support.py @@ -0,0 +1,160 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.convolution`` in TOSA. + +Provide general checks and hardware-specific constraints (e.g., U55 subset) for +convolution nodes prior to delegation to the TOSA backend. + +""" + +from typing import cast + +import torch +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class ConvolutionSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for convolutions.""" + + targets = [exir_ops.edge.aten.convolution.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Reject transposed convolutions and convolutions with non-zero output + padding. Apply additional hardware-specific constraints for U55. + + """ + # Not implemented + transposed = cast(bool, node.args[6]) + output_padding = cast(list[int], node.args[7]) + if transposed: + return False + + for pad in output_padding: + if pad != 0: + self.reporter.report_reject( + node, "Convolutions with non-zero output padding not implemented." + ) + return False + + # Hardware specific constraints + if tosa_spec.is_U55_subset: + return self._is_node_supported_u55(node) + else: + return True + + def _is_node_supported_u55(self, node: fx.Node) -> bool: + """Enforce Ethos-U55-specific constraints (Vela 4.2.0). + + Check channel dimensions, kernel sizes, and stride/pad/dilation + combinations permitted on U55. + + Args: + node (fx.Node): Convolution node to validate. + + Returns: + bool: True if supported; otherwise, False. + + """ + shape_in = cast(torch.Tensor, node.all_input_nodes[0].meta["val"]).shape + shape_out = node.meta["val"].shape + kernel = cast(fx.Node, node.args[1]).meta["val"].shape + group = cast(int, node.args[8]) + + C_in = shape_in[1] + C_out = shape_out[1] + if (C_in == group) and (C_out % C_in) == 0 and len(shape_in) <= 4: + # Depthwise convolution + for dim in shape_in[1:]: + if not 1 <= dim <= 65536: + self.reporter.report_reject( + node, + f"Depthwise convolution must have CWH <= 65536, got {dim})", + ) + return False + else: + # Convolution + if not 1 <= C_in <= 65536: + self.reporter.report_reject( + node, f"Convolution must have C <= 65536, got {C_in})" + ) + return False + + kernel_w = kernel[2] + kernel_h = kernel[3] if len(kernel) > 3 else 1 + kernel_z = kernel[4] if len(kernel) > 4 else 1 + # Kernel condition misses constraint on sum of absolute weights + if not 1 <= kernel_h <= 64 or not 1 <= kernel_w * kernel_h <= 4096: + self.reporter.report_reject( + node, + f"Convolution needs to have kernel_y<=64, kernel_x*kernel_y<=4096, got kernel ({kernel_w}, {kernel_h})", + ) + return False + if kernel_z != 1: + self.reporter.report_reject( + node, f"Convolution3d needs to have kernel_z==1, got {kernel_z}." + ) + return False + + if not self._stride_condition(node): + self.reporter.report_reject( + node, "Failed condition on stride, pad and dilation combination." + ) + return False + + return True + + def _stride_condition(self, node: fx.Node) -> bool: + """Check a simplified stride/padding/dilation constraint. + + Disallow strides greater than 3 unless there is no padding and the + dilation is 1. For 3D convolutions, enforce ``stride_z <= 1``. + + Args: + node (fx.Node): Convolution node to evaluate. + + Returns: + bool: True if the condition is satisfied. + + """ + strides = cast(list[int], node.args[3]) + has_padding = any(pad > 0 for pad in cast(list[int], node.args[4])) + dilations = cast(list[int], node.args[5]) + if len(dilations) == 1: + dilations = [dilations[0]] * 2 + if len(strides) == 1: + strides = [strides[0]] * 2 + + if len(strides) > 2: + stride_z = strides[2] + if stride_z > 1: + self.reporter.report_reject( + node, f"Convolution3d only supports stride_z<=1, got {stride_z}." + ) + return False + + for stride, dilation in zip(strides, dilations): + stride_condition = 1 <= stride <= 3 + dilation_condition = (not has_padding) and (dilation == 1) + if (not stride_condition) and (not dilation_condition): + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/embedding_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/embedding_support.py new file mode 100644 index 0000000..3ad1701 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/embedding_support.py @@ -0,0 +1,61 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.embedding`` in TOSA. + +Permit embeddings with int32 indices (TOSA lacks int64 support); other dtypes +are rejected by this check. + +""" + +import torch + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class EmbeddingSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.embedding``.""" + + targets = [exir_ops.edge.aten.embedding.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if the node is supported by TOSA. + + PyTorch's ``aten.embedding`` typically takes int64 indices, but for + TOSA we only allow int32 indices. The export path decomposes the op so + that int32 indices are ok. + + """ + if len(node.all_input_nodes) != 2: + self.reporter.report_reject( + node, + (f"Expected exactly two input nodes, got {len(node.all_input_nodes)}"), + ) + return False + + indices_val = node.all_input_nodes[1].meta["val"] + indices_dtype = indices_val.dtype + + if indices_dtype != torch.int32: + self.reporter.report_reject( + node, + f"Indices dtype {indices_val.dtype} is not supported in {node.target}.", + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/ethos_u55_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/ethos_u55_support.py new file mode 100644 index 0000000..bd43233 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/ethos_u55_support.py @@ -0,0 +1,598 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide Ethos-U55 specific operator support checks. + +Contains dtype validation, explicit unsupported-op filtering, and shape/ +permutation constraints for view and permute operations when targeting the +Ethos-U55 subset of TOSA. + +""" + + +import typing +from typing import cast + +import torch +import torch.fx as fx + +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm._passes.convert_permute_singleton_to_view_pass import ( + is_singleton_permutation, +) +from executorch.backends.arm._passes.insert_table_ops import TableOps +from executorch.backends.arm.operators.op_permute import transform_permutation_vector +from executorch.backends.arm.tosa.utils import tosa_shape +from executorch.exir.backend.utils import WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops +from torch.fx.passes.operator_support import OperatorSupportBase + + +def _try_determine_dtype(node: fx.Node) -> torch.dtype | None: + """Return an inferred dtype for a node when possible. + + Uses fake tensor metadata and nearby quantize/dequantize nodes to infer the + integer dtype used by the operator. Returns ``None`` when the dtype cannot + be determined reliably. + + Args: + node (fx.Node): FX node to inspect. + + Returns: + torch.dtype | None: Inferred dtype or ``None`` if unknown. + + """ + dtype = get_first_fake_tensor(node).dtype + if not dtype.is_floating_point: + return dtype + if node.target is exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default: + return get_first_fake_tensor(node.all_input_nodes[0]).dtype + q_node = list(node.users)[0] + if q_node.target is exir_ops.edge.quantized_decomposed.quantize_per_tensor.default: + return typing.cast(torch.dtype, q_node.args[-1]) + # We can't easily figure out dtype, return None + return None + + +class EthosU55DtypeSupport(OperatorSupportBase): + """Validate dtypes for U55-supported operators. + + Ensures operators use a supported integer dtype according to U55 + constraints, with specific rules for convolution, matmul, and table ops. + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + targeted_ops_i8_i16_i32 = [ + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.repeat.default, + exir_ops.edge.aten.constant_pad_nd.default, + exir_ops.edge.aten.view.default, + exir_ops.edge.aten.permute.default, + exir_ops.edge.aten.permute_copy.default, + ] + + target_ops_i8 = tuple(TableOps.included_ops()) + + def is_node_supported( # noqa: C901 + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node uses supported dtypes. + + Applies per-operator dtype rules for U55, including specialized input + and weight constraints for convolution and int8-only checks for table + operations and matmul variants. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: True if supported; otherwise, False. + + """ + dtype = _try_determine_dtype(node) + if dtype is None: + # If we couldn't determine dtype, just return ok. + return True + + if node.target in self.targeted_ops_i8_i16_i32: + if dtype not in (torch.int8, torch.int16, torch.int32): + self.reporter.report_reject( + node, f"Unsupported dtype {dtype} (Supports i8, i16, i32)." + ) + return False + + if node.target in self.target_ops_i8: + if dtype not in (torch.int8, torch.int16): + self.reporter.report_reject( + node, f"Unsupported dtype {dtype} (Supports i8, i16)." + ) + return False + + if node.target == exir_ops.edge.aten.convolution.default: + ifm, weight = node.all_input_nodes[0:2] + ifm_dtype = _try_determine_dtype(ifm) + if ifm_dtype is not None and ifm_dtype not in (torch.int8, torch.int16): + self.reporter.report_reject( + node, f"Unsupported input dtype {dtype} (Supports i8, i16)." + ) + return False + weight_dtype = _try_determine_dtype(weight) + if weight_dtype is not None and weight_dtype not in (torch.int8,): + self.reporter.report_reject( + node, f"Unsupported weight dtype {dtype} (Supports i8)." + ) + return False + if len(node.all_input_nodes) > 2: + bias = node.all_input_nodes[2] + bias_dtype = _try_determine_dtype(bias) + if bias_dtype is not None and bias_dtype not in (torch.int32,): + self.reporter.report_reject( + node, f"Unsupported bias dtype {dtype} (Supports i32)." + ) + return False + + if node.target in ( + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.bmm.default, + ): + for input_node in node.all_input_nodes: + dtype = _try_determine_dtype(input_node) + if dtype is not None and dtype != torch.int8: + self.reporter.report_reject( + input_node, + f"Input {input_node.name} has unsupported dtype {dtype} (Supports i8).", + ) + return False + + return True + + +class EthosU55NotSupported(OperatorSupportBase): + """Reject operators not supported by Ethos-U55. + + The ``unsupported_ops`` list contains aten ops that either map to TOSA + operators the U55 cannot run or remain unimplemented. The mapping comments + capture expected TOSA equivalents when not obvious. + + """ + + unsupported_ops = [ + exir_ops.edge.aten.any.default, # REDUCE_ANY + exir_ops.edge.aten.any.dim, # REDUCE_ANY + exir_ops.edge.aten.any.dims, # REDUCE_ANY + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.bitwise_and.Scalar, + exir_ops.edge.aten.bitwise_or.Scalar, + exir_ops.edge.aten.bitwise_xor.Scalar, + exir_ops.edge.aten.bitwise_not.default, + exir_ops.edge.aten.logical_and.default, + exir_ops.edge.aten.logical_or.default, + exir_ops.edge.aten.logical_xor.default, + exir_ops.edge.aten.logical_not.default, + exir_ops.edge.aten.amax.default, # REDUCE_MAX + exir_ops.edge.aten.amin.default, # REDUCE_MIN + exir_ops.edge.aten.conv3d.default, # CONV3D + exir_ops.edge.aten.conv3d.padding, # CONV3D (deprecated alias) + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.ne.Tensor, + exir_ops.edge.aten.ne.Scalar, + exir_ops.edge.aten.flip.default, # REVERSE + exir_ops.edge.aten.grid_sampler_2d, # GATHER + exir_ops.edge.aten.index.Tensor, # GATHER + exir_ops.edge.aten.index_select.default, # GATHER + exir_ops.edge.aten.scatter.src, + exir_ops.edge.aten.scatter.value, + exir_ops.edge.aten.select_scatter.default, + exir_ops.edge.aten.scatter_reduce.two, + exir_ops.edge.aten.scatter_add.default, + exir_ops.edge.aten.upsample_nearest2d.vec, # RESIZE + exir_ops.edge.aten.upsample_bilinear2d.vec, # RESIZE + exir_ops.edge.aten.reflection_pad1d.default, # REVERSE + exir_ops.edge.aten.reflection_pad2d.default, # REVERSE + exir_ops.edge.aten.reflection_pad3d.default, # REVERSE + exir_ops.edge.aten.where.self, # SELECT + ] + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + self.reporter = reporter + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return False for nodes explicitly unsupported on U55. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: False if ``node.target`` is in ``unsupported_ops``; else True. + + """ + if node.target in self.unsupported_ops: + self.reporter.report_reject(node, "Op is not supported on U55.") + return False + + return True + + +shape_t = list[int] + + +class EthosU55ViewCheck(OperatorSupportBase): + """Validate view/select shapes and dtypes for U55. + + Performs lightweight checks on output shape rank and product constraints, + with awareness that transposes may be inserted around view/select during + lowering to channels-last. + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + def axes_product(self, nhwc_shape: shape_t) -> int: + """Return the product of all axes in ``nhwc_shape``. + + Args: + nhwc_shape (list[int]): Shape in NHWC order. + + Returns: + int: Product of the axis sizes. + + """ + product = 1 + for axes in nhwc_shape: + product *= axes + return product + + # TODO: Extend this check to comply with u55 restrictions + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Check whether a given view/select node is U55-supported. + + Currently only checks dtypes and product of axes. + + It is not the view operator itself that is not supported on U55. In + order for the view operator to be compatible with the channels-last + format of TosaBackend, transposes may need to be inserted before and + after the view op. If that happens and that transpose operator does not + adhere to the limitations then it will result in the following error: + + CPU performance estimation for "Transpose" not implemented. + ... + CPU operations are not supported for GraphAPI input + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node for ``view_copy`` or ``select``. + + Returns: + bool: False if rejected by constraints; otherwise, True. + + """ + # Select decomposes into squeeze, which in turn becomes a view. Therefore, + # perform the same check on select operators as view operators. + if node.target not in ( + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.select.int, + exir_ops.edge.aten.select_copy.int, + ): + return True + + if node.target in ( + exir_ops.edge.aten.select.int, + exir_ops.edge.aten.select_copy.int, + ): + input_node, dim, index = cast(tuple[fx.Node, int, int], node.args) + + shape = input_node.meta["val"].shape + rank = len(shape) + if not -rank <= dim < rank: + self.reporter.report_reject( + node, + (f"Dimension {dim} out of range for rank {rank}."), + ) + return False + dim = dim % rank + + size = shape[dim] + if not -size <= index < size: + self.reporter.report_reject( + node, + (f"Index {index} out of range for dim {dim} with size {size}."), + ) + return False + index = index % size + + # Shape after squeeze. This may get converted into a view which may become + # a transpose. This is why we're checking select. + squeezed_shape = shape[:dim] + shape[dim + 1 :] + shape = squeezed_shape + else: + shape = list(get_first_fake_tensor(node).shape) + + dtype = _try_determine_dtype(node) + + rank = len(shape) + if rank > 4: + if dtype == torch.int32: + self.reporter.report_reject(node, "No support for rank > 4 in int32.") + return False + + if dtype in (torch.int8, torch.int16): + if self.axes_product(shape) > 65536: + self.reporter.report_reject( + node, + f"No support for {shape=}, {dtype=}. Product of axes must be <65536", + ) + return False + + return True + + +class EthosU55TransposeCheck(OperatorSupportBase): + """Validate permute nodes against U55 reshape/transpose limits. + + Applies dtype- and rank-specific constraints to permutations. Tests both + NCHW and NHWC interpretations for rank-3/4 shapes since dim order is unknown + at partition time. + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + def _pad_to_rank_4( + self, shape: shape_t, permutation: list[int] + ) -> tuple[shape_t, shape_t]: + """Pad shape/permutation to rank 4 by prepending ones/indices. + + Args: + shape (list[int]): Original shape. + permutation (list[int]): Original permutation indices. + + Returns: + tuple[list[int], list[int]]: Padded shape and permutation. + + """ + diff = 4 - len(shape) + padded_shape = [1] * diff + shape + for i in range(len(permutation)): + permutation[i] += diff + padded_permutation = list(range(diff)) + permutation + return padded_shape, padded_permutation + + def axes_product(self, nhwc_shape: shape_t) -> int: + """Return the product of all axes in ``nhwc_shape``. + + Args: + nhwc_shape (list[int]): Shape in NHWC order. + + Returns: + int: Product of the axis sizes. + + """ + product = 1 + for axes in nhwc_shape: + product *= axes + return product + + def _permute_constraint_i8_i16( + self, nhwc_shape: list[int], permutation: list[int] + ) -> bool: + """Return True if permutation meets i8/i16 constraints.""" + N, H, W, C = nhwc_shape + + if is_singleton_permutation(nhwc_shape, permutation): + return True + + match permutation: + case (0, 1, 2, 3): # NHWC -> NHWC + return True + case ( + (0, 2, 1, 3) | (0, 1, 3, 2) | (0, 3, 1, 2) | (0, 2, 3, 1) | (0, 3, 2, 1) + ): + # NHWC -> NWHC, NHCW, NCWH, NCHW, NCHW -> NHWC + return N * H <= 65536 and W <= 65536 and C <= 65536 + case _: + return self.axes_product(nhwc_shape) <= 65536 + + def _permute_constraint_i32( + self, nhwc_shape: list[int], permutation: list[int] + ) -> bool: + """Return True if permutation meets i32 constraints.""" + N, H, W, C = nhwc_shape + match permutation: + case (0, 1, 2, 3): # NHWC -> NHWC + return C <= 32768 + case (0, 2, 1, 3): # NHWC -> NHWC + return N == 1 and H <= 65536 and W <= 65536 and C <= 16384 + case (0, 1, 3, 2): # NHWC -> NHCW + return N * H <= 65536 and W <= 65536 and C <= 65536 + case _: + return False + + def _permute_constraint(self, shape, permutation, dtype): + """Return True if permutation meets dtype-specific constraints.""" + if dtype in (torch.int8, torch.int16): + return self._permute_constraint_i8_i16(shape, permutation) + if dtype == torch.int32: + return not self._permute_constraint_i32(shape, permutation) + return True + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if a permute node satisfies U55 constraints. + + Tests both NCHW and NHWC interpretations for rank-3/4 shapes, and + applies dtype-specific limits to shapes and permutations. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: True if supported; otherwise, False. + + """ + if not node.target == exir_ops.edge.aten.permute_copy.default: + return True + + shape = list(get_first_fake_tensor(node).shape) + dtype = _try_determine_dtype(node) + permutation = list(typing.cast(list[int], node.args[1])) + + rank = len(shape) + if rank > 4: + if dtype == torch.int32: + self.reporter.report_reject( + node, f"No support for {permutation=} in int32." + ) + return False + if dtype in (torch.int8, torch.int16): + if self.axes_product(shape) > 65536: + self.reporter.report_reject( + node, + f"No support for {shape=}, {dtype=}. Product of axes must be <65536", + ) + return False + return True + + shape, permutation = self._pad_to_rank_4(shape, permutation) + if rank == 3 or rank == 4: + # For rank 3 and 4, we can have channels first or channels last dim order. + # Since we don't know which at partition-time, test both. + + nhwc_shape = tosa_shape(shape, [0, 2, 3, 1]) + nhwc_permutation = transform_permutation_vector(permutation, [0, 2, 3, 1]) + + if not self._permute_constraint(nhwc_shape, nhwc_permutation, dtype): + self.reporter.report_reject( + node, + f"Unsupported NHWC {nhwc_shape=} for {nhwc_permutation=}, {dtype=}", + ) + return False + + if not self._permute_constraint(shape, permutation, dtype): + self.reporter.report_reject( + node, f"Unsupported NCHW {shape=} for {permutation=}, {dtype=}" + ) + return False + + return True + + +class EthosU55CastCheck(OperatorSupportBase): + """Reject unsupported casts on U55. + + U55 does not support casting from INT32 or any casts involving BOOL. Note that + casting from one dtype to the same dtype is a no-op and is supported. + + + Attributes: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + + targets = [ + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ] + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter. + + Args: + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + super().__init__() + self.reporter = reporter + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node satisfies the cast constraints of U55. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported modules. + node (fx.Node): FX node to check. + + Returns: + bool: True if supported; otherwise, False. + + """ + if node.target not in self.targets: + return True + input_dtype = get_first_fake_tensor(node.all_input_nodes[0]).dtype + output_dtype = get_first_fake_tensor(node).dtype + if input_dtype == output_dtype: + # This is ok as this will not result in a cast + return True + if input_dtype in (torch.bool, torch.int32): + self.reporter.report_reject( + node, f"Casting from {input_dtype} is not supported on U55." + ) + return False + if output_dtype in (torch.bool,): + self.reporter.report_reject( + node, f"Casting to {output_dtype} is not supported on U55." + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_select_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_select_support.py new file mode 100644 index 0000000..a83151a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_select_support.py @@ -0,0 +1,60 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.index_select`` in TOSA. + +Accept int32 indices and restrict supported weight shapes to 2D or 3D with a +unit batch dimension. + +""" +import torch +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class IndexSelectSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.index_select``.""" + + targets = [exir_ops.edge.aten.index_select.default] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if the node is supported by TOSA. + + Require int32 indices and limit weight shapes to 2D or 3D with a leading + dimension of 1. + + """ + weights_shape = node.all_input_nodes[0].meta["val"].shape + indices_val = node.all_input_nodes[1].meta["val"] + indices_dtype = indices_val.dtype + + if indices_dtype != torch.int32: + self.reporter.report_reject( + node, + f"Indices dtype {indices_val.dtype} is not supported in {node.target}.", + ) + return False + + if not ( + len(weights_shape) == 2 + or (len(weights_shape) == 3 and weights_shape[0] == 1) + ): + self.reporter.report_reject( + node, f"{node.target} with weights shape {weights_shape} not supported." + ) + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_tensor_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_tensor_support.py new file mode 100644 index 0000000..5de70c0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/index_tensor_support.py @@ -0,0 +1,160 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide TOSA support checks for ``aten.index.Tensor``. + +Reject unsupported patterns such as high-rank index tensors, front-positioned +slice/ellipsis/None markers, and cases that exceed ``int32`` element limits. + +""" + +import math + +import torch +import torch.fx as fx +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.common.type import ensure_type +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class IndexTensorSupported(SupportedTOSAOperatorCheck): + """Prevent partitioning of unsupported ``index.Tensor`` usages. + + This support check is intended to prevent the partitioning of + currently unsupported usages of the index.Tensor operator. + + 1. Usages where indexing tensors are of rank 4 or higher. + This is due to the AnnotateChannelsLastDimOrder pass and + the rarity of such operation. + Support is possible but would require further changes to the above + pass which can be added at such a time as is necessary. + + 2. Usages where slice, ellipsis or None are present before an indexing tensor: + t[{start}:{end}, indexTensor] - slicing + t[None, indexTensor] - unsqueeze + t[..., indexTensor] - ellipsis + + 3. Usages where the value tensor contains more than int32.max elements + This is due to int32 TOSA limitation and the fact that we flatten out + and accumulate all index tensors. + As such to avoid overflow we reject lowering of this operator if it is + possible for indices to go over the int32 limit. + + Extra information regarding #2: + Pytorch decomposes slice and None usages before they reach aten. + In the case of Slicing and Unsqueeze, Pytorch will add the relevant + operation just before the index.Tensor op. + In the case of Ellipsis no extra operation is added. + + In all three cases Pytorch will insert "None"(s) in the index list + only if the above operations are done on a dimension BEFORE one being indexed. + + When slicing, unsqueeze and ellipsis are done on dimensions after + the ones being indexed, then they do not affect the final output + values, only the shape. Thus None is not passed to the index.Tensor op. + + The purpose of None is to signify to index.Tensor that a dimension + should not be indexed. + In such cases the logic behaves similar to batching along that dimension. + For the sake of simplicity we have not implemented this behavior yet + and thus have put this support check in place to prevent the partitioning + of index.Tensor ops which include None. + + Examples: + #1 - Slice ----------------------------------------------------- + t = torch.randint(25, size(25, 3, 6)) + t[1:5, torch.arange(3)] + + Turns into: (edge pseudo code) + slice_res = ...edge__ops_aten_slice_copy_Tensor(t, dim=0, start=1, end=2) + out = ...edge__ops_aten_index_Tensor(slice_res, [None, torch.arange(3)]) + + #2 - None (Unsqueeze) ------------------------------------------ + t = torch.randint(25, size(25, 3, 6)) + t[None, torch.arange(3)] + + Turns into: edge pseudo code) + unsqueeze_res = ...edge__ops_aten_unsqueeze(t, dim=0) + out = ...edge__ops_aten_index_Tensor(unsqueeze_res, [None, torch.arange(3)]) + + #3 - None (Unsqueeze) After index ------------------------------ + t = torch.randint(25, size(25, 3, 6)) + t[torch.arange(3), None] + + Turns into: edge pseudo code) + unsqueeze_res = ...edge__ops_aten_unsqueeze(t, dim=1) + out = ...edge__ops_aten_index_Tensor(unsqueeze_res, [torch.arange(3)]) + + NB. + With the current implementation of flattening tensors and indices out, + supporting None (Unsqueeze) is simply a matter of ignoring the + None dimension. + This is not the case for Slice and Ellipsis operators, where + the size of the new dimension can be > 1. + + Note that slice ops interleaved between indexes such as: + t[1:3, torch.arange(5), 2:3, torch.arange(3).reshape(3,1)] + are also possible and can result in some unintuitive behaviors + where batching and indexing are mixed together. + + """ + + targets = [exir_ops.edge.aten.index.Tensor] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if ``aten.index.Tensor`` usage fits supported patterns. + + Enforces the following constraints: + - No ``None`` (unsqueeze), slice, or ellipsis before an indexing tensor. + - Indexing tensors have rank <= 3. + - The value tensor element count fits in ``int32``. + + """ + indices = node.args[1] + for index in indices: # type: ignore[union-attr] + # Usage 2 guard + if index is None: + self.reporter.report_reject( + node, + ( + "None (from slice/unsqueeze/ellipsis) before an indexing tensor" + " is not supported." + ), + ) + return False + + # Usage 1 guard + index = ensure_type(torch.fx.Node, index) + fake_tensor = get_first_fake_tensor(index) + if len(fake_tensor.size()) > 3: + self.reporter.report_reject( + node, + ("Indexing tensors of rank >= 4 is not supported."), + ) + return False + + # Usage 3 guard + input_node = ensure_type(torch.fx.Node, node.args[0]) + total_vals = math.prod(get_first_fake_tensor(input_node).shape) + if total_vals > torch.iinfo(torch.int32).max: + self.reporter.report_reject( + node, + ("Value size exceeds int32 range; would overflow flattened indexing."), + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/minmax_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/minmax_support.py new file mode 100644 index 0000000..8ba5d93 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/minmax_support.py @@ -0,0 +1,61 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for min/max along a dimension in TOSA. + +Provide support checks ensuring that argmax/argmin indices are not consumed, +restricting to float profiles until index quantization is supported. + +""" + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class MinMaxSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.max.dim`` and ``aten.min.dim``.""" + + targets = [ + exir_ops.edge.aten.max.dim, + exir_ops.edge.aten.min.dim, + ] + + # TODO : "MLETORCH-718 : Quantization of indices in arm_quantizer" + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Allow max/min when the argmax/argmin output is unused or dropped (i.e., + only the value is consumed). Disallow cases where arg indices are + further used. + + """ + if node.target in [exir_ops.edge.aten.max.dim, exir_ops.edge.aten.min.dim]: + no_argmax = len(node.users) == 1 + no_argmax_users = (len(node.users) == 2) and ( + len(list(node.users)[1].users) == 0 + ) + + if not (no_argmax or no_argmax_users): + self.reporter.report_reject( + node, + ( + "Using the indices output is not supported; only usage of the " + "values output is supported." + ), + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/pool_2d_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/pool_2d_support.py new file mode 100644 index 0000000..c0428e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/pool_2d_support.py @@ -0,0 +1,214 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide TOSA support checks for 2D pooling. + +Validate ``avg_pool2d`` and ``max_pool2d_with_indices`` against U55 profile +constraints including kernel size, stride, padding, and dimensionality. + +""" + +from typing import cast + +import torch +import torch.fx as fx +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +def kernel_check(kernel: tuple[int, int]) -> bool: + """Check if kernel size is within U55 constraints. + + Checks that ``kernel_x * kernel_y`` is in ``[1, 65536]`` and + ``kernel_y`` is in ``[1, 256]`` as required by the U55 profile. + + Args: + kernel (tuple[int, int]): Kernel height and width ``(kh, kw)``. + + Returns: + bool: True if the kernel passes validation. + + """ + if not (1 <= kernel[0] * kernel[1] <= 65536): + return False + return 1 <= kernel[1] <= 256 + + +def stride_check(strides: tuple[int, int]) -> bool: + """Check if strides are within U55 constraints. + + Args: + strides (tuple[int, int]): Vertical and horizontal strides. + + Returns: + bool: True if each stride is in ``[1, 3]``. + + """ + return all(1 <= stride <= 3 for stride in strides) + + +def dim_check(shape=torch.Size) -> bool: + """Check if non-batch dims are within U55 constraints. + + Verifies that all dimensions except batch are in ``[1, 65536]``. + + Args: + shape (torch.Size): Input tensor shape. + + Returns: + bool: True if all checked dimensions pass. + + """ + check = True + for dim in shape[1:]: + check &= 1 <= dim <= 65536 + return check + + +@register_tosa_support_check +class AvgPool2dSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support checks for ``aten.avg_pool2d``. + + Applies additional constraints when targeting the U55 subset, including + limits on kernel size, stride, padding behavior, and tensor ranks. + + """ + + targets = [ + exir_ops.edge.aten.avg_pool2d.default, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported(self, node: fx.Node, tosa_spec: TosaSpecification): + """Return True if ``avg_pool2d`` satisfies U55 constraints. + + Computes the effective TOSA padding (depending on ``count_include_pad`` + and ``divisor_override``) and validates kernel, stride, and shape limits. + + """ + if not tosa_spec.is_U55_subset: + return True + + # U55 case, Vela 4.2.0 (25.02 release) + input_arg = node.args[0] + if isinstance(input_arg, torch.fx.Node): + input_arg = get_first_fake_tensor(input_arg) + shape = input_arg.data.shape # type: ignore[union-attr] + + # Calculate padding used in the final TOSA operator + kernel = cast(tuple[int, int], node.args[1]) + stride = cast(tuple[int, int], node.args[2]) + padding = cast(tuple[int, int], node.args[3]) if len(node.args) > 3 else (0, 0) + ceil_mode = cast(bool, node.args[4]) if len(node.args) > 4 else False + count_include_pad = cast(bool, node.args[5]) if len(node.args) > 5 else True + divisor_override = cast(int, node.args[6]) if len(node.args) > 6 else None + + # If count_include_pad is True or divior_override is given, padding is applied + # by concating zero-elements rather than setting it in the avg_pool op. + if count_include_pad or divisor_override is not None: + tosa_padding = (0, 0, 0, 0) + # Otherwise, calculate the padding as done in the node visitor + else: + post_pad_h = adjust_pooling_pad_if_needed( + shape[2], kernel[0], stride[0], padding[0], ceil_mode + ) + post_pad_w = adjust_pooling_pad_if_needed( + shape[3], kernel[1], stride[1], padding[1], ceil_mode + ) + tosa_padding = (padding[0], post_pad_h, padding[1], post_pad_w) + + if not all(1 <= k <= 8 for k in kernel) and not all( + v == 0 for v in tosa_padding + ): + self.reporter.report_reject( + node, f"Avgpool2d with padding needs kernel dims < 8, got {kernel}" + ) + return False + + if not kernel_check(kernel): + self.reporter.report_reject( + node, + f"Avgpool2d needs kernel_y < 256, kernel_x*kernel_y<=65536, got {kernel}", + ) + return False + + if not dim_check(shape): + self.reporter.report_reject( + node, + f"Avgpool2d needs N == 1, rest dims <= 65536, got shape {list(shape)}", + ) + return False + if not stride_check(stride): + self.reporter.report_reject( + node, f"Avgpool2d needs stride <= 3, got {stride}" + ) + return False + if not shape[0] == 1: + self.reporter.report_reject( + node, f"Avgpool2d needs N==1, got N=={shape[0]}" + ) + return False + return True + + +@register_tosa_support_check +class MaxPool2dSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support checks for ``aten.max_pool2d_with_indices``. + + Applies additional constraints when targeting the U55 subset, including + limits on kernel size, stride, and tensor ranks. + + """ + + targets = [ + exir_ops.edge.aten.max_pool2d_with_indices.default, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported(self, node: fx.Node, tosa_spec: TosaSpecification): + """Return True if ``max_pool2d_with_indices`` satisfies U55 + constraints. + """ + if not tosa_spec.is_U55_subset: + return True + + # U55 case, Vela 4.2.0 (25.02 release) + shape = cast(torch.Tensor, node.all_input_nodes[0].meta["val"]).shape + kernel = cast(tuple[int, int], node.args[1]) + stride = cast(tuple[int, int], node.args[2]) + + if not kernel_check(kernel): + self.reporter.report_reject( + node, + f"Maxpool2d needs kernel_y < 256, kernel_x*kernel_y<=65536, got {kernel}", + ) + return False + if not dim_check(shape): + self.reporter.report_reject( + node, + f"Maxpool2d needs N == 1, rest dims <= 65536, got shape {list(shape)}", + ) + return False + if not stride_check(stride): + self.reporter.report_reject( + node, f"Maxpool2d needs stride <= 3, got {stride}" + ) + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/reduce_sum_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/reduce_sum_support.py new file mode 100644 index 0000000..02e9e0d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/reduce_sum_support.py @@ -0,0 +1,76 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.sum.dim_IntList`` in TOSA. + +Provide shape constraints for U55 subsets; otherwise allow reductions. + +""" +from typing import cast + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class SumSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for sum over dimensions.""" + + targets = [exir_ops.edge.aten.sum.dim_IntList] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + On U55 subsets, enforce bounds on the reduced dimension and the products + of sizes before/after the reduction axis. On other targets, accept the + operation unconditionally. + + """ + if not tosa_spec.is_U55_subset: + return True + + # U55 case, Vela 4.2.0 (25.02 release) + input_shape = node.all_input_nodes[0].meta["val"].shape + + if node.args[1] is None: + # Dim is allowed to be None, which means to sum all dimensions + dim_list = list(range(len(input_shape))) + else: + dim_list = cast(list[int], node.args[1]) + dim_list = [dim % len(input_shape) for dim in dim_list] + + for dim in dim_list: + if not 1 <= input_shape[dim] <= 65536: + self.reporter.report_reject( + node, f"sum needs dims < 65536, got shape {input_shape}" + ) + return False + + # We can't be certain of which dim is the last in memory yet, + # Always go for stricter condition. + pre_R_product = 1.0 + for length in input_shape[:dim]: + pre_R_product *= length + post_R_product = 1.0 + for length in input_shape[dim + 1 :]: + post_R_product *= length + if not 1 <= pre_R_product <= 65536: + self.reporter.report_reject(node, "Failed dim check") + return False + if not 1 <= post_R_product <= 65536: + self.reporter.report_reject(node, "Failed dim check") + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/right_shift_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/right_shift_support.py new file mode 100644 index 0000000..7670ede --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/right_shift_support.py @@ -0,0 +1,52 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for bitwise right-shift in TOSA. + +Provide support checks for ``aten.bitwise_right_shift`` and ``__rshift__`` +targets across integer and float TOSA profiles. + +""" + + +import logging + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + + +@register_tosa_support_check +class RightShiftSupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for right-shift operations.""" + + targets = [ + exir_ops.edge.aten.bitwise_right_shift.Tensor, + exir_ops.edge.aten.__rshift__.Scalar, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Emit a warning on U55 subsets where one-off errors may occur. Otherwise + accept all matching targets. + + """ + # TODO MLETORCH-525 Remove warning + if tosa_spec.is_U55_subset: + logger.warning(f"{node.target} may introduce one-off errors.") + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/slice_copy_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/slice_copy_support.py new file mode 100644 index 0000000..77f3e97 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/slice_copy_support.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``aten.slice_copy`` in TOSA. + +Support slicing with unit step only; emit a warning and reject otherwise. + +""" + +import logging + +import torch.fx as fx +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + + +@register_tosa_support_check +class SliceCopySupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``aten.slice_copy``.""" + + targets = [exir_ops.edge.aten.slice_copy.Tensor] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + """Return True if the node is supported by TOSA. + + Accept slice_copy when the step is 1 (or unspecified). Warn and reject + non-unit step sizes. + + """ + args = node.args + if len(args) == 5 and (step := args[4]) != 1: + logger.warning(f"{node.target} with step size of {step} not supported.") + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/to_dim_order_copy_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/to_dim_order_copy_support.py new file mode 100644 index 0000000..bd600a4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/to_dim_order_copy_support.py @@ -0,0 +1,200 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Declare operator support for ``_to_dim_order_copy`` in TOSA. + +Provide dtype-compatibility checks for casting when converting to a specific +dimension order. Supported input/output dtype pairs depend on the active TOSA +profile (integer and/or float). + +""" + +import copy +import logging + +import torch + +import torch.fx as fx + +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + +logger = logging.getLogger(__name__) + +SupportedTypeDict = dict[torch.dtype, list[torch.dtype]] + + +@register_tosa_support_check +class ToCopySupported(SupportedTOSAOperatorCheck): + """Provide TOSA support check for ``_to_dim_order_copy``. + + Attributes: + SUPPORTED_INT_PROFILE_DTYPES (dict[torch.dtype, list[torch.dtype]]): + Allowed output dtypes for each integer input dtype. + SUPPORTED_FP_PROFILE_DTYPES (dict[torch.dtype, list[torch.dtype]]): + Allowed output dtypes for each floating input dtype. + + """ + + targets = [ + exir_ops.edge.dim_order_ops._to_dim_order_copy.default, + ] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + @staticmethod + def _merge_supported_types( + dtypes1: SupportedTypeDict, + dtypes2: SupportedTypeDict, + ) -> SupportedTypeDict: + """Return a merged mapping of supported dtype transitions. + + Args: + dtypes1 (dict[torch.dtype, list[torch.dtype]]): Base mapping. + dtypes2 (dict[torch.dtype, list[torch.dtype]]): Mapping to merge in. + + Returns: + dict[torch.dtype, list[torch.dtype]]: Combined mapping. + + """ + merged_dtypes = copy.deepcopy( + dtypes1 + ) # Use deepcopy to avoid unintentionally modifying SUPPORTED_INT_PROFILE_DTYPES + for k, v in dtypes2.items(): + merged_dtypes[k] = merged_dtypes.get(k, []) + v + return merged_dtypes + + SUPPORTED_INT_PROFILE_DTYPES: SupportedTypeDict = { + torch.bool: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int8: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int16: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int32: [torch.bool, torch.int8, torch.int16, torch.int32], + torch.int64: [torch.bool, torch.int8, torch.int16, torch.int32], + } + SUPPORTED_FP_PROFILE_DTYPES: SupportedTypeDict = { + torch.int8: [torch.int8, torch.float16, torch.bfloat16, torch.float32], + torch.int16: [torch.int16, torch.float16, torch.bfloat16, torch.float32], + torch.int32: [torch.int32, torch.float16, torch.bfloat16, torch.float32], + # INT64 inputs to casts *should* be ok, since they should be rejected by + # CheckInt64InputsAndOutputs if the cast can't be done AOT. + torch.int64: [ + torch.int8, + torch.int16, + torch.int32, + torch.float16, + torch.bfloat16, + torch.float32, + ], + torch.bfloat16: [ + torch.int8, + torch.int16, + torch.int32, + torch.bfloat16, + torch.float32, + ], + torch.float16: [ + torch.int8, + torch.int16, + torch.int32, + torch.float16, + torch.float32, + ], + torch.float32: [ + torch.float32, + torch.int8, + torch.int16, + torch.int32, + torch.bfloat16, + torch.float16, + torch.float32, + ], + } + SUPPORTED_INT_FP_PROFILE_DTYPES: SupportedTypeDict = { + torch.bool: [torch.float32], + } + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Return True if the node is supported by TOSA. + + Check FakeTensor metadata, validate input dtype is supported for the + active profile, and ensure the output dtype is allowed for the given + input dtype. + + """ + supported_dtypes: SupportedTypeDict = {} + if tosa_spec.support_integer(): + supported_dtypes = self._merge_supported_types( + self.SUPPORTED_INT_PROFILE_DTYPES, supported_dtypes + ) + if tosa_spec.support_float(): + supported_dtypes = self._merge_supported_types( + self.SUPPORTED_FP_PROFILE_DTYPES, supported_dtypes + ) + if tosa_spec.support_integer() and tosa_spec.support_float(): + supported_dtypes = self._merge_supported_types( + self.SUPPORTED_INT_FP_PROFILE_DTYPES, supported_dtypes + ) + + if len(node.all_input_nodes) != 1: + self.reporter.report_reject( + node, + ( + "Expected exactly one input node, " + f"got {len(node.all_input_nodes)} for {node.target}." + ), + ) + return False + input_val = node.all_input_nodes[0].meta["val"] + if not isinstance(input_val, torch._subclasses.FakeTensor): + self.reporter.report_reject( + node, + ( + "Invalid or missing meta: expected FakeTensor input, got " + f"{type(input_val).__name__} for {node.target}." + ), + ) + return False + + # Check input type + input_dtype = input_val.dtype + if input_dtype not in supported_dtypes: + self.reporter.report_reject( + node, + f"Input dtype {input_val.dtype} is not supported in {node.target}.", + ) + return False + + # Check output type + output_val = node.meta["val"] + if not isinstance(output_val, torch._subclasses.FakeTensor): + self.reporter.report_reject( + node, + ( + "Invalid or missing meta: expected FakeTensor output, got " + f"{type(output_val).__name__} for {node.target}." + ), + ) + return False + if output_val.dtype not in supported_dtypes[input_dtype]: + self.reporter.report_reject( + node, + ( + f"Output dtype {output_val.dtype} is not supported in " + f"{node.target} for input dtype {input_dtype}. " + f"Supported output types: " + f"{', '.join(str(t) for t in supported_dtypes[input_dtype])}" + ), + ) + return False + + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_profile_supported_op_lists.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_profile_supported_op_lists.py new file mode 100644 index 0000000..46a92fe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_profile_supported_op_lists.py @@ -0,0 +1,251 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Define TOSA profile support lists for INT and FP. + +Expose static sets of EXIR operator overloads used by the TOSA partitioner to +seed positive support checks for different profiles. + +""" + +import operator +from typing import Final, Set + +import torch + +from executorch.exir.dialects._ops import ops as exir_ops + + +# INT profile: ops supported via native TOSA ops, decompositions/transformations, precompute, TableOps, etc. +# Note that ops supported via pre-quantization decompositions are not included here. +TOSA_PRO_INT_SupportList: Final[Set] = { + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.any.default, + exir_ops.edge.aten.any.dim, + exir_ops.edge.aten.any.dims, + exir_ops.edge.aten.bitwise_and.Tensor, + exir_ops.edge.aten.bitwise_or.Tensor, + exir_ops.edge.aten.bitwise_xor.Tensor, + exir_ops.edge.aten.bitwise_and.Scalar, + exir_ops.edge.aten.bitwise_or.Scalar, + exir_ops.edge.aten.bitwise_xor.Scalar, + exir_ops.edge.aten.cos.default, + exir_ops.edge.aten.logical_and.default, + exir_ops.edge.aten.logical_or.default, + exir_ops.edge.aten.logical_xor.default, + exir_ops.edge.aten.logical_not.default, + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.clamp.Tensor, + exir_ops.edge.aten.cumsum.default, + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.permute_copy.default, + exir_ops.edge.aten.hardsigmoid.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.hardswish.default, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.erf.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.expm1.default, + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.log1p.default, + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.split_with_sizes_copy.default, + exir_ops.edge.aten.split_copy.Tensor, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.sigmoid.default, + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.repeat.default, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.remainder.Tensor, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.select_copy.int, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.tanh.default, + exir_ops.edge.aten.upsample_bilinear2d.vec, + exir_ops.edge.aten.upsample_nearest2d.vec, + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.unsqueeze_copy.default, + exir_ops.edge.aten.squeeze_copy.dims, + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.pow.Tensor_Tensor, + operator.getitem, + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.quantize_per_channel.default, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.dequantize_per_channel.default, + exir_ops.edge.aten.constant_pad_nd.default, + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + exir_ops.edge.aten.eye.default, + exir_ops.edge.aten.linspace.default, + exir_ops.edge.aten.bitwise_left_shift.Tensor, + exir_ops.edge.aten.__lshift__.Scalar, + torch.ops.aten.scalar_tensor.default, + exir_ops.edge.aten.gelu.default, + exir_ops.edge.aten.alias_copy.default, + exir_ops.edge.aten.sin.default, + exir_ops.edge.aten.sinh.default, + exir_ops.edge.aten.atan.default, + exir_ops.edge.aten.acosh.default, + exir_ops.edge.aten._adaptive_avg_pool2d.default, + exir_ops.edge.aten.sign.default, + exir_ops.edge.aten.asin.default, + exir_ops.edge.aten.atanh.default, + exir_ops.edge.aten.masked_fill.Scalar, + exir_ops.edge.aten.asinh.default, + exir_ops.edge.aten.cosh.default, + exir_ops.edge.aten.acos.default, + exir_ops.edge.aten.elu.default, + exir_ops.edge.aten.bitwise_not.default, + exir_ops.edge.aten.copy.default, + exir_ops.edge.aten.tan.default, +} + + +# FP profile: ops supported via native TOSA ops, decompositions/transformations, precompute, etc. +TOSA_PRO_FP_SupportList: Final[Set] = { + exir_ops.edge.aten.abs.default, + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.any.default, + exir_ops.edge.aten.any.dim, + exir_ops.edge.aten.any.dims, + exir_ops.edge.aten.logical_and.default, + exir_ops.edge.aten.logical_or.default, + exir_ops.edge.aten.logical_xor.default, + exir_ops.edge.aten.logical_not.default, + exir_ops.edge.aten.arange.start_step, + exir_ops.edge.aten.expand_copy.default, + exir_ops.edge.aten.cat.default, + exir_ops.edge.aten.ceil.default, + exir_ops.edge.aten.clamp.default, + exir_ops.edge.aten.clamp.Tensor, + exir_ops.edge.aten.cos.default, + exir_ops.edge.aten.cumsum.default, + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.permute_copy.default, + exir_ops.edge.aten.hardsigmoid.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.hardswish.default, + exir_ops.edge.aten.div.Tensor, + exir_ops.edge.aten.div.Tensor_mode, + exir_ops.edge.aten.eq.Tensor, + exir_ops.edge.aten.eq.Scalar, + exir_ops.edge.aten.erf.default, + exir_ops.edge.aten.exp.default, + exir_ops.edge.aten.expm1.default, + exir_ops.edge.aten.log1p.default, + exir_ops.edge.aten.log.default, + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.split_with_sizes_copy.default, + exir_ops.edge.aten.split_copy.Tensor, + exir_ops.edge.aten.floor.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.ge.Tensor, + exir_ops.edge.aten.ge.Scalar, + exir_ops.edge.aten.gt.Tensor, + exir_ops.edge.aten.gt.Scalar, + exir_ops.edge.aten.le.Tensor, + exir_ops.edge.aten.le.Scalar, + exir_ops.edge.aten.lt.Tensor, + exir_ops.edge.aten.lt.Scalar, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.ne.Tensor, + exir_ops.edge.aten.ne.Scalar, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.add.Scalar, + exir_ops.edge.aten.sub.Scalar, + exir_ops.edge.aten.mul.Scalar, + exir_ops.edge.aten.div.Scalar, + exir_ops.edge.aten._native_batch_norm_legit_no_training.default, + exir_ops.edge.aten.native_layer_norm.default, + exir_ops.edge.aten.native_group_norm.default, + exir_ops.edge.aten.sigmoid.default, + exir_ops.edge.aten.mean.dim, + exir_ops.edge.aten.mean.default, + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.minimum.default, + exir_ops.edge.aten.maximum.default, + exir_ops.edge.aten.repeat.default, + exir_ops.edge.aten.reciprocal.default, + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.remainder.Scalar, + exir_ops.edge.aten.remainder.Tensor, + exir_ops.edge.aten.leaky_relu.default, + exir_ops.edge.aten.sqrt.default, + exir_ops.edge.aten.rsqrt.default, + exir_ops.edge.aten.round.default, + exir_ops.edge.aten._softmax.default, + exir_ops.edge.aten.select_copy.int, + exir_ops.edge.aten._log_softmax.default, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.tanh.default, + exir_ops.edge.aten.upsample_bilinear2d.vec, + exir_ops.edge.aten.upsample_nearest2d.vec, + exir_ops.edge.aten.var.correction, + exir_ops.edge.aten.var.dim, + exir_ops.edge.aten.view_copy.default, + exir_ops.edge.aten.unsqueeze_copy.default, + exir_ops.edge.aten.squeeze_copy.dims, + exir_ops.edge.aten.pow.Tensor_Scalar, + exir_ops.edge.aten.pow.Tensor_Tensor, + operator.getitem, + exir_ops.edge.aten.constant_pad_nd.default, + exir_ops.edge.aten.amax.default, + exir_ops.edge.aten.amin.default, + exir_ops.edge.aten.eye.default, + exir_ops.edge.aten.linspace.default, + exir_ops.edge.aten.bitwise_left_shift.Tensor, + exir_ops.edge.aten.__lshift__.Scalar, + torch.ops.aten.scalar_tensor.default, + exir_ops.edge.aten.gelu.default, + exir_ops.edge.aten.alias_copy.default, + exir_ops.edge.aten.sin.default, + exir_ops.edge.aten.sinh.default, + exir_ops.edge.aten.atan.default, + exir_ops.edge.aten.acosh.default, + exir_ops.edge.aten._adaptive_avg_pool2d.default, + exir_ops.edge.aten.sign.default, + exir_ops.edge.aten.asin.default, + exir_ops.edge.aten.atanh.default, + exir_ops.edge.aten.addmm.default, + exir_ops.edge.aten.masked_fill.Scalar, + exir_ops.edge.aten.asinh.default, + exir_ops.edge.aten.cosh.default, + exir_ops.edge.aten.glu.default, + exir_ops.edge.aten.logit.default, + exir_ops.edge.aten.acos.default, + exir_ops.edge.aten.elu.default, + exir_ops.edge.aten.copy.default, + exir_ops.edge.aten.floor_divide.default, + exir_ops.edge.aten.tan.default, +} + + +__all__ = [ + "TOSA_PRO_INT_SupportList", + "TOSA_PRO_FP_SupportList", +] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_supported_operators.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_supported_operators.py new file mode 100644 index 0000000..9240f14 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/tosa_supported_operators.py @@ -0,0 +1,748 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide operator-support checks and registries for TOSA delegation. + +Define a base check class, a registry/dispatcher, and several generic checks +used by the TOSA partitioner to decide if FX nodes are eligible for delegation. + +""" + + +import itertools +import operator +import typing +from typing import final, Optional, Sequence, Type + +import torch +import torch.fx as fx + +from executorch.backends.arm._passes.arm_pass_utils import ( + get_first_fake_tensor, + is_submodule_node, +) +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, +) +from executorch.backends.arm._passes.fuse_quantized_activation_pass import ( + FuseQuantizedActivationPass, +) +from executorch.backends.arm._passes.insert_table_ops import TableOps +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.constants import DQ_OPS, MAX_RANK, Q_OPS +from executorch.backends.arm.operator_support.control_flow_support import ( + ControlFlowOpSupported, + ControlFlowSubmoduleSupported, +) +from executorch.backends.arm.operator_support.ethos_u55_support import ( + EthosU55CastCheck, + EthosU55DtypeSupport, + EthosU55NotSupported, + EthosU55TransposeCheck, + EthosU55ViewCheck, +) +from executorch.backends.arm.operator_support.tosa_profile_supported_op_lists import ( + TOSA_PRO_FP_SupportList, + TOSA_PRO_INT_SupportList, +) +from executorch.backends.arm.tosa.specification import ( + TosaSpecification, + TosaSpecMapping, +) +from executorch.exir import ExportedProgram +from executorch.exir.backend.utils import WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops + +from torch._subclasses.fake_tensor import FakeTensor +from torch.export.graph_signature import InputKind +from torch.fx.passes.operator_support import any_chain, chain, OperatorSupportBase +from torch.fx.passes.utils.source_matcher_utils import get_source_partitions + + +class SupportedTOSAOperatorCheck(OperatorSupportBase): + """Provide a base operator-support check for TOSA lowering. + + Subclasses should implement :py:meth:`is_node_tosa_supported` and declare + the class attributes below to indicate what they support. + + Attributes: + targets (list[OpOverload]): Operator overloads supported by this + check. + tosa_specs (list[TosaSpecification]): TOSA specs where the check is + applicable. + + """ + + def __init__(self, tosa_spec: TosaSpecification, reporter: WhyNoPartitionReporter): + """Initialize the check with a TOSA spec and reporter. + + Args: + tosa_spec (TosaSpecification): Active TOSA specification. + reporter (WhyNoPartitionReporter): Reporter for rejection reasons. + + """ + self.tosa_spec = tosa_spec + self.reporter = reporter + + # Class attributes populated by subclasses + tosa_specs: list[TosaSpecification] = [] + targets: list[str] = [] + + @final + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node matches targets and subclass-specific checks. + + Args: + submodules (typing.Mapping[str, torch.nn.Module]): Exported program + modules. + node (fx.Node): Node to evaluate. + + Returns: + bool: True if both the target and TOSA-specific checks pass. + + """ + if node.target not in self.targets: + return False + return self.is_node_tosa_supported(node, self.tosa_spec) + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: + """Check if the node is lowerable under the given TOSA spec. + + Args: + node (fx.Node): FX node to check. + tosa_spec (TosaSpecification): Active TOSA specification. + + Returns: + bool: True if supported; otherwise, False. + + """ + raise NotImplementedError("SupportedTOSAOperatorCheck must be extended.") + + +# container for all SupportedTosaOperatorCheck classes +_tosa_spec_support: TosaSpecMapping[Type[SupportedTOSAOperatorCheck]] = ( + TosaSpecMapping() +) + + +def register_tosa_support_check(checker: Type[SupportedTOSAOperatorCheck]): + """Register an operator-support checker for one or more TOSA specs. + + Decorate subclasses of :py:class:`SupportedTOSAOperatorCheck` so they are + picked up by the factory and partitioner for the specs declared in their + ``tosa_specs`` class attribute. + + Args: + checker (Type[SupportedTOSAOperatorCheck]): Checker class to register. + + """ + for tosa_spec in checker.tosa_specs: + _tosa_spec_support.add(tosa_spec, checker) + return checker + + +def _is_integer_dtype(dtype: torch.dtype) -> bool: + return not dtype.is_floating_point and not dtype.is_complex + + +def _is_quantized_constant(node: torch.fx.Node) -> bool: + if node.target not in ( + exir_ops.edge.aten.full_like.default, + *ComputeConstantOpsAOTPass.targeted_ops, + ): + return False + + users = tuple(node.users) + if users and all(user.target in Q_OPS for user in users): + # The node feeds directly into only quantized ops. + return True + + for user in users: + if user.target == exir_ops.edge.dim_order_ops._to_dim_order_copy.default: + dim_order_dtype = get_first_fake_tensor(user).dtype + if not _is_integer_dtype(dim_order_dtype): + return False + else: + return False + + return len(users) > 0 + + +def is_quantized(node: torch.fx.Node) -> bool: + """Checks if the node is quantized. + + A node is considered quantized if any of the following is true: + - Its output dtype is not floating point or complex => integer + - It is an op that produces a constant that in turn feeds only quantized users + - It has been marked as quantized in the ArmAnnotationInfo custom meta. + + Args: + node (torch.fx.Node): The FX node to check. + + Returns: + bool: True if the node is quantized, False otherwise. + """ + + try: + node_dtype = get_first_fake_tensor(node).dtype + # Integer-like dtype implies the node is already quantized as long + # as inputs are not floating-point. + if _is_integer_dtype(node_dtype): + input_nodes = node.all_input_nodes + input_nodes_dtypes = [ + get_first_fake_tensor(input_node).dtype for input_node in input_nodes + ] + if all( + _is_integer_dtype(input_node_dtype) + for input_node_dtype in input_nodes_dtypes + ): + return True + + except TypeError: + # Could not determine dtype, fall back to other checks. + pass + + # Nodes introduced during lowering that exclusively feed quantized users. + if _is_quantized_constant(node): + return True + + # Finally, fall back to the explicit annotation emitted by Arm passes. + custom_meta = node.meta.get("custom", {}) + if ArmAnnotationInfo.CUSTOM_META_KEY in custom_meta: + return custom_meta[ArmAnnotationInfo.CUSTOM_META_KEY]["quantized"] + + return False + + +def get_registered_tosa_support_checks( + tosa_spec: TosaSpecification, +) -> list[Type[SupportedTOSAOperatorCheck]]: + """Get all registered operator-support checkers for a given spec. + + Args: + tosa_spec (TosaSpecification): TOSA spec to query. + + Returns: + list[Type[SupportedTOSAOperatorCheck]]: Registered checker classes. + + """ + checks = _tosa_spec_support.get(tosa_spec) + if not checks: + raise RuntimeError( + f"TOSA specification not valid: {tosa_spec} not in {list(_tosa_spec_support._mapping.keys())}" + ) + return checks + + +def tosa_support_factory( + tosa_spec: TosaSpecification, + exported_program: ExportedProgram, + reporter: WhyNoPartitionReporter, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, +) -> OperatorSupportBase: + """Create an OperatorSupport composite for a TOSA spec. + + Combine profile-specific positive checks, registered operator checks, and + negative checks into a single :py:class:`OperatorSupportBase` chain. + + Args: + tosa_spec (TosaSpecification): Active TOSA specification. + exported_program (ExportedProgram): Program context for checks. + reporter (WhyNoPartitionReporter): Reporter for rejections. + additional_checks (Optional[Sequence[OperatorSupportBase]]): Extra + negative checks to apply. + + Returns: + OperatorSupportBase: Composite checker for the given spec. + + """ + # Postive checks: Add nodes to partitioning + positive_checks: list[OperatorSupportBase] = [ + ControlFlowSubmoduleSupported(exported_program, tosa_spec, reporter), + ControlFlowOpSupported(exported_program, tosa_spec, reporter), + ] + + if tosa_spec.support_integer() and tosa_spec.support_float(): + positive_checks.append(TOSAProINTFPSupportList()) + elif tosa_spec.support_integer(): + positive_checks.append(TOSAProINTSupportList()) + elif tosa_spec.support_float(): + positive_checks.append(TOSAProFPSupportList()) + # TODO: Refactor to use TOSAProSupportLists + negtive checks + positive_checks += [ + check(tosa_spec, reporter) + for check in get_registered_tosa_support_checks(tosa_spec) + ] + + # Negative checks: Remove nodes from partitioning + negative_checks: list[OperatorSupportBase] = [ + CheckInt64InputsAndOutputs(exported_program, reporter), + CheckFloat64Inputs(exported_program, reporter), + RankCheck(reporter, max_rank=MAX_RANK), + *[ + reporter.wrap_check(check, f"Rejected by {check.__class__.__name__}") + for check in (additional_checks if additional_checks else []) + ], + ] + + if not tosa_spec.support_float(): + negative_checks.append(CheckArmQuantized(reporter)) + negative_checks.append(CheckProperQuantization(reporter)) + if tosa_spec.is_U55_subset: + negative_checks.append(EthosU55NotSupported(reporter)) + negative_checks.append(EthosU55DtypeSupport(reporter)) + negative_checks.append(EthosU55TransposeCheck(reporter)) + negative_checks.append(EthosU55ViewCheck(reporter)) + negative_checks.append(EthosU55CastCheck(reporter)) + + return chain( + reporter.wrap_check( + any_chain(*positive_checks), + "Not included in BaseTOSASupportList or a registered tosa_support_check", + ), + *negative_checks, + ) + + +class TOSAProINTSupportList(OperatorSupportBase): + """Provide the INT profile support list for TOSA. + + TOSA_PRO_INT_SupportList enumerates ops supported in the INT profile via + native TOSA ops, decompositions, pre-compute steps, or TableOps. + + Note: + Ops supported via pre-quantization decompositions are not included + here. + + """ + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node is in the INT profile support list.""" + return node.op == "call_function" and node.target in TOSA_PRO_INT_SupportList + + +class TOSAProFPSupportList(OperatorSupportBase): + """Provide the FP profile support list for TOSA. + + Includes ops supported natively, via decomposition/transformation, and pre- + compute. + + """ + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node is in the FP profile support list.""" + return node.op == "call_function" and node.target in TOSA_PRO_FP_SupportList + + +class TOSAProINTFPSupportList(OperatorSupportBase): + """ + TOSA_PRO_INT_FP_SupportList: + Ops supported in INT+FP profile via native TOSA ops, decomposition/transformation, pre-compute, or TableOp. + """ + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + if node.op != "call_function": + return False + + # Select list based on whether the node is quantized. + if is_quantized(node) or node.target in (*Q_OPS, *DQ_OPS): + support_list = TOSA_PRO_INT_SupportList + else: + support_list = TOSA_PRO_FP_SupportList + + return node.target in support_list + + +class CheckArmQuantized(OperatorSupportBase): + """ + Check if the node was marked as quantized in the Arm backend. + This is used to ensure that nodes that were quantized in the Arm backend + are only partitioned if they are supported by the TOSA backend. + """ + + def __init__(self, reporter: WhyNoPartitionReporter): + self.reporter = reporter + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + + if node.target in (*DQ_OPS, *Q_OPS): + return True + + if not is_quantized(node): + self.reporter.report_reject( + node, "Node was not marked as quantized in the Arm backend." + ) + return False + return True + + +class CheckProperQuantization(OperatorSupportBase): + """Ensure targeted nodes are properly quantized. + + Verify that a pair of quantize/dequantize nodes surrounds targeted ops so + rescaling and table operators behave correctly. + + """ + + targeted_ops = ( + exir_ops.edge.aten.add.Tensor, + exir_ops.edge.aten.avg_pool2d.default, + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.convolution.default, + exir_ops.edge.aten.full.default, + exir_ops.edge.aten.full_like.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.max_pool2d_with_indices.default, + exir_ops.edge.aten.mm.default, + exir_ops.edge.aten.mul.Tensor, + exir_ops.edge.aten.neg.default, + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.sub.Tensor, + exir_ops.edge.aten.upsample_bilinear2d.vec, + exir_ops.edge.aten.upsample_nearest2d.vec, + torch.ops.aten.scalar_tensor.default, + exir_ops.edge.aten.mean.dim, + *TableOps.included_ops(), + ) + + def __init__(self, reporter: WhyNoPartitionReporter): + """Initialize the check with a reporter.""" + self.reporter = reporter + + def _is_matmul_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ): + """Check quantization for decomposed matmul partitions. + + Handles an edge case where the quantized pipeline + `dq -> torch.matmul/operator.matmul -> q` decomposes into + `dq -> expand -> view -> aten.mm -> view -> q`. + + Args: + submodules (Mapping[str, torch.nn.Module]): Map of child modules to + inspect for matmul partitions. + node (fx.Node): Node that should belong to a quantized matmul + partition. + + Returns: + bool: True if the matched partition uses quantized inputs and + outputs. + + """ + for graph_module in submodules.values(): + graph_module = typing.cast(fx.GraphModule, graph_module) + matmul_partitions_map = get_source_partitions( + graph_module.graph, + [ + torch.matmul, + operator.matmul, + ], + None, + ) + matmul_partitions = list( + itertools.chain.from_iterable(matmul_partitions_map.values()) + ) + matched_partition = None + for partition in matmul_partitions: + if node in partition.nodes: + matched_partition = partition + if matched_partition is not None: + input_quantized = all( + input_node.target in DQ_OPS + for input_node in matched_partition.input_nodes + ) + if not input_quantized: + self.reporter.report_reject( + node, "One or more matmul inputs were not quantized." + ) + return False + output_quantized = all( + output_node_user.target in Q_OPS + for output_node_user in matched_partition.output_nodes[0].users + ) + if not output_quantized: + self.reporter.report_reject( + node, "One or more matmul outputs were not quantized." + ) + return False + else: + self.reporter.report_reject( + node, "Node did not match any matmul source partition." + ) + return False + + return True + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if the node passes constant-cast and multi-output checks. + + Ensures decomposition-specific matmul partitions keep quantized inputs + and outputs. + + """ + output_quantized = False + input_quantized = False + if node.target not in self.targeted_ops: + return True + elif node.target in ( + exir_ops.edge.aten.bmm.default, + exir_ops.edge.aten.mm.default, + ): + source_fn_stack: tuple[typing.Any] = node.meta.get("source_fn_stack", []) + if len(source_fn_stack) > 0: + if source_fn_stack[-1][1] in (torch.matmul, operator.matmul): + return self._is_matmul_node_supported(submodules, node) + + elif node.target in (exir_ops.edge.aten.max_pool2d_with_indices.default,): + users = node.users + output_quantized = all( + user.target == operator.getitem + and all(user_user.target in Q_OPS for user_user in user.users) + for user in users + ) + elif FuseQuantizedActivationPass._is_fuseable_input(node): + users = node.users + output_quantized = all( + FuseQuantizedActivationPass._is_fuseable_quantized_activation(user) + for user in users + ) + elif FuseQuantizedActivationPass._is_fuseable_quantized_activation(node): + input_node = node.all_input_nodes[0] + input_quantized = FuseQuantizedActivationPass._is_fuseable_input(input_node) + + input_quantized = input_quantized or all( + (input_node.target in DQ_OPS) + or _is_integer_dtype(get_first_fake_tensor(input_node).dtype) + for input_node in node.all_input_nodes + ) + + if not input_quantized: + self.reporter.report_reject(node, "One or more inputs were not quantized.") + return False + + all_q_users = all((output_node.target in Q_OPS) for output_node in node.users) + output_dtype = get_first_fake_tensor(node).dtype + output_quantized = ( + output_quantized or all_q_users or _is_integer_dtype(output_dtype) + ) + + if not output_quantized: + self.reporter.report_reject(node, "One or more outputs were not quantized.") + return False + return True + + +class CheckInt64InputsAndOutputs(OperatorSupportBase): + """Reject general int64 tensors while allowing safe exceptions. + + Exceptions are: + - Nodes with contant int64 output within int32 range that are cast away + from int64 by all users. + - Int64 output where all users are getitem nodes with non-int64 outputs. + In this case there are multiple outputs and the int64 output is unused. + - Nodes where all inputs are int64 constant placeholders or constant ops + that fulfill the above exceptions. + + """ + + def __init__( + self, exported_program: ExportedProgram, reporter: WhyNoPartitionReporter + ): + """Initialize the check with program context and reporter.""" + self.input_names = [ + spec.arg.name + for spec in exported_program.graph_signature.input_specs + if spec.kind == InputKind.USER_INPUT + ] + self.reporter = reporter + self.int32_min = torch.iinfo(torch.int32).min + self.int32_max = torch.iinfo(torch.int32).max + super().__init__() + + def inside_int32_bounds(self, node: torch.fx.Node) -> bool: + """Node is assumed to be call_function with int64 output.""" + if isinstance(node.target, str): + return False + data = node.target(*node.args, **node.kwargs) + min_val, max_val = int(torch.min(data)), int(torch.max(data)) + return min_val >= self.int32_min and max_val <= self.int32_max + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True when int64 use is absent or safe per exceptions.""" + if is_submodule_node(node): + return True + vals = node.meta["val"] + tensor_list = vals if isinstance(vals, (list, tuple)) else [vals] + + any_int64 = any(tensor.dtype == torch.int64 for tensor in tensor_list) + # Don't partition nodes with int64 output... + if any_int64: + # ... Except for constant ops that are directly cast to something non-int64. + # This could be an explicit cast, or something like a less than that outputs a different dtype than the input. + users_output_non_int64 = all( + get_first_fake_tensor(output_node).dtype != torch.int64 + for output_node in node.users + ) + if ( + node.target in ComputeConstantOpsAOTPass.targeted_ops + and users_output_non_int64 + ): + if not self.inside_int32_bounds(node): + self.reporter.report_reject( + node, "Constant node outside int32 range." + ) + return False + # Will never have input nodes, safe to return True + return True + + # ... Or ops with multiple outputs where only non-int64 are used. + users_are_getitem = all( + user.target == operator.getitem for user in node.users + ) + if users_are_getitem and users_output_non_int64: + # Passed output check, go to input check. + pass + else: + self.reporter.report_reject( + node, "Non-constant node with int64 output." + ) + return False + + # Ops with int64 inputs are only partitioned if input nodes are constant and will be partitioned. + # If it is not partitioned, the partition will get an int64 input and fail. + for input_node in ( + input_node + for input_node in node.all_input_nodes + if input_node.op != "get_attr" + ): + tensor_in = get_first_fake_tensor(input_node) + if tensor_in.dtype != torch.int64: + continue + # Constant placeholder + if ( + input_node.op != "call_function" + and input_node.name not in self.input_names + ): + continue + # Constant operator + if input_node.op == "call_function": + if input_node.target in ComputeConstantOpsAOTPass.targeted_ops: + # This is not perfect since the input_node can still be rejected by other checks but + # this should cover the majority of cases. + if self.is_node_supported({}, input_node): + continue + self.reporter.report_reject( + node, f"Non-constant int64 input {input_node.name}" + ) + return False + + return True + + +class CheckFloat64Inputs(OperatorSupportBase): + """Reject nodes with float64 inputs. + + Useful as a negative check for specs that do not allow float64. + + """ + + def __init__( + self, exported_program: ExportedProgram, reporter: WhyNoPartitionReporter + ): + """Initialize the check with program context and reporter.""" + self.reporter = reporter + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if no float64 inputs are present.""" + if is_submodule_node(node): + return True + for input_node in ( + input_node + for input_node in node.all_input_nodes + if input_node.op != "get_attr" + ): + tensor = get_first_fake_tensor(input_node) + if tensor.dtype == torch.float64: + self.reporter.report_reject( + node, + f"Had float64 input {input_node.name} that couldn't be handled.", + ) + return False + return True + + +class RankCheck(OperatorSupportBase): + """Reject nodes with rank greater than ``max_rank``.""" + + def __init__(self, reporter: WhyNoPartitionReporter, max_rank: int): + """Initialize the check with a reporter and maximum rank.""" + self.reporter = reporter + self.max_rank = max_rank + super().__init__() + + def is_node_supported( + self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node + ) -> bool: + """Return True if input/output tensor ranks are within the limit.""" + if is_submodule_node(node): + return True + input_nodes = ( + input_node + for input_node in node.all_input_nodes + if input_node.op != "get_attr" + ) + # check if any input node has an unsupported rank + for input_node in input_nodes: + input_node_shape = get_first_fake_tensor(input_node).shape + if len(input_node_shape) > self.max_rank: + self.reporter.report_reject( + node, + f"{node.name} has input_node {input_node.name} with shape {input_node_shape}, " + f"rank {len(input_node_shape)} which is unsupported. " + f"Max supported rank is {self.max_rank}.", + ) + return False + + meta_val = node.meta["val"] + if isinstance( + meta_val, (Sequence, torch.fx.immutable_collections.immutable_list) + ): + for val in meta_val: + if isinstance(val, FakeTensor): + if len(val.shape) > self.max_rank: + self.reporter.report_reject( + node, + f"{node.name} has a shape {val.shape}, rank {len(val.shape)} which is unsupported." + f"Max supported rank is {self.max_rank}.", + ) + return False + elif isinstance(meta_val, FakeTensor): + if len(meta_val.shape) > self.max_rank: + self.reporter.report_reject( + node, + f"{node.name} has shape {meta_val.shape}, rank={len(meta_val.shape)} which is unsupported." + f"Max supported rank is {self.max_rank}.", + ) + return False + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/where_support.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/where_support.py new file mode 100644 index 0000000..2ec7c30 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operator_support/where_support.py @@ -0,0 +1,77 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch + +import torch.fx as fx +from executorch.backends.arm.constants import DQ_OPS +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + register_tosa_support_check, + SupportedTOSAOperatorCheck, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_tosa_support_check +class WhereSupported(SupportedTOSAOperatorCheck): + targets = [exir_ops.edge.aten.where.self] + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def is_node_tosa_supported( + self, node: fx.Node, tosa_spec: TosaSpecification + ) -> bool: # type: ignore[override, misc] + + if len(node.all_input_nodes) != 3: + self.reporter.report_reject( + node, + ( + "Expected exactly three input nodes, " + f"got {len(node.all_input_nodes)} for {node.target}." + ), + ) + return False + + condition, x, y = node.all_input_nodes + if condition.meta["val"].dtype != torch.bool: + self.reporter.report_reject( + node, + f"Type of condition in {node.target} is not torch.bool", + ) + return False + + x_dtype, y_dtype = x.meta["val"].dtype, y.meta["val"].dtype + if tosa_spec.support_float(): + if x_dtype in (torch.bool, torch.float16, torch.float32) and y_dtype in ( + torch.bool, + torch.float16, + torch.float32, + ): + return True + + if tosa_spec.support_integer(): + if ( + x_dtype in (torch.bool, torch.int8, torch.int16, torch.int32) + or (x_dtype == torch.float32 and x.target in DQ_OPS) + ) and ( + y_dtype in (torch.bool, torch.int8, torch.int16, torch.int32) + or (y_dtype == torch.float32 and y.target in DQ_OPS) + ): + return True + + self.reporter.report_reject( + node, + ( + f"Tensor x dtype {x_dtype} and/or tensor y dtype {y_dtype} is not supported in {node.target} " + f"for tosa specification {tosa_spec}" + ), + ) + + return False diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/TARGETS new file mode 100644 index 0000000..38eb9e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/TARGETS @@ -0,0 +1,40 @@ +# @noautodeps +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "node_visitor", + srcs = ["node_visitor.py"], + deps = [ + "//executorch/backends/arm/debug:schema", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm/tosa:tosa", + ], +) + +runtime.python_library( + name = "operator_validation_utils", + srcs = ["operator_validation_utils.py"], +) + +runtime.python_library( + name = "ops", + srcs = glob(["op_*.py", "ops_*.py"]), + deps = [ + "fbsource//third-party/tosa_tools:tosa", + ":node_visitor", + ":operator_validation_utils", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm/tosa:utils", + "//executorch/backends/arm/_passes:passes", + "//executorch/exir:lib", + ], +) + +runtime.python_library( + name = "lib", + srcs = ["__init__.py"], + deps = [ + ":node_visitor", + ":ops", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/__init__.py new file mode 100644 index 0000000..15be109 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/__init__.py @@ -0,0 +1,71 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Import and register Arm TOSA operator visitors. + +Importing this package loads all visitor modules so their classes can be +registered via decorators and discovered at runtime. + +""" + + +from . import ( # noqa + node_visitor, + op_abs, + op_add, + op_amax, + op_amin, + op_any, + op_avg_pool2d, + op_bitwise_not, + op_cat, + op_ceil, + op_clamp, + op_cond_if, + op_constant_pad_nd, + op_cos, + op_eq, + op_erf, + op_exp, + op_floor, + op_ge, + op_gt, + op_index_select, + op_index_tensor, + op_le, + op_log, + op_logical_not, + op_lt, + op_max_pool2d, + op_maximum, + op_minimum, + op_mul, + op_neg, + op_permute, + op_pow, + op_reciprocal, + op_repeat, + op_rshift_tensor, + op_rsqrt, + op_sigmoid, + op_sin, + op_slice, + op_sub, + op_sum, + op_tanh, + op_to_dim_order_copy, + op_tosa_conv2d, + op_tosa_conv3d, + op_tosa_depthwise_conv2d, + op_tosa_matmul, + op_tosa_rescale, + op_tosa_resize, + op_tosa_table, + op_tosa_transpose, + op_view, + op_where, + op_while, + ops_binary, + ops_identity, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/node_visitor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/node_visitor.py new file mode 100644 index 0000000..68120d1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/node_visitor.py @@ -0,0 +1,177 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide utilities to register and apply TOSA node visitors. + +Use this module to construct and serialize TOSA operators from FX nodes. +- Define the NodeVisitor base class and registry +- Register concrete visitors per TOSA specification + +""" + +import json + +import logging +from typing import Any, Dict, List, Optional + +import torch +import tosa_serializer as ts + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.debug.schema import DebugHook +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import ( + TosaSpecification, + TosaSpecMapping, +) +from torch.export import ExportedProgram + +logger = logging.getLogger(__name__) + + +class NodeVisitor: + """Provide a visitor pattern to lower edge IR to TOSA. + + Attributes: + _exported_program (torch.export.ExportedProgram): Source program being lowered. + tosa_spec (TosaSpecification): Active TOSA specification for lowering. + debug_hook (Optional[DebugHook]): Optional hook for debug metadata. + + """ + + # Add the currently supported node_visitor specs as default. + # This should be overriden in the NodeVisitor subclasses to target + # a specific TOSA version. + # When all node_visitors has been refactored to target a specific + # version, this list should be removed. + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__( + self, + exported_program: ExportedProgram, + tosa_spec: TosaSpecification, + debug_hook: Optional[DebugHook] = None, + ): + self._exported_program = exported_program + self.tosa_spec = tosa_spec + self.debug_hook = debug_hook + + def _serialize_operator( + self, + node: torch.fx.Node, + tosa_graph: Any, + tosa_op: ts.Op, + inputs: List[str], + outputs: List[str], + attributes: Optional[Any] = None, + ) -> None: + """Serialize a TOSA operator into the graph. + + When a ``DebugHook`` is active, attach location metadata (in JSON) to + the operator for traceability. + + Args: + node (torch.fx.Node): Source FX node being lowered. + tosa_graph: Target TOSA serializer/graph object. + tosa_op: TOSA operator enum value to emit. + inputs (List[str]): Names of input tensors. + outputs (List[str]): Names of output tensors. + attributes (Optional[Any]): Optional TOSA attribute object. + + Returns: + None: Mutates ``tosa_graph`` in place. + + """ + op_location = None + if self.debug_hook: + debug_info = self.debug_hook.add( + node, + tosa_op=outputs[0], + tosa_op_id=tosa_op, + ) + + if self.debug_hook.mode == ArmCompileSpec.DebugMode.TOSA: + op_location = json.dumps(debug_info.to_dict()) + + tosa_graph.addOperator( + tosa_op, + inputs=inputs, + outputs=outputs, + attributes=attributes, + location=op_location, + ) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """Define a TOSA operator node. + + Args: + node (torch.fx.Node): FX node being lowered. + tosa_graph (serializer.tosa_serializer.TosaSerializer): Target TOSA graph. + inputs (List[TosaArg]): Input tensor arguments. + output (TosaArg): Output tensor descriptor. + + Returns: + None: Mutates ``tosa_graph`` in place. + + Raises: + ValueError: If input count or dtypes are invalid. + + """ + raise NotImplementedError("NodeVisitor must be extended.") + + +# container for all node visitors +_node_visitor_tuples: TosaSpecMapping[tuple] = TosaSpecMapping() + + +def register_node_visitor(visitor): + """Register a concrete ``NodeVisitor`` class for its TOSA specs.""" + for tosa_spec in visitor.tosa_specs: + # Try to get the tuple to make sure it doesn't exist + visitor_tuple = (visitor.target, visitor) + try: + tuples = _node_visitor_tuples.get(tosa_spec) + except KeyError: + tuples = [] + + if visitor_tuple in tuples: + raise RuntimeError( + f"Visitor for target {visitor.target} already registered for TOSA spec {tosa_spec}" + ) + _node_visitor_tuples.add(tosa_spec, visitor_tuple) + return visitor + + +def get_node_visitors(*args) -> Dict[str, NodeVisitor]: + """Return a mapping from target names to visitor instances for a spec.""" + node_visitors: Dict[str, NodeVisitor] = {} + tosa_spec: TosaSpecification | None = None + for arg in args: + if isinstance(arg, TosaSpecification): + tosa_spec = arg + break + + if tosa_spec is None: + raise RuntimeError("No TOSA specification supplied.") + + # Use the mapping to get the dict for this spec (handles combined specs) + for node_visitor_tuple in _node_visitor_tuples.get(tosa_spec): + target, visitor = node_visitor_tuple + if target in node_visitors and node_visitors[target].__class__ != visitor: + logger.warning( + f"Target {target} already has visitor class {node_visitors[target].__class__.__name__} registered, overwriting with class: {visitor.__name__}" + ) + node_visitors[target] = visitor(*args) + + return node_visitors diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_abs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_abs.py new file mode 100644 index 0000000..b5a5813 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_abs.py @@ -0,0 +1,59 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class AbsVisitor(NodeVisitor): + target = "aten.abs.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.AbsAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.ABS, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_add.py new file mode 100644 index 0000000..6c1ff2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_add.py @@ -0,0 +1,60 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class AddVisitor(NodeVisitor): + target = "aten.add.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.AddAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.ADD, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amax.py new file mode 100644 index 0000000..e4824fb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amax.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class MaxVisitor(NodeVisitor): + target = "aten.amax.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + input = inputs[0] + dim = inputs[1].number + + if dim < 0: + tensor = get_first_fake_tensor(node) + rank = len(tensor.size()) + dim = rank + dim + + keep_dims = inputs[2].number + if not keep_dims: + raise RuntimeError( + "TOSA only supports keepdims == True; Did you run the convert_minmax pass?" + ) + + attr = ts.TosaSerializerAttribute() + nan_mode = ts.NanPropagationMode.PROPAGATE + attr.ReduceMaxAttribute(axis=input.dim_order.index(dim), nan_mode=nan_mode) + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_MAX, + [input.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amin.py new file mode 100644 index 0000000..34d4d37 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_amin.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class MinVisitor(NodeVisitor): + target = "aten.amin.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + input = inputs[0] + dim = inputs[1].number + + if dim < 0: + tensor = get_first_fake_tensor(node) + rank = len(tensor.size()) + dim = rank + dim + + keep_dims = inputs[2].number + if not keep_dims: + raise RuntimeError( + "TOSA only supports keepdims == True; Did you run the convert_minmax pass?" + ) + + attr = ts.TosaSerializerAttribute() + attr.ReduceMinAttribute( + axis=input.dim_order.index(dim), nan_mode=ts.NanPropagationMode.PROPAGATE + ) + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_MIN, + [input.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_any.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_any.py new file mode 100644 index 0000000..2a850c0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_any.py @@ -0,0 +1,61 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( # type: ignore + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) + +from executorch.backends.arm.tosa.mapping import TosaArg # type: ignore +from torch.fx import Node + + +@register_node_visitor +class AnyVisitor(NodeVisitor): + target = "aten.any.dim" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, [inputs[0], output], ts.DType.BOOL, output.tosa_spec + ) + + input_shape = list(inputs[0].shape) + dim = cast(int, inputs[1].number) % len( + input_shape + ) # process the negative index + keep_dim = cast(bool, inputs[2].number if len(inputs) > 2 else False) + if not keep_dim: + raise ValueError("This case should be handled by DecomposeAnyPass") + + attr = ts.TosaSerializerAttribute() + attr.ReduceAnyAttribute(inputs[0].dim_order.index(dim)) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_ANY, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_avg_pool2d.py new file mode 100644 index 0000000..ec9d429 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_avg_pool2d.py @@ -0,0 +1,142 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class AvgPool2dVisitor(NodeVisitor): + target = "aten.avg_pool2d.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def _build_generic_avgpool2d( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + input_zp: int, + output_zp: int, + accumulator_type: Any, + ) -> None: + + input_tensor = inputs[0] + kernel_size_list = inputs[1].special + stride_size_list = inputs[2].special + + if len(inputs) > 4: + ceil_mode = bool(inputs[4].number) + else: + ceil_mode = False + + try: + pad_size_list = inputs[3].special + pad_size_list = [ + pad_size_list[0], + pad_size_list[0], + pad_size_list[1], + pad_size_list[1], + ] + except IndexError: + pad_size_list = [0, 0, 0, 0] + + # Adjust the padding as necessary + pad_size_list[1] = adjust_pooling_pad_if_needed( + input_tensor.shape[2], + kernel_size_list[0], + stride_size_list[0], + pad_size_list[1], + ceil_mode, + ) + pad_size_list[3] = adjust_pooling_pad_if_needed( + input_tensor.shape[3], + kernel_size_list[1], + stride_size_list[1], + pad_size_list[3], + ceil_mode, + ) + + attr = ts.TosaSerializerAttribute() + attr.AvgPool2dAttribute( + kernel=kernel_size_list, + stride=stride_size_list, + pad=pad_size_list, + acc_type=accumulator_type, + ) + dt: ts.DType = output.dtype + input_zp_tensor = tosa_graph.addConst(shape=[1], dtype=dt, vals=[input_zp]) + output_zp_tensor = tosa_graph.addConst(shape=[1], dtype=dt, vals=[output_zp]) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.AVG_POOL2D, + [input_tensor.name, input_zp_tensor.name, output_zp_tensor.name], + [output.name], + attr, + ) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [3, 4, 5, 6, 7]) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ts.DType.INT8, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + if inputs[0].dtype == ts.DType.INT8 or inputs[0].dtype == ts.DType.INT16: + accumulator_type = ts.DType.INT32 + input_qargs = get_input_qparams(node) + input_zp = input_qargs[0].get_zp_per_tensor() + + output_qargs = get_output_qparams(node) + output_zp = output_qargs[0].get_zp_per_tensor() + else: + accumulator_type = ts.DType.FP32 + input_zp = 0 + output_zp = 0 + + self._build_generic_avgpool2d( + node, tosa_graph, inputs, output, input_zp, output_zp, accumulator_type + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_bitwise_not.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_bitwise_not.py new file mode 100644 index 0000000..ac0f758 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_bitwise_not.py @@ -0,0 +1,62 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class BitwiseNotVisitor(NodeVisitor): + target = "aten.bitwise_not.default" + + # bitwise_not is not supported on the FP profile + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.BitwiseNotAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.BITWISE_NOT, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cat.py new file mode 100644 index 0000000..71c1853 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cat.py @@ -0,0 +1,68 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class CatVisitor(NodeVisitor): + target = "aten.cat.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + supported_dtypes = [ts.DType.BOOL, ts.DType.INT8, ts.DType.INT32, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_num_inputs(self.target, inputs, [1, 2]) + input_tosa_args = [TosaArg(arg, output.tosa_spec) for arg in inputs[0].special] + validate_same_dtype(self.target, [*input_tosa_args, output], ts) + validate_valid_dtype( + self.target, + [*input_tosa_args, output], + supported_dtypes, + output.tosa_spec, + ) + + dim = 0 if len(inputs) < 2 else inputs[1].number + rank = len(output.shape) + dim = (dim + rank) % rank + dim = output.dim_order.index(dim) + + attr = ts.TosaSerializerAttribute() + attr.ConcatAttribute(dim) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.CONCAT, + [tensor.name for tensor in input_tosa_args], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ceil.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ceil.py new file mode 100644 index 0000000..27ee81d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ceil.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class CeilVisitor(NodeVisitor): + target = "aten.ceil.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + inputs[0], + ts.DType.FP32, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.CeilAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.CEIL, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_clamp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_clamp.py new file mode 100644 index 0000000..d90f92f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_clamp.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree + + +from typing import Any, List, Tuple + +import numpy as np +import torch +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class ClampVisitor(NodeVisitor): + target = "aten.clamp.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def _get_min_max_arguments( + self, node: Node, dtype: torch.dtype + ) -> Tuple[int | float, int | float]: + def cast_type(value: Any) -> int | float: + if isinstance(value, int): + return value + else: + # Attempt to cast to float + return float(value) + + if dtype.is_floating_point: + dtype_min = torch.finfo(dtype).min + dtype_max = torch.finfo(dtype).max + else: + dtype_min = torch.iinfo(dtype).min + dtype_max = torch.iinfo(dtype).max + + min_arg = dtype_min + max_arg = dtype_max + + if node.args[1] is not None: + min_arg = cast_type(node.args[1]) + + if len(node.args) > 2: + if node.args[2] is not None: + max_arg = cast_type(node.args[2]) + + return min_arg, max_arg + + def _to_bytes(self, value: int | float, dtype: torch.dtype) -> bytes: + if dtype == torch.float32: + return np.frombuffer(np.float32(value).tobytes(), dtype=np.uint8).tolist() + elif dtype == torch.float16: + return np.frombuffer(np.float16(value).tobytes(), dtype=np.uint8).tolist() + elif dtype == torch.int8: + return np.frombuffer(np.int8(value).tobytes(), dtype=np.uint8).tolist() + elif dtype == torch.int16: + return np.frombuffer(np.int16(value).tobytes(), dtype=np.uint8).tolist() + else: + raise ValueError(f"Unsupported dtype for to_bytes: {dtype}") + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [2, 3]) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ts.DType.INT8, ts.DType.FP16, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + node_input_dtype = node.meta["val"].dtype + # NOTE: Quantization of the min/max arguments is handled by QuantizeOperatorArguments + min_val, max_val = self._get_min_max_arguments(node, node_input_dtype) + + attr = ts.TosaSerializerAttribute() + attr.ClampAttribute( + self._to_bytes(min_val, node_input_dtype), + self._to_bytes(max_val, node_input_dtype), + nan_mode=ts.NanPropagationMode.PROPAGATE, + ) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.CLAMP, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cond_if.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cond_if.py new file mode 100644 index 0000000..4cf5120 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cond_if.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe +from typing import Any, cast, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( # type: ignore + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_cf_extension, + validate_num_inputs, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg # type: ignore +from torch.fx import Node + + +@register_node_visitor +class CondVisitor(NodeVisitor): + target = "cond" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + validate_num_inputs(self.target, inputs, 4) + validate_valid_dtype(self.target, [inputs[0]], ts.DType.BOOL, self.tosa_spec) + validate_cf_extension(self.target, self.tosa_spec) + + attr = ts.TosaSerializerAttribute() + if_graph, else_graph = (cast(Node, arg).target for arg in node.args[1:3]) + attr.CondIfAttribute(if_graph, else_graph) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.COND_IF, + [ + inputs[0].name, + *(subgraph_input.name for subgraph_input in inputs[-1].special), + ], + output.multiple_output_names, + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_constant_pad_nd.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_constant_pad_nd.py new file mode 100644 index 0000000..47d11fb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_constant_pad_nd.py @@ -0,0 +1,117 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ConstantPadNDVisitor(NodeVisitor): + + target = "aten.constant_pad_nd.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ts.DType.BOOL, + ], + output.tosa_spec, + ) + + if inputs[0].dtype == ts.DType.INT8: + input_qparams = get_input_qparams(node) + qargs = input_qparams[0] + pad_const_val = qargs.quantize_value(inputs[2].number).item() + pad_const_dtype = ts.DType.INT8 + elif inputs[0].dtype == ts.DType.INT16: + input_qparams = get_input_qparams(node) + qargs = input_qparams[0] + pad_const_val = qargs.quantize_value(inputs[2].number).item() + pad_const_dtype = ts.DType.INT16 + else: + pad_const_val = inputs[2].number + pad_const_dtype = inputs[0].dtype + + rank = len(output.shape) + # Each dim needs 2 padding values. For example, to pad the last dimension, the pad has the form + # (padding_left, padding_right); to pad the last two dimensions, the pad has the form + # (padding_left, padding_right, padding_top, padding_bottom), and so on. For PyTorch NCHW format, the padding + # values are in the reverse order. So, firstly we need to reverse the input padding parameters. + input_pad = sum( + [ + [inputs[1].special[i], inputs[1].special[i + 1]] + for i in range(0, len(inputs[1].special), 2) + ][::-1], + [], + ) + # Then, add dummy zeros to make sure that both input_pad and output_pad has the same size. + input_pad = [0] * (rank * 2 - len(inputs[1].special)) + input_pad + # For PyTorch NCHW format, dim order is [0,...,rank-1] + input_dim_order = list(range(rank)) + output_pad = [0] * rank * 2 + + # Map input padding parameters into output padding parameters. TOSA is NHWC format. + for input_dim_idx, input_dim in enumerate(input_dim_order): + output_dim_idx = output.dim_order.index(input_dim) + output_pad[output_dim_idx * 2 : (output_dim_idx + 1) * 2] = input_pad[ + input_dim_idx * 2 : (input_dim_idx + 1) * 2 + ] + + padding = tosa_graph.addConst( + shape=[len(output_pad)], dtype=ts.DType.SHAPE, vals=output_pad + ) + + pad_const = tosa_graph.addConst( + shape=[1], dtype=pad_const_dtype, vals=[pad_const_val] + ) + + attr = ts.TosaSerializerAttribute() + attr.PadAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.PAD, + [inputs[0].name, padding.name, pad_const.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cos.py new file mode 100644 index 0000000..e603973 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_cos.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class CosVisitor(NodeVisitor): + target = "aten.cos.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: ts.TosaSerializer, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.CosAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.COS, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_eq.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_eq.py new file mode 100644 index 0000000..bd72c94 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_eq.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class EqualVisitor(NodeVisitor): + target = "aten.eq.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.EqualAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.EQUAL, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_erf.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_erf.py new file mode 100644 index 0000000..e642a40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_erf.py @@ -0,0 +1,54 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ERFVisitor(NodeVisitor): + target = "aten.erf.default" + + # INT case handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + ts.DType.FP32, + output.tosa_spec, + ) + + # MI lowering + attr = ts.TosaSerializerAttribute() + attr.ErfAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.ERF, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_exp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_exp.py new file mode 100644 index 0000000..72e89b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_exp.py @@ -0,0 +1,54 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class ExpVisitor(NodeVisitor): + target = "aten.exp.default" + + # BI case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + ts.DType.FP32, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.ExpAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.EXP, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_floor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_floor.py new file mode 100644 index 0000000..d9f831d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_floor.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class FloorVisitor(NodeVisitor): + target = "aten.floor.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + inputs[0], + ts.DType.FP32, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.FloorAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.FLOOR, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ge.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ge.py new file mode 100644 index 0000000..7547784 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_ge.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class GreaterEqualVisitor(NodeVisitor): + target = "aten.ge.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterEqualAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER_EQUAL, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_gt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_gt.py new file mode 100644 index 0000000..2a483f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_gt.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class GreaterThanVisitor(NodeVisitor): + target = "aten.gt.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_select.py new file mode 100644 index 0000000..ba2aa03 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_select.py @@ -0,0 +1,109 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + +from executorch.backends.arm.tosa.utils import build_reshape_tosa +from torch.fx import Node + + +@register_node_visitor +class IndexSelectVisitor(NodeVisitor): + """ + Simple example: + o = index_select(weights, index, indices) + Becomes: + i = view_copy(i) # reshape flattened indicies, i.e. [I] => [1, I] + o = index_select(w, index, i) + + Additional steps in case weights (w) are rank 2: + - before: insert view_copy to make rank 3, [x,y] => [1, x, y] + - after: insert view_copy to squeeze back output dims, [1, x, y] = [x,y] + """ + + target = "aten.index_select.default" + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + weights, _, indices = inputs + + if len(weights.shape) == 2: + weights_new_shape = [1, weights.shape[0], weights.shape[1]] + weights_reshaped = tosa_graph.addIntermediate( + weights_new_shape, + weights.dtype, + ) + build_reshape_tosa( + tosa_graph, weights.name, weights_new_shape, weights_reshaped.name + ) + + output_new_shape = [1, output.shape[0], output.shape[1]] + output_reshaped = tosa_graph.addIntermediate( + output_new_shape, + output.dtype, + ) + + else: + weights_reshaped = weights + output_reshaped = output + + output_name = output_reshaped.name + + # Reshape flattened indicies, i.e. [I] => [1, I] + indices_new_shape = [1, indices.shape[0]] + indices_reshaped = tosa_graph.addIntermediate( + indices_new_shape, + indices.dtype, + ) + build_reshape_tosa( + tosa_graph, indices.name, indices_new_shape, indices_reshaped.name + ) + + attr = ts.TosaSerializerAttribute() + attr.GatherAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GATHER, + [weights_reshaped.name, indices_reshaped.name], + [output_name], + attr, + ) + + if len(weights.shape) == 2: + output_real_shape = [output.shape[0], output.shape[1]] + build_reshape_tosa(tosa_graph, output_name, output_real_shape, output.name) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_tensor.py new file mode 100644 index 0000000..cd0809d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_index_tensor.py @@ -0,0 +1,247 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Any, List + +import executorch.backends.arm.tosa.utils as tutils + +import numpy as np +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_same_dtype, +) +from executorch.backends.arm.tosa.mapping import extract_tensor_meta, TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +class CommonIndexTensorVisitor(NodeVisitor): + target = "aten.index.Tensor" + + def __init__(self, *args): + super().__init__(*args) + + def _get_tensor_info(self, tensor: Node): + """ + Consolidates obtaining name, dtype and shape into a common function + reconciling access based on the type of the input. + + Args: + fake_tensors (list[FakeTensor]): List of 2 or more FakeTensors + who's shapes to evaluate + + Returns: + tuple[bool, list[int]]: First element is whether the shapes are + broadcastable. Second element is the common shape if compatible. + If not, empty list. + + """ + if isinstance(tensor, Node): + dtype, shape, _ = extract_tensor_meta(tensor.meta, self.tosa_spec) + return tensor.name, dtype, shape + else: + return tensor.name, tensor.dtype, tensor.shape + + def _calculate_tosa_vals( + self, + index_shape: List[int], + index_nodes: List[Node], + values_shape: List[int], + ): + # From TOSA spec + # N - number of batches + # W - number of indices in each batch + # K - range of each index (number of elements to index through) + # C - number of data channels for each index + N, K, W, C = 1, 1, 1, 1 + + # Calculate K, W, C + # N - kept to 1 for generic n-dim implementation + # Note: If/when slice and ellipsis support is added batching + # may have to be used to facilitate proper implementation of + # the relevant logic. + # W - common between all indices as they have been broadcast + # to a common shape in a pass. + W = math.prod(index_shape) + + for i, dim in enumerate(values_shape): + if i < len(index_nodes): + K *= dim + + total_vals = math.prod(values_shape) + C = int(total_vals / K) + + return N, K, W, C + + def _calculate_value_strides(self, values_shape: List[int]) -> List[int]: + values_strides: List[int] = [] + stride = 1 + for dim in reversed(values_shape): + values_strides.insert(0, stride) + stride *= dim + + return values_strides + + +@register_node_visitor +class IndexTensorVisitor(CommonIndexTensorVisitor): + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """ + This approach uses the fact that all indexing tensors are incremented + simultaneously and they essentially act as a map along the corresponding + dimensions of the values tensor. + Note: that this does not hold true when slicing or ellipsis ops + are involved as such they are not currently not supported. + + As such this approach flattens out the values tensor and + constructs a flattened out index obtained by flattening out the + index tensors, multiplying them by the relevant stride and accumulating them. + + This approach suffers from the fact that we are taking a number of index tensors of + type int32 and applying multiplications and additions. + + If the number of total elements in the values tensor exceeds int32 limits + then this approach falls apart. + """ + + validate_same_dtype(self.target, [inputs[0], output]) + + values, indices = inputs + index_nodes = indices.special + + # Broadcast indices + broadcasted_tensors = tutils.broadcast_tensors( + tosa_graph, index_nodes, self.tosa_spec + ) + + # Calculate strides so we can shift indices down the line. + values_strides = self._calculate_value_strides(values.shape) + + # The indices have already been broadcast to a common shape + # in so they are all the same. + _, index_dtype, index_shape = self._get_tensor_info(broadcasted_tensors[0]) + + N, K, W, C = self._calculate_tosa_vals(index_shape, index_nodes, values.shape) + + gather_idx_shape = [N, W] + + gather_index_name = "" + # Flatten out and shift indexes. + for i, index_node in enumerate(broadcasted_tensors): + index_name, _, _ = self._get_tensor_info(index_node) + index_name = index_node.name + + stride_shifted_indices = tosa_graph.addIntermediate( + index_shape, + index_dtype, + ) + + # Division by C is necessary when len(indices) < values.rank + # When there are dimensions left unindexed that changes the + # channels and thus the stride-shift. + data = np.full(index_shape, int(values_strides[i] / C)) + mul_const = tosa_graph.addConst(index_shape, index_dtype, data) + tosa_graph.addConst([1], ts.DType.INT8, 0, name=f"{output.name}_{i}_shift") + attr = ts.TosaSerializerAttribute() + attr.MulAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.MUL, + [index_name, mul_const.name, f"{output.name}_{i}_shift"], + [stride_shifted_indices.name], + attr, + ) + + reshaped_idxs = tosa_graph.addIntermediate( + gather_idx_shape, + index_dtype, + ) + tutils.build_reshape_tosa( + tosa_graph, + stride_shifted_indices.name, + gather_idx_shape, + reshaped_idxs.name, + shape_name_override=f"{output.name}_{i}_shape", + ) + + # Guarantees that the accumulation tensor is properly + # initialized and does not contain junk data. + if i == 0: + gather_index_name = reshaped_idxs.name + else: + add_idxs = tosa_graph.addIntermediate( + reshaped_idxs.shape, + reshaped_idxs.dtype, + ) + attr = ts.TosaSerializerAttribute() + attr.AddAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.ADD, + [gather_index_name, reshaped_idxs.name], + [add_idxs.name], + attr, + ) + gather_index_name = add_idxs.name + + gather_vals_shape = [N, K, C] + reshaped_input = tosa_graph.addIntermediate(gather_vals_shape, values.dtype) + + tutils.build_reshape_tosa( + tosa_graph, + values.name, + gather_vals_shape, + reshaped_input.name, + shape_name_override=f"{output.name}_index_shape", + ) + + gather_out_shape = (N, W, C) + gather_out = tosa_graph.addIntermediate( + gather_out_shape, + output.dtype, + ) + attr = ts.TosaSerializerAttribute() + attr.GatherAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GATHER, + [reshaped_input.name, gather_index_name], + [gather_out.name], + attr, + ) + + output_shape = tutils.tosa_shape(output.shape, output.dim_order) + + tutils.build_reshape_tosa( + tosa_graph, + gather_out.name, + list(output_shape), + output.name, + shape_name_override=f"{output.name}_output_shape", + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_le.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_le.py new file mode 100644 index 0000000..aa6b52b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_le.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class LessEqualVisitor(NodeVisitor): + target = "aten.le.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterEqualAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER_EQUAL, + [inputs[1].name, inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_log.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_log.py new file mode 100644 index 0000000..565d6d5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_log.py @@ -0,0 +1,50 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class LogVisitor(NodeVisitor): + target = "aten.log.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.LogAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.LOG, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_logical_not.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_logical_not.py new file mode 100644 index 0000000..695af5f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_logical_not.py @@ -0,0 +1,62 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class LogicalNotVisitor(NodeVisitor): + target = "aten.logical_not.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.BOOL], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.LogicalNotAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.LOGICAL_NOT, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_lt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_lt.py new file mode 100644 index 0000000..4b2b1a1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_lt.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class LessThanVisitor(NodeVisitor): + target = "aten.lt.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, inputs, ts) + validate_valid_dtype( + self.target, + inputs, + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + validate_valid_dtype(self.target, output, ts.DType.BOOL, output.tosa_spec) + + attr = ts.TosaSerializerAttribute() + attr.GreaterAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.GREATER, + [inputs[1].name, inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_max_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_max_pool2d.py new file mode 100644 index 0000000..bee0cc3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_max_pool2d.py @@ -0,0 +1,108 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + adjust_pooling_pad_if_needed, + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class MaxPool2dVisitor(NodeVisitor): + target = "aten.max_pool2d.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [3, 4, 5, 6]) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ts.DType.INT8, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + input_tensor = inputs[0] + kernel_size = inputs[1].special + stride = inputs[2].special + + if len(inputs) == 6: + ceil_mode = bool(inputs[5].number) + else: + ceil_mode = False + + try: + pad_size_list = inputs[3].special + pad_size_list = [ + pad_size_list[0], + pad_size_list[0], + pad_size_list[1], + pad_size_list[1], + ] + except (IndexError, AttributeError): + pad_size_list = [0, 0, 0, 0] + + # Adjust the padding as necessary + pad_size_list[1] = adjust_pooling_pad_if_needed( + input_tensor.shape[2], + kernel_size[0], + stride[0], + pad_size_list[1], + ceil_mode, + ) + pad_size_list[3] = adjust_pooling_pad_if_needed( + input_tensor.shape[3], + kernel_size[1], + stride[1], + pad_size_list[3], + ceil_mode, + ) + + attr = ts.TosaSerializerAttribute() + attr.MaxPool2dAttribute( + kernel=kernel_size, + stride=stride, + pad=pad_size_list, + nan_mode=ts.NanPropagationMode.PROPAGATE, + ) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MAX_POOL2D, + [input_tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_maximum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_maximum.py new file mode 100644 index 0000000..d3ab305 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_maximum.py @@ -0,0 +1,66 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class MaxVisitor(NodeVisitor): + target = "aten.maximum.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr_maximum = ts.TosaSerializerAttribute() + attr_maximum.MaximumAttribute(nan_mode=ts.NanPropagationMode.PROPAGATE) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MAXIMUM, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr_maximum, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_minimum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_minimum.py new file mode 100644 index 0000000..7f72d15 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_minimum.py @@ -0,0 +1,67 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class MinVisitor(NodeVisitor): + target = "aten.minimum.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr_minimum = ts.TosaSerializerAttribute() + attr_minimum.MinimumAttribute(nan_mode=ts.NanPropagationMode.PROPAGATE) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MINIMUM, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr_minimum, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_mul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_mul.py new file mode 100644 index 0000000..0e10443 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_mul.py @@ -0,0 +1,61 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification + + +@register_node_visitor +class MulVisitor(NodeVisitor): + target = "aten.mul.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ] + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + tosa_graph.addConst([1], ts.DType.INT8, 0, name=f"{output.name}_shift") + attr = ts.TosaSerializerAttribute() + attr.MulAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.MUL, + [inputs[0].name, inputs[1].name, f"{output.name}_shift"], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_neg.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_neg.py new file mode 100644 index 0000000..e0bb408 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_neg.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, + get_output_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def get_negate_zero_points(node: torch.fx.Node, is_int8: bool) -> tuple[int, int]: + """ + Returns (input1_zp, output_zp) for TOSA NEGATE. + Must be zero for non-int8 types. + """ + if is_int8: + return ( + get_input_qparams(node)[0].get_zp_per_tensor(), + get_output_qparams(node)[0].get_zp_per_tensor(), + ) + return (0, 0) + + +@register_node_visitor +class NegVisitor(NodeVisitor): + target = "aten.neg.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + supported_dtypes = [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP16, + ts.DType.BF16, + ts.DType.FP32, + ] + + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], supported_dtypes, output.tosa_spec + ) + + input_zp, output_zp = get_negate_zero_points( + node, inputs[0].dtype == ts.DType.INT8 + ) + + input_zp_tensor = tosa_graph.addConst( + (1,), inputs[0].dtype, [input_zp], name=output.name + "_input_zp" + ) + + output_zp_tensor = tosa_graph.addConst( + (1,), output.dtype, [output_zp], name=output.name + "_output_zp" + ) + attr = ts.TosaSerializerAttribute() + attr.NegateAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.NEGATE, + [inputs[0].name, input_zp_tensor.name, output_zp_tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_permute.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_permute.py new file mode 100644 index 0000000..fea0aea --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_permute.py @@ -0,0 +1,150 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def permutation_vector_to_matrix(permutation_vector: list[int]) -> torch.Tensor: + """ + Converts a permutation vector of length N to a NxN matrix that describes the same permutation. + for example: + (1,0,2) + -> + [0 1 0] + |1 0 0| + [0 0 1] + """ + N = len(permutation_vector) + P = torch.zeros(N, N) + for row_index, col_index in enumerate(permutation_vector): + P[row_index][col_index] = 1 + return P + + +def permutation_matrix_to_vector(permutation_matrix: torch.Tensor) -> list[int]: + """ + Converts a NxN permutation matrix to a permutation vector of length N that describes the same permutation. + [0 1 0] + |1 0 0| + [0 0 1] + -> + (1,0,2) + """ + N = len(permutation_matrix) + if N != len(permutation_matrix[0]): + raise ValueError( + f"A permutation matrix must be square, got shape {permutation_matrix.shape}" + ) + + p = [0] * N + for row_index, row in enumerate(permutation_matrix): + saw_one = False + for col_index, value in enumerate(row): + if value == 1: + if saw_one: + raise ValueError( + f"A permutation matrix can only have one 1 per row, got {row=}" + ) + p[row_index] = col_index + saw_one = True + elif value != 0: + raise ValueError( + f"A permutation matrix only contains 1's and 0's, got {value=}" + ) + return p + + +def transform_permutation_vector(permutation_vector: list[int], dim_order: list[int]): + """Transforms a permutation to dim_order.""" + + # We need to first transform to dim_order, apply the permutation P, + # and then transform back to the original dim_order. + # This transformation, S, is also a permutation, with the dim_order as permutation vector. + + # To do this, represent P and S with permutation matrices. + # Matrices can handle chained transformations and inversion easily. + S = permutation_vector_to_matrix(dim_order) + # The inverse of a permutation matrix is its transpose. + S_inverse = S.t() + P = permutation_vector_to_matrix(permutation_vector) + + # The complete transformation is S * P * S_inverse. + transformation_matrix = S.matmul(P.matmul(S_inverse)) + + # Luckily, since it is just a combination of permutations, the result is also a permutation + # that can again be described by a new permutation vector. + permutation_vector = permutation_matrix_to_vector(transformation_matrix) + return permutation_vector + + +@register_node_visitor +class PermuteVisitor(NodeVisitor): + target = "aten.permute_copy.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + # The permutation vector describes a permutation P in default Pytorch dim_order. + # For rank 4, the default dim_order NCHW. + # E.g. (2,3,0,1) -> permute (n,c,h,w) to (w,c,n,h) + permutation_vector = inputs[1].special + + if output.dim_order != tuple(range(len(output.dim_order))): + # the permutation vector can't be used directly if we are not in NCHW dim_order. + # Transform to dim_order. + permutation_vector = transform_permutation_vector( + permutation_vector, output.dim_order + ) + + attr = ts.TosaSerializerAttribute() + attr.TransposeAttribute(permutation_vector) + self._serialize_operator( + node, + tosa_graph, + ts.Op.TRANSPOSE, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_pow.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_pow.py new file mode 100644 index 0000000..33cbc29 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_pow.py @@ -0,0 +1,63 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class PowVisitor(NodeVisitor): + target = "aten.pow.Tensor_Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.FP16, ts.DType.FP32], + output.tosa_spec, + ) + attr = ts.TosaSerializerAttribute() + attr.PowAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.POW, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_reciprocal.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_reciprocal.py new file mode 100644 index 0000000..108a4fa --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_reciprocal.py @@ -0,0 +1,51 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ReciprocalVisitor(NodeVisitor): + target = "aten.reciprocal.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.ReciprocalAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.RECIPROCAL, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_repeat.py new file mode 100644 index 0000000..e44fede --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_repeat.py @@ -0,0 +1,77 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.utils import tosa_shape + + +@register_node_visitor +class RepeatVisitor(NodeVisitor): + target = "aten.repeat.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: list[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + multiples = inputs[1].special + + if len(multiples) == 0: + raise ValueError(f"Length of multiples argument is 0: {inputs[1]}!") + + multiple_shapes = tosa_graph.addConst( + (len(multiples),), + ts.DType.SHAPE, + list(tosa_shape(multiples, output.dim_order)), + name=output.name + "_multiples", + ) + + attr = ts.TosaSerializerAttribute() + attr.TileAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.TILE, + [inputs[0].name, multiple_shapes.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rshift_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rshift_tensor.py new file mode 100644 index 0000000..0b5717a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rshift_tensor.py @@ -0,0 +1,62 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class RshiftVisitor(NodeVisitor): + target = "aten.bitwise_right_shift.Tensor" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + round = False + if self.tosa_spec.is_U55_subset: + # U55 only supports INT32 and round == True + # TODO MLETORCH-525 Emulate round == False with different decomposition + round = True + attr.ArithmeticRightShiftAttribute(round=round) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.ARITHMETIC_RIGHT_SHIFT, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rsqrt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rsqrt.py new file mode 100644 index 0000000..a86eaa4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_rsqrt.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class RsqrtVisitor(NodeVisitor): + target = "aten.rsqrt.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.RsqrtAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.RSQRT, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sigmoid.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sigmoid.py new file mode 100644 index 0000000..908544f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sigmoid.py @@ -0,0 +1,50 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class SigmoidVisitor(NodeVisitor): + target = "aten.sigmoid.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.SigmoidAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.SIGMOID, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sin.py new file mode 100644 index 0000000..faa2499 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sin.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class SinVisitor(NodeVisitor): + target = "aten.sin.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: ts.TosaSerializer, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.SinAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.SIN, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_slice.py new file mode 100644 index 0000000..21c86e5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_slice.py @@ -0,0 +1,151 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +def _fixup_start(start, shape, dim): + # Normalize start index and clamp into [0, shape[dim]]. + # If not a constant, default to 0. + idx = getattr(start, "number", 0) + # Handle negative wrap-around + if idx < 0: + idx = idx % shape[dim] + # Clamp into valid bounds + if idx < 0: + idx = 0 + elif idx > shape[dim]: + idx = shape[dim] + return idx + + +def _fixup_end(end, shape, dim): + # Normalize end index and clamp into [0, shape[dim]]. + max_dim = shape[dim] + # If not a constant, default to the full size + idx = getattr(end, "number", max_dim) + # Handle negative wrap-around + if idx < 0: + idx = idx % max_dim + # Clamp into valid bounds + if idx < 0: + idx = 0 + elif idx > max_dim: + idx = max_dim + return idx + + +@register_node_visitor +class SliceVisitor(NodeVisitor): + target = "aten.slice_copy.Tensor" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [4, 5]) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + # See slice_copy_support.py + if not (len(inputs) == 4 or (len(inputs) == 5 and inputs[4].number == 1)): + raise ValueError("Unsupported combination of inputs") + + # aten.slice_copy supports slicing in 1d at a time. + # The arguments are the actual input, dimension of slicing, start index, end index and optinal step or stride. + input_node, dim, start, end = inputs + + # Translate and check parameters in Pytorch dim order. + shape = input_node.shape + dim = dim.number + + start_index = _fixup_start(start, shape, dim) + end_index = _fixup_end(end, shape, dim) + size = end_index - start_index + + if size <= 0: + raise ValueError( + f"The calculated slice size must be positive. Got {size=} " + f"with {start_index=} and {end_index=}." + ) + if size > shape[dim]: + raise ValueError( + f"The calculated slice size cannot be greater than the dimension size" + f". Got {size=} and {shape[dim]=}." + ) + + # Convert aten args to Tosa's start and size shape_t tensors and in TOSA dim order. + starts = [ + _fixup_start(start, shape, dim) if i == dim else 0 + for i in input_node.dim_order + ] + + if len(starts) != 0: + starts_len = len(starts) + else: + starts_len = 1 + starts = [0] + + start_tensor = tosa_graph.addConst( + (starts_len,), + ts.DType.SHAPE, + starts, + output.name + "_start_shape", + ) + + sizes = [size if i == dim else shape[i] for i in input_node.dim_order] + if len(sizes) != 0: + sizes_len = len(starts) + else: + sizes_len = 1 + sizes = [0] + sizes_tensor = tosa_graph.addConst( + (sizes_len,), ts.DType.SHAPE, sizes, output.name + "_sizes_shape" + ) + + attr = ts.TosaSerializerAttribute() + attr.SliceAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.SLICE, + [input_node.name, start_tensor.name, sizes_tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sub.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sub.py new file mode 100644 index 0000000..039a2f6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sub.py @@ -0,0 +1,63 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.fx import Node + + +@register_node_visitor +class SubVisitor(NodeVisitor): + target = "aten.sub.Tensor" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.SubAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.SUB, + [ + inputs[0].name, + inputs[1].name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sum.py new file mode 100644 index 0000000..e956359 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_sum.py @@ -0,0 +1,64 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class SumVisitor(NodeVisitor): + target = "aten.sum.dim_IntList" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 3) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ts.DType.INT32, ts.DType.FP32], + output.tosa_spec, + ) + + tensor = inputs[0] + input_shape = list(tensor.shape) + dim = int(inputs[1].number % len(input_shape)) + + attr = ts.TosaSerializerAttribute() + attr.ReduceSumAttribute(tensor.dim_order.index(dim)) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.REDUCE_SUM, + [tensor.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tanh.py new file mode 100644 index 0000000..c4603e9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tanh.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + +from torch.fx import Node + + +@register_node_visitor +class TanhVisitor(NodeVisitor): + target = "aten.tanh.default" + + # INT case should be handled by op_table + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+FP")] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [*inputs, output], ts) + validate_valid_dtype( + self.target, [*inputs, output], ts.DType.FP32, output.tosa_spec + ) + attr = ts.TosaSerializerAttribute() + attr.TanhAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.TANH, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_to_dim_order_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_to_dim_order_copy.py new file mode 100644 index 0000000..9d3aff8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_to_dim_order_copy.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class ToDimOrderCopyVisitor(NodeVisitor): + """ + Implement the type cast functionality of _to_dim_order_copy. + + Other features like setting of the dim_order or moving a tensor to a + different device are not supported. + + Also note that the node should not be quantized. + """ + + target = "dim_order_ops._to_dim_order_copy.default" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + attr = ts.TosaSerializerAttribute() + attr.CastAttribute() + self._serialize_operator( + node, tosa_graph, ts.Op.CAST, [inputs[0].name], [output.name], attr + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv2d.py new file mode 100644 index 0000000..7b7e415 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv2d.py @@ -0,0 +1,139 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import tosa_serializer as ts + +"""Provide a visitor for lowering 2D convolution to TOSA (INT/FP).""" + +from typing import Any, List + +import torch + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification + + +@register_node_visitor +class Conv2dVisitor(NodeVisitor): + """Provide a visitor that serializes TOSA ``CONV2D``.""" + + target = "tosa.CONV2D.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def _get_tosa_op(self): + return ts.Op.CONV2D + + def _get_attr_func(self, attr): + return attr.Conv2dAttribute + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """Define the TOSA CONV2D/DEPTHWISE_CONV2D operator.""" + + input, weight, bias, stride, pad, dilation = inputs + validate_num_inputs(self.target, inputs, 6) + + valid_input_dtypes = [] + if self.tosa_spec.support_float(): + valid_input_dtypes.append(ts.DType.FP32) + if self.tosa_spec.support_integer(): + valid_input_dtypes.append(ts.DType.INT8) + + if self.tosa_spec.support_extension("int16"): + valid_input_dtypes.append(ts.DType.INT16) + # Check constraints for int16 activations + if inputs[0].dtype == ts.DType.INT16: + validate_valid_dtype( + self.target, [inputs[1]], [ts.DType.INT8], self.tosa_spec + ) + validate_valid_dtype( + self.target, [inputs[2]], [ts.DType.INT48], self.tosa_spec + ) + + validate_valid_dtype( + self.target, + [inputs[0]], + valid_input_dtypes, + self.tosa_spec, + ) + + # Get the attributes of convolution. + pad_attr = pad.special + stride_attr = stride.special + dilation_attr = dilation.special + + input_zp = 0 + if inputs[0].dtype in (ts.DType.INT8, ts.DType.INT16): + # int8 and int16 input requires quantization information + input_qparams = get_input_qparams(node) + input_zp = input_qparams[0].get_zp_per_tensor() + + weight_zp = 0 + if inputs[1].dtype == ts.DType.INT8: + # int8 weights requires quantization information + input_qparams = get_input_qparams(node) + weight_zp = input_qparams[1].zp # type: ignore[assignment] + + conv2d_output_name = output.name + acc_type = output.dtype + + tosa_graph.addConst( + [1], inputs[0].dtype, [input_zp], name=f"{conv2d_output_name}_input_zp" + ) + tosa_graph.addConst( + [1], + inputs[1].dtype, + weight_zp, + name=f"{conv2d_output_name}_weight_zp", + ) + + tosa_op = self._get_tosa_op() + + attr = ts.TosaSerializerAttribute() + self._get_attr_func(attr)( + pad=pad_attr, + stride=stride_attr, + dilation=dilation_attr, + local_bound=False, + acc_type=acc_type, + ) + + self._serialize_operator( + node, + tosa_graph, + tosa_op, + [ + input.name, + weight.name, + bias.name, + f"{conv2d_output_name}_input_zp", + f"{conv2d_output_name}_weight_zp", + ], + [conv2d_output_name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv3d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv3d.py new file mode 100644 index 0000000..e0a8d2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_conv3d.py @@ -0,0 +1,24 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide a visitor for lowering 3D convolution to TOSA (INT/FP).""" + +from executorch.backends.arm.operators.node_visitor import register_node_visitor +from executorch.backends.arm.operators.op_tosa_conv2d import Conv2dVisitor + + +@register_node_visitor +class Conv3dVisitor(Conv2dVisitor): + """Provide a visitor that serializes TOSA ``CONV3D``.""" + + target = "tosa.CONV3D.default" + + def _get_tosa_op(self): + import serializer.tosa_serializer as ts # type: ignore + + return ts.Op.CONV3D + + def _get_attr_func(self, attr): + return attr.Conv3dAttribute diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_depthwise_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_depthwise_conv2d.py new file mode 100644 index 0000000..78e6e44 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_depthwise_conv2d.py @@ -0,0 +1,32 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide a visitor for lowering 2D depthwise convolution to TOSA (INT/FP).""" + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import register_node_visitor +from executorch.backends.arm.operators.op_tosa_conv2d import Conv2dVisitor +from executorch.backends.arm.tosa import TosaSpecification + + +@register_node_visitor +class DepthwiseConv2dVisitor(Conv2dVisitor): + """Provide a visitor that serializes TOSA ``DEPTHWISE_CONV2D``.""" + + target = "tosa.DEPTHWISE_CONV2D.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def _get_tosa_op(self): + return ts.Op.DEPTHWISE_CONV2D + + def _get_attr_func(self, attr): + return attr.DepthwiseConv2dAttribute + + # Inheriting the define_node method from Conv2dVisitor diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_matmul.py new file mode 100644 index 0000000..993caff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_matmul.py @@ -0,0 +1,102 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide a visitor for lowering batched matmul (BMM) to TOSA.""" + +from typing import Any, List + +import torch +import tosa_serializer as ts + +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + get_input_qparams, +) +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class MatmulVisitor(NodeVisitor): + """Provide a visitor that serializes TOSA ``MATMUL``.""" + + target = "tosa.MATMUL.default" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + """Define the TOSA ``MATMUL`` operator.""" + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs], ts) + supported_input_dtypes = [ts.DType.INT8, ts.DType.INT32, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_input_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [*inputs], + supported_input_dtypes, + output.tosa_spec, + ) + supported_output_dtypes = [ts.DType.INT32, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_output_dtypes.append(ts.DType.INT48) + validate_valid_dtype( + self.target, + [output], + supported_output_dtypes, + output.tosa_spec, + ) + + # We need to get the zero points and add an intermediate tensor for INT16 case + if inputs[0].dtype in (ts.DType.INT8, ts.DType.INT16): + input_qparams = get_input_qparams(node) + input0_zp = input_qparams[0].get_zp_per_tensor() + input1_zp = input_qparams[1].get_zp_per_tensor() + else: + input0_zp, input1_zp = 0, 0 + + input_A_ZP_name = f"{output.name}_A_ZP" + input_B_ZP_name = f"{output.name}_B_ZP" + tosa_graph.addConst([1], inputs[0].dtype, [input0_zp], name=input_A_ZP_name) + tosa_graph.addConst([1], inputs[1].dtype, [input1_zp], name=input_B_ZP_name) + + # Add the MATMUL to the TOSA graph. + attr = ts.TosaSerializerAttribute() + attr.MatMulAttribute() + + self._serialize_operator( + node, + tosa_graph, + ts.Op.MATMUL, + [ + inputs[0].name, + inputs[1].name, + input_A_ZP_name, + input_B_ZP_name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_rescale.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_rescale.py new file mode 100644 index 0000000..ae87dcc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_rescale.py @@ -0,0 +1,261 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Any, cast, List, Tuple + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, +) + +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import map_dtype, TosaArg +from torch.fx import Node + + +def _compute_multiplier_and_shift( + scales: list[float], scaleWidth: int = 32 +) -> Tuple[list[int], list[int]]: + """Derive integer multipliers and shifts from floating-point scales. + + TOSA uses the RESCALE operation to scale between values with differing + precision. The RESCALE operator is defined using an integer multiply, add, + and shift. This utility function is for calculating the multiplier and shift + given a scale. + Ref: https://www.mlplatform.org/tosa/tosa_spec.html#_precision_scaling + + Args: + scales (list[float]): Scale factors to decompose into multiplier and + shift pairs. + scaleWidth (int): Bit-width of the multiplier representation; expects + ``16`` or ``32``. + + Returns: + Tuple[list[int], list[int]]: Parallel lists containing the computed + multipliers and right shifts. + + Raises: + ValueError: If ``scaleWidth`` is not supported. + + """ + if scaleWidth == 16: + offset = 15 + elif scaleWidth == 32: + offset = 31 + else: + raise ValueError( + f"Unsupported scale width: {scaleWidth}, only 16 and 32 are valid values." + ) + + multipliers = [] + shifts = [] + for scale in scales: + mantissa, exponent = math.frexp(scale) + shift = exponent + + const_2_power_15_or_31 = 1 << offset + shifted_mantissa = round(mantissa * const_2_power_15_or_31) + + assert ( + shifted_mantissa <= const_2_power_15_or_31 + ), f"Mantissa {shifted_mantissa} exceeds limit {const_2_power_15_or_31}" + + if shifted_mantissa == const_2_power_15_or_31: + shifted_mantissa = shifted_mantissa // 2 + shift += 1 + + # TOSA expects right shift to be positive, and embed (1 << offset) into right shift bits. + shift = offset - shift + + # INT32_MAX, 2^31 - 1 + assert shifted_mantissa <= (const_2_power_15_or_31 - 1), ( + f"Mantissa {shifted_mantissa} exceeds signed max " + f"{const_2_power_15_or_31 - 1}" + ) + + multiplier = shifted_mantissa + + if shift > 62: + multiplier = multiplier >> min(31, shift - 62) + shift = 62 + + assert multiplier >= 0, "Multiplier should be non-negative" + assert shift >= 2 and shift <= 62, "Shift should be in range [2, 62]" + multipliers.append(multiplier) + shifts.append(shift) + return multipliers, shifts + + +def _create_const_ops_for_rescale( + tosa_fb, + scale_32, + input_dtype, + node_name, + multipliers, + shifts, + input_zp, + output_zp, + output_dtype, + ts, +): + """Materialize constant operands required by the TOSA RESCALE op. + + For TOSA spec v1.0 RESCALE operator requires multiplier, shifts, input_zp + and output_zp to be const inputs. Create constant operators from the data + already initialized. + + Args: + tosa_fb (Any): Graph builder used to emit TOSA operators and tensors. + scale_32 (bool): Flag indicating whether multipliers use 32-bit width. + input_dtype (ts.DType): Data type of the input tensor. + node_name (str): Base name reused for created constant tensors. + multipliers (list[int]): Precomputed multiplier coefficients. + shifts (list[int]): Precomputed shift coefficients. + input_zp (list[int]): Quantization zero points for the input. + output_zp (list[int]): Quantization zero points for the output. + output_dtype (ts.DType): Data type of the output tensor. + ts (module): Reference to the ``tosa_serializer`` module. + + Returns: + list[str]: Names of the constant tensors added to ``tosa_fb`` in the + order expected by RESCALE. + + """ + + multipliers = tosa_fb.addConst( + (len(multipliers),), + ts.DType.INT32 if scale_32 else ts.DType.INT16, + multipliers, + name=node_name + "_multipliers", + ) + shifts = tosa_fb.addConst( + (len(shifts),), ts.DType.INT8, shifts, name=node_name + "_shifts" + ) + input_zp = tosa_fb.addConst( + [1], input_dtype, input_zp, name=node_name + "_input_zp" + ) + output_zp = tosa_fb.addConst( + [1], output_dtype, output_zp, name=node_name + "_output_zp" + ) + + return [multipliers.name, shifts.name, input_zp.name, output_zp.name] + + +def _build_rescale( + tosa_fb: Any, + scale: list[float], + input_node: Any, + output_name: str, + output_type: Any, + input_zp: list[int], + output_zp: list[int], + rounding_mode: ts.RoundingMode, + per_channel: bool = False, + is_scale32: bool = True, +): + """Insert a TOSA RESCALE operator configured for the quantized path. + + Args: + tosa_fb (Any): Graph builder receiving the RESCALE operator. + scale (list[float]): Scale factors applied during rescaling. + input_node (Any): Input tensor node feeding the operator. + output_name (str): Name assigned to the RESCALE output tensor. + output_type (ts.DType): Data type of the output tensor. + input_zp (list[int]): Quantization zero points for the input tensor. + output_zp (list[int]): Quantization zero points for the output tensor. + rounding_mode (ts.RoundingMode): Rounding policy for the RESCALE op. + per_channel (bool): Whether scales are applied per output channel. + is_scale32 (bool): Declared scale width; ignored when the input type is + ``ts.DType.INT48``. + + """ + scaleWidth = 16 if input_node.dtype == ts.DType.INT48 else 32 + is_scale32 = False if input_node.dtype == ts.DType.INT48 else True + multipliers, shifts = _compute_multiplier_and_shift(scale, scaleWidth) + rescale_inputs = _create_const_ops_for_rescale( + tosa_fb, + is_scale32, + input_node.dtype, + output_name, + multipliers, + shifts, + input_zp, + output_zp, + output_type, + ts, + ) + attr_rescale = ts.TosaSerializerAttribute() + attr_rescale.RescaleAttribute( + scale32=is_scale32, + rounding_mode=rounding_mode, + per_channel=per_channel, + input_unsigned=False, + output_unsigned=False, + ) + + tosa_fb.addOperator( + ts.Op.RESCALE, + [input_node.name, *rescale_inputs], + [output_name], + attr_rescale, + ) + + +@register_node_visitor +class RescaleVisitor(NodeVisitor): + target = "tosa.RESCALE.default" + + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+INT")] + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 5) + + input_dtype = inputs[0].dtype + output_dtype = cast(torch.dtype, node.args[1]) + scales = cast(list[float], node.args[2]) + input_zp = cast(int, node.args[3]) + output_zp = cast(int, node.args[4]) + + if ( + input_dtype + not in [ + map_dtype(torch.int8, self.tosa_spec), + map_dtype(torch.int16, self.tosa_spec), + ] + and input_zp != 0 + ): + raise ValueError( + f"If input dtype is not int8 or int16, input_zp must be 0. Got input_dtype {input_dtype=}, {input_zp=}" + ) + if output_dtype not in [torch.int8, torch.int16] and output_zp != 0: + raise ValueError( + f"If output dtype is not int8 or int16, output_zp must be 0. Got {ts.DTypeNames[output_dtype]}, {output_zp=}" + ) + + _build_rescale( + tosa_graph, + scale=scales, + input_node=inputs[0], + output_name=output.name, + output_type=output.dtype, + input_zp=[input_zp], + output_zp=[output_zp], + rounding_mode=ts.RoundingMode.SINGLE_ROUND, + per_channel=len(scales) > 1, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_resize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_resize.py new file mode 100644 index 0000000..e7e63f1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_resize.py @@ -0,0 +1,124 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.utils import get_resize_parameters + + +@register_node_visitor +class ResizeVisitor(NodeVisitor): + target = "tosa.RESIZE.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, [3, 4]) + supported_input_dtypes = [ts.DType.INT8, ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_input_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, + [inputs[0]], + supported_input_dtypes, + output.tosa_spec, + ) + supported_output_dtypes = [ts.DType.FP32] + if node.kwargs.get("resize_mode") == "bilinear": + resize_mode = ts.ResizeMode.BILINEAR + align_corners = bool(node.args[2]) + supported_output_dtypes.append(ts.DType.INT32) + if self.tosa_spec.support_extension("int16"): + supported_output_dtypes.append(ts.DType.INT48) + else: + resize_mode = ts.ResizeMode.NEAREST + align_corners = False + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_output_dtypes.append(ts.DType.INT8) + if self.tosa_spec.support_extension("int16"): + supported_output_dtypes.append(ts.DType.INT16) + validate_valid_dtype( + self.target, [output], supported_output_dtypes, output.tosa_spec + ) + # tosa_shape output is NHWC, take HW + input_size_yx = tuple([inputs[0].shape[dim] for dim in inputs[0].dim_order])[ + 1:3 + ] + output_size_yx = tuple([output.shape[dim] for dim in output.dim_order])[1:3] + + # Align corners shouldn't make a difference for nearest upsampling. We set to False so + # half pixel centers are used for resize parameter logic. + scale_n_yx, scale_d_yx, offset_yx, border_yx = get_resize_parameters( + input_size_yx, output_size_yx, resize_mode, align_corners=align_corners + ) + + def in_int16_range(x): + return torch.all(x >= -(2**15)) and torch.all(x <= 2**15 - 1) + + if not in_int16_range(scale_n_yx): + raise ValueError("scale_n_yx is out of the int16 range") + if not in_int16_range(scale_d_yx): + raise ValueError("scale_d_yx is out of the int16 range") + if not in_int16_range(border_yx): + raise ValueError("border_yx is out of the int16 range") + + scale_n_vals = [int(v) for v in scale_n_yx.tolist()] + scale_d_vals = [int(v) for v in scale_d_yx.tolist()] + scales = [ + scale_n_vals[0], + scale_d_vals[0], + scale_n_vals[1], + scale_d_vals[1], + ] + scales_tensor = tosa_graph.addConst( + [len(scales)], ts.DType.SHAPE, scales, output.name + "_scales" + ) + offset = [int(v) for v in offset_yx.tolist()] + offset_tensor = tosa_graph.addConst( + [len(offset)], ts.DType.SHAPE, offset, output.name + "_offset" + ) + border = [int(v) for v in border_yx.tolist()] + border_tensor = tosa_graph.addConst( + [len(border)], ts.DType.SHAPE, border, output.name + "_border" + ) + attr = ts.TosaSerializerAttribute() + attr.ResizeAttribute(resize_mode) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.RESIZE, + [ + inputs[0].name, + scales_tensor.name, + offset_tensor.name, + border_tensor.name, + ], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_table.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_table.py new file mode 100644 index 0000000..7448898 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_table.py @@ -0,0 +1,72 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_valid_dtype, +) + +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class TableVisitor(NodeVisitor): + target = "tosa.TABLE.default" + + tosa_specs = [TosaSpecification.create_from_string("TOSA-1.0+INT")] + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + supported_input_dtypes = [ts.DType.INT8] + supported_output_dtypes = [ts.DType.INT8] + if self.tosa_spec.support_extension("int16"): + supported_input_dtypes.append(ts.DType.INT16) + supported_output_dtypes.append(ts.DType.INT32) + + validate_valid_dtype( + self.target, inputs, supported_input_dtypes, output.tosa_spec + ) + validate_valid_dtype( + self.target, output, supported_output_dtypes, output.tosa_spec + ) + + # The name of the table constant is a bit complex. + # The name of the pytorch buffer will be the target of last node argument. + # However, when it is serialized to TOSA, a submodule suffix might be added. The TOSA buffer name thus + # needs to be taken from the last TosaArg. + pytorch_table_buffer_name = node.args[-1].target # type: ignore[union-attr] + tosa_table_buffer_name = inputs[-1].name + if pytorch_table_buffer_name not in self._exported_program.state_dict.keys(): + raise RuntimeError( + f"Did not find key {node.name} in state_dict {self._exported_program.state_dict.keys()}." + ) + + attr = ts.TosaSerializerAttribute() + attr.TableAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.TABLE, + [inputs[0].name, tosa_table_buffer_name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_transpose.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_transpose.py new file mode 100644 index 0000000..c5aa66a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_tosa_transpose.py @@ -0,0 +1,71 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +@register_node_visitor +class TransposeVisitor(NodeVisitor): + """ + This node visitor targets the tosa::TRANSPOSE op defined in the + TOSA backend dialect. Used when switching between tosa_dim_orders. + Inserts a TOSA TRANSPOSE. + """ + + target = "tosa.TRANSPOSE.default" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP16, + ts.DType.FP32, + ], + output.tosa_spec, + ) + + output_rank = len(output.shape) + perms = [dim % output_rank for dim in inputs[1].special] + attr = ts.TosaSerializerAttribute() + attr.TransposeAttribute(perms) + self._serialize_operator( + node, + tosa_graph, + ts.Op.TRANSPOSE, + [inputs[0].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_view.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_view.py new file mode 100644 index 0000000..a32cb3a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_view.py @@ -0,0 +1,81 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, List + +import torch + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.utils import tosa_shape + + +@register_node_visitor +class ViewVisitor(NodeVisitor): + target = "aten.view_copy.default" + + tosa_specs = NodeVisitor.tosa_specs + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [inputs[0], output], ts) + validate_valid_dtype( + self.target, + [inputs[0], output], + [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ts.DType.FP32, + ts.DType.BOOL, + ], + output.tosa_spec, + ) + + tosa_graph = cast(ts.TosaSerializer, tosa_graph) + + if len(output.shape) != 0: + shape_len = [len(output.shape)] + shape_data = list(tosa_shape(output.shape, output.dim_order)) + else: + shape_len = [] + shape_data = [] + + shape = tosa_graph.addConst( + shape_len, + ts.DType.SHAPE, + shape_data, + name=output.name + "_shape", + ) + + attr = ts.TosaSerializerAttribute() + attr.ReshapeAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.RESHAPE, + [inputs[0].name, shape.name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_where.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_where.py new file mode 100644 index 0000000..f0b6538 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_where.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) + +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.mapping import TosaArg +from torch.fx import Node + + +@register_node_visitor +class WhereVisitor(NodeVisitor): + target = "aten.where.self" + + tosa_specs = [ + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ] + + def __init__(self, *args): + super().__init__(*args) + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + supported_dtypes = [ts.DType.BOOL] + if output.tosa_spec.support_integer(): + supported_dtypes += [ + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ] + if output.tosa_spec.support_float(): + supported_dtypes += [ts.DType.FP16, ts.DType.FP32] + + validate_num_inputs(self.target, inputs, 3) + # Not first input, which is condition tensor. + validate_same_dtype(self.target, inputs[1:], ts) + validate_valid_dtype(self.target, inputs[0], ts.DType.BOOL, output.tosa_spec) + validate_valid_dtype( + self.target, + [*inputs[1:], output], + supported_dtypes, + output.tosa_spec, + ) + + attr = ts.TosaSerializerAttribute() + attr.SelectAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.SELECT, + [inputs[0].name, inputs[1].name, inputs[2].name], + [output.name], + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_while.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_while.py new file mode 100644 index 0000000..b4ac4f4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/op_while.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, cast, List + +import tosa_serializer as ts +from executorch.backends.arm._passes.arm_pass_utils import get_output_dim_orders + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_cf_extension, + validate_num_inputs, +) +from executorch.backends.arm.tosa.mapping import map_dtype, TosaArg +from executorch.backends.arm.tosa.utils import tosa_shape + +from torch.fx import Node + + +@register_node_visitor +class WhileLoopVisitor(NodeVisitor): + target = "while_loop" + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + + validate_num_inputs(self.target, inputs, 4) + validate_cf_extension(self.target, self.tosa_spec) + + carried_inputs = inputs[2].special if hasattr(inputs[2], "special") else None + if carried_inputs is None: + raise ValueError(f"{self.target}: Expected loop input arguments to be set.") + + additional_inputs = inputs[3].special if hasattr(inputs[3], "special") else None + if additional_inputs: + raise ValueError( + "Additional inputs is not supported, use carried inputs instead." + ) + + attr = ts.TosaSerializerAttribute() + cond_graph, body_graph = (str(cast(Node, arg).target) for arg in node.args[:2]) + attr.WhileLoopAttribute(cond_graph, body_graph) + + input_names: list[str] = [] + for loop_input in carried_inputs: + if not isinstance(loop_input, Node): + raise ValueError( + f"{self.target}: Unsupported carried input type {type(loop_input)}." + ) + input_names.append(loop_input.name) + + num_inputs = len(input_names) + num_outputs = len(output.multiple_output_names) + if num_inputs > num_outputs: + # If we have more inputs than outputs, we can just add missing output tensors. + body_module = getattr(node.graph.owning_module, body_graph) + output_dim_orders = get_output_dim_orders(body_module) + body_outputs = body_module.graph.output_node().args[0] + outputs_needing_tensors = body_outputs[num_outputs - num_inputs :] + output_dim_orders = output_dim_orders[num_outputs - num_inputs :] + for ( + output_needing_tensor, + dim_order, + ) in zip(outputs_needing_tensors, output_dim_orders, strict=True): + tensor_name = output_needing_tensor.name + "_dummy" + shape = output_needing_tensor.meta["val"].shape + dtype = map_dtype( + output_needing_tensor.meta["val"].dtype, self.tosa_spec + ) + + tosa_graph.currRegion.currBasicBlock.addTensor( + tensor_name, + tosa_shape(shape, dim_order), + dtype, + ) + output.multiple_output_names.append(tensor_name) + elif num_inputs < num_outputs: + # This is a strange case, if we reach it something bad has happened. + raise ValueError( + f"TOSA specifies that the number of inputs, {input_names}, need to be the " + f"same as the number of outputs, {output.multiple_output_names}." + ) + + self._serialize_operator( + node, + tosa_graph, + ts.Op.WHILE_LOOP, + input_names, + output.multiple_output_names, + attr, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/operator_validation_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/operator_validation_utils.py new file mode 100644 index 0000000..20ee105 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/operator_validation_utils.py @@ -0,0 +1,201 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide validation helpers for operator inputs and dtypes. + +Use these utilities to validate input counts, ensure dtype consistency, check +allowed dtypes, and compute pooling padding adjustments. + +""" + +from math import ceil, floor +from typing import Any, List, Optional + +from executorch.backends.arm.tosa.specification import Tosa_1_00, TosaSpecification + + +def validate_num_inputs(op_name: str, inputs: List[Any], expected: int | List[int]): + """Validate the number of inputs against expected values. + + This function checks whether the length of the input list matches the + expected number(s) of inputs. + + Args: + op_name (str): The name of the operation for which the inputs are being + validated. Used in the error message to provide context. + inputs (List[TosaArg]): A list of inputs to be validated, where each + input is assumed to be an instance of ``TosaArg``. + expected (int | List[int]): The expected number of inputs. Can be either + an integer or a list of integers. + + Raises: + ValueError: If the number of inputs does not match the expected + value(s); the message indicates the operation name and the mismatch + in expected versus provided counts. + + Example: + from executorch.backends.arm.operators.operator_validation_utils import \ + validate_num_inputs + + validate_num_inputs(self.target, inputs, [3, 4]) + + """ + if isinstance(expected, int): + expected = [expected] + if len(inputs) not in expected: + expected_str = ", ".join(map(str, expected)) + raise ValueError( + f"{op_name}: Expected number of input(s) to be " + f"[{expected_str}], got {len(inputs)}" + ) + + +def validate_same_dtype(op_name: str, tensors: List[Any], ts: Optional[Any] = None): + """Validate that all given tensors have the same dtype. + + This function checks whether all items in the ``tensors`` list have the + same ``dtype`` as the first item. + + Args: + op_name (str): The name of the operation for which the dtype validation + is being performed. Used in the error message to provide context. + tensors (List[Any]): A list of tensors to be validated, each assumed to + have a ``dtype`` attribute. + ts (Optional[Any]): TOSA serializer (optional) to improve readability of + dtype names in error messages. + + Raises: + ValueError: If the dtype of any item in the list does not match the + dtype of the first item, or if the list is empty. + + Example: + from executorch.backends.arm.operators.operator_validation_utils import \ + validate_same_dtype + + validate_same_dtype(self.target, [input1, input2, output]) + + """ + if not tensors: + raise ValueError( + f"{op_name}: Input tensor list is empty, cannot validate dtypes" + ) + + # Get dtype of the first tensor to reference for comparison + reference_dtype = tensors[0].dtype + reference_dtype_name = str(reference_dtype) + + for tensor in tensors: + if tensor.dtype != reference_dtype: + inconsistent_dtype_name = str(tensor.dtype) + raise ValueError( + f"{op_name}: Expected all tensors to have dtype {reference_dtype_name}, " + f"but found inconsistent dtype {inconsistent_dtype_name}." + ) + + +def validate_valid_dtype( + op_name: str, tensors: Any | List[Any], valid_dtypes: Any | List[Any], tosa_spec +): + """Validate that one or more tensors have allowed dtypes. + + This function checks whether the ``dtype`` attribute of the provided + tensor(s) is one of the valid dtype values. It supports checking a single + tensor or a list of tensors. + + Args: + op_name (str): The name of the operation performing the validation. + tensors (Any | List[Any]): A tensor or list of tensors (each assumed to + have ``dtype`` and ``name`` attributes) whose dtype will be + validated. + valid_dtypes (Any | List[Any]): A dtype enum or list of dtype enums + representing allowed dtype values. + tosa_spec (Any): A TosaSpecification instance indicating which TOSA + version is targeted. This determines which serializer to use for + dtype name resolution. + + Raises: + ValueError: If no tensors are provided, or if any tensor has a dtype not + in ``valid_dtypes``. + + Example: + from executorch.backends.arm.operators.operator_validation_utils import \ + validate_valid_dtype + import serializer.tosa_serializer as ts + + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT32], + output.tosa_spec, + ) + + """ + if not tensors: + raise ValueError( + f"{op_name}: Input tensor list is empty, cannot validate dtypes" + ) + + if not isinstance(valid_dtypes, List): + valid_dtypes = [valid_dtypes] + + if not isinstance(tensors, List): + tensors = [tensors] + + for tensor in tensors: + if tensor.dtype not in valid_dtypes: + valid_names = [str(dtype) for dtype in valid_dtypes] + got_name = str(tensor.dtype) + raise ValueError( + f"Expected tensor {tensor.name} in {op_name} to have one of the " + f"following dtypes: {valid_names}, got: {got_name}" + ) + + +def validate_cf_extension(op_name: str, tosa_spec: TosaSpecification) -> None: + """Ensure that the requested control-flow operator is supported by the active TOSA spec.""" + if not isinstance(tosa_spec, Tosa_1_00): + raise ValueError( + f"Got TOSA version {tosa_spec.version}, that does not support extensions." + ) + if not tosa_spec.support_extension("cf"): + raise ValueError( + f"Trying to lower {op_name}, but TOSA specification {tosa_spec} does not " + "support the cf extension." + ) + + +def adjust_pooling_pad_if_needed( + input_size: int, kernel_size: int, stride: int, pad: int, ceil_mode: bool +) -> int: + """Compute the post padding needed for pooling. + + ATen pooling uses a single symmetric ``pad`` per dimension and rounds the + output size up or down depending on ``ceil_mode``. TOSA requires distinct + pre- and post-padding values that satisfy: + + output_size == (input_size + pre_pad + post_pad - kernel_size) / stride + 1 + + This function returns the required ``post_pad`` given a symmetric ``pad``. + + Args: + input_size (int): Input size. + kernel_size (int): Kernel size. + stride (int): Stride size. + pad (int): Symmetric padding specified by ATen. + ceil_mode (bool): Use ceil when computing output size. + + Returns: + int: Post-padding to satisfy the TOSA formula. + + """ + if ceil_mode: + output_size = ceil((input_size - kernel_size + 2 * pad) / stride) + 1 + else: + output_size = floor((input_size - kernel_size + 2 * pad) / stride) + 1 + + # Solve for post_pad from + # output_size = (input_size + pre_pad + post_pad - kernel_size) / stride + 1 + adjusted_post_pad = (output_size - 1) * stride - input_size + kernel_size - pad + + return adjusted_post_pad diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_binary.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_binary.py new file mode 100644 index 0000000..3e8cda7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_binary.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, Callable, List + +import torch +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def binary_operator_factory( + bw_target: str, tosa_op, attr_builder: Callable[[Any], None] +): + """Creates and registers NodeVisitors for operators that have two inputs and map directly to a TOSA op.""" + + class BinaryOperator(NodeVisitor): + target = bw_target + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 2) + validate_same_dtype(self.target, [*inputs, output], ts) + + if self.target in [ + "aten.bitwise_and.Tensor", + "aten.bitwise_xor.Tensor", + "aten.bitwise_or.Tensor", + "aten.bitwise_left_shift.Tensor", + ]: + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.INT8, ts.DType.INT16, ts.DType.INT32], + output.tosa_spec, + ) + if self.target in [ + "aten.logical_and.default", + "aten.logical_xor.defaul", + "aten.logical_or.default", + ]: + validate_valid_dtype( + self.target, + [*inputs, output], + [ts.DType.BOOL], + output.tosa_spec, + ) + attr = ts.TosaSerializerAttribute() + attr_builder(attr) + self._serialize_operator( + node, + tosa_graph, + tosa_op, + [inputs[0].name, inputs[1].name], + [output.name], + attr, + ) + + register_node_visitor(BinaryOperator) + + +binary_operator_factory( + "aten.bitwise_and.Tensor", + ts.Op.BITWISE_AND, + lambda attr: attr.BitwiseAndAttribute(), +) +binary_operator_factory( + "aten.bitwise_xor.Tensor", + ts.Op.BITWISE_XOR, + lambda attr: attr.BitwiseXorAttribute(), +) +binary_operator_factory( + "aten.bitwise_or.Tensor", ts.Op.BITWISE_OR, lambda attr: attr.BitwiseOrAttribute() +) +binary_operator_factory( + "aten.logical_and.default", + ts.Op.LOGICAL_AND, + lambda attr: attr.LogicalAndAttribute(), +) +binary_operator_factory( + "aten.logical_xor.default", + ts.Op.LOGICAL_XOR, + lambda attr: attr.LogicalXorAttribute(), +) +binary_operator_factory( + "aten.logical_or.default", ts.Op.LOGICAL_OR, lambda attr: attr.LogicalOrAttribute() +) +binary_operator_factory( + "aten.bitwise_left_shift.Tensor", + ts.Op.LOGICAL_LEFT_SHIFT, + lambda attr: attr.LogicalLeftShiftAttribute(), +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_identity.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_identity.py new file mode 100644 index 0000000..0930d7e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/operators/ops_identity.py @@ -0,0 +1,80 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, List + +import torch +import torch.fx + +import tosa_serializer as ts + +from executorch.backends.arm.operators.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.arm.operators.operator_validation_utils import ( + validate_num_inputs, + validate_same_dtype, + validate_valid_dtype, +) +from executorch.backends.arm.tosa.mapping import TosaArg + + +def identity_operator_factory(identity_target: str): + """ + Creates and registers NodeVisitors for operators that map directly + to a TOSA IDENTITY op. + """ + + class IdentityOperatorVisitor(NodeVisitor): + target = identity_target + + tosa_specs = NodeVisitor.tosa_specs + + def define_node( + self, + node: torch.fx.Node, + tosa_graph: Any, + inputs: List[TosaArg], + output: TosaArg, + ) -> None: + validate_num_inputs(self.target, inputs, 1) + validate_same_dtype(self.target, [inputs[0], output], ts) + supported_dtypes = [ + ts.DType.BOOL, + ts.DType.INT8, + ts.DType.INT16, + ts.DType.INT32, + ] + if output.tosa_spec.support_float(): + supported_dtypes += [ts.DType.FP32] + if self.tosa_spec.support_extension("int16"): + supported_dtypes += [ts.DType.INT48] + if self.tosa_spec.support_extension("int4"): + supported_dtypes += [ts.DType.INT4] + validate_valid_dtype( + self.target, + [inputs[0], output], + supported_dtypes, + output.tosa_spec, + ) + + # Simply add an identityOp + attr = ts.TosaSerializerAttribute() + attr.IdentityAttribute() + self._serialize_operator( + node, + tosa_graph, + ts.Op.IDENTITY, + [inputs[0].name], + [output.name], + attr, + ) + + register_node_visitor(IdentityOperatorVisitor) + + +identity_operator_factory("aten.alias_copy.default") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/process_node.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/process_node.py new file mode 100644 index 0000000..b85b1b4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/process_node.py @@ -0,0 +1,230 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +import operator +from typing import Any, cast, Dict + +import numpy as np +import torch +import torch.fx +import tosa_serializer as ts +from executorch.backends.arm.operators.node_visitor import NodeVisitor +from executorch.backends.arm.tosa.mapping import TosaArg +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.arm.tosa.utils import tosa_shape +from torch._export.utils import ( + get_buffer, + get_lifted_tensor_constant, + get_param, + is_buffer, + is_lifted_tensor_constant, + is_param, +) +from torch.export.exported_program import ExportedProgram + + +def process_call_function( + node: torch.fx.Node, + tosa_graph: Any, + node_visitors: Dict[str, NodeVisitor], + tosa_spec: TosaSpecification, +): + # Unpack arguments and convert + try: + inputs = [TosaArg(arg, tosa_spec) for arg in node.args] + except ValueError as e: + raise ValueError(f"Failed processing args to op:\n{node}") from e + + # Convert output (this node itself) + try: + output = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing call_function: {node.name}. " + "Is the original torch function supported?" + ) from e + + if not output.multiple_output_names: + tosa_graph.currRegion.currBasicBlock.addTensor( + output.name, tosa_shape(output.shape, output.dim_order), output.dtype + ) + + # Get item nodes just add tensors, no node visitor is needed. + if node.target == operator.getitem: + return + + # Visiting each Node + if node.target.__name__ in node_visitors: # type: ignore[union-attr] + node_visitors[node.target.__name__].define_node( # type: ignore[union-attr] + node, + tosa_graph, + inputs, + output, + ) + else: + raise RuntimeError(f"Unknown operator {node.target} for TOSA : {tosa_spec}") + + +def process_inputs( + node: torch.fx.Node, + tosa_graph: Any, + tosa_spec: TosaSpecification, +): + """Serialize an input node""" + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing input placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + + input_shape = tosa_arg.shape + input_dim_order = tosa_arg.dim_order + tensor = ts.TosaSerializerTensor( + tosa_arg.name, + tosa_shape(input_shape, input_dim_order), + tosa_arg.dtype, + data=None, + ) + tosa_graph.addInputTensor(tensor) + + +def process_inputs_to_parameters( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + tosa_spec: TosaSpecification, +): + """Serialize bias and non-quantized weights""" + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing parameter placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + parameter_data = get_param(edge_program, node) + + if not isinstance(parameter_data, torch.Tensor): + raise TypeError( + f"Expected parameter '{node.name}' to be a torch.Tensor, got " + f"{type(parameter_data).__name__}" + ) + parameter_values = parameter_data.detach().numpy() + + parameter_values = np.transpose(parameter_values, tosa_arg.dim_order) + + tosa_graph.addConst( + parameter_values.shape, tosa_arg.dtype, parameter_values, name=tosa_arg.name + ) + + +def process_inputs_to_buffers( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + tosa_spec: TosaSpecification, +): + """Serialize quantized weights""" + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing buffer placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + buffer_data = get_buffer(edge_program, node) + + if not isinstance(buffer_data, torch.Tensor): + raise TypeError( + f"Expected buffer '{node.name}' to be a torch.Tensor, got " + f"{type(buffer_data).__name__}" + ) + buffer_values = buffer_data.detach().numpy() + + # TODO: fragile code for temporary fix + # the mean and var tensors are also stored here but they have shape (1, ) + # we only transpose weights here + buffer_values = np.transpose(buffer_values, tosa_arg.dim_order) + + tosa_graph.addConst( + buffer_values.shape, tosa_arg.dtype, buffer_values, name=tosa_arg.name + ) + + +def process_inputs_to_lifted_tensor_constants( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + tosa_spec: TosaSpecification, +): + try: + tosa_arg = TosaArg(node, tosa_spec) + except ValueError as e: + raise ValueError( + f"Failed processing lifted tensor constant placeholder: {node.name}. " + "Is the original torch function supported?" + ) from e + tensor = get_lifted_tensor_constant(edge_program, node) + tensor_data = tensor.detach().numpy() # type: ignore[union-attr] + tensor_values = np.transpose(tensor_data, tosa_arg.dim_order) + + tosa_graph.addConst( + tensor_values.shape, tosa_arg.dtype, tensor_values, name=tosa_arg.name + ) + + +def _is_submodule_input( + node: torch.fx.Node, containing_graph_module: torch.fx.GraphModule +) -> bool: + """Determines whether 'node' is an input to a submodule of 'containing_graph_module'.""" + if node.op != "placeholder": + return False + return node.meta.get("is_input", False) + + +def process_placeholder( + node: torch.fx.Node, + tosa_graph: Any, + edge_program: ExportedProgram, + containing_graph_module: torch.fx.GraphModule | None, + tosa_spec: TosaSpecification, +): + """Wrapper for processing and serializing all types of placeholders""" + if node.name != node.target: + raise ValueError( + f"Placeholder name '{node.name}' does not match target '{node.target}'" + ) + if len(node.args) != 0: + raise ValueError(f"Placeholder '{node.name}' must not have default values") + + if node.name in edge_program.graph_signature.user_inputs: + process_inputs(node, tosa_graph, tosa_spec) + elif containing_graph_module and _is_submodule_input(node, containing_graph_module): + process_inputs(node, tosa_graph, tosa_spec) + elif is_param(edge_program, node): + process_inputs_to_parameters(node, tosa_graph, edge_program, tosa_spec) + elif is_buffer(edge_program, node): + process_inputs_to_buffers(node, tosa_graph, edge_program, tosa_spec) + elif is_lifted_tensor_constant(edge_program, node): + process_inputs_to_lifted_tensor_constants( + node, tosa_graph, edge_program, tosa_spec + ) + elif node.name in edge_program.graph_signature.inputs_to_lifted_custom_objs: + raise NotImplementedError( + "Placeholder is of type 'lifted custom object' which is not supported." + ) + else: + raise RuntimeError(f"Placeholder '{node.name}' is of unknown type.") + + +def process_output(node: torch.fx.Node, tosa_graph: Any, tosa_spec: TosaSpecification): + for output in cast(tuple[torch.fx.Node, ...], node.args[0]): + output_arg = TosaArg(output, tosa_spec) + tosa_graph.addOutputTensor( + tosa_graph.currRegion.currBasicBlock.tensors[output_arg.name] + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/TARGETS new file mode 100644 index 0000000..1a02340 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/TARGETS @@ -0,0 +1,54 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +# Exposed through __init__.py +runtime.python_library( + name = "quantization_config", + srcs = ["quantization_config.py"], + deps = [ + "//caffe2:torch", + "//pytorch/ao:torchao", + ], +) + +# Exposed through __init__.py +runtime.python_library( + name = "arm_quantizer", + srcs = ["arm_quantizer.py"], + deps = [ + ":arm_quantizer_utils", + ":quantization_annotator", + "//caffe2:torch", + "//executorch/exir:lib", + "//pytorch/ao:torchao", + ], +) + +runtime.python_library( + name = "quantization_annotator", + srcs = ["quantization_annotator.py"], + deps = [ + ":arm_quantizer_utils", + ":quantization_config", + "//caffe2:torch", + "//pytorch/ao:torchao", + ], +) + +runtime.python_library( + name = "arm_quantizer_utils", + srcs = ["arm_quantizer_utils.py"], + deps = [ + ":quantization_config", + "//pytorch/ao:torchao", + ], +) + +runtime.python_library( + name = "lib", + srcs = ["__init__.py"], + deps = [ + ":arm_quantizer", + ":quantization_config", + ":arm_quantizer_utils", + ] +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/__init__.py new file mode 100644 index 0000000..2018b84 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/__init__.py @@ -0,0 +1,35 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Expose quantizer APIs and load optional quantized kernels. + +Import the public quantizer classes and configuration helpers for Arm +backends. Attempt to load portable and quantized libraries; fall back to a +log message if unavailable. +""" + +from .quantization_config import QuantizationConfig # noqa # usort: skip +from .arm_quantizer import ( # noqa + EthosUQuantizer, + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, + VgfQuantizer, +) + +# Used in tests +from .arm_quantizer_utils import is_annotated # noqa + +# Load quantized ops library. +try: + import executorch.extension.pybindings.portable_lib + import executorch.kernels.quantized # noqa +except: + import logging + + logging.info( + "Failed to load portable_lib and quantized_aot_lib. To run quantized kernels AOT, either build " + "Executorch with pybindings, or load your own custom built op library using torch.ops.load_library." + ) + del logging diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer.py new file mode 100644 index 0000000..fb65455 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer.py @@ -0,0 +1,710 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Quantizer for Arm backend +# + +from __future__ import annotations + +import functools +from typing import Any, Callable, Dict, Iterable, List, Optional + +import torch +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from executorch.backends.arm.ethosu import EthosUCompileSpec + +from executorch.backends.arm.quantizer import QuantizationConfig +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.common.arm_compile_spec import ( + ArmCompileSpec, +) # isort: skip +from executorch.backends.arm.vgf import VgfCompileSpec +from executorch.exir.graph_module import get_cond_while_submodules + +from torch.fx import GraphModule, Node +from torchao.quantization.pt2e import ( + FakeQuantize, + FusedMovingAvgObsFakeQuantize, + HistogramObserver, + MinMaxObserver, + MovingAverageMinMaxObserver, + ObserverOrFakeQuantizeConstructor, + PerChannelMinMaxObserver, + PlaceholderObserver, +) +from torchao.quantization.pt2e.quantize_pt2e import ( + convert_pt2e, + prepare_pt2e, + prepare_qat_pt2e, +) + +from torchao.quantization.pt2e.quantizer import ( + annotate_input_qspec_map, + annotate_output_qspec, + get_module_name_filter, + QuantizationSpec, + Quantizer, +) + +from .arm_quantizer_utils import is_annotated, mark_node_as_annotated +from .quantization_annotator import annotate_graph + +__all__ = [ + "TOSAQuantizer", + "EthosUQuantizer", + "VgfQuantizer", + "get_symmetric_a16w8_quantization_config", + "get_symmetric_quantization_config", +] + + +@functools.lru_cache +def get_symmetric_quantization_config( + is_per_channel: bool = True, + is_qat: bool = False, + is_dynamic: bool = False, + act_qmin: int = -128, + act_qmax: int = 127, + weight_qmin: int = -127, + weight_qmax: int = 127, +) -> QuantizationConfig: + """Create symmetric quantization config for activations and weights. + + Args: + is_per_channel (bool): Whether to use per-channel quantization for + weights. + is_qat (bool): Whether the configuration targets quantization aware + training. + is_dynamic (bool): Whether to generate dynamic activation observers. + act_qmin (int): Minimum activation quantization value. + act_qmax (int): Maximum activation quantization value. + weight_qmin (int): Minimum weight quantization value. + weight_qmax (int): Maximum weight quantization value. + + Returns: + QuantizationConfig: Quantization settings for activations, weights, and + bias. + + """ + extra_args: Dict[str, Any] = {"eps": 2**-12} + if is_qat: + if is_dynamic: + act_observer_or_fake_quant_ctr = FakeQuantize + dynamic_quant_observer = MovingAverageMinMaxObserver.with_args( + averaging_constant=1 + ) + extra_args["observer"] = dynamic_quant_observer + else: + act_observer_or_fake_quant_ctr = FusedMovingAvgObsFakeQuantize # type: ignore[assignment] + else: + if is_dynamic: + act_observer_or_fake_quant_ctr = PlaceholderObserver # type: ignore[assignment] + else: + act_observer_or_fake_quant_ctr = HistogramObserver # type: ignore[assignment] + + act_quantization_spec = QuantizationSpec( + dtype=torch.int8, + quant_min=act_qmin, + quant_max=act_qmax, + qscheme=torch.per_tensor_affine, + is_dynamic=is_dynamic, + observer_or_fake_quant_ctr=act_observer_or_fake_quant_ctr.with_args( + **extra_args, + ), + ) + + # Setup quantization config for weights + weight_qscheme = ( + torch.per_channel_symmetric if is_per_channel else torch.per_tensor_symmetric + ) + weight_observer_or_fake_quant_ctr: ObserverOrFakeQuantizeConstructor = ( + MinMaxObserver + ) + + # Determine the right observer/fake-quant constructor + if is_qat: + if is_per_channel: + weight_observer_or_fake_quant_ctr = FakeQuantize.with_args( + observer=PerChannelMinMaxObserver, + quant_min=weight_qmin, + quant_max=weight_qmax, + dtype=torch.qint8, + qscheme=torch.per_channel_symmetric, + reduce_range=False, + ch_axis=0, + **extra_args, + ) + else: + # Set plain fake-quant with true min/max + weight_observer_or_fake_quant_ctr = FakeQuantize.with_args(**extra_args) + else: + # PTQ: set min/max observer + weight_observer_or_fake_quant_ctr = ( + PerChannelMinMaxObserver if is_per_channel else MinMaxObserver + ) + weight_observer_or_fake_quant_ctr = weight_observer_or_fake_quant_ctr.with_args( + **extra_args, + ) + + weight_quantization_spec = QuantizationSpec( + dtype=torch.int8, + quant_min=weight_qmin, + quant_max=weight_qmax, + qscheme=weight_qscheme, + ch_axis=0, + is_dynamic=False, + observer_or_fake_quant_ctr=weight_observer_or_fake_quant_ctr, + ) + + bias_quantization_spec = None + if is_dynamic: + quantization_config = QuantizationConfig( + act_quantization_spec, + None, + weight_quantization_spec, + bias_quantization_spec, + ) + else: + quantization_config = QuantizationConfig( + act_quantization_spec, + act_quantization_spec, + weight_quantization_spec, + bias_quantization_spec, + ) + return quantization_config + + +def get_symmetric_a8w4_quantization_config( + is_per_channel: bool = True, is_qat: bool = True, is_dynamic: bool = False +): + return get_symmetric_quantization_config( + is_per_channel, is_qat, is_dynamic, weight_qmin=-7, weight_qmax=7 + ) + + +@functools.lru_cache +def get_symmetric_a16w8_quantization_config( + is_per_channel: bool = True, + is_qat: bool = False, + is_dynamic: bool = False, + weight_qmin: int = -127, + weight_qmax: int = 127, + epsilon: float = 2**-12, +) -> QuantizationConfig: + """16A8W quantization config: 16-bit activations, 8-bit weights. + + This configuration provides better accuracy than 8A8W while maintaining + reasonable memory usage through 8-bit weights. + + Args: + is_per_channel (bool): Whether to use per-channel quantization for + weights. + is_qat (bool): Whether this is for quantization aware training. + is_dynamic (bool): Whether to use dynamic quantization. + weight_qmin (int): Minimum quantization value for weights. + weight_qmax (int): Maximum quantization value for weights. + epsilon (float): Value used to pad observed [qmin, qmax] before initial + zero-point and scale calculation. + + Returns: + QuantizationConfig: Configuration with 16-bit activations and 8-bit + weights. + + """ + extra_args: Dict[str, Any] = {"eps": epsilon} + + # Setup observer/fake-quant for 16-bit activations + if is_qat: + if is_dynamic: + act_observer_or_fake_quant_ctr = FakeQuantize + dynamic_quant_observer = MovingAverageMinMaxObserver.with_args( + averaging_constant=1 + ) + extra_args["observer"] = dynamic_quant_observer + else: + act_observer_or_fake_quant_ctr = FusedMovingAvgObsFakeQuantize # type: ignore[assignment] + else: + if is_dynamic: + act_observer_or_fake_quant_ctr = PlaceholderObserver # type: ignore[assignment] + else: + # HistogramObserver works well for 16-bit range + act_observer_or_fake_quant_ctr = HistogramObserver # type: ignore[assignment] + + # 16-bit activation quantization spec + act_quantization_spec = QuantizationSpec( + dtype=torch.int16, + quant_min=torch.iinfo(torch.int16).min + 1, # -32767 + quant_max=torch.iinfo(torch.int16).max, # 32767 + qscheme=torch.per_tensor_symmetric, + is_dynamic=is_dynamic, + observer_or_fake_quant_ctr=act_observer_or_fake_quant_ctr.with_args( + **extra_args, + ), + ) + + # Instead of reconstructing quantization_config, just clone and update as needed + # Clone the quantization_config from get_symmetric_quantization_config and update activation spec + base_config = get_symmetric_quantization_config( + is_per_channel=is_per_channel, + is_qat=is_qat, + is_dynamic=is_dynamic, + ) + # Replace activation quantization spec with 16-bit version + if is_dynamic: + quantization_config = QuantizationConfig( + act_quantization_spec, # 16-bit input activations + None, + base_config.weight, # 8-bit weights from base config + None, + ) + else: + quantization_config = QuantizationConfig( + act_quantization_spec, # 16-bit input activations + act_quantization_spec, # 16-bit output activations + base_config.weight, # 8-bit weights from base config + None, + ) + return quantization_config + + +NodeFilterType = Callable[[Node], bool] +"""Type for a Node Filter used by annotators. + +A Node filter is a function that takes a Node and returns whether the node +should be annotated or not. + +""" + + +def _get_module_type_filter(tp: Callable) -> NodeFilterType: + """Get the module_type_filter function for a given module type. + + The filter accepts a node and checks if the node comes from a module that + has a certain module type. + + Args: + tp (Callable): Module class to match against the graph node metadata. + + Returns: + NodeFilterType: Predicate that returns True for nodes from the module + type. + + For example: + node: linear_op = call_function[...](...) # type Block -> Sub -> Linear + + >> module_type_filter = _get_module_type_filter(Sub) + >> print(module_type_filter(node)) + True # the node is from the submodule `Sub` (same for `Block` and `Linear`) + + """ + tp_str = tp.__module__ + "." + tp.__qualname__ + + def module_type_filter(n: Node) -> bool: + """Return True if the node originates from the target module type.""" + # node_stack example: { + # 'L__self___sub': ("L['self'].sub", ), + # 'L__self___sub_linear': ("L['self'].sub.linear", ) + # } + nn_module_stack = n.meta.get("nn_module_stack", {}) + types = [t for _, t in nn_module_stack.values()] + return tp_str in types + + return module_type_filter + + +def _get_not_module_type_or_name_filter( + tp_list: List[Callable], module_name_list: List[str] +) -> NodeFilterType: + """Create a filter that excludes provided module types and names. + + Args: + tp_list (List[Callable]): Module types to exclude from annotation. + module_name_list (List[str]): Module names to exclude from annotation. + + Returns: + NodeFilterType: Filter that returns True when the node does not match + any provided module type or name. + + """ + module_type_filters = [_get_module_type_filter(tp) for tp in tp_list] + module_name_list_filters = [get_module_name_filter(m) for m in module_name_list] + + def not_module_type_or_name_filter(n: Node) -> bool: + """Return True when the node matches none of the blocked filters.""" + return not any(f(n) for f in module_type_filters + module_name_list_filters) + + return not_module_type_or_name_filter + + +def _get_composite_filter( + filters: List[NodeFilterType], reduce_func: Callable[[Iterable[bool]], bool] +): + """Get a composite filter function given a list of filters, the composite + filter accepts a node and checks it with every filter in the list. The + filters' outputs are reduced into a single bool output using reduce_func. + + Example: + >>> filters = [ + ... _get_module_name_filter("blocks.sub"), + ... _get_module_type_filter(torch.nn.Linear), + ... ] + >>> composite = _get_composite_filter(filters, any) + >>> composite(node) # True if any individual filter matches + True + """ + + def composite_filter(n: Node) -> bool: + return reduce_func((f(n) for f in filters)) + + return composite_filter + + +class TOSAQuantizer(Quantizer): + """Manage quantization annotations for TOSA-compatible backends.""" + + def __init__( + self, compile_spec_or_tosa_spec: TosaSpecification | ArmCompileSpec + ) -> None: + super().__init__() + self.compile_spec: ArmCompileSpec + if isinstance(compile_spec_or_tosa_spec, TosaSpecification): + from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec + + self.compile_spec = TosaCompileSpec(compile_spec_or_tosa_spec) + self.tosa_spec = self.compile_spec.tosa_spec + elif isinstance(compile_spec_or_tosa_spec, ArmCompileSpec): + self.compile_spec = compile_spec_or_tosa_spec + self.tosa_spec = self.compile_spec.tosa_spec + else: + raise TypeError( + f"TOSAQuantizer constructor expects " + f"a TosaSpecification or compile_spec list, " + f"got {type(compile_spec_or_tosa_spec)}" + ) + + self.global_config: Optional[QuantizationConfig] = None + self.io_config: Optional[QuantizationConfig] = None + self.module_type_config: Dict[Callable, Optional[QuantizationConfig]] = {} + self.module_name_config: Dict[str, Optional[QuantizationConfig]] = {} + + def set_global(self, quantization_config: QuantizationConfig) -> TOSAQuantizer: + """Set quantization_config for submodules not matched by other filters. + + Args: + quantization_config (QuantizationConfig): Configuration to apply to + modules that are not captured by name or type filters. + + """ + self.global_config = quantization_config + return self + + def set_module_type( + self, module_type: Callable, quantization_config: QuantizationConfig + ) -> TOSAQuantizer: + """Set quantization_config for submodules with a given module type. + + For example, calling set_module_type(Sub) quantizes supported patterns + in each Sub instance with the provided quantization_config. + + Args: + module_type (Callable): Type whose submodules should use the + provided quantization configuration. + quantization_config (QuantizationConfig): Configuration to apply to + submodules of the given type. + + """ + self.module_type_config[module_type] = quantization_config + return self + + def set_module_name( + self, module_name: str, quantization_config: Optional[QuantizationConfig] + ) -> TOSAQuantizer: + """Set quantization_config for submodules with a given module name. + + For example, calling set_module_name("blocks.sub") quantizes supported + patterns for that submodule with the provided quantization_config. + + Args: + module_name (str): Fully qualified module name to configure. + quantization_config (QuantizationConfig): Configuration applied to + the named submodule. + + """ + # Validate that quantization_config is provided + self.module_name_config[module_name] = quantization_config + return self + + def set_io(self, quantization_config: QuantizationConfig) -> TOSAQuantizer: + """Set quantization_config for input and output nodes. + + Args: + quantization_config (QuantizationConfig): Configuration describing + activation quantization for model inputs and outputs. + + """ + self.io_config = quantization_config + return self + + def _set_disallow_tfa_for_nodes(self, model: GraphModule) -> None: + """Populate `disallow_tfa` metadata for each FX node. + + Transform-for-annotation passes inspect this flag to decide whether + they may transform a node. Typically, a node should not be transformed + in case it is not to be quantized, which is relevant for partially + quantized models. + """ + + unquantized_modules_types = [ + m + for m in self.module_type_config.keys() + if self.module_type_config[m] is None + ] + module_filters = [ + _get_module_type_filter(module_type) + for module_type in unquantized_modules_types + ] + # Create a composite filter that returns True if any of the + # "unquantized" modules contains the node. + composite_filter = _get_composite_filter(module_filters, any) + + for node in model.graph.nodes: + node.meta[DISALLOW_TFA_META_KEY] = composite_filter(node) + + def transform_for_annotation(self, model: GraphModule) -> GraphModule: + """Transform the graph to prepare it for quantization annotation. + + Currently transforms scalar values to tensor attributes. + + Args: + model (GraphModule): Model whose graph will be transformed. + + Returns: + GraphModule: Transformed model prepared for annotation. + + """ + + self._set_disallow_tfa_for_nodes(model) + + # TODO: Fix the need to lazily import this. + from executorch.backends.arm._passes import ArmPassManager + + pass_manager = ArmPassManager(self.compile_spec) + return pass_manager.transform_for_annotation_pipeline(graph_module=model) + + def annotate(self, model: GraphModule) -> GraphModule: + """Annotate the graph with the configured quantization settings. + + Currently only does static quantization annotation. + + Args: + model (GraphModule): Model to annotate statically. + + Returns: + GraphModule: Annotated model ready for export. + + """ + model = self._annotate_for_static_quantization_config(model) + return model + + def _annotate_all_static_patterns( + self, + model: GraphModule, + quantization_config: Optional[QuantizationConfig], + filter_fn: Optional[Callable[[Node], bool]] = None, + ) -> GraphModule: + """Annotate all static patterns registered for the backend. + + Args: + model (GraphModule): Model to annotate statically. + quantization_config (Optional[QuantizationConfig]): Quantization + specs for input activations, output activations, weights, and + biases. + filter_fn (Optional[Callable[[Node], bool]]): Optional node filter + specifying which nodes to annotate. + + Returns: + GraphModule: Model populated with quantization annotations. + + """ + # TODO: implement the support for None to be canceling out previous annotations + if quantization_config is None: + return model + + annotate_graph(model, quantization_config, filter_fn) + return model + + def _annotate_for_static_quantization_config( + self, model: GraphModule + ) -> GraphModule: + """Match QuantizationConfigs to modules before annotating patterns. + + Args: + model (GraphModule): Model whose modules are being matched to + quantization configs. + + Returns: + GraphModule: Annotated model after applying configured filters. + + """ + if self.io_config: + self._annotate_io(model, self.io_config) + + module_name_list = list(self.module_name_config.keys()) + for module_name, config in self.module_name_config.items(): + self._annotate_all_static_patterns( + model, config, get_module_name_filter(module_name) + ) + + tp_list = list(self.module_type_config.keys()) + for module_type, config in self.module_type_config.items(): + self._annotate_all_static_patterns( + model, config, _get_module_type_filter(module_type) + ) + + self._annotate_all_static_patterns( + model, + self.global_config, + _get_not_module_type_or_name_filter(tp_list, module_name_list), + ) + + return model + + def _annotate_io( + self, + model: GraphModule, + quantization_config: QuantizationConfig, + ): + """Annotate graph inputs and outputs with the provided configuration. + + Args: + model (GraphModule): GraphModule being annotated. + quantization_config (QuantizationConfig): Activation qspecs to apply + to IO nodes. + + """ + for node in model.graph.nodes: + if is_annotated(node): + continue + if node.op == "placeholder" and len(node.users) > 0: + annotate_output_qspec( + node, + quantization_config.get_output_act_qspec(), + ) + mark_node_as_annotated(node) + if node.op == "output": + for parent in node.all_input_nodes: + annotate_input_qspec_map( + node, parent, quantization_config.get_input_act_qspec() + ) + mark_node_as_annotated(node) + + def validate(self, model: GraphModule) -> None: + """Validate the quantization results. Currently, this includes: + - Ensure tensor inputs to each operator live on the same device. + + Args: + model (GraphModule): GraphModule being validated. + Raises: + ValueError: If tensor inputs for any operator span more than one + device. + """ + for node in model.graph.nodes: + if node.op != "call_function": + continue + + devices = set() + for arg_node in node.all_input_nodes: + meta_val = arg_node.meta.get("val", None) + if meta_val is None: + continue + if isinstance(meta_val, (tuple, list)): + for tensor in meta_val: + devices.add( + str( + getattr( + tensor, + "device", + f"Could not get device from {tensor}", + ) + ) + ) + else: + devices.add( + str( + getattr( + meta_val, + "device", + f"Could not get device from {meta_val}", + ) + ) + ) + + if len(devices) > 1: + raise ValueError( + f"Quantizer detected operator {node.name} with different device inputs: {devices}." + ) + + def quantize_with_submodules( + self, + model: GraphModule, + calibration_samples: list[tuple], + is_qat: bool = False, + ): + """Quantizes a GraphModule in a way such that conditional submodules are handled properly. + + Args: + model (GraphModule): The model to quantize. + calibration_samples (list[tuple]): A list of inputs to used to + calibrate the model during quantization. To properly calibrate a + model with submodules, at least one sample per code path is + needed. + is_qat (bool): Whether to do quantization aware training or not. + + Returns: + GraphModule: The quantized model. + + """ + prepare_fn = prepare_qat_pt2e if is_qat else prepare_pt2e + + prepared = prepare_fn(model, self) + for name, submodule, _ in get_cond_while_submodules(prepared): + prepared.set_submodule(name, prepare_fn(submodule, self), strict=True) + for inp in calibration_samples: + prepared(*inp) + + for name, submodule, _ in get_cond_while_submodules(prepared): + prepared.set_submodule(name, convert_pt2e(submodule), strict=True) + converted = convert_pt2e(prepared) + return converted + + +class EthosUQuantizer(TOSAQuantizer): + """Quantizer supported by the Arm Ethos-U backend. + + Args: + compile_spec (EthosUCompileSpec): Backend compile specification for + Ethos-U targets. + + """ + + def __init__(self, compile_spec: EthosUCompileSpec) -> None: + super().__init__(compile_spec) + + +class VgfQuantizer(TOSAQuantizer): + """Quantizer supported by the Arm Vgf backend. + + Args: + compile_spec (VgfCompileSpec): Backend compile specification for Vgf + targets. + + """ + + def __init__(self, compile_spec: VgfCompileSpec) -> None: + super().__init__(compile_spec) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer_utils.py new file mode 100644 index 0000000..7bd8e00 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/arm_quantizer_utils.py @@ -0,0 +1,76 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide utilities for quantization annotations. + +Use these helpers to check and mark annotation state when working with +``QuantizationAnnotation`` entries in FX node metadata. + +""" + +from typing import cast + +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo + +from torch.fx import Node + +from torchao.quantization.pt2e.quantizer import QuantizationAnnotation +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + + +def is_annotated(node: Node) -> bool: + """Return True if the node is annotated. + + Args: + node (Node): FX node to inspect. + + Returns: + bool: True if ``Q_ANNOTATION_KEY`` exists and ``_annotated`` is set. + + """ + return ( + Q_ANNOTATION_KEY in node.meta + and cast(QuantizationAnnotation, node.meta[Q_ANNOTATION_KEY])._annotated + ) + + +def is_output_annotated(node: Node) -> bool: + """Return True if the node's output is annotated. + + Args: + node (Node): FX node to inspect. + + Returns: + bool: True if annotated and an output qspec is present. + + """ + if Q_ANNOTATION_KEY in node.meta: + annotation = cast(QuantizationAnnotation, node.meta[Q_ANNOTATION_KEY]) + return annotation._annotated and annotation.output_qspec is not None + else: + return False + + +def mark_node_as_annotated(node: Node) -> None: + """Mark a node as annotated. + + Create an empty ``QuantizationAnnotation`` on the node when missing and set + its ``_annotated`` flag to True. + + Args: + node (Node): FX node to update. + + """ + if Q_ANNOTATION_KEY not in node.meta: + node.meta[Q_ANNOTATION_KEY] = QuantizationAnnotation() + annotation_info = ArmAnnotationInfo( + quantized=True, + ) + node.meta[Q_ANNOTATION_KEY]._annotated = True + meta_custom = node.meta.get("custom", {}) + meta_custom[ArmAnnotationInfo.CUSTOM_META_KEY] = dict(annotation_info) + node.meta["custom"] = meta_custom diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_annotator.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_annotator.py new file mode 100644 index 0000000..34a9027 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_annotator.py @@ -0,0 +1,815 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide quantization annotation logic for Arm backends. + +This module computes per-node quantization properties and applies input/output +annotations to FX graphs using TorchAO qspecs. + +""" + +import logging +import operator +from dataclasses import dataclass +from typing import Callable, cast, List, Optional, Sequence + +import torch +import torch.fx +from executorch.backends.arm.common.debug import get_node_debug_info +from executorch.backends.arm.common.type import ensure_type +from executorch.backends.arm.quantizer import QuantizationConfig +from torch._subclasses import FakeTensor + +from torch.fx import Node +from torchao.quantization.pt2e.quantizer import ( + annotate_input_qspec_map, + annotate_output_qspec, + QuantizationSpecBase, + SharedQuantizationSpec, +) + +from .arm_quantizer_utils import ( + is_annotated, + is_output_annotated, + mark_node_as_annotated, +) + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class _QuantProperty: + """Specify how the input/output at 'index' must be quantized.""" + + index: int + qspec: QuantizationSpecBase | List[QuantizationSpecBase] + optional: bool = False + mark_annotated: bool = False + + +class _OpQuantProperties: + """Collect input/output quantization properties for a node. + + Attributes: + quant_inputs (List[_QuantProperty]): Quantization specs for inputs + indexed by argument positions. + quant_output (Optional[_QuantProperty]): Quantization spec for the + node's output when applicable. + + """ + + def __init__(self): + self.quant_inputs: List[_QuantProperty] = [] + self.quant_output: Optional[_QuantProperty] = None + + +def _as_list(x): + """Return ``x`` wrapped as a list if needed. + + Args: + x: Value or list of values. + + Returns: + list: ``x`` if already a list; otherwise ``[x]``. + + """ + if isinstance(x, (list, tuple)): + return x + else: + return [ + x, + ] + + +def _is_ok_for_quantization( + node: Node, quant_properties: _OpQuantProperties, gm: torch.fx.GraphModule +) -> bool: + """Check if a node can be quantized. + + A node can be quantized if: + - All inputs that are required for quantization are of type `float32` + and are not large scalar values. + - The output of the node itself is of type `float32` and is not a large + scalar. + + Args: + node (Node): The node being analyzed. + quant_properties (_OpQuantProperties): Contains quantization properties + for the node, including input and output quantization specifications. + gm (torch.fx.GraphModule): The graph module containing the computational + graph. + + Returns: + bool: `True` if the node can be quantized, otherwise `False`. + + """ + # Check output + if quant_properties.quant_output is not None: + if _is_non_float_tensor(node): + logger.debug( + "Could not quantize non float tensor for the following output node: " + f"{get_node_debug_info(node, gm)}" + ) + + return False + elif _is_large_scalar(node, gm): + logger.debug( + "Could not quantize large scalar node for the following output node: " + f"{get_node_debug_info(node, gm)}" + ) + + return False + + # Check inputs + for quant_property in quant_properties.quant_inputs: + if quant_property.optional and ( + quant_property.index >= len(node.args) + or node.args[quant_property.index] is None + ): + continue + + for n_arg in _as_list(node.args[quant_property.index]): + if not isinstance(n_arg, Node): + raise TypeError( + f"n_arg must be a Node instance, got {type(n_arg).__name__!r}" + ) + + if _is_non_float_tensor(n_arg): + logger.debug( + "Could not quantize non float tensor for the following input " + f"node: {get_node_debug_info(node, gm)}" + ) + + return False + elif _is_large_scalar(n_arg, gm): + logger.debug( + "Could not quantize large scalar node for the following input " + f"node: {get_node_debug_info(node, gm)}" + ) + + return False + + return True + + +def _get_node_target(module: torch.nn.Module | torch.fx.GraphModule, target_str: str): + """Get an attribute from a module by dotted path. + + Args: + module (torch.nn.Module | torch.fx.GraphModule): Root module. + target_str (str): Dotted attribute path, e.g., ``"sub.weight"``. + + Returns: + Any: Resolved attribute on the module. + + """ + targets = target_str.split(".") + for target in targets[:-1]: + module = module.get_submodule(target) + return getattr(module, targets[-1]) + + +def _is_large_scalar(node: Node, gm: torch.fx.GraphModule): + """Return True if input is a large scalar value. + + Large scalars are skipped because ``torch.histc`` supports values only up + to a certain upper bound. + + """ + HISTC_UPPER_BOUND = 3.4028235e15 + if node.op == "get_attr" and isinstance(node.target, str): + tensor = _get_node_target(gm, node.target) + # torch.histc works until this upper bound + return tensor.numel() == 1 and abs(tensor.item()) > HISTC_UPPER_BOUND + if node.op == "call_function" and node.target in ( + torch.ops.aten.full.default, + torch.ops.aten.full, + torch.ops.aten.fill_.Scalar, + ): + fill_value = cast(float, node.args[1]) + return abs(fill_value) > HISTC_UPPER_BOUND + return False + + +def _is_non_float_tensor(node: Node) -> bool: + """Check if the output of a node has a data type other than `torch.float32`. + + If the output is not `torch.float32`, quantization cannot be performed, as + observers only work with floating-point tensors. + + Args: + node (Node): The node to check the output(s) for. + + Returns: + bool: `True` if the data type is not float32, otherwise `False`. + + Note: + - If `node.meta["val"]` is a `list`, the function returns `True` if + any element is not an instance of `FakeTensor` or does not have + `torch.float32` as its data type. + - If node.meta["val"] is missing or is not an instance of `FakeTensor`, + the function returns True. + + """ + if "val" in node.meta and isinstance(node.meta["val"], Sequence): + return any( + not isinstance(fake_tensor, FakeTensor) + or fake_tensor.dtype != torch.float32 + for fake_tensor in node.meta["val"] + ) + + if "val" not in node.meta or not isinstance(node.meta["val"], FakeTensor): + return True + + return node.meta["val"].dtype != torch.float32 + + +def _annotate_input(node: Node, quant_property: _QuantProperty): + """Annotate a node's input with the given qspec. + + Maps the specified input argument(s) to the provided quantization spec and + optionally marks the input node(s) as annotated. + + Args: + node (Node): Node whose input should be annotated. + quant_property (_QuantProperty): Input index and qspec(s). + + Raises: + RuntimeError: If the node is already annotated. + TypeError: If an input argument is not a ``Node`` instance. + + """ + if is_annotated(node): + raise RuntimeError( + f"Cannot annotate input: node '{node.name}' is already annotated" + ) + if quant_property.optional and ( + quant_property.index >= len(node.args) + or node.args[quant_property.index] is None + ): + return + + for n_arg, qspec in zip( + _as_list(node.args[quant_property.index]), + _as_list(quant_property.qspec), + strict=True, + ): + if not isinstance(n_arg, Node): + raise TypeError( + f"n_arg must be a Node instance, got {type(n_arg).__name__!r}" + ) + annotate_input_qspec_map(node, n_arg, qspec) + if quant_property.mark_annotated: + mark_node_as_annotated(n_arg) # type: ignore[attr-defined] + + +def _annotate_output(node: Node, quant_property: _QuantProperty): + """Annotate a node's output with the given qspec. + + Args: + node (Node): Node whose output should be annotated. + quant_property (_QuantProperty): Output index and qspec. + + Raises: + RuntimeError: If the node is already annotated. + ValueError: If ``mark_annotated`` is True, ``optional`` is True, or + ``index`` is not zero. + + """ + if is_annotated(node): + raise RuntimeError( + f"Cannot annotate output: node '{node.name}' is already annotated" + ) + if quant_property.mark_annotated: + raise ValueError( + "quant_property.mark_annotated must be False for output annotation" + ) + if quant_property.optional: + raise ValueError("quant_property.optional must be False for output annotation") + if quant_property.index != 0: + raise ValueError("Only one output annotation supported currently") + + annotate_output_qspec(node, quant_property.qspec) + + +def _match_pattern( + node: Node, pattern: List[List], filter_fn: Optional[Callable[[Node], bool]] = None +) -> bool: + """Check whether a node chain matches a pattern. + + Verify a chain of ancestors -> node -> descendants matches the provided + ``pattern``. If ``filter_fn`` is provided, require all nodes in the chain + to pass the filter. Each pattern element is a list of disjunctive node + targets. + + """ + if len(pattern) < 1: + raise ValueError("No pattern provided") + + if filter_fn is not None: + if not filter_fn(node): + return False + if len(pattern) == 1: + # Base case where it has passed the filter_fn. Simply look if node.target is in pattern. + return node.target in pattern[0] + if node.target not in [op for sub_pattern in pattern for op in sub_pattern]: + # node.target not in pattern. No need to look at the rest of the pattern. + return False + # Find the index of this node's target in pattern + idx = [node.target in sub_pattern for sub_pattern in pattern].index(True) + left_pattern = pattern[:idx] + # Exclude idx as this contains node.target which we have already matched + right_pattern = pattern[idx + 1 :] + left_condition = True + right_condition = True + # Recursively look at the rest of the pattern by calling this function for + # node's input and user node with updated patterns. + if len(left_pattern) > 0: + parent = node.all_input_nodes[0] + if len(parent.users) != 1: + return False + left_condition = _match_pattern(parent, left_pattern, filter_fn) + if len(right_pattern) > 0: + right_condition = _match_pattern(list(node.users)[0], right_pattern, filter_fn) + return left_condition and right_condition + + +_conv_ops = [ + torch.ops.aten.conv1d.default, + torch.ops.aten.conv2d.default, + torch.ops.aten.conv2d.padding, + torch.ops.aten.conv3d.default, + torch.ops.aten.conv3d.padding, +] + +_one_to_one = [ + torch.ops.aten.abs.default, + torch.ops.aten.ceil.default, + torch.ops.aten.erf.default, + torch.ops.aten.exp.default, + torch.ops.aten.expm1.default, + torch.ops.aten.elu.default, + torch.ops.aten.floor.default, + torch.ops.aten.log.default, + torch.ops.aten.reciprocal.default, + torch.ops.aten.rsqrt.default, + torch.ops.aten.sigmoid.default, + torch.ops.aten.cos.default, + torch.ops.aten.sin.default, + torch.ops.aten.tanh.default, + torch.ops.aten.sum.dim_IntList, + torch.ops.aten.sum.default, + torch.ops.aten.hardsigmoid.default, + torch.ops.aten.hardswish.default, + torch.ops.aten.hardswish_.default, + torch.ops.aten.full_like.default, + torch.ops.aten.zeros_like.default, + torch.ops.aten.pow.Tensor_Scalar, + torch.ops.aten.gelu.default, + torch.ops.aten.sinh.default, + torch.ops.aten.atan.default, + torch.ops.aten.log1p.default, + torch.ops.aten.acosh.default, + torch.ops.aten.sign.default, + torch.ops.aten.asin.default, + torch.ops.aten.atanh.default, + torch.ops.aten.asinh.default, + torch.ops.aten.cosh.default, + torch.ops.aten.acos.default, + torch.ops.aten.cumsum.default, + torch.ops.aten.tan.default, +] + +_one_to_one_shared_input_qspec = [ + torch.ops.aten.squeeze.default, + torch.ops.aten.squeeze_copy.default, + torch.ops.aten.squeeze_copy.dim, + torch.ops.aten.squeeze.dim, + torch.ops.aten.squeeze.dims, + torch.ops.aten.unbind.int, + torch.ops.aten.unsqueeze.default, + torch.ops.aten.unsqueeze_copy.default, + torch.ops.aten.reshape.default, + torch.ops.aten.repeat.default, + torch.ops.aten.repeat_interleave.self_int, + torch.ops.aten.expand_copy.default, + torch.ops.aten.expand.default, + # Disabling these as there seems to be an issue with support for complex + # datatypes in torch: + # torch.ops.aten.view_as_complex.default, + # torch.ops.aten.view_as_complex_copy.default, + # torch.ops.aten.view_as_real.default, + # torch.ops.aten.view_as_real_copy.default, + torch.ops.aten.view.default, + torch.ops.aten.view_as.default, + torch.ops.aten.view_copy.default, + torch.ops.aten._unsafe_view.default, + torch.ops.aten.select.int, + torch.ops.aten.select_copy.int, + torch.ops.aten.slice.Tensor, + torch.ops.aten.slice_copy.Tensor, + torch.ops.aten.split.Tensor, + torch.ops.aten.split_with_sizes.default, + torch.ops.aten.split_copy.Tensor, + torch.ops.aten.transpose.Dimname, + torch.ops.aten.transpose.int, + torch.ops.aten.transpose_copy.int, + torch.ops.aten.t_copy.default, + torch.ops.aten.tile.default, + torch.ops.aten.flip.default, + torch.ops.aten.chunk.default, + torch.ops.aten.contiguous.default, + torch.ops.aten.upsample_bilinear2d.vec, + torch.ops.aten.upsample_nearest2d.vec, + torch.ops.aten.pad.default, + torch.ops.aten.amax.default, + torch.ops.aten.amin.default, + torch.ops.aten.clamp.default, + torch.ops.aten.clamp.Tensor, + torch.ops.aten.unflatten.int, + torch.ops.aten.index_select.default, + torch.ops.aten.index.Tensor, + # Neg operator flips the range, but keps the magnitude the same. + # That is why we force it to use the same qparams and avoid + # dequant -> neg -> requant chain. + torch.ops.aten.neg.default, +] + +_one_to_one_shared_input_or_input_act_qspec = [ + torch.ops.aten.alias.default, + torch.ops.aten.clone.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.mean.default, + torch.ops.aten.mean.dim, + torch.ops.aten.permute.default, + torch.ops.aten.permute_copy.default, + torch.ops.aten.avg_pool2d.default, + torch.ops.aten.max_pool2d.default, + torch.ops.aten.flatten.using_ints, + torch.ops.aten.dropout.default, + torch.ops.aten.dropout_.default, + torch.ops.aten.adaptive_avg_pool2d.default, + torch.ops.aten.alias_copy.default, + torch.ops.aten.pixel_shuffle.default, + torch.ops.aten.pixel_unshuffle.default, +] + + +def get_quant_properties( # noqa: C901 + node: Node, gm: torch.fx.GraphModule, quantization_config +) -> _OpQuantProperties | None: + """Compute quantization properties for a node. + + Determine which inputs and/or outputs should be annotated for quantization + based on the node's operator and surrounding pattern. + + Args: + node (Node): Node to analyze. + gm (torch.fx.GraphModule): Owning graph module. + quantization_config: Source for activation/weight/bias qspecs. + + Returns: + _OpQuantProperties | None: Properties to apply, or ``None`` if the + node is unsupported or not suitable for quantization. + + """ + input_act_qspec = quantization_config.get_input_act_qspec() + weight_qspec = quantization_config.get_weight_qspec() + output_act_qspec = quantization_config.get_output_act_qspec() + bias_qspec = quantization_config.get_bias_qspec(node) + if output_act_qspec is not None: + # Check if output activation qspec is symmetric. In that case + # we avoid conv + relu fusion for quantization annotation. + is_symmetric = output_act_qspec.qscheme == torch.per_tensor_symmetric + else: + is_symmetric = False + + quant_properties = _OpQuantProperties() + + def any_or_hardtanh_min_zero(n: Node): + """Return True for any op or hardtanh with ``min_val == 0``.""" + # Check that if the node is a hardtanh, its min_val is zero + return ( + n.target + not in (torch.ops.aten.hardtanh.default, torch.ops.aten.hardtanh_.default) + or n.args[1] == 0 + ) + + if not is_symmetric and _match_pattern( + node, + [ + _conv_ops, + [torch.ops.aten.batch_norm.default], + [ + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + ], + ], + filter_fn=any_or_hardtanh_min_zero, + ): + if node.target in _conv_ops: + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + elif node.target in ( + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + ): + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + + elif _match_pattern( + node, + [ + _conv_ops, + [torch.ops.aten.batch_norm.default], + ], + ): + if node.target in _conv_ops: + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + elif node.target in [ + torch.ops.aten.batch_norm.default, + ]: + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif not is_symmetric and _match_pattern( + node, + [ + [ + *_conv_ops, + torch.ops.aten.linear.default, + ], + [ + torch.ops.aten.relu.default, + torch.ops.aten.relu_.default, + torch.ops.aten.hardtanh.default, + torch.ops.aten.hardtanh_.default, + ], + ], + any_or_hardtanh_min_zero, + ): + if node.target in ( + *_conv_ops, + torch.ops.aten.linear.default, + ): + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + else: + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in ( + *_conv_ops, + torch.ops.aten.linear.default, + ): + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, weight_qspec, mark_annotated=True), + _QuantProperty(2, bias_qspec, optional=True, mark_annotated=True), + ] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in ( + torch.ops.aten.add.Tensor, + torch.ops.aten.add_.Tensor, + torch.ops.aten.sub.Tensor, + torch.ops.aten.sub_.Tensor, + torch.ops.aten.matmul.default, + torch.ops.aten.mm.default, + torch.ops.aten.bmm.default, + torch.ops.aten.mul.Tensor, + torch.ops.aten.mul_.Tensor, + ): + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, input_act_qspec), + ] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in ( + torch.ops.aten.minimum.default, + torch.ops.aten.maximum.default, + ): + lhs_node = ensure_type(Node, node.args[0]) + shared_qspec = SharedQuantizationSpec((lhs_node, node)) + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty( + 1, + input_act_qspec if node.args[0] == node.args[1] else shared_qspec, + ), + ] + quant_properties.quant_output = _QuantProperty(0, shared_qspec) + elif node.target in (torch.ops.aten.where.self,): + true_node = ensure_type(Node, node.args[1]) + input_qspec = ( + SharedQuantizationSpec(true_node) + if is_output_annotated(true_node) + else input_act_qspec + ) + quant_properties.quant_inputs = [ + _QuantProperty(1, input_qspec), + _QuantProperty(2, SharedQuantizationSpec((true_node, node))), + ] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((true_node, node)), + ) + elif node.target in _one_to_one_shared_input_or_input_act_qspec: + input_node = ensure_type(Node, node.args[0]) + input_qspec = ( + SharedQuantizationSpec(input_node) + if is_output_annotated(input_node) + else input_act_qspec + ) + quant_properties.quant_inputs = [_QuantProperty(0, input_qspec)] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((input_node, node)), + ) + elif node.target in ( + torch.ops.aten.cat.default, + torch.ops.aten.concatenate.default, + torch.ops.aten.stack.default, + ): + # first argument should be a non-empty list of nodes + if not isinstance(node.args[0], list): + raise TypeError( + "Expected node.args[0] to be a list, got " + f"{type(node.args[0]).__name__!r}" + ) + if len(node.args[0]) == 0: + raise ValueError("Expected non-empty list for node.args[0]") + inputs = [ensure_type(Node, element) for element in node.args[0]] + shared_qspec = SharedQuantizationSpec((inputs[0], node)) + quant_properties.quant_inputs = [ + _QuantProperty( + 0, + [input_act_qspec if n == inputs[0] else shared_qspec for n in inputs], + ) + ] + quant_properties.quant_output = _QuantProperty(0, shared_qspec) + elif node.target in _one_to_one: + quant_properties.quant_inputs = [_QuantProperty(0, input_act_qspec)] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in _one_to_one_shared_input_qspec: + input_node = ensure_type(Node, node.args[0]) + quant_properties.quant_inputs = [_QuantProperty(0, input_act_qspec)] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((input_node, node)), + ) + elif node.target in [torch.ops.aten.copy_.default]: + input_node = ensure_type(Node, node.args[1]) + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty(1, input_act_qspec), + ] + quant_properties.quant_output = _QuantProperty( + 0, + SharedQuantizationSpec((input_node, node)), + ) + elif node.target in [ + torch.ops.aten.eq.Tensor, + torch.ops.aten.ge.Tensor, + torch.ops.aten.gt.Tensor, + torch.ops.aten.le.Tensor, + torch.ops.aten.lt.Tensor, + ]: + input_node = ensure_type(Node, node.args[0]) + shared_qspec = SharedQuantizationSpec((input_node, node)) + quant_properties.quant_inputs = [ + _QuantProperty(0, input_act_qspec), + _QuantProperty( + 1, + input_act_qspec if node.args[0] == node.args[1] else shared_qspec, + ), + ] + quant_properties.quant_output = None + elif node.target in [ + torch.ops.aten.full.default, + torch.ops.aten.full, + torch.ops.aten.zeros.default, + torch.ops.aten.ones.default, + torch.ops.aten.fill_.Scalar, + torch.ops.aten.scalar_tensor.default, + ]: + quant_properties.quant_inputs = [] + quant_properties.quant_output = _QuantProperty(0, output_act_qspec) + elif node.target in [operator.getitem]: + input_node = ensure_type(Node, node.args[0]) + if not is_output_annotated(input_node): + return None + shared_qspec = SharedQuantizationSpec(input_node) + quant_properties.quant_inputs = [_QuantProperty(0, shared_qspec)] + quant_properties.quant_output = _QuantProperty(0, shared_qspec) + elif node.target in ( + torch.ops.higher_order.cond, + torch.ops.higher_order.while_loop, + ): + submodule_args_pos = -1 if node.target == torch.ops.higher_order.cond else -2 + submodule_args = node.args[submodule_args_pos] + output_qspec = output_act_qspec + if len(submodule_args) > 0: # type: ignore[arg-type] + # The way the TOSA backend handles quantized inputs, arrays of input tensors (such as the input to a + # conditional graph) need shared quantization. + shared_qspec = SharedQuantizationSpec( + (cast(list[Node], submodule_args)[0], node) + ) + quant_properties.quant_inputs = [ + _QuantProperty( + submodule_args_pos, + [ + input_act_qspec, + *([shared_qspec] * (len(submodule_args) - 1)), # type: ignore[arg-type] + ], + ) + ] + if node.target == torch.ops.higher_order.while_loop: + # The output of the while loop body can either re-enter the body, or exit the while loop. + # Therefore, A and B in the diagram below need to share the same quantization parameters. + # A -> while ( RESCALE -> ... RESCALE -> ) -> B + output_qspec = shared_qspec + + quant_properties.quant_output = _QuantProperty(0, output_qspec) + + else: + return None + + # Don't check if operator.getitem is ok for quantization, it's always ok + if node.target == operator.getitem: + return quant_properties + + # Check that each inputs/outputs can be quantized properly with the + # provided quantization properties. + if not _is_ok_for_quantization(node, quant_properties, gm): + return None + + return quant_properties + + +def annotate_graph( # type: ignore[return] + gm: torch.fx.GraphModule, + quantization_config: QuantizationConfig, + filter_fn: Optional[Callable[[Node], bool]] = None, +) -> Optional[List[List[Node]]]: + """Annotate supported nodes in a graph with quantization specs. + + Iterate through call_function nodes, computes quantization properties, and + apply input/output annotations. A filter can restrict which nodes are + considered. + + Args: + gm (torch.fx.GraphModule): Graph to annotate. + quantization_config (QuantizationConfig): Default qspecs for nodes. + filter_fn (Optional[Callable[[Node], bool]]): Optional node predicate. + + Returns: + Optional[List[List[Node]]]: Reserved for future use; currently None. + + """ + for node in gm.graph.nodes: + if node.op != "call_function": + continue + + if is_annotated(node): + continue + + if filter_fn is not None and not filter_fn(node): + continue + + quant_properties = get_quant_properties(node, gm, quantization_config) + if quant_properties is None: + continue + + for quant_property in quant_properties.quant_inputs: + _annotate_input(node, quant_property) + + if quant_properties.quant_output is not None: + _annotate_output(node, quant_properties.quant_output) + + mark_node_as_annotated(node) # type: ignore[attr-defined] + + # Quantization does not allow kwargs for some reason. + # Remove from ops we know have and where we know it does not break anything. + if node.target in [ + torch.ops.aten.full_like.default, + torch.ops.aten.full.default, + torch.ops.aten.full, + torch.ops.aten.fill_.Scalar, + torch.ops.aten.scalar_tensor.default, + torch.ops.aten.zeros.default, + torch.ops.aten.ones.default, + ]: + node.kwargs = {} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_config.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_config.py new file mode 100644 index 0000000..b2bc4a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/quantizer/quantization_config.py @@ -0,0 +1,228 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide quantization configuration helpers for the Arm backend. + +Define a small dataclass to carry activation/weight/bias specs and helper +accessors that validate specs before use. Use this module to build and validate +quantization specs consumed by the annotator. + +""" + + +from dataclasses import dataclass + +import torch +from torchao.quantization.pt2e import ObserverOrFakeQuantize + +from torchao.quantization.pt2e.quantizer import ( + DerivedQuantizationSpec, + QuantizationSpec, +) + + +@dataclass(eq=True, frozen=True) +class QuantizationConfig: + """Provide a container for quantization specs. + + Hold optional specs for input/output activations, weights, and bias, and + expose validated accessors. + + Attributes: + input_activation (QuantizationSpec | None): Spec for input activations. + output_activation (QuantizationSpec | None): Spec for output activations. + weight (QuantizationSpec | None): Spec for weights. + bias (QuantizationSpec | None): Spec for bias values. + + """ + + input_activation: QuantizationSpec | None + output_activation: QuantizationSpec | None + weight: QuantizationSpec | None + bias: QuantizationSpec | None + + def get_input_act_qspec(self) -> QuantizationSpec | None: + """Get the validated input activation spec. + + Validate that the input activation qscheme is supported before + returning the spec. + + Returns: + QuantizationSpec | None: Input activation spec, or ``None`` when + unset. + + Raises: + ValueError: If the qscheme is not per-tensor affine or symmetric. + + """ + if self.input_activation is None: + return None + # Validate that input_activation uses a supported qscheme + if self.input_activation.qscheme not in [ + torch.per_tensor_affine, + torch.per_tensor_symmetric, + ]: + raise ValueError( + f"Unsupported quantization_spec {self.input_activation} for input_activation." + ) + return self.input_activation + + def get_output_act_qspec(self) -> QuantizationSpec | None: + """Get the validated output activation spec. + + Validate that the output activation qscheme is supported before + returning the spec. + + Returns: + QuantizationSpec | None: Output activation spec, or ``None`` when + unset. + + Raises: + ValueError: If the qscheme is not per-tensor affine or symmetric. + + """ + if self.output_activation is None: + return None + # Validate that output_activation uses a supported qscheme + if self.output_activation.qscheme not in [ + torch.per_tensor_affine, + torch.per_tensor_symmetric, + ]: + raise ValueError( + f"Unsupported quantization_spec {self.output_activation} for output_activation." + ) + return self.output_activation + + def get_weight_qspec(self) -> QuantizationSpec | None: + """Get the validated weight spec. + + Validate that the weight qscheme is supported (per-tensor or + per-channel symmetric) before returning the spec. + + Returns: + QuantizationSpec | None: Weight spec, or ``None`` when unset. + + Raises: + ValueError: If the qscheme is not a supported symmetric scheme. + + """ + if self.weight is None: + return None + # Validate that weight uses a supported qscheme + if self.weight.qscheme not in [ + torch.per_tensor_symmetric, + torch.per_channel_symmetric, + ]: + raise ValueError(f"Unsupported quantization_spec {self.weight} for weight") + return self.weight + + def get_bias_qspec(self, node: torch.fx.Node) -> QuantizationSpec | None: + """Get the derived or validated bias spec. + + For conv/linear ops, derive bias qparams from the input/weight observers. + Otherwise, validate a user-provided floating-point bias spec. + + Args: + node (torch.fx.Node): Node whose bias spec is requested. + + Returns: + QuantizationSpec | None: Derived or provided bias spec, or ``None`` + when unset. + + Raises: + ValueError: If deriving qparams sees an unexpected number of + observers/fake-quantizers, or if a provided bias dtype is not + floating-point. + + """ + + def _derive_qparams_fn( + obs_or_fqs: list[ObserverOrFakeQuantize], + ) -> tuple[torch.Tensor, torch.Tensor]: + """Compute bias scale/zero-point from activation/weight observers. + + Expect two observers or fake-quantize modules: one for the input + activation and one for the weight. The bias scale is the product of + input and weight scales, and the zero-point is a tensor of zeros. + + Args: + obs_or_fqs (list[ObserverOrFakeQuantize]): Observers/fake-quant + in order ``[act, weight]``. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Bias scale tensor and + integer zero-point tensor. + + Raises: + ValueError: If the list does not contain exactly two items. + + """ + # Validate expected number of observers/fake-quantizes + if len(obs_or_fqs) != 2: + raise ValueError( + f"Expecting two obs/fqs, one for activation and one for weight, got: {len(obs_or_fqs)}" + ) + act_obs_or_fq = obs_or_fqs[0] + weight_obs_or_fq = obs_or_fqs[1] + act_scale, _ = act_obs_or_fq.calculate_qparams() + weight_scale, _ = weight_obs_or_fq.calculate_qparams() + return torch.tensor(act_scale * weight_scale).to( + torch.float32 + ), torch.full_like(weight_scale, fill_value=0, dtype=torch.int32) + + if node.target in [ + torch.ops.aten.conv1d.default, + torch.ops.aten.conv2d.default, + torch.ops.aten.linear.default, + torch.ops.aten.conv2d.padding, + torch.ops.aten.conv3d.default, + torch.ops.aten.conv3d.padding, + ]: + if self.input_activation is None or self.weight is None: + raise ValueError( + "Input activation and weight QuantizationConfig must be specified." + ) + + if (self.input_activation.dtype == self.weight.dtype == torch.int8) or ( + self.input_activation.dtype == torch.int16 + and self.weight.dtype == torch.int8 + ): + input_act = node.args[0] + weight = node.args[1] + + # If the weights are quantized per_tensor, do the same with bias + qscheme = ( + torch.per_tensor_symmetric + if self.weight is None + else self.weight.qscheme + ) + ch_axis = None + if self.weight is not None: + if qscheme == torch.per_channel_symmetric: + ch_axis = self.weight.ch_axis + + quantization_spec = DerivedQuantizationSpec( + derived_from=[(input_act, node), (weight, node)], # type: ignore[list-item] + derive_qparams_fn=_derive_qparams_fn, + dtype=torch.int32, + quant_min=torch.iinfo(torch.int32).min + 1, + quant_max=torch.iinfo(torch.int32).max, + qscheme=qscheme, + ch_axis=ch_axis, + ) + return quantization_spec # type: ignore[return-value] + else: + raise NotImplementedError( + f"Bias quantization of types: i:{self.input_activation.dtype}, w:{self.weight.dtype} not implemented" + ) + + if self.bias is None: + return None + # Validate that bias dtype is floating-point + if self.bias.dtype != torch.float: + raise ValueError( + "Only float dtype for bias is supported for bias right now" + ) + return self.bias diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-ethos-u.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-ethos-u.txt new file mode 100644 index 0000000..62e7143 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-ethos-u.txt @@ -0,0 +1,6 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +ethos-u-vela == 4.5.0 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-models-test.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-models-test.txt new file mode 100644 index 0000000..238e9d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-models-test.txt @@ -0,0 +1,6 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +diffusers[torch] == 0.33.1 \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-tosa.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-tosa.txt new file mode 100644 index 0000000..f16d967 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-tosa.txt @@ -0,0 +1,7 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +ml_dtypes == 0.5.1 +flatbuffers == 24.3.25 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-vgf.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-vgf.txt new file mode 100644 index 0000000..586976d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/requirements-arm-vgf.txt @@ -0,0 +1,8 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +ai_ml_emulation_layer_for_vulkan == 0.8.0 +ai_ml_sdk_model_converter == 0.8.0 +ai_ml_sdk_vgf_library == 0.8.0 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/BUCK new file mode 100644 index 0000000..67f2bab --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/BUCK @@ -0,0 +1,5 @@ +load("targets.bzl", "define_common_targets") + +oncall("odai_jarvis") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/EthosUBackend.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/EthosUBackend.cpp new file mode 100644 index 0000000..505f474 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/EthosUBackend.cpp @@ -0,0 +1,618 @@ +/* + * Copyright 2023-2025 Arm Limited and/or its affiliates. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * Arm backend for Ethos-U baremetal driver stack, this relies on the + * ethos-u-core-driver for hardware interaction. + */ + +// Workaround for runtime/core/portable_type/c10/c10/util/Float16-math.h +#if defined(__GNUC__) && defined(__ZEPHYR__) +#pragma GCC diagnostic ignored "-Wdouble-promotion" +#endif + +#include +#include +#include + +#include + +#if defined(ET_EVENT_TRACER_ENABLED) +#include +#include +using executorch::runtime::EventTracer; +using executorch::runtime::EventTracerEntry; + +class EventTraceScope { + public: + EventTraceScope(EventTracer* event_tracer_, const char* name) { + event_tracer = event_tracer_; + event_tracer_entry_scope = event_tracer->start_profiling(name); + } + ~EventTraceScope() { + event_tracer->end_profiling(event_tracer_entry_scope); + } + + private: + EventTracer* event_tracer; + EventTracerEntry event_tracer_entry_scope; +}; +#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) \ + EventTraceScope event_tracer_scope = EventTraceScope(EVENTTRACER, NAME) +#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) \ + SCOPE = EVENTTRACER->start_profiling(NAME) +#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) \ + EVENTTRACER->end_profiling(SCOPE) + +#else +#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) +#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) +#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) +#endif + +#include +#include +#include +#include +#include +#include + +using namespace std; + +using executorch::aten::ScalarType; +using executorch::runtime::ArrayRef; +using executorch::runtime::Backend; +using executorch::runtime::BackendExecutionContext; +using executorch::runtime::BackendInitContext; +using executorch::runtime::CompileSpec; +using executorch::runtime::DelegateHandle; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +#define ETHOSU_NUM_BASE_ADDRS 3 + +namespace executorch { +namespace backends { +namespace arm { + +typedef struct { + FreeableBuffer* processed; +} ExecutionHandle; + +extern "C" { +void __attribute__((weak)) EthosUBackend_execute_begin() {} +void __attribute__((weak)) EthosUBackend_execute_end() {} +__attribute__((weak)) unsigned char* ethosu_fast_scratch = nullptr; +__attribute__((weak)) size_t ethosu_fast_scratch_size = 0; +} + +class EthosUBackendExecuteCallbacks { + public: + EthosUBackendExecuteCallbacks() { + EthosUBackend_execute_begin(); + } + ~EthosUBackendExecuteCallbacks() { + EthosUBackend_execute_end(); + } +}; + +class EthosUBackend final : public ::executorch::runtime::BackendInterface { + public: + EthosUBackend() {} + + ~EthosUBackend() = default; + + virtual bool is_available() const override { + // TODO: revise to use a register check/init function + return 1; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + ET_LOG(Info, "data:%p", processed->data()); + + const char* data = static_cast(processed->data()); + size_t size = processed->size(); + + // Verify format of vela_bin + if (vela_bin_validate(data, size) == false) { + ET_LOG(Error, "Malformed vela_bin_stream found"); + return Error::InvalidProgram; + } + + MemoryAllocator* allocator = context.get_runtime_allocator(); + ExecutionHandle* handle = allocator->allocateInstance(); + if (handle == nullptr) { + return Error::MemoryAllocationFailed; + } + + handle->processed = processed; + + // Return the same buffer we were passed - this data will be + // executed directly + return handle; + } + + Error execute( + BackendExecutionContext& context, + DelegateHandle* input_handle, + Span args) const override { +#if defined(ET_EVENT_TRACER_ENABLED) + EventTracer* event_tracer = context.event_tracer(); + EventTracerEntry event_tracer_local_scope; +#endif + + EXECUTORCH_PROF_SCOPE(event_tracer, "EthosUBackend::execute()"); + + // CollectArm_CPU_Cycles is just used to save the numbers of CPU cycles + // used, If etdump is used the EXECUTORCH_PROF_SCOPE() above will do the + // same. If not, this is a cheap way of getting some stats and the + // CollectArm_CPU_Cycles object can safely be removed in production code. + // + // The EthosUBackendExecuteCallbacks class uses the C++ + // constructor/destructor to make sure that EthosUBackend_execute_begin() + // and EthosUBackend_execute_end() is called while CollectArm_CPU_Cycles is + // in scope. e.g. We meassure from now until we exit this metod (in any way + // we might do it). + EthosUBackendExecuteCallbacks CollectArm_CPU_Cycles; + + ExecutionHandle* execution_handle = + static_cast(input_handle); + VelaHandles handles; + + // Command stream - we know at this point it's aligned + EXECUTORCH_PROF_START( + event_tracer, + event_tracer_local_scope, + "+EthosUBackend::execute()processed_data"); + const char* data = + static_cast(execution_handle->processed->data()); + EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); + + ET_LOG(Debug, "data:%p", data); + + EXECUTORCH_PROF_START( + event_tracer, + event_tracer_local_scope, + "+EthosUBackend::execute()vela_bin_read()"); + // Read key sections from the vela_bin_stream + if (vela_bin_read(data, &handles, execution_handle->processed->size()) == + false) { + ET_LOG(Error, "vela_read: error, invalid binary layout"); + return Error::InvalidProgram; + } + EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); + + MemoryAllocator* temp_allocator = context.get_temp_allocator(); + // Use a temporary allocator for the intermediate tensors of the + // computation. The allocator is released in runtime/executor/method.cpp at + // the end of the execution of the Ethos-U custom delegate + // Ethos-U driver requires 16 bit alignment. + char* ethosu_scratch = static_cast( + temp_allocator->allocate(handles.scratch_data_size, 16UL)); + if (ethosu_scratch == nullptr) { + ET_LOG( + Error, + "Failed to allocate scratch buffer of %zu bytes from temp_allocator", + handles.scratch_data_size); + return Error::MemoryAllocationFailed; + } + ET_LOG( + Debug, + "Running program data:\n cmd %p %zu\n weight %p %zu\n scratch %p %zu\n fast scratch %p %zu\n", + handles.cmd_data, + handles.cmd_data_size, + handles.weight_data, + handles.weight_data_size, + ethosu_scratch, + handles.scratch_data_size, + ethosu_fast_scratch, + ethosu_fast_scratch_size); + + // Write argument values (from EValue tensor) into Ethos-U scratch + // TODO(MLETORCH-123): Optimise into direct write from Vela into the SRAM + // or DRAM output for compatible data layouts. + for (int i = 0; i < handles.inputs->count; i++) { + auto tensor_count = 1, io_count = 1; + auto tensor_in = args[i]->toTensor(); + char* scratch_addr = ethosu_scratch + handles.inputs->io[i].offset; + + // We accept: + bool supported = 0; + // 32 bit int (simple non-quantised test cases) + supported |= + (tensor_in.scalar_type() == ScalarType::Int and + handles.inputs->io[i].elem_size == 4); + // 8 bit int (IOQDQ pass prepared networks) + supported |= + (tensor_in.scalar_type() == ScalarType::Char and + handles.inputs->io[i].elem_size == 1); + // 16 bit int (IOQDQ pass prepared networks) + supported |= + (tensor_in.scalar_type() == ScalarType::Short and + handles.inputs->io[i].elem_size == 2); + // bool (IOQDQ pass prepared networks) + supported |= + (tensor_in.scalar_type() == ScalarType::Bool and + handles.inputs->io[i].elem_size == 1); + if (!supported) { + ET_LOG( + Error, + "Input %d expected Integer (4 byte), Char (1 byte) or Bool (1 byte) integer inputs, got ScalarType id %s size %d", + i, + executorch::runtime::toString(tensor_in.scalar_type()), + handles.inputs->io[i].elem_size); + return Error::InvalidProgram; + } + + // Select a compatible copy routine including checking for input layouts + // which require permutation. + bool both_int = tensor_in.scalar_type() == ScalarType::Int && + handles.inputs->io[i].elem_size == 4; + bool both_char = tensor_in.scalar_type() == ScalarType::Char && + handles.inputs->io[i].elem_size == 1; + bool both_short = tensor_in.scalar_type() == ScalarType::Short && + handles.inputs->io[i].elem_size == 2; + bool both_bool = tensor_in.scalar_type() == ScalarType::Bool && + (handles.inputs->io[i].elem_size == 1); + + if (both_char || both_int || both_short || both_bool) { + EXECUTORCH_PROF_SCOPE( + event_tracer, "+EthosUBackend::execute()handles.input.memcpy()"); + // Sizes match and elt size matches so memcpy + memcpy( + scratch_addr, + tensor_in.mutable_data_ptr(), + tensor_in.nbytes()); + } else { + ET_LOG(Error, "No matching input copy routine"); + return Error::InvalidProgram; + } + calculate_dimensions( + tensor_in, &handles.inputs->io[i], &tensor_count, &io_count); + if (tensor_count != io_count) { + ET_LOG(Error, "Input tensor sizes do not match"); + ET_LOG( + Error, + "Program expects %d elements but got %d", + io_count, + tensor_count); + return Error::InvalidProgram; + } + } + + // Allocate driver handle and synchronously invoke driver + auto driver = + std::unique_ptr( + ethosu_reserve_driver(), ethosu_release_driver); + if (driver == NULL) { + ET_LOG(Error, "ethosu_reserve_driver failed"); + return Error::InvalidState; + } + + // Ethos-U low level driver expected order for Ethos U-55, we have + // constant weight data, then scratch (which contains input and output) + // scratch is written above in this function. + + uint64_t bases[ETHOSU_NUM_BASE_ADDRS] = { + static_cast( + reinterpret_cast((handles.weight_data))), + static_cast(reinterpret_cast(ethosu_scratch)), + static_cast( + reinterpret_cast(ethosu_fast_scratch))}; + size_t bases_size[ETHOSU_NUM_BASE_ADDRS] = { + handles.weight_data_size, + handles.scratch_data_size, + ethosu_fast_scratch_size}; + int result = 0; + EXECUTORCH_PROF_START( + event_tracer, event_tracer_local_scope, "+EthosUBackend::execute()NPU"); + result = ethosu_invoke_v3( + driver.get(), + static_cast(handles.cmd_data), + handles.cmd_data_size, + bases, + bases_size, + ETHOSU_NUM_BASE_ADDRS, /* fixed array of pointers to binary interface*/ + nullptr); + EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); + + if (result != 0) { + ET_LOG(Error, "Ethos-U invocation failed error (%d)", result); + return Error::InvalidProgram; + } + size_t tensor_bytes_total = 0; + size_t io_bytes_total = 0; + // Write outputs from scratch into EValue pointers + for (int i = 0; i < handles.outputs->count; i++) { + int tensor_count = 1, io_count = 1; + const char* output_addr = ethosu_scratch + handles.outputs->io[i].offset; + // Process input EValue into scratch + // Outputs are in the index immediately after inputs + auto tensor_out = args[handles.inputs->count + i]->toTensor(); + + calculate_dimensions( + tensor_out, &handles.outputs->io[i], &tensor_count, &io_count); + + size_t tensor_bytes = tensor_out.nbytes(); + size_t io_bytes = static_cast(io_count) * + static_cast(handles.outputs->io[i].elem_size); + + ET_LOG( + Error, + "Output %d: tensor_bytes=%zu io_bytes=%zu tensor_count=%d io_count=%d elem_size=%d shape=[%d,%d,%d,%d,%d,%d] tensor_dim=%d offset=%d", + i, + tensor_bytes, + io_bytes, + tensor_count, + io_count, + handles.outputs->io[i].elem_size, + handles.outputs->io[i].shape[0], + handles.outputs->io[i].shape[1], + handles.outputs->io[i].shape[2], + handles.outputs->io[i].shape[3], + handles.outputs->io[i].shape[4], + handles.outputs->io[i].shape[5], + tensor_out.dim(), + handles.outputs->io[i].offset); + + if (tensor_bytes != io_bytes) { + ET_LOG( + Error, + "Output %d: MISMATCH tensor_bytes(%zu) != io_bytes(%zu)", + i, + tensor_bytes, + io_bytes); + Error status = copy_with_layout_adjustment( + handles.outputs->io[i], i, output_addr, tensor_out, tensor_bytes); + if (status != Error::Ok) { + ET_LOG( + Error, + "Output %d: copy_with_layout_adjustment FAILED status=%d", + i, + static_cast(status)); + return status; + } + io_bytes_total += tensor_bytes; + } else { + EXECUTORCH_PROF_SCOPE( + event_tracer, "+EthosUBackend::execute()handles.output.memcpy()"); + + memcpy( + tensor_out.mutable_data_ptr(), + static_cast(output_addr), + tensor_bytes); + io_bytes_total += io_bytes; + } + + // At times the topological order of the outputs may change. + // Lets instead ensure that the sum of output bytes match. + tensor_bytes_total += tensor_bytes; + } + if (tensor_bytes_total != io_bytes_total) { + ET_LOG(Error, "Total output tensor sizes do not match"); + ET_LOG( + Error, + "Program expects %zu bytes but got %zu", + io_bytes_total, + tensor_bytes_total); + return Error::InvalidProgram; + } + return Error::Ok; + } + + void destroy(DelegateHandle* handle) const override { + return; + } + + private: + // Copies Vela output into the ExecuTorch tensor, adjusting for padding or + // packed layouts produced by the delegate. + Error copy_with_layout_adjustment( + const VelaIO& output_io, + int output_index, + const char* src, + executorch::aten::Tensor& tensor_out, + size_t tensor_bytes) const { + const int elem_size = output_io.elem_size; + if (elem_size == 0) { + ET_LOG( + Error, "Ethos-U output %d reports zero element size", output_index); + return Error::InvalidProgram; + } + + size_t chunk_count = 1; + for (int dim = 0; dim < shapeDim - 1; ++dim) { + const int vela_dim = output_io.shape[dim]; + chunk_count *= static_cast(vela_dim == 0 ? 1 : vela_dim); + } + const int last_dim = output_io.shape[shapeDim - 1]; + const size_t vela_chunk_elems = + static_cast(last_dim == 0 ? 1 : last_dim); + const size_t vela_chunk_size = + vela_chunk_elems * static_cast(elem_size); + + if (tensor_bytes % chunk_count != 0) { + ET_LOG( + Error, + "Ethos-U output %d tensor bytes %zu not divisible by chunk count %zu", + output_index, + tensor_bytes, + chunk_count); + return Error::InvalidProgram; + } + + const size_t chunk_size = tensor_bytes / chunk_count; + + ET_LOG( + Error, + "copy_with_layout output %d: chunk_count=%zu vela_chunk=%zu chunk=%zu vela_elems=%zu elem_sz=%d", + output_index, + chunk_count, + vela_chunk_size, + chunk_size, + vela_chunk_elems, + elem_size); + + // If Vela writes fewer bytes than the tensor expects we may need to + // expand 4-bit data to 8-bit. Ethos-U outputs may be + // packed 4-bit values but ExecuTorch tensors are at least 8-bit. + if (vela_chunk_size < chunk_size) { + if (chunk_size % vela_chunk_size != 0) { + ET_LOG( + Error, + "Ethos-U output %d chunk bytes %zu not divisible by vela chunk bytes %zu", + output_index, + chunk_size, + vela_chunk_size); + return Error::InvalidProgram; + } + + const size_t expand_factor = chunk_size / vela_chunk_size; + if (expand_factor == 2 && elem_size == 1 && + tensor_out.scalar_type() == ScalarType::Char) { + return unpack_chunks_4bit_to_int8( + reinterpret_cast(src), + tensor_out.mutable_data_ptr(), + chunk_count, + chunk_size, + vela_chunk_size); + } + + ET_LOG( + Error, + "Ethos-U output %d expansion factor %zu with element size %d not supported", + output_index, + expand_factor, + elem_size); + return Error::InvalidProgram; + } + + return strip_delegate_padding( + src, + tensor_out.mutable_data_ptr(), + chunk_count, + chunk_size, + vela_chunk_size); + } + + Error unpack_chunks_4bit_to_int8( + const uint8_t* src, + int8_t* dest, + size_t chunk_count, + size_t dest_chunk_size, + size_t src_chunk_size) const { + const uint8_t* chunk_src = src; + int8_t* chunk_dest = dest; + for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { + unpack_single_chunk_4bit_to_int8(chunk_src, chunk_dest, src_chunk_size); + chunk_src += src_chunk_size; + chunk_dest += dest_chunk_size; + } + return Error::Ok; + } + + void unpack_single_chunk_4bit_to_int8( + const uint8_t* src, + int8_t* dest, + size_t chunk_size) const { + for (size_t byte_idx = 0; byte_idx < chunk_size; ++byte_idx) { + const uint8_t packed = src[byte_idx]; + int8_t low = static_cast(packed & 0x0F); + int8_t high = static_cast((packed >> 4) & 0x0F); + if (low >= 8) { + low -= 16; + } + if (high >= 8) { + high -= 16; + } + dest[2 * byte_idx] = low; + dest[2 * byte_idx + 1] = high; + } + } + + Error strip_delegate_padding( + const char* src, + char* dest, + size_t chunk_count, + size_t dest_chunk_size, + size_t src_chunk_size) const { + if (dest_chunk_size > src_chunk_size) { + ET_LOG( + Error, + "dest chunk size %zu must not exceed src chunk size %zu", + dest_chunk_size, + src_chunk_size); + return Error::InvalidProgram; + } + if (src == nullptr || dest == nullptr) { + ET_LOG(Error, "Ethos-U padded copy received null buffer"); + return Error::InvalidState; + } + for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { + memcpy(dest, src, dest_chunk_size); + src += src_chunk_size; + dest += dest_chunk_size; + } + return Error::Ok; + } + + void calculate_dimensions( + const executorch::aten::Tensor tensor, + VelaIO* io, + int* tensor_count, + int* io_count) const { + for (int i = 0; i < tensor.dim(); i++) { + *tensor_count = *tensor_count * tensor.size(i); + } + + // The VelaIO type has a shape of fixed size 6 + for (int i = 0; i < shapeDim; i++) { + *io_count = *io_count * io->shape[i]; + } + } +}; + +namespace { +auto EthosUBackend_backend = EthosUBackend(); +Backend EthosUBackend_id{"EthosUBackend", &EthosUBackend_backend}; +static executorch::runtime::Error EthosUBackend_registered = + register_backend(EthosUBackend_id); + +#ifdef __ZEPHYR__ +/** + * This function serves as a linker force-include mechanism to ensure the + * EthosU backend module gets properly linked into the final executable, + * even when it might otherwise be optimized out by the linker due to + * linker options that remove unused code or data for example + * if you link with --gc-sections + * This function can be called from your runner to force the inclusion of + * the EthosU backend module. As a bonus it will return the status of the + * backend registration, so you can also check if the registration was + * successful. + */ + +// Warning: This should not be considered to be an API and might get removed +// without notice in a future release if a better way to solve this is +// implemented. +extern "C" executorch::runtime::Error +executorch_delegate_EthosUBackend_registered() { + return EthosUBackend_registered; +} +#endif + +} // namespace + +} // namespace arm +} // namespace backends +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/TARGETS new file mode 100644 index 0000000..67f2bab --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/TARGETS @@ -0,0 +1,5 @@ +load("targets.bzl", "define_common_targets") + +oncall("odai_jarvis") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFBackend.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFBackend.cpp similarity index 85% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFBackend.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFBackend.cpp index 8ac804f..ce18205 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFBackend.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFBackend.cpp @@ -1,14 +1,14 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ -#include +#include +#include using namespace std; -#include #include #include #include @@ -75,9 +75,7 @@ void vkml_free_basics( VkInstance* instance, VkDevice* device, VkCommandPool* command_pool) { - if (*device != VK_NULL_HANDLE && *command_pool != VK_NULL_HANDLE) { - vkDestroyCommandPool(*device, *command_pool, nullptr); - } + vkDestroyCommandPool(*device, *command_pool, nullptr); // Note: These primitives are used by the emulation layer for vulkan // object allocation, the vulkan objects are freed in in library // shutdown, so we can't yet destroy these here without causing @@ -88,14 +86,7 @@ void vkml_free_basics( class VGFBackend final : public ::executorch::runtime::BackendInterface { public: - VGFBackend() = default; - - // Lazy Vulkan init — runs on first use, not in the constructor. - void ensure_initialized() { - if (is_initialized_) { - return; - } - + VGFBackend() { VkResult result; // Fetch basic vulkan objects once @@ -120,20 +111,21 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { result); return; } - - is_initialized_ = true; } ~VGFBackend() { vkml_free_basics(&vk_instance, &vk_device, &vk_command_pool); } bool is_available() const override { + VkResult result; + ET_LOG(Info, "Checking VGFBackend is available"); - const_cast(this)->ensure_initialized(); - if (!is_initialized_) { + // Query the device prepared in constructor for needed extensions + result = vkml_load_extensions(&vk_device); + if (result != VK_SUCCESS) return false; - } - return vkml_load_extensions(&vk_device) == VK_SUCCESS; + + return true; } Result init( @@ -142,14 +134,6 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { ArrayRef compile_specs) const override { ET_LOG(Info, "Entered VGF init"); - const_cast(this)->ensure_initialized(); - if (!is_initialized_) { - ET_LOG( - Error, - "VGF backend is unavailable because Vulkan initialization failed"); - return Error::NotSupported; - } - const char* vgf_data = reinterpret_cast(processed->data()); MemoryAllocator* allocator = context.get_runtime_allocator(); @@ -157,8 +141,7 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { new (repr) VgfRepr( vk_instance, vk_physical_device, vk_device, vk_queue, vk_command_pool); - auto valid_vgf = - repr->process_vgf(vgf_data, processed->size(), compile_specs); + auto valid_vgf = repr->process_vgf(vgf_data, compile_specs); if (!valid_vgf) { ET_LOG(Error, "Failed to process VGF blob."); return Error::Internal; @@ -191,18 +174,8 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { if (!io->is_input) continue; - size_t io_size = io->elt_size; - for (int64_t dim : io->size) { - ET_CHECK_OR_RETURN_ERROR( - dim >= 0, - InvalidArgument, - "Negative dimension in IO size: %" PRId64, - dim); - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(io_size, static_cast(dim), &io_size), - InvalidArgument, - "Overflow computing IO buffer size"); - } + size_t io_size = accumulate( + io->size.begin(), io->size.end(), io->elt_size, std::multiplies<>()); void* data; if (!repr->map_io(io, &data)) { @@ -236,18 +209,8 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { if (io->is_input) continue; - size_t io_size = io->elt_size; - for (int64_t dim : io->size) { - ET_CHECK_OR_RETURN_ERROR( - dim >= 0, - InvalidArgument, - "Negative dimension in IO size: %" PRId64, - dim); - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(io_size, static_cast(dim), &io_size), - InvalidArgument, - "Overflow computing IO buffer size"); - } + size_t io_size = accumulate( + io->size.begin(), io->size.end(), io->elt_size, std::multiplies<>()); void* data; if (!repr->map_io(io, &data)) { @@ -267,12 +230,11 @@ class VGFBackend final : public ::executorch::runtime::BackendInterface { } private: - VkInstance vk_instance = VK_NULL_HANDLE; - VkPhysicalDevice vk_physical_device = VK_NULL_HANDLE; - VkDevice vk_device = VK_NULL_HANDLE; - VkQueue vk_queue = VK_NULL_HANDLE; - VkCommandPool vk_command_pool = VK_NULL_HANDLE; - bool is_initialized_ = false; + VkInstance vk_instance; + VkPhysicalDevice vk_physical_device; + VkDevice vk_device; + VkQueue vk_queue; + VkCommandPool vk_command_pool; }; namespace { @@ -291,7 +253,6 @@ VkResult vkml_allocate_basics( if (VK_SUCCESS != volkInitialize()) { ET_LOG(Error, "Volk failed to initialize"); - return VK_ERROR_INITIALIZATION_FAILED; } VkApplicationInfo app_info{ @@ -364,16 +325,6 @@ VkResult vkml_allocate_basics( } volkLoadInstance(*instance); - // Bail out if the driver lacks ARM tensor/datagraph extensions. - if (!vkCreateTensorARM) { - ET_LOG( - Error, - "Vulkan driver does not support ARM tensor extensions (VK_ARM_tensors)"); - vkDestroyInstance(*instance, nullptr); - *instance = VK_NULL_HANDLE; - return VK_ERROR_FEATURE_NOT_PRESENT; - } - // Pick first GPU uint32_t gpu_count = 0; vkEnumeratePhysicalDevices(*instance, &gpu_count, nullptr); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFSetup.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFSetup.cpp similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFSetup.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFSetup.cpp index b62a6b2..fd3a114 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VGFSetup.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFSetup.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -31,7 +31,6 @@ namespace { constexpr int64_t kScalarSentinelDimension = 1; } -#if defined(ET_ARM_VGF_DEBUG) // Debug function to inspect memory properties static string memory_flags_to_string(VkMemoryPropertyFlags flags) { if (flags == 0) @@ -55,7 +54,7 @@ static string memory_flags_to_string(VkMemoryPropertyFlags flags) { #undef TRY_FLAG if (flags) { - // Preserve any unrecognized bits in hex so debug logs stay complete. + // any leftover bits we didn’t name ostringstream hex; hex << "0x" << std::hex << flags; parts.emplace_back(hex.str()); @@ -69,7 +68,6 @@ static string memory_flags_to_string(VkMemoryPropertyFlags flags) { } return joined.str(); } -#endif /** * Tensor free helper function @@ -175,12 +173,7 @@ VkResult allocate_tensor( .memoryTypeIndex = memory_index, }; - result = vkAllocateMemory(device, &allocate_info, nullptr, memory); - if (result != VK_SUCCESS) { - ET_LOG(Error, "Failed to allocate tensor memory, error %d", result); - vkDestroyTensorARM(device, *tensor, nullptr); - return result; - } + vkAllocateMemory(device, &allocate_info, nullptr, memory); // Bind tensor to memory const VkBindTensorMemoryInfoARM bind_info = { @@ -190,13 +183,7 @@ VkResult allocate_tensor( .memory = *memory, .memoryOffset = 0, }; - result = vkBindTensorMemoryARM(device, 1, &bind_info); - if (result != VK_SUCCESS) { - ET_LOG(Error, "Failed to bind tensor memory, error %d", result); - vkDestroyTensorARM(device, *tensor, nullptr); - vkFreeMemory(device, *memory, nullptr); - return result; - } + vkBindTensorMemoryARM(device, 1, &bind_info); VkTensorViewCreateInfoARM tensor_view_info = { .sType = VK_STRUCTURE_TYPE_TENSOR_VIEW_CREATE_INFO_ARM, @@ -249,7 +236,6 @@ static void debug_print_sequence( } } -#if defined(ET_ARM_VGF_DEBUG) static void debug_print_resources( unique_ptr& resource_decoder) { ET_LOG(Info, "Resources:"); @@ -274,7 +260,7 @@ static void debug_print_resources( case vgflib::ResourceCategory::INPUT: case vgflib::ResourceCategory::OUTPUT: { ET_LOG(Info, " Category INPUT/OUTPUT"); - // Log the tensor layout metadata carried in the resource table. + // Get tensor shape and strides auto shape = resource_decoder->getTensorShape(i); const vector the_shape(shape.begin(), shape.end()); auto stride = resource_decoder->getTensorStride(i); @@ -291,15 +277,7 @@ static void debug_print_resources( j, static_cast(the_shape[j])); } - // Show the memory property combination the runtime currently targets. - ET_LOG( - Info, - " memory flags %s", - memory_flags_to_string( - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) - .c_str()); + // Allocate a tensor with bound memory break; } case vgflib::ResourceCategory::INTERMEDIATE: @@ -314,7 +292,6 @@ static void debug_print_resources( } } } -#endif static void debug_print_modules( unique_ptr& module_decoder) { @@ -336,38 +313,26 @@ static void debug_print_modules( } } -bool VgfRepr::process_vgf( - const char* vgf_data, - size_t vgf_size, - ArrayRef specs) { +bool VgfRepr::process_vgf(const char* vgf_data, ArrayRef specs) { ET_LOG(Info, "Preparing VGF as Vulkan objects"); VkResult result; // Prepare temporary decoders unique_ptr header_decoder = - vgflib::CreateHeaderDecoder(vgf_data, vgflib::HeaderSize(), vgf_size); - if (!header_decoder) { - ET_LOG(Error, "Failed to create VGF header decoder"); - return false; - } - + vgflib::CreateHeaderDecoder(vgf_data); unique_ptr sequence_decoder = vgflib::CreateModelSequenceTableDecoder( - vgf_data + header_decoder->GetModelSequenceTableOffset(), - header_decoder->GetModelSequenceTableSize()); + vgf_data + header_decoder->GetModelSequenceTableOffset()); unique_ptr module_decoder = vgflib::CreateModuleTableDecoder( - vgf_data + header_decoder->GetModuleTableOffset(), - header_decoder->GetModuleTableSize()); + vgf_data + header_decoder->GetModuleTableOffset()); unique_ptr resource_decoder = vgflib::CreateModelResourceTableDecoder( - vgf_data + header_decoder->GetModelResourceTableOffset(), - header_decoder->GetModelResourceTableSize()); + vgf_data + header_decoder->GetModelResourceTableOffset()); unique_ptr constant_decoder = vgflib::CreateConstantDecoder( - vgf_data + header_decoder->GetConstantsOffset(), - header_decoder->GetConstantsSize()); + vgf_data + header_decoder->GetConstantsOffset()); // Check the VGF decoders if (not(header_decoder && module_decoder && sequence_decoder && resource_decoder && constant_decoder && header_decoder->IsValid() && @@ -382,9 +347,6 @@ bool VgfRepr::process_vgf( const int segment_id = 0; debug_print_sequence(sequence_decoder); -#if defined(ET_ARM_VGF_DEBUG) - debug_print_resources(resource_decoder); -#endif if (sequence_decoder->modelSequenceTableSize() != 1) { ET_LOG(Error, "Expected sequence length 1"); return false; @@ -576,7 +538,7 @@ bool VgfRepr::process_vgf( .pNext = nullptr, .flags = 0, .bindingCount = static_cast(layout_bindings.size()), - .pBindings = layout_bindings.data(), + layout_bindings.data(), }; result = vkCreateDescriptorSetLayout(vk_device, &layout_info, nullptr, &vk_layout); @@ -727,7 +689,8 @@ bool VgfRepr::process_vgf( VkDataGraphPipelineCreateInfoARM graph_pipeline_info{ .sType = VK_STRUCTURE_TYPE_DATA_GRAPH_PIPELINE_CREATE_INFO_ARM, .pNext = &shader_info, - .flags = VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR, + .flags = VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT | + VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR, .layout = vk_pipeline_layout, .resourceInfoCount = static_cast(data_graph_resources.size()), .pResourceInfos = data_graph_resources.data(), @@ -836,10 +799,7 @@ bool VgfRepr::process_vgf( .bindPoint = bind_point_requirement.bindPoint, .objectIndex = 0, // NOTE: tied to numObjects assert above }; - VkMemoryRequirements2 memory_requirements = { - .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, - .pNext = nullptr, - }; + VkMemoryRequirements2 memory_requirements; vkGetDataGraphPipelineSessionMemoryRequirementsARM( vk_device, &memory_requirements_info, &memory_requirements); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFSetup.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFSetup.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFSetup.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFSetup.h index 8e07b36..3faa7ca 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/VGFSetup.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VGFSetup.h @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -58,10 +58,7 @@ class VgfRepr { /* * Process a VGF ready for execution, allocate necessary Vulkan objects. */ - bool process_vgf( - const char* vgf_data, - size_t vgf_size, - ArrayRef specs); + bool process_vgf(const char* vgf_data, ArrayRef specs); /* * Execute the VGF we've previously processed. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VelaBinStream.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VelaBinStream.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VelaBinStream.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VelaBinStream.cpp index 70c5b0c..c8d5684 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VelaBinStream.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VelaBinStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2023, 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -65,10 +65,8 @@ bool vela_bin_read(const char* data, VelaHandles* handles, int size) { return false; } else if (!strncmp(b->name, "cmd_data", strlen("cmd_data"))) { // This driver magic header confirms a valid command stream in binary - if (strncmp(b->data, "COP1", strlen("COP1")) && - strncmp(b->data, "COP2", strlen("COP2"))) { + if (strncmp(b->data, "COP1", strlen("COP1"))) return false; - } handles->cmd_data = b->data; handles->cmd_data_size = b->size; } else if (!strncmp(b->name, "weight_data", strlen("weight_data"))) { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VelaBinStream.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VelaBinStream.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/VelaBinStream.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/VelaBinStream.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/targets.bzl new file mode 100644 index 0000000..7dd0d74 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/runtime/targets.bzl @@ -0,0 +1,31 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + runtime.cxx_library( + name = "vela_bin_stream", + srcs = ["VelaBinStream.cpp"], + exported_headers = ["VelaBinStream.h"], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/core:core", + ], + ) + runtime.cxx_library( + name = "arm_backend", + srcs = ["EthosUBackend.cpp"], + headers = [], + compatible_with = ["ovr_config//cpu:arm32-embedded", "ovr_config//cpu:arm32-embedded-fpu"], + # arm_executor_runner.cpp needs to compile with executor as whole + # @lint-ignore BUCKLINT: Avoid `link_whole=True` (https://fburl.com/avoid-link-whole) + link_whole = True, + supports_python_dlopen = True, + # Constructor needed for backend registration. + compiler_flags = ["-Wno-global-constructors"], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/backend:interface", + ":vela_bin_stream", + "//executorch/runtime/core:core", + "fbsource//third-party/ethos-u-core-driver:core_driver", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/TOSA_minimal_example.ipynb b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/TOSA_minimal_example.ipynb new file mode 100644 index 0000000..996082b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/TOSA_minimal_example.ipynb @@ -0,0 +1,266 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright 2025-2026 Arm Limited and/or its affiliates.\n", + "#\n", + "# This source code is licensed under the BSD-style license found in the\n", + "# LICENSE file in the root directory of this source tree." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TOSA delegate flow example\n", + "\n", + "This guide walks through the complete process of running a module on Arm TOSA using ExecuTorch, with a focus on TOSA lowering exploration. \n", + "This workflow is intended for validating and experimenting with model lowering to TOSA, and is aimed at contributors and developers, rather than production deployment.\n", + "It’s important to note that the compilation flow and passes applied can vary based on the target, so this flow does not necessarily produce TOSA flatbuffers and PTE files which are optimal (or even compatible) with any one target.\n", + "If something is not working for you, please raise a GitHub issue and tag Arm.\n", + "\n", + "Before you begin:\n", + "1. (In a clean virtual environment with a compatible Python version) Install executorch using `./install_executorch.sh`\n", + "2. Install Arm TOSA dependencies using `examples/arm/setup.sh --disable-ethos-u-deps`\n", + "\n", + "With all commands executed from the base `executorch` folder.\n", + "\n", + "\n", + "\n", + "*Some scripts in this notebook produces long output logs: Configuring the 'Customizing Notebook Layout' settings to enable 'Output:scrolling' and setting 'Output:Text Line Limit' makes this more manageable*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## AOT Flow\n", + "\n", + "The first step is creating the PyTorch module and exporting it. Exporting converts the python code in the module into a graph structure. The result is still runnable python code, which can be displayed by printing the `graph_module` of the exported program. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "\n", + "print(torch.__version__)\n", + "\n", + "class Add(torch.nn.Module):\n", + " def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:\n", + " return x + y\n", + "\n", + "example_inputs = (torch.ones(1,1,1,1),torch.ones(1,1,1,1))\n", + "\n", + "model = Add()\n", + "model = model.eval()\n", + "exported_program = torch.export.export(model, example_inputs)\n", + "graph_module = exported_program.module(check_guards=False)\n", + "\n", + "_ = graph_module.print_readable()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TOSA backend supports both INT and FP targets.\n", + "\n", + "To lower the graph_module for FP targets using the TOSA backend, we run it through the default FP lowering pipeline.\n", + "\n", + "FP lowering can be customized for different subgraphs; the sequence shown here is the recommended workflow for TOSA. Because we are staying in floating-point precision, no calibration with example inputs is required.\n", + "\n", + "If you print the module again, you will see that nodes are left in FP form (or annotated with any necessary casts) without any quantize/dequantize wrappers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec\n", + "from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e\n", + "from pathlib import Path\n", + "\n", + "target = \"TOSA-1.0+FP\"\n", + "base_name = \"tosa_simple_example\"\n", + "cwd_dir = Path.cwd()\n", + "\n", + "# Create a compilation spec describing the target for configuring the quantizer\n", + "# Dump intermediate artifacts (in this case TOSA flat buffers) to specified location\n", + "compile_spec = TosaCompileSpec(target).dump_intermediate_artifacts_to(str(cwd_dir / base_name))\n", + "\n", + "_ = graph_module.print_readable()\n", + "\n", + "# Create a new exported program using the quantized_graph_module\n", + "lowered_exported_program = torch.export.export(graph_module, example_inputs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To lower the graph_module for INT targets using the TOSA backend, we apply the arm_quantizer.\n", + "\n", + "Quantization can be performed in various ways and tailored to different subgraphs; the sequence shown here represents the recommended workflow for TOSA.\n", + "\n", + "This step also requires calibrating the module with representative inputs.\n", + "\n", + "If you print the module again, you’ll see that each node is now wrapped in quantization/dequantization nodes that embed the calculated quantization parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec\n", + "from executorch.backends.arm.quantizer import (\n", + " TOSAQuantizer,\n", + " get_symmetric_quantization_config,\n", + ")\n", + "from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e\n", + "from pathlib import Path\n", + "\n", + "target = \"TOSA-1.0+INT\"\n", + "base_name = \"tosa_simple_example\"\n", + "cwd_dir = Path.cwd()\n", + "\n", + "# Create a compilation spec describing the target for configuring the quantizer\n", + "# Dump intermediate artifacts (in this case TOSA flat buffers) to specified location\n", + "compile_spec = TosaCompileSpec(target).dump_intermediate_artifacts_to(str(cwd_dir / base_name))\n", + "\n", + "# Create and configure quantizer to use a symmetric quantization config globally on all nodes\n", + "quantizer = TOSAQuantizer(compile_spec)\n", + "operator_config = get_symmetric_quantization_config()\n", + "quantizer.set_global(operator_config)\n", + "\n", + "# Post training quantization\n", + "quantized_graph_module = prepare_pt2e(graph_module, quantizer)\n", + "quantized_graph_module(*example_inputs) # Calibrate the graph module with the example input\n", + "quantized_graph_module = convert_pt2e(quantized_graph_module)\n", + "\n", + "_ = quantized_graph_module.print_readable()\n", + "\n", + "# Create a new exported program using the quantized_graph_module\n", + "lowered_exported_program = torch.export.export(quantized_graph_module, example_inputs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The lowering in the TOSABackend happens in four steps:\n", + "\n", + "1. **Lowering to core Aten operator set**: Transform module to use a subset of operators applicable to edge devices. \n", + "2. **Partitioning**: Find subgraphs which are supported for running on TOSA\n", + "3. **Lowering to TOSA compatible operator set**: Perform transforms to make the TOSA subgraph(s) compatible with TOSA operator set\n", + "4. **Serialization to TOSA**: Compiles the graph module into a TOSA graph \n", + "Step 4 also prints a Network summary for each processed subgraph.\n", + "\n", + "All of this happens behind the scenes in `to_edge_transform_and_lower`. Printing the graph module shows that what is left in the graph is two quantization nodes for `x` and `y` going into an `executorch_call_delegate` node, followed by a dequantization node." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from executorch.backends.arm.tosa.partitioner import TOSAPartitioner\n", + "from executorch.exir import (\n", + " EdgeCompileConfig,\n", + " ExecutorchBackendConfig,\n", + " to_edge_transform_and_lower,\n", + ")\n", + "from executorch.extension.export_util.utils import save_pte_program\n", + "\n", + "# Create partitioner from compile spec\n", + "partitioner = TOSAPartitioner(compile_spec)\n", + "\n", + "# Lower the exported program to the TOSA backend\n", + "edge_program_manager = to_edge_transform_and_lower(\n", + " lowered_exported_program,\n", + " partitioner=[partitioner],\n", + " compile_config=EdgeCompileConfig(\n", + " _check_ir_validity=False,\n", + " ),\n", + " )\n", + "\n", + "# Convert edge program to executorch\n", + "executorch_program_manager = edge_program_manager.to_executorch(\n", + " config=ExecutorchBackendConfig(extract_delegate_segments=False)\n", + " )\n", + "\n", + "executorch_program_manager.exported_program().graph_module.print_readable()\n", + "\n", + "# Save pte file\n", + "pte_name = base_name + \".pte\"\n", + "pte_path = cwd_dir / base_name / pte_name\n", + "save_pte_program(executorch_program_manager, str(pte_path))\n", + "assert pte_path.exists(), \"Build failed; no .pte-file found\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Use TOSA reference model to verify TOSA graph\n", + "\n", + "After the AOT compilation flow is done, the resulting lowered TOSA graph can be verified using the TOSA reference model tool." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import subprocess\n", + "import tosa_reference_model as reference_model\n", + "from executorch.backends.arm.test.runner_utils import TosaReferenceModelDispatch\n", + "\n", + "# Run TOSA graph through reference model using sample inputs\n", + "with TosaReferenceModelDispatch():\n", + " executorch_program_manager.exported_program().module()(*example_inputs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner.sh new file mode 100755 index 0000000..4a14044 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +toolchain=arm-none-eabi-gcc +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." +source "${script_dir}/utils.sh" + +pte_file="" +target="ethos-u55-128" +build_type="Release" +bundleio=false +system_config="" +memory_mode="" +build_with_etdump=false +extra_build_flags="" +output_folder_set=false +output_folder="." +et_build_root="${et_root_dir}/arm_test" +ethosu_tools_dir=${et_root_dir}/examples/arm/arm-scratch +select_ops_list="" + +build_bundleio_flags=" -DET_BUNDLE_IO=OFF " +build_with_etdump_flags=" -DEXECUTORCH_ENABLE_EVENT_TRACER=OFF " + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --pte=||semihosting Set to a pte file (generated by the aot_arm_compier) to include the model in the elf." + echo " Or a hex address in the format of 0x00000000 if placed in memory you need to place it on this ADDR on your target, with your flash tool or other means." + echo " Or specify the word 'semihosting' to supply pte at runtime." + echo " --target= Target to build and run for Default: ${target}" + echo " --build_type= Build with Release, Debug or RelWithDebInfo, default is ${build_type}" + echo " --bundleio Support both pte and Bundle IO bpte using Devtools BundelIO with Input/RefOutput included" + echo " --system_config= System configuration to select from the Vela configuration file (see vela.ini). Default: Ethos_U55_High_End_Embedded for EthosU55 targets, Ethos_U85_SYS_DRAM_Mid for EthosU85 targets." + echo " NOTE: If given, this option must match the given target. This option along with the memory_mode sets timing adapter values customized for specific hardware, see ./executor_runner/CMakeLists.txt." + echo " --memory_mode= Vela memory mode, used for setting the Timing Adapter parameters of the Corstone platforms." + echo " Valid values are Shared_Sram(for Ethos-U55, Ethos-U65, Ethos-85), Sram_Only(for Ethos-U55, Ethos-U65, Ethos-U85) or Dedicated_Sram(for Ethos-U65, Ethos-U85)." + echo " Default: Shared_Sram for the Ethos-U55 and Sram_Only for the Ethos-U85" + echo " --etdump Adds Devtools etdump support to track timing and output, etdump area will be base64 encoded in the log" + echo " --extra_build_flags= Extra flags to pass to cmake like -DET_ARM_BAREMETAL_METHOD_ALLOCATOR_POOL_SIZE=60000 Default: none " + echo " --output= Output folder Default: /_.pte" + echo " --et_build_root= Build output root folder to use, defaults to ${et_build_root}" + echo " --ethosu_tools_dir= Path to your Ethos-U tools dir if you not using default: ${ethosu_tools_dir}" + echo " --toolchain= Toolchain can be specified (e.g. bare metal as arm-none-eabi-gcc or zephyr as arm-zephyr-eabi-gcc Default: ${toolchain}" + echo " --select_ops_list= Comma separated list of portable (non delagated) kernels to include Default: ${select_ops_list}" + echo " NOTE: This is used when select_ops_model is not possible to use, e.g. for semihosting or bundleio." + echo " See https://docs.pytorch.org/executorch/stable/kernel-library-selective-build.html for more information." + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --pte=*) pte_file="${arg#*=}";; + --target=*) target="${arg#*=}";; + --build_type=*) build_type="${arg#*=}";; + --bundleio) bundleio=true ;; + --system_config=*) system_config="${arg#*=}";; + --memory_mode=*) memory_mode="${arg#*=}";; + --etdump) build_with_etdump=true ;; + --extra_build_flags=*) extra_build_flags="${arg#*=}";; + --output=*) output_folder="${arg#*=}" ; output_folder_set=true ;; + --et_build_root=*) et_build_root="${arg#*=}";; + --ethosu_tools_dir=*) ethosu_tools_dir="${arg#*=}";; + --toolchain=*) toolchain="${arg#*=}";; + --select_ops_list=*) select_ops_list="${arg#*=}";; + *) + ;; + esac +done + +if [[ ${toolchain} == "arm-none-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/${toolchain}.cmake +elif [[ ${toolchain} == "arm-zephyr-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/zephyr/x86_64-linux-arm-zephyr-eabi-gcc.cmake +else + echo "Error: Invalid toolchain selection, provided: ${toolchain}" + echo " Valid options are {arm-none-eabi-gcc, arm-zephyr-eabi-gcc}" + exit 1; +fi +toolchain_cmake=$(realpath ${toolchain_cmake}) + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +if [[ ${pte_file} == "semihosting" ]]; then + pte_data="-DSEMIHOSTING=ON" +else + if [[ "$pte_file" =~ ^0x[0-9a-fA-F]{1,16}$ ]]; then + echo "PTE in memory at ${pte_file}, make sure to put it there on your target before starting." + pte_data="-DET_MODEL_PTE_ADDR=${pte_file}" + if [ "$output_folder_set" = false ] ; then + # Not locked down to a PTE use + output_folder=${et_build_root}/${target}_${pte_file}/cmake-out + fi + else + echo "PTE included in elf from file ${pte_file}" + pte_file=$(realpath ${pte_file}) + pte_data="-DET_PTE_FILE_PATH:PATH=${pte_file}" + if [ "$output_folder_set" = false ] ; then + # remove file ending + output_folder=${pte_file%.*}/cmake-out + fi + fi +fi +ethosu_tools_dir=$(realpath ${ethosu_tools_dir}) +ethos_u_root_dir="$ethosu_tools_dir/ethos-u" +mkdir -p "${ethos_u_root_dir}" +ethosu_tools_dir=$(realpath ${ethos_u_root_dir}) + +et_build_dir=${et_build_root}/cmake-out +mkdir -p ${et_build_dir} +et_build_dir=$(realpath ${et_build_dir}) + +if [[ ${system_config} == "" ]] +then + system_config="Ethos_U55_High_End_Embedded" + if [[ ${target} =~ "ethos-u85" ]] + then + system_config="Ethos_U85_SYS_DRAM_Mid" + fi +fi + +if [[ ${memory_mode} == "" ]] +then + memory_mode="Shared_Sram" + if [[ ${target} =~ "ethos-u85" ]] + then + memory_mode="Dedicated_Sram_384KB" + fi +fi + +mkdir -p "${output_folder}" +output_folder=$(realpath ${output_folder}) + +if [[ ${target} == *"ethos-u55"* ]]; then + target_cpu=cortex-m55 +else + target_cpu=cortex-m85 +fi +echo "--------------------------------------------------------------------------------" +echo "Build Arm ${toolchain/-gcc/} executor_runner for ${target} PTE: ${pte_file} using ${system_config} ${memory_mode} ${extra_build_flags} to '${output_folder}'" +echo "--------------------------------------------------------------------------------" + +cd ${et_root_dir}/examples/arm/executor_runner + +if [ "$bundleio" = true ] ; then + build_bundleio_flags=" -DET_BUNDLE_IO=ON " +fi + +if [ "$build_with_etdump" = true ] ; then + build_with_etdump_flags=" -DEXECUTORCH_ENABLE_EVENT_TRACER=ON -DET_DUMP_INTERMEDIATE_OUTPUTS=ON " +fi + +echo "Building with BundleIO/etdump/extra flags: ${build_bundleio_flags} ${build_with_etdump_flags} ${extra_build_flags}" +cmake \ + -DCMAKE_BUILD_TYPE=${build_type} \ + -DCMAKE_TOOLCHAIN_FILE=${toolchain_cmake} \ + -DTARGET_CPU=${target_cpu} \ + -DET_DIR_PATH:PATH=${et_root_dir} \ + -DET_BUILD_DIR_PATH:PATH=${et_build_dir} \ + -DETHOS_SDK_PATH:PATH=${ethos_u_root_dir} \ + -DETHOSU_TARGET_NPU_CONFIG=${target} \ + ${pte_data} \ + ${build_bundleio_flags} \ + ${build_with_etdump_flags} \ + -DPYTHON_EXECUTABLE=$(which python3) \ + -DSYSTEM_CONFIG=${system_config} \ + -DMEMORY_MODE=${memory_mode} \ + -DEXECUTORCH_SELECT_OPS_LIST="${select_ops_list}" \ + ${extra_build_flags} \ + -B ${output_folder} + +echo "[${BASH_SOURCE[0]}] Configured CMAKE" + +parallel_jobs="$(get_parallel_jobs)" + +cmake --build ${output_folder} -j"${parallel_jobs}" -- arm_executor_runner + +echo "[${BASH_SOURCE[0]}] Generated ${toolchain} elf file:" +find ${output_folder} -name "arm_executor_runner" +echo "executable_text: $(find ${output_folder} -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $1}') bytes" +echo "executable_data: $(find ${output_folder} -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $2}') bytes" +echo "executable_bss: $(find ${output_folder} -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $3}') bytes" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner_vkml.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner_vkml.sh new file mode 100755 index 0000000..f443032 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executor_runner_vkml.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." +build_type="Release" +build_with_etdump=false +extra_build_flags="" +output_folder="cmake-out-vkml" +build_with_etdump_flags="-DEXECUTORCH_ENABLE_EVENT_TRACER=OFF" +build_with_bundleio_flags="-DEXECUTORCH_ENABLE_BUNDLE_IO=OFF" + +source "${script_dir}/utils.sh" + + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --build_type= Build with Release, Debug or RelWithDebInfo, default is ${build_type}" + echo " --etdump Adds Devtools etdump support to track timing, etdump area will be base64 encoded in the log" + echo " --extra_build_flags= Extra flags to pass to cmake. Default: none " + echo " --output= Output folder Default: $(output_folder)" + echo " --bundleio Support BundleIO using Devtools with Input/RefOutput included" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --build_type=*) build_type="${arg#*=}";; + --etdump) build_with_etdump=true ;; + --extra_build_flags=*) extra_build_flags="${arg#*=}";; + --output=*) output_folder="${arg#*=}";; + --select_ops_list=*) select_ops_list="${arg#*=}";; + --bundleio) build_with_bundleio_flags="-DEXECUTORCH_ENABLE_BUNDLE_IO=ON" ;; + *) + ;; + esac +done + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +mkdir -p "${output_folder}" +output_folder=$(realpath "${output_folder}") + +cd ${et_root_dir}/examples/arm/executor_runner + +if [ "$build_with_etdump" = true ] ; then + build_with_etdump_flags="-DEXECUTORCH_ENABLE_EVENT_TRACER=ON" +fi + +echo "-----------------------------------------------------------------------------------------------" +echo "Build Arm VKML executor runner: '${output_folder}' with extra build flags: " +echo "${build_with_etdump_flags} ${build_with_bundleio_flags} ${extra_build_flags}" +echo "-----------------------------------------------------------------------------------------------" + +cmake \ + -S "${et_root_dir}" \ + -B "${output_folder}" \ + -Wall \ + -Werror \ + -DCMAKE_BUILD_TYPE=${build_type} \ + -DCMAKE_CXX_FLAGS="${extra_build_flags} ${CMAKE_CXX_FLAGS:-}" \ + -DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \ + -DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \ + -DEXECUTORCH_BUILD_EXTENSION_NAMED_DATA_MAP=ON \ + -DEXECUTORCH_BUILD_EXTENSION_FLAT_TENSOR=ON \ + -DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \ + -DEXECUTORCH_BUILD_XNNPACK=OFF \ + -DEXECUTORCH_BUILD_VULKAN=ON \ + -DEXECUTORCH_BUILD_VGF=ON \ + -DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \ + -DEXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT=ON \ + -DEXECUTORCH_ENABLE_LOGGING=ON \ + -DEXECUTORCH_BUILD_DEVTOOLS=ON \ + -DPYTHON_EXECUTABLE="$(which python3)" \ + ${build_with_etdump_flags} \ + ${build_with_bundleio_flags} + +echo "[${BASH_SOURCE[0]}] Configured CMAKE" + +parallel_jobs="$(get_parallel_jobs)" + +cmake --build "${output_folder}" --parallel "${parallel_jobs}" + +echo "[${BASH_SOURCE[0]}] Built VKML runner: " +find ${output_folder} -name "executor_runner" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executorch.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executorch.sh new file mode 100755 index 0000000..b0a93c9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_executorch.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Optional parameter: +# --build_type= "Release" | "Debug" | "RelWithDebInfo" | "UndefinedSanitizer" | "AddressSanitizer" +# --etdump build with devtools-etdump support + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +toolchain=arm-none-eabi-gcc +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + +source "${script_dir}/utils.sh" + +et_build_root="${et_root_dir}/arm_test" +build_type="Release" +build_devtools=OFF +build_with_etdump=OFF + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --et_build_root= Build output root folder to use, defaults to ${et_build_root}" + echo " --build_type= Build with Release, Debug, RelWithDebInfo, UndefinedSanitizer or AddressSanitizer, default is ${build_type}" + echo " --devtools Build Devtools libs" + echo " --etdump Adds Devtools etdump support to track timing, etdump area will be base64 encoded in the log" + echo " --toolchain= Toolchain can be specified (e.g. bare metal as arm-none-eabi-gcc or zephyr as arm-zephyr-eabi-gcc Default: ${toolchain}" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --et_build_root=*) et_build_root="${arg#*=}";; + --build_type=*) build_type="${arg#*=}";; + --devtools) build_devtools=ON ;; + --etdump) build_with_etdump=ON ;; + --toolchain=*) toolchain="${arg#*=}";; + *) + ;; + esac +done + +if [[ ${toolchain} == "arm-none-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/${toolchain}.cmake +elif [[ ${toolchain} == "arm-zephyr-eabi-gcc" ]]; then + toolchain_cmake=${et_root_dir}/examples/zephyr/x86_64-linux-arm-zephyr-eabi-gcc.cmake +else + echo "Error: Invalid toolchain selection, provided: ${toolchain}" + echo " Valid options are {arm-none-eabi-gcc, arm-zephyr-eabi-gcc}" + exit 1; +fi +toolchain_cmake=$(realpath ${toolchain_cmake}) + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +et_build_dir="${et_build_root}/cmake-out" + +set -x +cd "${et_root_dir}" + +( set +x ; + echo "--------------------------------------------------------------------------------" ; + echo "Build ExecuTorch target libs ${build_type} into '${et_build_dir}'" ; + echo "--------------------------------------------------------------------------------" ) + +# Build +cmake -DCMAKE_TOOLCHAIN_FILE=${toolchain_cmake} \ +-DCMAKE_BUILD_TYPE=${build_type} \ +-DEXECUTORCH_BUILD_DEVTOOLS=$build_devtools \ +-DEXECUTORCH_BUILD_ARM_ETDUMP=$build_with_etdump \ +--preset arm-baremetal -B${et_build_dir} + +parallel_jobs="$(get_parallel_jobs)" + +cmake --build ${et_build_dir} -j"${parallel_jobs}" --target install --config ${build_type} -- + +set +x + +echo "[$(basename $0)] Generated static libraries for ExecuTorch:" +find ${et_build_dir} -name "*.a" -exec ls -al {} \; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_portable_kernels.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_portable_kernels.sh new file mode 100755 index 0000000..cfa008c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/build_portable_kernels.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +echo "DEPRECATED: build_portable_kernels.sh is deprecated and will be removed. The kernel registration library is now built directly with the arm_executor_runner." diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/collect_testname_resources.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/collect_testname_resources.py new file mode 100644 index 0000000..54d4a9c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/collect_testname_resources.py @@ -0,0 +1,194 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +import ast +import pathlib +import re + +from executorch.exir.dialects.edge.spec.utils import SAMPLE_INPUT as _SAMPLE_INPUT + +# Add all targets and TOSA profiles we support here. +TARGETS = [ + "tosa_FP", + "tosa_INT", + "tosa_INT+FP", + "u55_INT", + "u85_INT", + "vgf_INT", + "vgf_FP", + "vgf_quant", + "vgf_no_quant", + "no_target", +] + +# Add edge ops which we lower but which are not included in exir/dialects/edge/edge.yaml here. +_CUSTOM_EDGE_OPS = [ + "linspace.default", + "cond.default", + "eye.default", + "expm1.default", + "vector_norm.default", + "hardsigmoid.default", + "hardswish.default", + "linear.default", + "maximum.default", + "mean.default", + "multihead_attention.default", + "adaptive_avg_pool2d.default", + "bitwise_right_shift.Tensor", + "bitwise_right_shift.Scalar", + "bitwise_left_shift.Tensor", + "bitwise_left_shift.Scalar", + "native_group_norm.default", + "silu.default", + "sdpa.default", + "sum.default", + "unbind.int", + "unflatten.int", + "_native_batch_norm_legit_no_training.default", + "_native_batch_norm_legit.no_stats", + "alias_copy.default", + "pixel_shuffle.default", + "pixel_unshuffle.default", + "while_loop.default", + "matmul.default", + "upsample_bilinear2d.vec", + "upsample_nearest2d.vec", +] +_ALL_EDGE_OPS = _SAMPLE_INPUT.keys() | _CUSTOM_EDGE_OPS + +_NON_ARM_PASSES = ["quantize_io_pass"] + +_MODEL_ENTRY_PATTERN = re.compile(r"^\s*(?:[-*]|\d+\.)\s+(?P.+?)\s*$") +_NUMERIC_SERIES_PATTERN = re.compile(r"(\d+)(?=[a-z])") +_CAMEL_BOUNDARY = re.compile( + r"(? set[str]: + names: set[str] = set() + names.update(_extract_pass_names_from_init(init_path)) + names.update(_NON_ARM_PASSES) + return {_separate_numeric_series(_strip_pass_suffix(name)) for name in names} + + +def _extract_pass_names_from_init(init_path: pathlib.Path) -> set[str]: + source = init_path.read_text(encoding="utf-8") + module = ast.parse(source, filename=str(init_path)) + names: set[str] = set() + + for node in module.body: + if not isinstance(node, ast.ImportFrom): + continue + for alias in node.names: + candidate = alias.asname or alias.name + if not candidate or not candidate.endswith("Pass"): + continue + if candidate == "ArmPass": + continue + names.add(_camel_to_snake(candidate)) + return names + + +def _strip_pass_suffix(name: str) -> str: + return name[:-5] if name.endswith("_pass") else name + + +def _separate_numeric_series(name: str) -> str: + def repl(match: re.Match[str]) -> str: + next_index = match.end() + next_char = match.string[next_index] if next_index < len(match.string) else "" + if next_char == "d": # Avoid creating patterns like 3_d + return match.group(1) + return f"{match.group(1)}_" + + return _NUMERIC_SERIES_PATTERN.sub(repl, name) + + +def _collect_arm_models(models_md: pathlib.Path) -> set[str]: + models: set[str] = set() + for line in models_md.read_text(encoding="utf-8").splitlines(): + stripped = line.strip() + if not stripped or stripped.startswith("#"): + continue + match = _MODEL_ENTRY_PATTERN.match(line) + if not match: + continue + base, alias, is_parent = _split_model_entry(match.group("entry")) + if is_parent: + continue + if alias: + models.add(_normalize_model_entry(alias)) + else: + models.add(_normalize_model_entry(base)) + + if not models: + raise RuntimeError(f"No supported models found in {models_md}") + return models + + +def _collect_arm_ops() -> set[str]: + """ + Returns a mapping from names on the form to be used in unittests to edge op: + 1. Names are in lowercase. + 2. Overload is ignored if 'default', otherwise it's appended with an underscore. + 3. Overly verbose name are shortened by removing certain prefixes/suffixes. + + Examples: + abs.default -> abs + split_copy.Tensor -> split_tensor + """ + ops: set[str] = set() + for edge_name in _ALL_EDGE_OPS: + op, overload = edge_name.split(".") + + # Normalize names + op = op.lower() + op = op.removeprefix("_") + op = op.removesuffix("_copy") + op = op.removesuffix("_with_indices") + overload = overload.lower() + + if overload == "default": + ops.add(op) + else: + ops.add(f"{op}_{overload}") + + return ops + + +def _split_model_entry(entry: str) -> tuple[str, str | None, bool]: + entry = entry.strip() + if not entry: + return "", None, False + is_parent = entry.endswith(":") + if is_parent: + entry = entry[:-1].rstrip() + if "(" in entry and entry.endswith(")"): + base, _, rest = entry.partition("(") + alias = rest[:-1].strip() + return base.strip(), alias or None, is_parent + return entry, None, is_parent + + +def _normalize_model_entry(name: str) -> str: + cleaned = name.lower() + cleaned = re.sub(r"[^a-z0-9\s]", "", cleaned) + cleaned = re.sub(r"\s+", " ", cleaned).strip() + return cleaned.replace(" ", "_") + + +def _camel_to_snake(name: str) -> str: + if not name: + return "" + name = name.replace("-", "_").replace(" ", "_") + return _CAMEL_BOUNDARY.sub("_", name).lower() + + +OP_LIST = sorted(_collect_arm_ops()) +PASS_LIST = sorted( + _collect_arm_passes(pathlib.Path("backends/arm/_passes/__init__.py")) +) +MODEL_LIST = sorted(_collect_arm_models(pathlib.Path("backends/arm/MODELS.md"))) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/corstone_utils.cmake b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/corstone_utils.cmake new file mode 100644 index 0000000..8253f39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/corstone_utils.cmake @@ -0,0 +1,463 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +function(fetch_ethos_u_content ETHOS_SDK_PATH ET_DIR_PATH) + message(STATUS "Fetching Ethos-U content into ${ETHOS_SDK_PATH}") + + file(MAKE_DIRECTORY ${ETHOS_SDK_PATH}/../ethos_u) + include(FetchContent) + set(ethos_u_base_tag "25.05") + FetchContent_Declare( + ethos_u + GIT_REPOSITORY + https://git.gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u.git + GIT_TAG ${ethos_u_base_tag} + SOURCE_DIR + ${ETHOS_SDK_PATH} + BINARY_DIR + ${ETHOS_SDK_PATH} + SUBBUILD_DIR + ${ETHOS_SDK_PATH}/../ethos_u-subbuild + SOURCE_SUBDIR + none + ) + FetchContent_MakeAvailable(ethos_u) + # Patch manifest to remove unused projects. + set(patch_dir "${ET_DIR_PATH}/examples/arm/ethos-u-setup") + set(ethos_u_base_rev "24950bd4381b6c51db0349a229f8ba86b8e1093f") + execute_process( + COMMAND + bash -c + "pwd && source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH} ${ethos_u_base_rev} ${patch_dir}" + WORKING_DIRECTORY ${ET_DIR_PATH} COMMAND_ECHO STDOUT + ) + # Get ethos_u externals only if core_platform folder does not already exist. + if(NOT EXISTS "${ETHOS_SDK_PATH}/core_platform") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} fetch_externals.py -c + ${ethos_u_base_tag}.json fetch + WORKING_DIRECTORY ${ETHOS_SDK_PATH} COMMAND_ECHO STDOUT + ) + endif() + # Patch core_software to remove unused projects. + set(core_software_base_rev "55904c3da73c876c6d6c58290938ae217a8b94bd") + execute_process( + COMMAND + bash -c + "pwd && source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH}/core_software ${core_software_base_rev} ${patch_dir}" + WORKING_DIRECTORY ${ET_DIR_PATH} COMMAND_ECHO STDOUT + ) + # Always patch the core_platform repo since this is fast enough. + set(core_platform_base_rev "1916a9c984819c35b19c9e5c4c80d47e4e866420") + execute_process( + COMMAND + bash -c + "pwd && source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH}/core_platform ${core_platform_base_rev} ${patch_dir}" + WORKING_DIRECTORY ${ET_DIR_PATH} COMMAND_ECHO STDOUT + ) +endfunction() + +function(add_corstone_subdirectory SYSTEM_CONFIG ETHOS_SDK_PATH) + if(SYSTEM_CONFIG MATCHES "Ethos_U55") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-300 target + ) + elseif(SYSTEM_CONFIG MATCHES "Ethos_U85") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-320 target + ) + else() + message(FATAL_ERROR "Unsupported SYSTEM_CONFIG ${SYSTEM_CONFIG}.") + endif() + if(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_target_common INTERFACE ETHOSU_MODEL=1 ETHOSU_ARENA=1 + ) + elseif(MEMORY_MODE MATCHES "Shared_Sram" OR MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common INTERFACE ETHOSU_MODEL=1 ETHOSU_ARENA=0 + ) + else() + message( + FATAL_ERROR + "Unsupported MEMORY_MODE ${MEMORY_MODE}. Memory_mode can be Shared_Sram, Sram_Only or Dedicated_Sram(applicable for the Ethos-U85)" + ) + endif() +endfunction() + +function(configure_timing_adapters SYSTEM_CONFIG MEMORY_MODE) + if(SYSTEM_CONFIG MATCHES "Ethos_U55_High_End_Embedded") + set(TARGET_BOARD + "corstone-300" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Shared_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Flash + ETHOSU_TA_MAXR_1=2 + ETHOSU_TA_MAXW_1=0 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=64 + ETHOSU_TA_WLATENCY_1=0 + ETHOSU_TA_PULSE_ON_1=320 + ETHOSU_TA_PULSE_OFF_1=80 + ETHOSU_TA_BWCAP_1=50 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # This is just example numbers and you should make this match + # your hardware SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=8 + ETHOSU_TA_MAXW_1=8 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=32 + ETHOSU_TA_WLATENCY_1=32 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + + else() + message( + FATAL_ERROR + "Unsupported memory_mode ${MEMORY_MODE} for the Ethos-U55. The Ethos-U55 supports only Shared_Sram and Sram_Only." + ) + endif() + elseif(SYSTEM_CONFIG MATCHES "Ethos_U55_Deep_Embedded") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-300 target + ) + set(TARGET_BOARD + "corstone-300" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Shared_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=4 + ETHOSU_TA_MAXW_0=4 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=8 + ETHOSU_TA_WLATENCY_0=8 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Flash + ETHOSU_TA_MAXR_1=2 + ETHOSU_TA_MAXW_1=0 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=32 + ETHOSU_TA_WLATENCY_1=0 + ETHOSU_TA_PULSE_ON_1=360 + ETHOSU_TA_PULSE_OFF_1=40 + ETHOSU_TA_BWCAP_1=25 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=4 + ETHOSU_TA_MAXW_0=4 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=8 + ETHOSU_TA_WLATENCY_0=8 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=4 + ETHOSU_TA_MAXW_1=4 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=8 + ETHOSU_TA_WLATENCY_1=8 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + else() + message( + FATAL_ERROR + "Unsupported memory_mode ${MEMORY_MODE} for the Ethos-U55. The Ethos-U55 supports only Shared_Sram and Sram_Only." + ) + endif() + elseif(SYSTEM_CONFIG MATCHES "Ethos_U85_SYS_DRAM_Low") + add_subdirectory( + ${ETHOS_SDK_PATH}/core_platform/targets/corstone-320 target + ) + set(TARGET_BOARD + "corstone-320" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=16 + ETHOSU_TA_WLATENCY_0=16 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # DRAM + ETHOSU_TA_MAXR_1=24 + ETHOSU_TA_MAXW_1=12 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=250 + ETHOSU_TA_WLATENCY_1=125 + ETHOSU_TA_PULSE_ON_1=4000 + ETHOSU_TA_PULSE_OFF_1=1000 + ETHOSU_TA_BWCAP_1=2344 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=16 + ETHOSU_TA_WLATENCY_0=16 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=8 + ETHOSU_TA_MAXW_1=8 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=16 + ETHOSU_TA_WLATENCY_1=16 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + endif() + elseif(SYSTEM_CONFIG STREQUAL "Ethos_U85_SYS_DRAM_Mid" + OR SYSTEM_CONFIG STREQUAL "Ethos_U85_SYS_DRAM_High" + ) + set(TARGET_BOARD + "corstone-320" + PARENT_SCOPE + ) + if(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # DRAM + ETHOSU_TA_MAXR_1=64 + ETHOSU_TA_MAXW_1=32 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=500 + ETHOSU_TA_WLATENCY_1=250 + ETHOSU_TA_PULSE_ON_1=4000 + ETHOSU_TA_PULSE_OFF_1=1000 + ETHOSU_TA_BWCAP_1=3750 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + elseif(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_target_common + INTERFACE # Configure NPU architecture timing adapters This is just + # example numbers and you should make this match your hardware + # SRAM + ETHOSU_TA_MAXR_0=8 + ETHOSU_TA_MAXW_0=8 + ETHOSU_TA_MAXRW_0=0 + ETHOSU_TA_RLATENCY_0=32 + ETHOSU_TA_WLATENCY_0=32 + ETHOSU_TA_PULSE_ON_0=3999 + ETHOSU_TA_PULSE_OFF_0=1 + ETHOSU_TA_BWCAP_0=4000 + ETHOSU_TA_PERFCTRL_0=0 + ETHOSU_TA_PERFCNT_0=0 + ETHOSU_TA_MODE_0=1 + ETHOSU_TA_HISTBIN_0=0 + ETHOSU_TA_HISTCNT_0=0 + # Set the second Timing Adapter to SRAM latency & bandwidth + ETHOSU_TA_MAXR_1=8 + ETHOSU_TA_MAXW_1=8 + ETHOSU_TA_MAXRW_1=0 + ETHOSU_TA_RLATENCY_1=32 + ETHOSU_TA_WLATENCY_1=32 + ETHOSU_TA_PULSE_ON_1=3999 + ETHOSU_TA_PULSE_OFF_1=1 + ETHOSU_TA_BWCAP_1=4000 + ETHOSU_TA_PERFCTRL_1=0 + ETHOSU_TA_PERFCNT_1=0 + ETHOSU_TA_MODE_1=1 + ETHOSU_TA_HISTBIN_1=0 + ETHOSU_TA_HISTCNT_1=0 + ) + endif() + else() + message(FATAL_ERROR "Unsupported SYSTEM_CONFIG: ${SYSTEM_CONFIG}") + endif() + + # The REGIONCFG registers of the Ethos-U control whether the NPU reads/writes + # data through the SRAM or the external memory. By default, the Ethos-U driver + # provides REGIONCFG configuration for Shared Sram memory mode. For Sram_Only + # and Dedicated_Sram memory modes, we need to change the settings for optimal + # performance. + # + # Currently, the convention used by Vela and the Ethos-U driver is that the + # NPU uses: Region 0 for traffic of the Read-Only data(weights & biases) + # Region 1 for traffic of of the intermediate Read/Write buffers required for + # the computation Region 2 for traffic of of the cache in Dedicated_Sram + # memory mode(not applicable in Sram_Only or Shared_Sram) + # + # NOTE: The above convention is determined by the Vela compiler and the + # Ethos-U driver and can change in the future. + # + # Common definitions: For Ethos-U55/U65/U85, region configs are set as: 0 or 1 + # = AXI0 (Ethos-U55 or Ethos-U65) or AXI_SRAM(Ethos-U85) 2 or 3 = AXI1 + # (Ethos-U55 or Ethos-U65) or AXI_EXT(Ethos-U85) + # + # When we compile a model for Sram_Only, the memory traffic for Region 0 and + # Region 1 should pass via the SRAM(hence regioncfg = 1) When we compile a + # model for Dedicated_Sram, the memory traffic for Region 0 should pass via + # the external memory(3), the memory traffic of Region 1 should pass via the + # external memory(3) and the traffic for Region 2 should pass via the SRAM(0) + # + + if(MEMORY_MODE MATCHES "Sram_Only") + target_compile_definitions( + ethosu_core_driver + PRIVATE NPU_QCONFIG=1 + NPU_REGIONCFG_0=1 + NPU_REGIONCFG_1=0 + NPU_REGIONCFG_2=0 + NPU_REGIONCFG_3=0 + NPU_REGIONCFG_4=0 + NPU_REGIONCFG_5=0 + NPU_REGIONCFG_6=0 + NPU_REGIONCFG_7=0 + ) + elseif(MEMORY_MODE MATCHES "Dedicated_Sram") + target_compile_definitions( + ethosu_core_driver + PRIVATE NPU_QCONFIG=3 + NPU_REGIONCFG_0=3 + NPU_REGIONCFG_1=3 + NPU_REGIONCFG_2=0 + NPU_REGIONCFG_3=0 + NPU_REGIONCFG_4=0 + NPU_REGIONCFG_5=0 + NPU_REGIONCFG_6=0 + NPU_REGIONCFG_7=0 + ) + endif() + +endfunction() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/fvp_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/fvp_utils.sh new file mode 100644 index 0000000..c320507 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/fvp_utils.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# The purpose of this file is to isolate all the functions to download +# and setup FVP. The reasons for behind this are multiple. +# The FVP needs a EULA acceptance and since the software download +# differs for arch and os it becomes quite messy to try and handle +# inside setup.sh. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source "${script_dir}/utils.sh" + +if [[ "${ARCH}" == "x86_64" ]]; then + # FVPs + corstone300_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.22_20_Linux64.tgz?rev=018659bd574f4e7b95fa647e7836ccf4&hash=22A79103C6FA5FFA7AFF3BE0447F3FF9" + corstone300_model_dir="Linux64_GCC-9.3" + corstone300_md5_checksum="98e93b949d0fbac977292d8668d34523" + + corstone320_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-320/FVP_Corstone_SSE-320_11.27_25_Linux64.tgz?rev=a507bffc219a4d5792f1192ab7002d89&hash=D9A824AA8227D2E679C9B9787FF4E8B6FBE3D7C6" + corstone320_model_dir="Linux64_GCC-9.3" + corstone320_md5_checksum="3deb3c68f9b2d145833f15374203514d" +elif [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]]; then + # FVPs + corstone300_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.22_20_Linux64_armv8l.tgz?rev=9cc6e9a32bb947ca9b21fa162144cb01&hash=7657A4CF27D42E892E3F08D452AAB073" + corstone300_model_dir="Linux64_armv8l_GCC-9.3" + corstone300_md5_checksum="cbbabbe39b07939cff7a3738e1492ef1" + + corstone320_url="https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-320/FVP_Corstone_SSE-320_11.27_25_Linux64_armv8l.tgz?rev=b6ebe0923cb84f739e017385fd3c333c&hash=8965C4B98E2FF7F792A099B08831FE3CB6120493" + corstone320_model_dir="Linux64_armv8l_GCC-9.3" + corstone320_md5_checksum="3889f1d80a6d9861ea4aa6f1c88dd0ae" +else + log_step "fvp" "Error: only x86-64 & aarch64/arm64 architecture is supported for now!" + exit 1 +fi + +function install_fvp() { + # Download and install the Corstone 300 FVP simulator platform + fvps=("corstone300" "corstone320") + + for fvp in "${fvps[@]}"; do + cd "${root_dir}" + if [[ ! -e "FVP_${fvp}.tgz" ]]; then + log_step "fvp" "Downloading FVP ${fvp}" + url_variable=${fvp}_url + fvp_url=${!url_variable} + curl --output "FVP_${fvp}.tgz" "${fvp_url}" + md5_variable=${fvp}_md5_checksum + fvp_md5_checksum=${!md5_variable} + verify_md5 ${fvp_md5_checksum} FVP_${fvp}.tgz || exit 1 + fi + + log_step "fvp" "Installing FVP ${fvp}" + rm -rf FVP-${fvp} + mkdir -p FVP-${fvp} + cd FVP-${fvp} + tar xf ../FVP_${fvp}.tgz + + # Install the FVP + case ${fvp} in + corstone300) + ./FVP_Corstone_SSE-300.sh --i-agree-to-the-contained-eula --force --destination ./ --quiet --no-interactive + ;; + corstone320) + ./FVP_Corstone_SSE-320.sh --i-agree-to-the-contained-eula --force --destination ./ --quiet --no-interactive + ;; + *) + log_step "fvp" "Error: Unknown FVP model ${fvp}. Exiting." + exit 1 + ;; + esac + done +} + +function check_fvp_eula () { + # Mandatory user arg --i-agree-to-the-contained-eula + eula_acceptance_by_variable="${ARM_FVP_INSTALL_I_AGREE_TO_THE_CONTAINED_EULA:-False}" + + if [[ "${eula_acceptance}" -eq 0 ]]; then + if [[ ${eula_acceptance_by_variable} != "True" ]]; then + log_step "fvp" "Must pass '--i-agree-to-the-contained-eula' to download the FVP" + log_step "fvp" "Alternatively set ARM_FVP_INSTALL_I_AGREE_TO_THE_CONTAINED_EULA=True" + log_step "fvp" "Exiting due to missing EULA acceptance" + exit 1 + else + log_step "fvp" "Arm EULA accepted via ARM_FVP_INSTALL_I_AGREE_TO_THE_CONTAINED_EULA=True" + fi + fi +} + +function setup_fvp() { + if [[ "${OS}" != "Linux" ]]; then + # Check if FVP is callable + if command -v FVP_Corstone_SSE-300_Ethos-U55 &> /dev/null; then + log_step "fvp" "Detected pre-installed MacOS FVP binaries; continuing" + return 0 # If true exit gracefully and proceed with setup + else + log_step "fvp" "Warning: FVP setup only supported on Linux; Mac users should install via https://github.com/Arm-Examples/FVPs-on-Mac and ensure binaries are on PATH" + return 1 # Throw error. User need to install FVP according to ^^^ + fi + fi +} + +function setup_path_fvp() { + fvps=("corstone300" "corstone320") + for fvp in "${fvps[@]}"; do + model_dir_variable=${fvp}_model_dir + fvp_model_dir=${!model_dir_variable} + fvp_bin_path="${root_dir}/FVP-${fvp}/models/${fvp_model_dir}" + append_env_in_setup_path PATH ${fvp_bin_path} + done + + # Fixup for Corstone-320 python dependency + append_env_in_setup_path LD_LIBRARY_PATH "${root_dir}/FVP-corstone320/python/lib/" + + echo "hash FVP_Corstone_SSE-300_Ethos-U55" >> ${setup_path_script}.sh + echo "hash FVP_Corstone_SSE-300_Ethos-U65" >> ${setup_path_script}.sh + echo "hash FVP_Corstone_SSE-320" >> ${setup_path_script}.sh +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/install_models_for_test.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/install_models_for_test.sh new file mode 100644 index 0000000..d6a7b9c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/install_models_for_test.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -e +pip install -r backends/arm/requirements-arm-models-test.txt + +# Install model gym repository +git clone https://github.com/arm/neural-graphics-model-gym.git +cd neural-graphics-model-gym +# Remove model-converter installation from model-gym repository (to prevent overwriting executorch version) +if [[ "$(uname)" == "Darwin" ]]; then + sed -i '' 's/^model-converter = "ng_model_gym.bin.model_converter_launcher:main"/#&/' pyproject.toml +else + sed -i 's/^model-converter = "ng_model_gym.bin.model_converter_launcher:main"/#&/' pyproject.toml +fi +pip install . --no-deps +cd .. +rm -rf neural-graphics-model-gym \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/mlsdk_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/mlsdk_utils.sh new file mode 100755 index 0000000..87fc206 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/mlsdk_utils.sh @@ -0,0 +1,258 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -euo pipefail + +# URL and tag of the MLSDK manifest repository. Can be overridden by environment variables. +# eg. export MLSDK_MANIFEST_URL=...; export MLSDK_MANIFEST_TAG=... +mlsdk_manifest_url="${MLSDK_MANIFEST_URL:-https://github.com/arm/ai-ml-sdk-manifest.git}" +mlsdk_manifest_tag="${MLSDK_MANIFEST_TAG:-refs/tags/v2025.12.0}" + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) + +source ${script_dir}/utils.sh + +function mlsdk_sync_manifest() { + local manifest_dir="$1" + + mkdir -p "${manifest_dir}" + pushd "${manifest_dir}" || return 1 + local parallel_jobs="$(get_parallel_jobs)" + + if [[ ! -f repo ]]; then + log_step "mlsdk" "Fetching repo tool" + curl https://storage.googleapis.com/git-repo-downloads/repo > repo + chmod u+x repo + fi + + ./repo init \ + --depth=1 \ + --no-repo-verify \ + --manifest-url "${mlsdk_manifest_url}" \ + --manifest-branch "${mlsdk_manifest_tag}" \ + -g model-converter,emulation-layer,vgf-library + + local default_manifest=".repo/manifests/default.xml" + + ./repo sync --force-sync -j"${parallel_jobs}" + + popd +} + +function download_ai_mlsdk_manifest() { + local _manifest_dir="$1" + + if [[ -z "${_manifest_dir}" ]]; then + log_step "mlsdk" "Error: _manifest_dir parameter missing" + return 1 + fi + + if [[ -z "${mlsdk_manifest_url}" ]]; then + log_step "mlsdk" "Error: mlsdk_manifest_url parameter missing" + return 1 + fi + + if [[ ! -d "${_manifest_dir}/sw" ]] || [[ ! -d "${_manifest_dir}/dependencies" ]]; then + log_step "mlsdk" "MLSDK checkout not found at ${_manifest_dir}; performing initial download" + mlsdk_sync_manifest "${_manifest_dir}" + return 0 + fi + + # If a checkout exists, get the URL and tag of the existing checkout. + local cached_url="" + local cached_tag="" + local repo_config="${_manifest_dir}/.repo/manifests.git/config" + if [[ -f "${repo_config}" ]]; then + cached_url="$(git config --file "${repo_config}" remote.origin.url 2>/dev/null || echo "")" + cached_tag="$(git config --file "${repo_config}" branch.default.merge 2>/dev/null || echo "")" + fi + + # If the tag is main or refs/heads/main, always refresh the checkout. + # This allows users to track the latest main branch without needing to manually + # delete the checkout. + local tag_tracks_main=0 + if [[ "${mlsdk_manifest_tag}" == "main" ]] || [[ "${mlsdk_manifest_tag}" == "refs/heads/main" ]]; then + tag_tracks_main=1 + fi + + # If the URL and tag match, and the tag does not track main, reuse the existing checkout. + # Skip fetching updates. + if [[ "${cached_url}" == "${mlsdk_manifest_url}" ]] && [[ "${cached_tag}" == "${mlsdk_manifest_tag}" ]] && [[ "${tag_tracks_main}" -eq 0 ]]; then + log_step "mlsdk" "Reusing cached MLSDK dependencies at ${_manifest_dir}" + return 0 + fi + + # If we reach here, either the URL or tag changed, or the tag tracks main. + # In all cases, refresh the checkout. + if [[ "${tag_tracks_main}" -eq 1 ]]; then + log_step "mlsdk" "Manifest tracks branch ${mlsdk_manifest_tag}; refreshing checkout" + else + log_step "mlsdk" "Manifest changed (url=${cached_url:-} -> ${mlsdk_manifest_url}, tag=${cached_tag:-} -> ${mlsdk_manifest_tag}); refreshing checkout" + fi + + # Clean up any local manifest changes to avoid repo sync errors. + # Since we patched in a local manifest for tosa_gitlab.xml, + # remove any existing local manifests to avoid conflicts. + # TODO: we should remove this at some point in the future, but its not hurting anything for now. + if [[ -d "${_manifest_dir}/.repo/local_manifests" ]]; then + rm -rf "${_manifest_dir}/.repo/local_manifests/" + fi + + # Clean up any local changes in the manifests repository. + if [[ -d "${_manifest_dir}/.repo/manifests.git" ]]; then + git -C "${_manifest_dir}/.repo/manifests.git" reset --hard HEAD >/dev/null 2>&1 || true + git -C "${_manifest_dir}/.repo/manifests.git" clean -fd >/dev/null 2>&1 || true + fi + + # Clean up any local changes in the manifests working copy. + if [[ -d "${_manifest_dir}/.repo/manifests" ]]; then + git -C "${_manifest_dir}/.repo/manifests" reset --hard HEAD >/dev/null 2>&1 || true + git -C "${_manifest_dir}/.repo/manifests" clean -fd >/dev/null 2>&1 || true + fi + + # Going from v2025.10.0 to v2025.12.0 seems particular hard so just keep it simple. + # TODO: Remove once this is history + if [[ "${cached_tag}" == "refs/tags/v2025.10.0" ]] && [[ "${mlsdk_manifest_tag}" == "refs/tags/v2025.12.0" ]]; then + pushd "${_manifest_dir}/.." + log_step "mlsdk" "Deleting ${mlsdk_manifest_dir} and starting fresh" + manifest_base_dir=$(basename "${_manifest_dir}") + rm -fr $manifest_base_dir + popd + fi + + mlsdk_sync_manifest "${_manifest_dir}" +} + +function setup_mlsdk() { + local work_dir="$1" + local manifest_dir="$2" + local enable_model_converter="$3" + local enable_vgf_lib="$4" + local enable_emulation_layer="$5" + + if [[ -z "$work_dir" ]]; then + log_step "mlsdk" "Error: work_dir parameter is required" + return 1 + fi + + if [[ -z "$manifest_dir" ]]; then + log_step "mlsdk" "Error: manifest_dir parameter is required" + return 1 + fi + + mkdir -p "$work_dir" + pushd "$work_dir" || exit 1 + + log_step "mlsdk" "Syncing MLSDK manifest into ${manifest_dir}" + download_ai_mlsdk_manifest "${manifest_dir}" + + pushd "$manifest_dir" + local parallel_jobs="$(get_parallel_jobs)" + + # model-converter + if [[ "${enable_model_converter}" -eq 1 ]]; then + log_step "mlsdk" "Building MLSDK model-converter" + python sw/model-converter/scripts/build.py -j"${parallel_jobs}" + log_step "mlsdk" "MLSDK model-converter build complete" + fi + + # libvgf + if [[ "${enable_vgf_lib}" -eq 1 ]]; then + log_step "mlsdk" "Building MLSDK VGF library" + pushd sw/vgf-lib + python scripts/build.py -j"${parallel_jobs}" + cmake --install build --prefix deploy + log_step "mlsdk" "MLSDK VGF library build complete" + popd + fi + + # emu layer + if [[ "${enable_emulation_layer}" -eq 1 ]]; then + log_step "mlsdk" "Building MLSDK Vulkan emulation layer" + pushd sw/emulation-layer + cmake -B build \ + -DGLSLANG_PATH=../../dependencies/glslang \ + -DSPIRV_CROSS_PATH=../../dependencies/SPIRV-Cross \ + -DSPIRV_HEADERS_PATH=../../dependencies/SPIRV-Headers \ + -DSPIRV_TOOLS_PATH=../../dependencies/SPIRV-Tools \ + -DVULKAN_HEADERS_PATH=../../dependencies/Vulkan-Headers + + cmake --build build -j"${parallel_jobs}" + cmake --install build --prefix deploy + log_step "mlsdk" "MLSDK Vulkan emulation layer build complete" + popd + fi + + popd +} + +function setup_path_model_converter() { + cd "${root_dir}" + model_converter_bin_path="$(cd "${mlsdk_manifest_dir}/sw/model-converter/build" && pwd)" + append_env_in_setup_path PATH "${model_converter_bin_path}" +} + +function setup_path_vgf_lib() { + cd "${root_dir}" + model_vgf_path="$(cd "${mlsdk_manifest_dir}/sw/vgf-lib/deploy" && pwd)" + append_env_in_setup_path PATH "${model_vgf_path}/bin" + append_env_in_setup_path LD_LIBRARY_PATH "${model_vgf_path}/lib" + append_env_in_setup_path DYLD_LIBRARY_PATH "${model_vgf_path}/lib" +} + +function setup_path_emulation_layer() { + cd "${root_dir}" + model_emulation_layer_path="$(cd "${mlsdk_manifest_dir}/sw/emulation-layer/" && pwd)" + prepend_env_in_setup_path LD_LIBRARY_PATH "${model_emulation_layer_path}/deploy/lib" + prepend_env_in_setup_path DYLD_LIBRARY_PATH "${model_emulation_layer_path}/deploy/lib" + prepend_env_in_setup_path VK_LAYER_PATH "${model_emulation_layer_path}/deploy/share/vulkan/explicit_layer.d" + prepend_env_in_setup_path VK_INSTANCE_LAYERS VK_LAYER_ML_Tensor_Emulation + prepend_env_in_setup_path VK_INSTANCE_LAYERS VK_LAYER_ML_Graph_Emulation +} + +function setup_path_emulation_layer_from_pip() { + if ! command -v emulation_layer >/dev/null 2>&1; then + echo "[mlsdk_utils] 'emulation_layer' command not found; skipping pip emulation layer path setup" + return + fi + + local output + if ! output=$(emulation_layer 2>/dev/null); then + echo "[mlsdk_utils] Failed to query emulation_layer environment; skipping" + return + fi + + local exports + exports=$(echo "$output" | grep '^export ' || true) + + local ld_line + ld_line=$(echo "$exports" | grep 'LD_LIBRARY_PATH=' || true) + if [[ -n "${ld_line}" ]]; then + local ld_value=${ld_line#export LD_LIBRARY_PATH=} + ld_value=${ld_value%%:\$LD_LIBRARY_PATH*} + if [[ -n "${ld_value}" ]]; then + prepend_env_in_setup_path LD_LIBRARY_PATH "${ld_value}" + fi + fi + + local vk_add_line + vk_add_line=$(echo "$exports" | grep 'VK_ADD_LAYER_PATH=' || true) + if [[ -n "${vk_add_line}" ]]; then + local vk_add_value=${vk_add_line#export VK_ADD_LAYER_PATH=} + if [[ -n "${vk_add_value}" ]]; then + prepend_env_in_setup_path VK_ADD_LAYER_PATH "${vk_add_value}" + fi + fi + + local vk_instance_line + vk_instance_line=$(echo "$exports" | grep 'VK_INSTANCE_LAYERS=' || true) + if [[ -n "${vk_instance_line}" ]]; then + local vk_instance_value=${vk_instance_line#export VK_INSTANCE_LAYERS=} + if [[ -n "${vk_instance_value}" ]]; then + prepend_env_in_setup_path VK_INSTANCE_LAYERS "${vk_instance_value}" + fi + fi +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/parse_test_names.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/parse_test_names.py new file mode 100644 index 0000000..beb8f73 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/parse_test_names.py @@ -0,0 +1,271 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from __future__ import annotations + +import ast +import os + +import pathlib +import re + +import sys + +from executorch.backends.arm.scripts.collect_testname_resources import ( + MODEL_LIST, + OP_LIST, + PASS_LIST, + TARGETS, +) + + +ALLOWED_DIRNAMES = ("misc", "passes", "models", "quantizer", "ops") + +SUFFIX_GROUP = r"(?:" + r"|".join(TARGETS) + r")" +DEFAULT_PATTERN = re.compile( + rf"^test_.*_(?P{SUFFIX_GROUP})(?:_.*)?$", +) +TARGET_EXTRACT_PATTERN = re.compile(rf"(?P{SUFFIX_GROUP})(?:_.*)?$") +TARGET_CHOICES_DISPLAY = ", ".join(TARGETS) + + +class TestCollector(ast.NodeVisitor): + def __init__(self, path: pathlib.Path, collected: list[str]): + self.path = path + self._collected = collected + self._class_stack: list[str] = [] + + def visit_ClassDef(self, node: ast.ClassDef): + self._class_stack.append(node.name) + self.generic_visit(node) + self._class_stack.pop() + + def visit_FunctionDef(self, node: ast.FunctionDef): + self._record_test(node) + self.generic_visit(node) + + def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef): + self._record_test(node) + self.generic_visit(node) + + def _record_test(self, node: ast.AST): + name = getattr(node, "name", "") + if name.startswith("test_"): + self._collected.append(str(self.path) + "::" + name) + + +def collect_test_files(test_root: pathlib.Path): + search_dirs = [] + for dirname in ALLOWED_DIRNAMES: + dir_path = test_root / dirname + if dir_path.is_dir(): + search_dirs.append(dir_path) + else: + print(f"warning: skipped missing directory {dir_path}", file=sys.stderr) + + file_paths: list[pathlib.Path] = [] + for dir_path in search_dirs: + file_paths.extend(dir_path.rglob("test_*.py")) + return sorted(file_paths) + + +def collect_tests(file_paths: list[pathlib.Path]) -> list[str]: + tests: list[str] = [] + for file_path in file_paths: + try: + source = file_path.read_text(encoding="utf-8") + except OSError as error: + print(f"warning: failed to read {file_path}: {error}", file=sys.stderr) + continue + + try: + tree = ast.parse(source, filename=str(file_path)) + except SyntaxError as error: + print(f"warning: failed to parse {file_path}: {error}", file=sys.stderr) + continue + + TestCollector(file_path, tests).visit(tree) + + return tests + + +def _match_allowed_op_prefix(test_name: str) -> tuple[str, str, bool]: + """ + Parses a test name on the form + test_OP_TARGET__ + where OP must match a key in op_name_map and TARGET one string in TARGETS. The + "not_delegated" suffix indicates that the test tests that the op is not delegated. + + Examples of valid names: "test_mm_u55_INT_not_delegated" and + "test_add_scalar_tosa_FP_two_inputs". + + Returns a tuple (OP, TARGET, IS_DELEGATED) if valid. + """ + test_name = test_name.removeprefix("test_") + is_delegated = "not_delegated" not in test_name + + op = "None" + target = "None" + for potential_target in TARGETS: + index = test_name.find(potential_target) + if index != -1: + op = test_name[: index - 1] + target = potential_target + break + # Special case for convolution + op = op.removesuffix("_1d") + op = op.removesuffix("_2d") + op = op.removesuffix("_3d") + + # Remove suffix for 16 bit activation and 8 bit weight test cases + op = op.removesuffix("_16a8w") + + return op, target, is_delegated + + +def _match_allowed_model_prefix(token: str, allowed_models: list[str]) -> str | None: + for allowed_model in allowed_models: + if token == allowed_model: + return allowed_model + return None + + +def _match_allowed_pass_prefix(token: str, allowed_passes: list[str]) -> str | None: + for allowed_pass in allowed_passes: + if token == allowed_pass: + return allowed_pass + return None + + +def _extract_target(name: str) -> str | None: + match = TARGET_EXTRACT_PATTERN.search(name) + if match and match.end() == len(name): + return match.group("target") + return None + + +def _parse_name_tokens(name: str) -> tuple[str, str]: + rest = name[5:] + target = _extract_target(name) + token = rest.rstrip("_") + if target: + idx = rest.rfind(target) + token = rest[:idx].rstrip("_") + return token, target # type: ignore[return-value] + + +def _describe_name_issue(kind: str, name: str) -> str: + token, target = _parse_name_tokens(name) + details: list[str] = [] + if token: + details.append(f"{kind} token parsed as '{token}'\n ") + else: + details.append(f"missing {kind} token before target\n ") + + if target: + details.append(f"target token parsed as '{target}'") + else: + details.append( + f"missing target suffix (expected one of: {TARGET_CHOICES_DISPLAY}" + ) + + details.append( + "\n please follow the test naming convention: https://confluence.arm.com/display/MLENG/Executorch+naming+conventions" + ) + + return "".join(details) + + +def check_test_convention( # noqa: C901 + tests: list[str], + allowed_ops: list[str], + allowed_models: list[str], + allowed_passes: list[str], +) -> list[str]: + violations: list[str] = [] + for test in tests: + path = test.split("::")[0] + name = test.split("::")[1] + try: + assert name[:5] == "test_", f"Unexpected input: {name}" + if str(os.sep) + "ops" + str(os.sep) in path: + matched_op, target, delegated = _match_allowed_op_prefix(name) + if "reject" in name: + desc = _describe_name_issue("op", name) + violations.append( + f"{test}\n expected test_OP_TARGET_*\n Use 'not_delegated' instead of 'reject' in {name}\n" + ) + if target == "None" or matched_op not in allowed_ops: + desc = _describe_name_issue("op", name) + violations.append( + f"{test}\n expected test_OP_TARGET_*\n {desc}\n" + ) + continue + if str(os.sep) + "models" + str(os.sep) in path: + token, target = _parse_name_tokens(name) + if not target or not token: + desc = _describe_name_issue("model", name) + violations.append( + f"{test}\n expected test_MODEL_TARGET_*\n {desc}\n" + ) + continue + matched_model = _match_allowed_model_prefix(token, allowed_models) + if matched_model is None: + desc = _describe_name_issue("model", name) + violations.append( + f"{test}\n unknown model prefix '{token}'\n expected test_MODEL_TARGET_* with MODEL in MODEL_LIST\n {desc}\n" + ) + continue + continue + if str(os.sep) + "passes" + str(os.sep) in path: + token, target = _parse_name_tokens(name) + if not target or not token: + desc = _describe_name_issue("pass", name) + violations.append( + f"{test}\n expected test_PASS_TARGET_*\n {desc}\n" + ) + continue + matched_pass = _match_allowed_pass_prefix(token, allowed_passes) + if matched_pass is None: + desc = _describe_name_issue("pass", name) + violations.append( + f"{test}\n unknown pass prefix '{token}'\n expected test_PASS_TARGET_* with PASS in PASS_LIST\n {desc}\n" + ) + continue + continue + if ( + str(os.sep) + "quantizer" + str(os.sep) in path + or str(os.sep) + "misc" + str(os.sep) in path + ): + token, target = _parse_name_tokens(name) + if not target or not token: + desc = _describe_name_issue("name", name) + violations.append( + f"{test}\n expected test_*_TARGET_*\n {desc}\n" + ) + continue + continue + except AssertionError as e: + print(e) + return violations + + +if __name__ == "__main__": + """Parses a list of test names given on the commandline.""" + + sys.tracebacklimit = 0 # Do not print stack trace + tests: list[str] = [] + path_list: list[pathlib.Path] = [pathlib.Path(path) for path in sys.argv[1:]] + + if path_list == []: + tests = collect_tests(collect_test_files(pathlib.Path("backends/arm/test"))) + else: + tests = collect_tests(path_list) + + violations = check_test_convention(tests, OP_LIST, MODEL_LIST, PASS_LIST) + + for entry in violations: + print(entry) + + print(f"Total tests needing renaming: {len(violations)}") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-commit b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-commit new file mode 100755 index 0000000..2000585 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-commit @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Check 1: If commit header contains WIP, everything is ok +git rev-list --format=%s --max-count=1 HEAD | grep -q WIP && exit 0 + +# Check 2: lintunner on latest patch. +lintrunner -a --revision 'HEAD^' --skip MYPY +commit_files=$(git diff-tree --no-commit-id --name-only --diff-filter=M HEAD -r) +git add $commit_files || true \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-push b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-push new file mode 100755 index 0000000..ce96a92 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/pre-push @@ -0,0 +1,215 @@ +#!/bin/bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Calling this script with one argument is equal to launching it in +# non-interactive mode. "$#" gives the number of positional arguments. +[ "$#" -eq 1 ] && is_script_interactive=1 || is_script_interactive=0 + +if [ $is_script_interactive -eq 1 ]; then + RESET='\e[0m' + RED='\e[31m' + GREEN='\e[32m' + YELLOW='\e[33m' + BLUE='\e[34m' +fi + +INFO="${BLUE}[INFO]${RESET}" +WARNING="${YELLOW}[WARNING]${RESET}" +ERROR="${RED}[ERROR]${RESET}" +SUCCESS="${GREEN}[SUCCESS]${RESET}" + +# This list of imperative verbs was compiled from the entire list of Executorch +# commits. It should be fairly exhaustive, but add more verbs if you find one +# that's missing. +VERBS="Add|Fix|Update|Refactor|Improve|Remove|Change|Implement|Create|Modify|"\ +"Enable|Integrate|Make|Support|Deprecate|Extend|Enhance|Convert|Rewrite|Unify|"\ +"Optimize|Expand|Reorganize|Adjust|Streamline|Clarify|Introduce|Document|"\ +"Polish|Standardize|Revise|Simplify|Restore|Resolve|Replace|Suppress|Migrate|"\ +"Generate|Delete|Exclude|Register|Include|Upgrade|Validate|Verify|Refine|"\ +"Reimplement|Patch|Sync|Revert|Fixup|Enhance|Append|Annotate|Disable|Emit|"\ +"Handle|Ignore|Interpret|Instantiate|Invoke|Limit|Load|Modify|Permit|Print|"\ +"Profile|Recalculate|Reconstruct|Redefine|Redesign|Reevaluate|Relocate|Remap|"\ +"Render|Reposition|Request|Revert|Sanitize|Specify|Strengthen|Stub|Substitute|"\ +"Tag|Tweak|Unify|Unlock|Unset|Use|Validate|Verify|Rename|Relax" + +# Remote branch +REMOTE=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null) +if [ $is_script_interactive -eq 0 ]; then + # Just use the one commit + COMMITS=$(git rev-list HEAD -n 1) +elif [ -z "$REMOTE" ]; then + echo -e "${WARNING} Could not find upstream branch to compare to." + echo "Please specify the number of commits you are pushing." + echo -n "Enter number of commits to check (default 1): " > /dev/tty + read NUM_COMMITS < /dev/tty + NUM_COMMITS=${NUM_COMMITS:-1} # Default to 1 if empty + RANGE=$(git rev-list HEAD -n "$NUM_COMMITS") + COMMITS=${RANGE} +elif [ "$(git rev-parse --abbrev-ref HEAD)" == "HEAD" ]; then + echo -e "${WARNING} You're in a detached HEAD state." + echo "Please specify the number of commits you are pushing." + echo -n "Enter number of commits to check (default 1): " > /dev/tty + read NUM_COMMITS < /dev/tty + NUM_COMMITS=${NUM_COMMITS:-1} # Default to 1 if empty + RANGE=$(git rev-list HEAD -n "$NUM_COMMITS") + COMMITS=${RANGE} +else + # Determine commits to check + RANGE="$REMOTE..HEAD" + COMMITS=$(git rev-list "$RANGE") +fi + +if [ -z "$COMMITS" ]; then + echo -e "${INFO} No new commits to check." + exit 0 +fi + +for COMMIT in ${COMMITS}; do + if [ -n "$REMOTE" ] && git merge-base --is-ancestor "$COMMIT" "$REMOTE"; then + echo -e "${INFO} Skipping commit ${COMMIT} (already on $REMOTE)" + continue + fi + + # If commit header contains WIP, everything is ok + git rev-list --format=%s --max-count=1 ${COMMIT} | grep -q WIP && \ + continue + + echo -e "${INFO} Checking commit ${COMMIT}" + + # lintrunner on latest patches. + echo -e "${INFO} Lintrunner" + MYPYPATH=./src/ lintrunner --revision ${COMMIT}^1 + if [[ $? != 0 ]]; then + echo -e "${ERROR} Failed linting" + FAILED=1 + else + echo -e "${SUCCESS} Lintrunner OK" + fi + + # Check license headers + # We do a simple check of if all committed headers contain + # "$current_year Arm". This does not guarantee OK in ci but should be ok + # most of the time. + echo -e "${INFO} License check" + + current_year=$(date +%Y) + failed_license_check=false + commit_files=$(git diff-tree --no-commit-id --name-only \ + --diff-filter=ACMR ${COMMIT} -r) + for commited_file in $commit_files; do + file_header=$(head "$commited_file") + if ! echo "$file_header" | grep -qi "Arm"; then + echo -e "${WARNING} No Arm copyright header in ${commited_file}"\ + " (skipping license year check)" + continue + fi + + if ! echo "$file_header" | grep -q "$current_year Arm"; then + echo -e "${ERROR} Header in $commited_file did not contain"\ + "'$current_year Arm'" + failed_license_check=true + else + echo -e "${SUCCESS} $commited_file passed license check" + fi + done + + if [[ $failed_license_check == true ]]; then + FAILED=1 + else + echo -e "${SUCCESS} All files passed license check" + fi + + # Check commit message + echo -e "${INFO} Checking commit message" + COMMIT_MSG=$(git log -1 --format=%B "$COMMIT") + + SUBJECT=$(echo "$COMMIT_MSG" | head -n1) + BODY=$(echo "$COMMIT_MSG" | tail -n +2) + + # Check subject length (72 chars) + SUBJECT_MAX_LEN=72 + if [ ${#SUBJECT} -gt ${SUBJECT_MAX_LEN} ]; then + echo -e "${ERROR} Subject exceeds ${SUBJECT_MAX_LEN} characters:"\ + "'${SUBJECT}'" >&2 + + FAILED=1 + else + echo -e "${SUCCESS} Commit message subject OK" + fi + + # Check body line length (72 chars) + BODY_MAX_LEN=72 + line_number=2 # Subject + 1 empty line + failed_body_check=false + while IFS= read -r line; do + if [ ${#line} -gt ${BODY_MAX_LEN} ]; then + echo -e "${ERROR} Line ${line_number} in body exceeds"\ + "${BODY_MAX_LEN} characters: '$line'" >&2 + + failed_body_check=true + fi + + ((line_number++)) + done <<< "$BODY" + + if [[ $failed_body_check == true ]]; then + FAILED=1 + else + echo -e "${SUCCESS} Commit message body OK" + fi + + # Check for Signed-off-by + if ! echo "$COMMIT_MSG" | grep -qE "^Signed-off-by: "; then + echo -e "${ERROR} Commit message must contain a 'Signed-off-by'"\ + "footer." >&2 + + FAILED=1 + fi + + # Check subject format, should start with 'Arm backend: ' and be + # imperative mood. + if [[ ! "$SUBJECT" =~ ^"Arm backend":\ (${VERBS}) ]]; then + echo -e "${WARNING} Subject should start with 'Arm backend: '"\ + "followed by an imperative verb." >&2 + + if [ $is_script_interactive -eq 1 ]; then + echo -n "There are warnings in your commit message. Do you want to"\ + "ignore the warning (y/N): " > /dev/tty + + read USER_INPUT < /dev/tty + + # Check user input for warnings + if [[ ! "$USER_INPUT" =~ ^[Yy]$ ]]; then + FAILED=1 + fi + fi + fi + + # Test name checks + test_files=$(echo $commit_files | grep -oE 'backends/arm/test/\S+') + if [ "$test_files" ]; then + + # Check that the test name follows the specified convention + python ./backends/arm/scripts/parse_test_names.py $test_files + if [ $? -ne 0 ]; then + echo -e "${ERROR} Failed op test name check." >&2 + FAILED=1 + fi + fi + + echo "" # Newline to visually separate commit processing +done + +if [[ $FAILED ]]; then + echo -e "${INFO} Fix your commit message errors with"\ + "'git commit --amend' or 'git commit --fixup='" + + exit 1 +else + echo -e "${SUCCESS} All checks passed" +fi + +exit 0 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_fvp.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_fvp.sh new file mode 100755 index 0000000..7dcebb2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_fvp.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Optional parameter: +# --build_type= "Release" | "Debug" | "RelWithDebInfo" +# --etdump build with devtools-etdump support + +set -eu + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + + +elf_file="" +data_file="" +target="ethos-u55-128" +timeout="600" +etrecord_file="" +trace_file="" + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --elf= elf file to run" + echo " --data=@
Place a file in memory at this address, useful to emulate a PTE flashed into memory instead as part of the code." + echo " --target= Target to build and run for Default: ${target}" + echo " --timeout= Maximum target runtime, used to detect hanging, might need to be higer on large models Default: ${timeout}" + echo " --etrecord= If ETDump is used you can supply a ETRecord file matching the PTE" + echo " --trace_file= File to write PMU trace output to" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --elf=*) elf_file="${arg#*=}";; + --data=*) data_file="--data ${arg#*=}";; + --target=*) target="${arg#*=}";; + --timeout=*) timeout="${arg#*=}";; + --etrecord=*) etrecord_file="${arg#*=}";; + --trace_file=*) trace_file="${arg#*=}";; + *) + ;; + esac +done + +elf_file=$(realpath ${elf_file}) + +if [[ ${target} == *"ethos-u55"* ]]; then + fvp_model=FVP_Corstone_SSE-300_Ethos-U55 +else + fvp_model=FVP_Corstone_SSE-320 +fi + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +# basic checks before we get started +hash ${fvp_model} \ + || { echo "Could not find ${fvp_model} on PATH, ${_setup_msg}"; exit 1; } + + +[[ ! -f $elf_file ]] && { echo "[${BASH_SOURCE[0]}]: Unable to find executor_runner elf: ${elf_file}"; exit 1; } +num_macs=$(echo ${target} | cut -d - -f 3) + +echo "--------------------------------------------------------------------------------" +echo "Running ${elf_file} for ${target} run with FVP:${fvp_model} num_macs:${num_macs} timeout:${timeout}" +echo "WARNING: Corstone FVP is not cycle accurate and should NOT be used to determine valid runtime" +echo "--------------------------------------------------------------------------------" + +# Check if stdbuf is intalled and use stdbuf -oL together with tee below to make the output +# go all the way to the console more directly and not be buffered + +if hash stdbuf 2>/dev/null; then + nobuf="stdbuf -oL" +else + nobuf="" +fi + +log_file=$(mktemp) + +extra_args_u55=() +extra_args_u85=() + +if [[ -n "${trace_file}" ]]; then + extra_args_u55+=(-C "ethosu.extra_args=--pmu-trace ${trace_file}") + extra_args_u85+=(-C "mps4_board.subsystem.ethosu.extra_args=--pmu-trace ${trace_file}") +fi + +if [[ ${target} == *"ethos-u55"* ]]; then + ${nobuf} ${fvp_model} \ + -C ethosu.num_macs=${num_macs} \ + -C mps3_board.visualisation.disable-visualisation=1 \ + -C mps3_board.telnetterminal0.start_telnet=0 \ + -C mps3_board.uart0.out_file='-' \ + -C mps3_board.uart0.shutdown_on_eot=1 \ + "${extra_args_u55[@]}" \ + -a "${elf_file}" \ + ${data_file} \ + --timelimit ${timeout} 2>&1 | sed 's/\r$//' | tee ${log_file} || true # seconds + echo "[${BASH_SOURCE[0]}] Simulation complete, $?" +elif [[ ${target} == *"ethos-u85"* ]]; then + ${nobuf} ${fvp_model} \ + -C mps4_board.subsystem.ethosu.num_macs=${num_macs} \ + -C mps4_board.visualisation.disable-visualisation=1 \ + -C vis_hdlcd.disable_visualisation=1 \ + -C mps4_board.telnetterminal0.start_telnet=0 \ + -C mps4_board.uart0.out_file='-' \ + -C mps4_board.uart0.shutdown_on_eot=1 \ + "${extra_args_u85[@]}" \ + -a "${elf_file}" \ + ${data_file} \ + --timelimit ${timeout} 2>&1 | sed 's/\r$//' | tee ${log_file} || true # seconds + echo "[${BASH_SOURCE[0]}] Simulation complete, $?" +else + echo "Running ${elf_file} for ${target} is not supported" + exit 1 +fi + +echo "Checking for a etdump in log" +! grep "#\[RUN THIS\]" ${log_file} >/dev/null +if [ $? != 0 ]; then + echo "Found ETDump in log!" + devtools_extra_args="" + echo "#!/bin/sh" > etdump_script.sh + sed -n '/^#\[RUN THIS\]$/,/^#\[END\]$/p' ${log_file} >> etdump_script.sh + # You can run etdump_script.sh if you do + # $ chmod a+x etdump_script.sh + # $ ./etdump_script.sh + # But lets not trust the script as a bad patch would run bad code on your machine + grep ">etdump.bin" etdump_script.sh | cut -d\" -f2- | cut -d\" -f1 | base64 -d >etdump.bin + ! grep ">debug_buffer.bin" etdump_script.sh >/dev/null + if [ $? != 0 ]; then + grep ">debug_buffer.bin" etdump_script.sh | cut -d\" -f2- | cut -d\" -f1 | base64 -d >debug_buffer.bin + devtools_extra_args="${devtools_extra_args} --debug_buffer_path debug_buffer.bin" + fi + if [[ ${etrecord_file} != "" ]]; then + devtools_extra_args="${devtools_extra_args} --etrecord_path ${etrecord_file}" + fi + python3 -m devtools.inspector.inspector_cli --etdump_path etdump.bin ${devtools_extra_args} --source_time_scale cycles --target_time_scale cycles +fi + +echo "Checking for problems in log:" +! grep -E "^(F|E|\\[critical\\]|Hard fault.|Info: Simulation is stopping. Reason: CPU time has been exceeded.).*$" ${log_file} +if [ $? != 0 ]; then + echo "Found ERROR" + rm "${log_file}" + exit 1 +fi +echo "No problems found!" +rm "${log_file}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_vkml.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_vkml.sh new file mode 100755 index 0000000..d65600e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/run_vkml.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Optional parameter: +# --build_type= "Release" | "Debug" | "RelWithDebInfo" +# --etdump build with devtools-etdump support + +set -eu +set -o pipefail + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +et_root_dir=$(realpath ${et_root_dir}) +setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + + +model="" +opt_flags="" +build_path="cmake-out-vkml" +converter="model-converter" + +help() { + echo "Usage: $(basename $0) [options]" + echo "Options:" + echo " --model= .pte model file to run" + echo " --build_path= Path to executor_runner build. for Default: ${build_path}" + exit 0 +} + +for arg in "$@"; do + case $arg in + -h|--help) help ;; + --optional_flags=*) opt_flags="${arg#*=}";; + --model=*) model="${arg#*=}";; + --build_path=*) build_path="${arg#*=}";; + *) + ;; + esac +done + +if [[ -z ${model} ]]; then echo "Model name needs to be provided"; exit 1; fi + + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } + +source ${setup_path_script} + +if ! command -v "${converter}" >/dev/null 2>&1; then + if command -v model_converter >/dev/null 2>&1; then + converter="model_converter" + fi +fi + +command -v "${converter}" >/dev/null 2>&1 \ + || { echo "Could not find a model converter executable (tried model-converter, model_converter). ${_setup_msg}"; exit 1; } + + +runner=$(find ${build_path} -name executor_runner -type f) + + +echo "--------------------------------------------------------------------------------" +echo "Running ${model} with ${runner} ${opt_flags}" +echo "WARNING: The VK_ML layer driver will not provide accurate performance information" +echo "--------------------------------------------------------------------------------" + +# Check if stdbuf is intalled and use stdbuf -oL together with tee below to make the output +# go all the way to the console more directly and not be buffered + +if hash stdbuf 2>/dev/null; then + nobuf="stdbuf -oL" +else + nobuf="" +fi + +log_file=$(mktemp) + + +${nobuf} ${runner} -model_path ${model} ${opt_flags} | tee ${log_file} +echo "[${BASH_SOURCE[0]}] execution complete, $?" + +# Most of these can happen for bare metal or linx executor_runner runs. +echo "Checking for problems in log:" +! grep -E "^(F|E|\\[critical\\]|Hard fault.|Info: Simulation is stopping. Reason: CPU time has been exceeded.).*$" ${log_file} +if [ $? != 0 ]; then + echo "Found ERROR" + rm "${log_file}" + exit 1 +fi +echo "No problems found!" +rm "${log_file}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/setup-dev-env.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/setup-dev-env.sh new file mode 100755 index 0000000..b8c9b3b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/setup-dev-env.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +git_dir=$(git rev-parse --git-dir) +ln $git_dir/../backends/arm/scripts/pre-push $git_dir/hooks +ln $git_dir/../backends/arm/scripts/pre-commit $git_dir/hooks \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/toolchain_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/toolchain_utils.sh new file mode 100644 index 0000000..d9e1cf0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/toolchain_utils.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source "${script_dir}/utils.sh" + +function gcc_select_toolchain() { + if [[ "${ARCH}" == "x86_64" ]] ; then + toolchain_url="https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz" + toolchain_dir="arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi" + toolchain_md5_checksum="0601a9588bc5b9c99ad2b56133b7f118" + elif [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]] ; then + if [[ "${OS}" == "Darwin" ]]; then + toolchain_url="https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-darwin-arm64-arm-none-eabi.tar.xz" + toolchain_dir="arm-gnu-toolchain-13.3.rel1-darwin-arm64-arm-none-eabi" + toolchain_md5_checksum="f1c18320bb3121fa89dca11399273f4e" + elif [[ "${OS}" == "Linux" ]]; then + toolchain_url="https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-aarch64-arm-none-eabi.tar.xz" + toolchain_dir="arm-gnu-toolchain-13.3.rel1-aarch64-arm-none-eabi" + toolchain_md5_checksum="303102d97b877ebbeb36b3158994b218" + fi + else + # This should never happen, it should be covered by setup.sh but catch it anyway + log_step "toolchain" "Error: Unsupported architecture ${ARCH}" + exit 1 + fi +} + +function zephyr_select_toolchain() { + if [[ "${OS}" != "Linux" ]] ; then + log_step "toolchain" "Error: Linux is required for Zephyr toolchain support" + exit 1 + fi + + if [[ "${ARCH}" == "x86_64" ]] ; then + toolchain_url="https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.2/toolchain_linux-x86_64_arm-zephyr-eabi.tar.xz" + toolchain_dir="arm-zephyr-eabi" + toolchain_md5_checksum="93128be0235cf5cf5f1ee561aa6eac5f" + elif [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]] ; then + toolchain_url="https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.2/toolchain_linux-aarch64_arm-zephyr-eabi.tar.xz" + toolchain_dir="arm-zephyr-eabi" + toolchain_md5_checksum="ef4ca56786204439a75270ba800cc64b" + else + # This should never happen, it should be covered by setup.sh but catch it anyway + log_step "toolchain" "Error: Unsupported architecture ${ARCH}" + exit 1 + fi +} + +function select_toolchain() { + if [[ "${target_toolchain}" == "zephyr" ]]; then + zephyr_select_toolchain + else + gcc_select_toolchain + fi + log_step "toolchain" "Selected ${toolchain_dir} for ${ARCH}/${OS}" +} + +function setup_toolchain() { + # Download and install the arm toolchain (default is arm-none-eabi) + # setting --target-toolchain to zephyr sets this to arm-zephyr-eabi + cd "${root_dir}" + if [[ ! -e "${toolchain_dir}.tar.xz" ]]; then + log_step "toolchain" "Downloading ${toolchain_dir} toolchain" + curl --output "${toolchain_dir}.tar.xz" -L "${toolchain_url}" + verify_md5 ${toolchain_md5_checksum} "${toolchain_dir}.tar.xz" || exit 1 + fi + + log_step "toolchain" "Installing ${toolchain_dir} toolchain" + rm -rf "${toolchain_dir}" + tar xf "${toolchain_dir}.tar.xz" +} + +function setup_path_toolchain() { + toolchain_bin_path="$(cd ${toolchain_dir}/bin && pwd)" + append_env_in_setup_path PATH ${toolchain_bin_path} +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/utils.sh new file mode 100644 index 0000000..1b4a920 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/utils.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +# Usage: +# log_step +# eg. +# log_step "step" "information message" +# outputs: +# [setup/step] information message +function log_step() { + local context="${1:-main}" + shift || true + local message="$*" + printf "[Arm Setup/%s] %s\n" "${context}" "${message}" +} + +function get_parallel_jobs() { + if command -v nproc >/dev/null 2>&1; then + nproc + elif command -v sysctl >/dev/null 2>&1 && sysctl hw.logicalcpu >/dev/null 2>&1; then + sysctl -n hw.logicalcpu + elif command -v getconf >/dev/null 2>&1; then + getconf _NPROCESSORS_ONLN + elif [[ -n "${NUMBER_OF_PROCESSORS:-}" ]]; then + echo "${NUMBER_OF_PROCESSORS}" + else + echo 1 + fi +} + +function verify_md5() { + # Compare the md5 of a file with a provided expected value. + + # Arg 1: Expected checksum for file + # Arg 2: Path to file + # Exits with return code 1 if the number of arguments is incorrect. + # Exits with return code 2 if the calculated mf5 does not match the given. + + [[ $# -ne 2 ]] \ + && { echo "[${FUNCNAME[0]}] Invalid number of args, expecting 2, but got $#"; exit 1; } + local ref_checksum="${1}" + local file="${2}" + + if [[ "${OS}" == "Darwin" ]]; then + local file_checksum="$(md5 -q $file)" + else + local file_checksum="$(md5sum $file | awk '{print $1}')" + fi + if [[ ${ref_checksum} != ${file_checksum} ]]; then + echo "Mismatched MD5 checksum for file: ${file}. Expecting ${ref_checksum} but got ${file_checksum}. Exiting." + exit 2 + fi +} + +function patch_repo() { + # Patch git repo found in $repo_dir, starting from patch $base_rev and applying patches found in $patch_dir/$name. + + # Arg 1: Directory of repo to patch + # Arg 2: Rev to start patching at + # Arg 3: Directory 'setup-dir' containing patches in 'setup-dir/$name' + # Exits with return code 1 if the number of arguments is incorrect. + # Does not do any error handling if the base_rev or patch_dir is not found etc. + + [[ $# -ne 3 ]] \ + && { echo "[${FUNCNAME[0]}] Invalid number of args, expecting 3, but got $#"; exit 1; } + + local repo_dir="${1}" + local base_rev="${2}" + local name="$(basename $repo_dir)" + local patch_dir="${3}/$name" + + echo -e "[${FUNCNAME[0]}] Patching ${name} repo_dir:${repo_dir} base_rev:${base_rev} patch_dir:${patch_dir}" + pushd $repo_dir + git fetch + git reset --hard ${base_rev} + + [[ -e ${patch_dir} && $(ls -A ${patch_dir}) ]] && \ + git am -3 ${patch_dir}/*.patch + + echo -e "[${FUNCNAME[0]}] Patched ${name} @ $(git describe --all --long 2> /dev/null) in ${repo_dir} dir.\n" + popd +} + +function check_platform_support() { + # No args + # Exits with return code 1 if the platform is unsupported + + # Make sure we are on a supported platform + if [[ "${ARCH}" != "x86_64" ]] && [[ "${ARCH}" != "aarch64" ]] \ + && [[ "${ARCH}" != "arm64" ]]; then + echo "[main] Error: only x86-64 & aarch64 architecture is supported for now!" + exit 1 + fi +} + +function check_os_support() { + # No args + # Exits with return code 1 if invalid combination of platform and os + + # Check valid combinations of OS and platform + + # Linux on x86_64 + if [[ "${ARCH}" == "x86_64" ]] && [[ "${OS}" != "Linux" ]]; then + echo "Error: Only Linux is supported on x86_64" + exit 1 + fi + + # Linux on arm64/aarch64 + # Darwin on arm64/aarch64 + if [[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]]; then + if [[ "${OS}" != "Darwin" ]] && [[ "${OS}" != "Linux" ]]; then + echo "Error: Only Linux and Darwin are supported on arm64" + exit 1 + fi + fi +} + +function prepend_env_in_setup_path() { + echo "export $1=$2:\${$1-}" >> ${setup_path_script}.sh + echo "set --path -pgx $1 $2" >> ${setup_path_script}.fish +} + +function append_env_in_setup_path() { + echo "export $1=\${$1-}:$2" >> ${setup_path_script}.sh + echo "set --path -agx $1 $2" >> ${setup_path_script}.fish +} + +function clear_setup_path() { + # Clear setup_path_script + echo "" > "${setup_path_script}.sh" + echo "" > "${setup_path_script}.fish" +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/vulkan_utils.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/vulkan_utils.sh new file mode 100644 index 0000000..2bbecff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/scripts/vulkan_utils.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Important to check for unset variables since this script is always sourced from setup.sh +set -u + +# Check if the script is being sourced +(return 0 2>/dev/null) +if [[ $? -ne 0 ]]; then + echo "Error: This script must be sourced." + exit 1 +fi + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) +source "${script_dir}/utils.sh" + +vulkan_sdk_version="1.4.321.1" +vulkan_sdk_base_dir="vulkan_sdk" + +# MLSDK dependencies +mlsdk_manifest_dir="ml-sdk-for-vulkan-manifest" + +os_name="${OS:-$(uname -s)}" +vulkan_sdk_arch="${ARCH}" + +# Vulkan SDK selection differs between macOS and Linux; macOS has its own SDK version +if [[ "${os_name}" == "Darwin" ]]; then + # Latest published macOS SDK is 1.4.321.0 (1.4.321.1 is not available for macOS) + vulkan_sdk_version="1.4.321.0" + vulkan_sdk_arch="macOS" + vulkan_sdk_url="https://sdk.lunarg.com/sdk/download/${vulkan_sdk_version}/mac/vulkansdk-macos-${vulkan_sdk_version}.zip" + vulkan_sdk_sha256="d873c43acacec1e3330fb530dafd541aa5d8a5726575a98a3f70ca505fc203db" +elif [[ "${os_name}" == "Linux" ]] && [[ "${ARCH}" == "x86_64" ]]; then + vulkan_sdk_url="https://sdk.lunarg.com/sdk/download/${vulkan_sdk_version}/linux/vulkansdk-linux-x86_64-${vulkan_sdk_version}.tar.xz" + vulkan_sdk_sha256="f22a3625bd4d7a32e7a0d926ace16d5278c149e938dac63cecc00537626cbf73" +elif [[ "${os_name}" == "Linux" ]] && ([[ "${ARCH}" == "aarch64" ]] || [[ "${ARCH}" == "arm64" ]]); then + if [[ "${vulkan_sdk_arch}" == "arm64" ]]; then + vulkan_sdk_arch="aarch64" + fi + vulkan_sdk_url="https://github.com/jakoch/vulkan-sdk-arm/releases/download/1.4.321.1/vulkansdk-ubuntu-22.04-arm-1.4.321.1.tar.xz" + vulkan_sdk_sha256="c57e318d0940394d3a304034bb7ddabda788b5b0b54638e80e90f7264efe9f84" +else + log_step "vulkan" "Error: only macOS and Linux are supported (detected ${os_name}); architecture must be x86-64 or aarch64/arm64" + exit 1 +fi + +vulkan_sdk_bin_dir="${vulkan_sdk_base_dir}/${vulkan_sdk_version}/${vulkan_sdk_arch}/bin" + +function download_and_extract_vulkan_sdk_linux() { + local vulkan_sdk_tar_file="${vulkan_sdk_url##*/}" + + if [[ ! -e "${vulkan_sdk_tar_file}" ]]; then + log_step "vulkan" "Downloading Vulkan SDK (${vulkan_sdk_version})" + curl -L --output "${vulkan_sdk_tar_file}" "${vulkan_sdk_url}" + echo "${vulkan_sdk_sha256} ${vulkan_sdk_tar_file}" | sha256sum -c - || exit 1 + rm -fr ${vulkan_sdk_base_dir} + fi + + mkdir -p ${vulkan_sdk_base_dir} + tar -C ${vulkan_sdk_base_dir} -xJf "${vulkan_sdk_tar_file}" +} + +function install_vulkan_sdk_macos() { + local vulkan_sdk_zip_file="${vulkan_sdk_url##*/}" + + if [[ ! -e "${vulkan_sdk_zip_file}" ]]; then + log_step "vulkan" "Downloading Vulkan SDK (${vulkan_sdk_version}) for macOS" + curl -L --output "${vulkan_sdk_zip_file}" "${vulkan_sdk_url}" + echo "${vulkan_sdk_sha256} ${vulkan_sdk_zip_file}" | shasum -a 256 -c - || exit 1 + rm -fr ${vulkan_sdk_base_dir} + fi + + log_step "vulkan" "Extracting Vulkan SDK installer" + unzip -q -o "${vulkan_sdk_zip_file}" + + local vulkan_sdk_app_path="" + vulkan_sdk_app_path="$(find . -maxdepth 3 -type d -name "vulkansdk-macOS-${vulkan_sdk_version}.app" -print -quit)" + if [[ -z "${vulkan_sdk_app_path}" ]]; then + vulkan_sdk_app_path="$(find . -maxdepth 3 -type d -name "vulkansdk-macos-${vulkan_sdk_version}.app" -print -quit)" + fi + if [[ -z "${vulkan_sdk_app_path}" ]]; then + log_step "vulkan" "Error: Vulkan SDK installer app not found after extracting ${vulkan_sdk_zip_file}" + exit 1 + fi + + local vulkan_sdk_installer="${vulkan_sdk_app_path}/Contents/MacOS/$(basename "${vulkan_sdk_app_path}" .app)" + if [[ ! -x "${vulkan_sdk_installer}" ]]; then + log_step "vulkan" "Error: Vulkan SDK installer binary not found at ${vulkan_sdk_installer}" + exit 1 + fi + + local install_root="$(cd "${root_dir}" && pwd)/${vulkan_sdk_base_dir}/${vulkan_sdk_version}" + mkdir -p "${install_root}" + local vulkan_sdk_root="${root_dir}/${vulkan_sdk_base_dir}" + + log_step "vulkan" "Installing Vulkan SDK (${vulkan_sdk_version}) to ${install_root}" + ${vulkan_sdk_installer} --root "${install_root}" --accept-licenses --default-answer --confirm-command install +} + +function setup_vulkan_sdk() { + cd "${root_dir}" + + if [[ "${os_name}" == "Darwin" ]]; then + install_vulkan_sdk_macos + else + download_and_extract_vulkan_sdk_linux + fi + + if [[ ! -d "${root_dir}/${vulkan_sdk_bin_dir}" ]]; then + log_step "vulkan" "Error: Vulkan SDK bin directory not found at ${root_dir}/${vulkan_sdk_bin_dir}" + exit 1 + fi + + vulkan_sdk_bin_path="$(cd "${root_dir}/${vulkan_sdk_bin_dir}" && pwd)" + if [[ ! -x "${vulkan_sdk_bin_path}/glslc" ]]; then + log_step "vulkan" "Error: glslc not found at ${vulkan_sdk_bin_path}/glslc" + exit 1 + fi + + if ${vulkan_sdk_bin_path}/glslc --version > /dev/null 2>&1; then + log_step "vulkan" "Vulkan SDK validation (glslc) succeeded" + else + log_step "vulkan" "Error: Vulkan SDK validation failed" + ${vulkan_sdk_bin_path}/glslc --version + exit 1 + fi +} + +function setup_path_vulkan() { + cd "${root_dir}" + if [[ ! -d "${root_dir}/${vulkan_sdk_bin_dir}" ]]; then + log_step "vulkan" "Vulkan SDK not found; skipping PATH update" + return + fi + + local vulkan_sdk_arch_root="${vulkan_sdk_base_dir}/${vulkan_sdk_version}/${vulkan_sdk_arch}" + + if [[ ! -d "${vulkan_sdk_arch_root}" ]]; then + log_step "vulkan" "Vulkan SDK arch path not found; skipping PATH update" + return + fi + + vulkan_sdk_arch_root="$(cd "${vulkan_sdk_arch_root}" && pwd)" + vulkan_sdk_bin_path="$(cd "${vulkan_sdk_bin_dir}" && pwd)" + + append_env_in_setup_path PATH ${vulkan_sdk_bin_path} + if [[ "${OS:-}" == "Darwin" ]]; then + prepend_env_in_setup_path DYLD_LIBRARY_PATH "${vulkan_sdk_arch_root}/lib" + local moltenvk_icd_path="${vulkan_sdk_arch_root}/share/vulkan/icd.d/MoltenVK_icd.json" + if [[ -f "${moltenvk_icd_path}" ]]; then + prepend_env_in_setup_path VK_DRIVER_FILES "${moltenvk_icd_path}" + log_step "vulkan" "Configured VK_DRIVER_FILES to include ${moltenvk_icd_path}" + else + log_step "vulkan" "MoltenVK ICD manifest not found at ${moltenvk_icd_path}; skipping VK_DRIVER_FILES update" + fi + else + prepend_env_in_setup_path LD_LIBRARY_PATH "${vulkan_sdk_arch_root}/lib" + fi + prepend_env_in_setup_path VULKAN_SDK "${vulkan_sdk_arch_root}" +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/.coveragerc b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/.coveragerc new file mode 100644 index 0000000..4172a3d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/.coveragerc @@ -0,0 +1,8 @@ +[run] +omit = + *__init__.py* + +[report] +skip_covered = true +exclude_also = + raise NotImplementedError diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/TARGETS new file mode 100644 index 0000000..f3cb00e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/TARGETS @@ -0,0 +1,86 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load(":targets.bzl", "define_arm_tests") + + +oncall("executorch") + +runtime.python_library( + name = "conftest", + srcs = ["conftest.py"], + deps = [ + "//executorch/exir:lib", + "//executorch/exir/backend:compile_spec_schema", + "fbsource//third-party/pypi/pytest:pytest", + ] +) + +runtime.python_library( + name = "runner_utils", + srcs = ["runner_utils.py"], + resources = { + "fbsource//third-party/flatbuffers:flatc-host": "flatbuffers-flatc", + }, + deps = [ + ":conftest", + "//executorch/backends/arm:arm_compile_spec", + "//executorch/backends/arm:ethosu", + "//executorch/backends/arm/tosa:compile_spec", + "//executorch/backends/arm/tosa:schemas", + "//executorch/backends/arm:vgf", + "//executorch/backends/arm/tosa:specification", + "//executorch/exir:lib", + "//executorch/exir/backend:compile_spec_schema", + ] +) + +runtime.python_library( + name = "common", + srcs = ["common.py"], + deps = [ + ":runner_utils", + "//executorch/backends/arm/tosa:tosa", + "fbsource//third-party/pypi/pytest:pytest", + ] +) + +runtime.python_library( + name = "arm_tester_serialize", + srcs = ["tester/serialize.py"], + deps = [ + "//executorch/backends/xnnpack/test/tester:tester", + "//executorch/devtools/backend_debug:delegation_info", + ] +) + +runtime.python_library( + name = "arm_tester_lib", + srcs = glob(["tester/*.py"], exclude = ["tester/serialize.py"]), + deps = [ + ":common", + "//executorch/backends/xnnpack/test/tester:tester", + "//executorch/backends/arm:ethosu", + "//executorch/backends/arm/quantizer:lib", + "//executorch/backends/arm/tosa:mapping", + "//executorch/backends/arm:vgf", + "//executorch/backends/arm:_factory", + "//executorch/devtools/backend_debug:delegation_info", + "//executorch/exir/backend:operator_support", + "fbsource//third-party/pypi/tabulate:tabulate", + ] +) + + +runtime.python_library( + name = "arm_tester", + deps = [ + "//executorch/backends/arm/test:arm_tester_lib", + "//executorch/backends/arm/test:arm_tester_serialize", + ] +) + +define_arm_tests() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/common.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/common.py new file mode 100644 index 0000000..c252294 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/common.py @@ -0,0 +1,302 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import os + +import tempfile +from datetime import datetime + +from pathlib import Path +from typing import Any, Callable, Optional, ParamSpec, TypeVar + +import pytest +from executorch.backends.arm.ethosu import EthosUCompileSpec + +from executorch.backends.arm.test.runner_utils import ( + arm_executor_runner_exists, + corstone300_installed, + corstone320_installed, + model_converter_installed, + vkml_emulation_layer_installed, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.vgf import VgfCompileSpec + + +def get_time_formatted_path(path: str, log_prefix: str) -> str: + """ + Returns the log path with the current time appended to it. Used for debugging. + + Args: + path: The path to the folder where the log file will be stored. + log_prefix: The name of the test. + + Example output: + './my_log_folder/test_INT_artifact_28-Nov-14:14:38.log' + """ + return str( + Path(path) / f"{log_prefix}_{datetime.now().strftime('%d-%b-%H:%M:%S')}.log" + ) + + +def maybe_get_tosa_collate_path() -> str | None: + """ + Checks the environment variable TOSA_TESTCASES_BASE_PATH and returns the + path to the where to store the current tests if it is set. + """ + tosa_test_base = os.environ.get("TOSA_TESTCASES_BASE_PATH") + if tosa_test_base: + current_test = os.environ.get("PYTEST_CURRENT_TEST") + # '::test_collate_tosa_INT_tests[randn] (call)' + test_name = current_test.split("::")[1].split(" ")[0] # type: ignore[union-attr] + if "INT" in test_name: + tosa_test_base = os.path.join(tosa_test_base, "tosa-int") + elif "FP" in test_name: + tosa_test_base = os.path.join(tosa_test_base, "tosa-fp") + else: + tosa_test_base = os.path.join(tosa_test_base, "other") + return os.path.join(tosa_test_base, test_name) + + return None + + +def get_tosa_compile_spec( + tosa_spec: str | TosaSpecification, + custom_path: Optional[str] = None, + tosa_debug_mode: TosaCompileSpec.DebugMode | None = None, +) -> TosaCompileSpec: + """Get the compile spec for default TOSA tests.""" + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + if custom_path is not None: + os.makedirs(custom_path, exist_ok=True) + + compile_spec = ( + TosaCompileSpec(tosa_spec) + .dump_intermediate_artifacts_to(custom_path) + .dump_debug_info(tosa_debug_mode) + ) + return compile_spec + + +def get_u55_compile_spec( + macs: int = 128, + system_config: str = "Ethos_U55_High_End_Embedded", + memory_mode: str = "Shared_Sram", + extra_flags: str = "--debug-force-regor --output-format=raw --arena-cache-size=2097152", + custom_path: Optional[str] = None, + config: Optional[str] = None, + tosa_debug_mode: EthosUCompileSpec.DebugMode | None = None, +) -> EthosUCompileSpec: + """Default compile spec for Ethos-U55 tests.""" + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + artifact_path = custom_path or tempfile.mkdtemp(prefix="arm_u55_") + if not os.path.exists(artifact_path): + os.makedirs(artifact_path, exist_ok=True) + + # https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-vela/-/blob/main/OPTIONS.md + assert macs in [32, 64, 128, 256], "Unsupported MACs value" + + if extra_flags is not None: + extra_flags_list = extra_flags.split(" ") + else: + extra_flags_list = [] + compile_spec = ( + EthosUCompileSpec( + f"ethos-u55-{macs}", + system_config=system_config, + memory_mode=memory_mode, + extra_flags=extra_flags_list, + config_ini=config, + ) + .dump_intermediate_artifacts_to(artifact_path) + .dump_debug_info(tosa_debug_mode) + ) + return compile_spec + + +def get_u85_compile_spec( + macs: int = 128, + system_config="Ethos_U85_SYS_DRAM_Mid", + memory_mode="Shared_Sram", + extra_flags="--output-format=raw --arena-cache-size=2097152", + custom_path: Optional[str] = None, + config: Optional[str] = None, + tosa_debug_mode: EthosUCompileSpec.DebugMode | None = None, +) -> EthosUCompileSpec: + """Default compile spec for Ethos-U85 tests.""" + + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + artifact_path = custom_path or tempfile.mkdtemp(prefix="arm_u85_") + if not os.path.exists(artifact_path): + os.makedirs(artifact_path, exist_ok=True) + + assert macs in [128, 256, 512, 1024, 2048], "Unsupported MACs value" + + if extra_flags is not None: + extra_flags_list = extra_flags.split(" ") + else: + extra_flags_list = [] + + compile_spec = ( + EthosUCompileSpec( + f"ethos-u85-{macs}", + system_config=system_config, + memory_mode=memory_mode, + extra_flags=extra_flags_list, + config_ini=config, + ) + .dump_intermediate_artifacts_to(artifact_path) + .dump_debug_info(tosa_debug_mode) + ) + return compile_spec # type: ignore[return-value] + + +def get_vgf_compile_spec( + tosa_spec: str | TosaSpecification, + compiler_flags: Optional[str] = "", + custom_path: Optional[str] = None, + tosa_debug_mode: VgfCompileSpec.DebugMode | None = None, +) -> VgfCompileSpec: + """Get the ArmCompileSpec for the default VGF tests, to modify + the compile spec before calling .build() to finalize it. + """ + + if not custom_path: + custom_path = maybe_get_tosa_collate_path() + profiles = [] + if "FP" in repr(tosa_spec): + profiles.append("fp") + if "INT" in repr(tosa_spec): + profiles.append("int") + if len(profiles) == 0: + raise ValueError(f"Unsupported vgf compile_spec: {repr(tosa_spec)}") + + if custom_path is None: + artifact_path = "arm_vgf_" + for profile in profiles: + artifact_path = artifact_path + f"_{profile}" + artifact_path = tempfile.mkdtemp(artifact_path) + else: + artifact_path = custom_path + + if not os.path.exists(artifact_path): + os.makedirs(artifact_path, exist_ok=True) + + if compiler_flags is not None: + compiler_flags_list = compiler_flags.split(" ") + else: + compiler_flags_list = [] + + compile_spec = ( + VgfCompileSpec(tosa_spec, compiler_flags_list) + .dump_intermediate_artifacts_to(artifact_path) + .dump_debug_info(tosa_debug_mode) + ) + + return compile_spec + + +XfailIfNoCorstone300 = pytest.mark.xfail( + condition=not ( + corstone300_installed() and arm_executor_runner_exists("corstone-300") + ), + raises=FileNotFoundError, + reason="Did not find Corstone-300 FVP or executor_runner on path", +) +"""Xfails a test if Corsone300 FVP is not installed, or if the executor runner is not built""" + +XfailIfNoCorstone320 = pytest.mark.xfail( + condition=not ( + corstone320_installed() and arm_executor_runner_exists("corstone-320") + ), + raises=FileNotFoundError, + reason="Did not find Corstone-320 FVP or executor_runner on path", +) +"""Xfails a test if Corsone320 FVP is not installed, or if the executor runner is not built""" + +SkipIfNoModelConverter = pytest.mark.skipif( # type: ignore[call-arg] + condition=not (model_converter_installed()), + raises=FileNotFoundError, + reason="Did not find model-converter on path", +) +"""Skips a test if model-converter is not installed""" + +XfailfNoVKMLEmulationLayer = pytest.mark.xfail( + condition=not (vkml_emulation_layer_installed()), + raises=TypeError, + reason="VKML environment is not set properly or executor_runner path is misused", +) +"""Xfails a test if VKML Emulation Layer is not installed""" + +xfail_type = str | tuple[str, type[Exception]] + +_P = ParamSpec("_P") +_R = TypeVar("_R") +Decorator = Callable[[Callable[_P, _R]], Callable[_P, _R]] + + +def parametrize( + arg_name: str, + test_data: dict[str, Any], + xfails: dict[str, xfail_type] | None = None, + skips: dict[str, str] | None = None, + strict: bool = True, + flakies: dict[str, int] | None = None, +) -> Decorator: + """ + Custom version of pytest.mark.parametrize with some syntatic sugar and added xfail functionality + - test_data is expected as a dict of (id, test_data) pairs + - alllows to specifiy a dict of (id, failure_reason) pairs to mark specific tests as xfail. + Failure_reason can be str, type[Exception], or tuple[str, type[Exception]]. + Strings set the reason for failure, the exception type sets expected error. + """ + if xfails is None: + xfails = {} + if skips is None: + skips = {} + if flakies is None: + flakies = {} + + def decorator_func(func: Callable[_P, _R]) -> Callable[_P, _R]: + """Test data is transformed from a dict of (id, data) pairs to a list of pytest params to work with the native pytests parametrize function""" + pytest_testsuite = [] + for id, test_parameters in test_data.items(): + if id in flakies: + # Mark this parameter as flaky with given reruns + marker = (pytest.mark.flaky(reruns=flakies[id]),) + elif id in skips: + # fail markers do not work with 'buck' based ci, so use skip instead + marker = (pytest.mark.skip(reason=skips[id]),) + elif id in xfails: + xfail_info = xfails[id] + reason = "" + raises = None + if isinstance(xfail_info, str): + reason = xfail_info + elif isinstance(xfail_info, tuple): + reason, raises = xfail_info + else: + raise RuntimeError( + "xfail info needs to be str, or tuple[str, type[Exception]]" + ) + # Set up our fail marker + marker: tuple[pytest.MarkDecorator, ...] # type: ignore[no-redef] + marker = ( + pytest.mark.xfail(reason=reason, raises=raises, strict=strict), + ) + else: + marker = () # type: ignore[assignment] + + pytest_param = pytest.param(test_parameters, id=id, marks=marker) + pytest_testsuite.append(pytest_param) + decorator = pytest.mark.parametrize(arg_name, pytest_testsuite) + return decorator(func) + + return decorator_func diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/conftest.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/conftest.py new file mode 100644 index 0000000..c33f551 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/conftest.py @@ -0,0 +1,134 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import random +import sys +from typing import Any + +import pytest + +""" +This file contains the pytest hooks, fixtures etc. for the Arm test suite. +""" + + +# ==== Pytest hooks ==== + + +def pytest_configure(config): + pytest._test_options = {} # type: ignore[attr-defined] + + if getattr(config.option, "llama_inputs", False) and config.option.llama_inputs: + pytest._test_options["llama_inputs"] = config.option.llama_inputs # type: ignore[attr-defined] + + pytest._test_options["tosa_version"] = "1.0" # type: ignore[attr-defined] + if config.option.arm_run_tosa_version: + pytest._test_options["tosa_version"] = config.option.arm_run_tosa_version + + logging.basicConfig(stream=sys.stdout) + + +def pytest_collection_modifyitems(config, items): + pass + + +def pytest_addoption(parser): + def try_addoption(*args, **kwargs): + try: + parser.addoption(*args, **kwargs) + except Exception: # nosec B110 - pytest redefines options, safe to ignore + pass + + try_addoption("--arm_quantize_io", action="store_true", help="Deprecated.") + try_addoption("--arm_run_corstoneFVP", action="store_true", help="Deprecated.") + try_addoption( + "--llama_inputs", + nargs="+", + help="List of two files. Firstly .pt file. Secondly .json", + ) + try_addoption("--arm_run_tosa_version", action="store", default="1.0") + + +def pytest_sessionstart(session): + pass + + +def pytest_sessionfinish(session, exitstatus): + pass + + +# ==== End of Pytest hooks ===== + + +# ==== Pytest fixtures ===== + + +@pytest.fixture(autouse=True) +def set_random_seed(): + """ + Control random numbers in Arm test suite. Default behavior is random seed, + which is set before each test. Use the env variable ARM_TEST_SEED to set the + seed you want to use to overrride the default behavior. Or set it to RANDOM + if you want to be explicit. + + Examples: + As default use random seed for each test + ARM_TEST_SEED=RANDOM pytest --config-file=/dev/null --verbose -s --color=yes backends/arm/test/ops/test_avg_pool.py -k + Rerun with a specific seed found under a random seed test + ARM_TEST_SEED=3478246 pytest --config-file=/dev/null --verbose -s --color=yes backends/arm/test/ops/test_avg_pool.py -k + """ + import torch + + if os.environ.get("ARM_TEST_SEED", "RANDOM") == "RANDOM": + random.seed() # reset seed, in case any other test has fiddled with it + seed = random.randint(0, 2**32 - 1) # nosec B311 - non-crypto seed for tests + torch.manual_seed(seed) + else: + seed_str = os.environ.get("ARM_TEST_SEED", "0") + if str.isdigit(seed_str): + seed = int(seed_str) + random.seed(seed) + torch.manual_seed(seed) + else: + raise TypeError( + "ARM_TEST_SEED env variable must be integers or the string RANDOM" + ) + + print(f" ARM_TEST_SEED={seed} ", end=" ") + + +# ==== End of Pytest fixtures ===== + + +def is_option_enabled(option: str, fail_if_not_enabled: bool = False) -> bool: + """ + Returns whether an option is successfully enabled, i.e. if the flag was + given to pytest and the necessary requirements are available. + + The optional parameter 'fail_if_not_enabled' makes the function raise + a RuntimeError instead of returning False. + """ + + if hasattr(pytest, "_test_options") and option in pytest._test_options and pytest._test_options[option]: # type: ignore[attr-defined] + return True + else: + if fail_if_not_enabled: + raise RuntimeError(f"Required option '{option}' for test is not enabled") + else: + return False + + +def get_option(option: str) -> Any | None: + """ + Returns the value of an pytest option if it is set, otherwise None. + + Args: + option (str): The option to check for. + """ + if option in pytest._test_options: # type: ignore[attr-defined] + return pytest._test_options[option] # type: ignore[attr-defined] + return None diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/TARGETS new file mode 100644 index 0000000..00b836c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/TARGETS @@ -0,0 +1,16 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +oncall("executorch") + +runtime.python_library( + name = "dw_convs_shared_weights_module", + srcs = ["test_dw_convs_with_shared_weights.py"], + deps = [ + "//executorch/backends/arm/test:arm_tester_lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_bn_relu_folding_qat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_bn_relu_folding_qat.py new file mode 100644 index 0000000..41675b3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_bn_relu_folding_qat.py @@ -0,0 +1,124 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT +from executorch.backends.arm.tosa import TosaSpecification + +from executorch.backends.xnnpack.test.tester.tester import Quantize +from torch import nn + + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Conv2dModule(torch.nn.Module): + input_shape = (1, 28, 28) + batch_size = 64 + test_data: input_t1 = (torch.randn(batch_size, *input_shape),) + + def __init__(self, batch_norm: bool = True, inplace: bool = False) -> None: + super().__init__() + self.conv = torch.nn.Conv2d(1, 16, 3, stride=2) + self.bn = nn.BatchNorm2d(num_features=16) if batch_norm else nn.Identity() + self.relu = nn.ReLU(inplace=inplace) + + def forward(self, x: torch.Tensor): + x = self.conv(x) + x = self.bn(x) + x = self.relu(x) + + return x + + +class Conv1dModule(torch.nn.Module): + input_shape = (3, 10) + batch_size = 2 + test_data: input_t1 = (torch.randn(batch_size, *input_shape),) + + def __init__(self, batch_norm: bool = True, inplace: bool = False) -> None: + super().__init__() + self.conv = torch.nn.Conv1d(3, 8, 5, padding=2) + self.bn = nn.BatchNorm1d(num_features=8) if batch_norm else nn.Identity() + self.relu = nn.ReLU(inplace=inplace) + + def forward(self, x: torch.Tensor): + x = self.conv(x) + x = self.bn(x) + x = self.relu(x) + + return x + + +models = { + # name : (model, is_per_channel) + "conv1d_bn_relu_per_channel": (Conv1dModule(batch_norm=True), True), + "conv1d_relu_per_channel": (Conv1dModule(batch_norm=False), True), + "conv1d_bn_relu_per_tensor": (Conv1dModule(batch_norm=True), False), + "conv1d_relu_per_tensor": (Conv1dModule(batch_norm=False), False), + "conv2d_bn_relu_per_channel": (Conv2dModule(batch_norm=True), True), + "conv2d_relu_per_channel": (Conv2dModule(batch_norm=False), True), + "conv2d_bn_relu_per_tensor": (Conv2dModule(batch_norm=True), False), + "conv2d_relu_per_tensor": (Conv2dModule(batch_norm=False), False), + "conv1d_bn_relu_inplace_per_channel": ( + Conv1dModule(batch_norm=True, inplace=True), + True, + ), + "conv1d_relu_inplace_per_channel": ( + Conv1dModule(batch_norm=False, inplace=True), + True, + ), + "conv1d_bn_relu_inplace_per_tensor": ( + Conv1dModule(batch_norm=True, inplace=True), + False, + ), + "conv1d_relu_inplace_per_tensor": ( + Conv1dModule(batch_norm=False, inplace=True), + False, + ), + "conv2d_bn_relu_inplace_per_channel": ( + Conv2dModule(batch_norm=True, inplace=True), + True, + ), + "conv2d_relu_inplace_per_channel": ( + Conv2dModule(batch_norm=False, inplace=True), + True, + ), + "conv2d_bn_relu_inplace_per_tensor": ( + Conv2dModule(batch_norm=True, inplace=True), + False, + ), + "conv2d_relu_inplace_per_tensor": ( + Conv2dModule(batch_norm=False, inplace=True), + False, + ), +} + + +@common.parametrize( + "test_data", + models, +) +def test_bn_relu_folding_qat_tosa_INT(test_data): + model, per_channel = test_data + pipeline = TosaPipelineINT[input_t1](model, model.test_data, [], [], qtol=1) + quantizer = TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + pipeline.change_args( + "quantize", + Quantize( + quantizer=quantizer, + quantization_config=get_symmetric_quantization_config( + is_qat=True, is_per_channel=per_channel + ), + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_call_operator_submodule.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_call_operator_submodule.py new file mode 100644 index 0000000..5c4029d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_call_operator_submodule.py @@ -0,0 +1,72 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, Optional + +import torch + +from executorch.backends.arm._passes.arm_pass import ArmPass +from executorch.backends.arm._passes.arm_pass_manager import ArmPassManager +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from torch.fx import GraphModule +from torch.fx.passes.infra.pass_base import PassResult + + +class _DepthRecordingPass(ArmPass): + _passes_required_after = set() + + def __init__(self, initial_graph_module): + super().__init__() + self.depths: list[int] = [] + self.initial_submodule = initial_graph_module + self.submodule = None + self.num_submodules_called = 0 + + def call_operator(self, op, args, kwargs, meta, updated: Optional[bool] = False): + """Should only be called from the top-level graph module.""" + self.depths.append(self.submodule_depth) + assert self.submodule == self.initial_submodule + return super().call_operator(op, args, kwargs, meta, updated) + + def call_submodule( + self, graph_module: GraphModule, inputs: tuple[Any, ...] + ) -> PassResult: + """Should be called for all three graph_modules: top-level, if, and else.""" + self.submodule = graph_module + self.num_submodules_called += 1 + return super().call_submodule(graph_module, inputs) + + +class _CondModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def _true_branch(arg: torch.Tensor) -> torch.Tensor: + return arg + 1 + + def _false_branch(arg: torch.Tensor) -> torch.Tensor: + return arg - 1 + + predicate = x.sum() > 0 + return torch.cond(predicate, _true_branch, _false_branch, [x]) + + +def test_call_operator_runs_once_for_cond_submodules_tosa_FP() -> None: + module = _CondModule() + example_inputs = (torch.randn(2, 3),) + exported = torch.export.export(module, example_inputs) + graph_module = exported.graph_module + + recording_pass = _DepthRecordingPass(graph_module) + pass_manager = ArmPassManager(TosaCompileSpec("TOSA-1.00+FP")) + pass_manager.add_pass(recording_pass) + pass_manager._transform(graph_module) + + assert recording_pass.num_submodules_called == 3 + assert recording_pass.depths, "call_operator was never invoked" + assert ( + max(recording_pass.depths) == 1 + ), "call_operator was invoked with larger than one submodule depth." + assert ( + min(recording_pass.depths) == 1 + ), "call_operator was invoked with zero submodule depth." diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_compile_spec.py new file mode 100644 index 0000000..e40776e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_compile_spec.py @@ -0,0 +1,55 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.ethosu import EthosUCompileSpec +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.vgf import VgfCompileSpec +from pytest import raises + + +def test_ethos_u_compile_spec_no_target(): + compile_spec = ( + EthosUCompileSpec("ethos-u55", extra_flags=["--my-flag"]) + .dump_intermediate_artifacts_to("my_path") + .dump_debug_info(EthosUCompileSpec.DebugMode.TOSA) + ) + spec_list = compile_spec.to_list() + + assert EthosUCompileSpec.from_list(spec_list) == compile_spec + assert "--my-flag" in compile_spec.compiler_flags + assert "--output-format=raw" in compile_spec.compiler_flags + with raises(ValueError, match="Incorrect output format"): + VgfCompileSpec.from_list(spec_list) + + spec_list.pop(0) + with raises(ValueError, match="No tosa_spec in compile spec."): + EthosUCompileSpec.from_list(spec_list) + + +def test_vgf_compile_spec_no_target(): + compile_spec = ( + VgfCompileSpec(compiler_flags=["--my-flag"]) + .dump_intermediate_artifacts_to("my_path") + .dump_debug_info(None) + ) + compile_spec2 = VgfCompileSpec( + compiler_flags=["--my-flag2"] + ).dump_intermediate_artifacts_to("my_path") + + spec_list = compile_spec.to_list() + + assert VgfCompileSpec.from_list(spec_list) == compile_spec + assert VgfCompileSpec.from_list(spec_list) != compile_spec2 + with raises(ValueError, match="Incorrect output format"): + EthosUCompileSpec.from_list(spec_list) + + +def test_tosa_compile_spec_no_target(): + compile_spec = TosaCompileSpec("TOSA-1.0+INT") + spec_list = compile_spec.to_list() + + assert TosaCompileSpec.from_list(spec_list) == compile_spec + with raises(ValueError, match="Incorrect output format"): + VgfCompileSpec.from_list(spec_list) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_conv_relu_residual_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_conv_relu_residual_add.py new file mode 100644 index 0000000..982cc1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_conv_relu_residual_add.py @@ -0,0 +1,108 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +import torch.nn as nn +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + + +# Model with Conv1D - ReLU sequence and a residual add. +# Testing the annotation of Conv1D-ReLU(to be fused) and annotation of add. +# ReLU outputs positive numbers and linear outputs positive and negative numbers, so they +# should have different quantisation parameters. If the ReLU gets wrong quantisation parameters(e.g. qmin!=zp) +# because of a shared observer of a following operators(e.g. add), the Conv1D-ReLU sequence is not fused +# and is left in FP32. As a result, the test fails. +class AddDifferentRanges(torch.nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, input_dim): + super().__init__() + self.conv1 = nn.Conv1d(in_channels, out_channels, kernel_size) + self.relu = torch.nn.ReLU() + self.linear = nn.Linear(out_channels, out_channels) + + def forward(self, x): + # Permute: (N, T, C) -> (N, C, T) + x = x.permute(0, 2, 1) + x = self.conv1(x) + x = self.relu(x) + x = x.permute(0, 2, 1) + out = x + self.linear(x) + return out + + +input_t = Tuple[torch.Tensor] +model = AddDifferentRanges(in_channels=3, out_channels=16, kernel_size=3, input_dim=10) +model_inputs = (torch.randn(1, 10, 3),) +quant_test_data = { + "per_channel_quantization=true": True, + "per_channel_quantization=false": False, +} + + +def test_conv_relu_residual_add_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("per_channel_quantization", quant_test_data) +def test_conv_relu_residual_add_tosa_INT(per_channel_quantization): + pipeline = TosaPipelineINT[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + qtol=0, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_conv_relu_residual_add_u55_INT(per_channel_quantization): + pipeline = EthosU55PipelineINT[input_t]( + model, + model_inputs, + [], + [], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + qtol=0, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_conv_relu_residual_add_u85_INT(per_channel_quantization): + pipeline = EthosU85PipelineINT[input_t]( + model, + model_inputs, + [], + [], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + qtol=0, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_custom_partition.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_custom_partition.py new file mode 100644 index 0000000..e38c98a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_custom_partition.py @@ -0,0 +1,183 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineFP +from executorch.exir.backend.operator_support import ( + DontPartition, + DontPartitionModule, + DontPartitionName, +) +from executorch.exir.dialects._ops import ops as exir_ops + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class CustomPartitioning(torch.nn.Module): + inputs = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + z = x + y + s = torch.sigmoid(z) + return s * z + + +class NestedModule(torch.nn.Module): + inputs = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def __init__(self): + super().__init__() + self.nested = CustomPartitioning() + + def forward(self, x: torch.Tensor, y: torch.Tensor): + a = x.sigmoid() + b = a + y + return self.nested(a, b) + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_single_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = CustomPartitioning() + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + check = DontPartition(exir_ops.edge.aten.sigmoid.default) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartition" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_multiple_reject_tosa_FP(test_data: input_t1): + module = CustomPartitioning() + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + check = DontPartition( + exir_ops.edge.aten.sigmoid.default, exir_ops.edge.aten.mul.Tensor + ) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_torch_op_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = CustomPartitioning() + check = DontPartition(torch.ops.aten.sigmoid.default) + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartition" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_string_op_reject_tosa_FP(test_data: input_t1): + module = CustomPartitioning() + check = DontPartition("aten.sigmoid.default") + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_name_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = CustomPartitioning() + check = DontPartitionName("mul", "sigmoid", exact=False) + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartitionName" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_module_reject_tosa_FP(test_data: input_t1): + module = NestedModule() + check = DontPartitionModule(module_name="CustomPartitioning") + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_inexact_module_reject_tosa_FP(caplog, test_data: input_t1): + caplog.set_level(logging.INFO) + + module = NestedModule() + check = DontPartitionModule(module_name="Custom", exact=False) + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() + assert "Rejected by DontPartitionModule" in caplog.text + + +@common.parametrize("test_data", CustomPartitioning.inputs) +def test_module_instance_reject_tosa_FP(test_data: input_t1): + module = NestedModule() + check = DontPartitionModule(instance_name="nested") + pipeline = TosaPipelineFP[input_t1](module, test_data, [], exir_op=[]) + pipeline.change_args("to_edge_transform_and_lower", additional_checks=[check]) + pipeline.change_args( + "check_count.exir", + {"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ) + pipeline.run() + assert check.has_rejected_node() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_feats.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_feats.py new file mode 100644 index 0000000..718e3a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_feats.py @@ -0,0 +1,316 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import json +import os +import shutil +import tempfile + +from pathlib import Path +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.test import common +from executorch.backends.arm.test.runner_utils import dbg_tosa_fb_to_json +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) +from executorch.backends.test.harness.stages import StageType + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Linear(torch.nn.Module): + inputs = { + "randn": (torch.randn(5, 10, 25, 3),), + } + + def __init__( + self, + ): + super().__init__() + self.fc = torch.nn.Linear( + in_features=3, + out_features=5, + bias=True, + ) + + def forward(self, x): + return self.fc(x) + + +"""Tests dumping the partition artifact in ArmTester. Both to file and to stdout.""" + + +def _tosa_FP_pipeline(module: torch.nn.Module, test_data: input_t1, dump_file=None): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1](module, test_data, aten_ops, exir_ops) + pipeline.dump_artifact("to_edge_transform_and_lower") + pipeline.dump_artifact("to_edge_transform_and_lower", suffix=dump_file) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +def _tosa_INT_pipeline(module: torch.nn.Module, test_data: input_t1, dump_file=None): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](module, test_data, aten_ops, exir_ops) + pipeline.dump_artifact("to_edge_transform_and_lower") + pipeline.dump_artifact("to_edge_transform_and_lower", suffix=dump_file) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +def _is_tosa_marker_in_file(tmp_file): + for line in open(tmp_file).readlines(): + if "'name': 'main'" in line: + return True + return False + + +@common.parametrize("test_data", Linear.inputs) +def test_artifact_tosa_FP(test_data: input_t1): + model = Linear() + tmp_file = common.get_time_formatted_path( + tempfile.mkdtemp(), test_artifact_tosa_FP.__name__ + ) + _tosa_FP_pipeline(model, test_data, dump_file=tmp_file) + assert os.path.exists(tmp_file), f"File {tmp_file} was not created" + if _is_tosa_marker_in_file(tmp_file): + return # Implicit pass test + pytest.fail("File does not contain TOSA dump!") + + +@common.parametrize("test_data", Linear.inputs) +def test_artifact_tosa_INT(test_data: input_t1): + model = Linear() + tmp_file = common.get_time_formatted_path( + tempfile.mkdtemp(), test_artifact_tosa_INT.__name__ + ) + _tosa_INT_pipeline(model, test_data, dump_file=tmp_file) + assert os.path.exists(tmp_file), f"File {tmp_file} was not created" + if _is_tosa_marker_in_file(tmp_file): + return # Implicit pass test + pytest.fail("File does not contain TOSA dump!") + + +"""Tests trigging the exception printout from the ArmTester's run and compare function.""" + + +@common.parametrize("test_data", Linear.inputs) +def test_numerical_diff_print_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + Linear(), + test_data, + aten_ops, + exir_ops, + custom_path="diff_print_test", + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + tester = pipeline.tester + # We expect an assertion error here. Any other issues will cause the + # test to fail. Likewise the test will fail if the assertion error is + # not present. + try: + # Tolerate 0 difference => we want to trigger a numerical diff + tester.run_method_and_compare_outputs( + stage=StageType.INITIAL_MODEL, atol=0, rtol=0, qtol=0 + ) + except AssertionError: + pass # Implicit pass test + else: + pytest.fail() + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_ops_and_dtypes_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.add_stage_after("quantize", pipeline.tester.dump_dtype_distribution) + pipeline.add_stage_after("quantize", pipeline.tester.dump_operator_distribution) + pipeline.add_stage_after("export", pipeline.tester.dump_dtype_distribution) + pipeline.add_stage_after("export", pipeline.tester.dump_operator_distribution) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_dtype_distribution + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_operator_distribution + ) + pipeline.run() + # Just test that there are no execptions. + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_ops_and_dtypes_parseable_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.add_stage_after("quantize", pipeline.tester.dump_dtype_distribution, False) + pipeline.add_stage_after( + "quantize", pipeline.tester.dump_operator_distribution, False + ) + pipeline.add_stage_after("export", pipeline.tester.dump_dtype_distribution, False) + pipeline.add_stage_after( + "export", pipeline.tester.dump_operator_distribution, False + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_dtype_distribution, False + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.dump_operator_distribution, False + ) + pipeline.run() + # Just test that there are no execptions. + + +"""Tests the collation of TOSA tests through setting the environment variable TOSA_TESTCASE_BASE_PATH.""" + + +@common.parametrize("test_data", Linear.inputs) +def test_collate_tests_tosa_INT(test_data: input_t1): + # Set the environment variable to trigger the collation of TOSA tests + os.environ["TOSA_TESTCASES_BASE_PATH"] = "test_collate_tosa_tests" + # Clear out the directory + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + test_collate_dir = ( + "test_collate_tosa_tests/tosa-int/test_collate_tests_tosa_INT[randn]" + ) + # test that the output directory is created and contains the expected files + assert os.path.exists(test_collate_dir) + for file in os.listdir(test_collate_dir): + file_name_prefix = "TOSA-1.0+INT" + assert file.endswith((f"{file_name_prefix}.json", f"{file_name_prefix}.tosa")) + + os.environ.pop("TOSA_TESTCASES_BASE_PATH") + shutil.rmtree("test_collate_tosa_tests", ignore_errors=True) + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_tosa_debug_json_tosa_INT(test_data: input_t1): + with tempfile.TemporaryDirectory() as tmpdir: + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + module=Linear(), + test_data=test_data, + aten_op=aten_ops, + exir_op=exir_ops, + custom_path=tmpdir, + tosa_debug_mode=ArmCompileSpec.DebugMode.JSON, + ) + + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + json_output_path = Path(tmpdir) / "debug.json" + + # The file should exist + assert json_output_path.exists() + + # Check the file is valid JSON and can be loaded + with json_output_path.open("r") as file: + try: + data = json.load(file) + + # Check it's not empty + assert data + except json.JSONDecodeError: + pytest.fail("Failed to load debug JSON file") + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_tosa_debug_tosa_FP(test_data: input_t1): + output_dir = "test_dump_tosa_debug" + + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1]( + module=Linear(), + test_data=test_data, + use_to_edge_transform_and_lower=True, + aten_op=aten_ops, + exir_op=exir_ops, + custom_path=output_dir, + tosa_debug_mode=ArmCompileSpec.DebugMode.TOSA, + ) + + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + output_path = Path(output_dir) + json_output_path = output_path / "debug.json" + + # A JSON file should not be created when TOSA mode used + assert not json_output_path.exists() + + # At least one TOSA file should exist + tosa_files = list(output_path.glob("*.tosa")) + assert len(tosa_files) > 0 + + tosa_file = tosa_files[0] + with tosa_file.open("rb") as f: + tosa_json = dbg_tosa_fb_to_json(f.read()) + + # Check all non-empty JSON strings are valid + ops = tosa_json["regions"][0]["blocks"][0]["operators"] + for op in ops: + if op["location"]["text"]: + try: + json.loads(op["location"]["text"]) + except json.JSONDecodeError: + pytest.fail("Failed to load debug JSON string") + + shutil.rmtree(output_dir, ignore_errors=True) + + +@common.parametrize("test_data", Linear.inputs) +def test_dump_tosa_ops_tosa_INT(capsys, test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1](Linear(), test_data, aten_ops, exir_ops) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.dump_operator_distribution("to_edge_transform_and_lower") + pipeline.run() + assert "TOSA operators:" in capsys.readouterr().out + + +class Add(torch.nn.Module): + inputs = { + "ones": (torch.ones(5),), + } + + def forward(self, x): + return x + x + + +@common.parametrize("test_data", Add.inputs) +@common.XfailIfNoCorstone300 +def test_fail_dump_ops_u55_INT(capsys, test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = EthosU55PipelineINT[input_t1]( + Add(), test_data, aten_ops, exir_ops, use_to_edge_transform_and_lower=True + ) + pipeline.dump_operator_distribution("to_edge_transform_and_lower") + error_msg = "Can not get operator distribution for Vela command stream." + with pytest.raises(NotImplementedError, match=error_msg): + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_hook.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_hook.py new file mode 100644 index 0000000..2dfe130 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_debug_hook.py @@ -0,0 +1,186 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass +from types import SimpleNamespace +from typing import cast + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.debug.schema import DebugHook, DebugSchema +from executorch.backends.arm.test import common + +from torch.fx import Node + + +@dataclass +class DebugHookTestCase: + mock_node: SimpleNamespace + tosa_op: str + op_id: int + expected_events: int + num_nodes_traced: int + + +def create_mock_node_1(): + def _get_action_str() -> str: + return "create" + + from_node_2 = SimpleNamespace( + name="convolution", + target="aten.convolution.default", + graph_id=6052414368, + pass_name="ExportedProgram.module()", # nosec B106 - static test string, not a secret + action="create", + from_node=[], + _get_action_string=_get_action_str, + ) + + from_node_1 = SimpleNamespace( + name="convolution", + target="aten.convolution.default", + graph_id=5705954832, + pass_name="Interpreter_PropagateUnbackedSymInts", # nosec B106 - static test string, not a secret + action="create", + from_node=[from_node_2], + _get_action_string=_get_action_str, + ) + + fx_node_mock = SimpleNamespace( + name="aten_convolution_default", + target="aten.convolution.default", + meta={ + "stack_trace": 'File "models/model.py", line 221, in forward\nreturn self.features(x)', + "nn_module_stack": {"__self__": ["", "model.Model"]}, + "torch_fn": ("conv2d", "builtin_function_or_method.conv2d"), + "from_node": [from_node_1], + }, + ) + + return fx_node_mock + + +def create_mock_node_2(): + def _get_action_str() -> str: + return "create" + + from_node_1 = SimpleNamespace( + name="convolution", + target="aten.convolution.default", + graph_id=5705954832, + pass_name="Interpreter_PropagateUnbackedSymInts", # nosec B106 - static test string, not a secret + action="create", + from_node=[], + _get_action_string=_get_action_str, + ) + + fx_node_mock = SimpleNamespace( + name="aten_convolution_default", + target="aten.convolution.default", + meta={ + "from_node": [from_node_1], + }, + ) + + return fx_node_mock + + +def create_mock_node_3(): + fx_node_mock = SimpleNamespace( + name="aten_convolution_default", + target="aten.convolution.default", + meta={ + "from_node": [], + }, + ) + + return fx_node_mock + + +def _compare_tosa_and_schema(debug_event: DebugSchema, tosa_op: str) -> None: + tosa_info = debug_event.tosa_info + assert tosa_info is not None + assert tosa_info.node_name == tosa_op + + # The mapping between op_ids to operator names could change + # So just check operator_name is a string + assert isinstance(tosa_info.operator_name, str) + + +def _compare_node_and_schema(debug_event: DebugSchema, mocked_node): + # Check aten info + aten_info = debug_event.aten_info + + assert aten_info.node_name == mocked_node.name + assert aten_info.operator_name == mocked_node.target + + # Check torch info + torch_info = debug_event.torch_info + + if "nn_module_stack" in mocked_node.meta: + assert torch_info.nn_module_stack == mocked_node.meta["nn_module_stack"] + else: + assert torch_info.nn_module_stack == "No module stack trace available" + + if "stack_trace" in mocked_node.meta: + assert torch_info.stack_trace == mocked_node.meta["stack_trace"].split("\n") + else: + assert torch_info.stack_trace == ["No stack trace available"] + + if "torch_fn" in mocked_node.meta: + assert torch_info.torch_fn == mocked_node.meta["torch_fn"] + else: + assert torch_info.torch_fn == "No torch_fn available" + + +TESTCASES = { + "mocked_node": DebugHookTestCase( + mock_node=create_mock_node_1(), + tosa_op="layer-1", + op_id=3, + expected_events=1, + num_nodes_traced=2, + ), + "mocked_node_partially_empty": DebugHookTestCase( + mock_node=create_mock_node_2(), + tosa_op="layer-1", + op_id=1, + expected_events=1, + num_nodes_traced=1, + ), + "mocked_node_all_empty": DebugHookTestCase( + mock_node=create_mock_node_3(), + tosa_op="layer-2", + op_id=1, + expected_events=1, + num_nodes_traced=0, + ), +} + + +@common.parametrize("test_data", TESTCASES) +def test_debug_hook_add_json_no_target(test_data: DebugHookTestCase): + hook = DebugHook(ArmCompileSpec.DebugMode.JSON) + hook.add(cast(Node, test_data.mock_node), test_data.tosa_op, test_data.op_id) + + debug_events = hook._debug_events + assert len(debug_events) == test_data.expected_events + assert len(debug_events[0].torch_info.node_trace) == test_data.num_nodes_traced + + _compare_tosa_and_schema(debug_events[0], test_data.tosa_op) + _compare_node_and_schema(debug_events[0], test_data.mock_node) + + +@common.parametrize("test_data", TESTCASES) +def test_debug_hook_add_tosa_no_target(test_data: DebugHookTestCase): + hook = DebugHook(ArmCompileSpec.DebugMode.TOSA) + hook.add(cast(Node, test_data.mock_node), test_data.tosa_op, test_data.op_id) + + debug_events = hook._debug_events + assert len(debug_events) == test_data.expected_events + assert len(debug_events[0].torch_info.node_trace) == test_data.num_nodes_traced + + assert debug_events[0].tosa_info is None + + _compare_node_and_schema(debug_events[0], test_data.mock_node) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dim_order.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dim_order.py new file mode 100644 index 0000000..14e1246 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dim_order.py @@ -0,0 +1,127 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + + +input_t1 = Tuple[torch.Tensor, ...] # Input x + + +class ChannelsLastInput(torch.nn.Module): + """ + Test a complex case with (channels last, channels first) input, + and (channels first, channels last) output. + """ + + inputs: input_t1 = ( + torch.arange(1, 25, dtype=torch.float32) + .reshape((1, 2, 3, 4)) + .to(memory_format=torch.channels_last), + torch.arange(1, 25, dtype=torch.float32).reshape((1, 2, 3, 4)), + ) + + def forward(self, x, y): + x = x * x + return y, x + + +class ChannelsFirstOutput(torch.nn.Module): + """ + Test coverting to channels_first inside the delegate. + """ + + inputs: input_t1 = ( + torch.arange(1, 25, dtype=torch.float32) + .reshape((1, 2, 3, 4)) + .to(memory_format=torch.channels_last), + ) + + def forward(self, x): + x = x.clone(memory_format=torch.contiguous_format) * x + return x + + +class ChannelsLastOutput(torch.nn.Module): + """ + Test changing of dim_order inside the delegate. + """ + + inputs: input_t1 = (torch.arange(1, 9, dtype=torch.float32).reshape((1, 2, 2, 2)),) + + def forward(self, x): + x = x * x + x = x.clone(memory_format=torch.channels_last) + return x + + +class ChannelsLastInsidePartition(torch.nn.Module): + """ + Test dim_order changes inside the partiton, but no dim_order changes at input/output. + """ + + inputs: input_t1 = (torch.randn((1, 2, 3, 3)),) + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d(in_channels=2, out_channels=2, kernel_size=(3, 3)) + + def forward(self, x): + return ( + self.conv2d(x.clone(memory_format=torch.channels_last)).clone( + memory_format=torch.contiguous_format + ) + * 1 + ) + + +test_modules = { + "channels_last_input": ChannelsLastInput, + "channels_first_output": ChannelsFirstOutput, + "channels_last_output": ChannelsLastOutput, + "channels_last_inside_partition": ChannelsLastInsidePartition, +} + + +@common.parametrize("module", test_modules) +def test_dim_order_tosa_FP(module) -> None: + aten_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1](module(), module.inputs, aten_ops) + pipeline.run() + + +@common.parametrize("module", test_modules) +def test_dim_order_tosa_INT(module) -> None: + aten_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + module(), module.inputs, aten_ops, symmetric_io_quantization=True + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("module", test_modules) +def test_dim_order_u55_INT(module) -> None: + aten_ops: list[str] = [] + pipeline = EthosU55PipelineINT[input_t1](module(), module.inputs, aten_ops) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("module", test_modules) +def test_dim_order_u85_INT(module) -> None: + aten_ops: list[str] = [] + pipeline = EthosU85PipelineINT[input_t1](module(), module.inputs, aten_ops) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dw_convs_with_shared_weights.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dw_convs_with_shared_weights.py new file mode 100644 index 0000000..9e09185 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_dw_convs_with_shared_weights.py @@ -0,0 +1,46 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, Tuple + +import torch +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor] + + +class DWConvsModule(torch.nn.Module): + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + conv = torch.nn.Conv2d(6, 6, kernel_size=(2, 2), groups=6) + relu = torch.nn.ReLU() + self.sequential = torch.nn.ModuleList([conv, relu, conv]) + + def forward(self, x) -> torch.Tensor: + for m in self.sequential: + x = m(x) + return x + + def get_inputs(self) -> input_t: + return (torch.randn(1, 6, 24, 24),) + + +def test_convs_tosa_FP(): + module = DWConvsModule() + pipeline = TosaPipelineFP[input_t]( + module, module.get_inputs(), aten_op=[], exir_op=[] + ) + pipeline.run() + + +def test_convs_tosa_INT(): + module = DWConvsModule() + pipeline = TosaPipelineINT[input_t]( + module, module.get_inputs(), aten_op=[], exir_op=[] + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_extract_io_params_tosa.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_extract_io_params_tosa.py new file mode 100644 index 0000000..229970b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_extract_io_params_tosa.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import copy + +import pytest +import torch +from executorch.backends.arm.quantizer import VgfQuantizer +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test.common import SkipIfNoModelConverter +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.vgf import VgfCompileSpec, VgfPartitioner +from executorch.exir import to_edge_transform_and_lower +from executorch.exir.passes.quantize_io_pass import extract_io_quant_params +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + + +class SimpleAdd(torch.nn.Module): + def forward(self, x, y): + return x + y + + +@pytest.mark.parametrize( + "compile_spec_cls, quantizer_cls, partitioner_cls", + [ + (TosaCompileSpec, TOSAQuantizer, TOSAPartitioner), + pytest.param( + VgfCompileSpec, + VgfQuantizer, + VgfPartitioner, + marks=SkipIfNoModelConverter, + id="VGF", + ), + ], +) +def test_roundtrip_extracts_io_params_tosa_INT( + compile_spec_cls: type[TosaCompileSpec] | type[VgfCompileSpec], + quantizer_cls, + partitioner_cls, +): + """ + Validates that IO quantization parameters round-trip for both flows. + """ + example_inputs = ( + torch.ones(1, 5), + torch.full((1, 5), 2.0), + ) + mod = SimpleAdd().eval() + + compile_spec = compile_spec_cls("TOSA-1.0+INT") + + quantizer = quantizer_cls(compile_spec) + operator_config = get_symmetric_quantization_config(is_qat=True) + quantizer.set_global(operator_config) + + exported = torch.export.export(mod, copy.deepcopy(example_inputs), strict=True) + prepared = prepare_pt2e(exported.module(), quantizer) + _ = prepared(*example_inputs) + + converted = convert_pt2e(prepared) + final_export = torch.export.export(converted, example_inputs, strict=True) + partitioner = partitioner_cls(compile_spec) + edge_prog = to_edge_transform_and_lower(final_export, partitioner=[partitioner]) + + # Extract IO quantization parameters + q = extract_io_quant_params( + edge_prog, + input_idxs=(0, 1), + output_idxs=(0,), + ) + + assert "inputs" in q + assert "outputs" in q + assert len(q["inputs"]) == 2 + assert len(q["outputs"]) == 1 + + for name, params in q["inputs"].items(): + assert isinstance(name, str) + assert isinstance(params["scale"], float) + assert isinstance(params["zero_point"], int) + + out_name, out_params = next(iter(q["outputs"].items())) + assert isinstance(out_name, str) + assert isinstance(out_params["scale"], float) + assert isinstance(out_params["zero_point"], int) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_int64.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_int64.py new file mode 100644 index 0000000..46a97ff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_int64.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.arm_tester import ArmTester + + +class ConstAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype, bias=0): + super().__init__() + self.dtype = dtype + self.bias = bias + + def forward(self, x: torch.Tensor): + c = torch.arange(self.bias, self.bias + 10, 1, dtype=self.dtype) + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +class BufferAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype, bias=0): + super().__init__() + self.dtype = dtype + self.buffer = torch.arange(0, 10, 1, dtype=self.dtype) + bias + self.bias = bias + + def forward(self, x: torch.Tensor): + c = self.buffer + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +class ConstChainAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype): + super().__init__() + self.dtype = dtype + + def forward(self, x: torch.Tensor): + c = torch.arange(0, 10, 1, dtype=self.dtype).reshape((2, 5)).unsqueeze(-1) + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +class BufferChainAdd(torch.nn.Module): + def __init__(self, dtype: torch.dtype): + super().__init__() + self.dtype = dtype + self.buffer = torch.arange(0, 10, 1, dtype=self.dtype) + + def forward(self, x: torch.Tensor): + c = self.buffer.reshape((2, 5)).unsqueeze(-1) + # Add explicit float cast to make quantization work, will be inserted by type promotion otherwise. + return x + c.to(torch.float32) + + +test_data_suite = { + "fp32_in+int64_buffer": (BufferAdd(torch.int64), (torch.rand(10) - 0.5,)), + "fp32_in+int64_buffer_overflow": ( + BufferAdd(torch.int64, 2**40), + (torch.rand(10) - 0.5,), + ), + "fp32_in+int64_const": (ConstAdd(torch.int64), (torch.rand(10) - 0.5,)), + "fp32_in+int64_const_overflow": ( + ConstAdd(torch.int64, 2**40), + (torch.rand(10) - 0.5,), + ), + "fp32_in+int64_buffer_chain": ( + BufferChainAdd(torch.int64), + (torch.rand(2, 5, 3) - 0.5,), + ), + "fp32_in+int64_const_chain": ( + ConstChainAdd(torch.int64), + (torch.rand(2, 5, 3) - 0.5,), + ), + "int64_in+float_const_chain": ( + ConstChainAdd(torch.float32), + (torch.randint(0, 10, (2, 5, 3)),), + ), +} + + +@common.parametrize("test_data", test_data_suite) +def test_int64_tosa_FP(test_data: Tuple): + model, inputs = test_data + ( + ArmTester( + model, + inputs, + common.get_tosa_compile_spec("TOSA-1.0+FP"), + ) + .export() + .to_edge_transform_and_lower() + .to_executorch() + .run_method_and_compare_outputs(inputs) + ) + + +@common.parametrize("test_data", test_data_suite) +def test_int64_tosa_INT(test_data: Tuple): + model, inputs = test_data + ( + ArmTester(model, inputs, common.get_tosa_compile_spec("TOSA-1.0+INT")) + .quantize() + .export() + .to_edge_transform_and_lower() + .to_executorch() + .run_method_and_compare_outputs(inputs) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_lifted_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_lifted_tensor.py new file mode 100644 index 0000000..ee9812b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_lifted_tensor.py @@ -0,0 +1,146 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import operator +from collections.abc import Callable +from typing import Union + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) +from executorch.backends.test.harness.stages import StageType + + +LiftedTensorInputs = tuple[torch.Tensor, int] +LiftedTensorCase = tuple[ + Callable[[torch.Tensor, torch.Tensor], torch.Tensor], + LiftedTensorInputs, +] +LiftedScalarTensorInputs = tuple[torch.Tensor, ...] +LiftedScalarTensorCase = tuple[ + Callable[[torch.Tensor, Union[float, int, torch.Tensor]], torch.Tensor], + LiftedScalarTensorInputs, + Union[float, int, torch.Tensor], +] + + +class LiftedTensor(torch.nn.Module): + + test_data: dict[str, LiftedTensorCase] = { + # test_name: (operator, test_data, length) + "add": (operator.add, (torch.randn(2, 2), 2)), + "truediv": (operator.truediv, (torch.ones(2, 2), 2)), + "mul": (operator.mul, (torch.randn(2, 2), 2)), + "sub": (operator.sub, (torch.rand(2, 2), 2)), + } + + def __init__(self, op: callable): # type: ignore[valid-type] + super().__init__() + self.op = op + self.lifted_tensor = torch.Tensor([[1, 2], [3, 4]]) + + def forward(self, x: torch.Tensor, length) -> torch.Tensor: + sliced = self.lifted_tensor[:, :length] + return self.op(sliced, x) # type: ignore[misc] + + +class LiftedScalarTensor(torch.nn.Module): + test_data: dict[str, LiftedScalarTensorCase] = { + # test_name: (operator, test_data) + "add": (operator.add, (torch.randn(2, 2),), 1.0), + "truediv": (operator.truediv, (torch.randn(4, 2),), 1.0), + "mul": (operator.mul, (torch.randn(1, 2),), 2.0), + "sub": (operator.sub, (torch.randn(3),), 1.0), + } + + def __init__(self, op: callable, arg1: Union[int, float, torch.tensor]): # type: ignore[valid-type] + super().__init__() + self.op = op + self.arg1 = arg1 + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.op(x, self.arg1) # type: ignore[misc] + + +"""Tests the ArmPartitioner with a placeholder of type lifted tensor.""" + + +@common.parametrize("test_data", LiftedTensor.test_data) +def test_partition_lifted_tensor_tosa_FP(test_data: LiftedTensorCase) -> None: + op, inputs = test_data + module = LiftedTensor(op) + aten_ops: list[str] = [] + pipeline = TosaPipelineFP[LiftedTensorInputs]( + module, + inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + signature = ( + pipeline.tester.stages[StageType.TO_EDGE] + .artifact.exported_program() + .graph_signature + ) + assert len(signature.lifted_tensor_constants) > 0 + + +@common.parametrize("test_data", LiftedTensor.test_data) +def test_partition_lifted_tensor_tosa_INT(test_data: LiftedTensorCase) -> None: + op, inputs = test_data + module = LiftedTensor(op) + aten_ops: list[str] = [] + pipeline = TosaPipelineINT[LiftedTensorInputs]( + module, + inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + signature = ( + pipeline.tester.stages[StageType.TO_EDGE] + .artifact.exported_program() + .graph_signature + ) + assert len(signature.lifted_tensor_constants) == 0 + + +@common.parametrize("test_data", LiftedScalarTensor.test_data) +def test_partition_lifted_scalar_tensor_tosa_FP( + test_data: LiftedScalarTensorCase, +) -> None: + op, tensor_inputs, scalar_arg = test_data + module = LiftedScalarTensor(op, scalar_arg) + aten_ops: list[str] = [] + pipeline = TosaPipelineFP[LiftedScalarTensorInputs]( + module, + tensor_inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LiftedScalarTensor.test_data) +def test_partition_lifted_scalar_tensor_tosa_INT( + test_data: LiftedScalarTensorCase, +) -> None: + op, tensor_inputs, scalar_arg = test_data + module = LiftedScalarTensor(op, scalar_arg) + aten_ops: list[str] = [] + pipeline = TosaPipelineINT[LiftedScalarTensorInputs]( + module, + tensor_inputs, + aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_mixed_type_lowering.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_mixed_type_lowering.py new file mode 100644 index 0000000..6a2a1e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_mixed_type_lowering.py @@ -0,0 +1,83 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from collections import Counter, defaultdict + +import torch +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT + + +def combine_op_dicts(*dicts): + merged = defaultdict(Counter) + for d in dicts: + for op, dtypes in d.items(): + merged[op].update(dtypes) + return {op: dict(counts) for op, counts in merged.items()} + + +def repeat_op_dict(op_dict, times): + repeated = {} + for op, dtypes in op_dict.items(): + repeated[op] = {dtype: count * times for (dtype, count) in dtypes.items()} + return repeated + + +# TODO Figure out how to handle multiple dq/q nodes properly +# See backends/arm/_passes/decompose_quant_nodes.py for details +dq_tosa_ops = { + "CAST": {"FP32": 1, "INT32": 1}, + "SUB": {"INT32": 1}, # zero-point subtraction + "MUL": {"FP32": 1}, # scale multiplication +} +q_tosa_ops = { + "CAST": {"INT8": 1}, + "MUL": {"FP32": 1}, # scale multiplication + "ADD": {"FP32": 2}, # zero-point addition, rounding + "SUB": {"FP32": 1}, # for rounding + "CLAMP": {"FP32": 1}, # clamp + "GREATER_EQUAL": {"BOOL": 1}, # for rounding + "SELECT": {"FP32": 1}, # for rounding + "CEIL": {"FP32": 1}, # for rounding + "FLOOR": {"FP32": 1}, # for rounding +} + + +class AddSigmoidMul(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x, y): + return self.sigmoid(x + y) * x + + +def test_mixed_type_lowering_tosa_INT_FP(): + model = AddSigmoidMul() + input_data = (torch.randn(1, 16, 16, 16), torch.randn(1, 16, 16, 16)) + + pipeline = TosaPipelineINT[type(input_data)]( + model, input_data, [], [], qtol=1, tosa_extensions=["FP"] + ) + pipeline.quantizer.set_module_type(torch.nn.Sigmoid, None) + expected_tosa_dtype_counts = combine_op_dicts( + { + "SIGMOID": {"FP32": 1}, # SIGMOID should be executed in FP32 + "ADD": {"INT32": 1}, # ADD should be executed in INT32 + "MUL": {"INT32": 1}, # MUL should be executed in INT32 + }, + repeat_op_dict( + q_tosa_ops, 3 + ), # Two decomposed boundary Q nodes + one for SIGMOID + repeat_op_dict( + dq_tosa_ops, 2 + ), # One decomposed boundary DQ nodes + one for SIGMOID + ) + + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + expected_tosa_dtype_counts, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_model_evaluator.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_model_evaluator.py new file mode 100644 index 0000000..d9b8659 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_model_evaluator.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import tempfile +import unittest + +import torch +from executorch.backends.arm.util.arm_model_evaluator import GenericModelEvaluator + +# Create an input that is hard to compress +COMPRESSION_RATIO_TEST = torch.rand([1024, 1024]) + + +def mocked_model_1(input: torch.Tensor) -> torch.Tensor: + return torch.tensor([1.0, 2.0, 3.0, 4.0]) + + +def mocked_model_2(input: torch.Tensor) -> torch.Tensor: + return torch.tensor([1.0, 2.0, 3.0, 3.0]) + + +class TestGenericModelEvaluator(unittest.TestCase): + """Tests the GenericModelEvaluator class.""" + + def test_get_model_error_no_target(self): + example_input = torch.tensor([[1.0, 2.0, 3.0, 4.0]]) + evaluator = GenericModelEvaluator( + "dummy_model", + mocked_model_1, + mocked_model_2, + example_input, + "tmp/output_tag0.tosa", + ) + + model_error_dict = evaluator.get_model_error() + + self.assertEqual(model_error_dict["max_error"], [1.0]) + self.assertEqual(model_error_dict["max_absolute_error"], [1.0]) + self.assertEqual(model_error_dict["max_percentage_error"], [25.0]) + self.assertEqual(model_error_dict["mean_absolute_error"], [0.25]) + + def test_get_compression_ratio_no_target(self): + with tempfile.NamedTemporaryFile(delete=True) as temp_bin: + torch.save(COMPRESSION_RATIO_TEST, temp_bin) + + example_input = torch.tensor([[1.0, 2.0, 3.0, 4.0]]) + evaluator = GenericModelEvaluator( + "dummy_model", + mocked_model_1, + mocked_model_2, + example_input, + temp_bin.name, + ) + + ratio = evaluator.get_compression_ratio() + self.assertAlmostEqual(ratio, 1.1, places=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_delegates.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_delegates.py new file mode 100644 index 0000000..bbc0b2b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_delegates.py @@ -0,0 +1,53 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class MultipleDelegatesModule(torch.nn.Module): + inputs = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + z = x + y + s = torch.max(z) + return s * z + + +@common.parametrize("test_data", MultipleDelegatesModule.inputs) +def test_multiple_delegates_tosa_FP(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1]( + MultipleDelegatesModule(), test_data, aten_ops, exir_ops + ) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleDelegatesModule.inputs) +def test_multiple_delegates_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + MultipleDelegatesModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_outputs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_outputs.py new file mode 100644 index 0000000..6160bf4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_multiple_outputs.py @@ -0,0 +1,70 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class MultipleOutputsModule(torch.nn.Module): + inputs: dict[str, input_t1] = { + "randn": (torch.randn(10, 4, 5), torch.randn(10, 4, 5)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return (x * y, x.sum(dim=-1, keepdim=True)) + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +def test_multiple_outputs_tosa_FP(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineFP[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +def test_multiple_outputs_tosa_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = TosaPipelineINT[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +@common.XfailIfNoCorstone300 +def test_multiple_outputs_u55_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = EthosU55PipelineINT[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", MultipleOutputsModule.inputs) +@common.XfailIfNoCorstone320 +def test_multiple_outputs_u85_INT(test_data: input_t1): + aten_ops: list[str] = [] + exir_ops: list[str] = [] + pipeline = EthosU85PipelineINT[input_t1]( + MultipleOutputsModule(), test_data, aten_ops, exir_ops, qtol=1 + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_non_persistent_buffers.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_non_persistent_buffers.py new file mode 100644 index 0000000..374eb0a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_non_persistent_buffers.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn as nn + +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +class NonPersistentBuffer(nn.Module): + """ + Min code version registering a non-persistent input buffer. + """ + + def __init__(self): + super().__init__() + self.register_buffer("test_buff", torch.rand(2, 2, 2, 2), persistent=False) + + def forward(self, x): + return x - self.test_buff + + +test_input = {"input": (torch.ones(2, 2, 2, 2),)} + +input_t = tuple[torch.Tensor] + + +@parametrize("test_data", test_input) +def test_non_persistent_buffer_tosa_FP(test_data: input_t): + """ + Test validates Arm backend handling of non-persistent buffers + and ensures that there are no asserts or errors when they are used. + """ + TosaPipelineFP[input_t](NonPersistentBuffer(), test_data, "").run() + + +@parametrize("test_data", test_input) +def test_non_persistent_buffer_tosa_INT(test_data: input_t): + """ + Test validates Arm backend handling of non-persistent buffers + and ensures that there are no asserts or errors when they are used. + """ + TosaPipelineINT[input_t](NonPersistentBuffer(), test_data, "").run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_outputs_order.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_outputs_order.py new file mode 100644 index 0000000..f241b9a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_outputs_order.py @@ -0,0 +1,122 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +import importlib +import tempfile +from pathlib import Path +from typing import Any + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.exir import to_edge_transform_and_lower +from torch import nn +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + +_TOSA_GRAPH: Any = importlib.import_module("tosa.TosaGraph") + + +class Network(nn.Module): + def __init__(self, batch_norm=False): + super().__init__() + self.conv2d_0 = nn.Sequential( + nn.Conv2d(1, 8, 3, padding=1, bias=False), + nn.BatchNorm2d(8) if batch_norm else nn.Identity(), + nn.ReLU(), + ) + self.conv2d_1 = nn.Sequential( + nn.Conv2d(8, 8, 3, padding=1, bias=False), + nn.BatchNorm2d(8) if batch_norm else nn.Identity(), + nn.ReLU(), + ) + self.conv2d_2 = nn.Sequential( + nn.Conv2d(8, 8, 3, padding=1, bias=False), + nn.BatchNorm2d(8) if batch_norm else nn.Identity(), + nn.ReLU(), + ) + self.out_0 = nn.Sequential(nn.Conv2d(8, 1, 3, padding=1, bias=False), nn.ReLU()) + self.out_1 = nn.Sequential(nn.Conv2d(8, 2, 3, padding=1, bias=False), nn.ReLU()) + self.out_2 = nn.Sequential(nn.Conv2d(8, 3, 3, padding=1, bias=False), nn.ReLU()) + + def forward(self, x): + x = self.conv2d_0(x) + x = self.conv2d_1(x) + x = self.conv2d_2(x) + out0 = self.out_0(x) + out1 = self.out_1(x) + out2 = self.out_2(x) + return out0, out1, out2 + + +def _read_tosa_outputs(tosa_path: Path): + # Find output tensor names in order and return shapes + buf = tosa_path.read_bytes() + buf_arr = bytearray(buf) + graph = _TOSA_GRAPH.TosaGraph.GetRootAsTosaGraph(buf_arr, 0) + region = graph.Regions(0) + block = region.Blocks(0) + # Build a dict name - tensor‑shape + tensors = {} + for i in range(block.TensorsLength()): + t = block.Tensors(i) + name = t.Name().decode() + # NHWC + shape = [t.Shape(j) for j in range(t.ShapeLength())] + tensors[name] = shape + shapes = [] + for i in range(block.OutputsLength()): + out_name = block.Outputs(i).decode() + shapes.append(tensors[out_name]) + return shapes + + +# TODO: MLETORCH-1266 Investigate output order issue +@pytest.mark.parametrize("batch_size", [1, 4]) +@pytest.mark.parametrize("output_order_workaround", [True, False]) +def test_network_output_order_and_restore_tosa_INT(batch_size, output_order_workaround): + model = Network(batch_norm=True).eval() + # Prepare spec + spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + tosa_compile_spec = TosaCompileSpec(spec).set_output_order_workaround( + output_order_workaround + ) + # Setup quantizer + quantizer = TOSAQuantizer(tosa_compile_spec) + quantizer.set_global( + get_symmetric_quantization_config(is_qat=True, is_per_channel=False) + ) + # Trace the model + dummy = torch.randn(batch_size, 1, 28, 28) + fx_mod = torch.export.export(model, (dummy,)).module() + model = prepare_pt2e(fx_mod, quantizer) + model(dummy) + model = convert_pt2e(model) + # Export to aten dialect + aten_gm = torch.export.export(model, args=(dummy,), strict=True) + with tempfile.TemporaryDirectory(dir="") as tmpdir: + art_dir = Path(tmpdir) + part = TOSAPartitioner( + tosa_compile_spec.dump_intermediate_artifacts_to(str(art_dir)) + ) + _ = to_edge_transform_and_lower(aten_gm, partitioner=[part]) + # Expect exactly one .tosa file in the artefact dir + tosa_files = list(art_dir.glob("*.tosa")) + assert ( + len(tosa_files) == 1 + ), f"Expected 1 .tosa artefact, found {len(tosa_files)} in {art_dir}" + out_shapes = _read_tosa_outputs(tosa_files[0]) + # We use shape that is unique to output to check + # that we preserve output order + channel_dims = [s[1] for s in reversed(out_shapes)] + assert channel_dims == [1, 2, 3], ( + "Outputs in .tosa do not keep author order: " + f"expected [1, 2, 3], got {channel_dims}" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py new file mode 100644 index 0000000..0514ad5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_partition_decomposed_quantized_ops.py @@ -0,0 +1,181 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Test that tosa_supported_operators reject operators that are not +# quantized properly. This is typically a consequence of a torch op +# such a Softplus that is decompsed into many other ops without +# surrounding q/dq nodes. + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +input_t1 = tuple[torch.Tensor, ...] +softplus_aten_op: list[str] = [ + "torch.ops.aten.add.Tensor", + "torch.ops.aten.softplus.default", +] +softplus_exir_op: list[str] = [ + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_exp_default", + "executorch_exir_dialects_edge__ops_aten_div_Tensor", +] + +linear_residual_aten_op: list[str] = [ + "torch.ops.aten.linear.default", + "torch.ops.aten.gelu.default", + "torch.ops.aten.dropout.default", + "torch.ops.aten.add.Tensor", +] +linear_residual_exir_op: list[str] = [ + "executorch_exir_dialects_edge__ops_aten_gelu_default", + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default", + "executorch_exir_dialects_edge__ops_aten_linear_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", +] + + +test_data: dict[str, input_t1] = { + "3d_rand": (torch.rand(1, 5, 5),), +} + + +class SoftplusModule(torch.nn.Module): + """Module containing an addition followed by a Softplus. Softplus is currently not supported by TosaBackend.""" + + def __init__(self): + super().__init__() + self.softplus = torch.nn.Softplus() + + def forward(self, x: torch.Tensor): + return self.softplus(x + x) + + +class LinearResidualModule(torch.nn.Module): + """Module containing a residual and a linear layer followed by GELU and a Dropout. + GELU is currently not supported by TosaBackend nor TosaQuantizer. + """ + + def __init__( + self, + ): + super().__init__() + self.linear = torch.nn.Linear(in_features=5, out_features=3) + self.gelu = torch.nn.GELU() + self.dropout = torch.nn.Dropout(0.5) + + def forward(self, x: torch.Tensor): + x1 = self.linear(x) + x2 = self.gelu(x1) + x3 = self.dropout(x2) + return x1 + x3 + + +# Softplus is decomposed which messes up the quantization. This test tests that CheckProperQuantization does not +# partition nodes where quantization is not as expected. +@common.parametrize("test_data", test_data) +def test_softplus_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SoftplusModule(), + test_data=test_data, + aten_op=softplus_aten_op, + exir_op=softplus_exir_op, + ) + # remove check_count.exir as there will be more than one delegate + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_softplus_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + SoftplusModule(), + test_data=test_data, + aten_op=softplus_aten_op, + exir_op=softplus_exir_op, + ) + pipeline.pop_stage("check_not.exir") + # check that all ops in softplus_exir_op except add are rejected + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check, + softplus_exir_op[1:], + suffix="exir_post_partition", + ) + pipeline.run() + + +# Since GELU will not be quantized by TosaQuantizer, the Dropout's input will not be quantized either. +# If so, the Dropout should not be partitioned by TosaPartitioner for TOSA INT profile. This test tests that the +# partitioner indeed does not partition the Dropout (clone) for TOSA INT. +@common.parametrize( + "test_data", + test_data, + {"3d_rand": "MLETORCH-909: Partition test to not rely on unsupported ops"}, + strict=False, +) +def test_linear_residaul_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + LinearResidualModule(), + test_data=test_data, + aten_op=linear_residual_aten_op, + exir_op=linear_residual_exir_op, + use_to_edge_transform_and_lower=True, + ) + # remove check_count.exir as there will be more than one delegate + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("check_not.exir") + # check that all ops in linear_residual_exir_op except GELU are partitioned + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_not, + linear_residual_exir_op[1:], + suffix="exir_post_partition", + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check, + linear_residual_exir_op[:1], + suffix="exir_post_partition", + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data, + {"3d_rand": "MLETORCH-855: Issue with Quantization folding."}, + strict=False, +) +def test_linear_residual_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + LinearResidualModule(), + test_data=test_data, + aten_op=linear_residual_aten_op, + exir_op=linear_residual_exir_op, + use_to_edge_transform_and_lower=True, + ) + # remove check_count.exir as there will be more than one delegate + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("check_not.exir") + # check that all ops in linear_residual_exir_op except GELU and Dropout are partitioned + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_not, + linear_residual_exir_op[2:], + suffix="exir_post_partition", + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check, + linear_residual_exir_op[:2], + suffix="exir_post_partition", + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_pipeline_config.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_pipeline_config.py new file mode 100644 index 0000000..6a031bf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_pipeline_config.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm._passes import ( + DecomposeSoftmaxUnstablePass, + FuseDuplicateUsersPass, +) +from executorch.backends.arm._passes.arm_pass_manager import ArmPassManager +from executorch.backends.arm.common.pipeline_config import ArmPassPipelineConfig +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.specification import TosaSpecification + + +def test_pipeline_config_override_outside_compile_spec_no_target(): + compile_spec = TosaCompileSpec( + TosaSpecification.create_from_string("TOSA-1.00+INT") + ) + default_manager = ArmPassManager(compile_spec) + default_skip_passes = default_manager._skip_pass_types + assert FuseDuplicateUsersPass not in default_skip_passes + assert DecomposeSoftmaxUnstablePass in default_skip_passes + + override_compile_spec = TosaCompileSpec( + TosaSpecification.create_from_string("TOSA-1.00+INT") + ) + override_config = ArmPassPipelineConfig() + override_config.disable_fuse_duplicate_users() + override_compile_spec.set_pass_pipeline_config(override_config) + override_manager = ArmPassManager(override_compile_spec) + skip_passes = override_manager._skip_pass_types + + assert FuseDuplicateUsersPass in skip_passes + assert DecomposeSoftmaxUnstablePass in skip_passes diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_required_order.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_required_order.py new file mode 100644 index 0000000..615a5a5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_pass_required_order.py @@ -0,0 +1,97 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import re +from typing import List, Set, Type + +import pytest +from executorch.backends.arm._passes.arm_pass_manager import ArmPass, ArmPassManager +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.exir.pass_base import ExportPass + + +class PassC(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = set() + + +class PassB(ArmPass): + _passes_required_after = {PassC} + + +class PassA(ArmPass): + _passes_required_after = {PassB, PassC} + + +class IndependentPass(ArmPass): + _passes_required_after: Set[Type[ExportPass]] = set() + + +def _setup_pass_manager(passes: List[ArmPass] | None = None): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.00+INT") + compile_spec = TosaCompileSpec(tosa_spec) + pass_manager = ArmPassManager(compile_spec) + if passes is not None: + for p in passes: + pass_manager.add_pass(p) + return pass_manager + + +def test_no_passes_tosa_INT(): + pass_manager = _setup_pass_manager() + pass_manager.validate_constraints_mandatory() + + +def test_correct_order_tosa_INT(): + pass_manager = _setup_pass_manager([PassA(), PassB(), PassC()]) + pass_manager.validate_constraints_mandatory() + + +def test_run_pass_twice_tosa_INT(): + pass_manager = _setup_pass_manager([PassA(), PassB(), PassB(), PassC()]) + pass_manager.validate_constraints_mandatory() + + +def test_independent_pass_tosa_INT(): + pass_manager = _setup_pass_manager( + [ + IndependentPass(), + PassA(), + IndependentPass(), + PassB(), + IndependentPass(), + PassC(), + IndependentPass(), + ] + ) + pass_manager.validate_constraints_mandatory() + + +def test_duplicated_requiring_pass_put_last_tosa_INT(): + error_msg = """The following constraints for passes are not met: + - PassC must run after PassB +""" + pass_manager = _setup_pass_manager([PassA(), PassB(), PassC(), PassB()]) + with pytest.raises(RuntimeError, match=re.escape(error_msg)): + pass_manager.validate_constraints_mandatory() + + +def test_two_passes_wrong_order_tosa_INT(): + error_msg = """The following constraints for passes are not met: + - PassC must run after PassB +""" + pass_manager = _setup_pass_manager([PassC(), PassB()]) + with pytest.raises(RuntimeError, match=re.escape(error_msg)): + pass_manager.validate_constraints_mandatory() + + +def test_missing_passes_tosa_INT(): + error_msg = """The following constraints for passes are not met: + - PassC must run after PassA + - PassC must run after PassB +""" + pass_manager = _setup_pass_manager([PassA(), PassB()]) + with pytest.raises(RuntimeError, match=re.escape(error_msg)): + pass_manager.validate_constraints_mandatory() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_qat_training_loop.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_qat_training_loop.py new file mode 100644 index 0000000..425849b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_qat_training_loop.py @@ -0,0 +1,100 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.tosa.specification import TosaSpecification +from torch.export import export +from torchao.quantization.pt2e import ( + move_exported_model_to_eval, + move_exported_model_to_train, +) +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_qat_pt2e + +logger = logging.getLogger(__name__) + + +class MLP(torch.nn.Module): + def __init__(self): + super().__init__() + self.sequential = torch.nn.Sequential( + torch.nn.Linear(1, 10), + torch.nn.ReLU(), + torch.nn.Linear(10, 10), + torch.nn.ReLU(), + torch.nn.Linear(10, 1), + ) + + def forward(self, x): + return self.sequential(x) + + +def evaluate_model(model, inputs, expected_outputs): + with torch.no_grad(): + test_outputs = model(inputs) + loss = torch.nn.functional.mse_loss(test_outputs, expected_outputs) + logger.info(f"Mean squared error: {loss.item()}") + + +def test_qat_training_loop_tosa_INT(): + """Test the QAT training loop with a simple MLP model. + This function creates a simple MLP model, prepares it for QAT, runs a training loop, + and evaluates the quantized model to make sure everything works as expected.""" + + model = MLP() + logger.info("Starting training loop test") + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + for epoch in range(100): + model.train() + optimizer.zero_grad() + inputs = torch.randn(100, 1).clamp(-1, 1) + outputs = model(inputs) + loss = torch.nn.functional.mse_loss(outputs, torch.sin(inputs)) + loss.backward() + optimizer.step() + if epoch % 5 == 0: + logger.info(f"Epoch {epoch}, Loss: {loss.item()}") + logger.info("Training loop test completed successfully") + + logger.info("Evaluating model before QAT") + test_inputs = torch.randn(20, 1).clamp(-1, 1) + test_outputs = torch.sin(test_inputs) + evaluate_model(model, test_inputs, test_outputs) + + exported_model = export(model, (torch.randn(1, 1),), strict=True) + quantizer = TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + quantizer.set_global(get_symmetric_quantization_config(is_qat=True)) + + prepared_model = prepare_qat_pt2e(exported_model.module(), quantizer) + prepared_model = move_exported_model_to_train(prepared_model) + logger.info("QAT model prepared successfully") + + logger.info("Starting QAT training loop") + + for epoch in range(25): + inputs = torch.randn(100, 1).clamp(-1, 1) + optimizer.zero_grad() + outputs = prepared_model(inputs) + loss = torch.nn.functional.mse_loss(outputs, torch.sin(inputs)) + loss.backward() + optimizer.step() + if epoch % 5 == 0: + logger.info(f"QAT Epoch {epoch}, Loss: {loss.item()}") + logger.info("QAT training loop completed successfully") + prepared_model = move_exported_model_to_eval(prepared_model) + + quantized_model = convert_pt2e(prepared_model) + logger.info("QAT model quantized successfully") + + logger.info("Evaluating quantized model") + test_inputs = torch.randn(100, 1).clamp(-1, 1) + test_outputs = torch.sin(test_inputs) + evaluate_model(quantized_model, test_inputs, test_outputs) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_quant_custom_meta.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_quant_custom_meta.py new file mode 100644 index 0000000..59156c2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_quant_custom_meta.py @@ -0,0 +1,105 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT + + +class AddSigmoidMul(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x, y): + return self.sigmoid(x + y) * x + + +@pytest.mark.parametrize("fp_extension", [True, False]) +def test_qdq_squeezed_fp_op_tosa_INT_FP(fp_extension: bool): + """Test that a float operation surrounded by quantize-dequantize pairs + is correctly handled by the partitioner and the TOSA backend. + Pattern: + q -> dq -> add -> q -> dq -> sigmoid -> q -> dq -> mul -> dq -> q + |_____unquantized_____| + """ + aten_op = "torch.ops.aten.add.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_add_Tensor" + module = AddSigmoidMul() + x = torch.randn(2, 3, 4) + y = torch.randn(2, 3, 4) + pipeline = TosaPipelineINT( + module=module, + test_data=(x, y), + aten_op=aten_op, + exir_op=exir_op, + tosa_extensions=["FP"] if fp_extension else None, + ) + pipeline.quantizer.set_module_type(torch.nn.Sigmoid, None) # type: ignore + + if not fp_extension: + # In case we don't have the FP extension, the unquantized part of the + # graph should not be delegated to the Arm backend. Modify the op count + # checks to reflect this behavior. + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 2, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + }, + ) + pipeline.run() + + +class MulAddSigmoidConv(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sigmoid = torch.nn.Sigmoid() + self.conv = torch.nn.Conv1d(3, 3, 1) + + def forward(self, x, y): + return self.conv(self.sigmoid(x + y * x)) + + +@pytest.mark.parametrize("fp_extension", [True, False]) +def test_quantized_to_float_transition_tosa_INT_FP(fp_extension: bool): + """Test that a model executing quantized ops followed by float ops + is correctly handled by the partitioner and the TOSA backend. + Pattern: + q -> dq -> mul -> q -> dq -> add -> q -> dq -> sigmoid -> conv + |___unquantized___| + """ + aten_op = "torch.ops.aten.add.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_add_Tensor" + module = MulAddSigmoidConv() + x = torch.randn(2, 3, 4) + y = torch.randn(2, 3, 4) + pipeline = TosaPipelineINT( + module=module, + test_data=(x, y), + aten_op=aten_op, + exir_op=exir_op, + tosa_extensions=["FP"] if fp_extension else None, + ) + if not fp_extension: + # In case we don't have the FP extension, the unquantized part of the + # graph should not be delegated to the Arm backend. Modify the op count + # checks to reflect this behavior. + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 1, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + }, + ) + pipeline.quantizer.set_module_type(torch.nn.Sigmoid, None) # type: ignore + pipeline.quantizer.set_module_type(torch.nn.Conv1d, None) # type: ignore + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_rescale_range.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_rescale_range.py new file mode 100644 index 0000000..1075dd4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_rescale_range.py @@ -0,0 +1,130 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch + +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from torch._subclasses.fake_tensor import FakeTensorMode + +input_t = Tuple[torch.Tensor, torch.Tensor] # Input x + + +def test_rescale_op_tosa_INT(): + sample_inputs = [ + # (data, out_dtype, scale, in_zp, out_zp) + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int32, + [0.2], + 2, + 0, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int32), + torch.int8, + [0.2], + 0, + -128, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int8, + [0.8], + 10, + 127, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input in sample_inputs: + exir_ops.backend.tosa.RESCALE.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_nonzero_zp_for_int32_tosa_INT(): + + sample_inputs = [ + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int32, + [0.2], + 2, # Should be 0, expect error + 1, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int32), + torch.int8, + [0.2], + 1, + 1, # Should be 0, expect error + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input in sample_inputs: + with pytest.raises( + ValueError, match="TOSA requires (output|input)_zp to be zero" + ): + exir_ops.backend.tosa.RESCALE.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_zp_outside_range_tosa_INT(): + + sample_inputs = [ + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int8), + torch.int32, + [0.2], + 128, # Should be <128, expect error + 0, + ), + ( + torch.randint(low=0, high=100, size=(4, 4, 4), dtype=torch.int32), + torch.int8, + [0.2], + 0, + -129, # Should be >-129 expect error + ), + ] + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input in sample_inputs: + with pytest.raises( + Exception, match="(in_zp|out_zp)=-?[0-9]* outside valid range" + ): + exir_ops.backend.tosa.RESCALE.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_save_exported_model.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_save_exported_model.py new file mode 100644 index 0000000..4ac5d46 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_save_exported_model.py @@ -0,0 +1,64 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import os + +import torch +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.quantizer import ( + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.tosa import TosaSpecification +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + + +class SimpleModule(torch.nn.Module): + example_inputs = (torch.randn(1, 10),) + + def __init__(self): + super().__init__() + self.linear = torch.nn.Linear(10, 10) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.linear(x) + + +def test_save_load_exported_int_model_tosa_INT(): + module = SimpleModule().eval() + example_inputs = module.example_inputs + exported_module = torch.export.export(module, example_inputs) + + # Set up quantizer + quantizer = TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + quantizer.set_global(get_symmetric_quantization_config()) + # Quantize model + prepared_module = prepare_pt2e(exported_module.module(), quantizer) + prepared_module(*example_inputs) + quantized_module = convert_pt2e(prepared_module) + quantized_exported_module = torch.export.export(quantized_module, example_inputs) + + base_path = "arm_test/misc/" + if not os.path.exists(base_path): + os.makedirs(base_path) + file_path = base_path + "exported_module.pt2" + # Verify that we can save the model + torch.export.save(quantized_exported_module, file_path) + + # Verify that we can load the model back + loaded_model = torch.export.load( + file_path + ) # nosec B614 - loads trusted test artifact + for original_node, loaded_node in zip( + quantized_exported_module.graph.nodes, loaded_model.graph.nodes + ): + # Verify that the custom metadata is preserved after save/load + assert original_node.meta.get("custom", {}) == loaded_node.meta.get( + "custom", {} + ) + if original_node.target == torch.ops.aten.linear.default: + assert ArmAnnotationInfo.CUSTOM_META_KEY in original_node.meta.get( + "custom", {} + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_conv2d.py new file mode 100644 index 0000000..7cee503 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_conv2d.py @@ -0,0 +1,220 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import executorch.backends.arm.tosa.dialect # noqa: unused +import pytest +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops +from torch._subclasses.fake_tensor import FakeTensorMode + + +def test_conv2d_tosa_INT(): + sample_inputs = [ + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (8, 2, 5, 5), dtype=torch.int8), + torch.randint(-(2**31), 2**31, (8,), dtype=torch.int32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 8, 20, 20), + torch.int32, + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (4, 2, 5, 5), dtype=torch.int8), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 4, 10, 10), + torch.int32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_conv2d_invalid_tosa_INT(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.float32} but found input type {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int8} weights for {torch.int8} input but found {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (8, 2, 5, 5), dtype=torch.int8), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int32} bias for {torch.int8} input but found {torch.float32}", + ), + ] + + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_conv2d_tosa_FP(): + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 8, 20, 20), + torch.float32, + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((4, 2, 5, 5), dtype=torch.float32), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 4, 10, 10), + torch.float32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+FP") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_conv2d_invalid_tosa_FP(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+FP") + sample_inputs = [ + ( + ( + torch.randint(-127, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.int8} but found input type {torch.int8}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float16), + torch.randn((8,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires weights {torch.float16} to be of the same type as input {torch.float32}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((8, 2, 5, 5), dtype=torch.float32), + torch.randn((8,), dtype=torch.float16), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires bias {torch.float16} to be of the same type as input {torch.float32}", + ), + ] + + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py new file mode 100644 index 0000000..3a6b5ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_dialect_dw_conv2d.py @@ -0,0 +1,227 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import executorch.backends.arm.tosa.dialect # noqa: unused +import pytest +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops +from torch._subclasses.fake_tensor import FakeTensorMode + + +def test_depthwise_conv2d_tosa_INT(): + sample_inputs = [ + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randint(-127, 127, (5, 2, 5, 8), dtype=torch.int8), + torch.randint(-(2**31), 2**31, (16,), dtype=torch.int32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 16, 20, 20), + torch.int32, + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randint(-127, 127, (5, 4, 5, 8), dtype=torch.int8), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 32, 10, 10), + torch.int32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+INT") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_depthwise_conv2d_invalid_tosa_INT(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.float32} but found input type {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int8} weights for {torch.int8} input but found {torch.float32}", + ), + ( + ( + torch.randint(-128, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randint(-127, 127, (5, 2, 5, 8), dtype=torch.int8), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"only supports {torch.int32} bias for {torch.int8} input but found {torch.float32}", + ), + ] + + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + + +def test_depthwise_conv2d_tosa_FP(): + sample_inputs = [ + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + (1, 16, 20, 20), + torch.float32, + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + # weight shape is [H, m_length, W, in_channels], where m_length = out_channels // in_channels + torch.randn((5, 4, 5, 8), dtype=torch.float32), + None, + [2, 2], + [2, 2, 2, 2], + [1, 1], + ), + (1, 32, 10, 10), + torch.float32, + ), + ] + + with TosaLoweringContext( + TosaSpecification.create_from_string("TOSA-1.0+FP") + ), FakeTensorMode() as mode: + for sample_input, expected_output_shape, expected_output_type in sample_inputs: + output = exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) + assert ( + output.dtype == expected_output_type + ), f"Expected output dtype {expected_output_type} but got {output.dtype}" + assert ( + tuple(output.shape) == expected_output_shape + ), f"Expected output shape {expected_output_shape} but got {tuple(output.shape)}" + + +def test_depthwise_conv2d_invalid_tosa_FP(): + + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+FP") + + sample_inputs = [ + ( + ( + torch.randint(-127, 127, (1, 8, 20, 20), dtype=torch.int8), + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"doesn't support {torch.int8} but found input type {torch.int8}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((5, 2, 5, 8), dtype=torch.float16), + torch.randn((16,), dtype=torch.float32), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires weights {torch.float16} to be of the same type as input {torch.float32}", + ), + ( + ( + torch.randn((1, 8, 20, 20), dtype=torch.float32), + torch.randn((5, 2, 5, 8), dtype=torch.float32), + torch.randn((16,), dtype=torch.float16), + [1, 1], + [2, 2, 2, 2], + [1, 1], + ), + TosaValueError, + f"requires bias {torch.float16} to be of the same type as input {torch.float32}", + ), + ] + with TosaLoweringContext(tosa_spec), FakeTensorMode() as mode: + for sample_input, expected_error, expected_error_str in sample_inputs: + with pytest.raises(expected_error, match=expected_error_str): + exir_ops.backend.tosa.DEPTHWISE_CONV2D.default( + *tuple( + [ + mode.from_tensor(i) if isinstance(i, torch.Tensor) else i + for i in sample_input + ] + ) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_spec.py new file mode 100644 index 0000000..9d8882e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/misc/test_tosa_spec.py @@ -0,0 +1,169 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +from executorch.backends.arm.tosa.specification import ( + Tosa_1_00, + TosaSpecification, + TosaSpecMapping, +) + +from parameterized import parameterized # type: ignore[import-untyped] + +test_valid_strings = [ + "TOSA-1.0.0+INT+FP+fft", + "TOSA-1.0.0+FP+bf16+fft", + "TOSA-1.0.0+INT+int4+cf", + "TOSA-1.0.0+FP+cf+bf16+8k", + "TOSA-1.0.0+FP+INT+bf16+fft+int4+cf", + "TOSA-1.0.0+FP+INT+fft+int4+cf+8k", + "TOSA-1.0+INT+FP+fft", + "TOSA-1.0+FP+bf16+fft", + "TOSA-1.0+INT+int4+cf", + "TOSA-1.0+FP+cf+bf16+8k", + "TOSA-1.0+FP+INT+bf16+fft+int4+cf", + "TOSA-1.0+FP+INT+fft+int4+cf+8k", +] + +test_valid_extensions = { + "INT": ["int16", "int4", "var", "cf"], + "FP": ["bf16", "fp8e4m3", "fp8e5m2", "fft", "var", "cf"], +} + +test_invalid_strings = [ + "TOSA-1.0.0+fft", + "TOSA-1.0.0+fp+bf16+fft", + "TOSA-1.0.0+INT+INT4+cf", + "TOSA-1.0.0+FP+FP+INT", + "TOSA-1.0.0+FP+CF+bf16", + "TOSA-1.0.0+BF16+fft+int4+cf+INT", +] + + +class TestTosaSpecification(unittest.TestCase): + """Tests the TOSA specification class""" + + @parameterized.expand(test_valid_strings) # type: ignore[misc] + def test_version_string_no_target(self, version_string: str): + tosa_spec = TosaSpecification.create_from_string(version_string) + assert isinstance(tosa_spec, Tosa_1_00) + assert [profile in ["INT", "FP"] for profile in tosa_spec.profiles].count( + True + ) > 0 + + for profile in tosa_spec.profiles: + assert [e in test_valid_extensions[profile] for e in tosa_spec.extensions] + + @parameterized.expand(test_invalid_strings) # type: ignore[misc] + def test_invalid_version_strings_no_target(self, version_string: str): + tosa_spec = None + with self.assertRaises(ValueError): + tosa_spec = TosaSpecification.create_from_string(version_string) + + assert tosa_spec is None + + @parameterized.expand(test_valid_strings) + def test_correct_string_representation_no_target(self, version_string: str): + tosa_spec = TosaSpecification.create_from_string(version_string) + assert isinstance(tosa_spec, Tosa_1_00) + assert f"{tosa_spec}" == version_string + + +class TestTosaSpecMapping(unittest.TestCase): + """Tests the TosaSpecMapping class""" + + def test_mapping_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + # check that the mapping is correct + vals = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + assert vals == ["A"] + assert len(vals) == 1 + + def test_mapping_multiple_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "B") + # check that the mapping is correct + vals = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + assert vals == ["A", "B"] + assert len(vals) == 2 + + def test_mapping_different_profiles_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "B") + # check that the mapping is correct + vals_int = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + vals_fp = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+FP")) + + assert vals_int == ["A"] + assert vals_fp == ["B"] + assert len(vals_int) == 1 + assert len(vals_fp) == 1 + + def test_mapping_different_profiles_combined_consumer_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "B") + # check that the mapping is correct + combined_vals = mapping.get( + TosaSpecification.create_from_string("TOSA-1.0+INT+FP") + ) + + assert "A" in combined_vals + assert "B" in combined_vals + assert len(combined_vals) == 2 + + def test_mapping_no_spec_no_target(self): + mapping = TosaSpecMapping() + with self.assertRaises(KeyError): + mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + def test_mapping_no_values_for_spec_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "A") + with self.assertRaises(KeyError): + mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + def test_spec_with_different_profiles_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+FP"), "A") + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "B") + # check that the mapping is correct + vals_int = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT")) + vals_fp = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+FP")) + vals_int_fp = mapping.get( + TosaSpecification.create_from_string("TOSA-1.0+INT+FP") + ) + + assert vals_fp == ["A"] + assert vals_int == ["B"] + assert len(vals_int) == 1 + assert len(vals_fp) == 1 + assert len(vals_int_fp) == 2 + + def test_combined_profiles_no_target(self): + mapping = TosaSpecMapping() + with self.assertRaises(ValueError): + # Don't allow multiple profiles in a single spec + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT+FP"), "A") + + def test_spec_add_with_extension_no_target(self): + mapping = TosaSpecMapping() + with self.assertRaises(ValueError): + mapping.add( + TosaSpecification.create_from_string("TOSA-1.0.0+INT+int16"), "A" + ) + + def test_spec_non_canonical_key_no_target(self): + mapping = TosaSpecMapping() + mapping.add(TosaSpecification.create_from_string("TOSA-1.0+INT"), "A") + + val = mapping.get(TosaSpecification.create_from_string("TOSA-1.0+INT+u55")) + assert val == ["A"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py new file mode 100644 index 0000000..86e9453 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/stable_diffusion_module_test_configs.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +# Adapted from Hugging Face's diffusers library: +# https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py +# +# Licensed under the Apache License, Version 2.0 +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from transformers import CLIPTextConfig, T5Config + + +""" +This file defines test configs used to initialize Stable Diffusion module tests. +Module tests in the same directory will import these configs. + +To stay aligned with the Stable Diffusion implementation in the HuggingFace Diffusers library, +the configs here are either directly copied from corresponding test files or exported from +pre-trained models used in the Diffusers library. + +Licenses: +The test parameters are from Hugging Face's diffusers library and under the Apache 2.0 License, +while the remainder of the code is under the BSD-style license found in the LICENSE file in the +root directory of this source tree. +""" + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py#L56 +CLIP_text_encoder_config = CLIPTextConfig( + bos_token_id=0, + eos_token_id=2, + hidden_size=32, + intermediate_size=37, + layer_norm_eps=1e-05, + num_attention_heads=4, + num_hidden_layers=5, + pad_token_id=1, + vocab_size=1000, + hidden_act="gelu", + projection_dim=32, +) + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py#L76 +# Exported from: T5EncoderModel.from_pretrained("hf-internal-testing/tiny-random-t5").config +T5_encoder_config = T5Config( + bos_token_id=0, + classifier_dropout=0.0, + d_ff=37, + d_kv=8, + d_model=32, + decoder_start_token_id=0, + dense_act_fn="relu", + dropout_rate=0.1, + eos_token_id=1, + feed_forward_proj="relu", + gradient_checkpointing=False, + initializer_factor=0.002, + is_encoder_decoder=True, + is_gated_act=False, + layer_norm_epsilon=1e-06, + model_type="t5", + num_decoder_layers=5, + num_heads=4, + num_layers=5, + pad_token_id=0, + relative_attention_max_distance=128, + relative_attention_num_buckets=8, + transformers_version="4.47.1", + vocab_size=1000, +) + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/models/transformers/test_models_transformer_sd3.py#L142 +SD3Transformer2DModel_init_dict = { + "sample_size": 32, + "patch_size": 1, + "in_channels": 4, + "num_layers": 4, + "attention_head_dim": 8, + "num_attention_heads": 4, + "caption_projection_dim": 32, + "joint_attention_dim": 32, + "pooled_projection_dim": 64, + "out_channels": 4, + "pos_embed_max_size": 96, + "dual_attention_layers": (0,), + "qk_norm": "rms_norm", +} + + +# Source: https://github.com/huggingface/diffusers/blob/v0.33.1/tests/pipelines/stable_diffusion_3/test_pipeline_stable_diffusion_3.py#L83 +AutoencoderKL_config = { + "sample_size": 32, + "in_channels": 3, + "out_channels": 3, + "block_out_channels": (4,), + "layers_per_block": 1, + "latent_channels": 4, + "norm_num_groups": 1, + "use_quant_conv": False, + "use_post_quant_conv": False, + "shift_factor": 0.0609, + "scaling_factor": 1.5035, +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py new file mode 100644 index 0000000..b68ad39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_CLIPTextModelWithProjection.py @@ -0,0 +1,168 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import ( + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, + InsertInt32CastsAfterInt64PlaceholdersPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + CLIP_text_encoder_config, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from transformers import CLIPTextModelWithProjection + +input_t = Tuple[torch.Tensor] + + +class TestCLIPTextModelWithProjection: + """ + Test class of CLIPTextModelWithProjection. + CLIPTextModelWithProjection is one of the text_encoder used by Stable Diffusion 3.5 Medium + """ + + # Adjust nbr below as we increase op support. + ops_after_partitioner_FP = { + "executorch_exir_dialects_edge__ops_aten_argmax_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 2, + } + + ops_after_partitioner_INT = { + "executorch_exir_dialects_edge__ops_aten_argmax_default": 1, + "executorch_exir_dialects_edge__ops_aten_index_select_default": 1, + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 2, + } + + ops_after_partitioner_vgf_quantize = ops_after_partitioner_FP + ops_after_partitioner_vgf_no_quantize = ops_after_partitioner_FP + + def _prepare_inputs( + self, + batch_size=12, + seq_length=7, + vocab_size=1000, + ): + input_ids = torch.randint( + low=0, + high=vocab_size, + size=(batch_size, seq_length), + dtype=torch.long, + ) + return (input_ids,) + + def prepare_model_and_inputs(self): + clip_text_encoder_config = CLIP_text_encoder_config + + text_encoder_model = CLIPTextModelWithProjection(clip_text_encoder_config) + text_encoder_model.eval() + text_encoder_model_inputs = self._prepare_inputs() + + return text_encoder_model, text_encoder_model_inputs + + +def test_clip_text_with_projection_tosa_FP(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + ) + pipeline.change_args( + "check_count.exir", TestCLIPTextModelWithProjection.ops_after_partitioner_FP + ) + pipeline.run() + + +def test_clip_text_with_projection_tosa_INT(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.8, + ) + pipeline.change_args( + "check_count.exir", + TestCLIPTextModelWithProjection.ops_after_partitioner_INT, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_clip_text_with_projection_vgf_no_quant(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=4, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + quantize=False, + ) + pipeline.change_args( + "check_count.exir", + TestCLIPTextModelWithProjection.ops_after_partitioner_vgf_no_quantize, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_clip_text_with_projection_vgf_quant(): + text_encoder_model, text_encoder_model_inputs = ( + TestCLIPTextModelWithProjection().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + text_encoder_model, + text_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.8, + quantize=True, + ) + pipeline.change_args( + "check_count.exir", + TestCLIPTextModelWithProjection.ops_after_partitioner_vgf_quantize, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py new file mode 100644 index 0000000..aa736d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_SD3Transformer2DModel.py @@ -0,0 +1,193 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from diffusers.models.transformers import ( # type: ignore[import-not-found] + SD3Transformer2DModel, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + SD3Transformer2DModel_init_dict, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t4 = Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor] + + +class TestSD3Transformer2DModel: + """ + Test class of AutoenSD3Transformer2DModelcoderKL. + SD3Transformer2DModel is the transformer model used by Stable Diffusion 3.5 Medium + """ + + # Adjust nbr below as we increase op support. + ops_after_partitioner_FP = { + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "torch.ops.higher_order.executorch_call_delegate": 1, + } + + ops_after_partitioner_INT = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 3, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + } + + ops_after_partitioner_vgf_quantize = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "torch.ops.higher_order.executorch_call_delegate": 1, + } + ops_after_partitioner_vgf_no_quantize = ops_after_partitioner_FP + + def _prepare_inputs( + self, + batch_size=2, + num_channels=4, + height=32, + width=32, + embedding_dim=32, + sequence_length=154, + max_timestep=1000, + ): + hidden_states = torch.randn( + ( + batch_size, + num_channels, + height, + width, + ) + ) + encoder_hidden_states = torch.randn( + ( + batch_size, + sequence_length, + embedding_dim, + ) + ) + pooled_prompt_embeds = torch.randn( + ( + batch_size, + embedding_dim * 2, + ) + ) + timestep = torch.randint(low=0, high=max_timestep, size=(batch_size,)) + + input_dict = { + "hidden_states": hidden_states, + "encoder_hidden_states": encoder_hidden_states, + "pooled_projections": pooled_prompt_embeds, + "timestep": timestep, + } + + return tuple(input_dict.values()) + + def prepare_model_and_inputs(self): + + class SD3Transformer2DModelWrapper(SD3Transformer2DModel): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs).sample + + init_dict = SD3Transformer2DModel_init_dict + + sd35_transformer2D_model = SD3Transformer2DModelWrapper(**init_dict) + sd35_transformer2D_model_inputs = self._prepare_inputs() + + return sd35_transformer2D_model, sd35_transformer2D_model_inputs + + +def test_sd3_transformer_tosa_FP(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + rtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT + atol=4.0, + ) + pipeline.change_args( + "check_count.exir", TestSD3Transformer2DModel.ops_after_partitioner_FP + ) + pipeline.run() + + +def test_sd3_transformer_tosa_INT(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + qtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT + rtol=1.0, + atol=4.0, + ) + pipeline.change_args( + "check_count.exir", TestSD3Transformer2DModel.ops_after_partitioner_INT + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sd3_transformer_vgf_no_quant(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + rtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT, + atol=4.0, + quantize=False, + ) + pipeline.change_args( + "check_count.exir", + TestSD3Transformer2DModel.ops_after_partitioner_vgf_no_quantize, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sd3_transformer_vgf_quant(): + sd35_transformer2D_model, sd35_transformer2D_model_inputs = ( + TestSD3Transformer2DModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t4]( + sd35_transformer2D_model, + sd35_transformer2D_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + qtol=1.0, + rtol=1.0, # TODO: MLETORCH-875: Reduce tolerance of SD3Transformer2DModel with FP and INT, + atol=4.0, + quantize=True, + ) + pipeline.change_args( + "check_count.exir", + TestSD3Transformer2DModel.ops_after_partitioner_vgf_quantize, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py new file mode 100644 index 0000000..ce6e5d5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_T5EncoderModel.py @@ -0,0 +1,161 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import ( + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, + InsertInt32CastsAfterInt64PlaceholdersPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + T5_encoder_config, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from transformers import T5EncoderModel + +input_t = Tuple[torch.Tensor] + + +class TestT5EncoderModel: + """ + Test class of T5EncoderModel. + T5EncoderModel is one of the text_encoder used by Stable Diffusion 3.5 Medium + """ + + # Adjust nbr below as we increase op support. + ops_after_partitioner_FP = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 2, + "torch.ops.higher_order.executorch_call_delegate": 2, + } + + ops_after_partitioner_INT = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 3, + "torch.ops.higher_order.executorch_call_delegate": 3, + } + + ops_after_partitioner_vgf_quantize = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "torch.ops.higher_order.executorch_call_delegate": 1, + } + + ops_after_partitioner_vgf_no_quantize = ops_after_partitioner_vgf_quantize + + def _prepare_inputs( + self, + batch_size=12, + seq_length=7, + vocab_size=1000, + ): + input_ids = torch.randint( + low=0, + high=vocab_size, + size=(batch_size, seq_length), + dtype=torch.long, + ) + return (input_ids,) + + def prepare_model_and_inputs(self): + t5_encoder_config = T5_encoder_config + + t5_encoder_model = T5EncoderModel(t5_encoder_config) + t5_encoder_model.eval() + t5_encoder_model_inputs = self._prepare_inputs() + + return t5_encoder_model, t5_encoder_model_inputs + + +def test_t5_encoder_tosa_FP(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_FP + ) + pipeline.run() + + +def test_t5_encoder_tosa_INT(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_INT + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_t5_encoder_vgf_no_quant(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + InsertInt32CastsAfterInt64PlaceholdersPass(), + ], + quantize=False, + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_vgf_no_quantize + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_t5_encoder_vgf_quant(): + t5_encoder_model, t5_encoder_model_inputs = ( + TestT5EncoderModel().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + t5_encoder_model, + t5_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.change_args( + "check_count.exir", TestT5EncoderModel.ops_after_partitioner_vgf_quantize + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py new file mode 100644 index 0000000..d57cded --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/stable_diffusion/test_vae_AutoencoderKL.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from diffusers.models.autoencoders import ( # type: ignore[import-not-found] + AutoencoderKL, +) +from diffusers.utils.testing_utils import ( # type: ignore[import-not-found] + floats_tensor, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.models.stable_diffusion.stable_diffusion_module_test_configs import ( + AutoencoderKL_config, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + + +class TestAutoencoderKL: + """ + Test class of AutoencoderKL. + AutoencoderKL is the encoder/decoder used by Stable Diffusion 3.5 Medium + """ + + def _prepare_inputs(self, batch_size=4, num_channels=3, sizes=(32, 32)): + image = floats_tensor((batch_size, num_channels) + sizes) + return (image,) + + def prepare_model_and_inputs(self): + + class AutoencoderWrapper(AutoencoderKL): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs).sample + + vae_config = AutoencoderKL_config + + auto_encoder_model = AutoencoderWrapper(**vae_config) + + auto_encoder_model_inputs = self._prepare_inputs() + + return auto_encoder_model, auto_encoder_model_inputs + + +def test_vae_tosa_FP(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +def test_vae_tosa_INT(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.0, # TODO: MLETORCH-990 Reduce tolerance of vae(AutoencoderKL) with INT + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_vae_vgf_no_quant(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_vae_vgf_quant(): + auto_encoder_model, auto_encoder_model_inputs = ( + TestAutoencoderKL().prepare_model_and_inputs() + ) + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + auto_encoder_model, + auto_encoder_model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.0, # TODO: MLETORCH-990 Reduce tolerance of vae(AutoencoderKL) with INT + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_conformer.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_conformer.py new file mode 100644 index 0000000..e04d8bd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_conformer.py @@ -0,0 +1,138 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchaudio.models import Conformer # type: ignore[import-untyped] + +input_t = Tuple[torch.Tensor, torch.IntTensor] # Input x, y + + +def get_test_inputs(dim, lengths, num_examples): + return (torch.rand(num_examples, int(lengths.max()), dim), lengths) + + +class TestConformer: + """Tests Torchaudio Conformer""" + + # Adjust nbr below as we increase op support. Note: most of the delegates + # calls are directly consecutive to each other in the .pte. The reason + # for that is some assert ops are removed by passes in the + # .to_executorch step, i.e. after Arm partitioner. + aten_ops = ["torch.ops.aten._assert_scalar.default"] + + # TODO(MLETORCH-635): reduce tolerance + atol = 0.4 + rtol = 0.4 + + dim = 16 + num_examples = 10 + lengths = torch.randint(1, 100, (num_examples,), dtype=torch.int32) + model_example_inputs = get_test_inputs(dim, lengths, num_examples) + conformer = Conformer( + input_dim=dim, + num_heads=4, + ffn_dim=64, + num_layers=2, + depthwise_conv_kernel_size=31, + ) + conformer = conformer.eval() + + +def test_conformer_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=TestConformer.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +def test_conformer_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@pytest.mark.xfail( + reason="TODO(MLETORCH-635): Expected failure under FVP option, but test passed." +) +def test_conformer_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_conformer_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_conformer_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=TestConformer.atol, + rtol=TestConformer.rtol, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_conformer_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestConformer.conformer, + TestConformer.model_example_inputs, + aten_op=TestConformer.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_deit_tiny_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_deit_tiny_arm.py new file mode 100644 index 0000000..c53ab4f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_deit_tiny_arm.py @@ -0,0 +1,120 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import timm # type: ignore[import-untyped] + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from timm.data import ( # type: ignore[import-untyped] + IMAGENET_INCEPTION_MEAN, + IMAGENET_INCEPTION_STD, +) +from torchvision import transforms # type: ignore[import-untyped] + +deit_tiny = timm.models.deit.deit_tiny_patch16_224(pretrained=True) + +deit_tiny.eval() + +normalize = transforms.Normalize( + mean=IMAGENET_INCEPTION_MEAN, std=IMAGENET_INCEPTION_STD +) +model_inputs = (normalize(torch.rand((1, 3, 224, 224))),) + +input_t = Tuple[torch.Tensor] + + +def test_deit_tiny_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +def test_deit_tiny_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + ) + pipeline.run() + + +def test_deit_tiny_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + deit_tiny, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + ) + # Multiple partitions + pipeline.pop_stage("check_count.exir") + # Don't run inference as model is too large for Corstone-300 + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_deit_tiny_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + deit_tiny, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_deit_tiny_vgf_quant(): + pipeline = VgfPipeline[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=1.5, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_deit_tiny_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + deit_tiny, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_dl3_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_dl3_arm.py new file mode 100644 index 0000000..8e10001 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_dl3_arm.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from executorch.examples.models import deeplab_v3 + +input_t = Tuple[torch.Tensor] # Input x + + +class TestDl3: + """Tests DeepLabv3.""" + + dl3 = deeplab_v3.DeepLabV3ResNet50Model() + model_example_inputs = dl3.get_example_inputs() + dl3 = dl3.get_eager_model() + + +def test_dl3_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +def test_dl3_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.XfailIfNoCorstone300 +@pytest.mark.skip(reason="upsample_bilinear2d operator is not supported on U55") +def test_dl3_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_ops=[], + exir_ops=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.XfailIfNoCorstone320 +@pytest.mark.skip(reason="Runs out of memory on U85") +def test_dl3_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_ops=[], + exir_ops=[], + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=1.0, atol=1.0 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_dl3_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", rtol=0.1, atol=0.1 + ) # TODO: MLETORCH-1036 decrease tolerance + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_dl3_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestDl3.dl3, + TestDl3.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_inception_v3_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_inception_v3_arm.py new file mode 100644 index 0000000..174d2c1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_inception_v3_arm.py @@ -0,0 +1,120 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchvision import models, transforms # type: ignore[import-untyped] + +ic3 = models.inception_v3(weights=models.Inception_V3_Weights) +ic3 = ic3.eval() + +# Normalization values referenced from here: +# https://docs.pytorch.org/vision/main/models/generated/torchvision.models.quantization.inception_v3.html +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +model_inputs = (normalize(torch.rand(1, 3, 224, 224)),) +input_t = Tuple[torch.Tensor] + + +@pytest.mark.slow +def test_ic3_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow +def test_ic3_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.65, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.XfailIfNoCorstone300 +def test_ic3_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + ic3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.6, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.XfailIfNoCorstone320 +def test_ic3_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + ic3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.6, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.SkipIfNoModelConverter +def test_ic3_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +@pytest.mark.slow +@pytest.mark.skip(reason="Takes too long to run on CI") +@common.SkipIfNoModelConverter +def test_ic3_vgf_quant(): + pipeline = VgfPipeline[input_t]( + ic3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_llama.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_llama.py new file mode 100644 index 0000000..ec0e34d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_llama.py @@ -0,0 +1,227 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import os +import sys + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm._passes import InsertInt32CastsAfterInt64PlaceholdersPass +from executorch.backends.arm.quantizer import get_symmetric_quantization_config + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.examples.models.llama.export_llama_lib import ( + build_args_parser, + get_llama_model, +) + +from executorch.extension.llm.export.config.llm_config import LlmConfig + +input_t = Tuple[torch.Tensor] + +# Add project dir to sys path to workaround importlib.import_module() conditions in model_factory.py +this_files_dir = os.path.dirname(os.path.abspath(__file__)) +project_dir = os.path.abspath(os.path.join(this_files_dir, "../../../..")) +sys.path.append(project_dir) + +logger = logging.getLogger(__name__) + + +class TestLlama: + """ + Test class of Llama models. Type of Llama model depends on command line parameters: + --llama_inputs + Example: --llama_inputs stories110M/stories110M.pt stories110M/params.json stories110m + For more examples and info see examples/models/llama/README.md. + """ + + def prepare_model(self): + checkpoint = None + params_file = None + usage = "To run use --llama_inputs <.pt/.pth> <.json> " + + if conftest.is_option_enabled("llama_inputs"): + param_list = conftest.get_option("llama_inputs") + + if not isinstance(param_list, list) or len(param_list) != 3: + raise RuntimeError( + f"Invalid number of inputs for --llama_inputs. {usage}" + ) + if not all(isinstance(param, str) for param in param_list): + raise RuntimeError( + f"All --llama_inputs are expected to be strings. {usage}" + ) + + checkpoint = param_list[0] + params_file = param_list[1] + model_name = param_list[2] + else: + logger.warning( + "Skipping Llama tests because of missing --llama_inputs. {usage}" + ) + return None, None, None + + assert os.path.isfile(checkpoint) and os.path.isfile( + params_file + ), "Invalid file paths" + + logger.info("Running test_llama.py") + + # TODO: Enable key value cache + args = [ + "--disable_dynamic_shape", + "-c", + checkpoint, + "-p", + params_file, + "--model", + model_name, + ] + parser = build_args_parser() + args = parser.parse_args(args) + llm_config = LlmConfig.from_args(args) + + llama_model, llama_inputs, llama_meta = get_llama_model(llm_config) + + return llama_model, llama_inputs, llama_meta + + +def _use_partial_quantizer(pipeline): + """Set the pipeline's quantizer to only include Linear layers""" + pipeline.quantizer.set_global(None) + pipeline.quantizer.set_module_type( + torch.nn.Linear, get_symmetric_quantization_config() + ) + + +def test_llama_tosa_FP(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = TosaPipelineFP[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + custom_path="llama_tosa_fb", + run_on_tosa_ref_model=False, # Just want to write TOSA FB to disk + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + ) + pipeline.add_stage_after("to_executorch", pipeline.tester.serialize) + pipeline.run() + + +def test_llama_tosa_INT(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + custom_path="llama_tosa_fb_int", + run_on_tosa_ref_model=False, # Just want to write TOSA FB to disk + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("to_executorch", pipeline.tester.serialize) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_llama_vgf_no_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_llama_vgf_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +def test_llama_tosa_INT_FP_partial_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = TosaPipelineINT[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + tosa_extensions=["FP"], + ) + _use_partial_quantizer(pipeline) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_llama_partial_quant_vgf_quant(): + llama_model, llama_inputs, llama_meta = TestLlama().prepare_model() + + if llama_model is None or llama_inputs is None: + pytest.skip("Missing model and/or input files") + + with torch.no_grad(): + pipeline = VgfPipeline[input_t]( + llama_model, + llama_inputs, + aten_op=[], + exir_op=[], + quantize=True, + ) + _use_partial_quantizer(pipeline) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_lstm_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_lstm_arm.py new file mode 100644 index 0000000..d83618a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_lstm_arm.py @@ -0,0 +1,194 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torch.nn.quantizable.modules import rnn + +input_t = Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] # (h0, c0) + + +def get_test_inputs(): + return ( + torch.randn(5, 3, 10), # input + (torch.randn(2, 3, 20), torch.randn(2, 3, 20)), # (h0, c0) + ) + + +class TestLSTM: + """Tests quantizable LSTM module.""" + + """ + Currently only the quantizable LSTM module has been verified with the arm backend. + There may be plans to update this to use torch.nn.LSTM. + TODO: MLETORCH-622 + """ + lstm = rnn.LSTM(10, 20, 2) + lstm = lstm.eval() + + # Used e.g. for quantization calibration and shape extraction in the tester + model_example_inputs = get_test_inputs() + + +def test_lstm_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", inputs=get_test_inputs(), atol=3e-1 + ) + pipeline.run() + + +def test_lstm_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", + inputs=get_test_inputs(), + atol=3e-1, + qtol=1.0, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +def test_lstm_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", + inputs=get_test_inputs(), + atol=3e-1, + qtol=1.0, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_lstm_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", + inputs=get_test_inputs(), + atol=3e-1, + qtol=1.0, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_lstm_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_lstm_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +def test_lstm_tosa_INT_16a8w(): + """Test LSTM model with 16A8W quantization (16-bit activations, 8-bit weights)""" + + pipeline = TosaPipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_op=[], + exir_op=[], + per_channel_quantization=False, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=False, epsilon=2**-16) + ) + pipeline.run() + + +@pytest.mark.xfail( + reason="MLETORCH-1452: AssertionError: Output 0 does not match reference output." +) +@common.XfailIfNoCorstone300 +def test_lstm_u55_INT_16a8w(): + pipeline = EthosU55PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=False, epsilon=2**-16) + ) + + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_lstm_u85_INT_16a8w(): + pipeline = EthosU85PipelineINT[input_t]( + TestLSTM.lstm, + TestLSTM.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=False, epsilon=2**-16) + ) + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v2_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v2_arm.py new file mode 100644 index 0000000..a0a758a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v2_arm.py @@ -0,0 +1,179 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.quantizer import get_symmetric_quantization_config +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchvision import models, transforms # type: ignore[import-untyped] +from torchvision.models.mobilenetv2 import ( # type: ignore[import-untyped] + MobileNet_V2_Weights, +) + + +mv2 = models.mobilenetv2.mobilenet_v2(weights=MobileNet_V2_Weights.DEFAULT) +mv2 = mv2.eval() +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +model_inputs = (normalize(torch.rand((1, 3, 224, 224))),) +input_t = Tuple[torch.Tensor] + + +quant_test_data = { + "per_channel_quantization=true": True, + "per_channel_quantization=false": False, +} + + +def _use_partial_quantizer(pipeline): + """Set the pipeline's quantizer to only include Conv2d and ReLU6""" + quant_cfg = get_symmetric_quantization_config() + pipeline.quantizer.set_global(None) + pipeline.quantizer.set_module_type(torch.nn.Conv2d, quant_cfg) + pipeline.quantizer.set_module_type(torch.nn.ReLU6, quant_cfg) + + +def test_mv2_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + mv2, model_inputs, aten_op=[], exir_op=[], use_to_edge_transform_and_lower=True + ) + pipeline.run() + + +def test_mv2_tosa_FP_channels_last(): + input_tensor = model_inputs[0].to(memory_format=torch.channels_last) + pipeline = TosaPipelineFP[input_t]( + mv2, + (input_tensor,), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + # Changing memory format leads to an unsupported as_strided_copy op being inserted into the graph, + # leading to a graph break. + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 2} + ) + pipeline.run() + + +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_tosa_INT(per_channel_quantization): + pipeline = TosaPipelineINT[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_u55_INT(per_channel_quantization): + pipeline = EthosU55PipelineINT[input_t]( + mv2, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_u85_INT(per_channel_quantization): + pipeline = EthosU85PipelineINT[input_t]( + mv2, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("per_channel_quantization", quant_test_data) +def test_mv2_vgf_quant(per_channel_quantization): + pipeline = VgfPipeline[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_mv2_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() + + +def test_mv2_tosa_INT_FP_partial_quant(): + pipeline = TosaPipelineINT[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + tosa_extensions=["FP"], + use_to_edge_transform_and_lower=True, + atol=0.20, + ) + _use_partial_quantizer(pipeline) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_mv2_partial_quant_vgf_quant(): + pipeline = VgfPipeline[input_t]( + mv2, + model_inputs, + aten_op=[], + exir_op=[], + quantize=True, + atol=0.10, + ) + _use_partial_quantizer(pipeline) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v3_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v3_arm.py new file mode 100644 index 0000000..d17fc48 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_mobilenet_v3_arm.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchvision import models, transforms # type: ignore[import-untyped] + +mv3 = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights) +mv3 = mv3.eval() + +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +input_tensor = torch.rand(1, 3, 232, 232) + +model_inputs = (normalize(input_tensor),) +input_t = Tuple[torch.Tensor] + + +@pytest.mark.slow +def test_mv3_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + mv3, model_inputs, aten_op=[], exir_op=[], use_to_edge_transform_and_lower=True + ) + pipeline.run() + + +@pytest.mark.slow +def test_mv3_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + mv3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +def test_mv3_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + mv3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +def test_mv3_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + mv3, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@pytest.mark.slow +def test_mv3_vgf_quant(): + pipeline = VgfPipeline[input_t]( + mv3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + atol=0.5, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_mv3_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + mv3, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_functional.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_functional.py new file mode 100644 index 0000000..7892534 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_functional.py @@ -0,0 +1,124 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +""" +Tests 10 popular torch.nn.functional not tested in other ways or training related +- normalize +- grid_sample +- one_hot +- softplus +- cosine_similarity +- unfold +- elu +- fold +- affine_grid +- max_pool1d +- threshold +""" +from typing import Callable + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +def module_factory(function: Callable) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def forward(self, *args): + return function(*args) + + return ModuleWrapper() + + +example_input = torch.rand(1, 6, 16, 16) + +module_tests = { + "normalize": (module_factory(torch.nn.functional.normalize), (example_input,)), + "grid_sample": ( + module_factory(torch.nn.functional.grid_sample), + (torch.rand(1, 1, 4, 4), torch.rand(1, 5, 5, 2)), + ), + "one_hot": ( + module_factory(torch.nn.functional.one_hot), + (torch.randint(0, 5, (2, 2, 5, 5)), 5), + ), + "softplus": (module_factory(torch.nn.functional.softplus), (example_input,)), + "cosine_similarity": ( + module_factory(torch.nn.functional.cosine_similarity), + (example_input, example_input), + ), + "unfold": ( + module_factory(torch.nn.functional.unfold), + (torch.randn(1, 3, 10, 12), (4, 5)), + ), + "elu": (module_factory(torch.nn.functional.elu), (example_input,)), + "fold": ( + module_factory(torch.nn.functional.fold), + (torch.randn(1, 12, 12), (4, 5), (2, 2)), + ), + "affine_grid": ( + module_factory(torch.nn.functional.affine_grid), + (torch.rand(1, 2, 3), (1, 2, 10, 10)), + ), + "max_pool1d": ( + module_factory(torch.nn.functional.max_pool1d), + (torch.randn(20, 16, 50), 4), + ), + "threshold": ( + module_factory(torch.nn.functional.threshold), + (example_input, 0.5, 0.1), + ), +} + +input_t = tuple[torch.Tensor] + + +@parametrize( + "test_data", + module_tests, +) +def test_nn_functional_tosa_FP(test_data): + module, inputs = test_data + pipeline = TosaPipelineFP[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=False + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e + + +@parametrize( + "test_data", + module_tests, +) +def test_nn_functional_tosa_INT(test_data): + module, inputs = test_data + pipeline = TosaPipelineINT[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + if pipeline.has_stage("check_not.quant_nodes"): + pipeline.pop_stage("check_not.quant_nodes") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_modules.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_modules.py new file mode 100644 index 0000000..c798e99 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nn_modules.py @@ -0,0 +1,161 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +""" +Tests 10 popular nn modules not tested in other ways or training related. +- Embedding +- LeakyReLU +- BatchNorm1d +- AdaptiveAvgPool2d +- ConvTranspose2d +- GRU +- GroupNorm +- InstanceNorm2d +- PReLU +- Transformer +""" + +from typing import Callable + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +def make_module_wrapper( + name: str, module_factory: Callable[[], torch.nn.Module] +) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def __init__(self): + super().__init__() + self._module = module_factory() + + def forward(self, *args, **kwargs): + return self._module(*args, **kwargs) + + ModuleWrapper.__name__ = name + ModuleWrapper.__qualname__ = name + return ModuleWrapper() + + +example_input = torch.rand(1, 6, 16, 16) + +module_tests = [ + ( + make_module_wrapper( + "EmbeddingModule", + lambda: torch.nn.Embedding(10, 10), + ), + (torch.LongTensor([[1, 2, 4, 5], [4, 3, 2, 9]]),), + ), + ( + make_module_wrapper("LeakyReLUModule", torch.nn.LeakyReLU), + (example_input,), + ), + ( + make_module_wrapper("BatchNorm1dModule", lambda: torch.nn.BatchNorm1d(16)), + (torch.rand(6, 16, 16),), + ), + ( + make_module_wrapper( + "AdaptiveAvgPool2dModule", + lambda: torch.nn.AdaptiveAvgPool2d((12, 12)), + ), + (example_input,), + ), + ( + make_module_wrapper( + "ConvTranspose2dModule", lambda: torch.nn.ConvTranspose2d(6, 3, 2) + ), + (example_input,), + ), + ( + make_module_wrapper("GRUModule", lambda: torch.nn.GRU(10, 20, 2)), + (torch.randn(5, 3, 10), torch.randn(2, 3, 20)), + ), + ( + make_module_wrapper("GroupNormModule", lambda: torch.nn.GroupNorm(2, 6)), + (example_input,), + ), + ( + make_module_wrapper( + "InstanceNorm2dModule", lambda: torch.nn.InstanceNorm2d(16) + ), + (example_input,), + ), + ( + make_module_wrapper("PReLUModule", torch.nn.PReLU), + (example_input,), + ), + ( + make_module_wrapper( + "TransformerModule", + lambda: torch.nn.Transformer( + d_model=64, + nhead=1, + num_encoder_layers=1, + num_decoder_layers=1, + dtype=torch.float32, + ), + ), + (torch.rand((10, 32, 64)), torch.rand((20, 32, 64))), + ), +] + +input_t = tuple[torch.Tensor] + +test_parameters = {str(test[0].__class__.__name__): test for test in module_tests} + + +@parametrize( + "test_data", + test_parameters, +) +def test_nn_modules_tosa_FP(test_data): + module, inputs = test_data + pipeline = TosaPipelineFP[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e + + +@parametrize( + "test_data", + test_parameters, + xfails={ + "TransformerModule": "AssertionError: Output 0 does not match reference output.", + }, +) +def test_nn_modules_tosa_INT(test_data): + module, inputs = test_data + pipeline = TosaPipelineINT[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + if pipeline.has_stage("check_not.quant_nodes"): + pipeline.pop_stage("check_not.quant_nodes") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nss.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nss.py new file mode 100644 index 0000000..e5e381c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_nss.py @@ -0,0 +1,146 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from huggingface_hub import hf_hub_download + +from ng_model_gym.usecases.nss.model.model_blocks import ( # type: ignore[import-not-found,import-untyped] + AutoEncoderV1, +) + +input_t = Tuple[torch.Tensor] # Input x + + +class NSS(torch.nn.Module): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.auto_encoder = AutoEncoderV1() + + +def nss() -> AutoEncoderV1: + """Get an instance of NSS with weights loaded.""" + + weights = hf_hub_download( + repo_id="Arm/neural-super-sampling", + filename="nss_v0.1.0_fp32.pt", + revision="2e9b606acd9fa25071825a12f0764f1c3bef9480", + ) + + nss_model = NSS() + nss_model.load_state_dict( + torch.load(weights, map_location=torch.device("cpu"), weights_only=True), + strict=False, + ) + return nss_model.auto_encoder + + +def example_inputs(): + return (torch.randn((1, 12, 544, 960)),) + + +def test_nss_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("export", pipeline.tester.dump_operator_distribution) + pipeline.run() + + +def test_nss_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.skip(reason="No support for aten_upsample_nearest2d_vec on U55") +@common.XfailIfNoCorstone300 +def test_nss_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + nss().eval(), + example_inputs(), + aten_ops=[], + exir_ops=[], + run_on_fvp=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="Fails at input memory allocation for input shape: [1, 12, 544, 960]" +) +@common.XfailIfNoCorstone320 +def test_nss_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + nss().eval(), + example_inputs(), + aten_ops=[], + exir_ops=[], + run_on_fvp=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.xfail( + reason="[MLETORCH-1430]: Double types are not supported in buffers in MSL" +) +@common.SkipIfNoModelConverter +def test_nss_vgf_FP(): + pipeline = VgfPipeline[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=False, + # Override tosa version to test FP-only path + tosa_version="TOSA-1.0+FP", + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_nss_vgf_INT(): + pipeline = VgfPipeline[input_t]( + nss().eval(), + example_inputs(), + aten_op=[], + exir_op=[], + symmetric_io_quantization=True, + use_to_edge_transform_and_lower=True, + run_on_vulkan_runtime=True, + quantize=True, + # Override tosa version to test INT-only path + tosa_version="TOSA-1.0+INT", + ) + pipeline.run() + + +ModelUnderTest = nss().eval() +ModelInputs = example_inputs() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_resnet18.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_resnet18.py new file mode 100644 index 0000000..8d795f3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_resnet18.py @@ -0,0 +1,98 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, +) + +from torchvision import transforms # type: ignore[import-untyped] +from torchvision.models import ( # type: ignore[import-untyped] + resnet18, + ResNet18_Weights, +) + +model = resnet18(weights=ResNet18_Weights) +model = model.eval() +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + +# Using torch.rand * 2 - 1 to generate numbers in the range [-1;1] like an RGB image +model_inputs = (normalize(torch.rand((1, 3, 224, 224)) * 2 - 1),) + +input_t = Tuple[torch.Tensor] + + +quant_test_data = { + "per_channel_quantization=true": True, + "per_channel_quantization=false": False, +} + + +def test_resnet_18_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("per_channel_quantization", quant_test_data) +def test_resnet_18_tosa_INT(per_channel_quantization): + pipeline = TosaPipelineINT[input_t]( + model, + model_inputs, + aten_op=[], + exir_op=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_resnet_18_u55_INT(per_channel_quantization): + pipeline = EthosU55PipelineINT[input_t]( + model, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@common.parametrize("per_channel_quantization", quant_test_data) +def test_resnet_18_u85_INT(per_channel_quantization): + pipeline = EthosU85PipelineINT[input_t]( + model, + model_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + per_channel_quantization=per_channel_quantization, + atol=0.25, + qtol=1, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_torch_functions.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_torch_functions.py new file mode 100644 index 0000000..5a6e4f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_torch_functions.py @@ -0,0 +1,151 @@ +# Copyright 2025 Arm Limited and/or its affiliates. + +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +""" +Tests 10 popular torch ops, not tested in other ways, training related or requring randomness. +- t +- zeros +- ones +- stack +- arange +- norm +- nonzero +- eye +- topk +- sort +""" + +from typing import Callable + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + + +def module_add_factory(function: Callable) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def forward(self, x, *args): + return x + function(*args).to(torch.float32) + + return ModuleWrapper() + + +def module_factory(function: Callable) -> torch.nn.Module: + class ModuleWrapper(torch.nn.Module): + def forward(self, *args): + return function(*args) + + return ModuleWrapper() + + +example_input = torch.rand(1, 6, 16, 16) + +module_tests = [ + ( + "t", + module_add_factory(torch.t), + ( + torch.rand(10, 6), + torch.rand(6, 10), + ), + ), + ( + "zeros", + module_add_factory(torch.zeros), + ( + torch.rand(4, 3, 2), + (4, 1, 2), + ), + ), + ( + "ones", + module_add_factory(torch.ones), + ( + torch.rand(4, 3, 2), + (4, 1, 2), + ), + ), + ( + "stack", + module_add_factory(torch.stack), + ( + torch.rand(1, 1, 1, 1), + (torch.rand(2, 3, 3), torch.rand(2, 3, 3)), + -2, + ), + ), + ("arange", module_add_factory(torch.arange), (torch.rand(1), 0, 10, 2)), + ("norm", module_factory(torch.norm), (torch.randn(5, 5),)), + ("nonzero", module_factory(torch.nonzero), (example_input,)), + ("eye", module_add_factory(torch.eye), (torch.rand(4, 4), 4)), + ("topk", module_factory(torch.topk), (torch.rand(10), 5)), + ("sort", module_factory(torch.sort), (torch.rand(5),)), +] + +input_t = tuple[torch.Tensor] + +test_parameters = {test[0]: test[1:] for test in module_tests} + + +@parametrize( + "test_data", + test_parameters, + xfails={ + "nonzero": "torch.fx.experimental.symbolic_shapes.GuardOnDataDependentSymNode: Could not guard on data-dependent expression Eq(u4, 0). " + "Requires dynamic output shape.", + "topk": "NotImplementedError: No registered serialization name for found", + "sort": "NotImplementedError: No registered serialization name for found", + }, +) +def test_torch_functions_tosa_FP(test_data): + module, inputs = test_data + pipeline = TosaPipelineFP[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e + + +@parametrize( + "test_data", + test_parameters, + xfails={ + "nonzero": "torch.fx.experimental.symbolic_shapes.GuardOnDataDependentSymNode: Could not guard on data-dependent expression Eq(u4, 0). " + "Requires dynamic output shape.", + "topk": "NotImplementedError: No registered serialization name for found", + "sort": "NotImplementedError: No registered serialization name for found", + }, + strict=True, +) +def test_torch_functions_tosa_INT(test_data): + module, inputs = test_data + pipeline = TosaPipelineINT[input_t]( + module, inputs, "", use_to_edge_transform_and_lower=True + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("check.quant_nodes") + pipeline.pop_stage("check_not.quant_nodes") + + try: + pipeline.run() + except RuntimeError as e: + if ( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + not in str(e) + ): + raise e diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_w2l_arm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_w2l_arm.py new file mode 100644 index 0000000..91e7732 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/models/test_w2l_arm.py @@ -0,0 +1,136 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +from torchaudio import models # type: ignore[import-untyped] + +input_t = Tuple[torch.Tensor] # Input x + + +def get_test_inputs(batch_size, num_features, input_frames): + return (torch.randn(batch_size, num_features, input_frames),) + + +class TestW2L(unittest.TestCase): + """Tests Wav2Letter.""" + + batch_size = 10 + input_frames = 400 + num_features = 1 + + model_example_inputs = get_test_inputs(batch_size, num_features, input_frames) + + all_operators = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten__log_softmax_default", + "executorch_exir_dialects_edge__ops_aten_relu_default", + ] + + @staticmethod + def create_model(input_type: str = "waveform"): + return models.Wav2Letter( + num_features=TestW2L.num_features, input_type=input_type + ).eval() + + +@pytest.mark.slow # about 3min on std laptop +def test_w2l_tosa_FP(): + pipeline = TosaPipelineFP[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow # about 1min on std laptop +@pytest.mark.flaky +def test_w2l_tosa_INT(): + pipeline = TosaPipelineINT[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone300 +@pytest.mark.xfail( + reason="Wav2Letter fails on U55 due to insufficient memory", + strict=True, +) +def test_w2l_u55_INT(): + pipeline = EthosU55PipelineINT[input_t]( + # Use "power_spectrum" variant because the default ("waveform") has a + # conv1d layer with an unsupported stride size. + TestW2L.create_model("power_spectrum"), + TestW2L.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.slow +@common.XfailIfNoCorstone320 +@pytest.mark.skip(reason="Intermittent timeout issue: MLETORCH-856") +def test_w2l_u85_INT(): + pipeline = EthosU85PipelineINT[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@pytest.mark.slow +def test_w2l_vgf_quant(): + pipeline = VgfPipeline[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_w2l_vgf_no_quant(): + pipeline = VgfPipeline[input_t]( + TestW2L.create_model(), + TestW2L.model_example_inputs, + aten_op=[], + exir_op=TestW2L.all_operators, + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_abs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_abs.py new file mode 100644 index 0000000..9e8ad2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_abs.py @@ -0,0 +1,101 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.abs.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_abs_default" + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Abs(torch.nn.Module): + test_parameters = { + "zeros": lambda: (torch.zeros(5),), + "full": lambda: (torch.full((5,), -1, dtype=torch.float32),), + "ones": lambda: (torch.ones(5) * -1,), + "randn_1d": lambda: (torch.randn(8),), + "randn_3d": lambda: (torch.randn(2, 3, 4),), + "randn_4d": lambda: (torch.randn(1, 2, 3, 4),), + "torch_normal": lambda: (torch.normal(mean=0, std=10, size=(2, 3, 4)),), + } + + def forward(self, x): + return torch.abs(x) + + +@common.parametrize("test_data", Abs.test_parameters) +def test_abs_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1](Abs(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +def test_abs_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1](Abs(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.XfailIfNoCorstone300 +def test_abs_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.XfailIfNoCorstone320 +def test_abs_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.SkipIfNoModelConverter +def test_abs_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Abs.test_parameters) +@common.SkipIfNoModelConverter +def test_abs_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Abs(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acos.py new file mode 100644 index 0000000..be91bd7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acos.py @@ -0,0 +1,121 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] +aten_op = "torch.ops.aten.acos.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__acos_default" + + +test_data_suite = { + "ones": lambda: torch.ones(1, 7, 10, 12), + "rand_in_range": lambda: (torch.rand(10, 10) - 0.5) * 2, # Uniform in [-1, 1) + "ramp_valid": lambda: torch.linspace(-1.0, 1.0, steps=160), + "edge_cases": lambda: torch.tensor([-1.0, 0.0, 1.0]), + "1d_tensor": lambda: torch.linspace(-1.0, 1.0, steps=10), # Shape: [10] + "2d_batch": lambda: torch.tensor( + [[-1.0, -0.5, 0.0, 0.5, 1.0], [0.9, -0.9, 0.3, -0.3, 0.0]] + ), # Shape: [2, 5] + "3d_batch": lambda: torch.rand(4, 5, 6) * 2 - 1, # Shape: [4, 5, 6] in [-1, 1) + "3d_mixed_shape": lambda: (torch.rand(7, 15, 2) - 0.5) * 2, + "4d_mixed": lambda: torch.linspace(-1, 1, steps=1 * 3 * 4 * 5).reshape( + 1, 3, 4, 5 + ), # Shape: [2, 3, 4, 5] + "4d_random": lambda: (torch.rand(1, 5, 10, 7) - 0.5) * 2, + "bool_casted": lambda: torch.ones(3, 3, dtype=torch.bool).to( + dtype=torch.float32 + ), # All 1.0 (edge case) +} + + +class Acos(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.acos(x) + + +@common.parametrize("test_data", test_data_suite) +def test_acos_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Acos(), + (test_data(),), + aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_acos_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Acos(), + (test_data(),), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_acos_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acos(), + (test_data(),), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_acos_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Acos(), + (test_data(),), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acos_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acos(), + (test_data(),), + [], + [], + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acos_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acos(), + (test_data(),), + [], + [], + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acosh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acosh.py new file mode 100644 index 0000000..48490a9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_acosh.py @@ -0,0 +1,137 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x +aten_op = "torch.ops.aten.acosh.default" + + +test_data_suite = { + # Valid input cases + "ones": lambda: torch.ones(1, 7, 10, 12), + "just_above_one": lambda: torch.tensor([1.0001, 1.01, 1.1, 2.0]), + "rand_valid": lambda: torch.rand(10, 10) * 10 + 1, # [1, 11) + "ramp_valid": lambda: torch.linspace(1.0, 20.0, steps=160), + "large": lambda: torch.tensor([10.0, 100.0, 1000.0, 1e6]), + "mixed_valid": lambda: torch.tensor([1.0, 2.0, 10.0, 100.0]), +} + +test_data_suite_xfails = { + # Invalid input cases (should return nan or error) + "zeros": lambda: torch.zeros(1, 5, 3, 2), + "neg_ones": lambda: -torch.ones(10, 10, 10), + "rand_invalid": lambda: torch.rand(10, 10), # [0, 1) + "ramp_invalid": lambda: torch.linspace(-10.0, 0.99, steps=160), + "near_zero": lambda: torch.tensor([-1e-6, 0.0, 1e-6]), + "large_negative": lambda: torch.tensor([-100.0, -10.0, 0.0]), +} + + +class Acosh(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.acosh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_acosh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Acosh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_acosh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_acosh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_xfails) +@pytest.mark.xfail(reason="Invalid inputs are currently not handled") +def test_acosh_u55_INT_xfail(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_acosh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_xfails) +@pytest.mark.xfail(reason="Invalid inputs are currently not handled") +def test_acosh_u85_INT_xfail(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Acosh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acosh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acosh(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_acosh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Acosh(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_adaptive_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_adaptive_avg_pool2d.py new file mode 100644 index 0000000..6197c37 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_adaptive_avg_pool2d.py @@ -0,0 +1,242 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +exir_op = "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default" + +input_t = Tuple[torch.Tensor] + + +class AdaptiveAvgPool2d(torch.nn.AdaptiveAvgPool2d): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs) + + +test_modules = { + "output_bigger_than_input_1_to_3": lambda: ( + AdaptiveAvgPool2d((3, 3)), + (torch.rand(1, 3, 1, 1),), + ), + "output_bigger_than_input_7_to_10": lambda: ( + AdaptiveAvgPool2d((10, 10)), + (torch.rand(1, 3, 7, 7),), + ), + "output_1x1": lambda: (AdaptiveAvgPool2d((1, 1)), (torch.rand(1, 4, 8, 8),)), + "output_2x2": lambda: (AdaptiveAvgPool2d((2, 2)), (torch.rand(1, 4, 10, 10),)), + "output_4x4": lambda: (AdaptiveAvgPool2d((4, 4)), (torch.rand(1, 5, 15, 15),)), + "output_2x3": lambda: (AdaptiveAvgPool2d((2, 3)), (torch.rand(1, 3, 9, 13),)), + "output_h_keep": lambda: ( + AdaptiveAvgPool2d((2, None)), + (torch.rand(1, 3, 10, 16),), + ), + "output_w_keep": lambda: ( + AdaptiveAvgPool2d((None, 4)), + (torch.rand(1, 3, 14, 20),), + ), + "output_5x5": lambda: (AdaptiveAvgPool2d((5, 5)), (torch.rand(1, 3, 25, 25),)), + "output_3x5": lambda: (AdaptiveAvgPool2d((3, 5)), (torch.rand(1, 3, 15, 20),)), + "output_7x1": lambda: (AdaptiveAvgPool2d((7, 1)), (torch.rand(1, 3, 21, 3),)), + "output_1x7": lambda: (AdaptiveAvgPool2d((1, 7)), (torch.rand(1, 3, 3, 21),)), + "output_3xNone": lambda: (AdaptiveAvgPool2d((3, None)), (torch.rand(1, 3, 9, 24),)), + "output_Nonex3": lambda: (AdaptiveAvgPool2d((None, 3)), (torch.rand(1, 3, 24, 9),)), + "pool_h_static_w_none": lambda: ( + AdaptiveAvgPool2d((3, None)), + (torch.rand(1, 3, 9, 17),), + ), + "pool_h_none_w_static": lambda: ( + AdaptiveAvgPool2d((None, 5)), + (torch.rand(1, 3, 15, 25),), + ), + "identity_pool": lambda: ( + AdaptiveAvgPool2d((10, 10)), + (torch.rand(1, 3, 10, 10),), + ), + "non_divisible_5x5_from_17x17": lambda: ( + AdaptiveAvgPool2d((5, 5)), + (torch.rand(1, 3, 17, 17),), + ), + "pool_height_only": lambda: ( + AdaptiveAvgPool2d((1, 6)), + (torch.rand(1, 3, 12, 6),), + ), + "pool_width_only": lambda: ( + AdaptiveAvgPool2d((6, 1)), + (torch.rand(1, 3, 6, 12),), + ), + "extreme_input_large": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 3, 128, 128),), + ), + "single_channel_input": lambda: ( + AdaptiveAvgPool2d((4, 4)), + (torch.rand(1, 1, 16, 16),), + ), + "high_channel_count": lambda: ( + AdaptiveAvgPool2d((2, 2)), + (torch.rand(1, 1024, 32, 32),), + ), + # Common input/output sizes found in models + "output_7x7_from_14x14": lambda: ( + AdaptiveAvgPool2d((7, 7)), + (torch.rand(1, 512, 14, 14),), + ), + "output_1x1_from_8x8": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 2048, 8, 8),), + ), + "output_1x1_from_19": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 2560, 19, 19),), + ), + "output_1x1_from_7x7": lambda: ( + AdaptiveAvgPool2d((1, 1)), + (torch.rand(1, 1280, 7, 7),), + ), +} + + +@common.parametrize("test_module", test_modules) +def test_adaptive_avg_pool2d_tosa_FP(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineFP[input_t]( + model, + input_tensor, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_adaptive_avg_pool2d_tosa_INT(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_adaptive_avg_pool2d_tosa_INT_a16w8(test_module): + """Test adaptive_avg_pool2d with int16 I/O quantization for TOSA INT.""" + model, input_tensor = test_module() + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op=[], + exir_op=exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_adaptive_avg_pool2d_u55_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +# Remove high_channel_count & output_1x1_from_19 due to 2MB SRAM access on U55 +u55_test_modules = test_modules +for key in ["high_channel_count", "output_1x1_from_19"]: + u55_test_modules.pop(key) + + +@common.parametrize("test_module", u55_test_modules) +@common.XfailIfNoCorstone300 +def test_adaptive_avg_pool2d_u55_INT_a16w8(test_module): + """Test adaptive_avg_pool2d with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + a16w8_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_adaptive_avg_pool2d_u85_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_adaptive_avg_pool2d_u85_INT_a16w8(test_module): + """Test adaptive_avg_pool2d with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_ops=[], + exir_ops=exir_op, + a16w8_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_no_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + [], + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + [], + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_add.py new file mode 100644 index 0000000..31c31c3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_add.py @@ -0,0 +1,291 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer import arm_quantizer +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from torchao.quantization.pt2e import HistogramObserver +from torchao.quantization.pt2e.quantizer import QuantizationSpec + +aten_op = "torch.ops.aten.add.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_add_Tensor" + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Add(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x + x + + test_data: list[input_t1] = { + "5d_float": lambda: (torch.FloatTensor([1, 2, 3, 5, 7]),), + "1d_ones": lambda: ((3 * torch.ones(8),)), + "1d_randn": lambda: (10 * torch.randn(8),), + "4d_ones_1": lambda: (torch.ones(1, 1, 4, 4),), + "4d_ones_2": lambda: (torch.ones(1, 3, 4, 2),), + } + + +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class Add2(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x + y + + test_data: list[input_t2] = { + "5d_float": lambda: ( + torch.FloatTensor([1, 2, 3, 5, 7]), + (torch.FloatTensor([2, 1, 2, 1, 10])), + ), + "4d_ones": lambda: (torch.ones(1, 10, 4, 6), torch.ones(1, 10, 4, 6)), + "4d_randn_1": lambda: (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "4d_randn_2": lambda: (torch.randn(1, 3, 4, 4), torch.randn(1, 3, 4, 4)), + "4d_randn_big": lambda: ( + (1 << 30) * torch.randn(1, 1, 4, 4), + torch.randn(1, 1, 4, 1), + ), + "4d_randn_1_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.ones(1, 1, 4, 4), + ), + "4d_big_small": lambda: ( + (10e10) * torch.randn(1, 10, 20, 30), + torch.randn(1, 10, 20, 30), + ), + } + + +class Add3(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return torch.add(x, y, alpha=1.5) + + test_data: list[input_t2] = { + "3d_randn_diff_rank": lambda: (torch.randn(1, 4, 5), torch.randn(4, 1)), + "4d_randn_diff_rank": lambda: (torch.randn(1, 1, 4, 4), torch.randn(4, 1)), + "4d_randn_diff_rank_2": lambda: (torch.randn(4, 1), torch.randn(1, 1, 4, 5)), + } + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Add(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Add(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_INT_i32(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Add(), test_data(), aten_op, exir_op) + + pipeline.quantizer.set_io(arm_quantizer.get_symmetric_quantization_config()) + observer_options = {"eps": 2**-16} + observer = HistogramObserver.with_args(**observer_options) + input_act_qspec = QuantizationSpec( + torch.int32, + observer, + qscheme=torch.per_tensor_symmetric, + quant_max=2**31 - 1, + quant_min=-(2**31), + ) + output_act_qspec = QuantizationSpec( + torch.int32, + observer, + qscheme=torch.per_tensor_symmetric, + quant_max=2**31 - 1, + quant_min=-(2**31), + ) + quantization_config = arm_quantizer.QuantizationConfig( + input_act_qspec, output_act_qspec, None, None + ) + pipeline.quantizer.set_global(quantization_config) + + # Check that we get the additional (dq -> q + pipeline.add_stage_after( + "export", pipeline.tester.check_count, {"torch.ops.quantized_decomposed": 8} + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone300 +def test_add_tensor_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone320 +def test_add_tensor_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +def test_add_tensor_tosa_FP_2(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2](Add2(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Add3.test_data) +def test_add_tensor_tosa_FP_3(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2](Add3(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Add3.test_data) +def test_add_tensor_tosa_INT_3(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2](Add3(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +def test_add_tensor_tosa_INT_2(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2](Add2(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +@common.XfailIfNoCorstone300 +def test_add_tensor_u55_INT_2(test_data: input_t2): + pipeline = EthosU55PipelineINT[input_t2]( + Add2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add2.test_data) +@common.XfailIfNoCorstone320 +def test_add_tensor_u85_INT_2(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Add2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.SkipIfNoModelConverter +def test_add_tensor_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.SkipIfNoModelConverter +def test_add_tensor_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +def test_add_tensor_tosa_INT_16a8w(test_data: input_t1): + """Test add operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone300 +def test_add_tensor_u55_INT_16a8w(test_data: input_t1): + """Test add operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", Add.test_data) +@common.XfailIfNoCorstone320 +def test_add_tensor_u85_INT_16a8w(test_data: input_t1): + """Test add operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Add(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_addmm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_addmm.py new file mode 100644 index 0000000..e951ced --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_addmm.py @@ -0,0 +1,285 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.addmm.default" + +exir_op = "executorch_exir_dialects_edge__ops_aten__addmm_default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor, torch.Tensor] # Input x1, x2, x3 + + +test_data_suite = { + "basic": [ + torch.tensor([[1.0, 2.0], [3.0, 4.0]]), + torch.tensor([[1.0, 0.0], [0.0, 1.0]]), + torch.tensor([[1.0, 2.0], [3.0, 4.0]]), + 1.0, + 1.0, + ], + "zeros": [torch.zeros(2, 2), torch.zeros(2, 3), torch.zeros(3, 2), 1.0, 1.0], + "beta_only": [ + torch.tensor([[10.0, 20.0], [30.0, 40.0]]), + torch.randn(2, 3), + torch.randn(3, 2), + 0.0, + 1.0, + ], + "alpha_only": [ + torch.tensor([[10.0, 20.0], [30.0, 40.0]]), + torch.randn(2, 3), + torch.randn(3, 2), + 1.0, + 0.0, + ], + "scaled": [ + torch.ones(2, 2), + torch.tensor([[1.0, 2.0], [3.0, 4.0]]), + torch.tensor([[5.0, 6.0], [7.0, 8.0]]), + 0.5, + 2.0, + ], + "negative_scalars": [ + torch.tensor([[1.0, -1.0], [-1.0, 1.0]]), + torch.tensor([[2.0, 0.0], [0.0, 2.0]]), + torch.tensor([[1.0, 1.0], [1.0, 1.0]]), + -1.0, + -1.0, + ], + "non_square": [torch.ones(3, 4), torch.rand(3, 2), torch.rand(2, 4), 1.0, 1.0], + "large_values": [ + torch.full((2, 2), 1e6), + torch.full((2, 3), 1e3), + torch.full((3, 2), 1e3), + 1.0, + 1.0, + ], + "small_values": [ + torch.full((2, 2), 1e-6), + torch.full((2, 3), 1e-3), + torch.full((3, 2), 1e-3), + 1.0, + 1.0, + ], + "random": [torch.randn(4, 5), torch.randn(4, 3), torch.randn(3, 5), 1.0, 1.0], + "broadcast_bias_row": [ + torch.randn(1, 2), + torch.randn(3, 4), + torch.randn(4, 2), + 1.0, + 1.0, + ], + "row_bias": [ + torch.randn(3, 1), + torch.randn(3, 4), + torch.randn(4, 4), + 1.0, + 1.0, + ], + "scalar_bias": [ + torch.tensor(2.0), + torch.randn(5, 3), + torch.randn(3, 6), + 1.0, + 1.0, + ], +} + + +class Addmm(torch.nn.Module): + def forward( + self, + x1: torch.Tensor, + x2: torch.Tensor, + x3: torch.Tensor, + alpha: float, + beta: float, + ) -> torch.Tensor: + return torch.addmm(x1, x2, x3, alpha=alpha, beta=beta) + + +@common.parametrize("test_data", test_data_suite) +def test_addmm_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Addmm(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_addmm_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_addmm_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_addmm_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_addmm_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Addmm(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_addmm_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Addmm(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_addmm_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_addmm_16a8w_tosa_INT(test_data: input_t1): + """Test addmm (FC layer) operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_op=[], + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_addmm_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +@pytest.mark.xfail( + reason="Vela compilation fails with 'Invalid arguments' for int16 addmm operations" +) +def test_addmm_16a8w_u55_INT(test_data: input_t1): + """Test addmm (FC layer) operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_addmm_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_addmm_16a8w_u85_INT(test_data: input_t1): + """Test addmm (FC layer) operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Addmm(), + (*test_data,), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_addmm_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_alias_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_alias_copy.py new file mode 100644 index 0000000..29c6893 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_alias_copy.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class AliasCopy(torch.nn.Module): + """ + Tests proper handling of alias_copy when used directly. + + alias_copy can also appear from PyTorch/ExecuTorch optimizations + such as `x.transpose(0, 0)`. This is optimized to an alias_copy but + not before dq/q operators are added. + """ + + aten_op = "torch.ops.aten.alias_copy.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_alias_copy_default" + + test_data: dict[input_t1] = { + "1d_ramp": lambda: (torch.arange(-16, 16, 0.2),), + "2d_ones": lambda: (torch.ones(5, 5),), + "3d_rand": lambda: (torch.rand(3, 5, 5),), + "4d_zeros": lambda: (torch.zeros(1, 10, 10, 10),), + } + + def __init__(self): + super().__init__() + + def forward(self, x: torch.Tensor): + return ( + torch.alias_copy(x) * 1 + ) # Multiply by one to make sure it is partitioned. + + +@common.parametrize("test_data", AliasCopy.test_data) +def test_alias_tosa_FP(test_data: input_t1): + TosaPipelineFP[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +def test_alias_tosa_INT(test_data: input_t1): + TosaPipelineINT[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.XfailIfNoCorstone300 +def test_alias_u55_INT(test_data: input_t1): + EthosU55PipelineINT[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.XfailIfNoCorstone320 +def test_alias_u85_INT(test_data: input_t1): + EthosU85PipelineINT[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + ).run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.SkipIfNoModelConverter +def test_alias_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AliasCopy.test_data) +@common.SkipIfNoModelConverter +def test_alias_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AliasCopy(), + test_data(), + AliasCopy.aten_op, + AliasCopy.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amax.py new file mode 100644 index 0000000..7109def --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amax.py @@ -0,0 +1,191 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Amax(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int | Tuple[int], bool] + aten_op = ["torch.ops.aten.amax"] + + def __init__(self, dim, keep_dims): + self.dim = dim + self.keep_dims = keep_dims + super().__init__() + + def forward(self, x): + return torch.amax(x, self.dim, self.keep_dims) + + test_data: Dict[str, input_t] = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0, False), + "rank_2_dim_1_keep_dims": lambda: ((torch.rand([2, 2]),), (1,), True), + "rank_4_all_dim": lambda: ((torch.rand([1, 2, 5, 5]),), (0, 1, 2, 3), False), + "rank_4_0,3_keep_dims": lambda: ((torch.rand([1, 2, 2, 2]),), (0, 3), True), + "rank_4_mult_batches": lambda: ((torch.rand([2, 2, 2, 2]),), (0), True), + } + + +class Max(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int] + aten_op = ["torch.ops.aten.amax"] + + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x = torch.max(x, self.dim, False) + return x[0] + + test_data: Dict[str, input_t] = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0), + "rank_2_dim_1": lambda: ((torch.rand([2, 2]),), 1), + "rank_4_dim_2": lambda: ((torch.rand([2, 2, 2, 2]),), 2), + "rank_4_dim_3": lambda: ((torch.rand([2, 2, 2, 2]),), 3), + } + + +class MaxWithIndex(torch.nn.Module): + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x, i = torch.max(x, self.dim) + return x, i + + +@common.parametrize("test_data", Amax.test_data) +def test_amax_tosa_FP(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineFP[Amax.input_t](Amax(dim, keep_dims), data, Amax.aten_op) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +def test_amax_tosa_INT(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineINT[Amax.input_t](Amax(dim, keep_dims), data, Amax.aten_op) + pipeline.run() + + +def test_amax_u55_INT_not_delegated(): + data, dim, keep_dims = Amax.test_data["rank_4_all_dim"]() + pipeline = OpNotSupportedPipeline[Amax.input_t]( + Amax(dim, keep_dims), + data, + {" executorch_exir_dialects_edge__ops_aten_amax_default": 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +@common.XfailIfNoCorstone320 +def test_amax_u85_INT(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + pipeline = EthosU85PipelineINT[Amax.input_t]( + Amax(dim, keep_dims), + data, + Amax.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +def test_max_dim_tosa_FP_to_amax(test_data: Max.input_t): + data, dim = test_data() + pipeline = TosaPipelineFP[Max.input_t](Max(dim), data, "torch.ops.aten.max") + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +def test_max_dim_tosa_INT_to_amax(test_data: Max.input_t): + data, dim = test_data() + module = Max(dim) + pipeline = TosaPipelineINT[Max.input_t](module, data, "torch.ops.aten.amax") + pipeline.run() + + +@pytest.mark.xfail(reason="MLETORCH-718 : Quantization of indices in arm_quantizer") +def test_max_dim_tosa_INT_not_delegated(): + data, dim = Max.test_data()["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Max.input_t]( + MaxWithIndex(dim), data, {}, quantize=True + ) + pipeline.run() + + +def test_max_dim_tosa_FP_not_delegated(): + data, dim = Max.test_data["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Max.input_t](MaxWithIndex(dim), data, {}) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +@common.SkipIfNoModelConverter +def test_amax_vgf_no_quant(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + module = Amax(dim, keep_dims) + pipeline = VgfPipeline[Amax.input_t]( + module, + data, + Amax.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Amax.test_data) +@common.SkipIfNoModelConverter +def test_amax_vgf_quant(test_data: Amax.input_t): + data, dim, keep_dims = test_data() + module = Amax(dim, keep_dims) + pipeline = VgfPipeline[Amax.input_t]( + module, + data, + Amax.aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +@common.SkipIfNoModelConverter +def test_max_dim_vgf_no_quant_to_amax(test_data: Max.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Max.input_t]( + Max(dim), + data, + "torch.ops.aten.max", + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Max.test_data) +@common.SkipIfNoModelConverter +def test_max_dim_vgf_quant_to_amax(test_data: Max.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Max.input_t]( + Max(dim), + data, + "torch.ops.aten.amax", + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amin.py new file mode 100644 index 0000000..c90980f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_amin.py @@ -0,0 +1,205 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Amin(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int | Tuple[int], bool] + aten_op = ["torch.ops.aten.amin"] + + def __init__(self, dim, keep_dims): + self.dim = dim + self.keep_dims = keep_dims + super().__init__() + + def forward(self, x): + if self.dim is None: + return torch.amin(x, keepdim=self.keep_dims) + else: + return torch.amin(x, self.dim, self.keep_dims) + + test_data: Dict = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0, False), + "rank_2_dim_1_keep_dims": lambda: ((torch.rand([2, 2]),), (1,), True), + "rank_4_all_dim": lambda: ((torch.rand([1, 2, 5, 5]),), (0, 1, 2, 3), False), + "rank_4_no_dim": lambda: ((torch.rand([1, 2, 5, 5]),), None, False), + "rank_4_0,3_keep_dims": lambda: ((torch.rand([1, 2, 2, 2]),), (0, 3), True), + "rank_4_mult_batches": lambda: ((torch.rand([2, 2, 2, 2]),), (0), True), + } + + +class Min(torch.nn.Module): + input_t = Tuple[Tuple[torch.Tensor], int] + aten_op = ["torch.ops.aten.amin"] + + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x = torch.min(x, self.dim) + return x[0] + + test_data: Dict = { + "rank_1_dim_0": lambda: ((torch.rand([10]),), 0), + "rank_2_dim_1": lambda: ((torch.rand([2, 2]),), 1), + "rank_4_dim_2": lambda: ((torch.rand([2, 2, 2, 2]),), 2), + "rank_4_dim_3": lambda: ((torch.rand([2, 2, 2, 2]),), 3), + } + + +class MinWithIndex(torch.nn.Module): + def __init__(self, dim): + self.dim = dim + super().__init__() + + def forward(self, x): + x, i = torch.min(x, self.dim) + return x, i + + +@common.parametrize("test_data", Amin.test_data) +def test_amin_tosa_FP(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineFP[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +def test_amin_tosa_INT(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = TosaPipelineINT[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + ) + pipeline.run() + + +def test_amin_u55_INT_not_delegated(): + data, dim, keep_dims = Amin.test_data["rank_4_all_dim"]() + pipeline = OpNotSupportedPipeline[Amin.input_t]( + Amin(dim, keep_dims), + data, + {" executorch_exir_dialects_edge__ops_aten_amin_default": 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +@common.XfailIfNoCorstone320 +def test_amin_u85_INT(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = EthosU85PipelineINT[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +def test_min_dim_tosa_FP_to_amin(test_data: Min.input_t): + data, dim = test_data() + pipeline = TosaPipelineFP[Min.input_t](Min(dim), data, "torch.ops.aten.min") + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +def test_min_dim_tosa_INT_to_amin(test_data: Min.input_t): + data, dim = test_data() + module = Min(dim) + pipeline = TosaPipelineINT[Min.input_t](module, data, "torch.ops.aten.amin") + pipeline.run() + + +@pytest.mark.xfail(reason="MLETORCH-718 : Quantization of indices in arm_quantizer") +def test_min_dim_tosa_INT_not_delegated(): + data, dim = Min.test_data["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Min.input_t]( + MinWithIndex(dim), + data, + {}, + quantize=True, + ) + pipeline.run() + + +def test_min_dim_tosa_FP_not_delegated(): + data, dim = Min.test_data["rank_4_dim_3"]() + pipeline = OpNotSupportedPipeline[Min.input_t](MinWithIndex(dim), data, {}) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +@common.SkipIfNoModelConverter +def test_amin_vgf_no_quant(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = VgfPipeline[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Amin.test_data) +@common.SkipIfNoModelConverter +def test_amin_vgf_quant(test_data: Amin.input_t): + data, dim, keep_dims = test_data() + pipeline = VgfPipeline[Amin.input_t]( + Amin(dim, keep_dims), + data, + Amin.aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +@common.SkipIfNoModelConverter +def test_min_dim_vgf_no_quant_to_amin(test_data: Min.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Min.input_t]( + Min(dim), + data, + "torch.ops.aten.min", + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Min.test_data) +@common.SkipIfNoModelConverter +def test_min_dim_vgf_quant_to_amin(test_data: Min.input_t): + data, dim = test_data() + pipeline = VgfPipeline[Min.input_t]( + Min(dim), + data, + "torch.ops.aten.amin", + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_any.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_any.py new file mode 100644 index 0000000..3cc3432 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_any.py @@ -0,0 +1,210 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class AnyDim(torch.nn.Module): + aten_op = "torch.ops.aten.any.dim" + exir_op = "executorch_exir_dialects_edge__ops_aten_any_dim" + + def forward(self, x: torch.Tensor, dim: int, keepdim: bool): + return torch.any(x, dim=dim, keepdim=keepdim) + + +class AnyDims(torch.nn.Module): + aten_op = "torch.ops.aten.any.dims" + exir_op = "executorch_exir_dialects_edge__ops_aten_any_dims" + + def forward(self, x: torch.Tensor, dim: List[int], keepdim: bool): + return torch.any(x, dim=dim, keepdim=keepdim) + + +class AnyReduceAll(torch.nn.Module): + aten_op = "torch.ops.aten.any.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_any_default" + + def forward(self, x: torch.Tensor): + return torch.any(x) + + +input_t1 = Tuple[torch.Tensor] # Input x + + +test_input: dict[input_t1] = { + "rank1": lambda: (torch.tensor([True, False, False], dtype=torch.bool), 0, True), + "rank1_squeeze": lambda: ( + torch.tensor([True, False, False], dtype=torch.bool), + -1, + False, + ), + "rank2": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + 0, + True, + ), + "rank2_squeeze": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + 0, + False, + ), + "rank2_dims": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + [0, 1], + True, + ), + "rank2_dims_squeeze": lambda: ( + torch.randint(0, 2, (2, 3), dtype=torch.bool), + [-2, 1], + False, + ), + "rank3_dims_squeeze": lambda: ( + torch.randint(0, 2, (6, 8, 10), dtype=torch.bool), + [1, 2], + False, + ), + "rank4": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + 1, + True, + ), + "rank4_squeeze": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + 1, + False, + ), + "rank4_dims": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + [0, 2], + True, + ), + "rank4_dims_squeeze": lambda: ( + torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool), + [1, -1], + False, + ), + "rank1_reduce_all": lambda: (torch.tensor([True, False, False], dtype=torch.bool),), + "rank2_reduce_all": lambda: (torch.randint(0, 2, (2, 3), dtype=torch.bool),), + "rank3_reduce_all": lambda: (torch.randint(0, 2, (6, 8, 10), dtype=torch.bool),), + "rank4_reduce_all": lambda: (torch.randint(0, 2, (1, 6, 8, 10), dtype=torch.bool),), +} + + +test_data = { + "any_rank1": lambda: (AnyDim(), test_input["rank1"]), + "any_rank1_squeeze": lambda: (AnyDim(), test_input["rank1_squeeze"]), + "any_rank2": lambda: (AnyDim(), test_input["rank2"]), + "any_rank2_squeeze": lambda: (AnyDim(), test_input["rank2_squeeze"]), + "any_rank2_dims": lambda: (AnyDims(), test_input["rank2_dims"]), + "any_rank2_dims_squeeze": lambda: (AnyDims(), test_input["rank2_dims_squeeze"]), + "any_rank3_dims_squeeze": lambda: (AnyDims(), test_input["rank3_dims_squeeze"]), + "any_rank4": lambda: (AnyDim(), test_input["rank4"]), + "any_rank4_squeeze": lambda: (AnyDim(), test_input["rank4_squeeze"]), + "any_rank4_dims": lambda: (AnyDims(), test_input["rank4_dims"]), + "any_rank4_dims_squeeze": lambda: (AnyDims(), test_input["rank4_dims_squeeze"]), + "any_rank1_reduce_all": lambda: (AnyReduceAll(), test_input["rank1_reduce_all"]), + "any_rank2_reduce_all": lambda: (AnyReduceAll(), test_input["rank2_reduce_all"]), + "any_rank3_reduce_all": lambda: (AnyReduceAll(), test_input["rank3_reduce_all"]), + "any_rank4_reduce_all": lambda: (AnyReduceAll(), test_input["rank4_reduce_all"]), +} + + +@common.parametrize("test_data", test_data) +def test_any_tosa_FP(test_data: input_t1): + op, test_input = test_data() + pipeline = TosaPipelineFP[input_t1]( + op, + test_input(), + op.aten_op, + op.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_any_tosa_INT(test_data: input_t1): + op, test_input = test_data() + pipeline = TosaPipelineINT[input_t1]( + op, + test_input(), + op.aten_op, + op.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_any_u55_INT(test_data: input_t1): + # Tests that we don't delegate these ops since they are not supported on U55. + op, test_input = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + op, + test_input(), + {op.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone320 +def test_any_u85_INT(test_data: input_t1): + op, test_input = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + op, + test_input(), + op.aten_op, + op.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_any_vgf_no_quant(test_data: input_t1): + op, data_fn = test_data() + pipeline = VgfPipeline[input_t1]( + op, + data_fn(), + op.aten_op, + op.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_any_vgf_quant(test_data: input_t1): + op, data_fn = test_data() + pipeline = VgfPipeline[input_t1]( + op, + data_fn(), + op.aten_op, + op.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_arange.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_arange.py new file mode 100644 index 0000000..90ab437 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_arange.py @@ -0,0 +1,258 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[Callable[[], input_t], tuple[float, float, float, torch.dtype]] + + +class ArangeAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.arange.start_step" + exir_op: str = "executorch_exir_dialects_edge__ops_aten_arange_start_step" + + def __init__(self, start: float, stop: float, step: float, dtype: torch.dtype): + super().__init__() + self.args = (start, stop, step) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.arange(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10": (lambda: (torch.randn(10, 1),), (0.0, 10.0, 1.0, torch.float32)), + "15": (lambda: (torch.randn(10),), (0.0, 15.0, 1.5, torch.float32)), + "100": (lambda: (torch.randn(10, 1),), (0.0, 10.0, 0.1, torch.float32)), + } + + test_data_dtypes: dict[str, test_data_t] = { + "fp32_int32": (lambda: (torch.randn(10),), (0.0, 10.0, 1.0, torch.int32)), + "fp32_int64": (lambda: (torch.randn(10),), (0.0, 10.0, 1.0, torch.int64)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (0.0, 10.0, 1.0, torch.int32), + ), + } + test_reject: dict[str, test_data_t] = { + "int32_int64": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (0.0, 10.0, 1.0, torch.int64), + ), + } + + +@common.parametrize("test_data", ArangeAdd.test_data) +def test_arange_start_step_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ArangeAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data_dtypes) +def test_arange_start_step_tosa_FP_dtypes(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ArangeAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_reject) +def test_arange_start_step_tosa_FP_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + ArangeAdd(*init_data), input_data(), non_delegated_ops={ArangeAdd.exir_op: 1} + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +def test_arange_start_step_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ArangeAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.XfailIfNoCorstone300 +def test_arange_start_step_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.XfailIfNoCorstone320 +def test_arange_start_step_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + ArangeAdd(*init_data), + input_data(), + ArangeAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.SkipIfNoModelConverter +def test_arange_start_step_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + module = ArangeAdd(*init_data) + pipeline = VgfPipeline[input_t]( + module, + input_data(), + module.aten_op, + module.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAdd.test_data) +@common.SkipIfNoModelConverter +def test_arange_start_step_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + module = ArangeAdd(*init_data) + pipeline = VgfPipeline[input_t]( + module, + input_data(), + module.aten_op, + module.exir_op, + quantize=True, + ) + pipeline.run() + + +class LinspaceAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.linspace.default" + exir_op: str = "executorch_exir_dialects_edge__ops_aten_arange_default" + + def __init__(self, start: float, stop: float, step: int, dtype: torch.dtype): + super().__init__() + self.args = (start, stop, step) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.linspace(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10": (lambda: (torch.randn(10, 1),), (0.0, 10.0, 100, torch.float32)), + "15": (lambda: (torch.randn(20),), (0.0, 15.0, 20, torch.float32)), + } + + +@common.parametrize("test_data", LinspaceAdd.test_data) +def test_linspace_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LinspaceAdd.test_data) +def test_linspace_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LinspaceAdd.test_data) +@common.SkipIfNoModelConverter +def test_linspace_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LinspaceAdd.test_data) +@common.SkipIfNoModelConverter +def test_linspace_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + LinspaceAdd(*init_data), + input_data(), + LinspaceAdd.aten_op, + LinspaceAdd.exir_op, + quantize=True, + ) + pipeline.run() + + +skip_str = "aten.arange.default is decomposed to aten.arange.start_step, so it will never exist in a lowered graph." + + +@pytest.mark.skip(reason=skip_str) +def test_arange_tosa_FP(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_tosa_INT(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_u55_INT(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_u85_INT(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_vgf_no_quant(): + pass + + +@pytest.mark.skip(reason=skip_str) +def test_arange_vgf_quant(): + pass diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asin.py new file mode 100644 index 0000000..e00e636 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asin.py @@ -0,0 +1,105 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x +aten_op = "torch.ops.aten.asin.default" + +test_data_suite = { + "zeros": lambda: torch.zeros(1, 5, 3, 2), # valid: asin(0) = 0 + "ones": lambda: torch.ones(10, 5, 15), # edge case: asin(1) = pi/2 + "neg_ones": lambda: -torch.ones(10, 5, 15), # edge case: asin(-1) = -pi/2 + "rand": lambda: (torch.rand(10, 10, 5) * 2) - 1, # uniform random in [-1, 1] + "ramp": lambda: torch.linspace(-1.0, 1.0, steps=160), # full domain coverage + "near_bounds": lambda: torch.tensor( + [-0.999, -0.9, -0.5, 0.0, 0.5, 0.9, 0.999] + ), # precision edge values + "pos_rand": lambda: torch.rand(7, 10, 2), # positive random values in [0, 1] +} + + +class Asin(torch.nn.Module): + def forward(self, x): + return torch.asin(x) + + +@common.parametrize("test_data", test_data_suite) +def test_asin_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Asin(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_asin_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Asin(), + (test_data(),), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_asin_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Asin(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_asin_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Asin(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asin_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asin(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asin_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asin(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asinh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asinh.py new file mode 100644 index 0000000..db902a3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_asinh.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x +aten_op = "torch.ops.aten.asinh.default" + +test_data_suite = { + "zeros": lambda: torch.zeros(1, 5, 3, 2), + "ones": lambda: torch.ones(10, 10, 10), + "neg_ones": lambda: -torch.ones(10, 10, 10), + "rand": lambda: (torch.rand(10, 10) - 0.5) * 20, + "ramp": lambda: torch.linspace(-10.0, 10.0, steps=160), + "near_zero": lambda: torch.tensor([-1e-6, 0.0, 1e-6]), + "large": lambda: torch.tensor([-100.0, -10.0, 0.0, 10.0, 100.0]), + "rand_4d": lambda: torch.randn(1, 3, 4, 5), +} + + +class Asinh(torch.nn.Module): + def forward(self, x): + return torch.asinh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_asinh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Asinh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_asinh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Asinh(), + (test_data(),), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_asinh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Asinh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_asinh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Asinh(), + (test_data(),), + aten_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asinh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asinh(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_asinh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Asinh(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_at.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_at.py new file mode 100644 index 0000000..8caa242 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_at.py @@ -0,0 +1,256 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op_mm = "torch.ops.aten.matmul.default" +exir_op_mm = "executorch_exir_dialects_edge__ops_aten_matmul_default" +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class AtMatMulSingleInput(torch.nn.Module): + test_data_generators = { + "rand_3d": lambda: (torch.rand(2, 5, 5),), + "rand_4d": lambda: (torch.rand(1, 2, 5, 5),), + } + + def forward(self, x: torch.Tensor): + return x @ x + + +class AtMatMulDoubleInput(torch.nn.Module): + test_data_generators = { + "rand_rand_3d": lambda: (torch.rand(2, 3, 5), torch.rand(2, 5, 2)), + "rand_rand_4d": lambda: (torch.rand(1, 2, 3, 5), torch.rand(1, 2, 5, 2)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x @ y + + +class AtMatMulMixedPattern1(torch.nn.Module): + test_data_generators = { + "rand_rand_rand_3d": lambda: ( + torch.rand(2, 5, 5), + torch.rand(2, 5, 2), + torch.rand(2, 2, 5), + ), + "rand_rand_rand_4d": lambda: ( + torch.rand(1, 2, 5, 5), + torch.rand(1, 2, 5, 2), + torch.rand(1, 2, 2, 5), + ), + } + + def forward(self, x1: torch.Tensor, x2: torch.Tensor, x3: torch.Tensor): + y1 = torch.matmul(x1, x1) + y2 = torch.matmul(x2, x3) + return y1 + y2 + + +class AtMatMulMixedPattern2(torch.nn.Module): + test_data_generators = { + "rand_rand_rand_3d": lambda: ( + torch.rand(2, 5, 5), + torch.rand(2, 5, 2), + torch.rand(2, 2, 5), + ), + "rand_rand_rand_4d": lambda: ( + torch.rand(1, 2, 5, 5), + torch.rand(1, 2, 5, 2), + torch.rand(1, 2, 2, 5), + ), + } + + def forward(self, x1: torch.Tensor, x2: torch.Tensor, x3: torch.Tensor): + y1 = torch.matmul(x1, x1) + y2 = torch.matmul(x2, x3) + return y1 @ y2 + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +def test_matmul_tosa_FP_at_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulSingleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +def test_matmul_tosa_FP_at_double_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulDoubleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +def test_matmul_tosa_FP_at_mixed_pattern1(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulMixedPattern1(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +def test_matmul_tosa_FP_at_mixed_pattern2(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + AtMatMulMixedPattern2(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +def test_matmul_tosa_INT_at_single_input(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulSingleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +def test_matmul_tosa_INT_at_double_input(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulDoubleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +def test_matmul_tosa_INT_at_mixed_pattern1(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulMixedPattern1(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +def test_matmul_tosa_INT_at_mixed_pattern2(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + AtMatMulMixedPattern2(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_double_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulDoubleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_mixed_pattern1(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern1(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_at_mixed_pattern2(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern2(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulDoubleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_double_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulDoubleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern1.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_mixed_pattern1(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern1(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AtMatMulMixedPattern2.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_at_mixed_pattern2(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + AtMatMulMixedPattern2(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atan.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atan.py new file mode 100644 index 0000000..4e103dc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atan.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.atan.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__atan_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10), + "zeros_alt_shape": torch.zeros(1, 10, 3, 5), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(1, 10, 3, 5) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Atan(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.atan(x) + + +@common.parametrize("test_data", test_data_suite) +def test_atan_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Atan(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_atan_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Atan(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_atan_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Atan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_atan_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Atan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atan_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Atan(), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atan_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Atan(), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atanh.py new file mode 100644 index 0000000..8ac2708 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_atanh.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.atanh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__atanh_default" + + +input_t1 = Tuple[torch.Tensor] + + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10), + "zeros_alt_shape": torch.zeros(1, 10, 3, 5), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(1, 10, 3, 5) - 0.5, + "ramp": torch.arange(-1, 1, 0.2), + "near_bounds": torch.tensor([-0.999999, -0.999, -0.9, 0.9, 0.999, 0.999999]), + "on_bounds": torch.tensor([-1.0, 1.0]), +} + + +class Atanh(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.atanh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_atanh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_atanh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_atanh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Atanh(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_atanh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Atanh(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atanh_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_atanh_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Atanh(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_avg_pool2d.py new file mode 100644 index 0000000..8885d19 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_avg_pool2d.py @@ -0,0 +1,295 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import conftest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "avg_pool2d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default" + +input_t = Tuple[torch.Tensor] + + +class AvgPool2d(torch.nn.modules.AvgPool2d): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs) + + +class BecomesMeanInToEdge(torch.nn.Module): + """This averagepool will be converted to mean when lowering to edge. This causes the decompose_meandim pass to not + trigger until the backend pipeline, which requires extra care. + """ + + def forward(self, x: torch.Tensor): + return torch.nn.functional.adaptive_avg_pool2d(x, (1, 1)) + + +test_modules = { + "zeros": lambda: (AvgPool2d(4, 2, 0, False), (torch.zeros(1, 16, 50, 32),)), + "ones": lambda: (AvgPool2d(4, 2, 0, False, True), (torch.ones(1, 16, 50, 32),)), + "rand": lambda: (AvgPool2d(4, 2, 0, False, True, 16), (torch.rand(1, 16, 50, 32),)), + "randn": lambda: ( + AvgPool2d(4, 2, 0, divisor_override=16), + (torch.randn(1, 16, 50, 32),), + ), + "kernel_3x3_stride_1_pad_1": lambda: ( + AvgPool2d((3, 3), (1, 1), 1), + (torch.rand(1, 16, 50, 32),), + ), + "kernel_3x2_stride_1x2_pad_1x0": lambda: ( + AvgPool2d((3, 2), (1, 2), (1, 0)), + (torch.rand(1, 16, 50, 32),), + ), + "kernel_4x6_stride_1x2_pad_2x3": lambda: ( + AvgPool2d((4, 6), (1, 2), (2, 3)), + (torch.rand(1, 16, 50, 32),), + ), + "non_divisible_window_adjust_padding": lambda: ( + AvgPool2d(3, 2, 1, count_include_pad=False), + (torch.rand(1, 16, 112, 112),), + ), + "non_divisible_window_adjust_padding_height": lambda: ( + AvgPool2d(3, (2, 1), 1), + (torch.rand(1, 16, 56, 56),), + ), + "non_divisible_window_adjust_padding_width": lambda: ( + AvgPool2d(3, (1, 2), 1, count_include_pad=False), + (torch.rand(1, 16, 56, 56),), + ), + "non_divisible_window_ceil_mode": lambda: ( + AvgPool2d(3, 2, 1, True), + (torch.rand(1, 16, 112, 112),), + ), + "non_divisible_window_height_ceil_mode": lambda: ( + AvgPool2d(3, (2, 1), 1, True, False), + (torch.rand(1, 1, 14, 14),), + ), + "non_divisible_window_width_ceil_mode": lambda: ( + AvgPool2d(3, (1, 2), 1, True, True), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override": lambda: ( + AvgPool2d(3, 2, 1, False, False, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override_count_include_pad": lambda: ( + AvgPool2d(3, 2, 1, False, True, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override_ceil_mode": lambda: ( + AvgPool2d(3, 2, 1, True, False, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "divisor_override_ceil_mode_count_include_pad": lambda: ( + AvgPool2d(3, 2, 1, True, True, divisor_override=2), + (torch.rand(1, 1, 14, 14),), + ), + "non_divisible_no_padding": lambda: ( + AvgPool2d(3, 2, 0), + (torch.rand(1, 16, 56, 56),), + ), + "non_divibile_window_adjust_padding+input": lambda: ( + AvgPool2d(3, 3, 1, count_include_pad=False), + (torch.rand(1, 16, 54, 54),), + ), + "non_divibile_window_height_adjust_padding+input": lambda: ( + AvgPool2d(3, (3, 1), 1), + (torch.rand(1, 16, 54, 54),), + ), + "non_divibile_window_width_adjust_padding+input": lambda: ( + AvgPool2d(3, (1, 3), 1, count_include_pad=False), + (torch.rand(1, 16, 54, 54),), + ), + "becomes_mean_rank3": lambda: (BecomesMeanInToEdge(), (torch.rand(2, 8, 8),)), + "becomes_mean_rank4": lambda: (BecomesMeanInToEdge(), (torch.rand(2, 2, 8, 8),)), + "becomes_mean_rank5": lambda: (BecomesMeanInToEdge(), (torch.rand(2, 2, 8, 8),)), +} + + +@common.parametrize("test_module", test_modules) +def test_avg_pool2d_tosa_FP(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineFP[input_t]( + model, + input_tensor, + aten_op, + exir_op, + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_avg_pool2d_tosa_INT(test_module): + model, input_tensor = test_module() + + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_avg_pool2d_tosa_INT_a16w8(test_module): + """Test avg_pool2d operation with int16 I/O quantization for TOSA INT.""" + model, input_tensor = test_module() + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + tosa_extensions=["int16"], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_avg_pool2d_u55_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_avg_pool2d_16a8w_u55_INT(test_module): + """Test avg_pool2d with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_avg_pool2d_u85_INT(test_module): + model, input_tensor = test_module() + + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_avg_pool2d_16a8w_u85_INT(test_module): + """Test avg_pool2d with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + model, input_tensor = test_module() + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_avg_pool2d_vgf_no_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_avg_pool2d_vgf_quant(test_module): + model, input_tensor = test_module() + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +reject_modules = { + "kernel_1x1_stride_1_pad_0": lambda: (AvgPool2d(1, 1, 0), torch.rand(2, 5, 5, 5)), + "kernel_2x9_stride_1_pad_1": lambda: ( + AvgPool2d((2, 9), 1, 1, count_include_pad=False), + torch.rand(1, 16, 5, 32), + ), + "kernel_1x4_stride_0_pad_0": lambda: ( + AvgPool2d(1, 4, 0, count_include_pad=False), + torch.rand(1, 10, 10, 10), + ), + "kernel_1x257_stride_1_pad_0_large": lambda: ( + AvgPool2d((1, 257), 1, 0, count_include_pad=False), + torch.rand(1, 16, 5, 300), + ), + "kernel_800x90_stride_1_pad_0_extreme": lambda: ( + AvgPool2d((800, 90), 1, 0, count_include_pad=False), + torch.rand(1, 16, 850, 100), + ), +} + + +@common.parametrize("reject_module", reject_modules) +def test_avg_pool2d_u55_INT_not_delegated(reject_module): + + model, test_data = reject_module() + + pipeline = OpNotSupportedPipeline[input_t]( + module=model, + test_data=(test_data,), + non_delegated_ops={}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_batch_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_batch_norm.py new file mode 100644 index 0000000..7c91588 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_batch_norm.py @@ -0,0 +1,385 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +test_data_suite = { + # (test_name, test_data, [num_features, affine, weight, bias] ) + "ones_1_32_112_112": lambda: (torch.rand(1, 32, 112, 112), [32, False, None, None]), + "rand_1_4_5_6": lambda: (torch.rand(1, 4, 5, 6), [4, False, None, torch.rand(4)]), + "rand_1_3_254_254": lambda: ( + torch.rand(1, 3, 254, 254), + [3, False, torch.rand(3), torch.rand(3)], + ), + "rand_1_32_112_112_affine": lambda: ( + torch.rand(1, 32, 112, 112), + [32, True, None, None], + ), + "ones_1_4_5_6_affine": lambda: ( + torch.rand(1, 4, 5, 6), + [4, True, torch.rand(4), torch.rand(4)], + ), + "rand_1_3_254_254_affine": lambda: ( + torch.rand(1, 3, 254, 254), + [3, True, torch.rand(3), None], + ), +} + + +class BatchNorm2d(torch.nn.Module): + aten_op = "torch.ops.aten.batch_norm.default" + + def __init__( + self, + num_features: int, + affine: bool, + weights: torch.tensor, + bias: torch.tensor, + ): + super().__init__() + self.batch_norm_2d = torch.nn.BatchNorm2d( + num_features, affine=affine, track_running_stats=True + ) + + # Optional + if weights is not None: + self.batch_norm_2d.weight = torch.nn.Parameter(weights) + if bias is not None: + self.batch_norm_2d.bias = torch.nn.Parameter(bias) + + # These will be 1 if not set since no training is done, randomize for more realistic values + self.batch_norm_2d.running_var = torch.rand(num_features) + self.batch_norm_2d.running_mean = torch.rand(num_features) * 2 - 1 + + def forward(self, x): + return self.batch_norm_2d(x) + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_training_tosa_FP(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + aten_op=BatchNorm2d.aten_op, + ) + pipeline.run() + + +# TODO(MLETORCH-100: Quantized stand-alone batch norms) +def test_native_batch_norm_legit_no_training_tosa_INT_not_delegated(): + test_data, model_params = test_data_suite["rand_1_3_254_254"]() + OpNotSupportedPipeline[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 1 + }, + quantize=True, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_no_quant(test_data: Tuple): + inp, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2d(*model_params), + (inp,), + aten_op=BatchNorm2d.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_quant(test_data: Tuple): + # TODO(MLETORCH-100: Quantized stand-alone batch norms) + pass + + +# TODO(MLETORCH-100: Quantized stand-alone batch norms) +def test_native_batch_norm_legit_no_training_u55_INT_not_delegated(): + test_data, model_params = test_data_suite["rand_1_3_254_254"]() + OpNotSupportedPipeline[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 1 + }, + quantize=True, + u55_subset=True, + ).run() + + +# TODO(MLETORCH-100: Quantized stand-alone batch norms) +def test_native_batch_norm_legit_no_training_u85_INT_not_delegated(): + test_data, model_params = test_data_suite["rand_1_3_254_254"]() + OpNotSupportedPipeline[input_t1]( + BatchNorm2d(*model_params), + (test_data,), + { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 1 + }, + quantize=True, + ).run() + + +class BatchNorm2dConv(torch.nn.Module): + aten_ops = ["torch.ops.aten.conv2d.default", "torch.ops.aten.batch_norm.default"] + + def __init__( + self, + num_features: int, + affine: bool, + weights: torch.tensor, + bias: torch.tensor, + ): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=num_features, + out_channels=num_features, + kernel_size=3, + stride=1, + groups=1, + ) + + self.batch_norm_2d = torch.nn.BatchNorm2d( + num_features, affine=affine, track_running_stats=True + ) + + # Optional + if weights is not None: + self.batch_norm_2d.weight = torch.nn.Parameter(weights) + if bias is not None: + self.batch_norm_2d.bias = torch.nn.Parameter(bias) + + # These will be 1 if not set since no training is done, randomize for more realistic values + self.batch_norm_2d.running_var = torch.rand(num_features) + self.batch_norm_2d.running_mean = torch.rand(num_features) * 2 - 1 + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x): + x = self.conv2d(x) + x = self.batch_norm_2d(x) + return x + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_training_tosa_FP_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_training_tosa_INT_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops[0], # Bn is removed before check + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_batch_norm_legit_no_training_u55_INT_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_ops=BatchNorm2dConv.aten_ops[0], # Bn is removed before check + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_batch_norm_legit_no_training_u85_INT_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_ops=BatchNorm2dConv.aten_ops[0], # Bn is removed before check + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_no_quant_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_training_vgf_quant_conv(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dConv(*model_params), + (test_data,), + aten_op=BatchNorm2dConv.aten_ops[0], + qtol=1, + quantize=True, + ) + pipeline.run() + + +class BatchNorm2dNoStats(torch.nn.Module): + """ + Decomposes into _native_batch_norm_legit.no_stats + """ + + aten_ops = ["torch.ops.aten.batch_norm.default"] + + def __init__( + self, + num_features: int, + affine: bool, + weights: torch.tensor, + bias: torch.tensor, + ): + super().__init__() + self.batch_norm_2d = torch.nn.BatchNorm2d( + num_features, affine=affine, track_running_stats=False + ) + + # Optional + if weights is not None: + self.batch_norm_2d.weight = torch.nn.Parameter(weights) + if bias is not None: + self.batch_norm_2d.bias = torch.nn.Parameter(bias) + + # These will be 1 if not set since no training is done, randomize for more realistic values + self.batch_norm_2d.running_var = torch.rand(num_features) + self.batch_norm_2d.running_mean = torch.rand(num_features) * 2 - 1 + + def forward(self, x): + return self.batch_norm_2d(x) + + +@common.parametrize("test_data", test_data_suite) +def test_native_batch_norm_legit_no_stats_tosa_FP(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +def test_native_batch_norm_legit_no_stats_tosa_INT(test_data: Tuple): + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_batch_norm_legit_no_stats_u55_INT(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_batch_norm_legit_no_stats_u85_INT(test_data: Tuple): + test_data, model_params = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_stats_vgf_no_quant(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + quantize=False, + ) + pipeline.run() + + +@pytest.mark.skip( + reason="MLETORCH-999: Add support for _native_batch_norm_legit.no_stats." +) +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_batch_norm_legit_no_stats_vgf_quant(test_data: Tuple): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + BatchNorm2dNoStats(*model_params), + (test_data,), + aten_op=BatchNorm2dNoStats.aten_ops, + qtol=1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise.py new file mode 100644 index 0000000..1565fe6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise.py @@ -0,0 +1,672 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from copy import copy +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineINT, + VgfPipeline, +) + +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class BitwiseBinary(torch.nn.Module): + test_data: dict[input_t2] = { + "zeros": lambda: ( + torch.zeros(1, 10, 10, 10, dtype=torch.int32), + torch.zeros(1, 10, 10, 10, dtype=torch.int32), + ), + "ones": lambda: ( + torch.ones(10, 10, 10, dtype=torch.int8), + torch.ones(10, 10, 10, dtype=torch.int8), + ), + "pattern_int8": lambda: ( + 0xAA * torch.ones(1, 2, 2, 2, dtype=torch.int8), + 0xCC * torch.ones(1, 2, 2, 2, dtype=torch.int8), + ), + "pattern_int16": lambda: ( + 0xAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int16), + 0xCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int16), + ), + "pattern_int32": lambda: ( + 0xAAAAAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int32), + 0xCCCCCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int32), + ), + "pattern_bool": lambda: ( + torch.tensor([True, False, True], dtype=torch.bool), + torch.tensor([True, True, False], dtype=torch.bool), + ), + "rand_rank2": lambda: ( + torch.randint(-128, 127, (10, 10), dtype=torch.int8), + torch.randint(-128, 127, (10, 10), dtype=torch.int8), + ), + "rand_rank4": lambda: ( + torch.randint(-128, -127, (1, 10, 10, 10), dtype=torch.int8), + torch.randint(-128, 127, (1, 10, 10, 10), dtype=torch.int8), + ), + } + + test_data_u85 = copy(test_data) + del test_data_u85["zeros"] + + +class BitwiseBinaryScalar(torch.nn.Module): + test_data = { + "zeros": lambda: (torch.zeros(1, 10, 10, 10, dtype=torch.int32), 0), + "ones_int8": lambda: (torch.ones(10, 10, 10, dtype=torch.int8), 1), + "pattern_int8": lambda: (0xAA * torch.ones(1, 2, 2, 2, dtype=torch.int8), 0x77), + "pattern_int16": lambda: ( + 0xAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int16), + 0x7777, + ), + "pattern_int32": lambda: ( + 0xAAAAAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int32), + 0x77777777, + ), + "rand_rank2": lambda: (torch.randint(-128, 127, (10, 10), dtype=torch.int8), 5), + "rand_rank4": lambda: ( + torch.randint(-128, 127, (1, 10, 10, 10), dtype=torch.int8), + -7, + ), + } + + test_data_u85 = copy(test_data) + del test_data_u85["zeros"] + + +class And(BitwiseBinary): + aten_op = "torch.ops.aten.bitwise_and.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.bitwise_and(tensor2) + + +class Xor(BitwiseBinary): + aten_op = "torch.ops.aten.bitwise_xor.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_xor_Tensor" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.bitwise_xor(tensor2) + + +class Or(BitwiseBinary): + aten_op = "torch.ops.aten.bitwise_or.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_or_Tensor" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.bitwise_or(tensor2) + + +class AndScalar(BitwiseBinaryScalar): + # Tensor because it gets converted from Scalar -> Tensor in lowering + aten_op = "torch.ops.aten.bitwise_and.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_bitwise_and_Scalar" + + def forward(self, tensor: torch.Tensor, scalar: int): + return tensor.bitwise_and(scalar) + + +class XorScalar(BitwiseBinaryScalar): + # Tensor because it gets converted from Scalar -> Tensor in lowering + aten_op = "torch.ops.aten.bitwise_xor.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_xor_Tensor" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_bitwise_xor_Scalar" + + def forward(self, tensor: torch.Tensor, scalar: int): + return tensor.bitwise_xor(scalar) + + +class OrScalar(BitwiseBinaryScalar): + # Tensor because it gets converted from Scalar -> Tensor in lowering + aten_op = "torch.ops.aten.bitwise_or.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_or_Tensor" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_bitwise_or_Scalar" + + def forward(self, tensor: torch.Tensor, scalar: int): + return tensor.bitwise_or(scalar) + + +######### +## AND ## +######### + + +@common.parametrize("test_data", And().test_data) +def test_bitwise_and_tensor_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data) +def test_bitwise_and_scalar_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + AndScalar(), + test_data(), + {AndScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_bitwise_and_tensor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data) +def test_bitwise_and_scalar_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + AndScalar(), + test_data(), + AndScalar.aten_op, + AndScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_bitwise_and_tensor_u55_INT(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data) +def test_bitwise_and_scalar_u55_INT(test_data: input_t2): + # There will be one full op which will be delegated. + num_delegates = 1 + num_exir = 0 + pipeline = OpNotSupportedPipeline[input_t2]( + AndScalar(), + test_data(), + { + AndScalar.exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar.test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_and_scalar_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + AndScalar(), + test_data(), + AndScalar.aten_op, + AndScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_and_tensor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_tensor_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_scalar_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + AndScalar(), + test_data(), + {AndScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_tensor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AndScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_and_scalar_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + AndScalar(), + test_data(), + AndScalar().aten_op, + AndScalar().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +######### +## XOR ## +######### + + +@common.parametrize("test_data", Xor().test_data) +def test_bitwise_xor_tensor_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data) +def test_bitwise_xor_scalar_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + XorScalar(), + test_data(), + {XorScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_bitwise_xor_tensor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data) +def test_bitwise_xor_scalar_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + XorScalar(), + test_data(), + XorScalar.aten_op, + XorScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_bitwise_xor_tensor_u55_INT(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data) +def test_bitwise_xor_scalar_u55_INT(test_data: input_t2): + # There will be one full op which will be delegated. + num_delegates = 1 + num_exir = 0 + pipeline = OpNotSupportedPipeline[input_t2]( + XorScalar(), + test_data(), + { + XorScalar.exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_xor_tensor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar.test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_xor_scalar_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + XorScalar(), + test_data(), + XorScalar.aten_op, + XorScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_tensor_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_scalar_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + XorScalar(), + test_data(), + {XorScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_tensor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", XorScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_xor_scalar_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + XorScalar(), + test_data(), + XorScalar().aten_op, + XorScalar().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +######## +## OR ## +######## + + +@common.parametrize("test_data", Or().test_data) +def test_bitwise_or_tensor_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data) +def test_bitwise_or_scalar_tosa_FP(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + OrScalar(), + test_data(), + {OrScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_bitwise_or_tensor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data) +def test_bitwise_or_scalar_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + OrScalar(), + test_data(), + OrScalar.aten_op, + OrScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_bitwise_or_tensor_u55_INT(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data) +def test_bitwise_or_scalar_u55_INT(test_data: input_t2): + # There will be one full op which will be delegated. + num_delegates = 1 + num_exir = 0 + pipeline = OpNotSupportedPipeline[input_t2]( + OrScalar(), + test_data(), + { + OrScalar.exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_or_tensor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar.test_data_u85) +@common.XfailIfNoCorstone320 +def test_bitwise_or_scalar_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + OrScalar(), + test_data(), + OrScalar.aten_op, + OrScalar.exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_tensor_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or.exir_op: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_scalar_vgf_no_quant(test_data: input_t2): + pipeline = OpNotSupportedPipeline[input_t2]( + OrScalar(), + test_data(), + {OrScalar.exir_op_scalar: 1}, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_tensor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", OrScalar().test_data) +@common.SkipIfNoModelConverter +def test_bitwise_or_scalar_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + OrScalar(), + test_data(), + OrScalar().aten_op, + OrScalar().exir_op, + atol=0, + rtol=0, + qtol=0, + quantize=True, + ) + pipeline.run() + + +@pytest.mark.xfail( + reason="MLBEDSW-11029: Fatal Python floating point error in Vela for rank 4 bitwse ops with int32 dtype." +) +def test_bitwise_or_tensor_u85_INT_zeros(): + raise RuntimeError( + "Dummy test to xfail mark u85 zeros test case since running the actual test causes a fatal crash." + ) + + +@pytest.mark.xfail( + reason="MLBEDSW-11029: Fatal Python floating point error in Vela for rank 4 bitwse ops with int32 dtype." +) +def test_bitwise_and_tensor_u85_INT_zeros(): + raise RuntimeError( + "Dummy test to xfail mark u85 zeros test case since running the actual test causes a fatal crash." + ) + + +@pytest.mark.xfail( + reason="MLBEDSW-11029: Fatal Python floating point error in Vela for rank 4 bitwse ops with int32 dtype." +) +def test_bitwise_xor_tensor_u85_INT_zeros(): + raise RuntimeError( + "Dummy test to xfail mark u85 zeros test case since running the actual test causes a fatal crash." + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise_not.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise_not.py new file mode 100644 index 0000000..2f60fda --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bitwise_not.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.bitwise_not.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_not_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10, dtype=torch.int32), + "ones": torch.ones(10, 2, 3, dtype=torch.int8), + "pattern1_int8": 0xAA * torch.ones(1, 2, 2, 2, dtype=torch.int8), + "pattern1_int16": 0xAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int16), + "pattern1_int32": 0xAAAAAAAA * torch.ones(1, 2, 2, 2, dtype=torch.int32), + "pattern2_int8": 0xCC * torch.ones(1, 2, 2, 2, dtype=torch.int8), + "pattern2_int16": 0xCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int16), + "pattern2_int32": 0xCCCCCCCC * torch.ones(1, 2, 2, 2, dtype=torch.int32), + "pattern_bool": torch.tensor([True, False, True], dtype=torch.bool), + "rand_rank2": torch.randint(-128, 127, (10, 10), dtype=torch.int8), + "rand_rank4": torch.randint(-128, 127, (1, 10, 10, 10), dtype=torch.int8), +} + + +class BitwiseNot(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.bitwise_not(x) + + +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_tosa_FP(test_data: Tuple): + # We don't delegate bitwise_not since it is not supported on the FP profile. + pipeline = OpNotSupportedPipeline[input_t1]( + BitwiseNot(), + (test_data,), + {exir_op: 1}, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + BitwiseNot(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_u55_INT(test_data: Tuple): + # We don't delegate bitwise_not since it is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t1]( + BitwiseNot(), + (test_data,), + {exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_bitwise_not_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + BitwiseNot(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_bitwise_not_vgf_no_quant(test_data: Tuple): + # We don't delegate bitwise_not since it is not supported on the FP profile. + pipeline = OpNotSupportedPipeline[input_t1]( + BitwiseNot(), + (test_data,), + {exir_op: 1}, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_bitwise_not_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + BitwiseNot(), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bmm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bmm.py new file mode 100644 index 0000000..d21b33c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_bmm.py @@ -0,0 +1,193 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op_bmm = "torch.ops.aten.bmm.default" +exir_op_bmm = "executorch_exir_dialects_edge__ops_aten_bmm_default" + +aten_op_mm = "torch.ops.aten.matmul.default" +exir_op_mm = "executorch_exir_dialects_edge__ops_aten_matmul_default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class BMM(torch.nn.Module): + test_data_generators = { + "rand_same": lambda: (torch.rand(2, 1, 1), torch.rand(2, 1, 1)), + "rand_diff": lambda: (torch.rand(5, 3, 5), torch.rand(5, 5, 2)), + "rand_ones": lambda: (torch.ones(1, 55, 3), torch.ones(1, 3, 44)), + "rand_big": lambda: (10000 * torch.randn(10, 1, 10), torch.randn(10, 10, 5)), + "rand_neg": lambda: ( + -10 * torch.randn(2, 32, 64), + 5 + 5 * torch.randn(2, 64, 32), + ), + } + + def forward(self, x, y): + return torch.bmm(x, y) + + +class BMMSingleInput(torch.nn.Module): + test_data_generators = { + "rand_3d_1": lambda: (torch.rand(20, 3, 3),), + "rand_3d_2": lambda: (torch.rand(2, 128, 128),), + "rand_big_1": lambda: (10000 * torch.randn(4, 25, 25),), + "rand_big_2": lambda: (5 + 5 * torch.randn(3, 64, 64),), + } + + def forward(self, x): + return torch.bmm(x, x) + + +@common.parametrize("test_data", BMM.test_data_generators) +def test_bmm_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](BMM(), test_data(), aten_op_bmm, exir_op_bmm) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLETORCH-534) +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +def test_bmm_tosa_FP_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + BMMSingleInput(), test_data(), aten_op_bmm, exir_op_bmm + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +def test_bmm_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + BMM(), test_data(), aten_op_bmm, exir_op_bmm, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +def test_bmm_tosa_INT_single_input(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + BMMSingleInput(), test_data(), aten_op_bmm, exir_op_bmm + ) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.XfailIfNoCorstone300 +def test_bmm_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.XfailIfNoCorstone320 +def test_bmm_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +@common.XfailIfNoCorstone300 +def test_bmm_u55_INT_single_input(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +@common.XfailIfNoCorstone320 +def test_bmm_u85_INT_single_input(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.SkipIfNoModelConverter +def test_bmm_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + BMMSingleInput.test_data_generators, + flakies={"rand_big_1": 3}, +) +@common.SkipIfNoModelConverter +def test_bmm_vgf_no_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", BMM.test_data_generators) +@common.SkipIfNoModelConverter +def test_bmm_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMM(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", BMMSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_bmm_vgf_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + BMMSingleInput(), + test_data(), + aten_op_bmm, + exir_op_bmm, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cat.py new file mode 100644 index 0000000..a037d0e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cat.py @@ -0,0 +1,219 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, +) +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.cat.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_cat_default" + + +class Cat(torch.nn.Module): + test_parameters = { + "cat_ones_two_tensors": lambda: ((torch.ones(1), torch.ones(1)), 0), + "cat_ones_and_rand_three_tensors": lambda: ( + (torch.ones(1, 2), torch.randn(1, 5), torch.randn(1, 1)), + 1, + ), + "cat_ones_and_rand_four_tensors": lambda: ( + ( + torch.ones(1, 2, 5), + torch.randn(1, 2, 4), + torch.randn(1, 2, 2), + torch.randn(1, 2, 1), + ), + -1, + ), + "cat_rand_two_tensors": lambda: ( + (torch.randn(1, 2, 4, 4), torch.randn(1, 2, 4, 1)), + 3, + ), + "cat_rand_two_tensors_dim_0": lambda: ( + (torch.randn(1, 2, 4, 4), torch.randn(1, 2, 4, 4)), + 0, + ), + "cat_rand_two_tensors_dim_3": lambda: ( + (torch.randn(2, 2, 4, 4), torch.randn(2, 2, 4, 1)), + 3, + ), + "cat_rand_large": lambda: ( + ( + 10000 * torch.randn(2, 3, 1, 4), + torch.randn(2, 7, 1, 4), + torch.randn(2, 1, 1, 4), + ), + -3, + ), + } + + def __init__(self): + super().__init__() + + def forward(self, t: tuple[torch.Tensor, ...], dim: int) -> torch.Tensor: + return torch.cat(t, dim=dim) + + +@common.parametrize("test_data", Cat.test_parameters) +def test_cat_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +def test_cat_tosa_FP_4d(): + square = torch.ones((2, 2, 2, 2)) + for dim in range(-3, 3): + test_data = ((square, square.clone()), dim) + pipeline = TosaPipelineFP[input_t1]( + Cat(), + test_data, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +def test_cat_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone300 +def test_cat_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone320 +def test_cat_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.SkipIfNoModelConverter +def test_cat_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.SkipIfNoModelConverter +def test_cat_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +def test_cat_16a8w_tosa_INT(test_data: Tuple): + """Test cat operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone300 +def test_cat_16a8w_u55_INT(test_data: Tuple): + """Test cat operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + pipeline.run() + + +@common.parametrize("test_data", Cat.test_parameters) +@common.XfailIfNoCorstone320 +def test_cat_16a8w_u85_INT(test_data: Tuple): + """Test cat operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Cat(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + pipeline.quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ceil.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ceil.py new file mode 100644 index 0000000..93b5f9c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ceil.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Ceil(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.ceil(x) + + aten_op = "torch.ops.aten.ceil.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_ceil_default" + + +zeros = torch.zeros(1, 10, 10, 10) +ones = torch.ones(10, 10, 10) +rand = torch.rand(10, 10) - 0.5 +randn_pos = torch.randn(1, 4, 4, 4) + 10 +randn_neg = torch.randn(1, 4, 4, 4) - 10 +ramp = torch.arange(-16, 16, 0.2) + +test_data = { + "ceil_zeros": lambda: (Ceil(), zeros), + "ceil_ones": lambda: (Ceil(), ones), + "ceil_rand": lambda: (Ceil(), rand), + "ceil_randn_pos": lambda: (Ceil(), randn_pos), + "ceil_randn_neg": lambda: (Ceil(), randn_neg), + "ceil_ramp": lambda: (Ceil(), ramp), +} + + +@common.parametrize("test_data", test_data) +def test_ceil_tosa_FP(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_ceil_tosa_INT(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone300 +def test_ceil_u55_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone320 +def test_ceil_u85_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_ceil_vgf_no_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_ceil_vgf_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clamp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clamp.py new file mode 100644 index 0000000..13c3479 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clamp.py @@ -0,0 +1,474 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from numbers import Number +from typing import Tuple, Union + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.clamp.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_clamp_default" + +input_t = Tuple[torch.Tensor] + + +test_data_suite = { + # test_name: (test_data, min, max) + "rank_1": lambda: (torch.rand(10) * 2, -1.0, 1.0), + "rank_2": lambda: (torch.rand(1, 35), 0.5, 0.8), + "rank_3": lambda: (torch.ones(1, 10, 10), -1, -1), + "rank_4": lambda: (torch.rand(1, 10, 10, 1) * 2, -0.1, 2.0), + "rank_4_mixed_min_max_dtype": lambda: (torch.rand(1, 10, 10, 5) + 10, 8.0, 10), + "rank_4_no_min": lambda: (torch.rand(1, 10, 10, 1) * 10, None, 5), + "rank_4_no_max": lambda: (torch.rand(1, 10, 10, 1) - 3, -3.3, None), +} + +test_data_suite_int32 = { + "int32_rank2": lambda: (torch.randint(-50, 50, (2, 3), dtype=torch.int32), -10, 10), + "int32_rank3_no_min": lambda: ( + torch.randint(-100, 100, (1, 3, 3), dtype=torch.int32), + None, + 25, + ), + "int32_rank3_no_max": lambda: ( + torch.randint(-100, 100, (1, 3, 3), dtype=torch.int32), + -25, + None, + ), + "int32_rank4_large_range": lambda: ( + torch.randint(-200, 200, (1, 2, 4, 4), dtype=torch.int32), + torch.iinfo(torch.int32).min, + torch.iinfo(torch.int32).max, + ), +} + + +class Clamp(torch.nn.Module): + def __init__( + self, + clamp_min: Union[torch.Tensor, Number, None], + clamp_max: Union[torch.Tensor, Number, None], + ): + super().__init__() + + self.clamp_min = clamp_min + self.clamp_max = clamp_max + + def forward(self, x): + return torch.clamp(x, self.clamp_min, self.clamp_max) + + +@common.parametrize("test_data", test_data_suite) +def test_clamp_tosa_FP(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineFP[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_clamp_tosa_INT(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +def test_clamp_tosa_INT_int32_inputs(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.pop_stage("quantize") + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_clamp_tosa_INT_a16w8(test_data): + """Test clamp operation with int16 I/O quantization for TOSA INT.""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT_16a8w(test_data): + """Test clamp operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT_16a8w(test_data): + """Test clamp operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_clamp_vgf_no_quant(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_clamp_vgf_quant(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +aten_op_tensor = "torch.ops.aten.clamp.Tensor" +exir_op_tensor = "executorch_exir_dialects_edge__ops_aten_clamp_Tensor" + +test_data_suite_tensor_FP = { + # test_name: (test_data, min, max) + "rank_1": lambda: (torch.rand(10) * 2, torch.tensor(-1.0), torch.tensor(1.0)), + "rank_2": lambda: (torch.rand(1, 35), torch.tensor(0.5), torch.tensor(0.8)), + "rank_3": lambda: ( + torch.ones(1, 10, 10), + torch.rand(1, 10, 10) * 0.5, + torch.rand(1, 10, 10) * -0.5, + ), + "rank_4": lambda: ( + torch.rand(1, 10, 10, 1) * 2, + torch.tensor(-0.1), + torch.tensor(2.0), + ), + "rank_4_no_max": lambda: ( + torch.rand(10, 20, 30, 40) - 3, + torch.rand(30, 40) - 3.3, + None, + ), + "rank_4_no_min": lambda: ( + torch.rand(10, 20, 30, 40) * 10, + None, + torch.rand(10, 20, 30, 40) * 5.0, + ), +} + +test_data_suite_tensor_INT32 = { + "int32_rank2": lambda: ( + torch.randint(-50, 50, (2, 3), dtype=torch.int32), + torch.tensor(-10), + torch.tensor(10), + ), + "int32_rank3_no_min_broadcast_1_3": lambda: ( + torch.randint(0, 100, (1, 3, 3), dtype=torch.int32) + 10, + None, + torch.tensor([[3, 5, 7]], dtype=torch.int32), # torch.Size([1, 3]) + ), + "int32_rank3_no_max_broadcast_3_1": lambda: ( + torch.randint(-100, 100, (1, 3, 3), dtype=torch.int32), + torch.tensor([[3], [5], [7]], dtype=torch.int32), # torch.Size([3, 1]) + None, + ), + "int32_rank4_large_range": lambda: ( + torch.randint(-200, 200, (1, 2, 4, 4), dtype=torch.int32), + torch.tensor((torch.iinfo(torch.int32).min)), + torch.tensor((torch.iinfo(torch.int32).max)), + ), + "int32_rank4_broadcast_1_2": lambda: ( + torch.ones(1, 2, 4, 4, dtype=torch.int32) * 100, + torch.randint(-10, 10, (4,), dtype=torch.int32), # torch.Size([4]) + torch.randint( + -10, + 10, + ( + 4, + 4, + ), + dtype=torch.int32, + ), # torch.Size([4, 4]) + ), + "int32_rank4_broadcast_3_4": lambda: ( + torch.ones(1, 2, 4, 4, dtype=torch.int32) * 100, + torch.randint( + -10, + 10, + ( + 1, + 4, + 4, + ), + dtype=torch.int32, + ), # torch.Size([1, 4, 4]) + torch.randint( + -10, + 10, + ( + 1, + 1, + 4, + 4, + ), + dtype=torch.int32, + ), # torch.Size([1, 1, 4, 4]) + ), +} + +test_data_suite_tensor_INT64 = { + "int64_rank_3": lambda: ( + torch.ones(1, 10, 10, dtype=torch.int64), + torch.tensor(-1), + torch.tensor(-1), + ), + "int64_rank_4": lambda: ( + torch.randint(-100, 100, (1, 3, 3)), + torch.tensor(-10), + torch.tensor(20), + ), +} + + +@common.parametrize("test_data", test_data_suite_tensor_FP) +def test_clamp_tosa_FP_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineFP[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + + pipeline.run() + + +@common.parametrize( + "test_data", test_data_suite_tensor_INT32 | test_data_suite_tensor_INT64 +) +def test_clamp_tosa_INT_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize( + "test_data", test_data_suite_tensor_INT32 | test_data_suite_tensor_INT64 +) +def test_clamp_tosa_INT_a16w8_tensor(test_data): + """Test clamp operation with int16 I/O quantization for TOSA INT.""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = TosaPipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone300 +def test_clamp_u55_INT_16a8w_tensor(test_data): + """Test clamp operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU55PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_INT32) +@common.XfailIfNoCorstone320 +def test_clamp_u85_INT_16a8w_tensor(test_data): + """Test clamp operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = EthosU85PipelineINT[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tensor_FP) +@common.SkipIfNoModelConverter +def test_clamp_vgf_no_quant_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", test_data_suite_tensor_INT32 | test_data_suite_tensor_INT64 +) +@common.SkipIfNoModelConverter +def test_clamp_vgf_quant_tensor(test_data): + input_tensor, min_val, max_val = test_data() + model = Clamp(min_val, max_val) + pipeline = VgfPipeline[input_t]( + model, + (input_tensor,), + aten_op_tensor, + exir_op_tensor, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clone.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clone.py new file mode 100644 index 0000000..3aec2ed --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_clone.py @@ -0,0 +1,150 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.clone.default" +exir_op = "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default" + +input_t = Tuple[torch.Tensor] + + +class CloneFirstArg(torch.nn.Module): + def forward(self, x): + return x.clone() + x + + +class CloneSecondArg(torch.nn.Module): + def forward(self, x): + return x * x.clone() + + +class CloneOutput(torch.nn.Module): + def forward(self, x): + return (x / x).clone() + + +class CloneBothArgs(torch.nn.Module): + def forward(self, x): + return x.clone() + x.clone() + + +class CloneAfterOtherOp(torch.nn.Module): + def forward(self, x): + x = x * 2 + return x.clone() + x + + +class CloneParallelToOtherOp(torch.nn.Module): + def forward(self, x): + return x * 2 + x.clone() + + +delegated_clones = { + "clone_first_arg": lambda: (CloneFirstArg, (torch.rand(1, 2, 3, 4),)), + "clone_second_arg": lambda: (CloneSecondArg, (torch.rand(1, 2, 3, 4),)), + "clone_output": lambda: (CloneOutput, (torch.rand(1, 2, 3, 4),)), + "clone_both_args": lambda: (CloneBothArgs, (torch.rand(1, 2, 3, 4),)), + "clone_after_other_op": lambda: (CloneAfterOtherOp, (torch.rand(1, 2, 3, 4),)), + "clone_parallel_to_other_op": lambda: ( + CloneParallelToOtherOp, + (torch.rand(1, 2, 3, 4),), + ), +} + + +@common.parametrize("input_data", delegated_clones) +def test_clone_tosa_FP(input_data): + module, input_tensor = input_data() + pipeline = TosaPipelineFP[input_t]( + module(), + input_tensor, + [], + ) + pipeline.run() + + +@common.parametrize("input_data", delegated_clones) +def test_clone_tosa_INT(input_data): + module, input_tensor = input_data() + + pipeline = TosaPipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", delegated_clones) +@common.XfailIfNoCorstone300 +def test_clone_u55_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU55PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("input_data", delegated_clones) +@common.XfailIfNoCorstone320 +def test_clone_u85_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU85PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("test_data", delegated_clones) +@common.SkipIfNoModelConverter +def test_clone_vgf_no_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", delegated_clones) +@common.SkipIfNoModelConverter +def test_clone_vgf_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cond.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cond.py new file mode 100644 index 0000000..b430bf9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cond.py @@ -0,0 +1,338 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.arm_tester import ArmTester +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from pytest import mark + +aten_op = "torch.ops.higher_order.cond" +exir_op = "torch.ops.higher_order.cond" + +input_t1 = Tuple[torch.Tensor] +input_t2 = Tuple[torch.Tensor, torch.Tensor] + + +class CondZeroArgsOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch() -> torch.Tensor: + return torch.zeros(10) + + def false_branch() -> torch.Tensor: + return torch.ones(10) + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, []) + + +class CondOneArgOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch(arg: torch.Tensor) -> torch.Tensor: + return torch.sin(arg) + + def false_branch(arg: torch.Tensor) -> torch.Tensor: + return torch.cos(arg) + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x]) + + +class CondOneArgBufferOneOutput(torch.nn.Module): + def __init__(self, *args: common.Any, **kwargs: common.Any) -> None: + super().__init__(*args, **kwargs) + self.buffer = torch.rand(1, 1, 2, 2) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch(arg: torch.Tensor, buffer: torch.Tensor) -> torch.Tensor: + return torch.sin(arg) + buffer + + def false_branch(arg: torch.Tensor, buffer: torch.Tensor) -> torch.Tensor: + return torch.cos(arg) + buffer + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x, self.buffer]) + + +class CondOneArgAndScalarOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def true_branch(arg: torch.Tensor) -> torch.Tensor: + return arg + 1.0 + + def false_branch(arg: torch.Tensor) -> torch.Tensor: + return arg - 1.0 + + predicate = x.sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x]) + + +class CondOneArgTwoOutputs(torch.nn.Module): + def forward(self, x: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: + def true_branch(arg: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: + return arg + torch.sin(arg), arg - torch.sin(arg) + + def false_branch(arg: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: + return arg - arg.mean(), arg + arg.mean() + + predicate = x.flatten().sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [x]) + + +class CondNestedOneArgOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def inner_true(arg: torch.Tensor) -> torch.Tensor: + return arg + torch.full((1,), (1.0)) + + def inner_false(arg: torch.Tensor) -> torch.Tensor: + return arg - torch.full((1,), (1.0)) + + def outer_true(arg: torch.Tensor) -> torch.Tensor: + inner_predicate = arg.mean() > 0 + return torch.cond(inner_predicate, inner_true, inner_false, [arg]) + + def outer_false(arg: torch.Tensor) -> torch.Tensor: + return arg * torch.full((1,), (1.0)) + + predicate = x.sum() > 0 + return torch.cond(predicate, outer_true, outer_false, [x]) + + +class CondMultipleOneArgOneOutput(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + def first_true(arg: torch.Tensor) -> torch.Tensor: + return arg.sigmoid() + + def first_false(arg: torch.Tensor) -> torch.Tensor: + return arg.relu() + + first_predicate = x.sum() > 0 + intermediate = torch.cond(first_predicate, first_true, first_false, [x]) + + def second_true(arg: torch.Tensor) -> torch.Tensor: + return arg.sin() + + def second_false(arg: torch.Tensor) -> torch.Tensor: + return arg.cos() + + second_predicate = intermediate.mean() > 0 + return torch.cond(second_predicate, second_true, second_false, [intermediate]) + + +class CondTwoArgsOneOutput(torch.nn.Module): + def forward(self, lhs: torch.Tensor, rhs: torch.Tensor) -> torch.Tensor: + def true_branch(arg_l: torch.Tensor, arg_r: torch.Tensor) -> torch.Tensor: + return arg_l + arg_r + + def false_branch(arg_l: torch.Tensor, arg_r: torch.Tensor) -> torch.Tensor: + return arg_l - arg_r + + predicate = (lhs - rhs).sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [lhs, rhs]) + + +class CondTwoArgsTwoOutputs(torch.nn.Module): + def forward( + self, lhs: torch.Tensor, rhs: torch.Tensor + ) -> tuple[torch.Tensor, torch.Tensor]: + def true_branch( + arg_l: torch.Tensor, arg_r: torch.Tensor + ) -> tuple[torch.Tensor, torch.Tensor]: + return arg_l + arg_r, arg_l * arg_r + + def false_branch( + arg_l: torch.Tensor, arg_r: torch.Tensor + ) -> tuple[torch.Tensor, torch.Tensor]: + diff = arg_l - arg_r + return diff, arg_l + diff + + predicate = (lhs * rhs).sum() > 0 + return torch.cond(predicate, true_branch, false_branch, [lhs, rhs]) + + +def _single_input_case( + module_factory: Callable[[], torch.nn.Module] +) -> Callable[[], tuple[torch.nn.Module, input_t1]]: + def _create() -> tuple[torch.nn.Module, input_t1]: + return module_factory(), (torch.randn(1, 1, 2, 2),) + + return _create + + +def _dual_input_case( + module_factory: Callable[[], torch.nn.Module] +) -> Callable[[], tuple[torch.nn.Module, input_t2]]: + def _create() -> tuple[torch.nn.Module, input_t2]: + return module_factory(), (torch.randn(2, 3, 4, 6), torch.randn(2, 3, 4, 6)) + + return _create + + +test_cases: dict[str, Callable[[], tuple[torch.nn.Module, tuple]]] = { + "zero_args_one_output": _single_input_case(CondZeroArgsOneOutput), + "one_arg_one_output": _single_input_case(CondOneArgOneOutput), + "one_arg_const_one_output": _single_input_case(CondOneArgBufferOneOutput), + "one_arg_and_scalar_one_output": _single_input_case(CondOneArgAndScalarOneOutput), + "one_arg_two_outputs": _single_input_case(CondOneArgTwoOutputs), + "two_args_one_output": _dual_input_case(CondTwoArgsOneOutput), + "two_args_two_outputs": _dual_input_case(CondTwoArgsTwoOutputs), + "nested_one_arg_one_output": _single_input_case(CondNestedOneArgOneOutput), + "multiple_one_arg_one_output": _single_input_case(CondMultipleOneArgOneOutput), +} + + +def _make_calibration_samples( + module: torch.nn.Module, example_inputs: tuple +) -> tuple[tuple[torch.Tensor, ...], ...]: + """Return one example input that triggers the if branch, and one that triggers the else branch.""" + + if isinstance(module, CondTwoArgsOneOutput): + # Predicate is sum(lhs-rhs) > 0 + lhs, rhs = example_inputs + if_example_inputs = (lhs, rhs) + else_example_inputs = (rhs, lhs) + elif isinstance(module, CondTwoArgsTwoOutputs): + # Predicate is sum(lhs*rhs) > 0 + lhs, rhs = example_inputs + if_example_inputs = (lhs, rhs) + else_example_inputs = (lhs, -rhs) + else: + # Predicate is sum(x) > 0 + (x,) = example_inputs + if_example_inputs = (x,) + else_example_inputs = (-x,) + + return (if_example_inputs, else_example_inputs) + + +def _set_branch_calibration_samples( + pipeline, module: torch.nn.Module, example_inputs: tuple +) -> None: + calibration_samples = _make_calibration_samples(module, example_inputs) + quant_stage_pos = pipeline.find_pos("quantize") + quant_stage = pipeline._stages[quant_stage_pos].args[0] + quant_stage.calibration_samples = calibration_samples + + +@common.parametrize( + "case", + test_cases, + xfails={ + "one_arg_and_scalar_one_output": "Scalars become get_attr nodes that are not supported.", + "nested_one_arg_one_output": "Not fully delegated.", + }, +) +def test_cond_tosa_FP(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineFP[tuple]( + module, example_inputs, aten_op, tosa_extensions=["cf"] + ) + + # Make sure no cond ops are left after partitioning. + pipeline.add_stage_after( + "to_edge_transform_and_lower", + ArmTester.check_not, + pipeline.tester, + ["torch.ops.higher_order.cond"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, + xfails={ + "one_arg_and_scalar_one_output": "Incorrect quantization on the scalar.", + "nested_one_arg_one_output": "Node submodule_0 target submodule_0 references nonexistent attribute submodule_0", + }, +) +def test_cond_tosa_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineINT[tuple]( + module, example_inputs, aten_op, tosa_extensions=["cf"] + ) + _set_branch_calibration_samples(pipeline, module, example_inputs) + + # Make sure no cond ops are left after partitioning. + pipeline.add_stage_after( + "to_edge_transform_and_lower", + ArmTester.check_not, + pipeline.tester, + ["torch.ops.higher_order.cond"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, +) +def test_cond_u55_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = OpNotSupportedPipeline[tuple](module, example_inputs, {aten_op: 1}) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize( + "case", + test_cases, + xfails={ + "one_arg_and_scalar_one_output": "Incorrect quantization on the scalar.", + "nested_one_arg_one_output": "Node submodule_0 target submodule_0 references nonexistent attribute submodule_0", + }, + skips={ + "one_arg_one_output": "Segfault when transpose goes into cond. MLBEDSW-11416.", + "one_arg_const_one_output": "Segfault when transpose goes into cond. MLBEDSW-11416.", + "multiple_one_arg_one_output": "Segfault when transpose goes into cond. MLBEDSW-11416.", + }, +) +@common.XfailIfNoCorstone320.with_args(raises=None) +def test_cond_u85_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = EthosU85PipelineINT[tuple](module, example_inputs, aten_op, exir_op) + _set_branch_calibration_samples(pipeline, module, example_inputs) + pipeline.run() + + +@mark.skip("Cond not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_cond_vgf_FP(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + VgfPipeline[tuple]( + module, + example_inputs, + aten_op, + exir_op, + ).run() + + +@mark.skip("Cond not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_cond_vgf_INT(case: Callable[[], tuple[torch.nn.Module, tuple]]): + module, example_inputs = case() + pipeline = VgfPipeline[tuple]( + module, + example_inputs, + aten_op, + exir_op, + ) + _set_branch_calibration_samples(pipeline, module, example_inputs) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_constant_pad_nd.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_constant_pad_nd.py new file mode 100644 index 0000000..05f14e6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_constant_pad_nd.py @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +# Test the pad_constant_nd op which pads the input tensor at specific dimension(s). +# +from typing import Tuple + +import torch +import torch.nn.functional as F +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.pad.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_pad_default" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + "4dim_last1dim": lambda: (torch.rand(1, 1, 16, 16), (1, 1, 0, 0, 0, 0, 0, 0), 1), + "4dim_last2dim": lambda: (torch.rand(1, 1, 16, 16), (1, 0, 1, 0, 0, 0, 0, 0), 2), + "4dim_last3dim": lambda: (torch.rand(1, 1, 16, 16), (1, 1, 0, 2, 0, 2, 0, 0), 3), + "4dim_last4dim": lambda: (torch.rand(1, 1, 16, 16), (1, 0, 1, 1, 0, 2, 0, 2), 4), + "3dim_last1dim": lambda: (torch.rand(1, 1, 16), (1, 1, 0, 0, 0, 0), 1), + "3dim_last2dim": lambda: (torch.rand(1, 1, 16), (1, 0, 1, 1, 0, 0), 2), + "3dim_last3dim": lambda: (torch.rand(1, 1, 16), (1, 0, 1, 0, 1, 1), 3), + "2dim_last1dim": lambda: (torch.rand(1, 1, 16), (1, 1, 0, 0), 1), + "2dim_last2dim": lambda: (torch.rand(1, 1, 16), (1, 0, 1, 1), 2), +} + + +class ConstantPadND(torch.nn.Module): + def __init__(self, pad: Tuple, value: float | None = None): + super().__init__() + self.value = value + nonzero_idx = len(pad) + for i in range(0, len(pad), 2): + if pad[i] + pad[i + 1] == 0: + nonzero_idx = i + break + self.pad = pad[:nonzero_idx] + + def forward(self, x: torch.Tensor): + x = F.pad(x, pad=self.pad, mode="constant", value=self.value) + return x + + +@common.parametrize( + "test_data", + test_data_suite, +) +def test_constant_pad_nd_tosa_FP(test_data: Tuple): + test_data, padding, value = test_data() + pipeline = TosaPipelineFP[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_INT(test_data: Tuple): + test_data, padding, value = test_data() + pipeline = TosaPipelineINT[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_INT_a16w8(test_data: Tuple): + """Test constant_pad_nd op with int16 I/O quantization for TOSA INT.""" + test_data, padding, value = test_data() + pipeline = TosaPipelineINT[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_no_quant(test_data: Tuple): + inp, padding, value = test_data() + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (inp,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_quant(test_data: Tuple): + inp, padding, value = test_data() + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (inp,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv1d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv1d.py new file mode 100644 index 0000000..7135167 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv1d.py @@ -0,0 +1,356 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple, Union + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.conv1d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + +input_t = Tuple[torch.Tensor] + + +class Conv1d(torch.nn.Module): + """ + Creates one or many chained 1D-convolutions. For multiple convolutions, the + respective parameteres are provided as lists. + """ + + def __init__( + self, + length=8, + nbr_conv=1, # Number of chained convs + in_channels: Union[List, int, None] = None, + out_channels: Union[List, int, None] = None, + kernel_size: Union[List, Tuple, None] = None, + stride: Union[List, Tuple, None] = None, + padding: Union[List, Tuple, None] = None, + dilation: Union[List, Tuple, None] = None, + groups: Union[List, int, None] = None, + bias: Union[List, bool, None] = None, + padding_mode: Union[List, str, None] = None, + batches=1, + dtype=torch.float32, + ): + super().__init__() + self.nbr_convs = nbr_conv + + # Handle default values + in_channels = [2] * nbr_conv if in_channels is None else in_channels + out_channels = [1 * nbr_conv] if out_channels is None else out_channels + kernel_size = [3] * nbr_conv if kernel_size is None else kernel_size + stride = [2] * nbr_conv if stride is None else stride + padding = [1] * nbr_conv if padding is None else padding + dilation = [1] * nbr_conv if dilation is None else dilation + groups = [1] * nbr_conv if groups is None else groups + bias = [True] * nbr_conv if bias is None else bias + padding_mode = ["zeros"] * nbr_conv if padding_mode is None else padding_mode + + # This allows the input parameters to be either a single value or a list + # as type hint implies + if not isinstance(in_channels, List): + in_channels = [in_channels] + if not isinstance(out_channels, List): + out_channels = [out_channels] + if not isinstance(kernel_size, List): + kernel_size = [kernel_size] + if not isinstance(stride, List): + stride = [stride] + if not isinstance(padding, List): + padding = [padding] + if not isinstance(dilation, List): + dilation = [dilation] + if not isinstance(groups, List): + groups = [groups] + if not isinstance(bias, List): + bias = [bias] + if not isinstance(padding_mode, List): + padding_mode = [padding_mode] + + self.batches = batches + self.in_channels = in_channels + self.length = length + self.dtype = dtype + + # Build chain of convs + for i in range(self.nbr_convs): + setattr( + self, + f"conv_{i}", + torch.nn.Conv1d( + in_channels=in_channels[i], + out_channels=out_channels[i], + kernel_size=kernel_size[i], + stride=stride[i], + padding=padding[i], + dilation=dilation[i], + groups=groups[i], + bias=bias[i], + padding_mode=padding_mode[i], + ).to(dtype), + ) + + def get_inputs(self): + return ( + torch.randn(self.batches, self.in_channels[0], self.length).to(self.dtype), + ) + + def forward(self, x): + for i in range(self.nbr_convs): + conv = getattr(self, f"conv_{i}") + x = conv(x) + return x + + +conv1d_2_3x2x40_nobias = Conv1d( + in_channels=2, + out_channels=3, + kernel_size=2, + stride=1, + bias=False, + padding=0, + length=40, + batches=1, +) + +conv1d_3_1x3x256_st1 = Conv1d( + in_channels=3, + out_channels=10, + kernel_size=3, + stride=1, + padding=0, + length=256, + batches=1, +) + +conv1d_3_1x3x12_st2_pd1 = Conv1d( + in_channels=3, + out_channels=4, + kernel_size=3, + stride=2, + padding=1, + length=12, + batches=1, +) + +conv1d_1_1x2x128_st1 = Conv1d( + in_channels=2, + out_channels=1, + kernel_size=1, + stride=1, + padding=0, + length=128, + batches=1, +) + +conv1d_2_1x2x14_st2 = Conv1d( + in_channels=2, + out_channels=1, + kernel_size=2, + stride=2, + padding=0, + length=14, + batches=1, +) + +conv1d_5_3x2x128_st1 = Conv1d( + in_channels=2, + out_channels=3, + kernel_size=5, + stride=1, + padding=0, + length=128, + batches=3, +) + +conv1d_3_1x3x224_st2_pd1 = Conv1d( + in_channels=3, + out_channels=16, + kernel_size=3, + stride=2, + padding=1, + length=224, + batches=1, +) + +conv1d_7_1x3x16_st2_pd1_dl2 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=7, + stride=2, + padding=1, + dilation=2, + length=16, + batches=1, +) +conv1d_7_1x3x15_st1_pd0_dl1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=7, + stride=1, + padding=0, + dilation=1, + length=15, + batches=1, +) +conv1d_5_1x3x14_st5_pd0_dl1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=5, + stride=5, + padding=0, + dilation=1, + length=14, + batches=1, +) +conv1d_5_1x3x9_st5_pd0_dl1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=5, + stride=5, + padding=0, + dilation=1, + length=9, + batches=1, +) + +two_conv1d_nobias = Conv1d( + nbr_conv=2, + length=256, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[5, 5], + stride=[1, 1], + padding=[0, 0], + bias=[False, False], + batches=1, +) + +two_conv1d = Conv1d( + nbr_conv=2, + length=256, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[5, 5], + stride=[1, 1], + padding=[0, 0], + bias=[True, True], + batches=1, +) + +test_data_FP = { + "2_3x2x40_nobias": lambda: conv1d_2_3x2x40_nobias, + "3_1x3x256_st1": lambda: conv1d_3_1x3x256_st1, + "3_1x3x12_st2_pd1": lambda: conv1d_3_1x3x12_st2_pd1, + "1_1x2x128_st1": lambda: conv1d_1_1x2x128_st1, + "2_1x2x14_st2": lambda: conv1d_2_1x2x14_st2, + "5_3x2x128_st1": lambda: conv1d_5_3x2x128_st1, + "3_1x3x224_st2_pd1": lambda: conv1d_3_1x3x224_st2_pd1, + "7_1x3x16_st2_pd1_dl2_needs_adjust_pass": lambda: conv1d_7_1x3x16_st2_pd1_dl2, + "7_1x3x15_st1_pd0_dl1_needs_adjust_pass": lambda: conv1d_7_1x3x15_st1_pd0_dl1, + "5_1x3x14_st5_pd0_dl1_needs_adjust_pass": lambda: conv1d_5_1x3x14_st5_pd0_dl1, + "5_1x3x9_st5_pd0_dl1_needs_adjust_pass": lambda: conv1d_5_1x3x9_st5_pd0_dl1, + "two_conv1d_nobias": lambda: two_conv1d_nobias, + "two_conv1d": lambda: two_conv1d, +} + +test_data_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + + +@common.parametrize("test_data", test_data_FP) +def test_convolution_1d_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t]( + test_data(), + test_data().get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_1d_tosa_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_1d_u55_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_1d_u85_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_1d_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t]( + test_data(), + test_data().get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_1d_vgf_quant(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv2d.py new file mode 100644 index 0000000..55eee29 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv2d.py @@ -0,0 +1,592 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple, Union + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a8w4_quantization_config, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +aten_op = "torch.ops.aten.conv2d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + + +class Conv2d(torch.nn.Module): + """ + Creates one or many chained 2D-convolutions. For multiple convolutions, the + respective parameteres are provided as lists. + """ + + def __init__( + self, + height=8, + width=8, + nbr_conv=1, # Number of chained convs + in_channels: Union[List, int, None] = None, + out_channels: Union[List, int, None] = None, + kernel_size: Union[List, Tuple, None] = None, + stride: Union[List, Tuple, int, None] = None, + padding: Union[List, Tuple, int, None] = None, + dilation: Union[List, Tuple, int, None] = None, + groups: Union[List, int, None] = None, + bias: Union[List, bool, None] = None, + padding_mode: Union[List, str, None] = None, + batches=1, + dtype=torch.float, + ): + super().__init__() + self.nbr_convs = nbr_conv + + # Handle default values + in_channels = [2] * nbr_conv if in_channels is None else in_channels + out_channels = [1 * nbr_conv] if out_channels is None else out_channels + kernel_size = [(3, 3)] * nbr_conv if kernel_size is None else kernel_size + stride = [(2, 2)] * nbr_conv if stride is None else stride + padding = [(1, 1)] * nbr_conv if padding is None else padding + dilation = [(1, 1)] * nbr_conv if dilation is None else dilation + groups = [1] * nbr_conv if groups is None else groups + bias = [True] * nbr_conv if bias is None else bias + padding_mode = ["zeros"] * nbr_conv if padding_mode is None else padding_mode + + # This allows the input parameters to be either a single value or a list + # as type hint implies + if not isinstance(in_channels, List): + in_channels = [in_channels] + if not isinstance(out_channels, List): + out_channels = [out_channels] + if not isinstance(kernel_size, List): + kernel_size = [kernel_size] + if not isinstance(stride, List): + stride = [stride] + if not isinstance(padding, List): + padding = [padding] + if not isinstance(dilation, List): + dilation = [dilation] + if not isinstance(groups, List): + groups = [groups] + if not isinstance(bias, List): + bias = [bias] + if not isinstance(padding_mode, List): + padding_mode = [padding_mode] + + self.batches = batches + self.in_channels = in_channels + self.height = height + self.width = width + self.dtype = dtype + + # Build chain of convs + for i in range(self.nbr_convs): + setattr( + self, + f"conv_{i}", + torch.nn.Conv2d( + in_channels=in_channels[i], + out_channels=out_channels[i], + kernel_size=kernel_size[i], + stride=stride[i], + padding=padding[i], + dilation=dilation[i], + groups=groups[i], + bias=bias[i], + padding_mode=padding_mode[i], + ).to(dtype), + ) + + def get_inputs(self): + return ( + torch.randn(self.batches, self.in_channels[0], self.height, self.width).to( + self.dtype + ), + ) + + def forward(self, x): + for i in range(self.nbr_convs): + conv = getattr(self, f"conv_{i}") + x = conv(x) + return x + + +conv2d_2x2_3x2x14x14_nobias = Conv2d( + in_channels=2, + out_channels=3, + kernel_size=(2, 2), + stride=1, + bias=False, + padding=0, + width=14, + height=14, + batches=2, +) + +conv2d_3x3_1x3x24x24_st1 = Conv2d( + in_channels=3, + out_channels=10, + kernel_size=(3, 3), + stride=1, + padding=0, + width=24, + height=24, + batches=1, +) + +conv2d_3x3_1x3x12x12_st2_pd1 = Conv2d( + in_channels=3, + out_channels=4, + kernel_size=(3, 3), + stride=2, + padding=1, + width=12, + height=12, + batches=1, +) + +conv2d_1x1_1x2x16x16_st1 = Conv2d( + in_channels=2, + out_channels=1, + kernel_size=(1, 1), + stride=1, + padding=0, + width=16, + height=16, + batches=1, +) + +conv2d_2x2_2x1x14x13_st2 = Conv2d( + in_channels=2, + out_channels=1, + kernel_size=(2, 2), + stride=2, + padding=0, + width=14, + height=13, + batches=1, +) + +conv2d_5x5_3x2x24x24_st1 = Conv2d( + in_channels=2, + out_channels=3, + kernel_size=(5, 5), + stride=1, + padding=0, + width=24, + height=24, + batches=2, +) + +conv2d_3x3_1x3x28x28_st2_pd1 = Conv2d( + in_channels=3, + out_channels=16, + kernel_size=(3, 3), + stride=2, + padding=1, + width=28, + height=28, + batches=1, +) + +conv2d_5x5_1x3x14x15_st3_pd1 = Conv2d( + in_channels=3, + out_channels=16, + kernel_size=(5, 5), + stride=3, + padding=1, + width=14, + height=15, + batches=1, +) + +conv2d_7x7_1x3x16x16_st2_pd1_dl2 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7), + stride=2, + padding=1, + dilation=2, + width=16, + height=16, + batches=1, +) + +conv2d_7x7_1x3x15x15_st1_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7), + stride=1, + padding=0, + dilation=1, + width=15, + height=15, + batches=1, +) + +conv2d_5x5_1x3x14x14_st5_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5), + stride=5, + padding=0, + dilation=1, + width=14, + height=14, + batches=1, +) + +conv2d_5x5_1x3x9x9_st5_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5), + stride=5, + padding=0, + dilation=1, + width=9, + height=9, + batches=1, +) + +conv2d_3x3_1x3x8x9_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv2d_3x3_1x3x9x8_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv2d_3x4_1x3x7x7_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 4), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +conv2d_4x3_1x3x7x7_st3_pd0_dl1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(4, 3), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +two_conv2d_nobias = Conv2d( + nbr_conv=2, + width=32, + height=32, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[(5, 5), (5, 5)], + stride=[1, 1], + padding=[0, 0], + bias=[False, False], + batches=1, +) + +two_conv2d = Conv2d( + nbr_conv=2, + width=32, + height=32, + in_channels=[3, 10], + out_channels=[10, 15], + kernel_size=[(5, 5), (5, 5)], + stride=[1, 1], + padding=[0, 0], + bias=[True, True], + batches=1, +) + +conv2d_groups = Conv2d( + in_channels=12, + out_channels=9, + kernel_size=(3, 3), + stride=1, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, + groups=3, + bias=False, +) + +conv2d_groups_bias = Conv2d( + in_channels=15, + out_channels=5, + kernel_size=(3, 3), + stride=1, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, + groups=5, + bias=True, +) + +# Shenanigan to get a nicer output when test fails. With unittest it looks like: +# FAIL: test_convolution_2d_tosa_INT_2_3x3_1x3x12x12_st2_pd1 +test_data_FP = { + "2x2_3x2x14x14_nobias": lambda: conv2d_2x2_3x2x14x14_nobias, + "3x3_1x3x24x24_st1": lambda: conv2d_3x3_1x3x24x24_st1, + "3x3_1x3x12x12_st2_pd1": lambda: conv2d_3x3_1x3x12x12_st2_pd1, + "1x1_1x2x16x16_st1": lambda: conv2d_1x1_1x2x16x16_st1, + "2x2_2x1x14x13_st2_needs_adjust_pass": lambda: conv2d_2x2_2x1x14x13_st2, + "5x5_1x3x14x15_st3_pd1_needs_adjust_pass": lambda: conv2d_5x5_1x3x14x15_st3_pd1, + "7x7_1x3x16x16_st2_pd1_dl2_needs_adjust_pass": lambda: conv2d_7x7_1x3x16x16_st2_pd1_dl2, + "7x7_1x3x15x15_st1_pd0_dl1_needs_adjust_pass": lambda: conv2d_7x7_1x3x15x15_st1_pd0_dl1, + "5x5_1x3x14x14_st5_pd0_dl1_needs_adjust_pass": lambda: conv2d_5x5_1x3x14x14_st5_pd0_dl1, + "5x5_1x3x9x9_st5_pd0_dl1_needs_adjust_pass": lambda: conv2d_5x5_1x3x9x9_st5_pd0_dl1, + "3x3_1x3x9x8_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_3x3_1x3x9x8_st3_pd0_dl1, + "3x3_1x3x8x9_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_3x3_1x3x8x9_st3_pd0_dl1, + "3x4_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_3x4_1x3x7x7_st3_pd0_dl1, + "4x3_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv2d_4x3_1x3x7x7_st3_pd0_dl1, + "5x5_3x2x24x24_st1": lambda: conv2d_5x5_3x2x24x24_st1, + "3x3_1x3x28x28_st2_pd1": lambda: conv2d_3x3_1x3x28x28_st2_pd1, + "two_conv2d_nobias": lambda: two_conv2d_nobias, + "two_conv2d": lambda: two_conv2d, + "groups": lambda: conv2d_groups, + "groups_bias": lambda: conv2d_groups_bias, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + +input_t = Tuple[torch.Tensor] + + +def _get_dtype_count(model: torch.nn.Module): + nbr_convs: int = model.nbr_convs # noqa + return { + "CONST": {"INT4": nbr_convs * 2}, # One for the weight, one for the zp. + "CONV2D": {"INT32": nbr_convs}, + "RESCALE": {"INT8": nbr_convs}, + } + + +@common.parametrize("test_data", test_data_FP) +def test_convolution_2d_tosa_FP(test_data): + model = test_data() + pipeline = TosaPipelineFP[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_2d_tosa_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_INT, + xfails={ + "groups,per_channel_quant=True": "Int4 not supported for grouped convolutions. MLETORCH-1726", + "groups,per_channel_quant=False": "Int4 not supported for grouped convolutions. MLETORCH-1726", + "groups_bias,per_channel_quant=True": "Int4 not supported for grouped convolutions. MLETORCH-1726", + "groups_bias,per_channel_quant=False": "Int4 not supported for grouped convolutions. MLETORCH-1726", + }, +) +def test_convolution_2d_tosa_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + tosa_extensions=["int4"], + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + _get_dtype_count(model), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_2d_u55_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_u85_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_2d_u85_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant(test_data): + model = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +reject_suite = { + "large_stride": lambda: Conv2d( + in_channels=1, + out_channels=1, + kernel_size=(2, 4), + stride=(2, 4), + padding=1, + width=10, + height=14, + batches=1, + ), + "large_kernel_height": lambda: Conv2d( + in_channels=1, + out_channels=1, + kernel_size=(2, 65), + stride=(1, 1), + padding=0, + width=70, + height=70, + batches=1, + ), + "large_kernel": lambda: Conv2d( + in_channels=1, + out_channels=1, + kernel_size=(70, 60), + stride=(1,), + padding=0, + width=80, + height=80, + batches=1, + ), +} + + +@common.parametrize("module", reject_suite) +def test_convolution_2d_u55_INT_not_delegated(module: Conv2d): + OpNotSupportedPipeline( + module(), + module().get_inputs(), + {"executorch_exir_dialects_edge__ops_aten_convolution_default": 1}, + quantize=True, + u55_subset=True, + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv3d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv3d.py new file mode 100644 index 0000000..f28315d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv3d.py @@ -0,0 +1,711 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List, Tuple, Union + +import pytest +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_a8w4_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.conv3d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + + +class Conv3d(torch.nn.Module): + """ + Creates one or many chained 3D-convolutions. For multiple convolutions, the + respective parameteres are provided as lists. + """ + + def __init__( + self, + height=8, + width=8, + depth=8, + nbr_conv=1, # Number of chained convs + in_channels: Union[List, int, None] = None, + out_channels: Union[List, int, None] = None, + kernel_size: Union[List, Tuple, None] = None, + stride: Union[List, Tuple, int, None] = None, + padding: Union[List, Tuple, int, None] = None, + dilation: Union[List, Tuple, int, None] = None, + groups: Union[List, int, None] = None, + bias: Union[List, bool, None] = None, + padding_mode: Union[List, str, None] = None, + batches=1, + dtype=torch.float, + ): + super().__init__() + self.nbr_convs = nbr_conv + + # Handle default values + in_channels = [2] * nbr_conv if in_channels is None else in_channels + out_channels = [1 * nbr_conv] if out_channels is None else out_channels + kernel_size = [(3, 3, 1)] * nbr_conv if kernel_size is None else kernel_size + stride = [(2, 2, 1)] * nbr_conv if stride is None else stride + padding = [(1, 1, 1)] * nbr_conv if padding is None else padding + dilation = [(1, 1, 1)] * nbr_conv if dilation is None else dilation + groups = [1] * nbr_conv if groups is None else groups + bias = [True] * nbr_conv if bias is None else bias + padding_mode = ["zeros"] * nbr_conv if padding_mode is None else padding_mode + + # This allows the input parameters to be either a single value or a list + # as type hint implies + if not isinstance(in_channels, List): + in_channels = [in_channels] + if not isinstance(out_channels, List): + out_channels = [out_channels] + if not isinstance(kernel_size, List): + kernel_size = [kernel_size] + if not isinstance(stride, List): + stride = [stride] + if not isinstance(padding, List): + padding = [padding] + if not isinstance(dilation, List): + dilation = [dilation] + if not isinstance(groups, List): + groups = [groups] + if not isinstance(bias, List): + bias = [bias] + if not isinstance(padding_mode, List): + padding_mode = [padding_mode] + + self.batches = batches + self.in_channels = in_channels + self.height = height + self.width = width + self.depth = depth + self.dtype = dtype + + # Build chain of convs + for i in range(self.nbr_convs): + setattr( + self, + f"conv_{i}", + torch.nn.Conv3d( + in_channels=in_channels[i], + out_channels=out_channels[i], + kernel_size=kernel_size[i], + stride=stride[i], + padding=padding[i], + dilation=dilation[i], + groups=groups[i], + bias=bias[i], + padding_mode=padding_mode[i], + ).to(dtype), + ) + + def get_inputs(self): + return ( + torch.randn( + self.batches, + self.in_channels[0], + self.depth, + self.height, + self.width, + ).to(self.dtype), + ) + + def forward(self, x): + for i in range(self.nbr_convs): + conv = getattr(self, f"conv_{i}") + x = conv(x) + return x + + +class Conv3dMultiOp(torch.nn.Module): + """ + Mixed Conv3d/Conv2d pipeline used to verify spatial-rank propagation across ops. + + Topology: + conv3d -> reshape -> conv2d -> reshape/permutation -> conv2d -> reshape -> add(5D) + """ + + def __init__(self, dtype=torch.float): + super().__init__() + self.dtype = dtype + self.conv3d = torch.nn.Conv3d( + in_channels=2, + out_channels=4, + kernel_size=(3, 3, 3), + stride=1, + padding=1, + ).to(dtype) + self.conv2d_main = torch.nn.Conv2d( + in_channels=4, + out_channels=4, + kernel_size=3, + stride=1, + padding=1, + ).to(dtype) + self.conv2d_pointwise = torch.nn.Conv2d( + in_channels=4, + out_channels=4, + kernel_size=1, + stride=1, + padding=0, + ).to(dtype) + self.activation = torch.nn.ReLU() + + def get_inputs(self): + return (torch.randn(1, 2, 3, 8, 8).to(self.dtype),) + + def forward(self, x): + x3d = self.conv3d(x) + batches, channels, depth, height, width = x3d.shape + + reshaped = x3d.reshape(batches * depth, channels, height, width) + conv2d_out = self.activation(self.conv2d_main(reshaped)) + + conv2d_out_5d = ( + conv2d_out.reshape(batches, depth, channels, height, width) + .permute(0, 2, 1, 3, 4) + .contiguous() + ) + + reshaped_again = conv2d_out_5d.permute(0, 2, 1, 3, 4).reshape( + batches * depth, channels, height, width + ) + conv2d_pointwise_out = self.conv2d_pointwise(reshaped_again) + conv2d_pointwise_out_5d = ( + conv2d_pointwise_out.reshape(batches, depth, channels, height, width) + .permute(0, 2, 1, 3, 4) + .contiguous() + ) + + return conv2d_pointwise_out_5d + x3d + + +class DepthwiseConv3d(torch.nn.Module): + def __init__(self, dtype=torch.float): + super().__init__() + self.dtype = dtype + self.conv = torch.nn.Conv3d( + in_channels=2, + out_channels=4, + kernel_size=(3, 3, 3), + padding=1, + groups=2, + ).to(dtype) + + def get_inputs(self): + return (torch.randn(1, 2, 3, 8, 8).to(self.dtype),) + + def forward(self, x): + return self.conv(x) + + +conv3d_2x2_3x2x14x14_nobias = Conv3d( + in_channels=2, + out_channels=3, + kernel_size=(2, 2, 2), + stride=1, + bias=False, + padding=0, + width=14, + height=14, + batches=2, +) + +conv3d_3x3_1x3x24x24_st1 = Conv3d( + in_channels=3, + out_channels=10, + kernel_size=(3, 3, 3), + stride=1, + padding=0, + width=24, + height=24, + batches=1, +) + +conv3d_3x3_1x3x12x12_st2_pd1 = Conv3d( + in_channels=3, + out_channels=4, + kernel_size=(3, 3, 3), + stride=2, + padding=1, + width=12, + height=12, + batches=1, +) + +conv3d_1x1_1x2x16x16_st1 = Conv3d( + in_channels=2, + out_channels=1, + kernel_size=(1, 1, 1), + stride=1, + padding=0, + width=16, + height=16, + batches=1, +) + +conv3d_2x2_1x1x14x13_st2 = Conv3d( + in_channels=1, + out_channels=1, + kernel_size=(2, 2, 2), + stride=2, + padding=0, + width=14, + height=13, + batches=1, +) + +conv3d_5x5_3x2x24x24_st1 = Conv3d( + in_channels=2, + out_channels=3, + kernel_size=(5, 5, 5), + stride=1, + padding=0, + width=24, + height=24, + batches=2, +) + +conv3d_3x3_1x3x28x28_st2_pd1 = Conv3d( + in_channels=3, + out_channels=16, + kernel_size=(3, 3, 3), + stride=2, + padding=1, + width=28, + height=28, + batches=1, +) + +conv3d_5x5_1x3x14x15_st3_pd1 = Conv3d( + in_channels=3, + out_channels=16, + kernel_size=(5, 5, 5), + stride=3, + padding=1, + width=14, + height=15, + batches=1, +) + +conv3d_7x7_1x3x16x16_st2_pd1_dl2 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7, 7), + stride=2, + padding=3, + dilation=1, + width=16, + height=16, + batches=1, +) + +conv3d_7x7_1x3x15x15_st1_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(7, 7, 7), + stride=1, + padding=0, + dilation=1, + width=15, + height=15, + batches=1, +) + +conv3d_5x5_1x3x14x14_st5_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5, 5), + stride=5, + padding=0, + dilation=1, + width=14, + height=14, + batches=1, +) + +conv3d_5x5_1x3x9x9_st5_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(5, 5, 5), + stride=5, + padding=0, + dilation=1, + width=9, + height=9, + batches=1, +) + +conv3d_3x3_1x3x8x9_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv3d_3x3_1x3x9x8_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3, 3), + stride=3, + padding=0, + dilation=1, + width=8, + height=9, + batches=1, +) + +conv3d_3x4_1x3x7x7_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(3, 4, 3), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +conv3d_4x3_1x3x7x7_st3_pd0_dl1 = Conv3d( + in_channels=3, + out_channels=3, + kernel_size=(4, 3, 3), + stride=3, + padding=0, + dilation=1, + width=7, + height=7, + batches=1, +) + +test_data_FP = { + "2x2_3x2x14x14_nobias": lambda: conv3d_2x2_3x2x14x14_nobias, + "3x3_1x3x24x24_st1": lambda: conv3d_3x3_1x3x24x24_st1, + "3x3_1x3x12x12_st2_pd1": lambda: conv3d_3x3_1x3x12x12_st2_pd1, + "1x1_1x2x16x16_st1": lambda: conv3d_1x1_1x2x16x16_st1, + "2x2_1x1x14x13_st2_needs_adjust_pass": lambda: conv3d_2x2_1x1x14x13_st2, + "5x5_1x3x14x15_st3_pd1_needs_adjust_pass": lambda: conv3d_5x5_1x3x14x15_st3_pd1, + "7x7_1x3x16x16_st2_pd1_dl2_needs_adjust_pass": lambda: conv3d_7x7_1x3x16x16_st2_pd1_dl2, + "7x7_1x3x15x15_st1_pd0_dl1_needs_adjust_pass": lambda: conv3d_7x7_1x3x15x15_st1_pd0_dl1, + "5x5_1x3x14x14_st5_pd0_dl1_needs_adjust_pass": lambda: conv3d_5x5_1x3x14x14_st5_pd0_dl1, + "5x5_1x3x9x9_st5_pd0_dl1_needs_adjust_pass": lambda: conv3d_5x5_1x3x9x9_st5_pd0_dl1, + "3x3_1x3x9x8_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_3x3_1x3x9x8_st3_pd0_dl1, + "3x3_1x3x8x9_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_3x3_1x3x8x9_st3_pd0_dl1, + "3x4_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_3x4_1x3x7x7_st3_pd0_dl1, + "4x3_1x3x7x7_st3_pd0_dl1_needs_adjust_pass": lambda: conv3d_4x3_1x3x7x7_st3_pd0_dl1, + "5x5_3x2x24x24_st1": lambda: conv3d_5x5_3x2x24x24_st1, + "3x3_1x3x28x28_st2_pd1": lambda: conv3d_3x3_1x3x28x28_st2_pd1, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + +test_data_INT16 = { + f"{k},16a8w,per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] +} + + +def _get_dtype_count(model: torch.nn.Module): + nbr_convs: int = model.nbr_convs # noqa + return { + "CONST": {"INT4": nbr_convs * 2}, + "CONV3D": {"INT32": nbr_convs}, + "RESCALE": {"INT8": nbr_convs}, + } + + +def get_symmetric_a16w8_conv3d_quantizer(per_channel_quantization: bool = False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quant_config = get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ) + quantizer.set_global(quant_config) + quantizer.set_module_type(torch.nn.Conv3d, quant_config) + + return Quantize( + quantizer, + quant_config, + ) + + +input_t = Tuple[torch.Tensor] + + +@common.parametrize("test_data", test_data_FP) +def test_convolution_3d_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t]( + test_data(), test_data().get_inputs(), aten_op, exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_3d_tosa_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +def test_convolution_3d_tosa_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + tosa_extensions=["int4"], + qtol=1, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + _get_dtype_count(model), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT16) +def test_convolution_3d_tosa_INT_a16w8(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + qtol=1, + ) + pipeline.change_args( + "quantize", + get_symmetric_a16w8_conv3d_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +def test_convolution_3d_tosa_FP_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = TosaPipelineFP[input_t](model, model.get_inputs(), aten_op, exir_op) + pipeline.run() + + +def test_convolution_3d_tosa_INT_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +def test_convolution_3d_tosa_FP_depthwise(): + """Depthwise or Grouped Conv3d should be rejected until grouped support exists.""" + model = DepthwiseConv3d() + pipeline = TosaPipelineFP[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + run_on_tosa_ref_model=False, + ) + with pytest.raises(RuntimeError, match="CONV3D with groups != 1"): + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U55 does not support CONV3D yet.") +def test_convolution_3d_u55_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U55 does not support CONV3D yet.") +def test_convolution_3d_u55_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U85 does not support CONV3D yet.") +def test_convolution_3d_u85_INT(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@pytest.mark.skip(reason="Ethos-U85 does not support CONV3D yet.") +def test_convolution_3d_u85_INT_a8w4(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t]( + test_data(), + test_data().get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_quant(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_no_quant_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_3d_vgf_quant_multi_op(): + """Ensure mixed Conv3d/Conv2d graphs keep correct spatial annotations.""" + model = Conv3dMultiOp() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +reject_suite = { + "large_stride": lambda: Conv3d( + in_channels=1, + out_channels=1, + kernel_size=(2, 2, 1), + stride=(2, 4, 2), + padding=1, + width=10, + height=14, + batches=1, + ), + "large_kernel_z": lambda: Conv3d( + in_channels=1, + out_channels=1, + kernel_size=(2, 2, 2), + stride=1, + padding=0, + width=80, + height=80, + batches=1, + ), +} + + +@common.parametrize("module", reject_suite) +def test_convolution_u55_INT_not_delegated_3d(module: Conv3d): + OpNotSupportedPipeline( + module(), + module().get_inputs(), + {"executorch_exir_dialects_edge__ops_aten_convolution_default": 1}, + quantize=True, + u55_subset=True, + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_combos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_combos.py new file mode 100644 index 0000000..1b69768 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_combos.py @@ -0,0 +1,668 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + +from torch.nn.parameter import Parameter + + +""" +This file contain unit tests where conv are combined with other ops. +""" + + +class ComboBlockBottleneckResidual(torch.nn.Module): + # This is the essence of MobileNetV2. Ref: https://arxiv.org/abs/1801.04381 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default", + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + test_data_INT = { + "per_channel_quant=True": True, + "per_channel_quant=False": False, + } + + def __init__(self): + super().__init__() + # (t, c, n, s) = (6, 96, 1, 1) + # 1. 1x1 CONV2d + ReLU6 (Pointwise) + self.pointwise_conv2d = torch.nn.Conv2d( + in_channels=16, out_channels=96, kernel_size=1, stride=1, groups=1 + ) ## Example output shape (1, 96, 33, 33) + self.batch_norm2d_16 = torch.nn.BatchNorm2d(96, affine=False) + self.relu6 = torch.nn.ReLU6() + + # 2. 3x3 DepthwiseConv2d + ReLu6 + self.depthwise_conv2d = torch.nn.Conv2d( + in_channels=96, + out_channels=96, + kernel_size=3, + padding=1, + stride=1, + groups=96, + ) ## Example output shape (1, 96, H, W) + + # 3. Linear 1x1 Conv2d + self.pointwise_conv2d_linear = torch.nn.Conv2d( + in_channels=96, out_channels=16, kernel_size=1, stride=1, groups=1 + ) ## Example output shape (1, 16, 33, 33) + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 16, 33, 33),) + + def forward(self, x): + input = x + # 1x1 CONV2d + ReLU6 (Pointwise) + x = self.pointwise_conv2d(x) + x = self.batch_norm2d_16(x) + x = self.relu6(x) + + # 3x3 DepthwiseConv2d + ReLu6 + x = self.depthwise_conv2d(x) + x = self.batch_norm2d_16(x) + x = self.relu6(x) + + # Linear 1x1 Conv2d + x = self.pointwise_conv2d_linear(x) + + # Final Residual Connection + x = x + input + + return x + + +class ComboConv2dMeandim(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten_mean_dim", + ] + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=10, kernel_size=5, stride=1, bias=False + ) + # will be specialized to aten.mean.dim + self.adaptive_avg_pool2d = torch.nn.AdaptiveAvgPool2d((1, 1)) + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 3, 48, 48),) + + def forward(self, x): + x = self.conv2d(x) + return self.adaptive_avg_pool2d(x) + + +class ComboConvBatchnormRelu6(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default", + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + ] + + test_data_FP = { + "affine=True": True, + "affine=False": False, + } + + test_data_INT = { + "affine=True,per_channel_quant=True": (True, True), + "affine=True,per_channel_quant=False": (True, False), + "affine=False,per_channel_quant=True": (False, True), + "affine=False,per_channel_quant=False": (False, False), + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + self.batch_norm2d.weight = Parameter(torch.rand(3)) + self.batch_norm2d.bias = Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> Tuple[torch.Tensor]: + return (torch.randn(1, 3, 64, 64),) + + def forward(self, x): + x = self.conv2d(x) + x = self.batch_norm2d(x) + x = self.relu6(x) + return x + + +class ComboConvRelu6(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + ] + + test_data_FP = { + "combo_conv_relu_2_x_4d": lambda: (2 * torch.randn(1, 3, 64, 64),), + "combo_conv_relu_0_5_x_4d": lambda: (0.5 * torch.randn(1, 3, 64, 64),), + "combo_conv_relu_4d": lambda: (torch.randn(1, 3, 64, 64),), + "combo_conv_relu_neg_0_5_x_4d": lambda: (-0.5 * torch.randn(1, 3, 64, 64),), + "combo_conv_relu_neg_2_x_4d": lambda: (-2 * torch.randn(1, 3, 64, 64),), + } + + # Generate a new test set paired with per_channel_quant=True/False. + test_data_INT = { + # test_name: (input, per_channel_quant) + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] + } + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.relu6 = torch.nn.ReLU6() + + def forward(self, x): + x = self.conv2d(x) + x = self.relu6(x) + return x + + +class ComboConvAvgPool2d(torch.nn.Module): + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_convolution_default", + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default", + ] + + test_data_FP = { + "combo_conv_avgpool_20_x_4d": lambda: (20 * torch.randn(1, 3, 48, 24),), + "combo_conv_avgpool_4d": lambda: (torch.randn(1, 3, 60, 120),), + "combo_conv_avgpool_5_x_4d_randn": lambda: (5 * torch.randn(1, 3, 64, 64),), + "combo_conv_avgpool_2_x_4d": lambda: (torch.rand(1, 3, 96, 32),), + } + + # Generate a new test set paired with per_channel_quant=True/False. + test_data_INT = { + # test_name: (input, per_channel_quant) + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_FP.items() + for q in [True, False] + } + + def __init__(self): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.avg_pool2d = torch.nn.AvgPool2d(kernel_size=(2, 2)) + + def forward(self, x): + x = self.conv2d(x) + x = self.avg_pool2d(x) + return x + + +#################### +## Conv + meandim ## +#################### + + +def test_convolution_2d_tosa_FP_meandim(): + model = ComboConv2dMeandim() + pipeline = TosaPipelineFP[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +def test_convolution_2d_tosa_INT_meandim(): + model = ComboConv2dMeandim() + pipeline = TosaPipelineINT[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_meandim(): + model = ComboConv2dMeandim() + pipeline = EthosU55PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_meandim(): + model = ComboConv2dMeandim() + pipeline = EthosU85PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=ComboConv2dMeandim.edge_op_list, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_meandim(): + model = ComboConv2dMeandim() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_meandim(): + model = ComboConv2dMeandim() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConv2dMeandim.edge_op_list, + quantize=True, + ) + pipeline.run() + + +############################## +## Conv + batch norm + relu ## +############################## + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_FP) +def test_convolution_2d_tosa_FP_batchnorm_relu6(test_data): + affine = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = TosaPipelineFP[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +def test_convolution_2d_tosa_INT_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = TosaPipelineINT[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = EthosU55PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = EthosU85PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_batchnorm_relu6(test_data): + affine = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvBatchnormRelu6.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_batchnorm_relu6(test_data): + affine, per_channel_quantization = test_data + model = ComboConvBatchnormRelu6(affine) + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboConvBatchnormRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +################## +## Conv + ReLU6 ## +################## + + +@common.parametrize("test_data", ComboConvRelu6.test_data_FP) +def test_convolution_2d_tosa_FP_relu6(test_data): + model = ComboConvRelu6() + pipeline = TosaPipelineFP[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +def test_convolution_2d_tosa_INT_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = TosaPipelineINT[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = EthosU55PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = EthosU85PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_relu6(test_data): + model = ComboConvRelu6() + pipeline = VgfPipeline[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvRelu6.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_relu6(test_data): + input, per_channel_quantization = test_data() + model = ComboConvRelu6() + pipeline = VgfPipeline[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvRelu6.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +############################### +## Block bottleneck residual ## +############################### +def test_convolution_2d_tosa_FP_block_bottleneck(): + model = ComboBlockBottleneckResidual() + pipeline = TosaPipelineFP[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +def test_convolution_2d_tosa_INT_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = TosaPipelineINT[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.change_args("run_method_and_compare_outputs", model.get_inputs(), qtol=1) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = EthosU55PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = EthosU85PipelineINT[input_t1]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_block_bottleneck(): + model = ComboBlockBottleneckResidual() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboBlockBottleneckResidual.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_block_bottleneck(test_data): + per_channel_quantization = test_data + model = ComboBlockBottleneckResidual() + pipeline = VgfPipeline[input_t1]( + model, + model.get_inputs(), + aten_op=[], + exir_op=ComboBlockBottleneckResidual.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +###################### +## Conv + AvgPool2d ## +###################### + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_FP) +def test_convolution_2d_tosa_FP_avgpool2d(test_data): + model = ComboConvAvgPool2d() + pipeline = TosaPipelineFP[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +def test_convolution_2d_tosa_INT_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = TosaPipelineINT[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +@common.XfailIfNoCorstone300 +def test_convolution_2d_u55_INT_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = EthosU55PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +@common.XfailIfNoCorstone320 +def test_convolution_2d_u85_INT_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = EthosU85PipelineINT[input_t1]( + model, + input, + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_avgpool2d(test_data): + model = ComboConvAvgPool2d() + pipeline = VgfPipeline[input_t1]( + model, + test_data(), + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", ComboConvAvgPool2d.test_data_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_avgpool2d(test_data): + input, per_channel_quantization = test_data() + model = ComboConvAvgPool2d() + pipeline = VgfPipeline[input_t1]( + model, + input, + aten_op=[], + exir_op=ComboConvAvgPool2d.edge_op_list, + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_constant_pad_nd.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_constant_pad_nd.py new file mode 100644 index 0000000..aecce1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_conv_constant_pad_nd.py @@ -0,0 +1,145 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Test the pad_constant_nd op which pads the input tensor at specific dimension(s). +# + +from typing import Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.pad.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_pad_default" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + "4dim_last1dim": (torch.rand(1, 1, 16, 16), (1, 1, 0, 0, 0, 0, 0, 0), 1), + "4dim_last2dim": (torch.rand(1, 1, 16, 16), (1, 0, 1, 0, 0, 0, 0, 0), 2), + "4dim_last3dim": (torch.rand(1, 1, 16, 16), (1, 1, 0, 2, 0, 2, 0, 0), 3), + "4dim_last4dim": (torch.rand(1, 1, 16, 16), (1, 0, 1, 1, 0, 2, 0, 2), 4), + "3dim_last1dim": (torch.rand(1, 1, 16), (1, 1, 0, 0, 0, 0), 1), + "3dim_last2dim": (torch.rand(1, 1, 16), (1, 0, 1, 1, 0, 0), 2), + "3dim_last3dim": (torch.rand(1, 1, 16), (1, 0, 1, 0, 1, 1), 3), + "2dim_last1dim": (torch.rand(1, 1, 16), (1, 1, 0, 0), 1), + "2dim_last2dim": (torch.rand(1, 1, 16), (1, 0, 1, 1), 2), +} + + +"""Tests conv + pad.""" + + +class ConstantPadND(torch.nn.Module): + def __init__(self, pad: Tuple, value: float | None = None): + super().__init__() + self.dim = len(pad) // 2 + self.value = value + in_channels = 1 + # Only apply conv2d when the input dim = 4. + if self.dim == 4: + in_channels += pad[-3] + pad[-4] + + self.conv2d = nn.Conv2d( + in_channels=in_channels, + out_channels=3, + kernel_size=3, + bias=True, + stride=(2, 2), + padding=0, + ) + + in_channels = 3 + in_channels += pad[-3] + pad[-4] + self.conv2d_1 = nn.Conv2d( + in_channels=in_channels, + out_channels=3, + kernel_size=3, + bias=True, + padding="same", + ) + + nonzero_idx = len(pad) + for i in range(0, len(pad), 2): + if pad[i] + pad[i + 1] == 0: + nonzero_idx = i + break + self.pad = pad[:nonzero_idx] + self.relu = nn.ReLU() + self.sigmoid = nn.Sigmoid() + + def forward(self, x: torch.Tensor): + x = F.pad(x, pad=self.pad, mode="constant", value=self.value) + if self.dim == 4: + x = self.conv2d(x) + x = self.relu(x) + + x = F.pad(x, pad=self.pad, mode="constant", value=self.value) + if self.dim == 4: + x = self.conv2d_1(x) + x = self.sigmoid(x) + return x + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_FP(test_data: Tuple): + test_data, padding, value = test_data + pipeline = TosaPipelineFP[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_constant_pad_nd_tosa_INT(test_data: Tuple): + test_data, padding, value = test_data + pipeline = TosaPipelineINT[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + atol=0.005, # TODO: Investigate flakyness (MLETORCH-989) + rtol=0.01, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_no_quant(test_data: Tuple): + test_data, padding, value = test_data + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_constant_pad_nd_vgf_quant(test_data: Tuple): + test_data, padding, value = test_data + pipeline = VgfPipeline[input_t1]( + ConstantPadND(padding, value), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_copy.py new file mode 100644 index 0000000..556e952 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_copy.py @@ -0,0 +1,171 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class CopyOutput(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return y.copy_(x / x) + x + + +class CopyFirstArg(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return y.copy_(x) + x + + +class CopySecondArg(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return x * y.copy_(x) + + +class CopyBothArgs(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return y.copy_(x) + y.copy_(x) + + +class CopyAfterOtherOp(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + x = x * 2 + return y.copy_(x) + x + + +class CopyParallelToOtherOp(torch.nn.Module): + def forward(self, x): + y = torch.zeros(x.shape) + return x * 2 + y.copy_(x) + + +test_suite = { + "copy_output": lambda: ( + CopyOutput, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_first_arg": lambda: ( + CopyFirstArg, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_second_arg": lambda: ( + CopySecondArg, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_both_args": lambda: ( + CopyBothArgs, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_after_other_op": lambda: ( + CopyAfterOtherOp, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), + "copy_parallel_to_other_op": lambda: ( + CopyParallelToOtherOp, + (torch.rand(1, 2, 3, 4, dtype=torch.float32),), + ), +} + + +aten_op = "torch.ops.aten.copy_.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_copy_default" + +input_t = Tuple[torch.Tensor] + + +@common.parametrize("input_data", test_suite) +def test_copy_tosa_FP(input_data): + module, input_tensor = input_data() + pipeline = TosaPipelineFP[input_t]( + module(), + input_tensor, + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", test_suite) +def test_copy_tosa_INT(input_data): + module, input_tensor = input_data() + + pipeline = TosaPipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", test_suite) +@common.XfailIfNoCorstone300 +def test_copy_u55_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU55PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("input_data", test_suite) +@common.XfailIfNoCorstone320 +def test_copy_u85_INT(input_data): + module, input_tensor = input_data() + + pipeline = EthosU85PipelineINT[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_suite) +@common.SkipIfNoModelConverter +def test_copy_vgf_no_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_suite) +@common.SkipIfNoModelConverter +def test_copy_vgf_quant(test_data): + module, input_tensor = test_data() + pipeline = VgfPipeline[input_t]( + module(), + input_tensor, + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cos.py new file mode 100644 index 0000000..4268611 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cos.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.cos.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10, 10), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Cos(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.cos(x) + + +@common.parametrize("test_data", test_data_suite) +@pytest.mark.tosa_ref_model +def test_cos_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + if conftest.get_option("tosa_version") == "1.0": + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@pytest.mark.tosa_ref_model +def test_cos_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_cos_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_cos_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cos_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cos_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cos(), + (test_data,), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cosh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cosh.py new file mode 100644 index 0000000..a07b3ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cosh.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.cosh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__cosh_default" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10), + "zeros_4D": torch.zeros(1, 10, 32, 7), + "zeros_alt_shape": torch.zeros(10, 3, 5), + "ones": torch.ones(15, 10, 7), + "ones_4D": torch.ones(1, 3, 32, 16), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(10, 3, 5) - 0.5, + "rand_4D": torch.rand(1, 6, 5, 7) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), + "large": 100 * torch.ones(1, 1), + "small": 0.000001 * torch.ones(1, 1), + "small_rand": torch.rand(100) * 0.01, + "biggest": torch.tensor([700.0, 710.0, 750.0]), +} + + +class Cosh(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.cosh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_cosh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Cosh(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_cosh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Cosh(), (test_data,), aten_op=aten_op, exir_op=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_cosh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Cosh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize( + "test_data", + test_data_suite, + strict=False, +) +def test_cosh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Cosh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cosh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cosh(), + (test_data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_cosh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Cosh(), + (test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cumsum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cumsum.py new file mode 100644 index 0000000..09afd57 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_cumsum.py @@ -0,0 +1,122 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, int] +aten_op = "torch.ops.aten.cumsum.default" + +""" +Tests the aten.cumsum operator by decomposing it into a convolution and +verifying results across various dims and pipelines. +""" + + +class CumsumModule(torch.nn.Module): + test_parameters = { + "1d_dim0": lambda: (torch.rand(10), 0), + "1d_dim_neg1": lambda: (torch.rand(10), -1), + "2d_dim1": lambda: (torch.rand(5, 6), 1), + "3d_dim2": lambda: (torch.rand(2, 3, 4), 2), + "3d_dim0": lambda: (torch.rand(2, 3, 4), 0), + "4d_dim3": lambda: (torch.rand(1, 2, 3, 4), 3), + "4d_dim1": lambda: (torch.rand(1, 2, 3, 4), 1), + } + + def forward(self, x: torch.Tensor, dim: int) -> torch.Tensor: + return torch.cumsum(x, dim) + + +@common.parametrize("test_data", CumsumModule.test_parameters) +def test_cumsum_tosa_FP(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + args, + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +def test_cumsum_tosa_INT(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + args, + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.SkipIfNoModelConverter +def test_cumsum_vgf_no_quant(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.SkipIfNoModelConverter +def test_cumsum_vgf_quant(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.XfailIfNoCorstone300 +def test_cumsum_u55_INT(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + args, + aten_ops=aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", CumsumModule.test_parameters) +@common.XfailIfNoCorstone320 +def test_cumsum_u85_INT(test_data: input_t1): + module = CumsumModule() + args = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + args, + aten_ops=aten_op, + exir_ops=[], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_depthwise_conv.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_depthwise_conv.py new file mode 100644 index 0000000..b4289f9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_depthwise_conv.py @@ -0,0 +1,404 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a8w4_quantization_config, +) +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] # Input x + +exir_op = "executorch_exir_dialects_edge__ops_aten_convolution_default" + +from executorch.backends.arm.test.ops.test_conv1d import Conv1d +from executorch.backends.arm.test.ops.test_conv2d import Conv2d + + +""" +The configuration when + groups == in_channels and + out_channels = K * in_channels + where K is a positive integer +is termed in literature as depthwise convolution. +""" + +dw_conv1d_3_1x3x14_gp3_st1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=7, + stride=1, + groups=3, + length=14, + batches=1, + padding=3, +) + +dw_conv1d_2_1x6x4_gp6_st1 = Conv1d( + in_channels=6, + out_channels=12, + kernel_size=2, + stride=1, + groups=6, + padding=0, + length=4, + batches=1, +) + +dw_conv2d_2x2_1x6x4x4_gp6_st1 = Conv2d( + in_channels=6, + out_channels=12, + kernel_size=(2, 2), + stride=(1, 1), + groups=6, + padding=0, + width=4, + height=4, + batches=1, +) + +dw_conv1d_3_1x3x32_gp3_st1 = Conv1d( + in_channels=3, + out_channels=3, + kernel_size=3, + stride=1, + groups=3, + padding=0, + length=32, + batches=1, +) + +dw_conv2d_3x3_1x3x24x24_gp3_st1 = Conv2d( + in_channels=3, + out_channels=3, + kernel_size=(3, 3), + stride=(1, 1), + groups=3, + padding=0, + width=24, + height=24, + batches=1, +) + +dw_conv2d_3x3_1x4x24x24_gp4_st1 = Conv2d( + in_channels=4, + out_channels=8, + kernel_size=(3, 3), + stride=(1, 1), + groups=4, + padding=0, + width=24, + height=24, + batches=1, +) + +dw_conv2d_3x3_2x8x27x27_gp8_st3 = Conv2d( + in_channels=8, + out_channels=16, + kernel_size=(3, 3), + stride=3, + groups=8, + padding=0, + width=27, + height=27, + batches=2, +) + +dw_conv2d_3x3_1x4x24x24_gp4_nobias = Conv2d( + in_channels=4, + out_channels=8, + kernel_size=(3, 3), + stride=1, + groups=4, + bias=False, + width=24, + height=24, + batches=1, +) + +two_dw_conv1d = Conv1d( + nbr_conv=2, + length=16, + in_channels=[4, 8], + out_channels=[8, 24], + kernel_size=[3, 3], + stride=[1, 1], + padding=[0, 0], + groups=[4, 8], + bias=[True, True], + batches=1, +) + +two_dw_conv2d = Conv2d( + nbr_conv=2, + width=24, + height=24, + in_channels=[4, 8], + out_channels=[8, 24], + kernel_size=[(3, 3), (3, 3)], + stride=[1, 1], + padding=[0, 0], + groups=[4, 8], + bias=[True, True], + batches=2, +) + +# Shenanigan to get a nicer output when test fails. +test_data_conv2d_FP = { + "2x2_1x6x4x4_gp6_st1": lambda: dw_conv2d_2x2_1x6x4x4_gp6_st1, + "3x3_1x3x24x24_gp3_st1": lambda: dw_conv2d_3x3_1x3x24x24_gp3_st1, + "3x3_1x4x24x24_gp4_nobias": lambda: dw_conv2d_3x3_1x4x24x24_gp4_nobias, + "3x3_1x4x24x24_gp4_st1": lambda: dw_conv2d_3x3_1x4x24x24_gp4_st1, + "3x3_2x8x27x27_gp8_st3": lambda: dw_conv2d_3x3_2x8x27x27_gp8_st3, + "two_dw_conv2d": lambda: two_dw_conv2d, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_conv2d_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_conv2d_FP.items() + for q in [True, False] +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_conv2d_u85 = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in { + "2x2_1x6x4x4_gp6_st1": lambda: dw_conv2d_2x2_1x6x4x4_gp6_st1, + "3x3_1x3x24x24_gp3_st1": lambda: dw_conv2d_3x3_1x3x24x24_gp3_st1, + "3x3_1x4x24x24_gp4_st1": lambda: dw_conv2d_3x3_1x4x24x24_gp4_st1, + "3x3_1x4x24x24_gp4_nobias": lambda: dw_conv2d_3x3_1x4x24x24_gp4_nobias, + }.items() + for q in [True, False] +} + +test_data_conv1d_FP = { + "2_1x6x4_gp6_st1": lambda: dw_conv1d_2_1x6x4_gp6_st1, + "two_dw_conv1d": lambda: two_dw_conv1d, + "3_1x3x32_gp3_st1": lambda: dw_conv1d_3_1x3x32_gp3_st1, + "3_1x3x14_gp3_st1": lambda: dw_conv1d_3_1x3x14_gp3_st1, +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_conv1d_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (v(), q)) + for (k, v) in test_data_conv1d_FP.items() + for q in [True, False] +} + + +def _get_dtype_count(model: torch.nn.Module): + nbr_convs: int = model.nbr_convs # noqa + return { + "CONST": {"INT4": nbr_convs * 2}, + "DEPTHWISE_CONV2D": {"INT32": nbr_convs}, + "RESCALE": {"INT8": nbr_convs}, + } + + +@common.parametrize("test_data", test_data_conv1d_FP | test_data_conv2d_FP) +def test_convolution_2d_tosa_FP_depthwise(test_data: torch.nn.Module): + pipeline = TosaPipelineFP[input_t]( + test_data(), + test_data().get_inputs(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@pytest.mark.flaky(reruns=5) # TODO: Investigate flakyness (MLTORCH-307) +@common.parametrize("test_data", test_data_conv1d_INT | test_data_conv2d_INT) +def test_convolution_2d_tosa_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_conv1d_INT | test_data_conv2d_INT) +def test_convolution_2d_tosa_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + tosa_extensions=["int4"], + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + _get_dtype_count(model), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_conv1d_FP | test_data_conv2d_FP) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_no_quant_depthwise(test_data: torch.nn.Module): + model = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_conv1d_INT | test_data_conv2d_INT) +@common.SkipIfNoModelConverter +def test_convolution_2d_vgf_quant_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = VgfPipeline[input_t]( + model, + model.get_inputs(), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u55_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u55_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u55_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u55_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u85_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv2d_INT) +def test_convolution_2d_u85_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u85_INT_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + per_channel_quantization=per_channel_quantization, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_conv1d_INT) +def test_convolution_1d_u85_INT_a8w4_depthwise(test_data): + model, per_channel_quantization = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + model.get_inputs(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div.py new file mode 100644 index 0000000..9e932b1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div.py @@ -0,0 +1,151 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Optional, Tuple, Union + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.div.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_div_Tensor" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, input, other, rounding_mode) See torch.div() for info + "op_div_rank1_ones": lambda: (torch.ones(5), torch.ones(5), None), + "op_div_rank1_negative_ones": lambda: ( + torch.ones(5) * (-1), + torch.ones(5) * (-1), + None, + ), + "op_div_rank1_rand": lambda: ( + torch.rand(5) * 5, + torch.rand(5) * 5, + None, + ), + "op_div_rank4_ones": lambda: ( + torch.ones(5, 10, 25, 20), + torch.ones(5, 10, 25, 20), + None, + ), + "op_div_rank4_negative_ones": lambda: ( + (-1) * torch.ones(5, 10, 25, 20), + torch.ones(5, 10, 25, 20), + None, + ), + "op_div_rank4_ones_div_negative": lambda: ( + torch.ones(5, 10, 25, 20), + (-1) * torch.ones(5, 10, 25, 20), + None, + ), + "op_div_rank4_large_rand": lambda: ( + 200 * torch.rand(5, 10, 25, 20), + torch.rand(5, 10, 25, 20), + None, + ), + "op_div_rank4_negative_large_rand": lambda: ( + (-200) * torch.rand(5, 10, 25, 20), + torch.rand(5, 10, 25, 20), + None, + ), + "op_div_rank4_large_randn": lambda: ( + 200 * torch.randn(5, 10, 25, 20) + 1, + torch.rand(5, 10, 25, 20) + 1, + None, + ), + "op_div_rank4_randn_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + None, + ), +} + + +class Div(torch.nn.Module): + + def forward( + self, + input_: Union[torch.Tensor, torch.types.Number], + other_: Union[torch.Tensor, torch.types.Number], + rounding_mode: Optional[str] = None, + ): + if rounding_mode is None: + return torch.div(input=input_, other=other_) + else: + return torch.div(input=input_, other=other_, rounding_mode=rounding_mode) + + +@common.parametrize("test_data", test_data_suite) +def test_div_tensor_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1](Div(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_div_tensor_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1](Div(), test_data(), aten_op=[], exir_op=[]) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_div_tensor_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Div(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_div_tensor_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Div(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_div_tensor_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Div(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_div_tensor_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Div(), + test_data(), + aten_op=[], + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div_tensor_mode.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div_tensor_mode.py new file mode 100644 index 0000000..866805a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_div_tensor_mode.py @@ -0,0 +1,151 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_tt = Tuple[torch.Tensor, torch.Tensor] + + +class DivTensorModeFloat(torch.nn.Module): + """ + torch.div(x, y, rounding_mode=mode) with + mode from {None, "floor", "trunc"}. + """ + + aten_ops = ["aten.div.Tensor_mode"] + aten_ops_int = ["aten.mul.Tensor", "aten.reciprocal.default"] + + def __init__(self, mode=None): + super().__init__() + assert mode in (None, "floor", "trunc") + self.mode = mode + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return torch.div(x, y, rounding_mode=self.mode) + + +test_data = { + "mode_none": lambda: (None, (torch.randn(4, 8), torch.randn(4, 8).abs() + 1e-3)), + "mode_floor": lambda: ( + "floor", + (torch.randn(4, 8), torch.randn(4, 8).abs() + 1e-3), + ), + "mode_trunc": lambda: ( + "trunc", + (torch.randn(4, 8), torch.randn(4, 8).abs() + 1e-3), + ), + "int_denominator": lambda: (None, (torch.randn(4, 8), 2)), +} + + +@common.parametrize("data", test_data) +def test_div_tensor_mode_tosa_FP(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = TosaPipelineFP[input_tt]( + model, + inputs, + aten_op=model.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize("data", test_data) +def test_div_tensor_mode_tosa_INT(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = TosaPipelineINT[input_tt]( + model, + inputs, + aten_op=model.aten_ops_int, + exir_op=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize( + "data", test_data, xfails={"mode_trunc": "CPU op missing in unittests"} +) +def test_div_tensor_mode_u55_INT(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = EthosU55PipelineINT[input_tt]( + model, + inputs, + aten_ops=model.aten_ops_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("data", test_data) +def test_div_tensor_mode_u85_INT(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = EthosU85PipelineINT[input_tt]( + model, + inputs, + aten_ops=model.aten_ops_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("data", test_data) +def test_div_tensor_mode_vgf_quant(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = VgfPipeline[input_tt]( + model, + inputs, + aten_op=model.aten_ops_int, + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("data", test_data) +def test_div_tensor_mode_vgf_no_quant(data): + mode, inputs = data() + model = DivTensorModeFloat(mode) + + pipeline = VgfPipeline[input_tt]( + model, + inputs, + aten_op=model.aten_ops, + exir_op=[], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_elu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_elu.py new file mode 100644 index 0000000..c748f83 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_elu.py @@ -0,0 +1,133 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +import torch.nn as nn + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "zeros_default": lambda: (1.0, torch.zeros(1, 10, 10, 10)), + "ones_default": lambda: (1.0, torch.ones(10, 10, 10)), + "rand_default": lambda: (1.0, torch.rand(10, 10) - 0.5), + "randn_pos_default": lambda: (1.0, torch.randn(1, 2, 3, 3) + 10), + "randn_neg_default": lambda: (1.0, torch.randn(2, 4, 3) - 10), + "ramp_default": lambda: (1.0, torch.arange(-16, 16, 0.2)), + "large_pos_default": lambda: (1.0, torch.randn(3, 3) * 1e6 + 1e7), + "large_neg_default": lambda: (1.0, -torch.empty(5).uniform_(1e5, 1e8)), + "small_pos_default": lambda: (1.0, torch.empty(5).uniform_(1e-8, 1e-5)), + "small_neg_default": lambda: (1.0, -torch.empty(5).uniform_(1e-8, 1e-5)), + "zeros_custom": lambda: (2.0, torch.zeros(1, 10, 10, 10)), + "ones_custom": lambda: (2.0, torch.ones(10, 10, 10)), + "rand_custom": lambda: (2.0, torch.rand(10, 10) - 0.5), + "randn_pos_custom": lambda: (2.0, torch.randn(1, 3, 3) + 10), + "randn_neg_custom": lambda: (2.0, torch.randn(1, 2, 4, 3) - 10), + "ramp_custom": lambda: (2.0, torch.arange(-16, 16, 0.2)), + "large_pos_custom": lambda: (2.0, torch.randn(3, 3) * 1e6 + 1e7), + "large_neg_custom": lambda: (2.0, -torch.empty(5).uniform_(1e5, 1e8)), + "small_pos_custom": lambda: (2.0, torch.empty(5).uniform_(1e-8, 1e-5)), + "small_neg_custom": lambda: (2.0, -torch.empty(5).uniform_(1e-8, 1e-5)), + "zeros_zero": lambda: (0.0, torch.zeros(1, 10, 10, 10)), + "ones_zero": lambda: (0.0, torch.ones(10, 10, 10)), + "rand_zero": lambda: (0.0, torch.rand(10, 10) - 0.5), + "randn_pos_zero": lambda: (0.0, torch.randn(1, 3, 3) + 10), + "randn_neg_zero": lambda: (0.0, torch.randn(1, 2, 4, 3) - 10), + "ramp_zero": lambda: (0.0, torch.arange(-16, 16, 0.2)), + "large_pos_zero": lambda: (0.0, torch.randn(3, 3) * 1e6 + 1e7), + "large_neg_zero": lambda: (0.0, -torch.empty(5).uniform_(1e5, 1e8)), + "small_pos_zero": lambda: (0.0, torch.empty(5).uniform_(1e-8, 1e-5)), + "small_neg_zero": lambda: (0.0, -torch.empty(5).uniform_(1e-8, 1e-5)), +} + + +class Elu(nn.Module): + aten_op = "torch.ops.aten.elu.default" + exir_op = "executorch_exir_dialects_edge__ops_aten__elu_default" + + def __init__(self, input_alpha: float = 1.0): + super().__init__() + self.elu = torch.nn.ELU(alpha=input_alpha) + + def forward(self, input_: torch.Tensor): + return self.elu(input_) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_module", test_data_suite) +def test_elu_tosa_FP(test_module: input_t1): + alpha, test_data = test_module() + pipeline = TosaPipelineFP[input_t1]( + Elu(alpha), (test_data,), aten_op=Elu.aten_op, exir_op=Elu.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_elu_tosa_INT(test_module: input_t1): + alpha, test_data = test_module() + pipeline = TosaPipelineINT[input_t1]( + Elu(alpha), (test_data,), aten_op=Elu.aten_op, exir_op=Elu.exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_module", test_data_suite) +def test_elu_u55_INT(test_module: input_t1): + alpha, test_data = test_module() + pipeline = EthosU55PipelineINT[input_t1]( + Elu(alpha), (test_data,), aten_ops=Elu.aten_op, exir_ops=Elu.exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_module", test_data_suite) +def test_elu_u85_INT(test_module: input_t1): + alpha, test_data = test_module() + pipeline = EthosU85PipelineINT[input_t1]( + Elu(alpha), (test_data,), aten_ops=Elu.aten_op, exir_ops=Elu.exir_op + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_elu_vgf_no_quant(test_module: input_t1): + alpha, test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Elu(alpha), + (test_data,), + aten_op=Elu.aten_op, + exir_op=Elu.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_elu_vgf_quant(test_module: input_t1): + alpha, test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Elu(alpha), + (test_data,), + aten_op=Elu.aten_op, + exir_op=Elu.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_embedding.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_embedding.py new file mode 100644 index 0000000..0030373 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_embedding.py @@ -0,0 +1,146 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm._passes import InsertInt32CastsAfterInt64PlaceholdersPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Embedding(torch.nn.Module): + + aten_op = "torch.ops.aten.embedding.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_embedding_default" + + def forward(self, weights: torch.Tensor, indices: torch.Tensor): + return torch.embedding(weights, indices) + + +class ExpandEmbedding(Embedding): + example_inputs = (torch.randn(10, 3), torch.tensor([[1, 2, 3]], dtype=torch.int32)) + + def forward(self, weights: torch.Tensor, indices: torch.Tensor): + return torch.embedding(weights, indices.expand(2, 3)) + + +input_params = Tuple[torch.Tensor, torch.Tensor] + + +test_input: dict[str, input_params] = { + "test_1": ( + torch.randn(10, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32), + ), + "test_2": ( + torch.randn(10, 4), + torch.tensor([[1, 4, 3], [4, 3, 2]], dtype=torch.int32), + ), + "test_3": ( + torch.randn(9, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int64), + ), + "test_4": ( + torch.randn(11, 5), + torch.randint(low=0, high=10, size=(4, 3), dtype=torch.int64), + ), + "test_5": ( + torch.randn(11, 5), + torch.randint(low=0, high=10, size=(4, 3, 2), dtype=torch.int64), + ), + "test_6": ( + torch.randn(11, 5), + torch.randint(low=0, high=10, size=(4, 3, 2, 5), dtype=torch.int64), + ), +} + + +@pytest.mark.skip(reason="MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize("test_input", test_input) +def test_embedding_tosa_FP(test_input: input_params): + op = Embedding() + pipeline = TosaPipelineFP[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + ) + pipeline.run() + + +@common.parametrize("test_input", test_input) +def test_embedding_tosa_INT(test_input: input_params): + op = Embedding() + pipeline = TosaPipelineINT[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + + pipeline.run() + + +def test_embedding_tosa_INT_expand(): + op = ExpandEmbedding() + pipeline = TosaPipelineINT( + op, + ExpandEmbedding.example_inputs, + ExpandEmbedding.aten_op, + ExpandEmbedding.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + + pipeline.run() + + +@pytest.mark.skip("reason=MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize("test_input", test_input) +@common.SkipIfNoModelConverter +def test_embedding_vgf_no_quant(test_input: input_params): + op = Embedding() + pipeline = VgfPipeline[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_input", test_input) +@common.SkipIfNoModelConverter +def test_embedding_vgf_quant(test_input: input_params): + op = Embedding() + pipeline = VgfPipeline[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.pop_stage("check.aten") + pipeline.pop_stage("check_count.exir") + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eq.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eq.py new file mode 100644 index 0000000..c4e7258 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eq.py @@ -0,0 +1,286 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + + +class Equal(torch.nn.Module): + aten_op_Tensor = "torch.ops.aten.eq.Tensor" + aten_op_Scalar = "torch.ops.aten.eq.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_eq_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ == other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_eq_tensor_rank1_ones = Equal( + torch.ones(5), + torch.ones(5), +) +op_eq_tensor_rank2_rand = Equal( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_eq_tensor_rank3_randn = Equal( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_eq_tensor_rank4_randn = Equal( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_eq_scalar_rank1_ones = Equal(torch.ones(5), 1.0) +op_eq_scalar_rank2_rand = Equal(torch.rand(4, 5), 0.2) +op_eq_scalar_rank3_randn = Equal(torch.randn(10, 5, 2), -0.1) +op_eq_scalar_rank4_randn = Equal(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "eq_tensor_rank1_ones": lambda: op_eq_tensor_rank1_ones, + "eq_tensor_rank2_rand": lambda: op_eq_tensor_rank2_rand, + "eq_tensor_rank3_randn": lambda: op_eq_tensor_rank3_randn, + "eq_tensor_rank4_randn": lambda: op_eq_tensor_rank4_randn, +} + +test_data_scalar = { + "eq_scalar_rank1_ones": lambda: op_eq_scalar_rank1_ones, + "eq_scalar_rank2_rand": lambda: op_eq_scalar_rank2_rand, + "eq_scalar_rank3_randn": lambda: op_eq_scalar_rank3_randn, + "eq_scalar_rank4_randn": lambda: op_eq_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_eq_scalar_tosa_FP_tensor(test_module): + pipeline = TosaPipelineFP[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_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Scalar, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_eq_scalar_tosa_INT_tensor(test_module): + pipeline = TosaPipelineINT[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_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_eq_scalar_tosa_INT_tensor_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_eq_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_eq_scalar_u55_INT_tensor(test_module): + # EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Equal.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_eq_scalar_u55_INT(test_module): + # EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Equal.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT_tensor(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT_tensor_16a8w(test_module): + """Test eq operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_eq_scalar_u85_INT_16a8w(test_module): + """Test eq operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_no_quant_tensor(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Scalar, + Equal.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_quant_tensor(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_eq_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Equal.aten_op_Tensor, + Equal.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_erf.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_erf.py new file mode 100644 index 0000000..6ad9f64 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_erf.py @@ -0,0 +1,96 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.erf.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_erf_default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Erf(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.erf(x) + + test_data: dict[str, input_t1] = { + "zeros": lambda: (torch.zeros(1, 10, 10, 10),), + "ones": lambda: (torch.ones(10, 10, 10),), + "rand": lambda: ((torch.rand(10, 10) - 0.5),), + "randn_pos": lambda: ((torch.randn(1, 4, 4, 4) + 10),), + "randn_neg": lambda: ((torch.randn(1, 4, 4, 4) - 10),), + "ramp": lambda: (torch.arange(-16, 16, 0.2),), + } + + +@common.parametrize("test_data", Erf.test_data) +def test_erf_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Erf(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +def test_erf_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Erf(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.XfailIfNoCorstone300 +def test_erf_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.XfailIfNoCorstone320 +def test_erf_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.SkipIfNoModelConverter +def test_erf_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Erf.test_data) +@common.SkipIfNoModelConverter +def test_erf_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Erf(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_exp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_exp.py new file mode 100644 index 0000000..71d5f49 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_exp.py @@ -0,0 +1,110 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(1, 4, 4, 4) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + +aten_op = "torch.ops.aten.exp.default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Exp(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.exp(x) + + +@common.parametrize("test_data", test_data_suite) +def test_exp_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_exp_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_exp_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_exp_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_exp_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_exp_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Exp(), + (test_data(),), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expand.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expand.py new file mode 100644 index 0000000..bddf7b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expand.py @@ -0,0 +1,153 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the expand op which copies the data of the input tensor (possibly with new data format) +# + + +from typing import Sequence, Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.expand.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_expand_copy_default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, Input y + + +class Expand(torch.nn.Module): + # (input tensor, multiples) + base_test_set = { + "rand_1d_both": lambda: (torch.rand(1), (2,)), + "rand_1d": lambda: (torch.randn(1), (2, 2, 4)), + "rand_4d": lambda: (torch.randn(1, 1, 1, 5), (1, 4, -1, -1)), + "rand_batch_1": lambda: (torch.randn(1, 1), (1, 2, 2, 4)), + "rand_batch_2": lambda: (torch.randn(1, 1), (2, 2, 2, 4)), + "rand_mix_neg": lambda: (torch.randn(10, 1, 1, 97), (-1, 4, -1, -1)), + "rand_small_neg": lambda: (torch.rand(1, 1, 2, 2), (4, 3, -1, 2)), + } + + test_u55_reject_set = { + "randbool_1d": lambda: (torch.randint(0, 2, (1,), dtype=torch.bool), (5,)), + } + test_reject_set = { + "rand_2d": lambda: (torch.randn(1, 4), (1, -1)), + "rand_neg_mul": lambda: (torch.randn(1, 1, 192), (1, -1, -1)), + } + test_parameters = base_test_set | test_u55_reject_set + + def forward(self, x: torch.Tensor, m: Sequence): + return x.expand(m) + + +@common.parametrize("test_data", Expand.test_parameters) +def test_expand_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +def test_expand_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize( + "test_data", + Expand.base_test_set, +) +@common.XfailIfNoCorstone300 +def test_expand_u55_INT(test_data: Tuple): + inputs = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + Expand(), + inputs, + aten_op, + exir_ops=[], + ) + if inputs[0].dtype == torch.bool: + pipeline.pop_stage("check_count.exir") + pipeline.tester.use_portable_ops = True + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +@common.XfailIfNoCorstone320 +def test_expand_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Expand(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +@common.SkipIfNoModelConverter +def test_expand_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_parameters) +@common.SkipIfNoModelConverter +def test_expand_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expand(), + test_data(), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_reject_set) +def test_expand_tosa_INT_not_delegated(test_data: Tuple): + pipeline = OpNotSupportedPipeline[input_t1]( + Expand(), test_data(), {exir_op: 1}, n_expected_delegates=0, quantize=True + ) + pipeline.run() + + +@common.parametrize("test_data", Expand.test_u55_reject_set) +def test_expand_u55_INT_not_delegated(test_data: Tuple): + pipeline = OpNotSupportedPipeline[input_t1]( + Expand(), + test_data(), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expm1.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expm1.py new file mode 100644 index 0000000..7556d1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_expm1.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.expm1.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_expm1_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeroes": torch.zeros(1, 10, 10, 10), + "ones": torch.ones(10, 2, 3), + "rand": torch.rand(10, 10) - 0.5, + "near_zero": torch.randn(100) * 0.01, + "taylor_small": torch.empty(5).uniform_( + -0.35, 0.35 + ), # test cases for taylor series expansion + "randn_large_pos": torch.randn(10) + 10, + "randn_large_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Expm1(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.expm1(x) + + +@common.parametrize("test_data", test_data_suite) +def test_expm1_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Expm1(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_expm1_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Expm1(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_expm1_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Expm1(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_expm1_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Expm1(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_expm1_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expm1(), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_expm1_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Expm1(), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eye.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eye.py new file mode 100644 index 0000000..c004b7c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_eye.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class EyeAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.eye.default" + + def __init__(self, n: int, dtype: torch.dtype): + super().__init__() + self.args = (n,) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.eye(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)), + "10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (10, torch.int32), + ), + } + + # Mixed dtypes - the eye op is delegated, but it leads to a non-delegated add op. + test_data_mixed_dtypes: dict[str, test_data_t] = { + "fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)), + "fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)), + } + + +# skip test since int32 isn't support on FP profile +# "int32_int32": "view/RESHAPE of integer tensor is not supported for +FP profile" +@pytest.mark.skip(reason="MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize("test_data", EyeAdd.test_data) +def test_eye_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", EyeAdd.test_data | EyeAdd.test_data_mixed_dtypes) +def test_eye_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", EyeAdd.test_data) +@common.XfailIfNoCorstone300 +def test_eye_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", EyeAdd.test_data) +@common.XfailIfNoCorstone320 +def test_eye_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +# skip since int32 isn't support on FP profile +# "int32_int32": "view/RESHAPE of integer tensor is not supported for +FP profile" +@pytest.mark.skip(reason="MLETORCH-1274 Improve data type checks during partitioning") +@common.parametrize( + "test_data", + EyeAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_eye_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + EyeAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_eye_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + EyeAdd(*init_data), + input_data(), + EyeAdd.aten_op, + quantize=True, + ) + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize( + "test_data", + EyeAdd.test_data_mixed_dtypes, +) +def test_eye_tosa_INT_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + EyeAdd(*init_data), + input_data(), + non_delegated_ops={"executorch_exir_dialects_edge__ops_aten_add_Tensor": 1}, + n_expected_delegates=1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_fill_scalar.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_fill_scalar.py new file mode 100644 index 0000000..5ca209f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_fill_scalar.py @@ -0,0 +1,108 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.fill_.Scalar" +exir_op = "executorch_exir_dialects_edge__ops_aten_full_like_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "ones_float": [torch.ones(2, 3), 5.0], + "ones_int": [torch.ones(2, 3), -3], +} + + +class FillScalar(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, y: torch.Tensor, fill_value: int | float): + mask = torch.full_like(y, 0) + mask.fill_(fill_value) + return mask * y + + +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + FillScalar(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + FillScalar(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + FillScalar(), + (*test_data,), + aten_ops=[aten_op], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_fill_scalar_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + FillScalar(), + (*test_data,), + aten_ops=[aten_op], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_fill_scalar_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FillScalar(), + (*test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_fill_scalar_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FillScalar(), + (*test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor.py new file mode 100644 index 0000000..d308db1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Floor(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.floor(x) + + aten_op = "torch.ops.aten.floor.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_floor_default" + + +zeros = torch.zeros(1, 10, 10, 10) +ones = torch.ones(10, 10, 10) +rand = torch.rand(10, 10) - 0.5 +randn_pos = torch.randn(1, 4, 4, 4) + 10 +randn_neg = torch.randn(1, 4, 4, 4) - 10 +ramp = torch.arange(-16, 16, 0.2) + +test_data = { + "floor_zeros": lambda: (Floor(), zeros), + "floor_ones": lambda: (Floor(), ones), + "floor_rand": lambda: (Floor(), rand), + "floor_randn_pos": lambda: (Floor(), randn_pos), + "floor_randn_neg": lambda: (Floor(), randn_neg), + "floor_ramp": lambda: (Floor(), ramp), +} + + +@common.parametrize("test_data", test_data) +def test_floor_tosa_FP(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +def test_floor_tosa_INT(test_data: input_t1): + module, data = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone300 +def test_floor_u55_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.XfailIfNoCorstone320 +def test_floor_u85_INT(test_data: input_t1): + module, data = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_floor_vgf_no_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data) +@common.SkipIfNoModelConverter +def test_floor_vgf_quant(test_data: input_t1): + module, data = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (data,), + module.aten_op, + module.exir_op, + atol=0.06, + rtol=0.01, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor_div.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor_div.py new file mode 100644 index 0000000..d2b4bc4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_floor_div.py @@ -0,0 +1,156 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple, Union + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, input, other) + "op_floor_div_rank1_ones": lambda: ( + torch.ones(5), + torch.ones(5), + ), + "op_floor_div_rank1_rand": lambda: ( + torch.rand(5) * 5, + torch.rand(5) * 5, + ), + "op_floor_div_rank4_negative_ones": lambda: ( + (-1) * torch.ones(5, 10, 25, 20), + torch.ones(5, 10, 25, 20), + ), + "op_floor_div_rank4_ones_div_negative": lambda: ( + torch.ones(5, 10, 25, 20), + (-1) * torch.ones(5, 10, 25, 20), + ), + "op_floor_div_rank4_randn_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + ), + "op_floor_div_rank4_randn_scalar": lambda: ( + torch.randn(1, 4, 4, 1), + 2, + ), + "op_floor_div_rank4_large_rand": lambda: ( + 200 * torch.rand(5, 10, 25, 20), + torch.rand(5, 10, 25, 20), + ), +} + + +class FloorDivide(torch.nn.Module): + aten_op = "torch.ops.aten.floor_divide.default" + aten_ops_int = ["aten.mul.Tensor", "aten.reciprocal.default", "aten.floor.default"] + exir_op = "executorch_exir_dialects_edge__ops_aten_div_Tensor_mode" + exir_ops_int = [ + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_floor_default", + ] + + def forward( + self, + input_: Union[torch.Tensor, torch.types.Number], + other_: Union[torch.Tensor, torch.types.Number], + ): + return torch.floor_divide(input=input_, other=other_) + + +input_t1 = Tuple[torch.Tensor, Union[torch.Tensor, int]] + + +@common.parametrize("test_data", test_data_suite) +def test_floor_divide_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + FloorDivide(), + test_data(), + FloorDivide.aten_op, + FloorDivide.exir_op, + use_to_edge_transform_and_lower=False, + rtol=0.06, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_floor_divide_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + FloorDivide(), + test_data(), + aten_op=FloorDivide.aten_ops_int, + exir_op=FloorDivide.exir_ops_int, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_floor_divide_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + FloorDivide(), + test_data(), + aten_ops=FloorDivide.aten_ops_int, + exir_ops=[], + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.pop_stage("check_not.exir") + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_floor_divide_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + FloorDivide(), + test_data(), + aten_ops=FloorDivide.aten_ops_int, + exir_ops=FloorDivide.exir_ops_int, + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_floor_divide_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FloorDivide(), + test_data(), + FloorDivide.aten_op, + FloorDivide.exir_op, + use_to_edge_transform_and_lower=False, + rtol=0.06, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_floor_divide_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + FloorDivide(), + test_data(), + aten_op=FloorDivide.aten_ops_int, + exir_op=FloorDivide.exir_ops_int, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_full.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_full.py new file mode 100644 index 0000000..9ee607e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_full.py @@ -0,0 +1,255 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the full op which creates a tensor of a given shape filled with a given value. +# The shape and value are set at compile time, i.e. can't be set by a tensor input. +# + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, int] + +exir_op = "executorch_exir_dialects_edge__ops_aten_full_default" + + +class Full(torch.nn.Module): + # A single full op + def forward(self): + return torch.full((3, 3), 4.5) + + +class AddConstFull(torch.nn.Module): + # Input + a full with constant value. + def forward(self, x: torch.Tensor): + return torch.full((2, 2, 3, 3), 4.5, dtype=torch.float32) + x + + +class AddVariableFull(torch.nn.Module): + sizes: list[tuple[int, ...]] = [ + (5,), + (5, 5), + (5, 5, 5), + (1, 5, 5, 5), + ] + test_parameters = {} + for i, n in enumerate(sizes): + test_parameters[f"slice_randn_{i}"] = (torch.randn(n) * 10 - 5, 3.2) + + def forward(self, x: torch.Tensor, y): + # Input + a full with the shape from the input and a given value 'y'. + return x + torch.full(x.shape, y) + + +class FullLike(torch.nn.Module): + """Since full_like is replaced with full, we only need to test on reference model, not FVP.""" + + test_parameters = { + "full_like_value_3_2": lambda: (torch.randn(2, 2, 2, 2) * 50, 3.2), + "full_like_value_3": lambda: (torch.randn(2, 2, 2, 2) * 50, 3), + "full_like_value_3_2_int32": lambda: ( + (torch.randn(2, 2, 2, 2) * 50).to(torch.int32), + 3.2, + ), + "full_like_value_3_int32": lambda: ( + (torch.randn(2, 2, 2, 2) * 50).to(torch.int32), + 3, + ), + } + + def forward(self, input_tensor: torch.Tensor, value): + # Our backend can't handle tensors without users, which input_tensor doesn't have + # when the full_like is converted to a full. Therefore involve it in the output. + return input_tensor + torch.full_like(input_tensor, value) + + +def test_full_tosa_FP_only(): + pipeline = TosaPipelineFP[input_t1]( + Full(), + (), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +def test_full_tosa_FP_const(): + test_data = (torch.rand((2, 2, 3, 3)) * 10,) + pipeline = TosaPipelineFP[input_t1]( + AddConstFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", FullLike.test_parameters) +def test_full_like_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + FullLike(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", FullLike.test_parameters) +def test_full_like_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + FullLike(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +def test_full_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +def test_full_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_full_vgf_no_quant_only(): + pipeline = VgfPipeline[input_t1]( + Full(), + (), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_full_vgf_no_quant_const(): + test_data = (torch.rand((2, 2, 3, 3)) * 10,) + pipeline = VgfPipeline[input_t1]( + AddConstFull(), + test_data, + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.SkipIfNoModelConverter +def test_full_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.SkipIfNoModelConverter +def test_full_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.XfailIfNoCorstone320 +def test_full_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + AddVariableFull(), + test_data, + aten_ops=[], + exir_ops=exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", AddVariableFull.test_parameters) +@common.XfailIfNoCorstone300 +def test_full_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + AddVariableFull(), + test_data, + aten_ops=[], + exir_ops=exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +# This fails since full outputs int64 by default if 'fill_value' is integer, which our backend doesn't support. +@pytest.mark.skip( + "This fails since full outputs int64 by default if 'fill_value' is integer, which our backend doesn't support." +) +def test_full_tosa_FP_integer_value(): + test_data = (torch.ones((2, 2)), 1.0) + pipeline = TosaPipelineFP[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +# This fails since the fill value in the full tensor is set at compile time by the example data (1.). +# Test data tries to set it again at runtime (to 2.) but it doesn't do anything. +# In eager mode, the fill value can be set at runtime, causing the outputs to not match. +@pytest.mark.skip( + "This fails since the fill value in the full tensor is set at compile time by the example data (1.)." +) +def test_full_tosa_FP_set_value_at_runtime(tosa_version: str): + test_data = (torch.ones((2, 2)), 1.0) + pipeline = TosaPipelineFP[input_t1]( + AddVariableFull(), + test_data, + aten_op=[], + exir_op=exir_op, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.add_stage( + pipeline.tester.run_method_and_compare_outputs, inputs=(torch.ones((2, 2)), 2.0) + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ge.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ge.py new file mode 100644 index 0000000..4674806 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ge.py @@ -0,0 +1,292 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + + +class GreaterEqual(torch.nn.Module): + aten_op_tensor = "torch.ops.aten.ge.Tensor" + aten_op_scalar = "torch.ops.aten.ge.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_ge_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ >= other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_ge_tensor_rank1_ones = GreaterEqual( + torch.ones(5), + torch.ones(5), +) +op_ge_tensor_rank2_rand = GreaterEqual( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_ge_tensor_rank3_randn = GreaterEqual( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_ge_tensor_rank4_randn = GreaterEqual( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_ge_scalar_rank1_ones = GreaterEqual(torch.ones(5), 1.0) +op_ge_scalar_rank2_rand = GreaterEqual(torch.rand(4, 5), 0.2) +op_ge_scalar_rank3_randn = GreaterEqual(torch.randn(10, 5, 2), -0.1) +op_ge_scalar_rank4_randn = GreaterEqual(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "ge_tensor_rank1_ones": lambda: op_ge_tensor_rank1_ones, + "ge_tensor_rank2_rand": lambda: op_ge_tensor_rank2_rand, + "ge_tensor_rank3_randn": lambda: op_ge_tensor_rank3_randn, + "ge_tensor_rank4_randn": lambda: op_ge_tensor_rank4_randn, +} + +test_data_scalar = { + "ge_scalar_rank1_ones": lambda: op_ge_scalar_rank1_ones, + "ge_scalar_rank2_rand": lambda: op_ge_scalar_rank2_rand, + "ge_scalar_rank3_randn": lambda: op_ge_scalar_rank3_randn, + "ge_scalar_rank4_randn": lambda: op_ge_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_ge_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ge_scalar_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_scalar, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_ge_tensor_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ge_scalar_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_ge_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ge_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_ge_tensor_u55_INT(test_module): + # GREATER_EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {GreaterEqual.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_ge_scalar_u55_INT(test_module): + # GREATER_EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {GreaterEqual.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_ge_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_ge_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_ge_tensor_16a8w_u85_INT(test_module): + """Test ge operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_ge_scalar_16a8w_u85_INT(test_module): + """Test ge operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ge_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ge_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ge_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_scalar, + GreaterEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ge_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + GreaterEqual.aten_op_tensor, + GreaterEqual.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gelu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gelu.py new file mode 100644 index 0000000..0936aa1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gelu.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Gelu(torch.nn.Module): + aten_op = "torch.ops.aten.gelu.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_gelu_default" + + test_data: dict[str, Tuple[str, input_t1]] = { + "zeros_none": lambda: ( + "none", + torch.zeros(1, 10, 10, 10), + ), + "ones_none": lambda: ( + "none", + torch.ones(10, 10, 10), + ), + "rand_none": lambda: ( + "none", + (torch.rand(10, 10) - 0.5), + ), + "randn_pos_none": lambda: ( + "none", + (torch.randn(1, 4, 4, 4) + 10), + ), + "randn_neg_none": lambda: ( + "none", + (torch.randn(1, 4, 4, 4) - 10), + ), + "ramp_none": lambda: ( + "none", + torch.arange(-16, 16, 0.2), + ), + "zeros_tanh": lambda: ( + "tanh", + torch.zeros(1, 10, 10, 10), + ), + "ones_tanh": lambda: ( + "tanh", + torch.ones(10, 10, 10), + ), + "rand_tanh": lambda: ( + "tanh", + (torch.rand(10, 10) - 0.5), + ), + "randn_pos_tanh": lambda: ( + "tanh", + (torch.randn(1, 4, 4, 4) + 10), + ), + "randn_neg_tanh": lambda: ( + "tanh", + (torch.randn(1, 4, 4, 4) - 10), + ), + "ramp_tanh": lambda: ( + "tanh", + torch.arange(-16, 16, 0.2), + ), + } + + def __init__(self, approximate: str = "none"): + super().__init__() + self.gelu = torch.nn.GELU(approximate) + + def forward(self, x: torch.Tensor): + return self.gelu(x) + + +@common.parametrize("test_data", Gelu.test_data) +def test_gelu_tosa_FP(test_data: input_t1): + approximate, test_data = test_data() + TosaPipelineFP[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + use_to_edge_transform_and_lower=False, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +def test_gelu_tosa_INT(test_data: input_t1): + approximate, test_data = test_data() + TosaPipelineINT[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.XfailIfNoCorstone300 +def test_gelu_u55_INT(test_data: input_t1): + approximate, test_data = test_data() + EthosU55PipelineINT[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.XfailIfNoCorstone320 +def test_gelu_u85_INT(test_data: input_t1): + approximate, test_data = test_data() + EthosU85PipelineINT[input_t1]( + Gelu(approximate), + (test_data,), + Gelu.aten_op, + Gelu.exir_op, + ).run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.SkipIfNoModelConverter +def test_gelu_vgf_no_quant(test_data: input_t1): + approximate, data = test_data() + pipeline = VgfPipeline[input_t1]( + Gelu(approximate), + (data,), + Gelu.aten_op, + Gelu.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Gelu.test_data) +@common.SkipIfNoModelConverter +def test_gelu_vgf_quant(test_data: input_t1): + approximate, data = test_data() + pipeline = VgfPipeline[input_t1]( + Gelu(approximate), + (data,), + Gelu.aten_op, + Gelu.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_glu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_glu.py new file mode 100644 index 0000000..c7426c0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_glu.py @@ -0,0 +1,130 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +import torch.nn.functional as F +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.glu.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__glu_default" + + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": [torch.zeros(10, 10, 2), -1], + "ones": [torch.ones(10, 10, 2), -1], + "rand": [torch.rand(10, 10, 2) - 0.5, -1], + "randn_pos": [torch.randn(10, 2) + 10, -1], + "randn_neg": [torch.randn(10, 2) - 10, -1], + "ramp": [torch.linspace(-16, 15.8, 160).reshape(-1, 2), -1], + "zeros_custom_dim": [torch.zeros(7, 10, 5), 1], + "rand_custom_dim": [torch.rand(10, 3, 3) - 0.5, 0], +} + + +class Glu(torch.nn.Module): + + def forward(self, a: torch.Tensor, dim: int) -> torch.Tensor: + return F.glu(a, dim=dim) + + +@common.parametrize( + "test_data", + test_data_suite, +) +def test_glu_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Glu(), + (*test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +def test_glu_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Glu(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.XfailIfNoCorstone300 +def test_glu_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Glu(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.XfailIfNoCorstone320 +def test_glu_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Glu(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_glu_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Glu(), + (*test_data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_glu_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Glu(), + (*test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_group_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_group_norm.py new file mode 100644 index 0000000..d80b94c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_group_norm.py @@ -0,0 +1,200 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class GroupNorm(torch.nn.Module): + + def __init__( + self, + num_groups: int, + num_channels: int, + eps: float = 1e-5, + affine: bool = True, + ): + super().__init__() + self.group_norm = torch.nn.GroupNorm( + num_groups, + num_channels, + eps=eps, + affine=affine, + ) + + def forward( + self, + x: torch.Tensor, + ): + return self.group_norm(x) + + +input_t = tuple[torch.Tensor] +test_data_suite = { + "rand_4_6_groups_1": ((torch.rand(4, 6),), GroupNorm(1, 6)), + "rand_4_6_groups_2": ((torch.rand(4, 6),), GroupNorm(2, 6)), + "rand_4_6_groups_6": ((torch.rand(4, 6),), GroupNorm(6, 6)), + "rand_4_6_8_groups_2_eps_no_affine": ( + (torch.rand(4, 6, 8),), + GroupNorm(2, 6, eps=1e-3, affine=False), + ), + "randn_1_12_8_6_groups_6_eps": ( + (torch.randn(1, 12, 8, 6),), + GroupNorm(6, 12, eps=1e-2), + ), + "randn_1_12_8_6_groups_12": ((torch.randn(1, 12, 8, 6),), GroupNorm(12, 12)), + "rand_6_8_10_12_groups_1": ((torch.rand(6, 8, 10, 12),), GroupNorm(1, 8)), + "rand_6_8_10_12_groups_4_no_affine": ( + (torch.rand(6, 8, 10, 12),), + GroupNorm(4, 8, affine=False), + ), + "rand_6_8_10_12_groups_8": ((torch.rand(6, 8, 10, 12),), GroupNorm(8, 8)), +} + + +@common.parametrize("test_data", test_data_suite) +def test_native_group_norm_tosa_FP(test_data): + aten_op = "torch.ops.aten.group_norm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + pipeline = TosaPipelineFP[input_t]( + test_data[1], + test_data[0], + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + }, + strict=False, +) +def test_native_group_norm_tosa_INT(test_data): + aten_op = "torch.ops.aten.sub.Tensor" # 'sub' op arbitrarily chosen to confirm groupnorm was decomposed + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + pipeline = TosaPipelineINT[input_t]( + test_data[1], + test_data[0], + aten_op=aten_op, + exir_op=exir_op, + atol=0.1, # TODO: "MLETORCH-925: Fix numerical issue for aten.native_group_norm" + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "rand_4_6_8_groups_2_eps_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_4_6_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_4_6_groups_2": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + }, + strict=False, +) +@common.XfailIfNoCorstone300 +def test_native_group_norm_u55_INT(test_data): + pipeline = EthosU55PipelineINT[input_t]( + test_data[1], + test_data[0], + "torch.ops.aten.sub.Tensor", # 'sub' op arbitrarily chosen to confirm groupnorm was decomposed + atol=0.1, # TODO: "MLETORCH-925: Fix numerical issue for aten.native_group_norm" + ) + pipeline.change_args("run_method_and_compare_outputs", atol=1, qtol=1) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue for aten.native_group_norm", + }, + strict=False, +) +@common.XfailIfNoCorstone320 +def test_native_group_norm_u85_INT(test_data): + pipeline = EthosU85PipelineINT[input_t]( + test_data[1], + test_data[0], + "torch.ops.aten.sub.Tensor", # 'sub' op arbitrarily chosen to confirm groupnorm was decomposed + atol=0.1, # TODO: "MLETORCH-925: Fix numerical issue for aten.native_group_norm" + ) + pipeline.change_args("run_method_and_compare_outputs", atol=1, qtol=1) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue", + }, + strict=False, +) +@common.SkipIfNoModelConverter +def test_native_group_norm_vgf_no_quant(test_data): + aten_op = "torch.ops.aten.group_norm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + model, inp = test_data + pipeline = VgfPipeline[input_t]( + inp, + model, + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, + xfails={ + "randn_1_12_8_6_groups_12": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_1": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_4_no_affine": "MLETORCH-925: Fix numerical issue", + "rand_6_8_10_12_groups_8": "MLETORCH-925: Fix numerical issue", + }, + strict=False, +) +@common.SkipIfNoModelConverter +def test_native_group_norm_vgf_quant(test_data): + aten_op = "torch.ops.aten.sub.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_native_group_norm_default" + model, inp = test_data + pipeline = VgfPipeline[input_t]( + inp, + model, + aten_op=aten_op, + exir_op=exir_op, + atol=0.1, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gt.py new file mode 100644 index 0000000..1fd1ec8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_gt.py @@ -0,0 +1,293 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +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 + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ > other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_gt_tensor_rank1_ones = Greater( + torch.ones(5), + torch.ones(5), +) +op_gt_tensor_rank2_rand = Greater( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_gt_tensor_rank3_randn = Greater( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_gt_tensor_rank4_randn = Greater( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +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": lambda: op_gt_tensor_rank1_ones, + "gt_tensor_rank2_rand": lambda: op_gt_tensor_rank2_rand, + "gt_tensor_rank3_randn": lambda: op_gt_tensor_rank3_randn, + "gt_tensor_rank4_randn": lambda: op_gt_tensor_rank4_randn, +} + +test_data_scalar = { + "gt_scalar_rank1_ones": lambda: op_gt_scalar_rank1_ones, + "gt_scalar_rank2_rand": lambda: op_gt_scalar_rank2_rand, + "gt_scalar_rank3_randn": lambda: op_gt_scalar_rank3_randn, + "gt_scalar_rank4_randn": lambda: op_gt_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_gt_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[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_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + 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_INT(test_module): + pipeline = TosaPipelineINT[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_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_gt_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_gt_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_gt_tensor_u55_INT(test_module): + # Greater is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Greater.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_gt_scalar_u55_INT(test_module): + # Greater is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {Greater.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_gt_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_gt_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_gt_tensor_16a8w_u85_INT(test_module): + """Test gt operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_gt_scalar_16a8w_u85_INT(test_module): + """Test gt operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_gt_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_gt_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_scalar, + Greater.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_gt_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_gt_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + Greater.aten_op_tensor, + Greater.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardsigmoid.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardsigmoid.py new file mode 100644 index 0000000..eb10e5a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardsigmoid.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.hardsigmoid.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Hardsigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.hardsigmoid = torch.nn.Hardsigmoid() + + def forward(self, x): + return self.hardsigmoid(x) + + +@common.parametrize("test_data", test_data_suite) +def test_hardsigmoid_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_hardsigmoid_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_hardsigmoid_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_hardsigmoid_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardsigmoid_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardsigmoid_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Hardsigmoid(), + (test_data(),), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardswish.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardswish.py new file mode 100644 index 0000000..68cd249 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardswish.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.hardswish.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_clamp_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: (torch.zeros(1, 10, 10, 10)), + "ones": lambda: (torch.ones(10, 10, 10)), + "rand": lambda: (torch.rand(10, 10) - 0.5), + "randn_pos": lambda: (torch.randn(10) + 10), + "randn_neg": lambda: (torch.randn(10) - 10), + "ramp": lambda: (torch.arange(-16, 16, 0.2)), +} + + +class Hardswish(torch.nn.Module): + def __init__(self): + super().__init__() + self.hardswish = torch.nn.Hardswish() + + def forward(self, x): + return self.hardswish(x) + + +@common.parametrize("test_data", test_data_suite) +def test_hardswish_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t1](Hardswish(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_hardswish_tosa_INT(test_data): + pipeline = TosaPipelineINT[input_t1](Hardswish(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_hardswish_u55_INT(test_data): + EthosU55PipelineINT[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_hardswish_u85_INT(test_data): + EthosU85PipelineINT[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardswish_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardswish_vgf_quant(test_data): + pipeline = VgfPipeline[input_t1]( + Hardswish(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardtanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardtanh.py new file mode 100644 index 0000000..a13e70d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_hardtanh.py @@ -0,0 +1,113 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: (torch.zeros(1, 10, 10, 10)), + "ones": lambda: (torch.ones(10, 10, 10)), + "rand": lambda: (torch.rand(10, 10) - 0.5), + "randn_pos": lambda: (torch.randn(10) + 10), + "randn_neg": lambda: (torch.randn(10) - 10), + "ramp": lambda: (torch.arange(-16, 16, 0.2)), +} + +aten_op = "torch.ops.aten.hardtanh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_hardtanh_default" + +input_t = Tuple[torch.Tensor] + + +class HardTanh(torch.nn.Module): + + def __init__(self): + super().__init__() + + self.hardTanh = torch.nn.Hardtanh() + + def forward(self, x): + return self.hardTanh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_hardtanh_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t](HardTanh(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_hardtanh_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_hardtanh_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_hardtanh_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardtanh_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_hardtanh_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t]( + HardTanh(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_select.py new file mode 100644 index 0000000..239c27a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_select.py @@ -0,0 +1,177 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class IndexSelect(torch.nn.Module): + aten_op = "torch.ops.aten.index_select.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_index_select_default" + + def forward(self, input_: torch.Tensor, dim, index_: torch.Tensor): + return torch.index_select(input_, dim=dim, index=index_) + + +input_params = Tuple[torch.Tensor, int, torch.Tensor] + + +test_input: dict[input_params] = { + "test_1": ( + torch.tensor( + [[[0.1, 0.2, 0.3], [1.1, 1.2, 1.3], [2.1, 2.2, 2.3], [3.1, 3.2, 3.3]]], + dtype=torch.float32, + ), # Shape: [N=1, K=4, C=3] + 1, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), + "test_2": ( + torch.tensor( + [[0.1, 0.2, 0.3], [1.1, 1.2, 1.3], [2.1, 2.2, 2.3], [3.1, 3.2, 3.3]], + dtype=torch.float32, + ), # Shape: [K=4, C=3] + 0, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), + "test_3_mult_batches": ( + torch.randn(2, 4, 3), # Batches > 1 not supported + 1, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), + "test_4_rand": ( + torch.randn(1, 4, 3), + 1, + torch.tensor( + [1, 3], dtype=torch.int32 + ), # Shape: [2] => Note TOSA requires [N=1, W=2] + ), +} + + +test_data = { + "index_select_test_1": (IndexSelect(), test_input["test_1"]), + "index_select_test_2": (IndexSelect(), test_input["test_2"]), + "index_select_test_3": pytest.param( + (IndexSelect(), test_input["test_3_mult_batches"]), + marks=pytest.mark.xfail( + reason="Rank3 weights with first dim larger than 1 is currently not supported" + ), + ), + "index_select_test_4": (IndexSelect(), test_input["test_4_rand"]), +} + + +@pytest.mark.parametrize("test_data", list(test_data.values())) +def test_index_select_tosa_FP(test_data: input_params): + op, test_input = test_data + pipeline = TosaPipelineFP[input_params]( + op, test_input, op.aten_op, op.exir_op, use_to_edge_transform_and_lower=True + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[:-1]) +def test_index_select_tosa_INT(test_data: input_params): + op, test_input = test_data + + pipeline = TosaPipelineINT[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[-1:]) +def test_index_select_tosa_INT_rand(test_data: input_params): + op, test_input = test_data + + pipeline = TosaPipelineINT[input_params]( + op, + test_input, + op.aten_op, + op.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.change_args( + "run_method_and_compare_outputs", inputs=test_input, atol=0.9, rtol=0.2, qtol=1 + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[-1:]) +def test_index_select_u55_INT_not_delegated(test_data: input_params): + op, test_input = test_data + + pipeline = OpNotSupportedPipeline[input_params]( + op, + test_input, + {op.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())) +@common.SkipIfNoModelConverter +def test_index_select_vgf_no_quant(test_data: input_params): + op, inp = test_data + pipeline = VgfPipeline[input_params]( + op, + inp, + op.aten_op, + op.exir_op, + quantize=False, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[:-1]) +@common.SkipIfNoModelConverter +def test_index_select_vgf_quant(test_data: input_params): + op, inp = test_data + pipeline = VgfPipeline[input_params]( + op, + inp, + op.aten_op, + op.exir_op, + quantize=True, + ) + pipeline.run() + + +@pytest.mark.parametrize("test_data", list(test_data.values())[-1:]) +@common.SkipIfNoModelConverter +def test_index_select_vgf_quant_rand(test_data: input_params): + op, inp = test_data + pipeline = VgfPipeline[input_params]( + op, + inp, + op.aten_op, + op.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_tensor.py new file mode 100644 index 0000000..bc19634 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_index_tensor.py @@ -0,0 +1,467 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, +) + + +class IndexTensorTestCommon: + """Class containing constants common between the tests""" + + aten_op = "torch.ops.aten.index.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_index_Tensor" + + # Gathers and reshapes should result in no inaccuracies + rtol = 0.0 + atol = 0.0 + BEFORE = "BEFORE" + MIDDLE = "MIDDLE" + AFTER = "AFTER" + + +input_params_slice = Tuple[torch.Tensor, int, int, str, Tuple[torch.Tensor]] +input_params = Tuple[torch.Tensor, Tuple[torch.Tensor]] + + +class IndexTensor_Ellipsis(torch.nn.Module): + """ + There are technical limitations with torch/export as it does not support + the ellipsis class and as such the forward function has been crafted + to circumvent that limitation. + """ + + # xfail - ellipsis unsupported + test_data_ellipsis: dict[input_params] = { + "test_4d_ellipsis_before": ( + torch.rand(size=(25, 5, 13, 7)), + IndexTensorTestCommon.BEFORE, + (torch.arange(2, dtype=torch.int32),), + ), + "test_4d_ellipsis_middle": ( + torch.rand(size=(25, 5, 13, 7)), + IndexTensorTestCommon.MIDDLE, + ( + torch.arange(2, dtype=torch.int32), + torch.arange(2, dtype=torch.int32), + ), + ), + "test_4d_ellipsis_after": ( + # Due to the information passed to the NodeVisitor and + # preceding passes, detecting this and rejecting it for + # partitioning is difficult and unreliable, as such + # it is not xfail as the existing logic can handle it. + torch.rand(size=(25, 5, 13, 7)), + IndexTensorTestCommon.AFTER, + (torch.arange(2, dtype=torch.int32),), + ), + } + + def forward( + self, + input_: torch.Tensor, + position: str, + indices: Tuple[None | torch.Tensor], + ): + match position: + case IndexTensorTestCommon.BEFORE: + return input_[..., indices[0]] + case IndexTensorTestCommon.MIDDLE: + return input_[indices[0], ..., indices[1]] + case IndexTensorTestCommon.AFTER: + return input_[indices[0], ...] + + return input_[indices] + + +@common.parametrize( + "test_data", + IndexTensor_Ellipsis.test_data_ellipsis, + xfails={ + # More info in index_tensor_support.py + "test_4d_ellipsis_before": "Ellipsis before index unsupported", + "test_4d_ellipsis_middle": "Ellipsis before index unsupported", + }, +) +def test_index_tensor_tosa_FP_ellipsis(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params]( + IndexTensor_Ellipsis(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor_Ellipsis.test_data_ellipsis, + xfails={ + # More info in index_tensor_support.py + "test_4d_ellipsis_before": "Ellipsis before index unsupported", + "test_4d_ellipsis_middle": "Ellipsis before index unsupported", + }, +) +def test_index_tensor_tosa_INT_ellipsis(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params]( + IndexTensor_Ellipsis(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +class IndexTensor_Slice(torch.nn.Module): + """ + There are technical limitations with Dynamo as it does not support the + slice class and as such the forward function has been crafted + to circumvent that limitation. + """ + + # xfail - None unsupported + test_data: dict[input_params_slice] = { + "test_4d_slice_before_1d_idx": ( + # Value tens is 3D because with the + torch.rand(size=(5, 3, 4, 5)), + 0, + 2, + IndexTensorTestCommon.BEFORE, + (torch.arange(2, dtype=torch.int32),), + ), + "test_3d_slice_before_2d_idx": ( + # TODO: MLETORCH-859 - Testing framework does not support output rank > 4 + # With the bellow configuration a 4D value tensor and 2D index tensor + # results in a 5D output. + torch.arange(5 * 3 * 4, dtype=torch.float32).reshape(5, 3, 4), + 0, + 2, + IndexTensorTestCommon.BEFORE, + (torch.arange(2, dtype=torch.int32).unsqueeze(0).tile(2, 1),), + ), + "test_4d_slice_middle": ( + torch.arange(5 * 3 * 2, dtype=torch.int32).reshape(5, 3, 2), + 0, + 2, + IndexTensorTestCommon.MIDDLE, + ( + torch.arange(2, dtype=torch.int32), + torch.arange(2, dtype=torch.int32), + ), + ), + "test_4d_slice_after": ( + # Due to the information passed to the NodeVisitor and + # preceding passes, detecting this and rejecting it for + # partitioning is difficult and unreliable, as such + # it is not xfail as the existing logic can handle it. + torch.rand(size=(25, 5, 13, 7)), + 0, + 2, + IndexTensorTestCommon.AFTER, + (torch.arange(2, dtype=torch.int32),), + ), + } + + def forward( + self, + input_: torch.Tensor, + slice_start: int, + slice_end: int, + position: str, + indices: Tuple[None | torch.Tensor], + ): + match position: + case IndexTensorTestCommon.BEFORE: + return input_[slice_start:slice_end, indices[0]] + case IndexTensorTestCommon.MIDDLE: + return input_[indices[0], slice_start:slice_end, indices[1]] + case IndexTensorTestCommon.AFTER: + return input_[indices[0], slice_start:slice_end] + + +@common.parametrize( + "test_data", + IndexTensor_Slice.test_data, + xfails={ + # More info in index_tensor_support.py + "test_4d_slice_before_1d_idx": "Slice before index unsupported", + "test_3d_slice_before_2d_idx": "Slice before index unsupported", + "test_4d_slice_middle": "Slice before index unsupported", + }, +) +def test_index_tensor_tosa_FP_slice(test_data: input_params_slice): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params_slice]( + IndexTensor_Slice(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor_Slice.test_data, + xfails={ + # More info in index_tensor_support.py + "test_4d_slice_before_1d_idx": "Slice before index unsupported", + "test_3d_slice_before_2d_idx": "Slice before index unsupported", + "test_4d_slice_middle": "Slice before index unsupported", + }, +) +def test_index_tensor_tosa_INT_slice(test_data: input_params_slice): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params_slice]( + IndexTensor_Slice(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +class IndexTensor(torch.nn.Module): + test_data: dict[input_params] = { + "test_2d_1_idx": (torch.rand(5, 2), (torch.arange(5, dtype=torch.int32),)), + "test_2d_1_less_than_max_idx": ( + torch.rand(5, 2), + (torch.arange(3, dtype=torch.int32),), + ), + "test_2d_1_2d_idx": ( + torch.rand(5, 2), + (torch.randint(5, size=(4, 3), dtype=torch.int32)), + ), + "test_2d_2_idx": ( + torch.rand(5, 2), + ( + torch.randint(5, size=(5,), dtype=torch.int32), + torch.randint(2, size=(5,), dtype=torch.int32), + ), + ), + "test_2d_2_2d_idx_broadcastable": ( + torch.rand(5, 2), + ( + torch.randint(5, size=(5, 3), dtype=torch.int32), + torch.randint(2, size=(1, 3), dtype=torch.int32), + ), + ), + "test_2d_2_2d_idx_broadcastable_2": ( + torch.rand(5, 2), + ( + torch.randint(5, size=(5, 1), dtype=torch.int32), + torch.randint(2, size=(3,), dtype=torch.int32), + ), + ), + "test_3d_1_idx": (torch.rand(12, 3, 7), (torch.arange(12, dtype=torch.int32),)), + "test_3d_2_idx": ( + torch.rand(12, 3, 7), + ( + torch.arange(12, dtype=torch.int32), + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + "test_3d_3_idx": ( + torch.rand(12, 3, 7), + ( + torch.arange(12, dtype=torch.int32), + torch.randint(3, size=(12,), dtype=torch.int32), + torch.randint(7, size=(12,), dtype=torch.int32), + ), + ), + "test_4d_1_idx": ( + torch.rand(15, 3, 7, 2), + (torch.arange(15, dtype=torch.int32),), + ), + "test_4d_2_idx": ( + torch.rand(15, 3, 7, 2), + ( + torch.randint(15, size=(15,), dtype=torch.int32), + torch.randint(3, size=(1,), dtype=torch.int32), + ), + ), + "test_4d_3_idx": ( + torch.rand(15, 3, 7, 2), + ( + torch.arange(15, dtype=torch.int32), + torch.randint(3, size=(15,), dtype=torch.int32), + torch.randint(7, size=(15,), dtype=torch.int32), + ), + ), + "test_4d_4_id_broadcastable": ( + torch.rand(15, 3, 7, 2), + ( + torch.arange(15, dtype=torch.int32), + torch.randint(3, size=(3, 1), dtype=torch.int32), + torch.randint(6, size=(6, 1, 1), dtype=torch.int32), + torch.randint(2, size=(15,), dtype=torch.int32), + ), + ), + } + + # xfail - None (unsqueeze) unsupported + test_data_none: dict[input_params] = { + "test_3d_3_idx_with_none_before": ( + torch.rand(12, 3, 7), + ( + None, + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + "test_3d_3_idx_with_2_none_before": ( + torch.rand(12, 3, 7), + ( + None, + None, + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + "test_3d_3_idx_with_none_around": ( + torch.rand(12, 3, 7), + ( + None, + torch.randint(3, size=(12,), dtype=torch.int32), + None, + ), + ), + "test_3d_3_idx_with_none_after": ( + # Due to the information passed to the NodeVisitor and + # preceding passes, detecting this and rejecting it for + # partitioning is difficult and unreliable, as such + # it is not xfail as the existing logic can handle it. + torch.rand(12, 3, 7), + ( + torch.randint(3, size=(12,), dtype=torch.int32), + None, + ), + ), + "test_3d_3_idx_with_none_middle": ( + torch.rand(12, 3, 7), + ( + torch.randint(3, size=(12,), dtype=torch.int32), + None, + torch.randint(3, size=(12,), dtype=torch.int32), + ), + ), + } + + def forward(self, input_: torch.Tensor, indices: Tuple[None | torch.Tensor]): + return input_[indices] + + +@common.parametrize("test_data", IndexTensor.test_data) +def test_index_tensor_tosa_FP(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize("test_data", IndexTensor.test_data) +def test_index_tensor_tosa_INT(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor.test_data_none, + xfails={ + # More info in index_tensor_support.py + "test_3d_3_idx_with_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_2_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_around": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_middle": "None (Unsqueeze) unsupported", + }, +) +def test_index_tensor_tosa_FP_none(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineFP[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + atol=IndexTensorTestCommon.atol, + rtol=IndexTensorTestCommon.rtol, + ).run() + ) + + +@common.parametrize( + "test_data", + IndexTensor.test_data_none, + xfails={ + # More info in index_tensor_support.py + "test_3d_3_idx_with_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_2_none_before": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_around": "None (Unsqueeze) unsupported", + "test_3d_3_idx_with_none_middle": "None (Unsqueeze) unsupported", + }, +) +def test_index_tensor_tosa_INT_none(test_data: input_params): + test_input = test_data + with torch.no_grad(): + ( + TosaPipelineINT[input_params]( + IndexTensor(), + test_input, + IndexTensorTestCommon.aten_op, + IndexTensorTestCommon.exir_op, + ).run() + ) + + +@common.parametrize("test_data", IndexTensor.test_data) +@common.XfailIfNoCorstone300 +def test_index_tensor_u55_INT_not_delegated(test_data: input_params): + """Ethos-U55 backend BI pipeline test for index.Tensor""" + test_input = test_data + with torch.no_grad(): + OpNotSupportedPipeline[input_params]( + IndexTensor(), + test_input, + {IndexTensorTestCommon.exir_op: 1}, + quantize=True, + u55_subset=True, + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_layer_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_layer_norm.py new file mode 100644 index 0000000..232fa0c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_layer_norm.py @@ -0,0 +1,186 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List, Union + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class LayerNorm(torch.nn.Module): + + def __init__( + self, + normalized_shape: Union[int, List[int]], + eps: float = 1e-5, + elementwise_affine: bool = True, + has_bias: bool = True, + ): + super().__init__() + self.layer_norm = torch.nn.LayerNorm( + normalized_shape, + eps=eps, + elementwise_affine=elementwise_affine, + bias=has_bias, + ) + if elementwise_affine: + self.layer_norm.weight = torch.nn.Parameter(torch.ones(normalized_shape)) + if has_bias: + self.layer_norm.bias = torch.nn.Parameter(torch.rand(normalized_shape)) + + def forward(self, x): + return self.layer_norm(x) + + +input_t = tuple[torch.Tensor] +test_data_suite = { + "randn_last_dim": lambda: ((torch.randn(1, 5, 5, 5),), LayerNorm([5])), + "rand_last_two_dims": lambda: ((torch.rand(1, 5, 5, 5),), LayerNorm([5, 5])), + "rand_last_two_dims_not_elementwise_affine": lambda: ( + (torch.rand(1, 5, 5, 5),), + LayerNorm([5, 5], 1e-5, False), + ), + "rand_last_two_dims_not_elementwise_affine_no_bias": lambda: ( + (torch.rand(1, 5, 5, 5),), + LayerNorm([5, 5], 1e-5, False, False), + ), + "randn_last_three_dims": lambda: ( + (torch.randn(1, 15, 10, 5),), + LayerNorm([15, 10, 5]), + ), + "randn_last_three_dims_no_bias": lambda: ( + (torch.randn(1, 15, 10, 5),), + LayerNorm([15, 10, 5], 1e-2, False, False), + ), +} + + +@common.parametrize("test_data", test_data_suite) +def test_native_layer_norm_tosa_FP(test_data): + test_data, model = test_data() + pipeline = TosaPipelineFP[input_t]( + model, + test_data, + "torch.ops.aten.layer_norm.default", + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_native_layer_norm_tosa_INT(test_data): + test_data, model = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + test_data, + "torch.ops.aten.sub.Tensor", # Just check for sub op included in the layernorm decomposition + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_layer_norm_u55_INT(test_data): + test_data, model = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + test_data, + "torch.ops.aten.sub.Tensor", # Just check for sub op included in the layernorm decomposition + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_layer_norm_u85_INT(test_data): + test_data, model = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + test_data, + "torch.ops.aten.sub.Tensor", # Just check for sub op included in the layernorm decomposition + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_layer_norm_vgf_no_quant(test_data): + test_input, model = test_data() + pipeline = VgfPipeline[input_t]( + model, + test_input, + "torch.ops.aten.layer_norm.default", + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_native_layer_norm_vgf_quant(test_data): + test_input, model = test_data() + pipeline = VgfPipeline[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_native_layer_norm_tosa_INT_a16w8(test_data): + """Test layer_norm with int16 I/O quantization for TOSA INT.""" + test_input, model = test_data() + pipeline = TosaPipelineINT[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", # check for sub op in decomposition + symmetric_io_quantization=True, + tosa_extensions=["int16"], + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_native_layer_norm_16a8w_u55_INT(test_data): + """Test layer_norm with int16 I/O quantization for U55""" + test_input, model = test_data() + pipeline = EthosU55PipelineINT[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", + symmetric_io_quantization=True, + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_native_layer_norm_16a8w_u85_INT(test_data): + """Test layer_norm with int16 I/O quantization for U85""" + test_input, model = test_data() + pipeline = EthosU85PipelineINT[input_t]( + model, + test_input, + "torch.ops.aten.sub.Tensor", + symmetric_io_quantization=True, + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_le.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_le.py new file mode 100644 index 0000000..6ed49c9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_le.py @@ -0,0 +1,296 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t = Tuple[torch.Tensor] + + +class LessEqual(torch.nn.Module): + aten_op_tensor = "torch.ops.aten.le.Tensor" + aten_op_scalar = "torch.ops.aten.le.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_le_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor, + ): + return input_ <= other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_le_tensor_rank1_ones = LessEqual( + torch.ones(5), + torch.ones(5), +) +op_le_tensor_rank2_rand = LessEqual( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_le_tensor_rank3_randn = LessEqual( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_le_tensor_rank4_randn = LessEqual( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_le_scalar_rank1_ones = LessEqual(torch.ones(5), 1.0) +op_le_scalar_rank2_rand = LessEqual(torch.rand(4, 5), 0.2) +op_le_scalar_rank3_randn = LessEqual(torch.randn(10, 5, 2), -0.1) +op_le_scalar_rank4_randn = LessEqual(torch.randn(3, 2, 2, 2), 0.3) + +test_data_tensor = { + "le_tensor_rank1_ones": lambda: op_le_tensor_rank1_ones, + "le_tensor_rank2_rand": lambda: op_le_tensor_rank2_rand, + "le_tensor_rank3_randn": lambda: op_le_tensor_rank3_randn, + "le_tensor_rank4_randn": lambda: op_le_tensor_rank4_randn, +} + +test_data_scalar = { + "le_scalar_rank1_ones": lambda: op_le_scalar_rank1_ones, + "le_scalar_rank2_rand": lambda: op_le_scalar_rank2_rand, + "le_scalar_rank3_randn": lambda: op_le_scalar_rank3_randn, + "le_scalar_rank4_randn": lambda: op_le_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_le_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_le_scalar_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_scalar, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_le_tensor_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_le_scalar_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_le_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_le_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_le_tensor_u55_INT_not_delegated(test_module): + # GREATER_EQUAL is not supported on U55. LE uses the GREATER_EQUAL Tosa operator. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessEqual.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_le_scalar_u55_INT_not_delegated(test_module): + # GREATER_EQUAL is not supported on U55. LE uses the GREATER_EQUAL Tosa operator. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessEqual.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.dump_operator_distribution("export") + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_le_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_le_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_le_tensor_16a8w_u85_INT(test_module): + """Test le operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_le_scalar_16a8w_u85_INT(test_module): + """Test le operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_le_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_le_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_le_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_scalar, + LessEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_le_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessEqual.aten_op_tensor, + LessEqual.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_leaky_relu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_leaky_relu.py new file mode 100644 index 0000000..9be2485 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_leaky_relu.py @@ -0,0 +1,125 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.leaky_relu.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_leaky_relu_default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class LeakyReLU(torch.nn.Module): + def __init__(self, slope: float = 0.01): + super().__init__() + self.activation = torch.nn.LeakyReLU(slope) + + def forward(self, x: torch.Tensor): + return self.activation(x) + + test_data: dict[str, input_t1] = { + "zeros": lambda: ((torch.zeros(1, 1, 5, 5),), 0.01), + "ones": lambda: ((torch.ones(1, 16, 96, 96),), 0.01), + "rand": lambda: ((torch.rand(1, 64, 56, 56),), 0.2), + "3Dtensor": lambda: ((torch.rand(5, 5, 5),), 0.001), + "negative_slope": lambda: ((torch.rand(1, 16, 96, 96),), -0.002), + } + + +@common.parametrize("test_data", LeakyReLU.test_data) +def test_leaky_relu_tosa_FP(test_data): + data, slope = test_data() + pipeline = TosaPipelineFP[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +def test_leaky_relu_tosa_INT(test_data): + data, slope = test_data() + pipeline = TosaPipelineINT[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.XfailIfNoCorstone300 +def test_leaky_relu_u55_INT(test_data): + data, slope = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.XfailIfNoCorstone320 +def test_leaky_relu_u85_INT(test_data): + data, slope = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.SkipIfNoModelConverter +def test_leaky_relu_vgf_no_quant(test_data): + data, slope = test_data() + pipeline = VgfPipeline[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + quantize=False, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [aten_op] + ) + pipeline.run() + + +@common.parametrize("test_data", LeakyReLU.test_data) +@common.SkipIfNoModelConverter +def test_leaky_relu_vgf_quant(test_data): + data, slope = test_data() + pipeline = VgfPipeline[input_t1]( + LeakyReLU(slope), + data, + [], + use_to_edge_transform_and_lower=True, + quantize=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linalg_vector_norm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linalg_vector_norm.py new file mode 100644 index 0000000..2723479 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linalg_vector_norm.py @@ -0,0 +1,160 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + +aten_op_q_decomposed_q = "torch.ops.quantized_decomposed.quantize_per_tensor.default" +exir_op_q_decomposed = "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default" + + +class VectorNormModel(torch.nn.Module): + def __init__( + self, + ord=None, + dim=1, + keepdim=False, + ): + """ + A simple module that applies torch.linalg.vector_norm to its input. + Ord is 2 by default. + """ + super().__init__() + self.ord = ord + self.dim = dim + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + if self.ord is None and self.dim is None: + return torch.linalg.vector_norm(x, keepdim=self.keepdim) + elif self.ord is None: + return torch.linalg.vector_norm(x, dim=self.dim, keepdim=self.keepdim) + elif self.dim is None: + return torch.linalg.vector_norm(x, ord=self.ord, keepdim=self.keepdim) + else: + return torch.linalg.vector_norm( + x, ord=self.ord, dim=self.dim, keepdim=self.keepdim + ) + + +test_modules = { + "default": (VectorNormModel(dim=1), (torch.rand(10, 4),)), + "ord1": (VectorNormModel(ord=1, dim=1), (torch.rand(10, 4),)), + "ord2": (VectorNormModel(ord=2, dim=1), (torch.rand(10, 20),)), + # Norm computed along a specific dimension of a 3D tensor + "dim_3d": (VectorNormModel(dim=2), (torch.rand(4, 5, 6),)), +} + + +@common.parametrize("test_module", test_modules) +def test_vector_norm_tosa_FP(test_module): + model, input_tensor = test_module + + # We decompose LinalgVectorNorm before quantize stage to have annotations + # with q/dq nodes. In case of FP, this operator will be decomposed + # by global decompositions. + aten_op = "torch.ops.aten.linalg_vector_norm.default" + # Should not found this op + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + + pipeline = TosaPipelineFP[input_t](model, input_tensor, aten_op, exir_op) + + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_vector_norm_tosa_INT(test_module): + model, input_tensor = test_module + + # Should not found this op + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + + pipeline = TosaPipelineINT[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op, + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_vector_norm_u55_INT_fvp(test_module): + model, input_tensor = test_module + + pipeline = EthosU55PipelineINT[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op_q_decomposed, + symmetric_io_quantization=True, + ) + pipeline.pop_stage("check_not.exir") + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_vector_norm_u85_INT_fvp(test_module): + model, input_tensor = test_module + + # The should be decomposed and annotated in DecomposeLinalgVectorNorm pass. + pipeline = EthosU85PipelineINT[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op_q_decomposed, + symmetric_io_quantization=True, + ) + pipeline.pop_stage("check_not.exir") + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_vector_norm_vgf_no_quant(test_module): + model, input_tensor = test_module + # FP VGF + aten_op = "torch.ops.aten.linalg_vector_norm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_vector_norm_vgf_quant(test_module): + model, input_tensor = test_module + # Should not found this op + exir_op = "executorch_exir_dialects_edge__ops_aten_linalg_vector_norm_default" + + pipeline = VgfPipeline[input_t]( + model, + input_tensor, + aten_op_q_decomposed_q, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linear.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linear.py new file mode 100644 index 0000000..7e22ad3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_linear.py @@ -0,0 +1,389 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_a8w4_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.linear.default" + +input_t1 = Tuple[torch.Tensor] + +test_data_rank1_FP = { + # test_name: (test_data, out_features, has_bias) + "model_linear_rank1_zeros": lambda: ( + torch.zeros(10), + 15, + True, + ), + "model_linear_rank1_ones": lambda: ( + torch.ones(10), + 15, + False, + ), + "model_linear_rank1_negative_ones": lambda: ( + torch.ones(10) * (-1), + 20, + True, + ), + "model_linear_rank1_rand": lambda: ( + torch.rand(10), + 10, + True, + ), + "model_linear_rank1_negative_large_rand": lambda: ( + torch.rand(10) * (-100), + 30, + False, + ), + "model_linear_rank1_large_randn": lambda: ( + torch.randn(15) * 100, + 20, + True, + ), +} + +test_data_rank4_FP = { + # test_name: (test_data, out_features, has_bias) + "model_linear_rank4_zeros": lambda: ( + torch.zeros(5, 10, 25, 20), + 30, + True, + ), + "model_linear_rank4_ones": lambda: ( + torch.ones(5, 10, 25, 20), + 30, + False, + ), + "model_linear_rank4_negative_ones": lambda: ( + torch.ones(5, 10, 25, 20) * (-1), + 30, + True, + ), + "model_linear_rank4_rand": lambda: ( + torch.rand(5, 10, 25, 20), + 30, + False, + ), + "model_linear_rank4_negative_large_rand": lambda: ( + torch.rand(5, 10, 25, 20) * (-100), + 30, + True, + ), + "model_linear_rank4_large_randn": lambda: ( + torch.randn(5, 10, 25, 20) * 100, + 30, + False, + ), +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_rank1_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (*v(), q)) + for (k, v) in test_data_rank1_FP.items() + for q in [True, False] +} + +# Generate a new test set paired with per_channel_quant=True/False. +test_data_rank4_INT = { + f"{k},per_channel_quant={q}": (lambda v=v, q=q: (*v(), q)) + for (k, v) in test_data_rank4_FP.items() + for q in [True, False] +} + + +class Linear(torch.nn.Module): + def __init__( + self, + in_features: int, + out_features: int = 3, + bias: bool = True, + ): + super().__init__() + self.fc = torch.nn.Linear( + in_features=in_features, + out_features=out_features, + bias=bias, + ) + + def forward(self, x): + return self.fc(x) + + +@common.parametrize("test_data", test_data_rank1_FP | test_data_rank4_FP) +def test_linear_tosa_FP(test_data: torch.Tensor): + test_data, out_features, has_bias = test_data() + in_features = test_data.shape[-1] + pipeline = TosaPipelineFP[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT | test_data_rank4_INT) +def test_linear_tosa_INT(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + pipeline = TosaPipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT | test_data_rank4_INT) +def test_linear_tosa_INT_a8w4(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + pipeline = TosaPipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + tosa_extensions=["int4"], + ) + pipeline.quantizer.set_global( + get_symmetric_a8w4_quantization_config(is_per_channel=per_channel_quantization) + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + pipeline.tester.check_dtype_count, + { + "CONST": {"INT4": 2}, + "CONV2D": {"INT32": 1}, + "RESCALE": {"INT8": 1}, + }, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT) +@common.XfailIfNoCorstone300 +def test_linear_u55_INT(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + EthosU55PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize( + "test_data", + test_data_rank1_INT | test_data_rank4_INT, +) +@common.XfailIfNoCorstone320 +def test_linear_u85_INT(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + EthosU85PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ).run() + + +@common.parametrize("test_data", test_data_rank1_FP | test_data_rank4_FP) +@common.SkipIfNoModelConverter +def test_linear_vgf_no_quant(test_data: torch.Tensor): + test_data, out_features, has_bias = test_data() + in_features = test_data.shape[-1] + pipeline = VgfPipeline[input_t1]( + Linear(in_features=in_features, out_features=out_features, bias=has_bias), + (test_data,), + aten_op=aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_rank1_INT | test_data_rank4_INT) +@common.SkipIfNoModelConverter +def test_linear_vgf_quant(test_data: torch.Tensor): + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + pipeline = VgfPipeline[input_t1]( + Linear(in_features=in_features, out_features=out_features, bias=has_bias), + (test_data,), + aten_op=aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_linear_quantizer( + u55_config=False, per_channel_quantization=False +): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + quantizer.set_module_type( + torch.nn.Linear, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +test_data_all_16a8w = test_data_rank1_INT | test_data_rank4_INT + + +@common.parametrize("test_data", test_data_all_16a8w) +def test_linear_16a8w_tosa_INT(test_data: torch.Tensor): + """Test linear operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + + # Create pipeline with custom 16A8W quantization config + pipeline = TosaPipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_linear_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + # Run the pipeline + pipeline.run() + + +@common.parametrize("test_data", test_data_all_16a8w) +@common.XfailIfNoCorstone300 +def test_linear_16a8w_u55_INT(test_data: torch.Tensor): + """Test linear operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + + pipeline = EthosU55PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_linear_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_all_16a8w) +@common.XfailIfNoCorstone320 +def test_linear_16a8w_u85_INT(test_data: torch.Tensor): + """Test linear operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + test_data, out_features, has_bias, per_channel_quantization = test_data() + in_features = test_data.shape[-1] + + pipeline = EthosU85PipelineINT[input_t1]( + Linear( + in_features=in_features, + out_features=out_features, + bias=has_bias, + ), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_linear_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log.py new file mode 100644 index 0000000..3f4bfcd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log.py @@ -0,0 +1,100 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.log.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_log_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + # (test_name, test_data) + "ones_rank4": lambda: (torch.ones(1, 10, 10, 10)), + "ones_rank3": lambda: (torch.ones(10, 10, 10)), + "rand": lambda: (torch.rand(10, 10) + 0.001), + "randn_pos": lambda: (torch.randn(10) + 10), + "randn_spread": lambda: (torch.max(torch.Tensor([0.0]), torch.randn(10) * 100)), + "ramp": lambda: (torch.arange(0.01, 20, 0.2)), +} + + +class Log(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.log(x) + + +@common.parametrize("test_data", test_data_suite) +def test_log_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Log(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_log_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Log(), (test_data(),), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_log_u55_INT(test_data: input_t1): + EthosU55PipelineINT[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_log_u85_INT(test_data: input_t1): + EthosU85PipelineINT[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Log(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log1p.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log1p.py new file mode 100644 index 0000000..a8ca4a9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_log1p.py @@ -0,0 +1,78 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.log1p.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_log1p_default" + +input_t1 = Tuple[torch.Tensor] + + +def _tensor(values): + return torch.tensor(values, dtype=torch.float32) + + +test_data_suite = { + "tiny_positive": lambda: (_tensor([5e-4, 8e-4, 9e-4, 1e-3, 1.2e-3]),), + "straddle_eps": lambda: (_tensor([5e-4, 1e-3, 2e-3, -5e-4, -1e-3]),), + "mixed_range": lambda: (_tensor([1e-4, 5e-4, 2e-3, 1e-2, 5e-2]),), +} + + +class Log1p(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.log1p(x) + + +@common.parametrize("test_data", test_data_suite) +def test_log1p_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Log1p(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_log1p_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + Log1p(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log1p_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Log1p(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_log1p_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Log1p(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logical.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logical.py new file mode 100644 index 0000000..a2a8279 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logical.py @@ -0,0 +1,429 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y +input_t1 = Tuple[torch.Tensor] # Input x + + +class LogicalBinary(torch.nn.Module): + test_data: dict[input_t2] = { + "rank1": lambda: ( + torch.tensor([True, True, False, False], dtype=torch.bool), + torch.tensor([True, False, True, False], dtype=torch.bool), + ), + "rand_rank2": lambda: ( + torch.randint(0, 2, (10, 10), dtype=torch.bool), + torch.randint(0, 2, (10, 10), dtype=torch.bool), + ), + "rand_rank3": lambda: ( + torch.randint(0, 2, (10, 10, 10), dtype=torch.bool), + torch.randint(0, 2, (10, 10, 10), dtype=torch.bool), + ), + "rand_rank4": lambda: ( + torch.randint(0, 2, (1, 10, 10, 10), dtype=torch.bool), + torch.randint(0, 2, (1, 10, 10, 10), dtype=torch.bool), + ), + } + + +class And(LogicalBinary): + aten_op = "torch.ops.aten.logical_and.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_and_default" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.logical_and(tensor2) + + +class Xor(LogicalBinary): + aten_op = "torch.ops.aten.logical_xor.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_xor_default" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.logical_xor(tensor2) + + +class Or(LogicalBinary): + aten_op = "torch.ops.aten.logical_or.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_or_default" + + def forward(self, tensor1: torch.Tensor, tensor2: torch.Tensor): + return tensor1.logical_or(tensor2) + + +class Not(torch.nn.Module): + test_data: dict[input_t1] = { + "rank1": lambda: (torch.tensor([True, True, False, False], dtype=torch.bool),), + "rand_rank2": lambda: (torch.randint(0, 2, (10, 10), dtype=torch.bool),), + "rand_rank3": lambda: (torch.randint(0, 2, (10, 10, 10), dtype=torch.bool),), + "rand_rank4": lambda: (torch.randint(0, 2, (1, 10, 10, 10), dtype=torch.bool),), + } + + aten_op = "torch.ops.aten.logical_not.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_logical_not_default" + + def forward(self, tensor: torch.Tensor): + return torch.logical_not(tensor) + + +################# +## logical_and ## +################# + + +@common.parametrize("test_data", And().test_data) +def test_logical_and_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_logical_and_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +def test_logical_and_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + And(), + test_data(), + {And().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.XfailIfNoCorstone320 +def test_logical_and_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_logical_and_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", And().test_data) +@common.SkipIfNoModelConverter +def test_logical_and_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + And(), + test_data(), + And().aten_op, + And().exir_op, + quantize=True, + ) + pipeline.run() + + +################# +## logical_xor ## +################# + + +@common.parametrize("test_data", Xor().test_data) +def test_logical_xor_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_logical_xor_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +def test_logical_xor_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Xor(), + test_data(), + {Xor().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.XfailIfNoCorstone320 +def test_logical_xor_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_logical_xor_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Xor().test_data) +@common.SkipIfNoModelConverter +def test_logical_xor_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Xor(), + test_data(), + Xor().aten_op, + Xor().exir_op, + quantize=True, + ) + pipeline.run() + + +################ +## logical_or ## +################ + + +@common.parametrize("test_data", Or().test_data) +def test_logical_or_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_logical_or_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +def test_logical_or_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Or(), + test_data(), + {Or().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.XfailIfNoCorstone320 +def test_logical_or_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_logical_or_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Or().test_data) +@common.SkipIfNoModelConverter +def test_logical_or_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Or(), + test_data(), + Or().aten_op, + Or().exir_op, + quantize=True, + ) + pipeline.run() + + +################# +## logical_not ## +################# + + +@common.parametrize("test_data", Not().test_data) +def test_logical_not_tosa_FP(test_data: input_t2): + pipeline = TosaPipelineFP[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +def test_logical_not_tosa_INT(test_data: input_t2): + pipeline = TosaPipelineINT[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +def test_logical_not_u55_INT_not_delegated(test_data: input_t2): + # Tests that we don't delegate these ops since they are not supported on U55. + pipeline = OpNotSupportedPipeline[input_t2]( + Not(), + test_data(), + {Not().exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +@common.XfailIfNoCorstone320 +def test_logical_not_u85_INT(test_data: input_t2): + pipeline = EthosU85PipelineINT[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + atol=0, + rtol=0, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +@common.SkipIfNoModelConverter +def test_logical_not_vgf_no_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Not().test_data) +@common.SkipIfNoModelConverter +def test_logical_not_vgf_quant(test_data: input_t2): + pipeline = VgfPipeline[input_t2]( + Not(), + test_data(), + Not().aten_op, + Not().exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logit.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logit.py new file mode 100644 index 0000000..b628504 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logit.py @@ -0,0 +1,119 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.logit.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__logit_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": [torch.zeros((10, 10, 10)), None], + "ones": [torch.ones((10, 10, 10)), None], + "uniform_valid": [torch.rand((10, 10, 10)), None], + "near_zero": [torch.full((10, 10), 1e-8), None], + "near_one": [torch.full((10, 10), 1 - 1e-8), None], + "mixed": [torch.tensor([0.0, 1e-5, 0.5, 1 - 1e-5, 1.0]), None], + "multi_dim": [torch.rand((2, 3, 4)), None], + "eps": [torch.zeros((10, 10, 10)), 1e-6], + "invalid_neg": [torch.full((5,), -0.1), 1e-6], + "invalid_gt1": [torch.full((5,), 1.1), 1e-6], +} + + +class Logit(torch.nn.Module): + + def forward(self, x: torch.Tensor, eps: torch.float32): + return torch.logit(x, eps=eps) + + +@common.parametrize("test_data", test_data_suite) +def test_logit_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Logit(), + (*test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_logit_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Logit(), + (*test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_logit_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Logit(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_logit_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Logit(), + (*test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_logit_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Logit(), + (*test_data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.SkipIfNoModelConverter +def test_logit_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Logit(), + (*test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logsoftmax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logsoftmax.py new file mode 100644 index 0000000..8d090b6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_logsoftmax.py @@ -0,0 +1,124 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.log_softmax.default" # Used for checking that we do not have log_softmax in the graph +exir_op = "executorch_exir_dialects_edge__ops_aten__log_softmax_tensor" + +input_t1 = Tuple[torch.Tensor] # Input x + + +class LogSoftmax(torch.nn.Module): + def __init__(self, dim: int = -1): + super().__init__() + self.log_softmax = torch.nn.LogSoftmax(dim=dim) + + def forward(self, x): + return self.log_softmax(x) + + test_data = { + "ones": lambda: ((torch.ones(10, 10),), 1), + "ones_neg_dim": lambda: ((torch.ones(1, 3, 4),), -1), + "randn_neg_dim": lambda: ((torch.randn(1, 5, 8, 7),), -3), + "zeros": lambda: ((torch.zeros(1, 8, 5, 2),), 0), + "zeros_neg_dim": lambda: ((torch.zeros(1, 7, 8, 9),), -4), + "rand": lambda: ((torch.rand(1, 2, 5, 8),), 2), + "rand_neg_dim": lambda: ((torch.rand(1, 10, 8, 10),), -2), + "randn_mult_batches": lambda: ((torch.randn(2, 10, 10, 10),), 3), + } + + +@common.parametrize("test_data", LogSoftmax.test_data) +def test_log_softmax_tosa_FP(test_data): + data, dim = test_data() + pipeline = TosaPipelineFP[input_t1](LogSoftmax(dim), data, []) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + + pipeline.run() + + +@pytest.mark.flaky(reruns=5) +@common.parametrize("test_data", LogSoftmax.test_data) +def test_log_softmax_tosa_INT(test_data): + data, dim = test_data() + pipeline = TosaPipelineINT[input_t1](LogSoftmax(dim), data, []) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.XfailIfNoCorstone300() +def test_log_softmax_u55_INT(test_data): + data, dim = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + LogSoftmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.XfailIfNoCorstone320 +def test_log_softmax_u85_INT(test_data): + data, dim = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + LogSoftmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.SkipIfNoModelConverter +def test_log_softmax_vgf_no_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + LogSoftmax(dim), + data, + [], + [], + quantize=False, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [aten_op] + ) + pipeline.run() + + +@common.parametrize("test_data", LogSoftmax.test_data) +@common.SkipIfNoModelConverter +def test_log_softmax_vgf_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + LogSoftmax(dim), + data, + [], + [], + quantize=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lshift.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lshift.py new file mode 100644 index 0000000..573b0ec --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lshift.py @@ -0,0 +1,220 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.common import ( + XfailIfNoCorstone300, + XfailIfNoCorstone320, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +scalar_input_t = tuple[torch.Tensor, int] + + +class LshiftScalar(torch.nn.Module): + torch_op_FP = "torch.ops.aten.__lshift__.Scalar" + torch_op_INT = "torch.ops.aten.bitwise_left_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_left_shift_Tensor" + test_data = { + "randint_neg_8_int8": ( + torch.randint(-8, 8, (1, 12, 3, 4), dtype=torch.int8), + 1, + ), + "randint_neg_100_int16": ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int16), + 5, + ), + "randint_neg_100_int32": ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int32), + 2, + ), + } + + def forward(self, x: torch.Tensor, shift: int): + return x << shift + + +tensor_input_t = tuple[torch.Tensor, torch.Tensor] + + +class LshiftTensor(torch.nn.Module): + torch_op = "torch.ops.aten.bitwise_left_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_left_shift_Tensor" + test_data = { + "randint_neg_8_tensor_int8": ( + torch.randint(-8, 8, (3, 3), dtype=torch.int8), + torch.randint(0, 4, (3, 3), dtype=torch.int8), + ), + "randint_neg_1024_tensor_int16": ( + torch.randint(-1024, 1024, (3, 3, 3), dtype=torch.int16), + torch.randint(0, 5, (3, 3, 3), dtype=torch.int16), + ), + "randint_0_tensor_int16": ( + torch.randint(0, 127, (1, 2, 3, 3), dtype=torch.int32), + torch.randint(0, 5, (1, 2, 3, 3), dtype=torch.int32), + ), + } + + def forward(self, x: torch.Tensor, shift: torch.Tensor): + return x.bitwise_left_shift(shift) + + +################## +## LshiftScalar ## +################## + + +@common.parametrize("test_data", LshiftScalar.test_data) +def test_bitwise_left_shift_scalar_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_FP, + LshiftScalar.exir_op, + ).run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +def test_bitwise_left_shift_scalar_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@XfailIfNoCorstone300 +def test_bitwise_left_shift_scalar_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@XfailIfNoCorstone320 +def test_bitwise_left_shift_scalar_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_scalar_vgf_no_quant(test_data: scalar_input_t): + pipeline = VgfPipeline[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_FP, + LshiftScalar.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_scalar_vgf_quant(test_data: scalar_input_t): + pipeline = VgfPipeline[scalar_input_t]( + LshiftScalar(), + test_data, + LshiftScalar.torch_op_INT, + LshiftScalar.exir_op, + quantize=True, + ) + pipeline.run() + + +################## +## LshiftTensor ## +################## + + +@common.parametrize("test_data", LshiftTensor.test_data) +def test_bitwise_left_shift_tensor_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ).run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +def test_bitwise_left_shift_tensor_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.XfailIfNoCorstone300 +def test_bitwise_left_shift_tensor_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.XfailIfNoCorstone320 +def test_bitwise_left_shift_tensor_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_tensor_vgf_no_quant(test_data: tensor_input_t): + pipeline = VgfPipeline[tensor_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", LshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_left_shift_tensor_vgf_quant(test_data: tensor_input_t): + pipeline = VgfPipeline[tensor_input_t]( + LshiftTensor(), + test_data, + LshiftTensor.torch_op, + LshiftTensor.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lt.py new file mode 100644 index 0000000..8b5b5c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_lt.py @@ -0,0 +1,293 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +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 + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ < other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_lt_tensor_rank1_ones = LessThan( + torch.ones(5), + torch.ones(5), +) +op_lt_tensor_rank2_rand = LessThan( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_lt_tensor_rank3_randn = LessThan( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_lt_tensor_rank4_randn = LessThan( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +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": lambda: op_lt_tensor_rank1_ones, + "lt_tensor_rank2_rand": lambda: op_lt_tensor_rank2_rand, + "lt_tensor_rank3_randn": lambda: op_lt_tensor_rank3_randn, + "lt_tensor_rank4_randn": lambda: op_lt_tensor_rank4_randn, +} + +test_data_scalar = { + "lt_scalar_rank1_ones": lambda: op_lt_scalar_rank1_ones, + "lt_scalar_rank2_rand": lambda: op_lt_scalar_rank2_rand, + "lt_scalar_rank3_randn": lambda: op_lt_scalar_rank3_randn, + "lt_scalar_rank4_randn": lambda: op_lt_scalar_rank4_randn, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_lt_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[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_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + 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_INT(test_module): + pipeline = TosaPipelineINT[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_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_lt_tensor_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_lt_scalar_tosa_INT_a16w8(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_lt_tensor_u55_INT_not_delegated(test_module): + # LessThan is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessThan.exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_lt_scalar_u55_INT_not_delegated(test_module): + # LessThan is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {LessThan.exir_op: 1}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, +) +@common.XfailIfNoCorstone320 +def test_lt_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, +) +@common.XfailIfNoCorstone320 +def test_lt_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone320 +def test_lt_tensor_16a8w_u85_INT(test_module): + """Test lt operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone320 +def test_lt_scalar_16a8w_u85_INT(test_module): + """Test lt operation (scalar) with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_lt_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_lt_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_scalar, + LessThan.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_lt_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_lt_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + LessThan.aten_op_tensor, + LessThan.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_masked_fill.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_masked_fill.py new file mode 100644 index 0000000..2704fa5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_masked_fill.py @@ -0,0 +1,171 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +aten_op = "torch.aten.ops.masked_fill.Scalar" +exir_op = "executorch_exir_dialects_edge__ops_aten_masked_fill_scalar" + +input_t = Tuple[torch.Tensor, torch.Tensor, float] + + +class MaskedFill(torch.nn.Module): + def forward( + self, x: torch.Tensor, mask: torch.Tensor, value: float + ) -> torch.Tensor: + return torch.masked_fill(x, mask, value) + + +test_modules = { + "masked_fill_1": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + (torch.rand(1, 3, 4, 5) < 0.5), # boolean mask + -1.0, + ), + ), + "masked_fill_2": lambda: ( + MaskedFill(), + ( + torch.rand(1, 10, 10, 10), + (torch.rand(1, 10, 10, 10) > 0.75), + 3.14, + ), + ), + "masked_fill_3_zero_fill": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + torch.rand(1, 3, 4, 5) < 0.2, + 0.0, + ), + ), + "masked_fill_4_full_mask": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + torch.ones(1, 3, 4, 5, dtype=torch.bool), + 7.0, + ), + ), + "masked_fill_5_no_mask": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 4, 5), + torch.zeros(1, 3, 4, 5, dtype=torch.bool), + -3.0, + ), + ), + "masked_fill_6_scalar_broadcast": lambda: ( + MaskedFill(), + ( + torch.rand(1, 1, 1, 1), + torch.tensor([[[[True]]]]), + 42.0, + ), + ), + "masked_fill_7_large_tensor": lambda: ( + MaskedFill(), + ( + torch.rand(1, 8, 8, 8), + torch.rand(1, 8, 8, 8) > 0.5, + -127.0, + ), + ), + "masked_fill_8_extreme_scalar_inf": lambda: ( + MaskedFill(), + ( + torch.rand(1, 3, 7, 5), + torch.rand(1, 3, 7, 5) > 0.5, + float("inf"), + ), + ), +} + + +@common.parametrize("test_module", test_modules) +def test_masked_fill_scalar_tosa_FP(test_module): + module, inputs = test_module() + pipeline = TosaPipelineFP[input_t](module, inputs, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +def test_masked_fill_scalar_tosa_INT(test_module): + module, inputs = test_module() + pipeline = TosaPipelineINT[input_t]( + module, + inputs, + aten_op=[], + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone300 +def test_masked_fill_scalar_u55_INT(test_module): + module, inputs = test_module() + pipeline = OpNotSupportedPipeline[input_t]( + module, + inputs, + {exir_op: 0, "executorch_exir_dialects_edge__ops_aten_where_self": 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.XfailIfNoCorstone320 +def test_masked_fill_scalar_u85_INT(test_module): + module, inputs = test_module() + pipeline = EthosU85PipelineINT[input_t]( + module, + inputs, + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_masked_fill_scalar_vgf_no_quant(test_module): + module, inputs = test_module() + pipeline = VgfPipeline[input_t]( + module, + inputs, + aten_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules) +@common.SkipIfNoModelConverter +def test_masked_fill_scalar_vgf_quant(test_module): + module, inputs = test_module() + pipeline = VgfPipeline[input_t]( + module, + inputs, + aten_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_matmul.py new file mode 100644 index 0000000..c9d5665 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_matmul.py @@ -0,0 +1,289 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op_mm = "torch.ops.aten.matmul.default" +exir_op_mm = "executorch_exir_dialects_edge__ops_aten_matmul_default" +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class MatMul(torch.nn.Module): + test_data_generators = { + "rand_rand_2d": lambda: (torch.rand(5, 5), torch.rand(5, 2)), + "rand_rand_3d": lambda: (torch.rand(2, 3, 5), torch.rand(2, 5, 2)), + "rand_rand_4d": lambda: (torch.rand(1, 2, 3, 5), torch.rand(1, 2, 5, 2)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return torch.matmul(x, y) + + +class MatMulSingleInput(torch.nn.Module): + test_data_generators = { + "rand_2d": lambda: (torch.rand(5, 5),), + "rand_3d": lambda: (torch.rand(2, 5, 5),), + "rand_4d": lambda: (torch.rand(1, 2, 5, 5),), + } + + def forward(self, x: torch.Tensor): + return torch.matmul(x, x) + + +class MatMulCombo(torch.nn.Module): + test_data_generators = { + "rand_rand_rand_2d": lambda: ( + torch.rand(5, 5), + torch.rand(5, 2), + torch.rand(2, 5), + ), + "rand_rand_rand_3d": lambda: ( + torch.rand(2, 5, 5), + torch.rand(2, 5, 2), + torch.rand(2, 2, 5), + ), + "rand_rand_rand_4d": lambda: ( + torch.rand(1, 2, 5, 5), + torch.rand(1, 2, 5, 2), + torch.rand(1, 2, 2, 5), + ), + } + + def forward(self, x1: torch.Tensor, x2: torch.Tensor, x3: torch.Tensor): + y1 = torch.matmul(x1, x1) + y2 = torch.matmul(x2, x3) + return y1 + y2 + + +@common.parametrize("test_data", MatMul.test_data_generators) +def test_matmul_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](MatMul(), test_data(), aten_op_mm, exir_op_mm) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +def test_matmul_tosa_FP_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + MatMulSingleInput(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +def test_matmul_tosa_FP_combo(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + MatMulCombo(), test_data(), aten_op_mm, exir_op_mm + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +def test_matmul_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + MatMul(), test_data(), aten_op_mm, exir_op_mm, qtol=1 + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +def test_matmul_tosa_INT_single_input(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +def test_matmul_tosa_INT_combo(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + qtol=1, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.XfailIfNoCorstone300 +def test_matmul_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulSingleInput.test_data_generators, +) +@common.XfailIfNoCorstone300 +def test_matmul_u55_INT_single_input(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulCombo.test_data_generators, +) +@common.XfailIfNoCorstone300 +def test_matmul_u55_INT_combo(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.XfailIfNoCorstone320 +def test_matmul_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulSingleInput.test_data_generators, +) +@common.XfailIfNoCorstone320 +def test_matmul_u85_INT_single_input(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + MatMulCombo.test_data_generators, +) +@common.XfailIfNoCorstone320 +def test_matmul_u85_INT_combo(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_no_quant_combo(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMul.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMul(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulSingleInput.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_single_input(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulSingleInput(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MatMulCombo.test_data_generators) +@common.SkipIfNoModelConverter +def test_matmul_vgf_quant_combo(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + MatMulCombo(), + test_data(), + aten_op_mm, + exir_op_mm, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_max_pool.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_max_pool.py new file mode 100644 index 0000000..b2cd807 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_max_pool.py @@ -0,0 +1,329 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data, [kernel_size, stride, padding]) + "zeros": lambda: (torch.zeros(1, 1, 4, 8), [(4, 6), 2, (2, 0)]), + "ones": lambda: (torch.ones(1, 16, 50, 32), [4, 2, 0]), + "rand": lambda: (torch.rand(1, 16, 52, 16), [4, 3, 0]), + "non_divisible": lambda: (torch.rand(1, 16, 112, 112), [3, 2, 1]), + "non_divisible_window_height": lambda: (torch.rand(1, 16, 56, 56), [3, (2, 1), 1]), + "non_divisible_window_width": lambda: (torch.rand(1, 16, 56, 56), [3, (1, 2), 1]), + "non_divisible_ceil_mode": lambda: ( + torch.rand(1, 16, 112, 112), + [3, 2, 1, 1, True], + ), + "non_divisible_window_height_ceil_mode": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (2, 1), 1, 1, True], + ), + "non_divisible_window_width_ceil_mode": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (1, 2), 1, 1, True], + ), + "non_divisible_window_adjust_padding": lambda: ( + torch.rand(1, 16, 112, 112), + [3, 2, 1], + ), + "non_divisible_window_height_adjust_padding": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (2, 1), 1], + ), + "non_divisible_window_width_adjust_padding": lambda: ( + torch.rand(1, 16, 56, 56), + [3, (1, 2), 1], + ), + "non_divisble_no_padding": lambda: (torch.rand(1, 16, 56, 56), [3, 2, 0]), + "non_divisible_window_adjust_padding+input": lambda: ( + torch.rand(1, 16, 54, 54), + [3, 3, 1], + ), + "non_divisible_window_height_adjust_padding+input": lambda: ( + torch.rand(1, 16, 54, 54), + [3, (3, 1), 1], + ), + "non_divisible_window_width_adjust_padding+input": lambda: ( + torch.rand(1, 16, 54, 54), + [3, (1, 3), 1], + ), + "randn": lambda: (torch.randn(5, 16, 50, 32), [4, 2, 0]), +} + + +test_data_suite_dilation = [ + # Simple dilation=2 on 8x8 input, kernel=3, stride=1, no padding + ("dilation2", torch.rand(1, 1, 8, 8), [3, 1, 0, 2]), + # Input is 6x6, kernel=3, stride=1, dilation=2. + # Padding=1 expands the effective input to 8x8. + ("pad_then_dil2", torch.rand(1, 1, 6, 6), [3, 1, 1, 2]), + # Input is 16x16, kernel=2x2, stride=2x2, dilation=1 (no dilation). + # Padding of 1 ensures the input size remains divisible by stride + # after padding. + ("even_kernel_fast", torch.rand(1, 3, 16, 16), [(2, 2), (2, 2), (1, 1), 1]), + # Multi-batch, multi-channel input (N=4, C=3), kernel=3x3, + # stride=3x3, no padding, dilation=1. + ("mb_ch_dil1", torch.rand(4, 3, 12, 12), [(3, 3), (3, 3), 0, 1]), +] + +aten_op = "torch.ops.aten.max_pool2d.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_max_pool2d_default" + +input_t1 = Tuple[torch.Tensor] + + +class MaxPool2d(torch.nn.Module): + def __init__( + self, + kernel_size: int | Tuple[int, int], + stride: int | Tuple[int, int], + padding: int | Tuple[int, int], + dilation: int | Tuple[int, int] = 1, + ceil_mode: bool = False, + ): + super().__init__() + self.max_pool_2d = torch.nn.MaxPool2d( + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + ceil_mode=ceil_mode, + ) + + def forward(self, x): + return self.max_pool_2d(x) + + +@common.parametrize("test_data", test_data_suite) +def test_max_pool2d_tosa_FP(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + MaxPool2d(*model_params), (test_data,), aten_op, exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_max_pool2d_tosa_INT(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_max_pool2d_tosa_INT_a16w8(test_data: torch.Tensor): + """Test max_pool2d operation with int16 I/O quantization for TOSA INT.""" + test_data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + tosa_extensions=["int16"], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_max_pool2d_u55_INT(test_data: torch.Tensor): + test_data, model_params = test_data() + EthosU55PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_max_pool2d_16a8w_u55_INT(test_data: torch.Tensor): + """Test max_pool2d with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + test_data, model_params = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_max_pool2d_u85_INT(test_data: torch.Tensor): + test_data, model_params = test_data() + EthosU85PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_max_pool2d_16a8w_u85_INT(test_data: torch.Tensor): + """Test max_pool2d with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + test_data, model_params = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +reject_data_suite = { + "reject_1": lambda: (MaxPool2d(1, 4, 0), torch.rand(1, 10, 10, 10)), + "reject_2": lambda: (MaxPool2d((1, 257), 1, 0), torch.rand(1, 16, 5, 300)), + "reject_3": lambda: (MaxPool2d((800, 90), 1, 0), torch.rand(1, 16, 850, 100)), +} + + +@common.parametrize("test_data", reject_data_suite) +@common.XfailIfNoCorstone300 +def test_max_pool2d_u55_INT_failure_set(test_data: Tuple): + module, test_data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + (test_data,), + aten_op, + exir_op, + run_on_fvp=False, + use_to_edge_transform_and_lower=True, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +# Convert the list of (name, tensor, params) into the dict-of-lambdas shape +dilation_test_data = { + name: (lambda data=data, params=params: (data, params)) + for name, data, params in test_data_suite_dilation +} + + +@common.parametrize("test_data", dilation_test_data) +def test_max_pool2d_tosa_FP_dilation(test_data): + """ + TOSA FP pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + data, model_params = test_data() + pipeline = TosaPipelineFP[input_t1]( + MaxPool2d(*model_params), + (data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", dilation_test_data) +def test_max_pool2d_tosa_INT_dilation(test_data): + """ + TOSA INT pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + data, model_params = test_data() + pipeline = TosaPipelineINT[input_t1]( + MaxPool2d(*model_params), + (data,), + aten_op, + exir_op, + symmetric_io_quantization=True, + ) + pipeline.run() + + +# VGF tests +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_no_quant(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_quant(test_data: torch.Tensor): + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", dilation_test_data) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_no_quant_dilation(test_data: torch.Tensor): + """ + VGF FP pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", dilation_test_data) +@common.SkipIfNoModelConverter +def test_max_pool2d_vgf_quant_dilation(test_data: torch.Tensor): + """ + VGF INT pipeline with dilation > 1 (and dilation=1 sanity cases). + """ + test_data, model_params = test_data() + pipeline = VgfPipeline[input_t1]( + MaxPool2d(*model_params), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_maximum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_maximum.py new file mode 100644 index 0000000..e213842 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_maximum.py @@ -0,0 +1,98 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_t = tuple[torch.Tensor, torch.Tensor] +aten_op = "torch.ops.aten.maximum.default" + + +class Maximum(torch.nn.Module): + test_parameters = { + "float_tensor": lambda: ( + torch.FloatTensor([1, 2, 3, 5, 7]), + (torch.FloatTensor([2, 1, 2, 1, 10])), + ), + "ones": lambda: (torch.ones(1, 10, 4, 6), 2 * torch.ones(1, 10, 4, 6)), + "rand_diff": lambda: (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "rand_same": lambda: (torch.randn(1, 3, 4, 4), torch.randn(1, 3, 4, 4)), + "rand_large": lambda: ( + 10000 * torch.randn(1, 1, 4, 4), + torch.randn(1, 1, 4, 1), + ), + } + + def __init__(self): + super().__init__() + + def forward(self, x, y): + return torch.maximum(x, y) + + +@common.parametrize("test_data", Maximum.test_parameters) +def test_maximum_tosa_FP(test_data: Tuple): + TosaPipelineFP[test_t](Maximum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +def test_maximum_tosa_INT(test_data: Tuple): + TosaPipelineINT[test_t](Maximum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.XfailIfNoCorstone300 +def test_maximum_u55_INT(test_data: Tuple): + EthosU55PipelineINT[test_t]( + Maximum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.XfailIfNoCorstone320 +def test_maximum_u85_INT(test_data: Tuple): + EthosU85PipelineINT[test_t]( + Maximum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.SkipIfNoModelConverter +def test_maximum_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + Maximum(), + test_data(), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Maximum.test_parameters) +@common.SkipIfNoModelConverter +def test_maximum_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + Maximum(), + test_data(), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mean_dim.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mean_dim.py new file mode 100644 index 0000000..5195d95 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mean_dim.py @@ -0,0 +1,388 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Callable + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] + + +class AdaptiveAveragePool2d(torch.nn.Module): + test_data_suite = { + # (test_name, test_data) + "zeros": lambda: (torch.zeros(1, 1280, 7, 7),), + "ones": lambda: (torch.ones(1, 1280, 7, 7),), + "rand": lambda: (torch.rand(1, 1280, 7, 7),), + "randn": lambda: (torch.randn(1, 1280, 7, 7),), + } + aten_op = "torch.ops.aten.adaptive_avg_pool2d.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_mean_dim" + + def __init__(self): + super().__init__() + self.adaptive_avg_pool2d = torch.nn.AdaptiveAvgPool2d(output_size=(1, 1)) + + def forward(self, x): + return self.adaptive_avg_pool2d(x) + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +def test_adaptive_avg_pool2d_tosa_FP(test_data): + TosaPipelineFP[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +def test_adaptive_avg_pool2d_tosa_INT(test_data): + TosaPipelineINT[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.XfailIfNoCorstone300 +def test_adaptive_avg_pool2d_u55_INT(test_data): + EthosU55PipelineINT[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.XfailIfNoCorstone320 +def test_adaptive_avg_pool2d_u85_INT(test_data): + EthosU85PipelineINT[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + ).run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_no_quant(test_data): + pipeline = VgfPipeline[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite) +@common.SkipIfNoModelConverter +def test_adaptive_avg_pool2d_vgf_quant(test_data): + pipeline = VgfPipeline[input_t]( + AdaptiveAveragePool2d(), + test_data(), + AdaptiveAveragePool2d.aten_op, + AdaptiveAveragePool2d.exir_op, + symmetric_io_quantization=True, + quantize=True, + ) + pipeline.run() + + +class MeanDim(torch.nn.Module): + test_data_suite: dict[str, tuple] = { + "rank_1_keepdim": lambda: ( + torch.rand(7), + 0, + True, + ), + "rank_2_keepdim": lambda: ( + torch.rand(7, 3), + (0, 1), + True, + ), + "rank_3_keepdim": lambda: ( + torch.rand(5, 7, 3), + (0, 1, 2), + True, + ), + "rand_1_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1), + True, + ), + "rand_2_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (2), + True, + ), + "rand_3_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (3), + True, + ), + "rand_12_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1, 2), + True, + ), + "rand_13_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1, 3), + True, + ), + "rand_23_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (2, 3), + True, + ), + "rand_123_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (1, 2, 3), + True, + ), + "rand_0123_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + (0, 1, 2, 3), + True, + ), + "rand_none_keepdim": lambda: ( + torch.rand(1, 5, 7, 3), + None, + True, + ), + "rank_1": lambda: ( + torch.rand(7), + (-1), + False, + ), + "rank_2": lambda: ( + torch.rand(5, 7), + (-2, -1), + False, + ), + "rank_3": lambda: ( + torch.rand(5, 7, 3), + (-3, -2, -1), + False, + ), + "rand_1": lambda: ( + torch.rand(1, 5, 7, 3), + (-3), + False, + ), + "rand_2": lambda: ( + torch.rand(1, 5, 7, 3), + (-2), + False, + ), + "rand_3": lambda: ( + torch.rand(1, 5, 7, 3), + (-1), + False, + ), + "rand_12": lambda: ( + torch.rand(1, 5, 7, 3), + (-3, -2), + False, + ), + "rand_13": lambda: ( + torch.rand(1, 5, 7, 3), + (-3, -1), + False, + ), + "rand_23": lambda: ( + torch.rand(1, 5, 7, 3), + (-2, -1), + False, + ), + "rand_123": lambda: ( + torch.rand(1, 5, 7, 3), + (-3, -2, -1), + False, + ), + "rand_0123": lambda: ( + torch.rand(1, 5, 7, 3), + (-4, -3, -2, -1), + False, + ), + "rank5_01234": lambda: ( + torch.rand(1, 1, 7, 3, 2), + (-5, -4, -3, -2, -1), + False, + ), + "rank5_234": lambda: ( + torch.rand(1, 1, 7, 3, 2), + (-3, -2, -1), + False, + ), + "rank5_12": lambda: ( + torch.rand(1, 1, 7, 3, 2), + (1, 2), + False, + ), + "rank5_2": lambda: ( + torch.rand(1, 4, 7, 3, 2), + (2), + False, + ), + "u55_avg_pool_not_supported": lambda: ( + torch.rand(1, 1, 1, 257), + (0, 1, 2, 3), + True, + ), + } + torch_op = "torch.ops.aten.mean.dim" + exir_op = "executorch_exir_dialects_edge__ops_aten_mean_dim" + + def __init__(self, dim: int | list[int] = -1, keepdim: bool = True): + super().__init__() + self.dim = dim + self.keepdim = keepdim + + def forward(self, x: torch.Tensor): + return x.mean(dim=self.dim, keepdim=self.keepdim) + + +@common.parametrize("test_data", MeanDim.test_data_suite) +def test_mean_dim_tosa_FP(test_data): + test_data, dim, keep_dim = test_data() + TosaPipelineFP[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + MeanDim.torch_op, + MeanDim.exir_op, + ).run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +def test_mean_dim_tosa_INT(test_data): + test_data, dim, keep_dim = test_data() + pipeline = TosaPipelineINT[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.XfailIfNoCorstone300 +def test_mean_dim_u55_INT(test_data): + test_data, dim, keep_dim = test_data() + pipeline = EthosU55PipelineINT[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.add_stage_after( + "export", + pipeline.tester.check_not, + ["torch.ops.aten.adaptive_avg_pool2d.default"], + suffix="avg_pool", + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.XfailIfNoCorstone320 +def test_mean_dim_u85_INT(test_data): + test_data, dim, keep_dim = test_data() + pipeline = EthosU85PipelineINT[input_t]( + MeanDim(dim, keep_dim), + (test_data,), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.SkipIfNoModelConverter +def test_mean_dim_vgf_no_quant(test_data): + test_data_val, dim, keep_dim = test_data() + pipeline = VgfPipeline[input_t]( + MeanDim(dim, keep_dim), + (test_data_val,), + MeanDim.torch_op, + MeanDim.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDim.test_data_suite) +@common.SkipIfNoModelConverter +def test_mean_dim_vgf_quant(test_data): + test_data_val, dim, keep_dim = test_data() + pipeline = VgfPipeline[input_t]( + MeanDim(dim, keep_dim), + (test_data_val,), + [], + symmetric_io_quantization=True, + quantize=True, + ) + pipeline.run() + + +mean_input_t = tuple[torch.Tensor, bool] + + +class MeanDefault(torch.nn.Module): + def forward(self, tensor: torch.Tensor, keepdim: bool): + return tensor.mean() + + test_data_suite: dict[str, Callable[[], mean_input_t]] = { + "rank1": lambda: ( + torch.rand( + 1, + ), + False, + ), + "rank2": lambda: (torch.rand(5, 5), True), + "rank4": lambda: (torch.rand(5, 1, 10, 1), False), + } + + +@common.parametrize("test_data", MeanDefault.test_data_suite) +def test_mean_tosa_FP(test_data): + pipeline = TosaPipelineFP[mean_input_t]( + MeanDefault(), + test_data(), + [], # Might be sum, avgpool, or both + ) + pipeline.run() + + +@common.parametrize("test_data", MeanDefault.test_data_suite) +def test_mean_tosa_INT(test_data): + pipeline = TosaPipelineINT[mean_input_t]( + MeanDefault(), + test_data(), + [], # Might be sum, avgpool, or both + symmetric_io_quantization=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_minimum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_minimum.py new file mode 100644 index 0000000..ff706f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_minimum.py @@ -0,0 +1,98 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_t = tuple[torch.Tensor, torch.Tensor] +aten_op = "torch.ops.aten.minimum.default" + + +class Minimum(torch.nn.Module): + test_parameters = { + "float_tensor": lambda: ( + torch.FloatTensor([1, 2, 3, 5, 7]), + (torch.FloatTensor([2, 1, 2, 1, 10])), + ), + "ones": lambda: (torch.ones(1, 10, 4, 6), 2 * torch.ones(1, 10, 4, 6)), + "rand_diff": lambda: (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "rand_same": lambda: (torch.randn(1, 3, 4, 4), torch.randn(1, 3, 4, 4)), + "rand_large": lambda: ( + 10000 * torch.randn(1, 1, 4, 4), + torch.randn(1, 1, 4, 1), + ), + } + + def __init__(self): + super().__init__() + + def forward(self, x, y): + return torch.minimum(x, y) + + +@common.parametrize("test_data", Minimum.test_parameters) +def test_minimum_tosa_FP(test_data: Tuple): + TosaPipelineFP[test_t](Minimum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +def test_minimum_tosa_INT(test_data: Tuple): + TosaPipelineINT[test_t](Minimum(), test_data(), aten_op).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.XfailIfNoCorstone300 +def test_minimum_u55_INT(test_data: Tuple): + EthosU55PipelineINT[test_t]( + Minimum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.XfailIfNoCorstone320 +def test_minimum_u85_INT(test_data: Tuple): + EthosU85PipelineINT[test_t]( + Minimum(), + test_data(), + aten_op, + ).run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.SkipIfNoModelConverter +def test_minimum_vgf_no_quant(test_data: test_t): + pipeline = VgfPipeline[test_t]( + Minimum(), + test_data(), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Minimum.test_parameters) +@common.SkipIfNoModelConverter +def test_minimum_vgf_quant(test_data: test_t): + pipeline = VgfPipeline[test_t]( + Minimum(), + test_data(), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mm.py new file mode 100644 index 0000000..6d02688 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mm.py @@ -0,0 +1,93 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_t = tuple[torch.Tensor, torch.Tensor] + + +class MM(torch.nn.Module): + test_data_generators = { + "rand_2d": lambda: (torch.rand(3, 5), torch.rand(5, 2)), + "rand_same": lambda: (torch.rand(1, 1), torch.rand(1, 1)), + "ones": lambda: (torch.ones(55, 3), torch.ones(3, 44)), + "randn_large": lambda: (10000 * torch.randn(1, 10), torch.randn(10, 5)), + "rand_neg": lambda: (-10 * torch.randn(32, 64), 5 + 5 * torch.randn(64, 32)), + } + aten_op = "torch.ops.aten.mm.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_mm_default" + + def forward(self, x, y): + return torch.mm(x, y) + + +@common.parametrize("test_data", MM.test_data_generators) +def test_mm_tosa_FP(test_data: Tuple): + TosaPipelineFP[test_t](MM(), test_data(), MM.aten_op).run() + + +@common.parametrize("test_data", MM.test_data_generators) +def test_mm_tosa_INT(test_data: Tuple): + TosaPipelineINT[test_t](MM(), test_data(), MM.aten_op, MM.exir_op, qtol=1).run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.XfailIfNoCorstone300 +@pytest.mark.flaky # Investigate flakiness (MLETORCH-870) +def test_mm_u55_INT(test_data: Tuple): + EthosU55PipelineINT[test_t]( + MM(), + test_data(), + MM.aten_op, + ).run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.XfailIfNoCorstone320 +def test_mm_u85_INT(test_data: Tuple): + EthosU85PipelineINT[test_t]( + MM(), + test_data(), + MM.aten_op, + MM.exir_op, + ).run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.SkipIfNoModelConverter +def test_mm_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + MM(), + test_data(), + MM.aten_op, + MM.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", MM.test_data_generators) +@common.SkipIfNoModelConverter +def test_mm_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[test_t]( + MM(), + test_data(), + MM.aten_op, + MM.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mul.py new file mode 100644 index 0000000..a938b4c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_mul.py @@ -0,0 +1,376 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification + +from executorch.backends.xnnpack.test.tester import Quantize + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x +aten_op = "torch.ops.aten.mul.Tensor" + +test_data_suite = { + # (test_name, input, other,) See torch.mul() for info + "op_mul_rank1_rand": lambda: ( + torch.rand(5) * 3.7, + torch.rand(5) * 1.5, + ), + "op_mul_rank2_rand": lambda: ( + torch.rand(4, 5), + torch.rand(1, 5), + ), + "op_mul_rank3_randn": lambda: ( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), + ), + "op_mul_rank4_randn": lambda: ( + torch.randn(1, 10, 25, 20), + torch.randn(1, 10, 25, 20), + ), + "op_mul_rank4_ones_mul_negative": lambda: ( + torch.ones(1, 10, 25, 20), + (-1) * torch.ones(1, 10, 25, 20), + ), + "op_mul_rank4_negative_large_rand": lambda: ( + (-200) * torch.rand(1, 10, 25, 20), + torch.rand(1, 1, 1, 20), + ), + "op_mul_rank4_large_randn": lambda: ( + 200 * torch.randn(1, 10, 25, 20), + torch.rand(1, 10, 25, 1), + ), + "op_mul_rank4_randn_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + ), +} + + +test_data_suite_2 = { + # (test_name, input, other,) See torch.mul() for info + "op_mul_rank2_rand": lambda: ( + torch.rand(4, 5), + torch.rand(5), + ), + "op_mul_rank3_randn": lambda: ( + torch.randn(10, 5, 2), + torch.randn(5, 2), + ), + "op_mul_rank4_randn": lambda: ( + torch.randn(1, 10, 25, 20), + torch.randn(1, 25, 20), + ), + "op_mul_rank4_randn_2": lambda: ( + torch.randn(1, 25, 1), + torch.randn(1, 3, 25, 10), + ), +} + + +test_data_suite_int32 = { + # (test_name, input, other,) See torch.mul() for info + "op_mul_rank4_randn_int32": lambda: ( + torch.randint(0, 10, (1, 10, 25, 20), dtype=torch.int32), + torch.randint(0, 10, (1, 10, 25, 20), dtype=torch.int32), + ), + "op_mul_rank4_randn_mutltiple_broadcasts_int32": lambda: ( + torch.randint(0, 10, (1, 4, 4, 1), dtype=torch.int32), + torch.randint(0, 10, (1, 1, 4, 4), dtype=torch.int32), + ), + "op_mul_rank4_randn_broadcast_int32": lambda: ( + torch.randint(0, 10, (1, 10, 25, 20), dtype=torch.int32), + torch.randint(0, 10, (1, 25, 20), dtype=torch.int32), + ), +} + + +class Mul(torch.nn.Module): + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor, + ): + return input_ * other_ + + +@common.parametrize("test_data", test_data_suite) +def test_mul_tensor_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_2) +def test_mul_tensor_tosa_FP_diff_input_ranks(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +# MLETORCH-1274 Improve data type checks during partitioning +# view/RESHAPE of integer tensor is not supported for +FP profile which causes issues +# with view_copy (RESHAPE) which isn't supported in FP so removing the int32 tests +# to allow for the dtype validation patches to land. +# filter out the 'op_mul_rank4_randn_int32' only +test_data_int32_without_broadcasting = { + k: v for k, v in test_data_suite_int32.items() if k != "op_mul_rank4_randn_int32" +} + + +@common.parametrize("test_data", test_data_int32_without_broadcasting) +def test_mul_tensor_tosa_FP_int32(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_2) +def test_mul_tensor_tosa_INT_diff_input_ranks(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_mul_tensor_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +def test_mul_tensor_tosa_INT_int32(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_mul_tensor_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_mul_tensor_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +@common.XfailIfNoCorstone300 +def test_mul_tensor_u55_INT_int32(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +@common.XfailIfNoCorstone320 +def test_mul_tensor_u85_INT_int32(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +# view/RESHAPE of integer tensor is not supported for +FP profile which causes issues +# with view_copy (RESHAPE) which isn't supported in FP so removing the int32 tests +# to allow for the dtype validation patches to land. + + +@common.parametrize( + "test_data", + test_data_suite | test_data_suite_2 | test_data_int32_without_broadcasting, +) +@common.SkipIfNoModelConverter +def test_mul_tensor_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite | test_data_suite_2) +@common.SkipIfNoModelConverter +def test_mul_tensor_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_int32) +@common.SkipIfNoModelConverter +def test_mul_tensor_vgf_quant_int32(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_mul_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_mul_tensor_16a8w_tosa_INT(test_data: input_t1): + """Test mul operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_mul_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_mul_tensor_16a8w_u55_INT(test_data: input_t1): + """Test mul operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_mul_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_mul_tensor_16a8w_u85_INT(test_data: input_t1): + """Test mul operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Mul(), + test_data(), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_mul_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_multihead_attention.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_multihead_attention.py new file mode 100644 index 0000000..50dcaae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_multihead_attention.py @@ -0,0 +1,138 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class MultiheadAttention(torch.nn.MultiheadAttention): + def forward(self, *args, **kwargs): + return super().forward(*args, **kwargs) + + +input_t1 = tuple[torch.Tensor, torch.nn.Module] +test_suite = { + # test_name, (x,), embed_dim, num_heads, batch_first + "rand_2d": lambda: ( + (torch.rand(6, 3),), + MultiheadAttention(embed_dim=3, num_heads=3, batch_first=True), + ), + "randn_2d": lambda: ( + (torch.randn(2, 4),), + MultiheadAttention(embed_dim=4, num_heads=2, batch_first=True), + ), + "randn_3d": lambda: ( + (torch.randn(3, 2, 4),), + MultiheadAttention(embed_dim=4, num_heads=2, batch_first=False), + ), +} + + +@common.parametrize( + "test_data", + test_suite, +) +def test_multihead_attention_tosa_FP(test_data: input_t1): + test_data, module = test_data() + pipeline = TosaPipelineFP(module, (*test_data, *test_data, *test_data), [], []) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +def test_multihead_attention_tosa_INT(test_data): + test_data, module = test_data() + pipeline = TosaPipelineINT( + module, + (*test_data, *test_data, *test_data), + [], + [], + # TODO: Per-channel quantization is broken (MLETORCH-1144) + per_channel_quantization=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.XfailIfNoCorstone300 +def test_multihead_attention_u55_INT(test_data: input_t1): + test_data, module = test_data() + pipeline = EthosU55PipelineINT( + module, + (*test_data, *test_data, *test_data), + [], + [], + use_to_edge_transform_and_lower=True, + # TODO: Per-channel quantization is broken (MLETORCH-1144) + per_channel_quantization=False, + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.XfailIfNoCorstone320 +def test_multihead_attention_u85_INT(test_data: input_t1): + test_data, module = test_data() + pipeline = EthosU85PipelineINT( + module, + (*test_data, *test_data, *test_data), + [], + [], + use_to_edge_transform_and_lower=True, + # TODO: Per-channel quantization is broken (MLETORCH-1144) + per_channel_quantization=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.SkipIfNoModelConverter +def test_multihead_attention_vgf_no_quant(test_data: input_t1): + test_data_vals, module = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (*test_data_vals, *test_data_vals, *test_data_vals), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + test_suite, +) +@common.SkipIfNoModelConverter +def test_multihead_attention_vgf_quant(test_data: input_t1): + test_data_vals, module = test_data() + pipeline = VgfPipeline[input_t1]( + module, + (*test_data_vals, *test_data_vals, *test_data_vals), + [], + [], + per_channel_quantization=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ne.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ne.py new file mode 100644 index 0000000..9fa1b1d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ne.py @@ -0,0 +1,243 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t = Tuple[torch.Tensor] + + +class NotEqual(torch.nn.Module): + aten_op_Tensor = "torch.ops.aten.ne.Tensor" + aten_op_Scalar = "torch.ops.aten.ne.Scalar" + decomposed_ops = ["torch.ops.aten.eq.Tensor", "torch.ops.aten.logical_not.default"] + decomposed_exir_ops = [ + "executorch_exir_dialects_edge__ops_aten_eq_Tensor", + "executorch_exir_dialects_edge__ops_aten_logical_not_default", + ] + exir_op = "executorch_exir_dialects_edge__ops_aten_ne_Tensor" + + def __init__(self, input, other): + super().__init__() + self.input_ = input + self.other_ = other + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor | int | float, + ): + return input_ != other_ + + def get_inputs(self): + return (self.input_, self.other_) + + +op_ne_tensor_rank1_ones = NotEqual( + torch.ones(5), + torch.ones(5), +) +op_ne_tensor_rank2_rand = NotEqual( + torch.rand(4, 5), + torch.rand(1, 5), +) +op_ne_tensor_rank3_randn = NotEqual( + torch.randn(10, 5, 2), + torch.randn(10, 5, 2), +) +op_ne_tensor_rank4_randn = NotEqual( + torch.randn(3, 2, 2, 2), + torch.randn(3, 2, 2, 2), +) + +op_ne_scalar_rank1_ones = NotEqual(torch.ones(5), 1.0) +op_ne_scalar_rank2_rand = NotEqual(torch.rand(4, 5), 0.2) +op_ne_scalar_rank3_randn = NotEqual(torch.randn(10, 5, 2), -0.1) +op_ne_scalar_rank4_randn = NotEqual(torch.randn(3, 2, 2, 2), 0.3) +op_ne_scalar_rank4_randn_1batch = NotEqual(torch.randn(1, 2, 2, 2), 0.3) + +test_data_tensor = { + "ne_tensor_rank1_ones": op_ne_tensor_rank1_ones, + "ne_tensor_rank2_rand": op_ne_tensor_rank2_rand, + "ne_tensor_rank3_randn": op_ne_tensor_rank3_randn, + "ne_tensor_rank4_randn": op_ne_tensor_rank4_randn, +} + +test_data_scalar = { + "ne_scalar_rank1_ones": op_ne_scalar_rank1_ones, + "ne_scalar_rank2_rand": op_ne_scalar_rank2_rand, + "ne_scalar_rank3_randn": op_ne_scalar_rank3_randn, + "ne_scalar_rank4_randn": op_ne_scalar_rank4_randn, + "ne_scalar_rank4_randn_1batch": op_ne_scalar_rank4_randn_1batch, +} + + +@common.parametrize("test_module", test_data_tensor) +def test_ne_tensor_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module, test_module.get_inputs(), NotEqual.aten_op_Tensor, NotEqual.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ne_scalar_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.aten_op_Scalar, + NotEqual.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +def test_ne_tensor_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module, test_module.get_inputs(), NotEqual.decomposed_ops, NotEqual.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +def test_ne_scalar_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module, test_module.get_inputs(), NotEqual.decomposed_ops, NotEqual.exir_op + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.XfailIfNoCorstone300 +def test_ne_tensor_u55_INT(test_module): + # EQUAL is not supported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module, + test_module.get_inputs(), + { + NotEqual.decomposed_exir_ops[0]: 1, + NotEqual.decomposed_exir_ops[1]: 1, + }, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.XfailIfNoCorstone300 +def test_ne_scalar_u55_INT(test_module): + # Not equal (ne) is decomposed into the TOSA ops EQUAL and LOGICAL_NOT, both of + # which are unsupported on U55. + pipeline = OpNotSupportedPipeline[input_t]( + test_module, + test_module.get_inputs(), + { + NotEqual.decomposed_exir_ops[0]: 1, + NotEqual.decomposed_exir_ops[1]: 1, + }, + quantize=True, + u55_subset=True, + n_expected_delegates=1, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_tensor, + strict=False, +) +@common.XfailIfNoCorstone320 +def test_ne_tensor_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.decomposed_exir_ops, + ) + pipeline.run() + + +@common.parametrize( + "test_module", + test_data_scalar, + xfails={ + "ne_scalar_rank4_randn_1batch": "MLETORCH-847: Boolean ne result unstable on U85", + }, + strict=False, +) +@common.XfailIfNoCorstone320 +def test_ne_scalar_u85_INT(test_module): + pipeline = EthosU85PipelineINT[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.decomposed_exir_ops, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ne_tensor_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.aten_op_Tensor, + NotEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_tensor) +@common.SkipIfNoModelConverter +def test_ne_tensor_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ne_scalar_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.aten_op_Scalar, + NotEqual.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_scalar) +@common.SkipIfNoModelConverter +def test_ne_scalar_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module, + test_module.get_inputs(), + NotEqual.decomposed_ops, + NotEqual.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_neg.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_neg.py new file mode 100644 index 0000000..11d1153 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_neg.py @@ -0,0 +1,99 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] + + +class Neg(torch.nn.Module): + + aten_op = "torch.ops.aten.neg.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_neg_default" + + test_data: Dict[str, input_t1] = { + "rank_1_ramp": (torch.arange(-16, 16, 0.2),), + "rank_2_rand_uniform": (torch.rand(10, 10) - 0.5,), + "rank_3_all_ones": (torch.ones(10, 10, 10),), + "rank_4_all_zeros": (torch.zeros(1, 10, 10, 10),), + "rank_4_randn_pos": (torch.randn(1, 4, 4, 4) + 10,), + "rank_4_randn_neg": (torch.randn(1, 4, 4, 4) - 10,), + } + + def forward(self, x: torch.Tensor): + return torch.neg(x) + + +@common.parametrize("test_data", Neg.test_data) +def test_neg_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1](Neg(), test_data, Neg.aten_op, Neg.exir_op) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +def test_neg_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1](Neg(), test_data, Neg.aten_op, Neg.exir_op) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.XfailIfNoCorstone300 +def test_neg_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.XfailIfNoCorstone320 +def test_neg_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.SkipIfNoModelConverter +def test_neg_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Neg.test_data) +@common.SkipIfNoModelConverter +def test_neg_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Neg(), + test_data, + Neg.aten_op, + Neg.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ones.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ones.py new file mode 100644 index 0000000..48c7590 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_ones.py @@ -0,0 +1,152 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class OnesAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.ones.default" + + def __init__(self, n: int, dtype: torch.dtype): + super().__init__() + self.args = (n,) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.ones(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)), + "10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (10, torch.int32), + ), + } + + # Mixed dtypes - the ones op is delegated, but it leads to a non-delegated add op. + test_data_mixed_dtypes: dict[str, test_data_t] = { + "fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)), + "fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)), + } + + +@common.parametrize("test_data", OnesAdd.test_data | OnesAdd.test_data_mixed_dtypes) +def test_ones_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data | OnesAdd.test_data_mixed_dtypes) +def test_ones_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.XfailIfNoCorstone300 +def test_ones_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.XfailIfNoCorstone320 +def test_ones_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize( + "test_data", + OnesAdd.test_data_mixed_dtypes, +) +def test_ones_tosa_INT_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + OnesAdd(*init_data), + input_data(), + non_delegated_ops={"executorch_exir_dialects_edge__ops_aten_add_Tensor": 1}, + n_expected_delegates=1, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.SkipIfNoModelConverter +def test_ones_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", OnesAdd.test_data) +@common.SkipIfNoModelConverter +def test_ones_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + OnesAdd(*init_data), + input_data(), + OnesAdd.aten_op, + quantize=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_permute.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_permute.py new file mode 100644 index 0000000..f6c6aeb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_permute.py @@ -0,0 +1,256 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.permute.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_permute_copy_default" + +test_data_suite_u55 = { + # (test_name,test_data,dims) + "rank_2": lambda: (torch.rand(10, 10), [1, 0]), + "rank_3": lambda: (torch.rand(10, 10, 10), [2, 0, 1]), + "rank_3_2": lambda: (torch.rand(10, 10, 10), [1, 2, 0]), + "rank_4": lambda: (torch.rand(1, 5, 1, 10), [0, 2, 3, 1]), + "rank_4_2": lambda: (torch.rand(1, 2, 5, 10), [1, 0, 2, 3]), + "rank_4_3": lambda: (torch.rand(1, 10, 10, 5), [2, 0, 1, 3]), + "rank_4_large": lambda: (torch.rand(2, 8, 64, 65), [0, 2, 3, 1]), + "rank_3_large": lambda: (torch.rand(16, 64, 65), [1, 2, 0]), + "reshape_large_1": lambda: (torch.rand(1, 1, 65537), [0, 2, 1]), + "reshape_large_2": lambda: (torch.rand(65537, 1, 1), [1, 2, 0]), +} + +test_data_suite_u55_reject = { + "rank2_bool": lambda: (torch.randint(0, 2, (5, 5), dtype=torch.bool), [1, 0]), +} +test_data_suite = test_data_suite_u55.copy() | test_data_suite_u55_reject.copy() + + +class SimplePermute(torch.nn.Module): + + def __init__(self, dims: list[int]): + super().__init__() + + self.dims = dims + + def forward(self, x): + return torch.permute(x, self.dims) + + +@common.parametrize("test_data", test_data_suite) +def test_permute_tosa_FP(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = TosaPipelineFP[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_permute_tosa_INT(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = TosaPipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55) +@common.XfailIfNoCorstone300 +def test_permute_u55_INT(test_data): + test_data, dims = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops="executorch_exir_dialects_edge__ops_aten_permute_copy_default", + ) + if test_data[0].dtype == torch.bool: + pipeline.pop_stage("check_count.exir") + pipeline.tester.use_portable_ops = True + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55_reject) +def test_permute_u55_INT_not_delegated(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + SimplePermute(dims=dims), + (test_data,), + non_delegated_ops={exir_op: 1}, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_permute_u85_INT(test_data: torch.Tensor): + test_data, dims = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops="executorch_exir_dialects_edge__ops_aten_permute_copy_default", + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_permute_vgf_no_quant(test_data): + test_data, dims = test_data() + pipeline = VgfPipeline[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_permute_vgf_quant(test_data): + test_data, dims = test_data() + pipeline = VgfPipeline[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_permute_quantizer( + u55_config=False, per_channel_quantization=False +): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_permute_16a8w_tosa_INT(test_data: torch.Tensor): + """Test permute operation with int16 quantization""" + test_data, dims = test_data() + pipeline = TosaPipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_op=[], + per_channel_quantization=False, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_permute_quantizer(per_channel_quantization=False), + ) + # Run the pipeline + pipeline.run() + + +test_data_suite_exact = { + x: test_data_suite[x] + for x in test_data_suite + if x not in ("rank_4_3", "rank2_bool") +} + + +@common.parametrize( + "test_data", + test_data_suite_exact, +) +@common.XfailIfNoCorstone300 +def test_permute_16a8w_u55_INT(test_data: torch.Tensor): + """Test permute operation with int16 quantization on U55""" + test_data, dims = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops=[], + per_channel_quantization=True, + use_to_edge_transform_and_lower=True, + atol=1e-02, + rtol=1e-02, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_permute_quantizer(per_channel_quantization=False), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_permute_16a8w_u85_INT(test_data: torch.Tensor): + """Test permute operation with int16 quantization on U85""" + test_data, dims = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + SimplePermute(dims=dims), + (test_data,), + aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + atol=1e-03, + rtol=1e-03, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_permute_quantizer(per_channel_quantization=False), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pixel_shuffling.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pixel_shuffling.py new file mode 100644 index 0000000..0c3436d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pixel_shuffling.py @@ -0,0 +1,237 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.constants import MAX_RANK + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from torch import nn + +aten_op_pixel_unshuffle = "torch.ops.aten.pixel_unshuffle.default" +exir_op_pixel_unshuffle = ( + "executorch_exir_dialects_edge__ops_aten_pixel_unshuffle_default" +) + +aten_op_pixel_shuffle = "torch.ops.aten.pixel_shuffle.default" +exir_op_pixel_shuffle = "executorch_exir_dialects_edge__ops_aten_pixel_shuffle_default" + +input_t1 = Tuple[torch.Tensor] # single positional input (1-tuple) + +max_rank_input_supported = MAX_RANK - 2 + + +class PixelUnShuffle(nn.Module): + + upscale_factor = 2 + test_data_generators = { + "rand_4d": lambda: (torch.randn(1, 12, 64, 64),), + "test_4d": lambda: (torch.tensor([[[[10.0, 20.0], [30.0, 40.0]]]]),), + "test_3d": lambda: (torch.tensor([[[10.0, 20.0], [30.0, 40.0]]]),), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.space_to_depth = nn.PixelUnshuffle(self.upscale_factor) + + def forward(self, inputs: torch.Tensor) -> torch.Tensor: + if inputs.dim() > max_rank_input_supported: + raise RuntimeError( + f"Max rank of input for pixel_unshuffle is currently {max_rank_input_supported}, got {inputs.dim()}" + ) + return self.space_to_depth(inputs) + + +class PixelShuffle(nn.Module): + + upscale_factor = 2 + test_data_generators = { + "rand_4d": lambda: (torch.randn(1, 12, 64, 64),), + "test_4d": lambda: (torch.tensor([[[[10.0]], [[20.0]], [[30.0]], [[40.0]]]]),), + "test_3d": lambda: (torch.tensor([[[10.0]], [[20.0]], [[30.0]], [[40.0]]]),), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.depth_to_space = nn.PixelShuffle(self.upscale_factor) + + def forward(self, inputs: torch.Tensor) -> torch.Tensor: + if inputs.dim() > max_rank_input_supported: + raise RuntimeError( + f"Max rank of input for pixel_shuffle is currently {max_rank_input_supported}, got {inputs.dim()}" + ) + return self.depth_to_space(inputs) + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +def test_pixel_unshuffle_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +def test_pixel_unshuffle_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +def test_pixel_shuffle_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +def test_pixel_shuffle_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_unshuffle_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_unshuffle_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_shuffle_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +@common.SkipIfNoModelConverter +def test_pixel_shuffle_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelUnShuffle.test_data_generators) +@common.XfailIfNoCorstone300 +def test_pixel_unshuffle_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_fvp=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + PixelUnShuffle.test_data_generators, + xfails={"rand_4d": "MLETORCH-1424: rand test fails"}, +) +@common.XfailIfNoCorstone320 +def test_pixel_unshuffle_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + PixelUnShuffle(), + test_data(), + aten_op_pixel_unshuffle, + exir_op_pixel_unshuffle, + run_on_fvp=True, + ) + pipeline.run() + + +@common.parametrize("test_data", PixelShuffle.test_data_generators) +@common.XfailIfNoCorstone300 +def test_pixel_shuffle_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_fvp=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + PixelShuffle.test_data_generators, + xfails={"rand_4d": "MLETORCH-1424: rand test fails"}, +) +@common.XfailIfNoCorstone320 +def test_pixel_shuffle_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + PixelShuffle(), + test_data(), + aten_op_pixel_shuffle, + exir_op_pixel_shuffle, + run_on_fvp=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pow.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pow.py new file mode 100644 index 0000000..1955ff4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_pow.py @@ -0,0 +1,204 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Pow_TensorTensor(torch.nn.Module): + aten_op = "torch.ops.aten.pow.Tensor_Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Tensor" + + input_t = Tuple[torch.Tensor | float, torch.Tensor | float] + + # The sign of the operands are important w.r.t. TOSA's spec of pow + test_data = { + "zero_base_pos_exp": lambda: ( + torch.zeros(1, 8, 3, 7), + torch.abs(torch.randn((1, 8, 1, 7))) + 1e5, + ), + "pos_base": lambda: ( + torch.abs(torch.randn((3, 2, 4, 2))) + 1e5, + torch.randn((1, 2, 4, 1)), + ), + "zero_base_zero_exp": lambda: (torch.zeros(2, 3), torch.zeros(2, 3)), + "pos_base_zero_exp": lambda: ( + torch.abs(torch.randn((1, 7, 2, 3))) + 1e5, + torch.zeros(1, 1, 2, 3), + ), + "neg_base_zero_exp": lambda: ( + -torch.abs(torch.randn((1, 2, 3, 4))) - 1e5, + torch.zeros(1, 2, 3, 4), + ), + "base_has_lower_rank": lambda: (torch.ones(3, 4), torch.ones(1, 2, 3, 4)), + "exp_has_lower_rank": lambda: (torch.ones(1, 2, 3, 4), torch.ones(3, 4)), + "f16_tensors": lambda: ( + torch.HalfTensor([[1.0, 2.0, 3.0], [0.5, 1.5, 2.5]]), + torch.HalfTensor([[1.0, 2.0, 0.0]]), + ), + } + + def forward(self, x: torch.Tensor | float, y: torch.Tensor | float): + return torch.pow(x, y) + + +class Pow_TensorScalar(torch.nn.Module): + aten_op = "torch.ops.aten.pow.Tensor_Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar" + + input_t = Tuple[torch.Tensor] + + test_data = { + # Test whole number exponents + "exp_minus_three": lambda: (torch.randn((10, 5)).relu() + 0.1, -3.0), + "exp_minus_one": lambda: (torch.randn((42,)).relu() + 0.1, -1.0), + "exp_zero": lambda: (torch.randn((1, 2, 3, 7)).relu(), 0.0), + "exp_one": lambda: (torch.randn((1, 4, 6, 2)).relu(), 1.0), + "exp_two": lambda: (torch.randn((1, 2, 3, 6)), 2.0), + # Test decimal exponent (base must be non-negative) + "non_neg_base_exp_pos_decimal": lambda: ( + torch.abs(torch.randn((1, 2, 3, 6))), + 6.789, + ), + "neg_base_exp_pos_integer": lambda: ( + -torch.abs(torch.randn((1, 2, 3, 6))) - 10, + 3, + ), + } + + def __init__(self, exp): + super().__init__() + self.exp = exp + + def forward(self, x: torch.Tensor): + return torch.pow(x, self.exp) + + +x_fail = { + "zero_base_zero_exp": "TOSA constraints: If x == 0 and y ⇐ 0, the result is undefined.", + "neg_base_zero_exp": "TOSA constraints: If x == 0 and y ⇐ 0, the result is undefined.", +} + + +@common.parametrize("test_data", Pow_TensorTensor.test_data, x_fail, strict=False) +def test_pow_tensor_tensor_tosa_FP(test_data: Pow_TensorTensor.input_t): + pipeline = TosaPipelineFP[Pow_TensorTensor.input_t]( + Pow_TensorTensor(), + test_data(), + Pow_TensorTensor.aten_op, + Pow_TensorTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorTensor.test_data, x_fail, strict=False) +@common.SkipIfNoModelConverter +def test_pow_tensor_tensor_vgf_no_quant(test_data: Pow_TensorTensor.input_t): + pipeline = VgfPipeline[Pow_TensorTensor.input_t]( + Pow_TensorTensor(), + test_data(), + Pow_TensorTensor.aten_op, + Pow_TensorTensor.exir_op, + quantize=False, + ) + pipeline.run() + + +x_fail = { + "exp_two": "TOSA constraints: If x <0 .", +} + + +@common.parametrize( + "test_data", Pow_TensorScalar.test_data, xfails=x_fail, strict=False +) +def test_pow_tensor_scalar_tosa_FP(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = TosaPipelineFP[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data, strict=False) +def test_pow_tensor_scalar_tosa_INT(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = TosaPipelineINT[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data) +@common.XfailIfNoCorstone300 +def test_pow_tensor_scalar_u55_INT(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = EthosU55PipelineINT[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data) +@common.XfailIfNoCorstone320 +def test_pow_tensor_scalar_u85_INT(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = EthosU85PipelineINT[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Pow_TensorScalar.test_data, x_fail, strict=False) +@common.SkipIfNoModelConverter +def test_pow_tensor_scalar_vgf_no_quant(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = VgfPipeline[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + Pow_TensorScalar.test_data, +) +@common.SkipIfNoModelConverter +def test_pow_tensor_scalar_vgf_quant(test_data: Pow_TensorScalar.input_t): + base, exp = test_data() + pipeline = VgfPipeline[Pow_TensorScalar.input_t]( + Pow_TensorScalar(exp), + (base,), + Pow_TensorScalar.aten_op, + Pow_TensorScalar.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_reciprocal.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_reciprocal.py new file mode 100644 index 0000000..5d09dfd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_reciprocal.py @@ -0,0 +1,112 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x, Input y +aten_op = "torch.ops.aten.reciprocal.default" + +test_data_suite = { + "op_reciprocal_rank1_ones": lambda: torch.ones(5), + "op_reciprocal_rank1_rand": lambda: torch.rand(5) * 5, + "op_reciprocal_rank1_negative_ones": lambda: torch.ones(5) * (-1), + "op_reciprocal_rank4_ones": lambda: torch.ones(1, 10, 25, 20), + "op_reciprocal_rank4_negative_ones": lambda: (-1) * torch.ones(1, 10, 25, 20), + "op_reciprocal_rank4_ones_reciprocal_negative": lambda: torch.ones(1, 10, 25, 20), + "op_reciprocal_rank4_large_rand": lambda: 200 * torch.rand(1, 10, 25, 20), + "op_reciprocal_rank4_negative_large_rand": lambda: (-200) + * torch.rand(1, 10, 25, 20), + "op_reciprocal_rank4_large_randn": lambda: 200 * torch.randn(1, 10, 25, 20) + 1, +} + + +class Reciprocal(torch.nn.Module): + + def forward(self, input_: torch.Tensor): + return input_.reciprocal() + + +@common.parametrize("test_data", test_data_suite) +def test_reciprocal_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_reciprocal_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_reciprocal_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_reciprocal_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + exir_ops=[], + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_reciprocal_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_reciprocal_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Reciprocal(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_relu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_relu.py new file mode 100644 index 0000000..4044cb2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_relu.py @@ -0,0 +1,166 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.relu.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_relu_default" + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Relu(torch.nn.Module): + def __init__(self): + super().__init__() + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.relu(x) + + +test_data_conv_relu = { + # (test_name, test_data) + "4d_randn_inplace=True": (lambda: (torch.randn(1, 64, 96, 96) * 1000, True)), + "4d_randn_inplace=False": (lambda: (torch.randn(1, 64, 96, 96) * 1000, False)), +} + + +class Conv2d_Relu_Add(torch.nn.Module): + def __init__(self, inplace: bool = True): + super().__init__() + self.conv1 = torch.nn.Conv2d( + in_channels=64, out_channels=64, kernel_size=7, padding="same" + ) + self.relu = torch.nn.ReLU(inplace=inplace) + + def forward(self, x: torch.Tensor): + y = self.conv1(x) + z = self.relu(y) + out = x + z + return out + + +@common.parametrize("test_data", test_data_suite) +def test_relu_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +# Test the folding of Conv2D with ReLU +@common.parametrize("test_data", test_data_conv_relu) +def test_relu_tosa_INT_conv_folding(test_data: torch.Tensor): + input_data, inplace = test_data() + pipeline = TosaPipelineINT[input_t1]( + Conv2d_Relu_Add(inplace=inplace), + (input_data,), + [], + [], + ) + # We should have : + # 3 quantize_per_tensor nodes: input activation , output of the conv-relu sequence, out of the add + # 4 dequantize_per_tensor nodes: into the conv2d input, into the add, output of the conv-relu sequence, before returning + # 2 dequantize_per_channel nodes: one for the weights and another one for the bias + # In case of incorrect annotation of the ReLU, we get separate Q/DR around both the conv2d and the ReLU and + # therefore more quantize_per_tensor and dequantize_per_tensor nodes + pipeline.add_stage_after( + "quantize", + pipeline.tester.check_count, + { + "quantized_decomposed.quantize_per_tensor.default": 3, + "torch.ops.quantized_decomposed.dequantize_per_tensor.default": 4, + "quantized_decomposed.dequantize_per_channel.default": 2, + }, + suffix="quant_nodes", + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_relu_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_relu_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_relu_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_relu_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_relu_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Relu(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_remainder.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_remainder.py new file mode 100644 index 0000000..d1874d1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_remainder.py @@ -0,0 +1,199 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +def _nonzero_float_tensor(*shape: int) -> torch.Tensor: + return torch.rand(*shape, dtype=torch.float32) * 5 + 0.1 + + +class Remainder(torch.nn.Module): + input_t = Tuple[torch.Tensor | float, torch.Tensor | float] + + aten_op_tensor = "torch.ops.aten.remainder.Tensor" + exir_op_tensor = "executorch_exir_dialects_edge__ops_aten_remainder_Tensor" + aten_op_scalar = "torch.ops.aten.remainder.Scalar" + exir_op_scalar = "executorch_exir_dialects_edge__ops_aten_remainder_Scalar" + + test_cases_tensor = { + "rank2_tensors": lambda: ( + torch.randn(2, 3) * 7, + _nonzero_float_tensor(2, 3), + ), + "rank4_tensors": lambda: ( + torch.randn(1, 4, 2, 3) * 7, + _nonzero_float_tensor(1, 4, 2, 3), + ), + "broadcast": lambda: ( + torch.randn(4, 5, 1), + _nonzero_float_tensor(1, 5, 6), + ), + } + + test_cases_scalar = { + "scalar_pos": lambda: ( + torch.randn(1, 2, 3, 4), + 0.25, + ), + "scalar_neg": lambda: ( + torch.randn(3, 4), + -0.25, + ), + } + + def forward(self, x: torch.Tensor | float, y: torch.Tensor | float) -> torch.Tensor: + return torch.remainder(x, y) + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +def test_remainder_tensor_tosa_FP(test_data): + data = test_data() + pipeline = TosaPipelineFP[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_tensor, + Remainder.exir_op_tensor, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +def test_remainder_scalar_tosa_FP(test_data): + data = test_data() + pipeline = TosaPipelineFP[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_scalar, + Remainder.exir_op_scalar, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +def test_remainder_tensor_tosa_INT(test_data): + pipeline = TosaPipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +def test_remainder_scalar_tosa_INT(test_data): + pipeline = TosaPipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.XfailIfNoCorstone300 +def test_remainder_tensor_u55_INT(test_data): + pipeline = EthosU55PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.XfailIfNoCorstone300 +def test_remainder_scalar_u55_INT(test_data): + pipeline = EthosU55PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.XfailIfNoCorstone320 +def test_remainder_tensor_u85_INT(test_data): + pipeline = EthosU85PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.XfailIfNoCorstone320 +def test_remainder_scalar_u85_INT(test_data): + pipeline = EthosU85PipelineINT[Remainder.input_t]( + Remainder(), + test_data(), + [], + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.SkipIfNoModelConverter +def test_remainder_tensor_vgf_no_quant(test_data): + data = test_data() + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_tensor, + Remainder.exir_op_tensor, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.SkipIfNoModelConverter +def test_remainder_scalar_vgf_no_quant(test_data): + data = test_data() + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + data, + Remainder.aten_op_scalar, + Remainder.exir_op_scalar, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_tensor) +@common.SkipIfNoModelConverter +def test_remainder_tensor_vgf_quant(test_data): + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + test_data(), + [], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Remainder.test_cases_scalar) +@common.SkipIfNoModelConverter +def test_remainder_scalar_vgf_quant(test_data): + pipeline = VgfPipeline[Remainder.input_t]( + Remainder(), + test_data(), + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_repeat.py new file mode 100644 index 0000000..0b3de3b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_repeat.py @@ -0,0 +1,162 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the repeat op which copies the data of the input tensor (possibly with new data format) +# + + +from typing import Sequence, Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, Input y + + +"""Tests Tensor.repeat for different ranks and dimensions.""" + + +class Repeat(torch.nn.Module): + aten_op = "torch.ops.aten.repeat.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_repeat_default" + + def __init__(self, multiples: Sequence[int]): + super().__init__() + self.multiples = multiples + + def forward(self, x: torch.Tensor): + return x.repeat(self.multiples) + + +class RepeatInterleaveInt(torch.nn.Module): + aten_op = "torch.ops.aten.repeat_interleave.self_int" + + def __init__(self, repeats: int, dim: int): + super().__init__() + self.repeats = repeats + self.dim = dim + + def forward(self, x: torch.Tensor): + return x.repeat_interleave(self.repeats, self.dim) + + +test_data_suite_u55 = { + # test_name : lambda: (module, test_data) + "1_x_1": lambda: (Repeat((2,)), (torch.randn(3),)), + "2_x_2": lambda: (Repeat((2, 1)), (torch.randn(3, 4),)), + "4_x_4": lambda: (Repeat((1, 2, 3, 4)), (torch.randn(1, 1, 2, 2),)), + "1_x_2": lambda: (Repeat((2, 2)), (torch.randn(3),)), + "1_x_3": lambda: (Repeat((1, 2, 3)), (torch.randn(3),)), + "2_x_3": lambda: (Repeat((2, 2, 2)), (torch.randn((3, 3)),)), + "1_x_4": lambda: (Repeat((2, 1, 2, 4)), (torch.randn((3, 3, 3)),)), + "interleave_int_3_x_1": lambda: (RepeatInterleaveInt(3, 1), (torch.randn(3, 4),)), +} +test_data_suite_u55_reject = { + "1_x_1_bool": lambda: ( + Repeat((2,)), + (torch.randint(0, 2, (3,), dtype=torch.bool),), + ), +} +test_data_suite = test_data_suite_u55 | test_data_suite_u55_reject + + +@common.parametrize("test_data", test_data_suite) +def test_repeat_tosa_FP(test_data: Tuple): + module, test_data = test_data() + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + module.aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_repeat_tosa_INT(test_data: Tuple): + module, test_data = test_data() + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + module.aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55) +@common.XfailIfNoCorstone300 +def test_repeat_u55_INT(test_data: Tuple): + module, test_data = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + module, + test_data, + module.aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_u55_reject) +@common.XfailIfNoCorstone300 +def test_repeat_u55_INT_not_delegated(test_data: Tuple): + module, test_data = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + module, + test_data, + non_delegated_ops={module.exir_op: 1}, + u55_subset=True, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_repeat_u85_INT(test_data: Tuple): + module, test_data = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + module, + test_data, + module.aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_repeat_vgf_no_quant(test_data: Tuple): + module, args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + module.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_repeat_vgf_quant(test_data: Tuple): + module, args = test_data() + pipeline = VgfPipeline[input_t1]( + module, + args, + module.aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_round.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_round.py new file mode 100644 index 0000000..572163c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_round.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + +aten_op = "torch.ops.aten.round.default" +exir_op = "executorch_exir_dialects_edge__ops_aten_round_default" + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(1, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Round(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x.round() + + +@common.parametrize("test_data", test_data_suite) +def test_round_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Round(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_round_tosa_INT(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +@pytest.mark.xfail(reason="where.self not supported on U55") +def test_round_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_round_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_round_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Round(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_round_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Round(), + (test_data(),), + [], + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rshift.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rshift.py new file mode 100644 index 0000000..ff3f78f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rshift.py @@ -0,0 +1,226 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.common import ( + XfailIfNoCorstone300, + XfailIfNoCorstone320, +) +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +scalar_input_t = tuple[torch.Tensor, int] + + +class RshiftScalar(torch.nn.Module): + torch_op_FP = "torch.ops.aten.__rshift__.Scalar" + torch_op_INT = "torch.ops.aten.bitwise_right_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_right_shift_Tensor" + test_data = { + "randint_neg_100_int8": lambda: ( + torch.randint(-100, 100, (1, 12, 3, 4), dtype=torch.int8), + 1, + ), + "randint_neg_100_int16": lambda: ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int16), + 5, + ), + "randint_neg_100_int32": lambda: ( + torch.randint(-100, 100, (1, 5, 3, 4), dtype=torch.int32), + 2, + ), + } + + def forward(self, x: torch.Tensor, shift: int): + return x >> shift + + +tensor_input_t = tuple[torch.Tensor, torch.Tensor] + + +class RshiftTensor(torch.nn.Module): + torch_op = "torch.ops.aten.bitwise_right_shift.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_bitwise_right_shift_Tensor" + test_data = { + "randint_neg_128_int8": lambda: ( + torch.randint(-128, 127, (3, 3), dtype=torch.int8), + torch.randint(0, 5, (3, 3), dtype=torch.int8), + ), + "randint_neg_1024_int16": lambda: ( + torch.randint(-1024, 1024, (3, 3, 3), dtype=torch.int16), + torch.randint(0, 5, (3, 3, 3), dtype=torch.int16), + ), + "randint_0_127_int32": lambda: ( + torch.randint(0, 127, (1, 2, 3, 3), dtype=torch.int32), + torch.randint(0, 5, (1, 2, 3, 3), dtype=torch.int32), + ), + } + + def forward(self, x: torch.Tensor, shift: torch.Tensor): + return x.bitwise_right_shift(shift) + + +################## +## RshiftScalar ## +################## + + +@common.parametrize("test_data", RshiftScalar.test_data) +def test_bitwise_right_shift_scalar_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_FP, + RshiftScalar.exir_op, + ).run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +def test_bitwise_right_shift_scalar_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.XfailIfNoCorstone300 +def test_bitwise_right_shift_scalar_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + ) + + # Forced rounding in U55 HW causes off-by-one errors. + pipeline.change_args("run_method_and_compare_outputs", inputs=test_data(), atol=1) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.XfailIfNoCorstone320 +def test_bitwise_right_shift_scalar_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_scalar_vgf_no_quant(test_data): + pipeline = VgfPipeline[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_FP, + RshiftScalar.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftScalar.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_scalar_vgf_quant(test_data): + pipeline = VgfPipeline[scalar_input_t]( + RshiftScalar(), + test_data(), + RshiftScalar.torch_op_INT, + RshiftScalar.exir_op, + quantize=True, + ) + pipeline.run() + + +################## +## RshiftTensor ## +################## + + +@common.parametrize("test_data", RshiftTensor.test_data) +def test_bitwise_right_shift_tensor_tosa_FP(test_data): + TosaPipelineFP[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ).run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +def test_bitwise_right_shift_tensor_tosa_INT(test_data): + pipeline = TosaPipelineINT[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@XfailIfNoCorstone300 +def test_bitwise_right_shift_tensor_u55_INT(test_data): + pipeline = EthosU55PipelineINT[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ) + + # Forced rounding in U55 HW causes off-by-one errors. + pipeline.change_args("run_method_and_compare_outputs", inputs=test_data(), atol=1) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@XfailIfNoCorstone320 +def test_bitwise_right_shift_tensor_u85_INT(test_data): + pipeline = EthosU85PipelineINT[scalar_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_tensor_vgf_no_quant(test_data): + pipeline = VgfPipeline[tensor_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", RshiftTensor.test_data) +@common.SkipIfNoModelConverter +def test_bitwise_right_shift_tensor_vgf_quant(test_data): + pipeline = VgfPipeline[tensor_input_t]( + RshiftTensor(), + test_data(), + RshiftTensor.torch_op, + RshiftTensor.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsqrt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsqrt.py new file mode 100644 index 0000000..d2e805f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsqrt.py @@ -0,0 +1,153 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# +# Tests the rsqrt op. +# + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.rsqrt.default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Rsqrt(torch.nn.Module): + test_parameters = { + "ones_4d": lambda: (torch.ones(1, 10, 10, 10),), + "rand_4d_1": lambda: (torch.rand(1, 10, 10, 10),), + "rand_4d_2": lambda: (torch.rand(1, 5, 10, 20),), + "rand_3d": lambda: (torch.rand(5, 10, 20),), + } + + def forward(self, x: torch.Tensor): + return x.rsqrt() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +def test_rsqrt_tosa_FP(test_tensor: torch.Tensor): + pipeline = TosaPipelineFP[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +def test_rsqrt_tosa_INT(test_tensor: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone300 +def test_rsqrt_u55_INT(test_tensor: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone320 +def test_rsqrt_u85_INT(test_tensor: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.SkipIfNoModelConverter +def test_rsqrt_vgf_no_quant(test_tensor: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.SkipIfNoModelConverter +def test_rsqrt_vgf_quant(test_tensor: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +def test_rsqrt_tosa_INT_a16w8(test_tensor: torch.Tensor): + """Test rsqrt operation with int16 I/O quantization for TOSA INT.""" + # Use wider tolerances for int16 I/O quantization + pipeline = TosaPipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_op=[], + tosa_extensions=["int16"], + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone300 +def test_rsqrt_16a8w_u55_INT16(test_tensor: torch.Tensor): + """Test rsqrt operation with int16 I/O quantization for U55""" + # Use wider tolerances for int16 I/O quantization on U55 + pipeline = EthosU55PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Rsqrt.test_parameters) +@common.XfailIfNoCorstone320 +def test_rsqrt_16a8w_u85_INT(test_tensor: torch.Tensor): + """Test rsqrt operation with int16 I/O quantization for U85""" + # Use wider tolerances for int16 I/O quantization on U85 + pipeline = EthosU85PipelineINT[input_t1]( + Rsqrt(), + test_tensor(), + aten_op, + exir_ops=[], + a16w8_quantization=True, + epsilon=2**16, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsub.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsub.py new file mode 100644 index 0000000..1872521 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_rsub.py @@ -0,0 +1,126 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +rsub_test_data = { + "rand_2D_4x4": lambda: (torch.rand(4, 4), 2), + "rand_3D_4x4x4": lambda: (torch.rand(4, 2, 2), 1.5), + "rand_4D_2x2x4x4": lambda: (torch.rand(2, 2, 4, 4), -1.1), + "rand_4D_big_small": lambda: ( + (10e30) * torch.randn(1, 20, 30, 40), + -0.25, + ), + "zero": lambda: (torch.rand(4, 4), 0), + # "swapped": lambda: (2, torch.rand(4, 4)), # torch.rsub(Scalar, Tensor) is not supported as it is not supported in eager mode. +} + + +class Rsub(torch.nn.Module): + aten_op = "torch.ops.aten.rsub.Scalar" + exir_op = "executorch_exir_dialects_edge__ops_aten_sub_Tensor" + + def forward(self, x: torch.Tensor, y: int): + return torch.rsub(x, y) + + +input_t1 = Tuple[torch.Tensor, torch.Tensor] + + +@common.parametrize("test_data", rsub_test_data) +def test_rsub_scalar_tosa_FP(test_data): + pipeline = TosaPipelineFP[input_t1]( + Rsub(), + test_data(), + aten_op=Rsub.aten_op, + exir_op=Rsub.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +def test_rsub_scalar_tosa_INT(test_data): + """Test Subtraction (TOSA INT)""" + pipeline = TosaPipelineINT[input_t1]( + Rsub(), + test_data(), + aten_op="torch.ops.aten.sub.Tensor", + exir_op=Rsub.exir_op, + use_to_edge_transform_and_lower=False, + qtol=0, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.XfailIfNoCorstone300 +def test_rsub_scalar_u55_INT(test_data): + """Test Subtraction on Ethos-U55 (FVP Mode)""" + pipeline = EthosU55PipelineINT[input_t1]( + Rsub(), + test_data(), + aten_ops="torch.ops.aten.sub.Tensor", + exir_ops=Rsub.exir_op, + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.XfailIfNoCorstone320 +def test_rsub_scalar_u85_INT(test_data): + """Test Subtraction on Ethos-U85 (FVP Mode)""" + pipeline = EthosU85PipelineINT[input_t1]( + Rsub(), + test_data(), + aten_ops="torch.ops.aten.sub.Tensor", + exir_ops=Rsub.exir_op, + run_on_fvp=True, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.SkipIfNoModelConverter +def test_rsub_scalar_vgf_no_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF FP)""" + pipeline = VgfPipeline[input_t1]( + Rsub(), + test_data(), + Rsub.aten_op, + Rsub.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", rsub_test_data) +@common.SkipIfNoModelConverter +def test_rsub_scalar_vgf_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF INT)""" + pipeline = VgfPipeline[input_t1]( + Rsub(), + test_data(), + aten_op="torch.ops.aten.sub.Tensor", + exir_op=Rsub.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalar_tensor.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalar_tensor.py new file mode 100644 index 0000000..bc26507 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalar_tensor.py @@ -0,0 +1,135 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +float_test_data_suite = { + "scalar_tensor_float_1": lambda: (3.7, torch.float32, torch.rand((1, 2, 3, 4))), + "scalar_tensor_float_2": lambda: (66, torch.float32, torch.rand((1, 2, 3))), +} + +int_test_data_suite = { + "scalar_tensor_int32": lambda: ( + 33, + torch.int32, + torch.randint(0, 10, (1, 2), dtype=torch.int32), + ), + "scalar_tensor_int8": lambda: ( + 8, + torch.int8, + torch.rand(1, 2, 3), + ), + "scalar_tensor_int16": lambda: ( + 16 * 16 * 16, + torch.int16, + torch.rand((1,)).unsqueeze(0), # Rank 0 inputs not supported + ), +} + + +class ScalarTensor(torch.nn.Module): + aten_op = "torch.ops.aten.scalar_tensor.default" + + def __init__(self, scalar, dtype=torch.float32): + super().__init__() + self.scalar = scalar + self.dtype = dtype + + def forward(self, x: torch.Tensor): + return torch.scalar_tensor(self.scalar, dtype=self.dtype) + x + + +@common.parametrize( + "test_data", + int_test_data_suite | float_test_data_suite, +) +def test_scalar_tensor_tosa_FP(test_data): # Note TOSA FP supports all types + scalar, dtype, data = test_data() + TosaPipelineFP( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ).run() + + +@common.parametrize( + "test_data", + int_test_data_suite | float_test_data_suite, +) +def test_scalar_tensor_tosa_INT(test_data): + scalar, dtype, data = test_data() + pipeline: TosaPipelineINT = TosaPipelineINT( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", float_test_data_suite) +@common.XfailIfNoCorstone300 +def test_scalar_tensor_u55_INT(test_data): + scalar, dtype, data = test_data() + EthosU55PipelineINT( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ).run() + + +@common.parametrize("test_data", float_test_data_suite) +@common.XfailIfNoCorstone320 +def test_scalar_tensor_u85_INT(test_data): + scalar, dtype, data = test_data() + EthosU85PipelineINT( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + ).run() + + +@common.parametrize("test_data", float_test_data_suite) +@common.SkipIfNoModelConverter +def test_scalar_tensor_vgf_no_quant(test_data): + scalar, dtype, data = test_data() + pipeline = VgfPipeline( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + int_test_data_suite, +) +@common.SkipIfNoModelConverter +def test_scalar_tensor_vgf_quant(test_data): + scalar, dtype, data = test_data() + pipeline = VgfPipeline( + ScalarTensor(scalar, dtype), + tuple(data), + ScalarTensor.aten_op, + quantize=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalars.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalars.py new file mode 100644 index 0000000..b3704c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_scalars.py @@ -0,0 +1,438 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import pytest + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +""" +Summary of non-working cases. +FP: + Op(scalar, tensor): + One issue is that lift_constant_tensor_pass looks for a fake_tensor in the meta of the first + node which does not work the first node is a scalar. + Fixing that, the lowering fails since edge_program.graph_signatures.inputs_to_buffers is changed from + {"_lifted_tensor_constant0":"_lifted_tensor_constant0"} to {"x":"_lifted_tensor_constant0"} + somewhere in _transform in the to_edge step. This makes ArmPartitioner miss tagging the + data in tag_constant_data. + # MLETORCH-408 + Sub or inplace-sub with an integer input. +""" +input_t1 = Tuple[torch.Tensor, torch.scalar_tensor] # Input x, Input y + + +"""Tests various scalar cases""" + + +class Add(torch.nn.Module): + aten_op = "torch.ops.aten.add.Tensor" + + def forward(self, x, y): + return x + y + + +class Sub(torch.nn.Module): + aten_op = "torch.ops.aten.sub.Tensor" + + def forward(self, x, y): + return x - y + + +class Div(torch.nn.Module): + aten_op = "torch.ops.aten.div.Tensor" + + def forward(self, x, y): + return x / y + + +class Mul(torch.nn.Module): + aten_op = "torch.ops.aten.mul.Tensor" + + def forward(self, x, y): + return x * y + + +class MulScalar(torch.nn.Module): + aten_op = "torch.ops.aten.mul.Scalar" + + def forward(self, x, y): + return torch.ops.aten.mul.Scalar(x, y) + + +class DivScalar(torch.nn.Module): + aten_op = "torch.ops.aten.div.Scalar" + + def forward(self, x, y): + return torch.ops.aten.div.Scalar(x, y) + + +class AddScalar(torch.nn.Module): + aten_op = "torch.ops.aten.add.Scalar" + + def forward(self, x, y): + return torch.ops.aten.add.Scalar(x, y) + + +class SubScalar(torch.nn.Module): + aten_op = "torch.ops.aten.sub.Scalar" + + def forward(self, x, y): + return torch.ops.aten.sub.Scalar(x, y) + + +class AddInplace(torch.nn.Module): + aten_op = "torch.ops.aten.add_.Tensor" + + def forward(self, x, y): + x += y + return x + + +class SubInplace(torch.nn.Module): + aten_op = "torch.ops.aten.sub_.Tensor" + + def forward(self, x, y): + x -= y + return x + + +class DivInplace(torch.nn.Module): + aten_op = "torch.ops.aten.div_.Tensor" + + def forward(self, x, y): + x /= y + return x + + +class MulInplace(torch.nn.Module): + aten_op = "torch.ops.aten.mul_.Tensor" + + def forward(self, x, y): + x *= y + return x + + +class AddConst(torch.nn.Module): + aten_op = "torch.ops.aten.add.Tensor" + + def forward(self, x): + x = 1.0 + x + return x + + +class ShiftInplaceSub(torch.nn.Module): + + def forward(self, x): + x = x >> 4 + x -= 10 + return x + + +dtypes = [("int", 3), ("float", 3.0)] +sizes = [("r1", (1)), ("r4", (2, 4, 5, 3))] + +# Create combinations of tests +tensor_scalar_tests = {} +for dtype in dtypes: + for size in sizes: + test_name = f"{dtype[0]}_{size[0]}" + tensor = torch.rand(size[1]) + scalar = dtype[1] + tensor_scalar_tests[test_name + "_ts"] = (tensor, scalar) + # # Don't add (scalar, tensor) test case for .Scalar ops. + # if op[0][-6:] == "Scalar": + # continue + + tensor_scalar_tests[test_name + "_st"] = (scalar, tensor) + +tensor_const_tests = {} +for size in sizes: + test_name = f"{size[0]}" + tensor = torch.rand(size[1]) + tensor_const_tests[test_name] = (tensor,) + +xfails = { + "int_r1_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", + "int_r4_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", + "float_r1_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", + "float_r4_st": "MLETORCH-408: Arithmetic ops can't handle scalars first", +} + + +# ADD FP ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_tensor_tosa_FP_scalar(test_data): + """Tests regular add with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Add(), test_data, aten_op=Add.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_tensor_tosa_FP_inplace(test_data): + """Tests inplace add with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](AddInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_const_tests, xfails=xfails) +def test_add_tensor_tosa_FP_const(test_data): + """Tests regular add with one scalar input, with one of inputs constant.""" + pipeline = TosaPipelineFP[input_t1](AddConst(), test_data, aten_op=AddConst.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_scalar_tosa_FP(test_data): + """Tests a scalar add with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + AddScalar(), test_data, aten_op=AddScalar.aten_op + ) + pipeline.run() + + +# ADD INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_add_tensor_tosa_INT_scalar(test_data): + """Tests regular add with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Add(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_add_tensor_tosa_INT_inplace(test_data): + """Tests inplace add with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](AddInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_const_tests) +def test_add_tensor_tosa_INT_const(test_data): + """Tests regular add with one scalar input, with one of inputs constant.""" + pipeline = TosaPipelineINT[input_t1]( + AddConst(), test_data, aten_op=AddConst.aten_op + ) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_add_scalar_tosa_INT(test_data): + """Tests a scalar add with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](AddScalar(), test_data, aten_op=Add.aten_op) + pipeline.run() + + +# ADD ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_add_scalar_tosa_INT") +def test_add_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_add_scalar_tosa_INT") +def test_add_scalar_u85_INT(): + pass + + +# SUB FP ------------------------------------------------------ + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_tensor_tosa_FP_scalar(test_data): + """Tests regular sub with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Sub(), test_data, aten_op=Sub.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_tensor_tosa_FP_inplace(test_data): + """Tests inplace sub with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](SubInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_scalar_tosa_FP(test_data): + """Tests a scalar sub with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + SubScalar(), test_data, aten_op=SubScalar.aten_op + ) + pipeline.run() + + +# SUB INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_sub_tensor_tosa_INT_scalar(test_data): + """Tests regular sub with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Sub(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_sub_tensor_tosa_INT_inplace(test_data): + """Tests inplace sub with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](SubInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_sub_scalar_tosa_INT(test_data): + """Tests a scalar sub with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](SubScalar(), test_data, aten_op=Sub.aten_op) + pipeline.run() + + +# SUB ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_sub_scalar_tosa_INT") +def test_sub_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_sub_scalar_tosa_INT") +def test_sub_scalar_u85_INT(): + pass + + +# MUL FP ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_tensor_tosa_FP_scalar(test_data): + """Tests regular mul with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Mul(), test_data, aten_op=Mul.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_tensor_tosa_FP_inplace(test_data): + """Tests inplace mul with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](MulInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_scalar_tosa_FP(test_data): + """Tests a scalar mul with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + MulScalar(), test_data, aten_op=MulScalar.aten_op + ) + pipeline.run() + + +# MUL INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_mul_tensor_tosa_INT_scalar(test_data): + """Tests regular mul with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Mul(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_mul_tensor_tosa_INT_inplace(test_data): + """Tests inplace mul with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](MulInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_mul_scalar_tosa_INT(test_data): + """Tests a scalar mul with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](MulScalar(), test_data, aten_op=Mul.aten_op) + pipeline.run() + + +# MUL ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_mul_scalar_tosa_INT") +def test_mul_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_mul_scalar_tosa_INT") +def test_mul_scalar_u85_INT(): + pass + + +# DIV FP ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_tensor_tosa_FP_scalar(test_data): + """Tests regular div with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](Div(), test_data, aten_op=Div.aten_op) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_tensor_tosa_FP_inplace(test_data): + """Tests inplace div with one scalar input.""" + pipeline = TosaPipelineFP[input_t1](DivInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_scalar_tosa_FP(test_data): + """Tests a scalar div with one scalar input.""" + pipeline = TosaPipelineFP[input_t1]( + DivScalar(), test_data, aten_op=DivScalar.aten_op + ) + pipeline.run() + + +# DIV INT ------------------------------------------------------ +@common.parametrize("test_data", tensor_scalar_tests) +def test_div_tensor_tosa_INT_scalar(test_data): + """Tests regular div with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](Div(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests) +def test_div_tensor_tosa_INT_inplace(test_data): + """Tests inplace div with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](DivInplace(), test_data, aten_op=[]) + pipeline.run() + + +@common.parametrize("test_data", tensor_scalar_tests, xfails=xfails) +def test_div_scalar_tosa_INT(test_data): + """Tests a scalar div with one scalar input.""" + pipeline = TosaPipelineINT[input_t1](DivScalar(), test_data, aten_op=[]) + pipeline.run() + + +# DIV ETHOS-U ------------------------------------------------------ +@pytest.mark.skip(reason="This is tested in test_div_scalar_tosa_INT") +def test_div_scalar_u55_INT(): + pass + + +@pytest.mark.skip(reason="This is tested in test_div_scalar_tosa_INT") +def test_div_scalar_u85_INT(): + pass + + +# SHIFT ETHOS-U ------------------------------------------------------ +@pytest.mark.skip( + reason="integer operations (shift and sub) are not supported on FP profile" +) +def test_bitwise_right_shift_tensor_tosa_FP_inplace(): + pipeline = TosaPipelineFP[input_t1]( + ShiftInplaceSub(), + (torch.IntTensor(5),), + aten_op="torch.ops.aten.__rshift__.Scalar", + ) + pipeline.run() + + +def test_bitwise_right_shift_tensor_tosa_INT_inplace(): + pipeline = TosaPipelineINT[input_t1]( + ShiftInplaceSub(), + (torch.IntTensor(5),), + aten_op="torch.ops.aten.bitwise_right_shift.Tensor", + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sdpa.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sdpa.py new file mode 100644 index 0000000..201d80a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sdpa.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class SDPA(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, query, key, value): + return torch.nn.functional.scaled_dot_product_attention( + query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False + ) + + +input_t = Tuple[torch.Tensor, torch.Tensor, torch.Tensor] + + +def test_sdpa_tosa_FP(): + test_input = tuple(torch.randn(1, 3, 197, 64) for x in range(3)) + pipeline = TosaPipelineFP[input_t](SDPA(), test_input, [], []) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +def test_sdpa_tosa_INT(): + test_input = tuple(torch.randn(1, 3, 197, 64) for x in range(3)) + pipeline = TosaPipelineINT[input_t](SDPA(), test_input, [], []) + pipeline.pop_stage("check.quant_nodes") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage( + "run_method_and_compare_outputs" + ) # TODO: reference is not quantized + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sdpa_vgf_no_quant(): + test_input = tuple(torch.randn(1, 3, 197, 64) for _ in range(3)) + pipeline = VgfPipeline[input_t]( + SDPA(), + test_input, + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sdpa_vgf_quant(): + test_input = tuple(torch.randn(1, 3, 197, 64) for _ in range(3)) + pipeline = VgfPipeline[input_t]( + SDPA(), + test_input, + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select.py new file mode 100644 index 0000000..91c1e14 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select.py @@ -0,0 +1,219 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor, int, int] + +test_data_suite = { + # (test_data, dim, index) + "select3d_neg_1_dim_0_index": lambda: (torch.zeros(5, 3, 20), -1, 0), + "select3d_0_dim_neg_1_index": lambda: (torch.rand(5, 3, 20), 0, -1), + "select3d_0_dim_4_index": lambda: (torch.zeros(5, 3, 20), 0, 4), + "select3d_0_dim_2_index": lambda: (torch.ones(10, 10, 10), 0, 2), + "select4d_0_dim_2_index": lambda: (torch.rand(5, 3, 20, 2), 0, 2), + "select2d_0_dim_0_index": lambda: (torch.rand(10, 10) - 0.5, 0, 0), + "select1d_0_dim_1_index": lambda: (torch.randn(10) + 10, 0, 1), + "select1d_0_dim_0_index": lambda: (torch.randn(10) - 10, 0, 2), + "select3d_0_dim_1_index": lambda: (torch.arange(-16, 16, 0.2), 0, 1), +} + +test_data_not_delegated = { + "select3d_large_after_squeeze": lambda: (torch.rand(3, 64, 3, 49, 32), 0, 0), +} + +aten_op_copy = "torch.ops.aten.select_copy.int" +aten_op_int = "torch.ops.aten.select.int" + + +class SelectCopy(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, x, dim: int, index: int): + return torch.select_copy(x, dim=dim, index=index) + + +class SelectInt(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, x, dim: int, index: int): + return torch.select(x, dim=dim, index=index) + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_FP_copy(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SelectCopy(), + test_data(), + aten_op=aten_op_copy, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SelectInt(), + test_data(), + aten_op=aten_op_int, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_INT_copy(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SelectCopy(), + test_data(), + aten_op=aten_op_copy, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_select_int_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SelectInt(), + test_data(), + aten_op=aten_op_int, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_select_int_u55_INT_copy(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_select_int_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_not_delegated) +def test_select_int_u55_INT_not_delegated(test_data: Tuple): + pipeline = OpNotSupportedPipeline[input_t1]( + SelectInt(), + test_data(), + {aten_op_copy: 0}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_select_int_u85_INT_copy(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_select_int_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_no_quant_copy(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_quant_copy(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectCopy(), + test_data(), + aten_op_copy, + [], + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_select_int_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SelectInt(), + test_data(), + aten_op_int, + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select_scatter.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select_scatter.py new file mode 100644 index 0000000..b4df8d4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_select_scatter.py @@ -0,0 +1,173 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + "rank2_rand": lambda: ( + torch.randint(-30, 30, (5, 9), dtype=torch.float32), + torch.randint(0, 9, (9,), dtype=torch.float32), + 0, + 2, + ), + "rank2_zeros": lambda: ( + torch.rand((3, 2), dtype=torch.float32), + torch.randint(0, 4, (2,), dtype=torch.float32), + 0, + 0, + ), + "rank3_rand": lambda: ( + torch.rand((2, 4, 5), dtype=torch.float32), + torch.randint(-5, 5, (2, 5), dtype=torch.float32), + 1, + 0, + ), + "rank3_ones": lambda: ( + torch.ones((2, 3, 3), dtype=torch.float32), + torch.rand((2, 3), dtype=torch.float32), + 2, + 2, + ), + "rank4_rand": lambda: ( + torch.rand((1, 2, 4, 5), dtype=torch.float32), + torch.rand((2, 4, 5), dtype=torch.float32), + 0, + 0, + ), + "rank4_ones": lambda: ( + torch.ones((2, 3, 3, 2), dtype=torch.float32), + torch.randint(-5, 5, (2, 3, 2), dtype=torch.float32), + 2, + -1, + ), + "rank5_ones": lambda: ( + torch.ones((3, 4, 20, 9, 5), dtype=torch.float32), + torch.randn((3, 4, 20, 9), dtype=torch.float32), + 4, + 1, + ), + "rank6_rand": lambda: ( + torch.rand((1, 2, 3, 4, 2, 1), dtype=torch.float32), + torch.randn((2, 3, 4, 2, 1), dtype=torch.float32), + 0, + 0, + ), +} + + +class SelectScatter(torch.nn.Module): + fp_aten_op = "torch.ops.aten.select_scatter.default" + int_aten_ops = [ + "torch.ops.aten.arange.start_step", + "torch.ops.aten.view_copy.default", + "torch.ops.aten.unsqueeze_copy.default", + "torch.ops.aten.expand_copy.default", + "torch.ops.aten.where.self", + "torch.ops.aten.eq.Tensor", + ] + fp_exir_op = ["executorch_exir_dialects_edge__ops_aten_select_scatter_default"] + int_exir_ops = [ + "executorch_exir_dialects_edge__ops_aten_eq_Tensor", + "executorch_exir_dialects_edge__ops_aten_where_self", + "executorch_exir_dialects_edge__ops_aten_arange_start_step", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default", + "executorch_exir_dialects_edge__ops_aten_expand_copy_default", + ] + u55_not_supported = { + "executorch_exir_dialects_edge__ops_aten_eq_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_where_self": 1, + } + + def forward(self, x: torch.Tensor, y: torch.Tensor, dim: int, index: int): + return x.select_scatter(y, dim, index) + + +input_t = Tuple[torch.Tensor, torch.Tensor, int, int] + + +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_tosa_FP(test_module: input_t): + pipeline = TosaPipelineFP[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.fp_aten_op, + exir_op=SelectScatter.fp_exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_tosa_INT(test_module: input_t): + pipeline = TosaPipelineINT[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.int_aten_ops, + exir_op=SelectScatter.int_exir_ops, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_u55_INT(test_module: input_t): + # select_scatter is not supported on U55 + pipeline = OpNotSupportedPipeline[input_t]( + SelectScatter(), + test_module(), + SelectScatter.u55_not_supported, + quantize=True, + u55_subset=True, + n_expected_delegates=1, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_u85_INT(test_module: input_t): + pipeline = EthosU85PipelineINT[input_t]( + SelectScatter(), + test_module(), + aten_ops=SelectScatter.int_aten_ops, + exir_ops=SelectScatter.int_exir_ops, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_vgf_no_quant(test_module: input_t): + pipeline = VgfPipeline[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.fp_aten_op, + exir_op=SelectScatter.fp_exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_select_scatter_vgf_quant(test_module: input_t): + pipeline = VgfPipeline[input_t]( + SelectScatter(), + test_module(), + aten_op=SelectScatter.int_aten_ops, + exir_op=SelectScatter.int_exir_ops, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid.py new file mode 100644 index 0000000..29bf037 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid.py @@ -0,0 +1,357 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.sigmoid.default" # Used for checking that we do not have softmax in the graph after decompose +exir_op = "executorch_exir_dialects_edge__ops_aten_sigmoid_default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(10, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "rand_4d": lambda: torch.rand(1, 1, 5, 10), + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Sigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid(x) + + +class AddSigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid(x + x) + + +class SigmoidAdd(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return x + self.sigmoid(x) + + +class SigmoidAddSigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x, y): + return self.sigmoid((self.sigmoid(y) + self.sigmoid(x))) + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_FP(test_data: torch.Tensor): + TosaPipelineFP[input_t1](Sigmoid(), (test_data(),), aten_op, exir_op).run() + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_INT(test_data: torch.Tensor): + TosaPipelineINT[input_t1](Sigmoid(), (test_data(),), aten_op, exir_op).run() + + +def test_sigmoid_tosa_FP_add(): + TosaPipelineFP[input_t1]( + AddSigmoid(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_INT_add(): + TosaPipelineINT[input_t1]( + AddSigmoid(), + (test_data_suite["ramp"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_FP_add_2(): + TosaPipelineFP[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_INT_add_2(): + TosaPipelineINT[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_FP_add_3(): + TosaPipelineFP[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + ).run() + + +def test_sigmoid_tosa_INT_3(): + TosaPipelineINT[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + ).run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sigmoid_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant_add(): + pipeline = VgfPipeline[input_t1]( + AddSigmoid(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant_add(): + pipeline = VgfPipeline[input_t1]( + AddSigmoid(), + (test_data_suite["ramp"](),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant_add_2(): + pipeline = VgfPipeline[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant_add_2(): + pipeline = VgfPipeline[input_t1]( + SigmoidAdd(), + (test_data_suite["zeros"](),), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_no_quant_add_3(): + pipeline = VgfPipeline[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +def test_sigmoid_vgf_quant_add_3(): + pipeline = VgfPipeline[input_t1]( + SigmoidAddSigmoid(), + (test_data_suite["randn_neg"](), test_data_suite["randn_pos"]()), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_sigmoid_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + + # Use a smaller episilon value to not greatly inflate [qmin, qmax] + quantizer.set_global( + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=2**-16 + ) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=2**-16 + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_16a8w_tosa_INT(test_data: torch.Tensor): + """Test sigmoid operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sigmoid_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_16a8w_u55_INT16(test_data: torch.Tensor): + """Test sigmoid operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sigmoid_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sigmoid_16a8w_u85_INT(test_data: torch.Tensor): + """Test sigmoid operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Sigmoid(), + (test_data(),), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sigmoid_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid_32bit.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid_32bit.py new file mode 100644 index 0000000..29fc90b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sigmoid_32bit.py @@ -0,0 +1,177 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineINT, +) +from torchao.quantization.pt2e import HistogramObserver +from torchao.quantization.pt2e.quantizer import QuantizationSpec + + +def _get_16_bit_quant_config(): + int16_spec = QuantizationSpec( + dtype=torch.int16, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_symmetric, + ) + int32_spec = QuantizationSpec( + dtype=torch.int32, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_symmetric, + ) + qconfig = QuantizationConfig( + input_activation=int16_spec, + output_activation=int32_spec, + weight=None, + bias=None, + ) + return qconfig + + +def _get_32_bit_quant_config(): + int32_spec = QuantizationSpec( + dtype=torch.int32, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_symmetric, + ) + qconfig = QuantizationConfig( + input_activation=int32_spec, + output_activation=int32_spec, + weight=None, + bias=None, + ) + return qconfig + + +def configure_32bit_sigmoid_quantizer(pipeline): + pipeline.quantizer.set_global(_get_32_bit_quant_config()) + pipeline.quantizer.set_module_type( + torch.nn.modules.activation.Sigmoid, _get_16_bit_quant_config() + ) + + +input_t = tuple[torch.Tensor] +test_data_suite = { + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "rand_4d": lambda: torch.rand(1, 10, 10, 10), + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Sigmoid(torch.nn.Module): + aten_op = "torch.ops.aten.sigmoid.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_sigmoid_default" + + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid(x) + + +class SigmoidAddSigmoid(torch.nn.Module): + def __init__(self): + super().__init__() + self.sigmoid = torch.nn.Sigmoid() + + def forward(self, x): + return self.sigmoid((self.sigmoid(x) + self.sigmoid(x))) + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_INT(test_data): + pipeline = TosaPipelineINT( + Sigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + qtol=1, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sigmoid_tosa_INT_add_sigmoid(test_data): + pipeline = TosaPipelineINT( + SigmoidAddSigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + qtol=1, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_u55_INT(test_data): + pipeline = OpNotSupportedPipeline( + Sigmoid(), + (test_data(),), + {Sigmoid.exir_op: 1}, + quantize=True, + u55_subset=True, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sigmoid_u55_INT_add_sigmoid(test_data): + pipeline = OpNotSupportedPipeline( + SigmoidAddSigmoid(), + (test_data(),), + {Sigmoid.exir_op: 3}, + n_expected_delegates=1, + quantize=True, + u55_subset=True, + tosa_extensions=["int16"], + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sigmoid_u85_INT(test_data): + pipeline = EthosU85PipelineINT( + Sigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() + + +@common.parametrize( + "test_data", + test_data_suite, +) +@common.XfailIfNoCorstone320 +def test_sigmoid_u85_INT_add_sigmoid(test_data): + pipeline = EthosU85PipelineINT( + SigmoidAddSigmoid(), + (test_data(),), + Sigmoid.aten_op, + Sigmoid.exir_op, + ) + configure_32bit_sigmoid_quantizer(pipeline) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sign.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sign.py new file mode 100644 index 0000000..dd4f289 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sign.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import pytest +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sign.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__sign_default" + +input_t1 = Tuple[torch.Tensor] + +test_data_suite = { + "zeros": torch.zeros(3, 5), + "ones": torch.ones(4, 4), + "neg_ones": -torch.ones(4, 4), + "mixed_signs": torch.tensor([[-2.0, -1.0, 0.0, 1.0, 2.0]]), + "positive_ramp": torch.arange(0.1, 1.1, 0.2), + "negative_ramp": torch.arange(-1.0, -0.1, 0.2), + "small_values": torch.tensor([-1e-7, 0.0, 1e-7]), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(10, 3, 5) - 0.5, + "high_magnitude": torch.tensor([-1e6, -10.0, 0.0, 10.0, 1e6]), +} + + +class Sign(torch.nn.Module): + def forward(self, x: torch.Tensor): + return torch.sign(x) + + +@common.parametrize("test_data", test_data_suite) +def test_sign_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Sign(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sign_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Sign(), + (test_data,), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +@pytest.mark.xfail(reason="where.self not supported on U55") +def test_sign_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sign(), + (test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_sign_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sign(), + (test_data,), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sign_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sign(), + (test_data,), + aten_op=aten_op, + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sign_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sign(), + (test_data,), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_silu.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_silu.py new file mode 100644 index 0000000..03dea73 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_silu.py @@ -0,0 +1,174 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +input_t = Tuple[torch.Tensor] + + +class Silu(torch.nn.Module): + def forward( + self, + _input: torch.Tensor, + _inplace: Optional[bool] = False, + ): + return torch.nn.SiLU(inplace=_inplace)(_input) + + test_data: list[input_t] = { + "op_silu_rank1_ones": lambda: torch.ones(5), + "op_silu_rank1_negative_ones": lambda: torch.ones(5) * (-1), + "op_silu_rank1_rand": lambda: torch.rand(5) * 5, + "op_silu_rank4_ones": lambda: torch.ones(1, 10, 25, 20), + "op_silu_rank4_negative_ones": lambda: (-1) * torch.ones(1, 10, 25, 20), + "op_silu_rank4_large_rand": lambda: 200 * torch.rand(1, 10, 25, 20), + "op_silu_rank4_negative_large_rand": lambda: (-200) * torch.rand(1, 10, 25, 20), + "op_silu_rank4_large_randn": lambda: 200 * torch.randn(1, 10, 25, 20) + 1, + } + + aten_op_FP = "torch.ops.aten.silu.default" + aten_op_inplace_FP = "torch.ops.aten.silu_.default" + aten_op_INT = ["torch.ops.aten.sigmoid.default", "torch.ops.aten.mul.Tensor"] + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_FP(test_data: input_t): + silu_data = (test_data(), False) + pipeline = TosaPipelineFP[input_t](Silu(), silu_data, Silu.aten_op_FP) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_FP_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = TosaPipelineFP[input_t](Silu(), silu_data, Silu.aten_op_inplace_FP) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_INT(test_data: input_t): + silu_data = (test_data(), False) + pipeline = TosaPipelineINT[input_t](Silu(), silu_data, Silu.aten_op_INT) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +def test_silu_tosa_INT_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = TosaPipelineINT[input_t](Silu(), silu_data, Silu.aten_op_INT) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone300 +def test_silu_u55_INT(test_data: input_t): + silu_data = (test_data(), False) + pipeline = EthosU55PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone300 +def test_silu_u55_INT_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = EthosU55PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone320 +def test_silu_u85_INT(test_data: input_t): + silu_data = (test_data(), False) + pipeline = EthosU85PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.XfailIfNoCorstone320 +def test_silu_u85_INT_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = EthosU85PipelineINT[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_no_quant(test_data: input_t): + silu_data = (test_data(), False) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_FP, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_no_quant_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_inplace_FP, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_quant(test_data: input_t): + silu_data = (test_data(), False) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Silu.test_data) +@common.SkipIfNoModelConverter +def test_silu_vgf_quant_inplace(test_data: input_t): + silu_data = (test_data(), True) + pipeline = VgfPipeline[input_t]( + Silu(), + silu_data, + Silu.aten_op_INT, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sin.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sin.py new file mode 100644 index 0000000..05cc8f5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sin.py @@ -0,0 +1,108 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sin.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10, 10), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), +} + + +class Sin(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.sin(x) + + +@common.parametrize("test_data", test_data_suite) +def test_sin_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_op=[], + ) + if conftest.get_option("tosa_version") == "1.0": + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sin_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_sin_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_sin_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sin(), + (test_data,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sin_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sin(), + (test_data,), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sin_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sin(), + (test_data,), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sinh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sinh.py new file mode 100644 index 0000000..703d3e5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sinh.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sinh.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__sinh_default" + + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": torch.zeros(10, 10, 10), + "zeros_alt_shape": torch.zeros(10, 3, 5), + "ones": torch.ones(10, 10, 10), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(10, 3, 5) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), + "large": 100 * torch.ones(1, 1), + "small": 0.000001 * torch.ones(1, 1), +} + + +class Sinh(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.sinh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_sinh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Sinh(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_sinh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Sinh(), (test_data,), aten_op=aten_op, exir_op=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_sinh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sinh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_sinh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sinh(), (test_data,), aten_ops=aten_op, exir_ops=exir_op + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sinh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sinh(), + (test_data,), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_sinh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Sinh(), + (test_data,), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_slice.py new file mode 100644 index 0000000..f98efe1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_slice.py @@ -0,0 +1,217 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.slice.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_slice_copy" + +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + "ones_neg_3": lambda: (torch.ones(10), [(3, -3)]), + "ones_neg_8": lambda: (torch.ones(10), [(-8, 3)]), + "ones_slice_2": lambda: (torch.ones(10, 10), [(1, 3), (3, 10)]), + "ones_slice_3": lambda: (torch.ones(10, 10, 10), [(0, 7), (0, 10), (0, 8)]), + "ones_slice_4": lambda: ( + torch.ones((1, 12, 10, 10)), + [(0, 1), (0, 5), (3, 5), (4, 10)], + ), +} + + +class Slice(torch.nn.Module): + def forward(self, x: torch.Tensor, s: list[tuple[int, int]]): + slices = [slice(*i) for i in s] + return x[slices] + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_tosa_FP(test_data: torch.Tensor): + pipeline = TosaPipelineFP[input_t1](Slice(), test_data(), aten_op, exir_op) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_tosa_INT_nchw(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_tosa_INT_nhwc(test_data: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_slice_tensor_u55_INT(test_data: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_slice_tensor_u85_INT(test_data: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_slice_tensor_vgf_no_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_slice_tensor_vgf_quant(test_data: torch.Tensor): + pipeline = VgfPipeline[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_slice_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", test_data_suite) +def test_slice_tensor_16a8w_tosa_INT(test_data: torch.Tensor): + """Test slice operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Slice(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_slice_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_slice_tensor_16a8w_u55_INT(test_data: torch.Tensor): + """Test slice operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_slice_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_slice_tensor_16a8w_u85_INT(test_data: torch.Tensor): + """Test slice operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Slice(), + test_data(), + aten_ops=[], + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_slice_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_softmax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_softmax.py new file mode 100644 index 0000000..0b2af23 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_softmax.py @@ -0,0 +1,121 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.softmax.default" # Used for checking that we do not have softmax in the graph after decompose +exir_op = "executorch_exir_dialects_edge__ops_aten__softmax_tensor" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Softmax(torch.nn.Module): + def __init__(self, dim: int = -1): + super().__init__() + self.softmax = torch.nn.Softmax(dim=dim) + + def forward(self, x): + return self.softmax(x) + + test_data = { + "ones": lambda: ((torch.ones(10, 10),), 1), + "ones_neg_dim": lambda: ((torch.ones(1, 3, 4),), -1), + "randn_neg_dim": lambda: ((torch.randn(1, 5, 8, 7),), -3), + "zeros": lambda: ((torch.zeros(1, 8, 5, 2),), 0), + "zeros_neg_dim": lambda: ((torch.zeros(1, 7, 8, 9),), -4), + "rand": lambda: ((torch.rand(1, 2, 5, 8),), 2), + "rand_neg_dim": lambda: ((torch.rand(1, 10, 8, 10),), -2), + "randn_mult_batches": lambda: ((torch.randn(2, 10, 10, 10),), 3), + } + + +@common.parametrize("test_data", Softmax.test_data) +def test_softmax_tosa_FP(test_data): + data, dim = test_data() + pipeline = TosaPipelineFP[input_t1](Softmax(dim), data, []) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +def test_softmax_tosa_INT(test_data): + data, dim = test_data() + pipeline = TosaPipelineINT[input_t1](Softmax(dim), data, []) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.XfailIfNoCorstone300 +def test_softmax_u55_INT(test_data): + data, dim = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + Softmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.XfailIfNoCorstone320 +def test_softmax_u85_INT(test_data): + data, dim = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + Softmax(dim), + data, + [], + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.SkipIfNoModelConverter +def test_softmax_vgf_no_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + Softmax(dim), + data, + [], + quantize=False, + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", pipeline.tester.check_not, [exir_op] + ) + pipeline.run() + + +@common.parametrize("test_data", Softmax.test_data) +@common.SkipIfNoModelConverter +def test_softmax_vgf_quant(test_data): + data, dim = test_data() + pipeline = VgfPipeline[input_t1]( + Softmax(dim), + data, + [], + quantize=True, + ) + pipeline.add_stage_after("quantize", pipeline.tester.check_not, [aten_op]) + # TODO: MLETORCH-1136 Change args of run_method_and_compare_outputs of the vgf tests + # pipeline.change_args("run_method_and_compare_outputs", qtol=1) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_split.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_split.py new file mode 100644 index 0000000..6af3362 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_split.py @@ -0,0 +1,312 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +exir_op = "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default" +input_t1 = Tuple[torch.Tensor] # Input x + + +class Split(torch.nn.Module): + test_data = { + "split_1d_2_size_0_dim": lambda: (torch.rand(10), 2, 0), + "split_2d_3_size_1_dim": lambda: (torch.rand(10, 10), 3, 1), + "split_2d_2_size_4_dim": lambda: (torch.rand(10, 10), 4, -1), + "split_4d_2_size_2_dim": lambda: (torch.rand(4, 4, 4, 4), 2, 0), + } + + test_data_list = { + "split_3d_2_sizes_dim": lambda: (torch.rand(10, 15, 10), [2, 2, 11], 1), + "split_4d_2_sizes_dim_neg": lambda: (torch.rand(4, 4, 4, 4), [1, 1, 1, 1], -2), + } + + def forward( + self, x: torch.Tensor, split_size_or_sections: int | list[int], dim: int + ): + return x.split(split_size=split_size_or_sections, dim=dim) + + +class SplitWithSizes(torch.nn.Module): + def forward(self, x: torch.Tensor, split_sizes: list[int], dim: int): + return x.split_with_sizes(split_sizes=split_sizes, dim=dim) + + +class SplitSingleOut(torch.nn.Module): + def forward( + self, x: torch.Tensor, split_size_or_sections: int | list[int], dim: int + ): + return x.split(split_size=split_size_or_sections, dim=dim)[1] + + +class SplitTwoOut(torch.nn.Module): + def forward( + self, x: torch.Tensor, split_size_or_sections: int | list[int], dim: int + ): + return x.split(split_size=split_size_or_sections, dim=dim)[1:3] + + +class SplitCopy(torch.nn.Module): + aten_op = "torch.ops.aten.split_copy.Tensor" + exir_op = "executorch_exir_dialects_edge__ops_aten_split_copy_Tensor" + + def forward( + self, + x: torch.Tensor, + split_size: int, + dim: int, + ): + return torch.split_copy(x, split_size=split_size, dim=dim) + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data_list) +def test_split_with_sizes_tosa_FP_2(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SplitWithSizes(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_FP_one_out(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SplitSingleOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_FP_two_out(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + SplitTwoOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +def test_split_with_sizes_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", (Split.test_data | Split.test_data_list)) +@common.XfailIfNoCorstone300 +def test_split_with_sizes_u55_INT(test_data: input_t1): + pipeline = EthosU55PipelineINT[input_t1]( + Split(), + test_data(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", (Split.test_data | Split.test_data_list)) +@common.XfailIfNoCorstone320 +def test_split_with_sizes_u85_INT(test_data: input_t1): + pipeline = EthosU85PipelineINT[input_t1]( + Split(), + test_data(), + aten_ops=[], + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data_list) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant_2(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + SplitWithSizes(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant_one_out(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + SplitSingleOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_no_quant_two_out(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + SplitTwoOut(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + (Split.test_data | Split.test_data_list), +) +@common.SkipIfNoModelConverter +def test_split_with_sizes_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Split(), + test_data(), + aten_op=[], + exir_op=exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SplitCopy(), + test_data(), + aten_ops=SplitCopy.aten_op, + exir_ops=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", Split.test_data) +def test_split_tensor_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SplitCopy(), + test_data(), + aten_ops=SplitCopy.aten_op, + exir_ops=SplitCopy.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +@common.SkipIfNoModelConverter +def test_split_tensor_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Split.test_data) +@common.SkipIfNoModelConverter +def test_split_tensor_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SplitCopy(), + test_data(), + aten_op=SplitCopy.aten_op, + exir_op=SplitCopy.exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sqrt.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sqrt.py new file mode 100644 index 0000000..c3d1aae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sqrt.py @@ -0,0 +1,112 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + + +class Sqrt(torch.nn.Module): + input_t = Tuple[torch.Tensor] + aten_op_FP = "torch.ops.aten.sqrt.default" + exir_op_FP = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Tensor" + + aten_op_INT = "torch.ops.aten.pow.Tensor_Scalar" + exir_op_INT = "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar" + + def __init__(self): + super().__init__() + + def forward(self, x): + return torch.sqrt(x) + + test_data: Dict[str, input_t] = { + "sqrt_tensor_rank1_ones": lambda: (torch.ones(10),), + "sqrt_tensor_rank2_random": lambda: (torch.rand(5, 10),), + "sqrt_tensor_rank3_ones": lambda: (torch.ones(2, 3, 4),), + "sqrt_tensor_rank4_random": lambda: (torch.rand(1, 3, 8, 8),), + "sqrt_tensor_rank4_multibatch": lambda: (torch.rand(2, 3, 4, 4),), + } + + +@common.parametrize("test_data", Sqrt.test_data) +def test_sqrt_tosa_FP(test_data: Sqrt.input_t): + pipeline = TosaPipelineFP[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_FP, + Sqrt.exir_op_FP, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +def test_sqrt_tosa_INT(test_data: Sqrt.input_t): + pipeline = TosaPipelineINT[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.XfailIfNoCorstone300 +def test_sqrt_u55_INT(test_data: Sqrt.input_t): + pipeline = EthosU55PipelineINT[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.XfailIfNoCorstone320 +def test_sqrt_u85_INT(test_data: Sqrt.input_t): + pipeline = EthosU85PipelineINT[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.SkipIfNoModelConverter +def test_sqrt_vgf_no_quant(test_data: Sqrt.input_t): + pipeline = VgfPipeline[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_FP, + Sqrt.exir_op_FP, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Sqrt.test_data) +@common.SkipIfNoModelConverter +def test_sqrt_vgf_quant(test_data: Sqrt.input_t): + pipeline = VgfPipeline[Sqrt.input_t]( + Sqrt(), + test_data(), + Sqrt.aten_op_INT, + Sqrt.exir_op_INT, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_squeeze.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_squeeze.py new file mode 100644 index 0000000..fcef851 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_squeeze.py @@ -0,0 +1,291 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the squeeze op which squeezes a given dimension with size 1 into a lower ranked tensor. +# + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class SqueezeDim(torch.nn.Module): + test_parameters = { + "squeeze3d_dim_neg_2": lambda: (torch.randn(1, 1, 5), -2), + "squeeze4d_dim_pos_3": lambda: (torch.randn(1, 2, 3, 1), 3), + "squeeze4d_dim_neg_2": lambda: (torch.randn(1, 5, 1, 5), -2), + "squeeze5d_dim_neg_2": lambda: (torch.randn(1, 1, 5, 1, 5), -2), + } + + def forward(self, x: torch.Tensor, dim: int): + return x.squeeze(dim) + + +class SqueezeDims(torch.nn.Module): + test_parameters = { + "squeeze3d_dims_0_1": lambda: (torch.randn(1, 1, 5), (0, 1)), + "squeeze4d_dims_0_neg_1": lambda: (torch.randn(1, 5, 5, 1), (0, -1)), + "squeeze4d_dims_0_neg_2": lambda: (torch.randn(1, 5, 1, 5), (0, -2)), + "squeeze5d_dims_0_neg_2": lambda: (torch.randn(1, 1, 5, 1, 5), (0, -2)), + } + + def forward(self, x: torch.Tensor, dims: tuple[int]): + return x.squeeze(dims) + + +class Squeeze(torch.nn.Module): + test_parameters = { + "squeeze3d": lambda: (torch.randn(1, 1, 5),), + "squeeze4d_dims": lambda: (torch.randn(1, 5, 5, 1),), + "squeeze3d_dims_mix": lambda: (torch.randn(1, 5, 1, 5),), + "squeeze4d_dims_mix": lambda: (torch.randn(1, 1, 5, 1, 5),), + } + + def forward(self, x: torch.Tensor): + return x.squeeze() + + +############## +## Squeeze ### +############## + + +@common.parametrize("test_data", Squeeze.test_parameters) +def test_squeeze_dim_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Squeeze(), + test_data(), + aten_op="torch.ops.aten.squeeze.default", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +def test_squeeze_dim_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Squeeze(), + test_data(), + aten_op="torch.ops.aten.squeeze.default", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.XfailIfNoCorstone300 +def test_squeeze_dim_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Squeeze(), + test_data(), + aten_ops="torch.ops.aten.squeeze.default", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.XfailIfNoCorstone320 +def test_squeeze_dim_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Squeeze(), + test_data(), + aten_ops="torch.ops.aten.squeeze.default", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Squeeze(), + test_data(), + "torch.ops.aten.squeeze.default", + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Squeeze.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Squeeze(), + test_data(), + "torch.ops.aten.squeeze.default", + [], + quantize=True, + ) + pipeline.run() + + +################# +## SqueezeDim ### +################# + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +def test_squeeze_dim_tosa_FP_2(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SqueezeDim(), + test_data(), + aten_op="torch.ops.aten.squeeze.dim", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +def test_squeeze_dim_tosa_INT_2(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SqueezeDim(), + test_data(), + aten_op="torch.ops.aten.squeeze.dim", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.XfailIfNoCorstone300 +def test_squeeze_dim_u55_INT_2(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SqueezeDim(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dim", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.XfailIfNoCorstone320 +def test_squeeze_dim_u85_INT_2(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SqueezeDim(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dim", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_no_quant_2(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDim(), + test_data(), + "torch.ops.aten.squeeze.dim", + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDim.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dim_vgf_quant_2(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDim(), + test_data(), + "torch.ops.aten.squeeze.dim", + [], + quantize=True, + ) + pipeline.run() + + +################## +## SqueezeDims ### +################## + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +def test_squeeze_dims_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + SqueezeDims(), + test_data(), + aten_op="torch.ops.aten.squeeze.dims", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +def test_squeeze_dims_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + SqueezeDims(), + test_data(), + aten_op="torch.ops.aten.squeeze.dims", + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.XfailIfNoCorstone300 +def test_squeeze_dims_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + SqueezeDims(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dims", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.XfailIfNoCorstone320 +def test_squeeze_dims_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + SqueezeDims(), + test_data(), + aten_ops="torch.ops.aten.squeeze.dims", + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dims_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDims(), + test_data(), + "torch.ops.aten.squeeze.dims", + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", SqueezeDims.test_parameters) +@common.SkipIfNoModelConverter +def test_squeeze_dims_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + SqueezeDims(), + test_data(), + "torch.ops.aten.squeeze.dims", + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_stack.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_stack.py new file mode 100644 index 0000000..a3911a6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_stack.py @@ -0,0 +1,150 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +import torch.nn as nn + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # (test_name, test_data) + "ones_two_tensors": lambda: ((torch.ones(1), torch.ones(1)), 0), + "ones_and_rand_three_tensors": lambda: ( + (torch.ones(1, 2), torch.randn(1, 2), torch.randn(1, 2)), + 1, + ), + "ones_and_rand_four_tensors": lambda: ( + ( + torch.ones(1, 2, 5), + torch.randn(1, 2, 5), + torch.randn(1, 2, 5), + torch.randn(1, 2, 5), + ), + -1, + ), + "rand_two_tensors": lambda: ( + (torch.randn(2, 2, 4), torch.randn(2, 2, 4)), + 2, + ), + "rand_two_tensors_dim_0": lambda: ( + (torch.randn(1, 2, 4, 4), torch.randn(1, 2, 4, 4)), + ), + "rand_two_tensors_dim_2": lambda: ( + (torch.randn(2, 2, 3, 5), torch.randn(2, 2, 3, 5)), + 2, + ), + "rand_large": lambda: ( + ( + 10000 * torch.randn(2, 3, 1, 4), + torch.randn(2, 3, 1, 4), + torch.randn(2, 3, 1, 4), + ), + -3, + ), +} + + +class Stack(nn.Module): + aten_op = "torch.ops.aten.stack.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_cat_default" + + def forward(self, n: tuple[torch.Tensor, ...], dim: int = 0): + return torch.stack(n, dim) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_module", test_data_suite) +def test_stack_tosa_FP(test_module: input_t1): + test_data = test_module() + pipeline = TosaPipelineFP[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_data_suite) +def test_stack_tosa_INT(test_module: input_t1): + test_data = test_module() + pipeline = TosaPipelineINT[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_module", test_data_suite) +def test_stack_u55_INT(test_module: input_t1): + test_data = test_module() + pipeline = EthosU55PipelineINT[input_t1]( + Stack(), + test_data, + aten_ops=Stack.aten_op, + exir_ops=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_module", test_data_suite) +def test_stack_u85_INT(test_module: input_t1): + test_data = test_module() + pipeline = EthosU85PipelineINT[input_t1]( + Stack(), + test_data, + aten_ops=Stack.aten_op, + exir_ops=Stack.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_stack_vgf_no_quant(test_module: input_t1): + test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.SkipIfNoModelConverter +@common.parametrize("test_module", test_data_suite) +def test_stack_vgf_quant(test_module: input_t1): + test_data = test_module() + pipeline = VgfPipeline[input_t1]( + Stack(), + test_data, + aten_op=Stack.aten_op, + exir_op=Stack.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sub.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sub.py new file mode 100644 index 0000000..1db6f7b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sub.py @@ -0,0 +1,366 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.sub.Tensor" +exir_op = "executorch_exir_dialects_edge__ops_aten_sub_Tensor" + +# Single-input subtraction (x - x) +sub_test_data = { + "ones_1D_5": lambda: (torch.ones(5),), + "ones_1D_50": lambda: (torch.ones(50),), + "rand_1D_10": lambda: (torch.rand(10),), + "rand_2D_5x5": lambda: (torch.rand(5, 5),), + "rand_3D_5x5x5": lambda: (torch.rand(5, 5, 5),), + "rand_4D_2x3x4x5": lambda: (torch.rand(2, 3, 4, 5),), + "zeros": lambda: (torch.zeros(10),), +} + +# Two-input subtraction (x - y) +sub2_test_data = { + "rand_2D_4x4": lambda: (torch.rand(4, 4), torch.rand(4, 4)), + "rand_3D_4x4x4": lambda: (torch.rand(4, 2, 2), torch.rand(4, 2, 2)), + "rand_4D_2x2x4x4": lambda: (torch.rand(2, 2, 4, 4), torch.rand(2, 2, 4, 4)), + "rand_4D_big_small": lambda: ( + (10e30) * torch.randn(1, 20, 30, 40), + torch.randn(1, 20, 30, 40), + ), + "zeros": lambda: (torch.rand(4, 4), torch.zeros(4, 4)), + "randn_4D_mutltiple_broadcasts": lambda: ( + torch.randn(1, 4, 4, 1), + torch.randn(1, 1, 4, 4), + ), + "rand_3d_rand_Scalar": lambda: (torch.rand(1, 6, 2), torch.rand(1)), + "rand_3d_Scalar": lambda: (torch.rand(1, 6, 2), 1), +} + +# Sub and tan - the tan has a really steep curve just before Pi/2 and a point of discontinuity at Pi/2 +# so if the sub result is inaccurate, the error will be amplified by the tan +sub_tan_test_data = { + "rand_4D_pi": lambda: ( + torch.randn(1, 10, 20, 30) * math.pi / 2, + torch.randn(1, 10, 20, 30) * math.pi / 2, + ), + "rand_3D_pi": lambda: (torch.randn(1, 30, 40) * math.pi / 2, torch.rand(1, 30, 40)), +} + + +class Sub(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x - x + + +class Sub2(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x - y + + +class SubAlpha(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor): + return torch.sub(x, y, alpha=5) + + +class SubTan(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor): + z = x - y + t = torch.tan(z) + return t + + +input_t1 = Tuple[torch.Tensor] # Input x +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +@common.parametrize("test_data", sub_test_data) +def test_sub_tensor_tosa_FP(test_data): + """Test Subtraction (TOSA FP)""" + pipeline = TosaPipelineFP[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +def test_sub_tensor_tosa_FP_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (TOSA FP)""" + pipeline = TosaPipelineFP[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_tan_test_data) +def test_sub_tensor_tosa_FP_alpha(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction with alpha (TOSA FP)""" + pipeline = TosaPipelineFP[input_t2]( + SubAlpha(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +def test_sub_tensor_tosa_INT(test_data): + """Test Subtraction (TOSA INT)""" + pipeline = TosaPipelineINT[input_t1](Sub(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +def test_sub_tensor_tosa_INT_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (TOSA INT)""" + pipeline = TosaPipelineINT[input_t2](Sub2(), test_data(), aten_op, exir_op, qtol=0) + pipeline.run() + + +@common.parametrize("test_data", sub_tan_test_data) +def test_sub_tensor_tosa_INT_3(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (TOSA INT)""" + # This test has only been added to the tosa INT profile in order to catch quantization-induced errors. + pipeline = TosaPipelineINT[input_t2]( + SubTan(), test_data(), aten_op, exir_op, qtol=0 + ) + pipeline.run() + + +@common.parametrize("test_data", sub_tan_test_data) +def test_sub_tensor_tosa_INT_alpha(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction with alpha (TOSA INT)""" + pipeline = TosaPipelineINT[input_t2]( + SubAlpha(), test_data(), aten_op, exir_op, qtol=0 + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone300 +def test_sub_tensor_u55_INT(test_data): + """Test Subtraction on Ethos-U55 (FVP Mode)""" + pipeline = EthosU55PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.XfailIfNoCorstone300 +def test_sub_tensor_u55_INT_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction on Ethos-U55 (FVP Mode)""" + pipeline = EthosU55PipelineINT[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone320 +def test_sub_tensor_u85_INT_2(test_data): + """Test Subtraction on Ethos-U85 (FVP Mode)""" + pipeline = EthosU85PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.XfailIfNoCorstone320 +def test_sub_tensor_u85_INT(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction on Ethos-U85 (FVP Mode)""" + pipeline = EthosU85PipelineINT[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_no_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF FP)""" + pipeline = VgfPipeline[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_no_quant_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (VGF FP)""" + pipeline = VgfPipeline[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_quant(test_data: Tuple[torch.Tensor]): + """Test Subtraction (VGF INT)""" + pipeline = VgfPipeline[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", sub2_test_data) +@common.SkipIfNoModelConverter +def test_sub_tensor_vgf_quant_2(test_data: Tuple[torch.Tensor, torch.Tensor]): + """Test Two-Operand Subtraction (VGF INT)""" + pipeline = VgfPipeline[input_t2]( + Sub2(), + test_data(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() + + +def get_symmetric_a16w8_sub_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", sub_test_data) +def test_sub_tensor_16a8w_tosa_INT(test_data: input_t1): + """Test sub operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sub_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone300 +def test_sub_tensor_16a8w_u55_INT(test_data: input_t1): + """Test sub operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sub_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", sub_test_data) +@common.XfailIfNoCorstone320 +def test_sub_tensor_16a8w_u85_INT(test_data: input_t1): + """Test sub operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Sub(), + test_data(), + aten_op, + exir_op, + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + run_on_fvp=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_sub_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sum.py new file mode 100644 index 0000000..14a6eee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_sum.py @@ -0,0 +1,161 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.sum.dim_IntList" +input_t1 = Tuple[torch.Tensor] # Input x + + +"""Tests sum which sums all elements along some specified dimensions. +keepdim specifies whether the dimension that is summed should +be squeezed or not. +""" + + +class Sum(torch.nn.Module): + test_parameters = { + "1d_dim_0_keep": lambda: (torch.rand(10), 0, True), + "2d_dim_1_no_keep": lambda: (torch.rand(10, 10), 1, False), + "3d_dims_keep": lambda: (torch.rand(10, 10, 10), [-3, 1], True), + "4d_dims_no_keep": lambda: (torch.rand(1, 1, 5, 8), 1, False), + "4d_dim_3_keep": lambda: (torch.rand(1, 2, 3, 4), 3, True), + "4d_dims_keep": lambda: (torch.rand(1, 2, 8, 8), [2, 3, 0], True), + "dim_None": lambda: (torch.rand(10), None, True), + "dim_None_4d_tensor": lambda: (torch.rand(10, 3, 2, 1), None, True), + } + + def forward(self, x: torch.Tensor, dim: int, keepdim: bool): + return x.sum(dim=dim, keepdim=keepdim) + + +@common.parametrize("test_data", Sum.test_parameters) +def test_sum_dim_intlist_tosa_FP(test_data: input_t1): + pipeline = TosaPipelineFP[input_t1]( + Sum(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +def test_sum_dim_intlist_tosa_INT(test_data: input_t1): + pipeline = TosaPipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.XfailIfNoCorstone300 +def test_view_u55_INT_1_0(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.XfailIfNoCorstone320 +def test_view_u85_INT_1_0(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.SkipIfNoModelConverter +def test_sum_dim_intlist_vgf_no_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Sum(), + test_data(), + aten_op, + run_on_vulkan_runtime=True, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Sum.test_parameters) +@common.SkipIfNoModelConverter +def test_sum_dim_intlist_vgf_quant(test_data: input_t1): + pipeline = VgfPipeline[input_t1]( + Sum(), + test_data(), + aten_op, + run_on_vulkan_runtime=True, + quantize=True, + ) + pipeline.run() + + +reject_inputs = { + "reject_large_0_dim": lambda: (torch.rand((65537, 1, 1)), 0, False), + "reject_large_2_dim": lambda: (torch.rand((800, 90, 1)), 2, False), + "reject_large_1_dim": lambda: (torch.rand((3, 2, 800, 90)), 1, False), +} + + +@common.parametrize("test_data", reject_inputs) +def test_view_u55_INT_failure_set(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Sum(), + test_data(), + aten_op, + exir_ops=[], + run_on_fvp=False, # Run fails since we are missing a non partitioned sum op + ) + pipeline.pop_stage("check_count.exir") + pipeline.run() + + +input_t2 = tuple[torch.Tensor] + + +class SumDefault(torch.nn.Module): + test_parameters = { + "rank1": lambda: (torch.rand(10),), + "rank2": lambda: (torch.rand(10, 1, 10),), + "rank4": lambda: (torch.rand(1, 1, 5, 8),), + } + aten_op = "torch.ops.aten.sum.default" + + def forward(self, x: torch.Tensor): + return x.sum() + + +@common.parametrize("test_data", SumDefault.test_parameters) +def test_sum_tosa_FP(test_data: Callable[[], input_t2]): + pipeline = TosaPipelineFP[input_t2](SumDefault(), test_data(), SumDefault.aten_op) + pipeline.run() + + +@common.parametrize("test_data", SumDefault.test_parameters) +def test_sum_tosa_INT(test_data: Callable[[], input_t2]): + pipeline = TosaPipelineINT[input_t1](SumDefault(), test_data(), SumDefault.aten_op) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_t_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_t_copy.py new file mode 100644 index 0000000..705e812 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_t_copy.py @@ -0,0 +1,115 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # test_name: (test_data, min, max) + "rand": lambda: (torch.rand(2, 3),), + "rand_multiplied": lambda: (torch.rand(3, 4) * 10,), + "ones": lambda: (torch.ones(5, 10),), + "randn": lambda: (torch.randn(1, 10) * 2,), +} + + +class TCopy(torch.nn.Module): + aten_op = "torch.ops.aten.t_copy.default" + exir_op = "executorch_exir_dialects_edge__ops_aten_permute_copy_default" + + def forward(self, x: torch.Tensor): + return torch.t_copy(x) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_data", test_data_suite) +def test_t_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_t_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_t_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + TCopy(), + test_data(), + aten_ops=TCopy.aten_op, + exir_ops=[], + use_to_edge_transform_and_lower=True, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_t_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + TCopy(), + test_data(), + aten_ops=TCopy.aten_op, + exir_ops=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_t_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_t_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TCopy(), + test_data(), + aten_op=TCopy.aten_op, + exir_op=TCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tan.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tan.py new file mode 100644 index 0000000..cf711bf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tan.py @@ -0,0 +1,146 @@ +# Copyright 2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = Tuple[torch.Tensor] + +aten_op = "torch.ops.aten.tan.default" +exir_op = "executorch_exir_dialects_edge__ops_aten__tan_default" + +eps32 = torch.finfo(torch.float32).eps +tiny32 = torch.finfo(torch.float32).tiny + +test_data_suite = { + "zeros": torch.zeros(1, 10, 10, 10), + "zeros_alt_shape": torch.zeros(1, 10, 3, 5), + "ones": torch.ones(10, 15, 25), + "rand": torch.rand(10, 10) - 0.5, + "rand_alt_shape": torch.rand(1, 10, 3, 5) - 0.5, + "randn_pos": torch.randn(10) + 10, + "randn_neg": torch.randn(10) - 10, + "ramp": torch.arange(-16, 16, 0.2), + "pi_multiples": (torch.arange(-5, 6, dtype=torch.float32) * math.pi), + "common_angles": torch.tensor( + [ + -math.pi, + -2 * math.pi / 3, + -math.pi / 2 + 1e-3, + -math.pi / 3, + -math.pi / 4, + -math.pi / 6, + 0.0, + math.pi / 6, + math.pi / 4, + math.pi / 3, + math.pi / 2 - 1e-3, + 2 * math.pi / 3, + math.pi, + ], + dtype=torch.float32, + ), + "near_asymptote_pos": torch.tensor( + [ + math.pi / 2 - 1e-7, + math.pi / 2 - 1e-6, + math.pi / 2 - 1e-4, + math.pi / 2 + 1e-7, + math.pi / 2 + 1e-6, + math.pi / 2 + 1e-4, + ], + dtype=torch.float32, + ), + "high_rank": torch.randn(1, 3, 7, 4, 5), + "very_small": torch.tensor( + [-tiny32, -eps32, -1e-10, 0.0, 1e-10, eps32, tiny32], dtype=torch.float32 + ), + "large_values": torch.linspace(-1e6, 1e6, steps=257, dtype=torch.float32), + "undefined": torch.tensor([math.pi / 2, -math.pi / 2, 3 * math.pi / 2]), +} + + +class Tan(torch.nn.Module): + + def forward(self, x: torch.Tensor): + return torch.tan(x) + + +@common.parametrize("test_data", test_data_suite) +def test_tan_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t]( + Tan(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_tan_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t]( + Tan(), + (test_data,), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_tan_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t]( + Tan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_tan_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t]( + Tan(), + (test_data,), + aten_ops=aten_op, + exir_ops=exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tan_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t](Tan(), (test_data,), [], [], quantize=False) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tan_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t]( + Tan(), + (test_data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tanh.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tanh.py new file mode 100644 index 0000000..c2b5e88 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_tanh.py @@ -0,0 +1,169 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.tanh.default" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data) + "zeros": lambda: torch.zeros(10, 10, 10, 10), + "ones": lambda: torch.ones(10, 10, 10), + "rand": lambda: torch.rand(10, 10) - 0.5, + "randn_pos": lambda: torch.randn(10) + 10, + "randn_neg": lambda: torch.randn(10) - 10, + "ramp": lambda: torch.arange(-16, 16, 0.2), +} + + +class Tanh(torch.nn.Module): + def __init__(self): + super().__init__() + self.tanh = torch.nn.Tanh() + + def forward(self, x): + return self.tanh(x) + + +@common.parametrize("test_data", test_data_suite) +def test_tanh_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_tanh_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_tanh_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_tanh_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tanh_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Tanh(), + (test_data(),), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_tanh_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + Tanh(), + (test_data(),), + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_tanh_16a8w_tosa_INT(test_data: torch.Tensor): + """Test tanh operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = TosaPipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + epsilon=2**-16, + rtol=2e-03, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone300 +def test_tanh_16a8w_u55_INT16(test_data: torch.Tensor): + """Test tanh operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU55PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + a16w8_quantization=True, + epsilon=2**-16, + rtol=2e-03, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.XfailIfNoCorstone320 +def test_tanh_16a8w_u85_INT(test_data: torch.Tensor): + """Test tanh operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + + pipeline = EthosU85PipelineINT[input_t1]( + Tanh(), + (test_data(),), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + a16w8_quantization=True, + epsilon=2**-16, + rtol=2e-03, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_to_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_to_copy.py new file mode 100644 index 0000000..114051d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_to_copy.py @@ -0,0 +1,296 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the _to_copy op which is interpreted as a cast for our purposes. +# + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Cast(torch.nn.Module): + def __init__(self, target_dtype): + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor): + return x.to(dtype=self.target_dtype) + + +class CastAdd(torch.nn.Module): + def __init__(self, target_dtype): + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor): + return x.to(dtype=self.target_dtype) + x.to(dtype=self.target_dtype) + + +""" +Tests the _to_copy operation. + +Only test unquantized graphs as explicit casting of dtypes messes with the +quantization. +However, the model being exported may have some explicit casting to floating +point dtypes. The casting or their decomposition should be rejected during +partition. This test will be coveraged by class TestToCopy_INT. + +Note: This is also covered by test_scalars.py. +""" + +_TO_COPY_TEST_DATA_FP = { + "rand_fp16": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float16), torch.float32), + "rand_fp32": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float32), torch.float16), + "rand_int8": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.float32, + ), + "rand_int8_int32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.int32, + ), + "rand_int32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.int8, + ), +} + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_FP) +def test_to_tosa_FP(test_data: Tuple): + test_tensor, new_dtype = test_data() + + pipeline = TosaPipelineFP[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + ) + # int to int cast is not supported in TOSA+FP profile + if not new_dtype.is_floating_point and not torch.is_floating_point(test_tensor): + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 0, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + }, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_FP) +@common.SkipIfNoModelConverter +def test_to_vgf_no_quant(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = VgfPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + quantize=False, + ) + pipeline.run() + + +""" +Casting operations that output floating-point dtypes should be rejected under INT profile, +rather than introducing an invalid dtype into the tosa graph. +For example, x.to(dtype=torch.float32) will be eventually lowered to +exir_ops.edge.dim_order_ops._to_dim_order_copy.default. We should reject this operation +in ToCopySupported::is_node_tosa_supported() before it goes into the delegated graph. +""" +_TO_COPY_TEST_DATA_INT = { + "rand_int8_fp32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.float32, + ), + "rand_int16_fp32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int16), + torch.float32, + ), + "rand_int32_fp32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.float32, + ), + "rand_int32_fp16": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.float16, + ), + "rand_int32_bf16": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.bfloat16, + ), +} + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT) +def test_to_tosa_INT_not_delegated(test_data: Tuple): + test_tensor, new_dtype = test_data() + + pipeline = OpNotSupportedPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1 + }, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT) +@common.SkipIfNoModelConverter +def test_to_vgf_quant(test_data: Tuple): + # Op not supported + pass + + +_TO_COPY_TEST_DATA_REDUNDANT_CAST = { + "rand_fp16_fp16": lambda: ( + torch.rand((1, 2, 3, 4), dtype=torch.float16), + torch.float16, + ), + "rand_fp32_fp32": lambda: ( + torch.rand((1, 2, 3, 4), dtype=torch.float32), + torch.float32, + ), + "rand_int8_int8": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int8), + torch.int8, + ), + "rand_int16_int16": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int16), + torch.int16, + ), + "rand_int32_int32": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.int32, + ), +} + +redundant_xfails = { + "rand_fp16_fp16": "FP16 is not supported", + "rand_int8_int8": "Tracing graph with quantized input is not supported.", + "rand_int16_int16": "Tracing graph with quantized input is not supported.", +} + + +@common.parametrize( + "test_data", _TO_COPY_TEST_DATA_REDUNDANT_CAST, xfails=redundant_xfails +) +def test_to_tosa_FP_REDUNDANT_CAST(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = TosaPipelineFP[input_t1]( + CastAdd(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize( + "test_data", _TO_COPY_TEST_DATA_REDUNDANT_CAST, xfails=redundant_xfails +) +def test_to_tosa_INT_REDUNDANT_CAST(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = TosaPipelineINT[input_t1]( + CastAdd(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_REDUNDANT_CAST) +def test_to_tosa_INT_not_delegated_REDUNDANT_CAST(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + non_delegated_ops={}, # These are removed outside of the Arm backend so the graph is empty + ) + pipeline.run() + + +_TO_COPY_DATA_INT_U55_REJECT = { + "rand_bool_int8": lambda: ( + torch.randint(0, 2, (1, 2, 3, 4), dtype=torch.bool), + torch.int8, + ), + "rand_int16_bool": lambda: ( + torch.randint(-1000, 1000, (1, 2, 3, 4), dtype=torch.int16), + torch.bool, + ), + "rand_int32_int8": lambda: ( + torch.randint(-1000, 1000, (1, 2, 3, 4), dtype=torch.int32), + torch.int8, + ), +} + + +@common.parametrize("test_data", _TO_COPY_DATA_INT_U55_REJECT) +def test_to_u55_INT(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + u55_subset=True, + quantize=True, + non_delegated_ops={}, # These are removed outside of the Arm backend so the graph is empty + ) + pipeline.run() + + +_TO_COPY_TEST_DATA_INT_FP = { + "bool_fp32": lambda: ( + torch.tensor([True, False], dtype=torch.bool), + torch.float32, + ), +} + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT_FP) +@common.SkipIfNoModelConverter +def test_to_vgf_no_quant_bool_fp32(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = VgfPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", _TO_COPY_TEST_DATA_INT_FP) +@common.SkipIfNoModelConverter +def test_to_vgf_quant_bool_fp32(test_data: Tuple): + test_tensor, new_dtype = test_data() + pipeline = VgfPipeline[input_t1]( + Cast(new_dtype), + (test_tensor,), + aten_op=[], + exir_op=[], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_transpose_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_transpose_copy.py new file mode 100644 index 0000000..fb521ed --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_transpose_copy.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +test_data_suite = { + # test_name: (test_data, min, max) + "rank_2": lambda: (torch.rand(2, 3), 0, 1), + "rank_2_swapped": lambda: (torch.rand(3, 4), 1, 0), + "rank_3": lambda: (torch.ones(5, 10, 10), 1, 2), + "rank_4": lambda: (torch.rand(1, 10, 4, 2) * 2, 2, 0), +} + + +class TransposeCopy(torch.nn.Module): + aten_op = "torch.ops.aten.transpose_copy.int" + exir_op = "executorch_exir_dialects_edge__ops_aten_permute_copy_default" + + def forward(self, x: torch.Tensor, dim0: int, dim1: int): + return torch.transpose_copy(x, dim0=dim0, dim1=dim1) + + +input_t1 = Tuple[torch.Tensor] + + +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_tosa_FP(test_data: Tuple): + pipeline = TosaPipelineFP[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_tosa_INT(test_data: Tuple): + pipeline = TosaPipelineINT[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone300 +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_u55_INT(test_data: Tuple): + pipeline = EthosU55PipelineINT[input_t1]( + TransposeCopy(), + test_data(), + aten_ops=TransposeCopy.aten_op, + exir_ops=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.XfailIfNoCorstone320 +@common.parametrize("test_data", test_data_suite) +def test_transpose_int_u85_INT(test_data: Tuple): + pipeline = EthosU85PipelineINT[input_t1]( + TransposeCopy(), + test_data(), + aten_ops=TransposeCopy.aten_op, + exir_ops=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_transpose_int_vgf_no_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_transpose_int_vgf_quant(test_data: Tuple): + pipeline = VgfPipeline[input_t1]( + TransposeCopy(), + test_data(), + aten_op=TransposeCopy.aten_op, + exir_op=TransposeCopy.exir_op, + use_to_edge_transform_and_lower=False, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unary_combos.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unary_combos.py new file mode 100644 index 0000000..f938e1d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unary_combos.py @@ -0,0 +1,144 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import pytest + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +Tensor1 = Tuple[torch.Tensor] + + +class NegAdd(torch.nn.Module): + # neg(x) + 1 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_neg_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10),) + + def forward(self, x): + return torch.neg(x) + 1.0 + + +class MinAddZero(torch.nn.Module): + # min(x, 0) + 1 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_full_like_default", + "executorch_exir_dialects_edge__ops_aten_minimum_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + # range [-1, 1] + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10) * 2 - 1,) + + def forward(self, x): + # We want Tensor-Tensor minimum + z = torch.full_like(x, 0.0) + return torch.minimum(x, z) + 1.0 + + +class MaxAddZero(torch.nn.Module): + # max(x, 0) + 1.0 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_full_like_default", + "executorch_exir_dialects_edge__ops_aten_maximum_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + # range [-1, 1] + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10) * 2 - 1,) + + def forward(self, x): + z = torch.full_like(x, 0.0) + return torch.maximum(x, z) + 1.0 + + +class AbsAdd(torch.nn.Module): + # abs(x) + 1.0 + edge_op_list = [ + "executorch_exir_dialects_edge__ops_aten_abs_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + + def get_inputs(self) -> Tensor1: + return (torch.rand(10, 10, 10),) + + def forward(self, x): + return torch.abs(x) + 1.0 + + +MODELS = [NegAdd, AbsAdd, MaxAddZero, MinAddZero] + + +def _build(model_cls): + m = model_cls() + return m, m.get_inputs(), model_cls.edge_op_list + + +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_tosa_FP_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = TosaPipelineFP[Tensor1](m, inputs, aten_op=[], exir_op=exir) + p.run() + + +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_tosa_INT_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = TosaPipelineINT[Tensor1](m, inputs, aten_op=[], exir_op=exir, qtol=1) + p.run() + + +@common.XfailIfNoCorstone300 +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_u55_INT_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = EthosU55PipelineINT[Tensor1]( + m, + inputs, + aten_ops=[], + exir_ops=exir, + ) + p.run() + + +@common.XfailIfNoCorstone320 +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_u85_INT_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = EthosU85PipelineINT[Tensor1]( + m, + inputs, + aten_ops=[], + exir_ops=exir, + ) + p.run() + + +@common.SkipIfNoModelConverter +@pytest.mark.parametrize("model_cls", MODELS, ids=lambda c: c.__name__) +def test_add_tensor_vgf_quant_combos(model_cls): + m, inputs, exir = _build(model_cls) + p = VgfPipeline[Tensor1]( + m, + inputs, + aten_op=[], + exir_op=exir, + quantize=True, + ) + p.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unbind.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unbind.py new file mode 100644 index 0000000..ce3f769 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unbind.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class Unbind(torch.nn.Module): + aten_op: str = "torch.ops.aten.unbind.int" + + def __init__(self, dim: int): + super().__init__() + self.dim = dim + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor]: + return torch.unbind(x, self.dim) + + test_data: dict[str, test_data_t] = { + "randn_4d": (lambda: (torch.randn(1, 5, 4, 3),), (2,)), + "randn_3d": (lambda: (torch.randn(5, 4, 3),), (0,)), + } + + +@common.parametrize("test_data", Unbind.test_data) +def test_unbind_int_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unbind.test_data) +def test_unbind_int_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unbind.test_data) +@common.SkipIfNoModelConverter +def test_unbind_int_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Unbind.test_data) +@common.SkipIfNoModelConverter +def test_unbind_int_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + Unbind(*init_data), + input_data(), + Unbind.aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unflatten.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unflatten.py new file mode 100644 index 0000000..d4730ac --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unflatten.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[torch.nn.Module, input_t] + + +class Unflatten(torch.nn.Module): + aten_op: str = "torch.ops.aten.unflatten.int" + + def __init__(self, dim: int, sizes: Tuple[int, ...]): + super().__init__() + self.dim = dim + self.sizes = sizes + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.unflatten(x, self.dim, self.sizes) + + test_data: dict[str, test_data_t] = { + "rand_3d_batch3": (lambda: (Unflatten(1, (-1, 2)), (torch.rand(3, 4, 4),))), + "rand_3d_batch1": (lambda: (Unflatten(1, (-1, 2)), (torch.rand(1, 4, 4),))), + "randn_4d_dim1": (lambda: (Unflatten(1, (2, 2)), (torch.randn(3, 4, 5, 1),))), + "randn_4d_dim3": (lambda: (Unflatten(3, (2, 2)), (torch.randn(1, 1, 5, 4),))), + } + + +@common.parametrize("test_data", Unflatten.test_data) +def test_unflatten_int_tosa_FP(test_data: test_data_t): + module, inputs = test_data() + pipeline = TosaPipelineFP[input_t]( + module, + inputs, + Unflatten.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data) +def test_unflatten_int_tosa_INT(test_data: test_data_t): + module, inputs = test_data() + pipeline = TosaPipelineINT[input_t](module, inputs, Unflatten.aten_op) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data, strict=False) +@common.XfailIfNoCorstone300 +def test_unflatten_int_u55_INT(test_data: test_data_t): + module, inputs = test_data() + pipeline = EthosU55PipelineINT[input_t]( + module, + inputs, + Unflatten.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data, strict=False) +@common.XfailIfNoCorstone320 +def test_unflatten_int_u85_INT(test_data: test_data_t): + module, inputs = test_data() + pipeline = EthosU85PipelineINT[input_t]( + module, + inputs, + Unflatten.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data) +@common.SkipIfNoModelConverter +def test_unflatten_int_vgf_no_quant(test_data: test_data_t): + module, inputs = test_data() + pipeline = VgfPipeline[input_t]( + module, + inputs, + Unflatten.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Unflatten.test_data) +@common.SkipIfNoModelConverter +def test_unflatten_int_vgf_quant(test_data: test_data_t): + module, inputs = test_data() + pipeline = VgfPipeline[input_t]( + module, + inputs, + Unflatten.aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unsqueeze.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unsqueeze.py new file mode 100644 index 0000000..0c29d3b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_unsqueeze.py @@ -0,0 +1,107 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the unsqueeze op which copies the data of the input tensor (possibly with new data format) +# + +from typing import Sequence, Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.unsqueeze.default" +input_t1 = Tuple[torch.Tensor, torch.scalar_tensor] # Input x, Input y + + +class Unsqueeze(torch.nn.Module): + shapes: list[int | Sequence[int]] = [5, (5, 5), (5, 4), (5, 4, 3), (1, 5, 4, 3)] + test_parameters = {} + for n in shapes: + test_parameters[f"rand_{n}"] = (torch.randn(n),) + + def forward(self, x: torch.Tensor, dim): + return x.unsqueeze(dim) + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +def test_unsqueeze_tosa_FP(test_tensor: torch.Tensor): + for i in range(-test_tensor[0].dim() - 1, test_tensor[0].dim() + 1): + pipeline = TosaPipelineFP[input_t1]( + Unsqueeze(), + (*test_tensor, i), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +def test_unsqueeze_tosa_INT(test_tensor: torch.Tensor): + pipeline = TosaPipelineINT[input_t1]( + Unsqueeze(), + (*test_tensor, 0), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.XfailIfNoCorstone300 +def test_unsqueeze_u55_INT(test_tensor: torch.Tensor): + pipeline = EthosU55PipelineINT[input_t1]( + Unsqueeze(), + (*test_tensor, 0), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.XfailIfNoCorstone320 +def test_unsqueeze_u85_INT(test_tensor: torch.Tensor): + pipeline = EthosU85PipelineINT[input_t1]( + Unsqueeze(), + (*test_tensor, 0), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.SkipIfNoModelConverter +def test_unsqueeze_vgf_no_quant(test_tensor: torch.Tensor): + for i in range(-test_tensor[0].dim() - 1, test_tensor[0].dim() + 1): + pipeline = VgfPipeline[input_t1]( + Unsqueeze(), + (*test_tensor, i), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_tensor", Unsqueeze.test_parameters) +@common.SkipIfNoModelConverter +def test_unsqueeze_vgf_quant(test_tensor: torch.Tensor): + for i in range(-test_tensor[0].dim() - 1, test_tensor[0].dim() + 1): + pipeline = VgfPipeline[input_t1]( + Unsqueeze(), + (*test_tensor, i), + aten_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_bilinear2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_bilinear2d.py new file mode 100644 index 0000000..11ac351 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_bilinear2d.py @@ -0,0 +1,443 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.upsample_bilinear2d.vec" +exir_op = "executorch_exir_dialects_edge__ops_aten_upsample_bilinear2d_vec" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite_tosa = { + # (test_name, test_data, size, scale_factor, compare_outputs) + "rand_double_scale": (torch.rand(2, 4, 8, 3), None, 2.0, True), + "rand_double_scale_one_dim": (torch.rand(2, 4, 8, 3), None, (1.0, 2.0), True), + "rand_double_size": (torch.rand(2, 4, 8, 3), (16, 6), None, True), + "rand_one_double_scale": (torch.rand(2, 4, 1, 1), None, 2.0, True), + "rand_one_double_size": (torch.rand(2, 4, 1, 1), (2, 2), None, True), + "rand_one_same_scale": (torch.rand(2, 4, 1, 1), None, 1.0, True), + "rand_one_same_size": (torch.rand(2, 4, 1, 1), (1, 1), None, True), + # Can't compare outputs as the rounding when selecting the nearest pixel is + # different between PyTorch and TOSA. Just check the legalization went well. + # TODO Improve the test infrastructure to support more in depth verification + # of the TOSA legalization results. + "rand_half_scale": (torch.rand(2, 4, 8, 6), None, 0.5, False), + "rand_half_size": (torch.rand(2, 4, 8, 6), (4, 3), None, False), + "rand_one_and_half_scale": (torch.rand(2, 4, 8, 3), None, 1.5, False), + "rand_one_and_half_size": (torch.rand(2, 4, 8, 3), (12, 4), None, False), + # Use randn for a bunch of tests to get random numbers from the + # normal distribution where negative is also a possibilty + "randn_double_scale_negative": (torch.randn(2, 4, 8, 3), None, 2.0, True), + "randn_double_scale_one_dim_negative": ( + torch.randn(2, 4, 8, 3), + None, + (1.0, 2.0), + True, + ), + "randn_double_size_negative": (torch.randn(2, 4, 8, 3), (16, 6), None, True), + "randn_one_double_scale_negative": (torch.randn(2, 4, 1, 1), None, 2.0, True), + "randn_one_double_size_negative": (torch.randn(2, 4, 1, 1), (2, 2), None, True), + "randn_one_same_scale_negative": (torch.randn(2, 4, 1, 1), None, 1.0, True), + "randn_one_same_size_negative": (torch.randn(2, 4, 1, 1), (1, 1), None, True), +} + +test_data_suite_Uxx = { + "rand_half_scale": (torch.rand(2, 4, 8, 6), None, 0.5, False), + "rand_half_size": (torch.rand(2, 4, 8, 6), (4, 3), None, False), + "rand_one_and_half_scale": (torch.rand(2, 4, 8, 3), None, 1.5, False), + "rand_one_and_half_size": (torch.rand(2, 4, 8, 3), (12, 4), None, False), +} + +test_data_u55 = { + "rand_double_size": (torch.rand(2, 4, 8, 3), (16, 6), None, True), +} + + +class UpsamplingBilinear2d(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.UpsamplingBilinear2d( # noqa: TOR101 + size=size, scale_factor=scale_factor + ) + + def forward(self, x): + return self.upsample(x) + + +class Upsample(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.Upsample( + size=size, scale_factor=scale_factor, mode="bilinear", align_corners=True + ) + + def forward(self, x): + return self.upsample(x) + + +class Interpolate(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = lambda x: torch.nn.functional.interpolate( + x, size=size, scale_factor=scale_factor, mode="bilinear", align_corners=True + ) + + def forward(self, x): + return self.upsample(x) + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_FP_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineFP[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_FP_Upsample( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineFP[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_FP_Interpolate( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineFP[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_INT_intropolate( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineINT[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_INT_Upsample( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +def test_upsample_bilinear2d_vec_tosa_INT_a16w8( + test_data: torch.Tensor, +): + """Test upsample_bilinear2d vector op with int16 I/O quantization for TOSA INT.""" + test_data, size, scale_factor, compare_outputs = test_data + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + tosa_extensions=["int16"], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_bilinear2d_vec_u55_INT_Upsample_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + pipeline = OpNotSupportedPipeline[input_t1]( + Upsample(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_bilinear2d_vec_u55_INT_Interpolate_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + pipeline = OpNotSupportedPipeline[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_bilinear2d_vec_u55_INT_UpsamplingBilinear2d_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + pipeline = OpNotSupportedPipeline[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_Upsample(test_data: input_t1): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + qtol=1, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_Interpolate( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + qtol=1, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (test_data,), + aten_op, + qtol=1, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_Uxx) +@common.XfailIfNoCorstone320 +def test_upsample_bilinear2d_vec_u85_INT_a16w8( + test_data: input_t1, +): + """Test upsample_bilinear2d vec op with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + data, size, scale_factor, compare_outputs = test_data + + pipeline = EthosU85PipelineINT[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (data,), + aten_op, + per_channel_quantization=False, + a16w8_quantization=True, + use_to_edge_transform_and_lower=True, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_no_quant_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_no_quant_Upsample(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_no_quant_Interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_quant_UpsamplingBilinear2d( + test_data: torch.Tensor, +): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + UpsamplingBilinear2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_quant_Upsample(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_tosa) +@common.SkipIfNoModelConverter +def test_upsample_bilinear2d_vec_vgf_quant_Interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_nearest2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_nearest2d.py new file mode 100644 index 0000000..cb7d487 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_upsample_nearest2d.py @@ -0,0 +1,520 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +aten_op = "torch.ops.aten.upsample_nearest2d.vec" +exir_op = "executorch_exir_dialects_edge__ops_aten_upsample_nearest2d_vec" +input_t1 = Tuple[torch.Tensor] # Input x + +test_data_suite = { + # (test_name, test_data, size, scale_factor, compare_outputs) + "rand_double_scale": lambda: (torch.rand(2, 4, 8, 3), None, 2.0, True), + "rand_double_scale_one_dim": lambda: ( + torch.rand(2, 4, 8, 3), + None, + (1.0, 2.0), + True, + ), + "rand_double_size": lambda: (torch.rand(2, 4, 8, 3), (16, 6), None, True), + "rand_one_double_scale": lambda: (torch.rand(2, 4, 1, 1), None, 2.0, True), + "rand_one_double_size": lambda: (torch.rand(2, 4, 1, 1), (2, 2), None, True), + "rand_one_same_scale": lambda: (torch.rand(2, 4, 1, 1), None, 1.0, True), + "rand_one_same_size": lambda: (torch.rand(2, 4, 1, 1), (1, 1), None, True), + # Can't compare outputs as the rounding when selecting the nearest pixel is + # different between PyTorch and TOSA. Just check the legalization went well. + # TODO Improve the test infrastructure to support more in depth verification + # of the TOSA legalization results. + "rand_half_scale": lambda: (torch.rand(2, 4, 8, 6), None, 0.5, False), + "rand_half_size": lambda: (torch.rand(2, 4, 8, 6), (4, 3), None, False), + "rand_one_and_half_scale": lambda: (torch.rand(2, 4, 8, 3), None, 1.5, False), + "rand_one_and_half_size": lambda: (torch.rand(2, 4, 8, 3), (12, 4), None, False), +} + +test_data_u55 = { + "rand_double_size": lambda: (torch.rand(2, 4, 8, 3), (16, 6), None, True), +} + +test_data_suite_dynamic = { + # (test_name, test_data, size, scale_factor, compare_outputs) + "rand_double_scale": lambda: (torch.rand(2, 4, 8, 3), None, 2.0, False), + "rand_double_scale_one_dim": lambda: ( + torch.rand(2, 4, 8, 3), + None, + (1.0, 2.0), + False, + ), +} + + +class UpsamplingNearest2d(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.UpsamplingNearest2d( # noqa: TOR101 + size=size, scale_factor=scale_factor + ) + + def forward(self, x): + return self.upsample(x) + + +class Upsample(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = torch.nn.Upsample( + size=size, scale_factor=scale_factor, mode="nearest" + ) + + def forward(self, x): + return self.upsample(x) + + +class Interpolate(torch.nn.Module): + def __init__( + self, + size: Optional[Tuple[int]], + scale_factor: Optional[float | Tuple[float]], + ): + super().__init__() + self.upsample = lambda x: torch.nn.functional.interpolate( + x, size=size, scale_factor=scale_factor, mode="nearest" + ) + + def forward(self, x): + return self.upsample(x) + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_FP(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineFP[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_FP_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = TosaPipelineFP[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_FP_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineFP[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineINT[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + pipeline = TosaPipelineINT[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +def test_upsample_nearest2d_vec_tosa_INT_a16w8(test_data: torch.Tensor): + """Test upsample_nearest2d vector op with int16 I/O quantization for TOSA INT.""" + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + tosa_extensions=["int16"], + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_no_quant(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_no_quant_nearest(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_no_quant_interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=False, + # Override tosa version to test FP-only path + tosa_version="TOSA-1.0+FP", + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_quant(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_quant_nearest(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Upsample(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite) +@common.SkipIfNoModelConverter +def test_upsample_nearest2d_vec_vgf_INT_interpolate(test_data: torch.Tensor): + data, size, scale_factor, compare = test_data() + pipeline = VgfPipeline[input_t1]( + Interpolate(size, scale_factor), + (data,), + aten_op, + exir_op, + quantize=True, + # Override tosa version to test INT-only path + tosa_version="TOSA-1.0+INT", + ) + if not compare: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_nearest2d_vec_u55_INT_Upsample_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Upsample(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_nearest2d_vec_u55_INT_Interpolate_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_u55) +@common.XfailIfNoCorstone300 +def test_upsample_nearest2d_vec_u55_INT_UpsamplingBilinear2d_not_delegated( + test_data: torch.Tensor, +): + test_data, size, scale_factor, compare_outputs = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + {exir_op: 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_FP_dynamic_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=1000) + input_height = torch.export.Dim("input_height", min=0, max=1000) + input_width = torch.export.Dim("input_width", min=0, max=1000) + + dynamic_shapes = {"x": {0: batch_size, 2: input_height, 3: input_width}} + + pipeline = TosaPipelineFP[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_INT_dynamic_nearest(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=0, max=8) + input_width = torch.export.Dim("input_width", min=0, max=8) + + dynamic_shapes = {"x": {0: batch_size, 2: input_height, 3: input_width}} + + pipeline = TosaPipelineINT[input_t1]( + UpsamplingNearest2d(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_FP_dynamic_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=4, max=8) + input_width = torch.export.Dim("input_width", min=3, max=8) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineFP[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_INT_dynamic_interpolate(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=4, max=8) + input_width = torch.export.Dim("input_width", min=3, max=8) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineINT[input_t1]( + Interpolate(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_FP_dynamic_upsample(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=1000) + input_height = torch.export.Dim("input_height", min=0, max=1000) + input_width = torch.export.Dim("input_width", min=0, max=1000) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineFP[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_dynamic) +def test_upsample_nearest2d_vec_tosa_INT_dynamic_upsample(test_data: torch.Tensor): + test_data, size, scale_factor, compare_outputs = test_data() + + batch_size = torch.export.Dim("batch", min=0, max=2) + input_height = torch.export.Dim("input_height", min=0, max=8) + input_width = torch.export.Dim("input_width", min=0, max=8) + + dynamic_shapes = { + "x": { + 0: batch_size, + 2: input_height, + 3: input_width, + } + } + + pipeline = TosaPipelineINT[input_t1]( + Upsample(size, scale_factor), + (test_data,), + aten_op, + exir_op=[], + dynamic_shapes=dynamic_shapes, + ) + if not compare_outputs: + pipeline.pop_stage(-1) + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_var.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_var.py new file mode 100644 index 0000000..a7943bf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_var.py @@ -0,0 +1,394 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class Var(torch.nn.Module): + test_parameters = { + "var_4d_keep_dim_0_correction": lambda: (torch.randn(1, 50, 10, 20), True, 0), + "var_3d_no_keep_dim_0_correction": lambda: (torch.rand(1, 50, 10), False, 0), + "var_4d_keep_dim_1_correction": lambda: (torch.randn(1, 30, 15, 20), True, 1), + "var_4d_no_keep_dim_0_5_correction": lambda: ( + torch.rand(1, 50, 10, 20), + False, + 0.5, + ), + } + + def __init__(self, keepdim: bool = True, correction: int = 0): + super().__init__() + self.keepdim = keepdim + self.correction = correction + + def forward( + self, + x: torch.Tensor, + ): + return x.var(keepdim=self.keepdim, correction=self.correction) + + +class VarDim(torch.nn.Module): + test_parameters = { + "var_4d_dim_1_keep_dim_unbiased": lambda: ( + torch.randn(1, 50, 10, 20), + 1, + True, + False, + ), + "var_3d_dim_neg_2_no_keep_dim_unbiased": lambda: ( + torch.rand(1, 50, 10), + -2, + False, + False, + ), + "var_3d_dim_neg_3_keep_dim_biased": lambda: ( + torch.randn(1, 30, 15, 20), + -3, + True, + True, + ), + "var_3d_dim_neg_1_no_keep_dim_biased": lambda: ( + torch.rand(1, 50, 10, 20), + -1, + False, + True, + ), + } + + test_parameters_u55 = { + "var_4d_dim_1_keep_dim_unbiased": lambda: ( + torch.randn(1, 50, 10, 20), + 1, + True, + False, + ), + "var_4d_dim_neg_3_keep_dim_biased": lambda: ( + torch.randn(1, 30, 15, 20), + -3, + True, + True, + ), + } + + def __init__(self, dim: int = -1, keepdim: bool = True, unbiased: bool = False): + super().__init__() + self.dim = dim + self.keepdim = keepdim + self.unbiased = unbiased + + def forward( + self, + x: torch.Tensor, + ): + return x.var(dim=self.dim, keepdim=self.keepdim, unbiased=self.unbiased) + + +class VarCorrection(torch.nn.Module): + test_parameters = { + "var_4d_dims_keep_dim_0_correction": lambda: ( + torch.randn(1, 50, 10, 20), + (-1, -2), + True, + 0, + ), + "var_3d_dims_keep_dim_0_correction": lambda: ( + torch.rand(1, 50, 10), + (-2), + True, + 0, + ), + "var_4d_dims_keep_dim_1_correction": lambda: ( + torch.randn(1, 30, 15, 20), + (-1, -2, -3), + True, + 1, + ), + "var_4d_dims_keep_dim_0_5_correction": lambda: ( + torch.rand(1, 50, 10, 20), + (-1, -2), + True, + 0.5, + ), + } + + def __init__(self, dim: int = -1, keepdim: bool = True, correction: bool = False): + super().__init__() + self.dim = dim + self.keepdim = keepdim + self.correction = correction + + def forward( + self, + x: torch.Tensor, + ): + return x.var(dim=self.dim, keepdim=self.keepdim, correction=self.correction) + + +########## +## Var ### +########## + + +@common.parametrize("test_data", Var.test_parameters) +def test_var_dim_tosa_FP_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = TosaPipelineFP[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +def test_var_dim_tosa_INT_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = TosaPipelineINT[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.XfailIfNoCorstone300 +def test_var_dim_u55_INT_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.XfailIfNoCorstone320 +def test_var_dim_u85_INT_no_dim(test_data: Tuple): + test_data, keepdim, correction = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + Var(keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_no_quant_no_dim(test_data: Tuple): + data, keepdim, correction = test_data() + pipeline = VgfPipeline[input_t1]( + Var(keepdim, correction), + (data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", Var.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_quant_no_dim(test_data: Tuple): + data, keepdim, correction = test_data() + pipeline = VgfPipeline[input_t1]( + Var(keepdim, correction), + (data,), + [], + [], + quantize=True, + ) + pipeline.run() + + +############# +## VarDim ### +############# + + +@common.parametrize("test_data", VarDim.test_parameters) +def test_var_dim_tosa_FP(test_data: Tuple): + test_data, dim, keepdim, unbiased = test_data() + pipeline = TosaPipelineFP[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +def test_var_dim_tosa_INT(test_data: Tuple): + + test_data, dim, keepdim, unbiased = test_data() + pipeline = TosaPipelineINT[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters_u55) +@common.XfailIfNoCorstone300 +def test_var_dim_u55_INT(test_data: Tuple): + test_data, dim, keepdim, unbiased = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +@common.XfailIfNoCorstone320 +def test_var_dim_u85_INT(test_data: Tuple): + test_data, dim, keepdim, unbiased = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + VarDim(dim, keepdim, unbiased), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_no_quant(test_data: Tuple): + data, dim, keepdim, unbiased = test_data() + pipeline = VgfPipeline[input_t1]( + VarDim(dim, keepdim, unbiased), + (data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", VarDim.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_quant(test_data: Tuple): + data, dim, keepdim, unbiased = test_data() + pipeline = VgfPipeline[input_t1]( + VarDim(dim, keepdim, unbiased), + (data,), + [], + [], + quantize=True, + ) + pipeline.run() + + +#################### +## VarCorrection ### +#################### + + +@common.parametrize("test_data", VarCorrection.test_parameters) +def test_var_dim_tosa_FP_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = TosaPipelineFP[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +def test_var_dim_tosa_INT_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = TosaPipelineINT[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_op=[], + exir_op=[], + ) + pipeline.run() + + +@common.parametrize( + "test_data", + VarCorrection.test_parameters, +) +@common.XfailIfNoCorstone300 +def test_var_dim_u55_INT_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +@common.XfailIfNoCorstone320 +def test_var_dim_u85_INT_correction(test_data: Tuple): + test_data, dim, keepdim, correction = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + VarCorrection(dim, keepdim, correction), + (test_data,), + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_no_quant_correction(test_data: Tuple): + data, dim, keepdim, corr = test_data() + pipeline = VgfPipeline[input_t1]( + VarCorrection(dim, keepdim, corr), + (data,), + [], + [], + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", VarCorrection.test_parameters) +@common.SkipIfNoModelConverter +def test_var_dim_vgf_quant_correction(test_data: Tuple): + data, dim, keepdim, corr = test_data() + pipeline = VgfPipeline[input_t1]( + VarCorrection(dim, keepdim, corr), + (data,), + [], + [], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_view.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_view.py new file mode 100644 index 0000000..fb0445a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_view.py @@ -0,0 +1,253 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# Tests the view op which changes the size of a Tensor without changing the underlying data. +# + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer.arm_quantizer import ( + get_symmetric_a16w8_quantization_config, + TOSAQuantizer, +) + +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.arm.tosa.specification import TosaSpecification +from executorch.backends.xnnpack.test.tester import Quantize + +aten_op = "torch.ops.aten.view.default" + +input_t1 = Tuple[torch.Tensor, torch.Tensor] # Input x, Input y + + +class View(torch.nn.Module): + + needs_transpose_tests = { + "rand_1d_neg": lambda: (torch.rand(100), (1, -1, 5, 2)), + "rand_4d_neg": lambda: (torch.rand(10, 2, 1, 5), (1, -1, 5, 2)), + "rand_4d_4d_small": lambda: (torch.rand(1, 2, 1, 9), (3, 1, 3, 2)), + "rand_4d_4d": lambda: (torch.rand(2, 1, 1, 9), (3, 2, 3, 1)), + "rand_4d_2d": lambda: (torch.rand(2, 50, 2, 1), (1, 200)), + "rand_4d_3d": lambda: (torch.rand(2, 5, 2, 3), (1, 15, 4)), + "rand_4d_1": lambda: (torch.rand(2, 1, 1, 9), (3, 1, 3, 2)), + "rand_4d_2": lambda: (torch.rand(5, 10, 1, 1), (25, 2, 1, 1)), + "rand_4d_2_4": lambda: (torch.rand(10, 2), (1, 1, 5, 4)), + "rand_4d_2_4_big": lambda: (torch.rand(10, 10), (5, 1, 5, 4)), + "rand_4d_4_4": lambda: (torch.rand(1, 1, 1, 10), (1, 1, 10, 1)), + "rand_4d_4_4_big": lambda: (torch.rand(1, 1, 5, 10), (1, 1, 50, 1)), + "rand_4d_4_3": lambda: (torch.rand(5, 10, 1, 1), (1, 25, 2)), + "rand_4d_4_2": lambda: (torch.rand(2, 50, 1, 1), (1, 100)), + "rand_4d_2_4_same": lambda: (torch.rand(2, 3, 2, 3), (2, 3, 3, 2)), + "rand_4d_5d": lambda: (torch.rand(1, 3, 4, 5), (1, 1, 4, 5, -1)), + "rand_5d_5d": lambda: (torch.rand(1, 1, 4, 5, 6), (1, 1, 4, -1, 6)), + "rand_5d_3d": lambda: (torch.rand(1, 1, 4, 5, 6), (2, 3, -1)), + "rand_3d_5d": lambda: (torch.rand(4, 5, 6), (1, 1, 2, -1, 3)), + } + + rank_product_too_large = { + "rand_4d_large": lambda: (torch.rand(1, 49, 16, 128), (1, 16, 49, 128)), + } + + def __init__(self, new_shape): + super().__init__() + self.new_shape = new_shape + + def forward(self, x: torch.Tensor): + return x.view(self.new_shape) + + +@common.parametrize("test_data", View.needs_transpose_tests) +def test_view_tosa_FP(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = TosaPipelineFP[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +def test_view_tosa_INT(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = TosaPipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_op=[], + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone300 +def test_view_u55_INT(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = EthosU55PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.SkipIfNoModelConverter +def test_view_vgf_no_quant(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = VgfPipeline[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.SkipIfNoModelConverter +def test_view_vgf_quant(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = VgfPipeline[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + quantize=True, + ) + pipeline.run() + + +@common.parametrize("test_data", View.rank_product_too_large) +@common.XfailIfNoCorstone300 +def test_view_u55_INT_not_delegated(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = OpNotSupportedPipeline[input_t1]( + View(new_shape), + (test_tensor,), + {"executorch_exir_dialects_edge__ops_aten_view_copy": 1}, + n_expected_delegates=0, + quantize=True, + u55_subset=True, + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone320 +def test_view_u85_INT(test_data: Tuple): + test_tensor, new_shape = test_data() + pipeline = EthosU85PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + ) + pipeline.run() + + +def get_symmetric_a16w8_view_quantizer(per_channel_quantization=False): + tosa_version = conftest.get_option("tosa_version") + tosa_profiles = { + "1.0": TosaSpecification.create_from_string("TOSA-1.0+INT+int16"), + } + + quantizer = TOSAQuantizer(tosa_profiles[tosa_version]) + quantizer.set_global( + get_symmetric_a16w8_quantization_config(is_per_channel=per_channel_quantization) + ) + + return Quantize( + quantizer, + get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization + ), + ) + + +@common.parametrize("test_data", View.needs_transpose_tests) +def test_view_16a8w_tosa_INT(test_data: Tuple): + """Test view operation with 16A8W quantization (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + test_tensor, new_shape = test_data() + + pipeline = TosaPipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_op=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + tosa_extensions=["int16"], + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_view_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone300 +def test_view_16a8w_u55_INT(test_data: Tuple): + """Test view operation with 16A8W quantization on U55 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + test_tensor, new_shape = test_data() + + pipeline = EthosU55PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_view_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() + + +@common.parametrize("test_data", View.needs_transpose_tests) +@common.XfailIfNoCorstone320 +def test_view_16a8w_u85_INT(test_data: Tuple): + """Test view operation with 16A8W quantization on U85 (16-bit activations, 8-bit weights)""" + per_channel_quantization = False + test_tensor, new_shape = test_data() + + pipeline = EthosU85PipelineINT[input_t1]( + View(new_shape), + (test_tensor,), + aten_op, + exir_ops=[], + per_channel_quantization=per_channel_quantization, + use_to_edge_transform_and_lower=True, + ) + + pipeline.change_args( + "quantize", + get_symmetric_a16w8_view_quantizer( + per_channel_quantization=per_channel_quantization + ), + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_where.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_where.py new file mode 100644 index 0000000..50a7aef --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_where.py @@ -0,0 +1,285 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List, Tuple + +import torch +from executorch.backends.arm.quantizer import ( + EthosUQuantizer, + get_symmetric_quantization_config, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from executorch.backends.xnnpack.test.tester.tester import Quantize + +aten_op = "torch.ops.aten.where.self" +exir_op = "executorch_exir_dialects_edge__ops_aten_where_self" + + +class Where(torch.nn.Module): + def __init__( + self, shape: tuple | int, dtype: torch.dtype | Tuple[torch.dtype], condition + ): + super().__init__() + self.shape = shape if isinstance(shape, tuple) else (shape,) * shape + self.dtype = (dtype, dtype) if isinstance(dtype, torch.dtype) else dtype + self.condition = condition + + def get_inputs(self): + inputs: List = [0, 0] + for i in range(2): + if self.dtype[i] in [torch.int8, torch.int16, torch.int32]: + inputs[i] = torch.randint( + torch.iinfo(self.dtype[i]).min, + torch.iinfo(self.dtype[i]).max, + self.shape, + dtype=self.dtype[i], + ) + elif self.dtype[i] in [torch.float32]: + inputs[i] = torch.randn(*self.shape).to(self.dtype[i]) + elif self.dtype[i] is torch.bool: + inputs[i] = torch.randint(0, 1, self.shape, dtype=torch.bool) + else: + raise TypeError( + f"Input generation for dtype {self.dtype[i]} not implemented in " + "Where()" + ) + + return tuple(inputs) + + def forward( + self, + input_: torch.Tensor, + other_: torch.Tensor, + ): + return torch.where(self.condition(input_), input_, other_) + + +class ConstWhere(torch.nn.Module): + + def __init__(self, buffer: torch.Tensor, dtype: torch.dtype): + super().__init__() + self.buffer = buffer + self.dtype = dtype + self.min = torch.nn.Buffer(torch.tensor(0.0, dtype=self.dtype)) + self.input_1 = torch.nn.Buffer(torch.tensor(-1.0, dtype=self.dtype)) + self.input_2 = torch.nn.Buffer(torch.tensor(1.0, dtype=self.dtype)) + + def get_inputs(self): + return (torch.rand(self.buffer.size(), dtype=self.dtype),) + + def forward(self, input: torch.Tensor): + return ( + torch.where( + self.buffer > self.min, + self.input_1, + self.input_2, + ) + + input + ) + + +def tensor_condition(input: torch.Tensor): + return input > torch.zeros_like(input) + + +def scalar_condition(input: torch.Tensor): + return input > 0 + + +two_dim_tensor_cond = Where( + 2, + torch.float32, + tensor_condition, +) + +three_dim_tensor_cond = Where( + 3, + torch.float32, + tensor_condition, +) + +float32_tensor_cond = Where( + 1, + torch.float32, + tensor_condition, +) + +float32_tensor_cond_tuple_dtype = Where( + 1, + (torch.float32, torch.int8), + tensor_condition, +) + +float32_tensor_cond_tuple_dtype_bool = Where( + 1, + (torch.float32, torch.bool), + tensor_condition, +) + +# Scalar tests +two_dim_scalar_cond = Where( + 2, + torch.float32, + scalar_condition, +) + +three_dim_scalar_cond = Where( + 3, + torch.float32, + scalar_condition, +) + +float32_scalar_cond = Where( + 1, + torch.float32, + scalar_condition, +) + +int32_scalar_cond = Where( + 1, + torch.int32, + scalar_condition, +) + +const_float32 = ConstWhere( + buffer=torch.tensor([[1.0, -1.0], [-1.0, 1.0]]), + dtype=torch.float32, +) + +test_modules_common = { + "two_dim_tensor_cond": lambda: two_dim_tensor_cond, + "three_dim_tensor_cond": lambda: three_dim_tensor_cond, + "float32_tensor_cond": lambda: float32_tensor_cond, + "two_dim_scalar_cond": lambda: two_dim_scalar_cond, + "three_dim_scalar_cond": lambda: three_dim_scalar_cond, + "float32_scalar_cond": lambda: float32_scalar_cond, + "const_float32": lambda: const_float32, +} + +test_modules_FP = { + **test_modules_common, + "float32_tensor_cond_tuple_dtype_bool": lambda: float32_tensor_cond_tuple_dtype_bool, +} + +test_modules_FP_unsupported_dtype = { + "float32_tensor_cond_tuple_dtype": lambda: float32_tensor_cond_tuple_dtype, + "int32_scalar_cond": lambda: int32_scalar_cond, +} + +test_modules_INT = { + **test_modules_common, +} + +input_t = Tuple[torch.Tensor] + + +@common.parametrize("test_module", test_modules_FP) +def test_where_self_tosa_FP(test_module): + pipeline = TosaPipelineFP[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_FP_unsupported_dtype) +def test_where_self_tosa_FP_unsupported_dtype(test_module): + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + {exir_op: 1}, + n_expected_delegates=1, # condition can be delegated + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +def test_where_self_tosa_INT(test_module): + pipeline = TosaPipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +@common.XfailIfNoCorstone300 +def test_where_self_u55_INT_not_delegated(test_module): + # There will be one full_like op which will be delegated. + num_delegates = 1 + num_exir = 0 + + compile_spec = common.get_u55_compile_spec() + quantizer = EthosUQuantizer(compile_spec).set_io( + get_symmetric_quantization_config() + ) + + pipeline = OpNotSupportedPipeline[input_t]( + test_module(), + test_module().get_inputs(), + { + exir_op: 1, + "executorch_exir_dialects_edge__ops_aten_full_default": num_exir, + }, + num_delegates, + quantize=True, + u55_subset=True, + ) + pipeline.change_args( + "quantize", Quantize(quantizer, get_symmetric_quantization_config()) + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +@common.XfailIfNoCorstone320 +def test_where_self_u85_INT(test_module): + + pipeline = EthosU85PipelineINT[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + symmetric_io_quantization=True, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_FP) +@common.SkipIfNoModelConverter +def test_where_self_vgf_no_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize("test_module", test_modules_INT) +@common.SkipIfNoModelConverter +def test_where_self_vgf_quant(test_module): + pipeline = VgfPipeline[input_t]( + test_module(), + test_module().get_inputs(), + aten_op, + exir_op, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_while.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_while.py new file mode 100644 index 0000000..64870ee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_while.py @@ -0,0 +1,264 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Tuple + +import torch +import torch.fx + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.arm_tester import ArmTester +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) +from pytest import mark + +input_single = Tuple[torch.Tensor] +input_double = Tuple[torch.Tensor, torch.Tensor] + + +class WhileTwoInputsTwoOutputs(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + + def forward( + self, lhs: torch.Tensor, rhs: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + def cond_fn(lhs_val: torch.Tensor, rhs_val: torch.Tensor) -> torch.Tensor: + total = torch.sum(rhs_val) + zero = torch.zeros_like(total) + return torch.gt(total, zero).squeeze() + + def body_fn( + lhs_val: torch.Tensor, rhs_val: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + next_lhs = torch.add(lhs_val, rhs_val) + next_rhs = torch.sub(rhs_val, torch.full((1,), 1.0)) + return (next_lhs, next_rhs) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (lhs, rhs), + (), + ) + return result # type: ignore + + +class WhileOneInputOneBufferTwoOutputs(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer("threshold", torch.tensor((30.0,))) + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor, limit: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.lt(total, limit).squeeze() + + def body_fn( + value: torch.Tensor, limit: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + return (torch.add(value, value), limit.clone()) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value, self.threshold), + (), + ) + return result # type: ignore + + +class DecreasingOutput(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.gt(total, torch.full((1,), 60.0)).squeeze() + + def body_fn(value: torch.Tensor) -> Tuple[torch.Tensor]: + return (torch.div(value, torch.full((1,), 2.0)),) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value,), + (), + ) + return result[0] # type: ignore + + +class WhileAdditionalArg(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer("threshold", torch.tensor((300.0,))) + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor, limit: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.lt(total, limit).squeeze() + + def body_fn(value: torch.Tensor, limit: torch.Tensor) -> tuple[torch.Tensor]: + return (torch.add(value, value),) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value,), + (self.threshold,), + ) + return result # type: ignore + + +class WhileSingleCapturedOutput(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer("threshold", torch.tensor((200.0,))) + + def forward(self, value: torch.Tensor) -> torch.Tensor: + def cond_fn(value: torch.Tensor, limit: torch.Tensor) -> torch.Tensor: + total = value.sum() + return torch.lt(total, limit).squeeze() + + def body_fn( + value: torch.Tensor, limit: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + return (torch.add(value, value), limit.clone()) + + result = torch.ops.higher_order.while_loop( + cond_fn, + body_fn, + (value, self.threshold), + (), + ) + return result[0] # type: ignore + + +def _single_input_case( + module_factory: Callable[[], torch.nn.Module], +) -> Callable[[], Tuple[torch.nn.Module, input_single]]: + def _create() -> Tuple[torch.nn.Module, input_single]: + return module_factory(), (torch.ones(2, 3, 4, 6),) + + return _create + + +def _dual_input_case( + module_factory: Callable[[], torch.nn.Module], +) -> Callable[[], Tuple[torch.nn.Module, input_double]]: + def _create() -> Tuple[torch.nn.Module, input_double]: + return module_factory(), (torch.zeros(2, 3), torch.full((2, 3), -2.0)) + + return _create + + +test_cases: dict[str, Callable[[], Tuple[torch.nn.Module, Tuple]]] = { + "two_in_two_out": _dual_input_case(WhileTwoInputsTwoOutputs), + "one_in_one_buffer_two_out": _single_input_case(WhileOneInputOneBufferTwoOutputs), + "decreasing_output": _single_input_case(DecreasingOutput), + "additional_arg": _single_input_case(WhileAdditionalArg), + "two_in_one_captured_out": _single_input_case(WhileSingleCapturedOutput), +} + + +@common.parametrize( + "case", + test_cases, +) +def test_while_loop_tosa_FP(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineFP[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + tosa_extensions=["cf"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, +) +def test_while_loop_tosa_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + pipeline = TosaPipelineINT[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + tosa_extensions=["cf"], + ) + pipeline.add_stage_after( + "to_edge_transform_and_lower", + ArmTester.check_not, + pipeline.tester, + ["torch.ops.higher_order.while_loop"], + ) + pipeline.run() + + +@common.parametrize( + "case", + test_cases, +) +def test_while_loop_u55_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + OpNotSupportedPipeline[tuple]( + module, + example_inputs, + non_delegated_ops={"torch.ops.higher_order.while_loop": 1}, + u55_subset=True, + ).run() + + +@common.parametrize( + "case", + test_cases, +) +@common.XfailIfNoCorstone320 +def test_while_loop_u85_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + EthosU85PipelineINT[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + ).run() + + +@mark.skip("While not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_while_loop_vgf_FP(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + VgfPipeline[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + tosa_version="TOSA-1.0+FP", + ).run() + + +@mark.skip("While not supported in model_converter.") +@common.parametrize( + "case", + test_cases, +) +@common.SkipIfNoModelConverter +def test_while_loop_vgf_INT(case: Callable[[], Tuple[torch.nn.Module, Tuple]]): + module, example_inputs = case() + VgfPipeline[tuple]( + module, + example_inputs, + "torch.ops.higher_order.while_loop", + ).run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_zeros.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_zeros.py new file mode 100644 index 0000000..7e1609e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/ops/test_zeros.py @@ -0,0 +1,158 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + OpNotSupportedPipeline, + TosaPipelineFP, + TosaPipelineINT, + VgfPipeline, +) + +input_t = tuple[torch.Tensor] +test_data_t = tuple[int, torch.dtype] + + +class ZerosAdd(torch.nn.Module): + aten_op: str = "torch.ops.aten.zeros.default" + + def __init__(self, n: int, dtype: torch.dtype): + super().__init__() + self.args = (n,) + self.dtype = dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.zeros(*self.args, dtype=self.dtype) + x + + test_data: dict[str, test_data_t] = { + "10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)), + "10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)), + "int32_int32": ( + lambda: (torch.randint(0, 10, [10], dtype=torch.int32),), + (10, torch.int32), + ), + } + + # Mixed dtypes - the zeros op is delegated, but it leads to a non-delegated add op. + test_data_mixed_dtypes: dict[str, test_data_t] = { + "fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)), + "fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)), + } + + +@common.parametrize("test_data", ZerosAdd.test_data | ZerosAdd.test_data_mixed_dtypes) +def test_zeros_tosa_FP(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineFP[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ZerosAdd.test_data | ZerosAdd.test_data_mixed_dtypes) +def test_zeros_tosa_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = TosaPipelineINT[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", ZerosAdd.test_data) +@common.XfailIfNoCorstone300 +def test_zeros_u55_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU55PipelineINT[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize("test_data", ZerosAdd.test_data) +@common.XfailIfNoCorstone320 +def test_zeros_u85_INT(test_data: test_data_t): + input_data, init_data = test_data + pipeline = EthosU85PipelineINT[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + use_to_edge_transform_and_lower=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +@common.parametrize( + "test_data", + ZerosAdd.test_data_mixed_dtypes, +) +def test_zeros_tosa_INT_not_delegated(test_data: test_data_t): + input_data, init_data = test_data + pipeline = OpNotSupportedPipeline[input_t]( + ZerosAdd(*init_data), + input_data(), + non_delegated_ops={"executorch_exir_dialects_edge__ops_aten_add_Tensor": 1}, + n_expected_delegates=1, + quantize=True, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + ZerosAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_zeros_vgf_no_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + quantize=False, + ) + pipeline.run() + + +@common.parametrize( + "test_data", + ZerosAdd.test_data, +) +@common.SkipIfNoModelConverter +def test_zeros_vgf_quant(test_data: test_data_t): + input_data, init_data = test_data + pipeline = VgfPipeline[input_t]( + ZerosAdd(*init_data), + input_data(), + ZerosAdd.aten_op, + quantize=True, + ) + # Pop the quantization check stage if it exists as no + # quantization nodes will be present for int + fp inputs. + if pipeline.has_stage("check.quant_nodes"): + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_broadcast_args_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_broadcast_args_pass.py new file mode 100644 index 0000000..eab4f20 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_broadcast_args_pass.py @@ -0,0 +1,57 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import operator +from typing import Callable, Tuple + +import torch +from executorch.backends.arm._passes import BroadcastArgsPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class NeedsMultipleBroadcastsModel(torch.nn.Module): + test_data = (torch.rand(1, 10), torch.rand(10, 1)) + + def __init__( + self, op: Callable[[torch.Tensor, torch.Tensor], torch.Tensor] + ) -> None: + self.op = op + super().__init__() + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return self.op(x, y) + + +modules = { + "add": NeedsMultipleBroadcastsModel(operator.add), + "sub": NeedsMultipleBroadcastsModel(operator.sub), + "mul": NeedsMultipleBroadcastsModel(operator.mul), + "div": NeedsMultipleBroadcastsModel(operator.truediv), +} + + +@common.parametrize("module", modules) +def test_broadcast_args_tosa_INT_multiple(module: NeedsMultipleBroadcastsModel): + test_data = module.test_data + ops_not_before_pass = [ + "executorch_exir_dialects_edge__ops_aten_repeat_default", + ] + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_repeat_default": 1, + } + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=True, + ops_not_before_pass=ops_not_before_pass, + ops_after_pass=ops_after_pass, + pass_list=[BroadcastArgsPass], + tosa_extensions=["u55"], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_cast_int64_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_cast_int64_pass.py new file mode 100644 index 0000000..dac4922 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_cast_int64_pass.py @@ -0,0 +1,49 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import CastInt64BuffersToInt32Pass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +from executorch.backends.test.harness.stages import StageType + +input_t = Tuple[torch.Tensor] # Input x + + +class Int64Model(torch.nn.Module): + test_data = { + "rand": (torch.rand(4),), + } + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x + 3 + + +@common.parametrize("test_data", Int64Model.test_data) +def test_cast_int64_buffers_to_int32_tosa_FP(test_data: input_t): + module = Int64Model() + op_checks = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + } + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass=op_checks, + ops_after_pass=op_checks, + passes_with_exported_program=[CastInt64BuffersToInt32Pass], + ) + pipeline.run() + + exported_program = pipeline.tester.get_artifact( + StageType.RUN_PASSES + ).exported_program() + for state in exported_program.state_dict: + assert exported_program.state_dict[state].dtype == torch.int32 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py new file mode 100644 index 0000000..8217d4e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_expand_copy_to_repeat.py @@ -0,0 +1,51 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.convert_expand_copy_to_repeat import ( + ConvertExpandCopyToRepeatPass, +) + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Expand(torch.nn.Module): + """ + Basic expand model using torch.Tensor.expand function + """ + + def __init__(self) -> None: + super().__init__() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.expand(3, 4) + + def get_inputs(self) -> input_t: + return (torch.rand(3, 1),) + + +def test_convert_expand_copy_to_repeat_tosa_INT() -> None: + module = Expand() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_expand_copy_default": 1, + }, + ops_not_before_pass=["executorch_exir_dialects_edge__ops_aten_repeat_default"], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_repeat_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_expand_copy_default" + ], + pass_list=[ConvertExpandCopyToRepeatPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py new file mode 100644 index 0000000..0dbc9d9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_const_ops_to_int32.py @@ -0,0 +1,529 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, ClassVar, Dict, Tuple, Union + +import pytest + +import torch +from executorch.backends.arm._passes import ( + ConvertInt64ConstOpsToInt32Pass, + ConvertInt64OutputOpsToInt32Pass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + TosaPipelineFP, + TosaPipelineINT, +) + +input_t1 = Tuple[torch.Tensor] # Input x +input_t2 = Tuple[torch.Tensor, torch.Tensor] # Input x, y + +Scalar = Union[bool, float, int] +ArangeNoneParam = Tuple[Callable[[], input_t1], Tuple[Scalar, Scalar, Scalar]] +FullNoneParam = Tuple[Callable[[], input_t1], Tuple[Tuple[int, ...], Scalar]] + + +##################################################### +## Test arange(dtype=int64) -> arange(dtype=int32) ## +##################################################### + + +class ArangeDefaultIncrementViewLessThan(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (torch.arange(10, dtype=torch.int64) + 1).view(-1, 1) < x + + test_data: ClassVar[Dict[str, input_t1]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", ArangeDefaultIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_default( + test_data: input_t1, +) -> None: + module = ArangeDefaultIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ConvertInt64ConstOpsToInt32Pass()], + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeDefaultIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_default( + test_data: input_t1, +) -> None: + module = ArangeDefaultIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +class ArangeStartIncrementViewLessThan(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (torch.arange(0, 10, dtype=torch.int64) + 1).view(-1, 1) < x + + test_data: ClassVar[Dict[str, input_t1]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", ArangeStartIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_start( + test_data: input_t1, +) -> None: + module = ArangeStartIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ConvertInt64ConstOpsToInt32Pass()], + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeStartIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_start( + test_data: input_t1, +) -> None: + module = ArangeStartIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +class ArangeStartStepIncrementViewLessThan(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (torch.arange(0, 10, 2, dtype=torch.int64) + 1).view(-1, 1) < x + + test_data: ClassVar[Dict[str, input_t1]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", ArangeStartStepIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_start_step( + test_data: input_t1, +) -> None: + module = ArangeStartStepIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ConvertInt64ConstOpsToInt32Pass()], + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeStartStepIncrementViewLessThan.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_start_step( + test_data: input_t1, +) -> None: + module = ArangeStartStepIncrementViewLessThan() + aten_ops_checks = [ + "torch.ops.aten.lt.Tensor", + "torch.ops.aten.view.default", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ] + pipeline = TosaPipelineINT[input_t1]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +######################################################### +## Test arange(dtype=None) -> arange(dtype=None/int32) ## +######################################################### + + +class ArangeAddDtypeNone(torch.nn.Module): + aten_op: str = "torch.ops.aten.arange.start_step" + exir_op: str = "executorch_exir_dialects_edge__ops_aten_arange_start_step" + + def __init__(self, start: float, stop: float, step: float): + super().__init__() + self.args = (start, stop, step) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.arange(*self.args) + x + + test_data: ClassVar[Dict[str, ArangeNoneParam]] = { + "int64": (lambda: (torch.randn(10, 1),), (0, 10, 1)), + "float32_start": (lambda: (torch.randn(10, 1),), (0.0, 10, 1)), + "float32_stop": (lambda: (torch.randn(10, 1),), (0, 10.0, 1)), + "float32_step": (lambda: (torch.randn(10, 1),), (0, 10, 1.0)), + "int64_bool_0": (lambda: (torch.randn(10, 1),), (False, True, True)), + "int64_bool_1": (lambda: (torch.randn(10, 1),), (False, True, True * 10)), + "float32_bool_0": (lambda: (torch.randn(10, 1),), (0.0, True, True)), + "float32_bool_1": (lambda: (torch.randn(10, 1),), (False, True, True * 10.0)), + } + + +@common.parametrize("test_data", ArangeAddDtypeNone.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_arange_none( + test_data: ArangeNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineFP[input_t1]( + ArangeAddDtypeNone(*init_data), + input_factory(), + ArangeAddDtypeNone.aten_op, + ArangeAddDtypeNone.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", ArangeAddDtypeNone.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_arange_none( + test_data: ArangeNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineINT[input_t1]( + ArangeAddDtypeNone(*init_data), + input_factory(), + ArangeAddDtypeNone.aten_op, + ArangeAddDtypeNone.exir_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.run() + + +################################################# +## Test full(dtype=int64) -> full(dtype=int32) ## +################################################# + + +class FullIncrementViewMulXLessThanY(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return ( + ( + torch.full( + ( + 1, + 3, + 5, + ), + 10, + dtype=torch.int64, + ) + + 1 + ).view(-1, 1) + * x + ) < y + + test_data: ClassVar[Dict[str, input_t2]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", FullIncrementViewMulXLessThanY.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_full( + test_data: input_t2, +) -> None: + """ + There are four int64 placeholders in the original graph: + 1. _lifted_tensor_constant0: 1 + 2. x + 3. y + Ideally, after applying ConvertInt64ConstOpsToInt32Pass to convert the aten.full from int64 to int32, + the int32 type should propagate throughout the graph, and no int64 values should remain. + However, due to unexpected retracing behavior, a cast from int32 → int64 for x was reintroducedh. + + Applying ConvertInt64OutputOpsToInt32Pass afterward resolves this issue, + removing the int64 cast and producing a fully delegated int32 graph. + """ + module = FullIncrementViewMulXLessThanY() + aten_ops_checks = [ + "torch.ops.aten.full.default", + "torch.ops.aten.add.Tensor", + "torch.ops.aten.view.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.lt.Tensor", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + ] + pipeline = TosaPipelineFP[input_t2]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + ], + ) + pipeline.run() + + +@common.parametrize("test_data", FullIncrementViewMulXLessThanY.test_data) +def test_convert_int64_const_ops_to_int32_tosa_INT_full( + test_data: input_t2, +) -> None: + """ + For INT profile, _lifted_tensor_constant0 is still int64 after applying ConvertInt64ConstOpsToInt32Pass(). + And an int64->int32 cast is inserted at the beginning of the graph. + TODO: Explore why _lifted_tensor_constant0 is handled in different ways in FP and INT profile. + Find a way to optimize out the int64->int32 cast. + """ + module = FullIncrementViewMulXLessThanY() + aten_ops_checks = [ + "torch.ops.aten.full.default", + "torch.ops.aten.add.Tensor", + "torch.ops.aten.view.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.lt.Tensor", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_lt_Tensor", + ] + pipeline = TosaPipelineINT[input_t2]( + module, + test_data, + aten_ops_checks, + exir_ops_checks, + ) + pipeline.run() + + +class RejectFullIncrementViewMulXLessThanY(torch.nn.Module): + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return ( + ( + torch.full( + ( + 1, + 3, + 5, + ), + torch.iinfo(torch.int32).max + 1, + dtype=torch.int64, + ) + + 1 + ).view(-1, 1) + * x + ) < y + + test_data: ClassVar[Dict[str, input_t2]] = { + "randint": ( + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + torch.randint( + 0, + 10, + (1,), + dtype=torch.int32, + ), + ), + } + + +@common.parametrize("test_data", RejectFullIncrementViewMulXLessThanY.test_data) +@pytest.mark.xfail( + reason="MLETORCH-1254: Add operator support check for aten.arange and aten.full" +) +def test_convert_int64_const_ops_to_int32_tosa_FP_reject_full( + test_data: input_t2, +) -> None: + module = RejectFullIncrementViewMulXLessThanY() + aten_ops_checks = [ + "torch.ops.aten.full.default", + "torch.ops.aten.add.Tensor", + "torch.ops.aten.view.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.lt.Tensor", + ] + pipeline = TosaPipelineFP[input_t2]( + module, + test_data, + aten_ops_checks, + exir_op=[], + transform_passes=[ + ConvertInt64ConstOpsToInt32Pass(), + ConvertInt64OutputOpsToInt32Pass(), + ], + ) + pipeline.run() + + +##################################################### +## Test full(dtype=None) -> full(dtype=None/int32) ## +##################################################### + + +class AddConstFullDtypeNone(torch.nn.Module): + # Input + a full with constant value. + exir_op = "executorch_exir_dialects_edge__ops_aten_full_default" + + def __init__(self, size: tuple, fill_value: Union[bool, float, int]): + super().__init__() + self.args = (size, fill_value) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.full(*self.args) + x + + test_data = { + "int64": (lambda: (torch.randn(1),), ((1, 2, 3), 10)), + "float32": (lambda: (torch.randn(1),), ((1, 2, 3), 10.0)), + } + + test_data_bool = { + "bool": (lambda: (torch.randn(1),), ((1, 2, 3), True)), + } + + +@common.parametrize("test_data", AddConstFullDtypeNone.test_data) +def test_convert_int64_const_ops_to_int32_tosa_FP_full_none( + test_data: FullNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineFP[input_t1]( + AddConstFullDtypeNone(*init_data), + input_factory(), + aten_op=[], + exir_op=AddConstFullDtypeNone.exir_op, + ) + pipeline.run() + + +@common.parametrize("test_data", AddConstFullDtypeNone.test_data_bool) +def test_convert_int64_const_ops_to_int32_tosa_FP_full_none_bool( + test_data: FullNoneParam, +) -> None: + input_factory, init_data = test_data + pipeline = TosaPipelineFP[input_t1]( + AddConstFullDtypeNone(*init_data), + input_factory(), + aten_op=[], + exir_op=AddConstFullDtypeNone.exir_op, + ) + pipeline.change_args( + "check_count.exir", + {"torch.ops.higher_order.executorch_call_delegate": 2}, + ) + pipeline.run() + + +@common.parametrize( + "test_data", AddConstFullDtypeNone.test_data | AddConstFullDtypeNone.test_data_bool +) +def test_convert_int64_const_ops_to_int32_tosa_INT_full_none(test_data): + input_data, init_data = test_data + input_factory, init_data = test_data + pipeline = TosaPipelineINT[input_t1]( + AddConstFullDtypeNone(*init_data), + input_factory(), + aten_op=[], + exir_op=AddConstFullDtypeNone.exir_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py new file mode 100644 index 0000000..4e15f4a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_int64_output_ops_to_int32.py @@ -0,0 +1,129 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Dict, Tuple + +import torch +from executorch.backends.arm._passes import ConvertInt64OutputOpsToInt32Pass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineFP + +input_t1 = Tuple[torch.Tensor] # Input x + + +######################################### +## Test [int32 | other types] -> int64 ## +######################################### + + +class CastingToInt64Model(torch.nn.Module): + def __init__(self, target_dtype: torch.dtype) -> None: + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.to(dtype=self.target_dtype) + + +test_data_suite_convert: Dict[str, Callable[[], Tuple[torch.Tensor, torch.dtype]]] = { + "fp32_input": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float32), torch.int64), + "fp16_input": lambda: (torch.rand((1, 2, 3, 4), dtype=torch.float16), torch.int64), +} + +test_data_suite_remove: Dict[str, Callable[[], Tuple[torch.Tensor, torch.dtype]]] = { + "int32_input": lambda: ( + torch.randint(-127, 128, (1, 2, 3, 4), dtype=torch.int32), + torch.int64, + ), +} + + +TestDataFactory = Callable[[], Tuple[torch.Tensor, torch.dtype]] + + +@common.parametrize("test_data", test_data_suite_convert) +def test_convert_int64_output_ops_to_int32_tosa_FP_convert_casting( + test_data: TestDataFactory, +) -> None: + test_tensor, target_dtype = test_data() + module = CastingToInt64Model(target_dtype) + + pipeline = TosaPipelineFP[input_t1]( + module, + (test_tensor,), + aten_op="torch.ops.aten.to.dtype", + exir_op=[], + transform_passes=[ConvertInt64OutputOpsToInt32Pass()], + ) + pipeline.pop_stage( + "run_method_and_compare_outputs" + ) # As expected: RuntimeError: Int did not match Long + pipeline.run() + + +@common.parametrize("test_data", test_data_suite_remove) +def test_convert_int64_output_ops_to_int32_tosa_FP_remove_casting( + test_data: TestDataFactory, +) -> None: + test_tensor, target_dtype = test_data() + module = CastingToInt64Model(target_dtype) + + pipeline = TosaPipelineFP[input_t1]( + module, + (test_tensor,), + aten_op=[], + exir_op=[], + transform_passes=[ConvertInt64OutputOpsToInt32Pass()], + ) + pipeline.change_args( + "check_count.exir", {"torch.ops.higher_order.executorch_call_delegate": 0} + ) # Empty graph without nodes + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +##################################################### +## Test arange(dtype=int64) -> arange(dtype=int32) ## +##################################################### + + +class Int64OutputModel(torch.nn.Module): + + def forward(self, x: torch.Tensor) -> torch.Tensor: + # return torch.argmax(x) # RuntimeError: Int did not match Long; But this is expected as we expect _argmax_i32 to generate int32 output + # return (10 * torch.argmax(x) + 10).to(dtype=torch.int32) # [1]. This behavior is deprecated, and in a future PyTorch release outputs will not be resized unless they have zero elements. You can explicitly reuse an out tensor t by resizing it, inplace, to zero elements with t.resize_(0). (function _resize_output_check) + return (10 * torch.argmax(x, dim=-1) + 10) + 1.5 + + def get_inputs(self) -> input_t1: + return ( + torch.randint( + 0, + 10, + (2, 4, 6, 8), + ), + ) + + +def test_convert_int64_output_ops_to_int32_tosa_FP_insert_cast(): + module = Int64OutputModel() + aten_ops_checks = [ + "torch.ops.aten.argmax.default", + "torch.ops.aten.mul.Tensor", + "torch.ops.aten.add.Tensor", + ] + exir_ops_checks = [ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + ] + pipeline = TosaPipelineFP[input_t1]( + module, + module.get_inputs(), + aten_op=aten_ops_checks, + exir_op=exir_ops_checks, + transform_passes=[ConvertInt64OutputOpsToInt32Pass()], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py new file mode 100644 index 0000000..8478cff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_permute_singleton_to_view_pass.py @@ -0,0 +1,100 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch + +from executorch.backends.arm._passes import ConvertPermuteSingletonToViewPass +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] + + +class PermuteSingletonAxesModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.permute(0, 2, 3, 1) + + @staticmethod + def input() -> input_t: + return (torch.randn(2, 1, 3, 4),) + + +def test_convert_permute_singleton_to_view_tosa_FP_applies(): + module = PermuteSingletonAxesModule() + pipeline = PassPipeline[input_t]( + module, + PermuteSingletonAxesModule.input(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default", + ], + pass_list=[ConvertPermuteSingletonToViewPass], + ) + pipeline.run() + + +class PermuteNonSingletonModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.permute(0, 2, 1) + + @staticmethod + def input() -> input_t: + return (torch.randn(2, 3, 4),) + + +def test_convert_permute_singleton_to_view_tosa_FP_skip_non_singleton(): + module = PermuteNonSingletonModule() + pipeline = PassPipeline[input_t]( + module, + PermuteNonSingletonModule.input(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ], + pass_list=[ConvertPermuteSingletonToViewPass], + ) + pipeline.run() + + +class PermuteSameSizedNonSingletonModule(torch.nn.Module): + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.permute(2, 1, 0) + + @staticmethod + def input() -> input_t: + return (torch.randn(2, 1, 2),) + + +def test_convert_permute_singleton_to_view_tosa_FP_skip_same_size_non_singleton(): + module = PermuteSameSizedNonSingletonModule() + pipeline = PassPipeline[input_t]( + module, + PermuteSameSizedNonSingletonModule.input(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + ], + pass_list=[ConvertPermuteSingletonToViewPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_split_to_slice.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_split_to_slice.py new file mode 100644 index 0000000..ee70b7b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_split_to_slice.py @@ -0,0 +1,75 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.convert_split_to_slice import ( + ConvertSplitToSlicePass, +) + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class Split(torch.nn.Module): + """ + Basic split model using torch.split function + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, ...]: + return torch.split(x, 2) + + +class SplitTensor(torch.nn.Module): + """ + Basic split model using torch.Tensor.split function + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, ...]: + return x.split(2) + + +modules: Dict[str, ModuleWithInputs] = { + "split_basic": Split(), + "split_tensor": SplitTensor(), +} + + +@common.parametrize("module", modules) +def test_convert_split_to_slice_tosa_INT(module: ModuleWithInputs) -> None: + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor" + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor": 5, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default" + ], + pass_list=[ConvertSplitToSlicePass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_to_clamp.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_to_clamp.py new file mode 100644 index 0000000..24f575b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_convert_to_clamp.py @@ -0,0 +1,92 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes.convert_to_clamp_pass import ConvertToClampPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class HardTanh(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = {"rand": (torch.rand(1, 64, 64, 3),)} + + def __init__(self): + super().__init__() + + self.hardtanh = torch.nn.Hardtanh() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.hardtanh(x) + + +class ReLU(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = {"rand": (torch.rand(1, 64, 64, 3),)} + + def __init__(self): + super().__init__() + + self.relu = torch.nn.ReLU() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.relu(x) + + +""" +Tests the ConvertToClampPass which converts hardtanh.default and relu.default to clamp.default +""" + + +@common.parametrize("test_data", HardTanh.test_data) +def test_convert_to_clamp_tosa_FP_hardtahn(test_data: input_t) -> None: + module = HardTanh() + op_checks_before_pass = { + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + } + op_checks_after_pass = { + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + } + op_checks_not_after_pass = [ + "executorch_exir_dialects_edge__ops_aten_hardtanh_default", + ] + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass=op_checks_before_pass, + ops_after_pass=op_checks_after_pass, + ops_not_after_pass=op_checks_not_after_pass, + pass_list=[ConvertToClampPass], + ) + pipeline.run() + + +@common.parametrize("test_data", ReLU.test_data) +def test_convert_to_clamp_tosa_FP_relu(test_data: input_t) -> None: + module = ReLU() + op_checks_before_pass = { + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + } + op_checks_after_pass = { + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + } + op_checks_not_after_pass = [ + "executorch_exir_dialects_edge__ops_aten_relu_default", + ] + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass=op_checks_before_pass, + ops_after_pass=op_checks_after_pass, + ops_not_after_pass=op_checks_not_after_pass, + pass_list=[ConvertToClampPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py new file mode 100644 index 0000000..093b563 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_avg_pool2d_pass.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.decompose_avg_pool2d_pass import ( + DecomposeAvgPool2dPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class AvgPool2dWithStride(torch.nn.Module): + """ + avg_pool2d model with explicit stride parameter + """ + + def get_inputs(self) -> input_t: + return (torch.rand(1, 3, 8, 8),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.avg_pool2d(x, kernel_size=2, stride=2) + + +class AvgPool2dWithoutStride(torch.nn.Module): + """ + avg_pool2d model without stride parameter (should default to kernel_size) + """ + + def get_inputs(self) -> input_t: + return (torch.rand(1, 3, 8, 8),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.avg_pool2d(x, kernel_size=3) + + +class AvgPool2dListKernel(torch.nn.Module): + """ + avg_pool2d model with list kernel_size and no stride + """ + + def get_inputs(self) -> input_t: + return (torch.rand(1, 3, 8, 8),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.avg_pool2d(x, kernel_size=[2, 3]) + + +modules: Dict[str, ModuleWithInputs] = { + "avg_pool2d_with_stride": AvgPool2dWithStride(), + "avg_pool2d_without_stride": AvgPool2dWithoutStride(), + "avg_pool2d_list_kernel": AvgPool2dListKernel(), +} + + +@common.parametrize("module", modules) +def test_decompose_avg_pool2d_tosa_FP(module: ModuleWithInputs) -> None: + """Test that DecomposeAvgPool2d pass works correctly with and without stride parameters.""" + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1, + }, + ops_after_pass={ + # After decomposition, we should still see avg_pool2d (transformed) + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1, + }, + pass_list=[DecomposeAvgPool2dPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py new file mode 100644 index 0000000..8dec840 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_cosine_similarity_pass.py @@ -0,0 +1,58 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch + +from executorch.backends.arm._passes.decompose_cosine_similarity_pass import ( + DecomposeCosineSimilarityPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class CosineSimilarityModel(torch.nn.Module): + def get_inputs(self) -> input_t: + return (torch.rand(2, 3, 4), torch.rand(2, 3, 4)) + + def forward(self, x1: torch.Tensor, x2: torch.Tensor) -> torch.Tensor: + return torch.cosine_similarity(x1, x2, dim=1, eps=1e-6) + + +modules: Dict[str, ModuleWithInputs] = {"cosine_basic": CosineSimilarityModel()} + + +@common.parametrize("module", modules) +def test_decompose_cosine_similarity_tosa_INT(module: ModuleWithInputs) -> None: + + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 5, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 3, + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 2, + # TODO(masnesral): uncomment after https://github.com/pytorch/pytorch/pull/144765 + # "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 2, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + } + + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + ops_before_pass=None, + ops_not_before_pass=None, + ops_after_pass=ops_after_pass, + ops_not_after_pass=None, + pass_list=[DecomposeCosineSimilarityPass], + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_div_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_div_pass.py new file mode 100644 index 0000000..3d6293b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_div_pass.py @@ -0,0 +1,70 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.decompose_div_pass import DecomposeDivPass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class Div(torch.nn.Module): + """ + Basic div model using torch.div + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.div(x, 2) + + +class DivTensor(torch.nn.Module): + """ + Basic div model using torch.Tensor.div + """ + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.div(2) + + +modules: Dict[str, ModuleWithInputs] = {"div_basic": Div(), "div_tensor": DivTensor()} + + +@common.parametrize("module", modules) +def test_decompose_div_tosa_FP(module: ModuleWithInputs) -> None: + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_div_Tensor": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten_div_Tensor"], + pass_list=[DecomposeDivPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_int_pow_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_int_pow_pass.py new file mode 100644 index 0000000..e12fc21 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_int_pow_pass.py @@ -0,0 +1,80 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes import DecomposeIntPowPass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Inputs to the module + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +TestParam = Tuple[ModuleWithInputs, int] + + +class Square(torch.nn.Module): + """ + Basic squaring + """ + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.square() + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +class Pow(torch.nn.Module): + """ + Basic squaring + """ + + def __init__(self, exponent: int) -> None: + super().__init__() + self.exponent = exponent + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.pow(self.exponent) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +test_data: Dict[str, TestParam] = { + "square": (Square(), 1), + "pow_2": (Pow(2), 1), + "pow_3": (Pow(3), 2), + "pow_0": (Pow(0), 0), + "pow_neg_2": (Pow(-2), 1), +} + + +@common.parametrize("data", test_data) +def test_decompose_int_pow_tosa_FP(data: TestParam) -> None: + module_with_inputs, nbr_muls = data + module = cast(torch.nn.Module, module_with_inputs) + pipeline = PassPipeline[input_t]( + module, + module_with_inputs.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 1, + }, + ops_not_before_pass=[], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": nbr_muls, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_pow_Tensor_Scalar"], + pass_list=[DecomposeIntPowPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_layernorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_layernorm_pass.py new file mode 100644 index 0000000..018d108 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_layernorm_pass.py @@ -0,0 +1,69 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.decompose_layernorm_pass import ( + DecomposeLayerNormPass, +) + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class LayerNorm(torch.nn.Module): + """ + Basic layer_norm model using torch.nn.layer_norm layer + """ + + def __init__(self): + super(LayerNorm, self).__init__() + self.layer_norm = torch.nn.LayerNorm(10) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.layer_norm(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(10),) + + +def test_decompose_layer_norm_tosa_FP(): + module = LayerNorm() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_native_layer_norm_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_add_Tensor", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_rsqrt_default", + "executorch_exir_dialects_edge__ops_aten_var_correction", + "executorch_exir_dialects_edge__ops_aten_sub_Tensor", + "executorch_exir_dialects_edge__ops_aten_mean_dim", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_rsqrt_default": 1, + "executorch_exir_dialects_edge__ops_aten_var_correction": 1, + "executorch_exir_dialects_edge__ops_aten_sub_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_expand_copy_default" + ], + pass_list=[DecomposeLayerNormPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py new file mode 100644 index 0000000..73b9008 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_linalg_vector_norm_pass.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch + +from executorch.backends.arm._passes.decompose_linalg_vector_norm_pass import ( + DecomposeLinalgVectorNormPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] + + +class ModuleWithInputs(Protocol): + ord: float | None + + def get_inputs(self) -> input_t: ... + + +class VectorNormModel(torch.nn.Module): + """ + A test module with torch.linalg.vector_norm. + https://pytorch.org/docs/stable/generated/torch.linalg.vector_norm.html + + We support only order 1 or 2. + """ + + def __init__( + self, ord: float | None = None, dim=None, keepdim: bool = False + ) -> None: + super().__init__() + self.ord = ord + self.dim = dim + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + if self.ord is None and self.dim is None: + return torch.linalg.vector_norm(x, keepdim=self.keepdim) + elif self.ord is None: + return torch.linalg.vector_norm(x, dim=self.dim, keepdim=self.keepdim) + elif self.dim is None: + return torch.linalg.vector_norm(x, ord=self.ord, keepdim=self.keepdim) + else: + return torch.linalg.vector_norm( + x, ord=self.ord, dim=self.dim, keepdim=self.keepdim + ) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +modules = { + # Default uses p=2 (l2 vector norm) + "default_p2": VectorNormModel(dim=1), + # p = 1: L1 norm over all elements + "p1": VectorNormModel(ord=1, dim=1), +} + + +@common.parametrize("module", modules) +def test_decompose_linalg_vector_norm_tosa_INT(module: ModuleWithInputs) -> None: + """ + This test creates a PassPipeline that applies the DecomposeLinalgVectorNormPass. + The expected primitive ops vary depending on the norm order: + - p == 1: should decompose to ABS and SUM. + - p == 2 (default): should decompose to MUL, SUM, and SQRT. + - Other p: should decompose to ABS, two instances of POW, and SUM. + """ + ord_val = module.ord if module.ord is not None else 2.0 + + ops_after_pass: Dict[str, int] + if ord_val == 1: + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_abs_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + } + elif ord_val == 2: + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 2, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + } + else: + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_abs_default": 1, + "executorch_exir_dialects_edge__ops_aten_pow_Tensor_Scalar": 2, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + } + + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + # The op is decomposed in legalization aten -> edge, so we are not able to check ops before + ops_before_pass=None, + ops_not_before_pass=None, + ops_after_pass=ops_after_pass, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_linarg_vector_norm_default", + ], + pass_list=[DecomposeLinalgVectorNormPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_meandim_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_meandim_pass.py new file mode 100644 index 0000000..d696485 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_meandim_pass.py @@ -0,0 +1,137 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithMeanAttrs(Protocol): + ops_after_pass: Dict[str, int] + ops_not_after_pass: list[str] + u55_ops_after_pass: Dict[str, int] + u55_ops_not_after_pass: list[str] + + def get_inputs(self) -> input_t: ... + + +class MeanDim(torch.nn.Module): + """ + Basic mean model using torch.mean with keepdim = True + """ + + ops_after_pass = u55_ops_after_pass = { + "torch.ops.aten.sum.dim_IntList": 2, + "torch.ops.aten.mul.Tensor": 1, + } + + ops_not_after_pass = u55_ops_not_after_pass = [ + "torch.ops.aten.reshape.default", + "torch.ops.aten.avg_pool2d.default", + "torch.ops.aten.mean.dim", + ] + + def __init__(self): + super(MeanDim, self).__init__() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.mean(x, (0, 1), True) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4, 4, 4),) + + +class MeanDimTensor(torch.nn.Module): + """ + Basic mean model using torch.Tensor.mean with keepdim = False + """ + + ops_after_pass = { + "torch.ops.aten.sum.dim_IntList": 2, + "torch.ops.aten.mul.Tensor": 1, + "torch.ops.aten.avg_pool2d.default": 1, + "torch.ops.aten.reshape.default": 1, + } + + ops_not_after_pass = [ + "torch.ops.aten.mean.dim", + ] + + u55_ops_after_pass = { + "torch.ops.aten.sum.dim_IntList": 2, + "torch.ops.aten.mul.Tensor": 1, + "torch.ops.aten.reshape.default": 1, + } + + u55_ops_not_after_pass = [ + "torch.ops.aten.avg_pool2d.default", + "torch.ops.aten.mean.dim", + ] + + def __init__(self): + super(MeanDimTensor, self).__init__() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.mean((0, 2), False) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4, 4, 4),) + + +modules: Dict[str, ModuleWithMeanAttrs] = { + "meandim_basic": MeanDim(), + "meandim_tensor": MeanDimTensor(), +} + + +@common.parametrize("module", modules) +def test_decompose_mean_dim_tosa_INT(module: ModuleWithMeanAttrs) -> None: + # Decompose meandim_pass requires initiating the pas with args, which is not supported + # by RunPasses in the arm_tester -> PassPipeline cannot be used. + nn_module = cast(torch.nn.Module, module) + pipeline = TosaPipelineINT[input_t](nn_module, module.get_inputs(), []) + pipeline.pop_stage("check_not.exir") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("to_executorch") + pipeline.pop_stage("check.aten") + pipeline.add_stage_after("quantize", pipeline.tester.check, module.ops_after_pass) + pipeline.add_stage_after( + "quantize", pipeline.tester.check_not, module.ops_not_after_pass + ) + + pipeline.dump_artifact("quantize") + pipeline.run() + + +@common.parametrize("module", modules) +def test_decompose_mean_dim_u55_INT(module: ModuleWithMeanAttrs) -> None: + # Decompose meandim_pass requires initiating the pas with args, which is not supported + # by RunPasses in the arm_tester -> PassPipeline cannot be used. + nn_module = cast(torch.nn.Module, module) + pipeline = EthosU55PipelineINT[input_t]( + nn_module, module.get_inputs(), [], run_on_fvp=False + ) + pipeline.pop_stage("check_not.exir") + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("to_executorch") + pipeline.pop_stage("check.aten") + pipeline.add_stage_after( + "quantize", pipeline.tester.check, module.u55_ops_after_pass + ) + pipeline.add_stage_after( + "quantize", pipeline.tester.check_not, module.u55_ops_not_after_pass + ) + + pipeline.dump_artifact("quantize") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_quant_nodes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_quant_nodes.py new file mode 100644 index 0000000..b25dffd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_quant_nodes.py @@ -0,0 +1,44 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import DecomposeQuantNodesPass +from executorch.backends.arm.test.common import parametrize +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +class Mul(torch.nn.Module): + test_data = { + "randn": (torch.randn(1, 3, 16, 16), torch.randn(1, 3, 16, 16)), + "large_randn": (10e10 * torch.randn(1, 3, 16, 16), torch.randn(1, 3, 16, 16)), + } + + def forward(self, x, y): + return x * y + + +@parametrize("test_data", Mul.test_data) +def test_decompose_quant_nodes_tosa_INT(test_data: Tuple[torch.Tensor]): + module = Mul() + q_dq_ops = { + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + # Verify that DecomposeQuantNodesPass removes quantize/dequantize nodes + # and that the output is correct. + pipeline = PassPipeline( + module, + test_data, + quantize=True, + pass_list=[ + DecomposeQuantNodesPass, + ], + ops_before_pass=q_dq_ops, + ops_not_after_pass=list(q_dq_ops.keys()), + tosa_extensions=["FP"], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_softmax_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_softmax_pass.py new file mode 100644 index 0000000..1212593 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_softmax_pass.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.decompose_softmax_pass import DecomposeSoftmaxPass + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Softmax(torch.nn.Module): + """ + Basic torch.nn.softmax layer model + """ + + def __init__(self): + super(Softmax, self).__init__() + self.softmax = torch.nn.Softmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.softmax(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(2, 3),) + + +class SoftmaxLog(torch.nn.Module): + """ + Basic torch.nn.log_softmax layer model + """ + + def __init__(self): + super(SoftmaxLog, self).__init__() + self.softmax = torch.nn.LogSoftmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.softmax(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(2, 3),) + + +def test_decompose_softmax_tosa_FP_basic(): + module = Softmax() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten__softmax_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList", + "executorch_exir_dialects_edge__ops_aten_exp_default", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_exp_default": 1, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten__softmax_default"], + pass_list=[DecomposeSoftmaxPass], + ) + pipeline.run() + + +def test_decompose_softmax_tosa_FP_log(): + module = SoftmaxLog() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten__log_softmax_default": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_reciprocal_default", + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList", + "executorch_exir_dialects_edge__ops_aten_exp_default", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_exp_default": 1, + "executorch_exir_dialects_edge__ops_aten_reciprocal_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten__log_softmax_default" + ], + pass_list=[DecomposeSoftmaxPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py new file mode 100644 index 0000000..756685c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_tosa_unsupported_clamp_pass.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.decompose_tosa_unsupported_clamp_pass import ( + DecomposeTOSAUnsupportedClampPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] + + +class ClampInt32(torch.nn.Module): + test_data = {"rand": (torch.randint(-50, 50, (2, 3), dtype=torch.int32),)} + + def forward(self, x: torch.Tensor): + return torch.clamp(x, -10, 5) + + +@common.parametrize("test_data", ClampInt32.test_data) +def test_decompose_tosa_unsupported_clamp_tosa_FP_int32(test_data: input_t): + module = ClampInt32() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_clamp_default", + ], + pass_list=[DecomposeTOSAUnsupportedClampPass], + ) + pipeline.run() + + +class ClampTensorInt32(torch.nn.Module): + test_data = {"rand": (torch.randint(-50, 50, (2, 3), dtype=torch.int32),)} + + def forward(self, x: torch.Tensor): + return torch.clamp(x, torch.tensor(-10), torch.tensor(5)) + + +@common.parametrize("test_data", ClampTensorInt32.test_data) +def test_decompose_tosa_unsupported_clamp_tosa_FP_int32_tensor(test_data: input_t): + module = ClampTensorInt32() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_clamp_Tensor": 1, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_aten_clamp_Tensor", + ], + pass_list=[DecomposeTOSAUnsupportedClampPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_var_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_var_pass.py new file mode 100644 index 0000000..2e31c9d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decompose_var_pass.py @@ -0,0 +1,89 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.decompose_var_pass import DecomposeVarPass + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithInputs(Protocol): + def get_inputs(self) -> input_t: ... + + +class VarDim(torch.nn.Module): + """ + Basic variance model using torch.Tensor.var function. + """ + + def __init__(self, keepdim): + super(VarDim, self).__init__() + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.var(dim=-1, keepdim=self.keepdim) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +class VarCorrection(torch.nn.Module): + """ + Basic variance model using torch.var function. + """ + + def __init__(self, keepdim): + super(VarCorrection, self).__init__() + self.keepdim = keepdim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.var(x, -1, keepdim=self.keepdim) + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4),) + + +modules: Dict[str, ModuleWithInputs] = { + "vardim_keepdim": VarDim(True), + "vardim_no_keepdim": VarDim(False), + "varcorrection_keepdim": VarCorrection(True), + "varcorrection_no_keepdim": VarCorrection(False), +} + + +@common.parametrize("module", modules) +def test_decompose_var_tosa_FP(module: ModuleWithInputs) -> None: + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_aten_var_correction": 1, + }, + ops_not_before_pass=[ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor", + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList", + "executorch_exir_dialects_edge__ops_aten_mean_dim", + "executorch_exir_dialects_edge__ops_aten_sub_Tensor", + ], + ops_after_pass={ + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 1, + "executorch_exir_dialects_edge__ops_aten_sub_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_sum_dim_IntList": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten_var_correction"], + pass_list=[DecomposeVarPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py new file mode 100644 index 0000000..588428a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_decorate_fp32_to_int32_casting_pass.py @@ -0,0 +1,85 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Dict, Tuple + +import torch +from executorch.backends.arm.test import common, conftest + +from executorch.backends.arm.test.tester.test_pipeline import ( + OpNotSupportedPipeline, + TosaPipelineFP, +) + +input_t1 = Tuple[torch.Tensor] # Input x + + +class FP32ToINT32Casting(torch.nn.Module): + def __init__(self, target_dtype: torch.dtype) -> None: + super().__init__() + self.target_dtype = target_dtype + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.to(self.target_dtype) + + +test_data_fp32_input: Dict[str, Callable[[], Tuple[torch.Tensor, torch.dtype]]] = { + "fp32_input_rank1": lambda: ( + torch.rand((4), dtype=torch.float32), + torch.int32, + ), + "fp32_input_rank2": lambda: ( + torch.rand((3, 4), dtype=torch.float32), + torch.int32, + ), + "fp32_input_rank3": lambda: ( + torch.rand((2, 3, 4), dtype=torch.float32), + torch.int32, + ), + "fp32_input_rank4": lambda: ( + torch.rand((1, 2, 3, 4), dtype=torch.float32), + torch.int32, + ), +} + + +@common.parametrize("test_data", test_data_fp32_input) +def test_decorate_fp32_to_int32_casting_tosa_FP( + test_data: Callable[[], Tuple[torch.Tensor, torch.dtype]] +) -> None: + test_tensor, target_dtype = test_data() + module = FP32ToINT32Casting(target_dtype) + + pipeline = TosaPipelineFP[input_t1]( + module, + (test_tensor,), + aten_op=[], + exir_op=[], + run_on_tosa_ref_model=conftest.is_option_enabled("tosa_ref_model"), + ) + pipeline.run() + + +@common.parametrize("test_data", test_data_fp32_input) +def test_decorate_fp32_to_int32_casting_tosa_INT( + test_data: Callable[[], Tuple[torch.Tensor, torch.dtype]] +) -> None: + """ + Casting operation involving floating-point dtypes will be rejected in INT/INT profile. + Therefore, the DecorateFp32toInt32CastingPass is not required in this profile. + Add a INT test to ensure that such casting is rejected as expected. + """ + test_tensor, target_dtype = test_data() + module = FP32ToINT32Casting(target_dtype) + + pipeline = OpNotSupportedPipeline[input_t1]( + module, + (test_tensor,), + { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1 + }, + quantize=True, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fold_qdq_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fold_qdq_pass.py new file mode 100644 index 0000000..d76384a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fold_qdq_pass.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes import FoldAndAnnotateQParamsPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +input_t = Tuple[torch.Tensor, torch.Tensor] # Input x, y + + +class SimpleQuantizeModel(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = { + "rand": (torch.rand(1, 1280, 7, 7), torch.rand(1, 1280, 7, 7)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return x + torch.maximum((x + x), (y + y)) + + +@common.parametrize("test_data", SimpleQuantizeModel.test_data) +def test_fold_and_annotate_q_params_tosa_INT(test_data: input_t) -> None: + """ + Tests the FoldAndAnnotateQParamsPass which folds dq/q nodes into + the node and stores the quantization parameters in meta. + + Check that the pass runs for add operation and that one q node and one dq node + is removed from the representation. + """ + module = SimpleQuantizeModel() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 7, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 6, + }, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + }, + pass_list=[FoldAndAnnotateQParamsPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_batchnorm_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_batchnorm_pass.py new file mode 100644 index 0000000..5e461f9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_batchnorm_pass.py @@ -0,0 +1,164 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, ClassVar, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.fuse_batch_norm2d_pass import FuseBatchNorm2dPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithBatchNormAttrs(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + + def get_inputs(self) -> input_t: ... + + +class MergeOneOfTwoBN(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 2, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 0, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 2, + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + if affine: + self.batch_norm2d.weight = torch.nn.Parameter(torch.rand(3)) + self.batch_norm2d.bias = torch.nn.Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> input_t: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.conv2d(x) + x = self.batch_norm2d(x) + x = self.relu6(x) + x = self.batch_norm2d(x) + return x + + +class MergeTwosOfTwoBN(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 2, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 2, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 0, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 2, + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.conv2d2 = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + if affine: + self.batch_norm2d.weight = torch.nn.Parameter(torch.rand(3)) + self.batch_norm2d.bias = torch.nn.Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> input_t: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.conv2d(x) + x = self.batch_norm2d(x) + x = self.relu6(x) + x = self.conv2d2(x) + x = self.batch_norm2d(x) + return x + + +class MergeMultipleUsersBN(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 2, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 3, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten__native_batch_norm_legit_no_training_default": 0, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 4, + } + + def __init__(self, affine: bool): + super().__init__() + self.conv2d = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.conv2d2 = torch.nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, stride=1, groups=1 + ) + self.batch_norm2d = torch.nn.BatchNorm2d(3, affine=affine) + self.batch_norm2d.running_mean = torch.rand(3) + self.batch_norm2d.running_var = torch.rand(3) + if affine: + self.batch_norm2d.weight = torch.nn.Parameter(torch.rand(3)) + self.batch_norm2d.bias = torch.nn.Parameter(torch.rand(3)) + self.relu6 = torch.nn.ReLU6() + + def get_inputs(self) -> input_t: + return (torch.randn(1, 3, 256, 256),) + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + x1 = self.conv2d(x) + x = self.batch_norm2d( + x1 + ) # Replaces bn wih a new conv since x1 has multiple users + x = self.relu6(x) + y = self.conv2d2(x1) + z = self.conv2d2(x) + a = self.batch_norm2d( + y + ) # Can be fused despite paramters of conv2d2 having multiple users. + + return z, a + + +modules: Dict[str, ModuleWithBatchNormAttrs] = { + "merge_one_of_two_bn_affine": cast(ModuleWithBatchNormAttrs, MergeOneOfTwoBN(True)), + "merge_one_of_two_bn": cast(ModuleWithBatchNormAttrs, MergeOneOfTwoBN(False)), + "merge_two_of_two_bn_affine": cast( + ModuleWithBatchNormAttrs, MergeTwosOfTwoBN(True) + ), + "merge_multiple_users_bn_affine": cast( + ModuleWithBatchNormAttrs, MergeMultipleUsersBN(True) + ), +} + + +@common.parametrize("module", modules) +def test_fuse_batch_norm2d_tosa_FP(module: ModuleWithBatchNormAttrs) -> None: + """Test various cases where the batchnorm should either be fused with a previous + conv, or converted to a new conv.""" + nn_module = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + nn_module, + module.get_inputs(), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[FuseBatchNorm2dPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_constant_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_constant_ops_pass.py new file mode 100644 index 0000000..19888f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_constant_ops_pass.py @@ -0,0 +1,177 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import operator +from typing import cast, ClassVar, Dict, Protocol, Tuple + +import torch +from executorch.backends.arm._passes.fuse_constant_ops_pass import ( + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, +) +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x +input_t2 = Tuple[torch.Tensor, torch.Tensor] + + +class ModuleWithFuseAttrs(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + ops_not_after_pass: list[str] + + def get_inputs(self) -> input_t: ... + + +class FuseParameter(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 1, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1 + } + ops_not_after_pass: ClassVar[list[str]] = [ + "executorch_exir_dialects_edge__ops_aten_full_default", + "executorch_exir_dialects_edge__ops_aten_view_copy_default", + "executorch_exir_dialects_edge__ops_aten_permute_copy_default", + "executorch_exir_dialects_edge__ops_aten_addmm_default", + ] + + def __init__( + self, + in_features: int = 1, + out_features: int = 1, + bias: bool = True, + ): + super().__init__() + self.fc = torch.nn.Linear( + in_features=in_features, + out_features=out_features, + bias=bias, + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.fc(torch.ones(1)) + x + + +class FuseBuffer(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + } + ops_not_after_pass: ClassVar[list[str]] = [ + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default" + ] + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return (x + 1) * 2 + + +class FuseLiftedTensor(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_select_copy_int": 1, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1 + } + ops_not_after_pass: ClassVar[list[str]] = [ + "executorch_exir_dialects_edge__ops_aten_select_copy_int" + ] + + def __init__( + self, + ): + super().__init__() + self.lifted_tensor = torch.rand(2) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + sliced = self.lifted_tensor[0] + return operator.add(sliced, x) + + +class CatConst(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + } + ops_after_pass: ClassVar[Dict[str, int]] = { + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + } + ops_not_after_pass: ClassVar[list[str]] = [] + + def __init__(self): + super().__init__() + + def forward(self, a: torch.Tensor, b: torch.Tensor) -> torch.Tensor: + return torch.cat((a, b), dim=0) + + +modules: Dict[str, ModuleWithFuseAttrs] = { + "fuse_parameter": cast(ModuleWithFuseAttrs, FuseParameter()), + "fuse_buffer": cast(ModuleWithFuseAttrs, FuseBuffer()), + "fuse_const_tensor": cast(ModuleWithFuseAttrs, FuseLiftedTensor()), +} + +cat_module: Dict[str, ModuleWithFuseAttrs] = { + "fuse_cat": cast(ModuleWithFuseAttrs, CatConst()), +} + + +@common.parametrize("module", modules) +def test_fuse_constant_args_tosa_FP(module: ModuleWithFuseAttrs) -> None: + pipeline = PassPipeline[input_t]( + module=cast(torch.nn.Module, module), + test_data=(torch.rand(1),), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + ops_not_after_pass=module.ops_not_after_pass, + passes_with_exported_program=[ + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, + ], + ) + pipeline.run() + + +@common.parametrize("module", modules) +def test_fuse_constant_args_tosa_INT(module: ModuleWithFuseAttrs) -> None: + pipeline = PassPipeline[input_t]( + cast(torch.nn.Module, module), + (torch.rand(10, 10),), + quantize=True, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[ + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, + ], + ) + pipeline.run() + + +@common.parametrize("module", cat_module) +def test_fuse_constant_args_tosa_INT_cat(module: ModuleWithFuseAttrs) -> None: + pipeline = PassPipeline[input_t2]( + cast(torch.nn.Module, module), + (torch.rand(3), torch.rand(2)), + quantize=True, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[ + ComputeConstantOpsAOTPass, + FuseConstantArgsPass, + ], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_duplicate_users_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_duplicate_users_pass.py new file mode 100644 index 0000000..d94e01f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_duplicate_users_pass.py @@ -0,0 +1,70 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, Tuple + +import torch +from executorch.backends.arm._passes import FuseDuplicateUsersPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithOps(torch.nn.Module): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + + +class FuseaAvgPool(ModuleWithOps): + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 3, + } + ops_after_pass = {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1} + + def __init__(self): + super().__init__() + self.avg = torch.nn.AvgPool2d(1) + + def forward(self, x): + return self.avg(x) + self.avg(x) + self.avg(x) + + +class FuseAvgPoolChain(ModuleWithOps): + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 6, + } + ops_after_pass = {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 2} + + def __init__(self): + super().__init__() + self.avg = torch.nn.AvgPool2d(1) + + def forward(self, x): + first = self.avg(self.avg(x)) + second = self.avg(self.avg(x)) + third = self.avg(self.avg(x)) + return first + second + third + + +modules: Dict[str, ModuleWithOps] = { + "fuse_avg_pool": FuseaAvgPool(), + "fuse_avg_pool_chain": FuseAvgPoolChain(), +} + + +@common.parametrize("module", modules) +def test_fuse_duplicate_users_tosa_FP(module: ModuleWithOps): + pipeline = PassPipeline[input_t]( + module=module, + test_data=(torch.ones(1, 1, 1, 1),), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + pass_list=[ + FuseDuplicateUsersPass, + ], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py new file mode 100644 index 0000000..b29bb67 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_equal_placeholders_ops_pass.py @@ -0,0 +1,170 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from copy import deepcopy +from typing import Callable, cast, ClassVar, Dict, Protocol, Tuple, TypeVar + +import torch +from executorch.backends.arm._passes.fuse_equal_placeholders_pass import ( + FuseEqualPlaceholdersPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + PassPipeline, + TosaPipelineFP, +) + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleWithEqualPlaceholderAttrs(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + ops_not_after_pass: list[str] + + def get_inputs(self) -> input_t: ... + + +T = TypeVar("T") +TestDecorator = Callable[[Callable[[T], None]], Callable[[T], None]] + + +def _typed_parametrize(test_data: Dict[str, T]) -> TestDecorator: + return cast(TestDecorator, common.parametrize("module", test_data)) + + +class FuseWeightsConstants(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = {} + ops_after_pass: ClassVar[Dict[str, int]] = {} + ops_not_after_pass: ClassVar[list[str]] = [] + + def __init__( + self, + ): + super().__init__() + self.weights1 = torch.rand(1, 2, 1) + self.weights2 = deepcopy(self.weights1) + self.bias1 = torch.rand(1) + self.bias2 = deepcopy(self.bias1) + self.bias3 = deepcopy(self.bias1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return ( + torch.conv1d(x, self.weights1, self.bias1) + + torch.conv1d(x, self.weights2, self.bias2) + + self.bias3 + ) + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 8),) + + +class FuseWeightsStateDict(torch.nn.Module): + ops_before_pass: ClassVar[Dict[str, int]] = {} + ops_after_pass: ClassVar[Dict[str, int]] = {} + ops_not_after_pass: ClassVar[list[str]] = [] + + def __init__( + self, + ): + super().__init__() + self.fc1 = torch.nn.Linear(in_features=8, out_features=2, bias=True) + self.fc2 = deepcopy(self.fc1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.fc1(x) + self.fc2(x) + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 8),) + + +class NotFuseTensorWithDifferentType(torch.nn.Module): + + ops_before_pass: ClassVar[Dict[str, int]] = {} + ops_after_pass: ClassVar[Dict[str, int]] = {} + ops_not_after_pass: ClassVar[list[str]] = [] + + def forward(self, x: torch.Tensor, y: torch.Tensor): + """ + Args: + x: A float tensor (dtype=torch.float32) + y: An int tensor (dtype=torch.int32) + """ + a = torch.tensor(1.0, dtype=torch.float32) + b = torch.tensor(1, dtype=torch.int32) + m = x < a + n = y > b + return m, n + + +constants_modules: Dict[str, ModuleWithEqualPlaceholderAttrs] = { + "fuse_constants": cast(ModuleWithEqualPlaceholderAttrs, FuseWeightsConstants()), +} + +parametrize_constants = _typed_parametrize(constants_modules) + + +@parametrize_constants +def test_fuse_equal_placeholders_tosa_FP_constants( + module: ModuleWithEqualPlaceholderAttrs, +) -> None: + pipeline = PassPipeline[input_t]( + cast(torch.nn.Module, module), + module.get_inputs(), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[FuseEqualPlaceholdersPass], + ) + pipeline.run() + + # Check that weights and bias has been merged. + exp_program = pipeline.tester.get_artifact().exported_program() + constant_keys = list(exp_program.constants.keys()) + assert len(constant_keys) == 2, "FuseEqualPlaceholders constants failed" + assert "_common" in constant_keys[0], "FuseEqualPlaceholders constants failed" + assert "_common" in constant_keys[1], "FuseEqualPlaceholders constants failed" + + +def test_fuse_equal_placeholders_tosa_FP_state_dict() -> None: + module = FuseWeightsStateDict() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=False, + ops_before_pass=module.ops_before_pass, + ops_after_pass=module.ops_after_pass, + passes_with_exported_program=[FuseEqualPlaceholdersPass], + ) + pipeline.run() + + # Check that weights and bias has been merged. + exp_program = pipeline.tester.get_artifact().exported_program() + state_dict_keys = list(exp_program.state_dict.keys()) + assert len(state_dict_keys) == 2, "FuseEqualPlaceholders state_dict failed" + assert "_common" in state_dict_keys[0], "FuseEqualPlaceholders state_dict failed" + assert "_common" in state_dict_keys[1], "FuseEqualPlaceholders state_dict failed" + + +def test_fuse_equal_placeholders_tosa_FP_no_fuse_type_diff(): + module = NotFuseTensorWithDifferentType() + data = ( + torch.rand( + 1, + ), + torch.randint( + 0, + 10, + (1,), + dtype=torch.int, + ), + ) + pipeline = TosaPipelineFP[input_t]( + module, + data, + aten_op=[], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_view_copy.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_view_copy.py new file mode 100644 index 0000000..6901ca9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_fuse_view_copy.py @@ -0,0 +1,82 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline +from executorch.backends.transforms.fuse_view_copy import FuseViewCopyTransform + + +class FuseSequentialViews(torch.nn.Module): + def forward(self, x: torch.Tensor): + return x.view((1, 2, 3, 4)).view((2, 3, 4, 1)).view((2, 3, 4)) + + data = (torch.randn(2, 3, 1, 4),) + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 3, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 1, + } + + +class FuseSequentialWithNoopsViews(torch.nn.Module): + def forward(self, x: torch.Tensor): + return ( + x.view((1, 2, 3, 4)) + .clone() + .view((2, 3, 4, 1)) + .to(dtype=torch.int32) + .view((2, 3, 4)) + .abs() + .reciprocal() + .sqrt() + .view((12, 2)) + ) + + data = (torch.randn(2, 3, 1, 4),) + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 4, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 1, + } + + +class DontFuseBranchingViews(torch.nn.Module): + def forward(self, x: torch.Tensor): + x = x.view((1, 2, 3, 4)) + x1 = x.abs().view((2, 3, 4, 1)) + x2 = x.ceil().view((2, 3, 4, 1)) + return x1 + x2 + + data = (torch.randn(2, 3, 1, 4),) + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 3, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 3, + } + + +tests = { + "fuse_sequential_views": FuseSequentialViews(), + "fuse_sequential_with_noops_views": FuseSequentialWithNoopsViews(), + "dont_fuse_branching_views": DontFuseBranchingViews(), +} + + +@common.parametrize("model", tests) +def test_fuse_view_copy_transform_tosa_FP(model): + pipeline = PassPipeline( + model, + model.data, + quantize=False, + ops_before_pass=model.ops_before_pass, + ops_after_pass=model.ops_after_pass, + pass_list=[FuseViewCopyTransform], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py new file mode 100644 index 0000000..8cae159 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_int32_casts_after_int64_placeholders_pass.py @@ -0,0 +1,114 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import InsertInt32CastsAfterInt64PlaceholdersPass + +from executorch.backends.arm.test.tester.test_pipeline import ( + PassPipeline, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor, torch.Tensor] # weights, indices +input_t3 = Tuple[torch.Tensor, torch.LongTensor, torch.Tensor] + + +class Int64InputModel(torch.nn.Module): + + def forward(self, weights: torch.Tensor, indices: torch.Tensor): + return torch.embedding(weights, indices) + + def get_inputs(self) -> input_t: + return ( + torch.randn(9, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int64), + ) + + +def test_insert_int32_casts_after_int64_placeholders_tosa_FP(): + module = Int64InputModel() + op_checks_before = { + "executorch_exir_dialects_edge__ops_aten_embedding_default": 1, + } + op_checks_after = { + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_embedding_default": 1, + } + + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + ops_before_pass=op_checks_before, + ops_after_pass=op_checks_after, + pass_list=[InsertInt32CastsAfterInt64PlaceholdersPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() + + +class UpcastToInt64ForIndexCopyInplaceModel(torch.nn.Module): + aten_op = "torch.ops.aten.index_copy_.default" + + def forward(self, x: torch.Tensor, index: torch.LongTensor, y: torch.Tensor): + return x.index_copy_(0, index, y) + + def get_inputs(self) -> input_t3: + return ( + torch.zeros(5, 3), + torch.LongTensor([0, 4, 2]), + torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=torch.float), + ) + + +def test_insert_int32_casts_after_int64_placeholders_tosa_INT_upcast_for_index_copy_inplace(): + module = UpcastToInt64ForIndexCopyInplaceModel() + pipeline = TosaPipelineINT[input_t3]( + module, + module.get_inputs(), + aten_op=module.aten_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 0, + }, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +class UpcastToInt64ForIndexCopyModel(torch.nn.Module): + aten_op = "torch.ops.aten.index_copy.default" + + def forward(self, x: torch.Tensor, index: torch.LongTensor, y: torch.Tensor): + return x.index_copy(0, index, y) + + def get_inputs(self) -> input_t3: + return ( + torch.zeros(5, 3), + torch.LongTensor([0, 4, 2]), + torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=torch.float), + ) + + +def test_insert_int32_casts_after_int64_placeholders_tosa_INT_upcast_for_index_copy(): + module = UpcastToInt64ForIndexCopyModel() + pipeline = TosaPipelineINT[input_t3]( + module, + module.get_inputs(), + aten_op=module.aten_op, + ) + pipeline.pop_stage("check.quant_nodes") + pipeline.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": 0, + }, + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_rescale_i32_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_rescale_i32_pass.py new file mode 100644 index 0000000..e685da1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_rescale_i32_pass.py @@ -0,0 +1,107 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import ( + FoldAndAnnotateQParamsPass, + InsertRescaleInt32Pass, +) +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +class MultipleOpsModel(torch.nn.Module): + """A module containing ops that require INT32 inputs/outputs.""" + + input_t = Tuple[torch.Tensor, torch.Tensor] + + def forward(self, x, y): + a = x - y + b = x * a + c = torch.maximum(a, b) + d = torch.abs(b) + e = c + d + f = e > a + return f + + def get_inputs(self, dtype) -> input_t: + if dtype == torch.float32: + return (torch.rand(1, 3, 5, 6), torch.rand(1, 3, 5, 6)) + elif dtype == torch.int32: + return ( + torch.randint(3, 5, (3,), dtype=torch.int32), + torch.randint(3, 5, (3,), dtype=torch.int32), + ) + else: + raise ValueError("Not a valid input dtype for model") + + def get_num_expected_rescales(self): + # "number of op nodes with i8 output" + "number of i8 node inputs" + return 5 + 11 + + +class SumModel(torch.nn.Module): + input_t = Tuple[torch.Tensor] + + def forward(self, x): + a = torch.sum(x, 2, keepdim=True) # (1, 2, 1, 4) + b = torch.sum(a, [1, 3], keepdim=True) # (1, 1, 1, 1) + c = torch.sum(b, [0, 2], keepdim=False) # (1, 1) + return c + + def get_inputs(self, dtype) -> input_t: + if dtype == torch.float32: + return (torch.rand(1, 2, 3, 4),) + elif dtype == torch.int32: + return (torch.randint(0, 10, (1, 2, 3, 4), dtype=torch.int32),) + else: + raise ValueError("Not a valid input dtype for model") + + def get_num_expected_rescales(self): + # Two RESCALE nodes per SUM node + return 6 + + +def _test_model_with_f32_data(model): + ops_not_before = {"executorch_exir_dialects_backend__ops_tosa_RESCALE_default"} + ops_after = { + "executorch_exir_dialects_backend__ops_tosa_RESCALE_default": model.get_num_expected_rescales(), + } + pipeline = PassPipeline[model.input_t]( + model, + model.get_inputs(torch.float32), + quantize=True, + ops_not_before_pass=ops_not_before, + ops_after_pass=ops_after, + pass_list=[FoldAndAnnotateQParamsPass, InsertRescaleInt32Pass], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +def test_insert_rescale_int32_tosa_INT_sum(): + _test_model_with_f32_data(SumModel()) + + +def test_insert_rescale_int32_tosa_INT_multiple_ops(): + _test_model_with_f32_data(MultipleOpsModel()) + + +def test_insert_rescale_int32_tosa_FP_dont_insert_rescales(): + module = MultipleOpsModel() + input_t = Tuple[torch.Tensor, torch.Tensor] + ops_not_before = {"executorch_exir_dialects_backend__ops_tosa_RESCALE_default"} + # All inputs are already i32. Rescales should not be added. + ops_not_after = {"executorch_exir_dialects_backend__ops_tosa_RESCALE_default"} + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(torch.int32), + ops_not_before_pass=ops_not_before, + ops_not_after_pass=ops_not_after, + pass_list=[FoldAndAnnotateQParamsPass, InsertRescaleInt32Pass], + ) + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_table_ops_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_table_ops_pass.py new file mode 100644 index 0000000..693bd19 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_insert_table_ops_pass.py @@ -0,0 +1,47 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes.fold_qdq_with_annotated_qparams_pass import ( + FoldAndAnnotateQParamsPass, +) +from executorch.backends.arm._passes.insert_table_ops import InsertTableOpsPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Sigmoid(torch.nn.Module): + test_data: ClassVar[Dict[str, input_t]] = { + "rand": (torch.rand(4),), + } + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.sigmoid() + + +@common.parametrize("test_data", Sigmoid.test_data) +def test_insert_table_ops_tosa_INT(test_data: input_t) -> None: + module = Sigmoid() + pipeline = PassPipeline[input_t]( + module, + test_data, + quantize=True, + ops_before_pass={"executorch_exir_dialects_edge__ops_aten_sigmoid_default": 1}, + ops_after_pass={ + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 1, + "backend__ops_tosa_TABLE_default": 1, + }, + ops_not_after_pass=["executorch_exir_dialects_edge__ops_aten_sigmoid_default"], + pass_list=[FoldAndAnnotateQParamsPass], + passes_with_exported_program=[InsertTableOpsPass], + ) + pipeline.pop_stage(-1) # Do not compare output + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_int32_cast_embedding_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_int32_cast_embedding_pass.py new file mode 100644 index 0000000..dbe4d1b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_int32_cast_embedding_pass.py @@ -0,0 +1,46 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes import DecomposeEmbeddingPass + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class Int32Embedding(torch.nn.Module): + + def forward(self, weights: torch.Tensor, indices: torch.Tensor) -> torch.Tensor: + return torch.embedding(weights, indices) + + def get_inputs(self) -> input_t: + return ( + torch.randn(9, 3), + torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32), + ) + + +def test_decompose_embedding_tosa_FP_int32(): + module = Int32Embedding() + op_checks_before = { + "executorch_exir_dialects_edge__ops_aten_embedding_default": 1, + } + op_checks_after = { + "executorch_exir_dialects_edge__ops_aten_view_copy": 2, + "executorch_exir_dialects_edge__ops_aten_index_select": 1, + } + + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + ops_before_pass=op_checks_before, + ops_after_pass=op_checks_after, + pass_list=[DecomposeEmbeddingPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_ioquantization_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_ioquantization_pass.py new file mode 100644 index 0000000..3fe89a7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_ioquantization_pass.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Tuple + +import torch + +from executorch.backends.arm.test import common + +from executorch.backends.arm.test.tester.test_pipeline import EthosU55PipelineINT +from executorch.exir.passes.quantize_io_pass import QuantizeInputs, QuantizeOutputs + + +input_t = Tuple[torch.Tensor, torch.Tensor] + + +class SimpleModel(torch.nn.Module): + test_data = { + "rand_rand": (torch.rand(1, 2, 2, 1), torch.rand(1, 2, 2, 1)), + } + + def forward(self, x, y): + return x + y + + +@common.parametrize("test_data", SimpleModel.test_data) +def test_quantize_io_u55_INT(test_data: input_t): + """ + Test the executorch/exir/passes/quantize_io_pass pass works(meaning we don't get Q/DQ nodes) on a simple model + """ + model = SimpleModel() + pipeline = EthosU55PipelineINT( + model, + test_data, + aten_ops=[], + exir_ops=[], + use_to_edge_transform_and_lower=False, + run_on_fvp=False, + ) + pipeline.pop_stage(-1) + pipeline.run() + edge = pipeline.tester.get_artifact() + edge.transform(passes=[QuantizeInputs(edge, [0, 1]), QuantizeOutputs(edge, [0])]) + pipeline.tester.check_not(["edge__ops_quantized_decomposed_quantize_per_tensor"]) + pipeline.tester.check_not(["edge__ops_quantized_decomposed_dequantize_per_tensor"]) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_promote_bool_operands_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_promote_bool_operands_pass.py new file mode 100644 index 0000000..61be6d4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_promote_bool_operands_pass.py @@ -0,0 +1,103 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import ClassVar, Dict, Tuple + +import torch +from executorch.backends.arm._passes import PromoteBoolOperandsPass + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline +from executorch.backends.test.harness.stages import StageType +from executorch.exir.dialects._ops import ops as exir_ops + +tensor_pair_t = Tuple[torch.Tensor, torch.Tensor] + + +def _collect_cast_dtypes(pipeline: PassPipeline[tensor_pair_t]) -> list[torch.dtype]: + exported_program = pipeline.tester.get_artifact( + StageType.RUN_PASSES + ).exported_program() + graph_module = exported_program.graph_module + cast_dtypes: list[torch.dtype] = [] + for node in graph_module.graph.nodes: + if ( + node.op == "call_function" + and node.target == exir_ops.edge.dim_order_ops._to_dim_order_copy.default + and "dtype" in node.kwargs + ): + cast_dtypes.append(node.kwargs["dtype"]) + return cast_dtypes + + +class BoolBitwiseAndModule(torch.nn.Module): + test_data: ClassVar[Dict[str, tensor_pair_t]] = { + "bool_tensors": ( + torch.tensor([[True, False], [False, True]], dtype=torch.bool), + torch.tensor([[False, True], [True, False]], dtype=torch.bool), + ) + } + + def forward(self, lhs: torch.Tensor, rhs: torch.Tensor) -> torch.Tensor: + return torch.bitwise_and(lhs, rhs) + + +class MixedMulModule(torch.nn.Module): + test_data: ClassVar[Dict[str, tensor_pair_t]] = { + "mixed_tensors": ( + torch.tensor([True, False, True, False], dtype=torch.bool), + torch.tensor([1, 2, 3, 4], dtype=torch.int32), + ) + } + + def forward(self, lhs: torch.Tensor, rhs: torch.Tensor) -> torch.Tensor: + return torch.mul(lhs, rhs) + + +@common.parametrize("test_data", BoolBitwiseAndModule.test_data) +def test_promote_bool_operands_tosa_FP_all_bool(test_data: tensor_pair_t) -> None: + module = BoolBitwiseAndModule() + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor": 1, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_bitwise_and_Tensor": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 3, + } + pipeline = PassPipeline[tensor_pair_t]( + module, + test_data, + quantize=False, + ops_before_pass=ops_before_pass, + ops_after_pass=ops_after_pass, + pass_list=[PromoteBoolOperandsPass], + ) + pipeline.run() + cast_dtypes = _collect_cast_dtypes(pipeline) + assert cast_dtypes.count(torch.int8) == 2 + assert cast_dtypes.count(torch.bool) == 1 + + +@common.parametrize("test_data", MixedMulModule.test_data) +def test_promote_bool_operands_tosa_FP_mixed_types(test_data: tensor_pair_t) -> None: + module = MixedMulModule() + ops_before_pass = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + } + ops_after_pass = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 1, + } + pipeline = PassPipeline[tensor_pair_t]( + module, + test_data, + quantize=False, + ops_before_pass=ops_before_pass, + ops_after_pass=ops_after_pass, + pass_list=[PromoteBoolOperandsPass], + ) + pipeline.run() + cast_dtypes = _collect_cast_dtypes(pipeline) + assert cast_dtypes.count(torch.int32) == 1 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_remove_clone_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_remove_clone_pass.py new file mode 100755 index 0000000..c0182b2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_remove_clone_pass.py @@ -0,0 +1,45 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm._passes.remove_noop_pass import RemoveNoopPass + +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +input_t = Tuple[torch.Tensor] # Input x + + +class Clone(torch.nn.Module): + """ + Basic remove layer model to test RemoveNoopePass + """ + + def __init__(self): + super(Clone, self).__init__() + + def forward(self, x): + return torch.clone(x) + + def get_inputs(self) -> input_t: + return (torch.rand(3, 1),) + + +def test_remove_noop_tosa_INT_clone(): + module = Clone() + pipeline = PassPipeline[input_t]( + module, + module.get_inputs(), + quantize=True, + ops_before_pass={ + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + }, + ops_not_after_pass=[ + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default" + ], + pass_list=[RemoveNoopPass], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_replace_inf_values_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_replace_inf_values_pass.py new file mode 100644 index 0000000..d079058 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_replace_inf_values_pass.py @@ -0,0 +1,96 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm._passes.replace_inf_and_limit_values_pass import ( + ReplaceInfAndLimitValuesPass, +) + +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from torch import fx + + +class ModuleWithInf(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.register_buffer( + "mask", torch.tensor([float("inf"), float("-inf")], dtype=torch.float32) + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = x + self.mask # type: ignore[operator] + x = torch.ops.aten.add.Tensor(x, float("-inf")) + x = torch.ops.aten.add.Tensor(x, float("inf")) + return x + + +def _get_add_constants(module_with_infinf: fx.GraphModule) -> list[float]: + """ + Return the scalar literals passed to `aten.add.Tensor`, skipping tensor inputs. + """ + return [ + node.args[1] + for node in module_with_infinf.graph.nodes + if node.op == "call_function" + and node.target == torch.ops.aten.add.Tensor + and len(node.args) > 1 + and not isinstance(node.args[1], fx.Node) + ] + + +def _get_mask_buffer(graph_module: fx.GraphModule) -> torch.Tensor: + """ + Fetch the `mask` buffer tensor from the traced module. + """ + buffers = dict(graph_module.named_buffers()) + assert "mask" in buffers, "Mask buffer not found" + return buffers["mask"] + + +def test_replace_inf_values_pass_clamps_inf_constants(): + """ + Trace a module with infinities, run ReplaceInfAndLimitValuesPass, and expect the buffer and scalar + literals to be clamped to ±255 with no infinities left. + """ + gm = fx.symbolic_trace(ModuleWithInf()) + + result = ReplaceInfAndLimitValuesPass().call(gm) + mask_after_pass = _get_mask_buffer(result.graph_module) + + assert result.modified + expected = torch.tensor([255.0, -255.0], dtype=mask_after_pass.dtype) + assert torch.equal(mask_after_pass, expected) + assert not torch.isinf(mask_after_pass).any() + assert sorted(_get_add_constants(result.graph_module)) == [-255, 255] + + +def test_replace_inf_values_respects_disallowed_nodes(): + """ + When nodes opt out of transforms, running the pass in TFA mode should leave the mask buffer + untouched while still clamping scalar literals to ±255. + """ + gm = fx.symbolic_trace(ModuleWithInf()) + mask_before = _get_mask_buffer(gm).clone() + + for node in gm.graph.nodes: + if node.op != "call_function": + continue + + if any( + isinstance(arg, fx.Node) and arg.op == "get_attr" and arg.target == "mask" + for arg in node.args + ): + node.meta[DISALLOW_TFA_META_KEY] = True + + replace_inf = ReplaceInfAndLimitValuesPass() + replace_inf.is_tfa_pass = True + + result = replace_inf.call(gm) + assert result.modified + + mask_after = _get_mask_buffer(result.graph_module) + assert torch.equal(mask_after, mask_before) + assert torch.isinf(mask_after).tolist() == [True, True] + assert sorted(_get_add_constants(result.graph_module)) == [-255, 255] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rescale_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rescale_pass.py new file mode 100644 index 0000000..7d2e596 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rescale_pass.py @@ -0,0 +1,81 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Tuple + +import torch +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.test_pipeline import ( + EthosU55PipelineINT, + EthosU85PipelineINT, + TosaPipelineINT, +) + +input_t = Tuple[torch.Tensor, torch.Tensor] # Input x + + +class RescaleNetwork(torch.nn.Module): + test_data = { + "rand": (torch.rand(5), torch.rand(5)), + "randn": (torch.randn(5, 2), torch.randn(5, 1)), + "ones": (torch.ones(1, 10, 4, 6), torch.ones(1, 10, 4, 6)), + "randn_ones": (torch.randn(1, 1, 4, 4), torch.ones(1, 1, 4, 1)), + "randn_large": (10000 * torch.randn(1, 1, 4, 4), torch.randn(1, 1, 4, 1)), + } + + def forward(self, x: torch.Tensor, y: torch.Tensor): + a = y.exp() + g = (a + 5).log() + c = a + x + d = c - g + e = c * d + f = e.sigmoid() + + return f + + +@common.parametrize("test_data", RescaleNetwork.test_data) +def test_insert_rescale_tosa_INT(test_data: tuple[torch.Tensor, torch.Tensor]): + """Tests a model with many ops that requires rescales. As more ops are quantized to int32 and + need the InsertRescalesPass, make sure that they play nicely together.""" + module = RescaleNetwork() + pipeline = TosaPipelineINT( + module=module, + test_data=test_data, + aten_op=[], + exir_op=[], + ) + if not conftest.is_option_enabled("tosa_ref_model"): + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + +@common.parametrize("test_data", RescaleNetwork.test_data) +@common.XfailIfNoCorstone300 +def test_insert_rescale_u55_INT(test_data: input_t): + """Tests a model with many ops that requires rescales. As more ops are quantized to int32 and + need the InsertRescalesPass, make sure that they play nicely together.""" + module = RescaleNetwork() + pipeline = EthosU55PipelineINT( + module=module, + test_data=test_data, + aten_ops=[], + exir_ops=[], + ) + pipeline.run() + + +@common.parametrize("test_data", RescaleNetwork.test_data) +@common.XfailIfNoCorstone320 +def test_insert_rescale_u85_INT(test_data: input_t): + """Tests a model with many ops that requires rescales. As more ops are quantized to int32 and + need the InsertRescalesPass, make sure that they play nicely together.""" + module = RescaleNetwork() + pipeline = EthosU85PipelineINT( + module=module, + test_data=test_data, + aten_ops=[], + exir_ops=[], + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rewrite_conv_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rewrite_conv_pass.py new file mode 100644 index 0000000..d59dbc9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_rewrite_conv_pass.py @@ -0,0 +1,20 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm._passes.rewrite_conv_pass import RewriteConvPass +from executorch.backends.arm.test.misc.test_dw_convs_with_shared_weights import ( + DWConvsModule, +) +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + + +def test_rewrite_conv_tosa_FP(): + module = DWConvsModule() + pipeline = PassPipeline( + module, module.get_inputs(), passes_with_exported_program=[RewriteConvPass] + ) + # We can't run TOSA backend dialect operators in eager mode + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_to_tosa_memory_format.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_to_tosa_memory_format.py new file mode 100644 index 0000000..486a906 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_to_tosa_memory_format.py @@ -0,0 +1,213 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import cast, Dict, List, Protocol, Tuple + +import torch +from executorch.backends.arm._passes import ( + AnnotateOutputDimOrderPass, + ToTosaMemoryFormatPass, +) + +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import ( + PassPipeline, + TosaPipelineINT, +) +from executorch.backends.transforms.remove_getitem_op import RemoveGetItemPass + +input_t = Tuple[torch.Tensor] # Input x + + +class ModuleMetadata(Protocol): + ops_before_pass: Dict[str, int] + ops_after_pass: Dict[str, int] + ops_not_after_pass: List[str] + + def get_inputs(self) -> input_t: ... + + +class NoNHWC(torch.nn.Module): + """ + Test-module with no ops requiring NHWC mermory format. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 2 + } + ops_not_after_pass: List[str] = [] + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = x + x + return x + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 2, 2),) + + +class ParallelClusters(torch.nn.Module): + """ + Test-module with multiple parallel clusters of nodes requiring different memory formats. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 2 + } + ops_not_after_pass: List[str] = [] + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d( + in_channels=2, + out_channels=2, + kernel_size=1, + bias=True, + ) + self.maxpool = torch.nn.MaxPool2d(1, 1) + self.avgpool = torch.nn.AvgPool2d(1, 1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x1 = self.conv(x) + x2 = self.maxpool(x) + x3 = self.avgpool(x) + x4 = x * x + return x1 + x2 + x3 + x4 + + def get_inputs(self) -> input_t: + return (torch.rand(1, 2, 2, 2),) + + +class SerialClusters(torch.nn.Module): + """ + Test-module with multiple serial clusters of nodes requring different memory formats. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 4 + } + ops_not_after_pass: List[str] = [] + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d( + in_channels=2, + out_channels=2, + kernel_size=1, + bias=True, + ) + self.fc = torch.nn.Linear( + in_features=2, + out_features=2, + bias=True, + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.conv(x) + x = x * x + x = self.conv(x) + x = x.view((2, 1, 2, 4)) + x = x * 2 + x = x.view((2, 2, 2, 2)) + x = self.conv(x) + return x + + def get_inputs(self) -> input_t: + return (torch.rand(2, 2, 2, 2),) + + +class Reshapes(torch.nn.Module): + """ + Test-module with different configurations of views requiring different memory formats. + """ + + ops_before_pass: Dict[str, int] = {} + ops_after_pass: Dict[str, int] = { + "executorch_exir_dialects_backend__ops_tosa_TRANSPOSE_default": 16 + } + ops_not_after_pass: List[str] = [] + + def __init__(self): + super().__init__() + self.maxpool = torch.nn.MaxPool2d(1, 1) # Use maxpool to force NHWC format + + def forward(self, x: torch.Tensor) -> torch.Tensor: + + x = self.maxpool(x) + x = x.view((2, 2, 4, 16, 1)) # N-C-HW-invariant intact, no transposes needed + x = x * 2 # Add op to avoid views merging + x = x.view((4, 4, 4, 4)) + x = x / 2 # Add op to avoid views merging + x = self.maxpool(x) + + x = x.view((256)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((16, 16)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((16, 4, 4)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((2, 4, 4, 8)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = x / 2 + x = self.maxpool(x) + + x = x.view((8, 1, 2, 4, 4)) # Break N-C-HW invariant + x = x * 2 + x = x.view((4, 4, 4, 4)) + x = self.maxpool(x) + + return x + + def get_inputs(self) -> input_t: + return (torch.rand(4, 4, 4, 4),) + + +modules: Dict[str, ModuleMetadata] = { + "no_nhwc": NoNHWC(), + "parallel_clusters": ParallelClusters(), + "serial_clusters": SerialClusters(), + "reshapes": Reshapes(), +} + + +@common.parametrize("module", modules) +def test_to_tosa_memory_format_tosa_INT(module: ModuleMetadata) -> None: + # We cannot check op counts after a specific pass with the full pipeline + module_nn = cast(torch.nn.Module, module) + pipeline = PassPipeline[input_t]( + module_nn, + module.get_inputs(), + ops_after_pass=module.ops_after_pass, + ops_not_after_pass=module.ops_not_after_pass, + pass_list=[RemoveGetItemPass, AnnotateOutputDimOrderPass], + passes_with_exported_program=[ToTosaMemoryFormatPass], + ) + pipeline.pop_stage( + "run_method_and_compare_outputs" + ) # Eager execution is not possible after introducing tosa.TRANSPOSE + pipeline.run() + + +@common.parametrize("module", modules) +def test_to_tosa_memory_format_tosa_INT_functional(module: ModuleMetadata) -> None: + # Also run the actual pass pipeline to ensure functional correctness. + module_nn = cast(torch.nn.Module, module) + pipeline = TosaPipelineINT[input_t](module_nn, module.get_inputs(), []) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py new file mode 100644 index 0000000..f6ff8b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/passes/test_unsqueeze_before_repeat_pass.py @@ -0,0 +1,62 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Tuple + +import torch +from executorch.backends.arm._passes import UnsqueezeBeforeRepeatPass +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import PassPipeline + +pipeline_input_t = Tuple[torch.Tensor, ...] +test_case_t = Tuple[ + pipeline_input_t, + Dict[str, int], + List[str], +] + + +class Repeat(torch.nn.Module): + """ + Basic repeat model. + """ + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.repeat(2, 2, 2, 2) + + test_data: Dict[str, test_case_t] = { + "insert_view": ( + (torch.rand((2, 3, 4)),), + {"aten_repeat_default": 3, "aten_view_copy_default": 4}, + [], + ), + "dont_insert_view": ( + (torch.rand((2, 3, 4, 1)),), + {"aten_repeat_default": 3}, + ["aten_view_copy_default"], + ), + } + + +@common.parametrize("test_data", Repeat.test_data) +def test_unsqueeze_before_repeat_tosa_FP(test_data: test_case_t): + """ + When rank(input) != number of repeated dimensions (=4 in Repeat module), + insert view. + """ + module = Repeat() + data, ops_after_pass, ops_not_after_pass = test_data + pipeline = PassPipeline[pipeline_input_t]( + module, + data, + quantize=False, + ops_before_pass={"aten_repeat_default": 3}, + ops_not_before_pass=["aten_view_copy_default"], + ops_after_pass=ops_after_pass, + ops_not_after_pass=ops_not_after_pass, + pass_list=[UnsqueezeBeforeRepeatPass], + ) + pipeline.pop_stage(-1) # Do not compare output + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/pytest.ini b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/pytest.ini new file mode 100644 index 0000000..8d25e4c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +addopts = --strict-markers +markers = + slow: Tests that take long time + tosa_ref_model: Tests that use TOSA reference model # Temporary! diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_conv_relu_fusing.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_conv_relu_fusing.py new file mode 100644 index 0000000..83179c1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_conv_relu_fusing.py @@ -0,0 +1,118 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.quantizer.quantization_config import ( + QuantizationConfig, + QuantizationSpec, +) +from executorch.backends.arm.test.tester.test_pipeline import QuantizationPipeline +from executorch.backends.arm.tosa import TosaSpecification + + +def get_symmetric_a8w8_quantization_config(): + affine_quant_config = get_symmetric_quantization_config() + output_activation = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=affine_quant_config.get_output_act_qspec().observer_or_fake_quant_ctr, + quant_min=-127, + quant_max=127, + qscheme=torch.per_tensor_symmetric, + ch_axis=None, + is_dynamic=False, + ) + input_activation = output_activation + symmetric_quant_config = QuantizationConfig( + input_activation=input_activation, + output_activation=output_activation, + weight=affine_quant_config.get_weight_qspec(), + bias=None, + ) + return symmetric_quant_config + + +class ConvBNRelu(torch.nn.Module): + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d( + in_channels=3, + out_channels=4, + kernel_size=2, + ) + self.bn = torch.nn.BatchNorm2d(num_features=4) + self.relu = torch.nn.ReLU() + + def forward(self, x): + conv = self.conv(x) + bn = self.bn(conv) + relu = self.relu(bn) + return relu + + def get_example_inputs(self): + return (torch.randn(1, 3, 8, 8),) + + +def test_conv_relu_fusing_8a8w_tosa_INT_affine(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + quant_config = get_symmetric_quantization_config() + quantizer.set_global(quant_config) + expected_annotations = { + "aten.conv2d.default": {None: 1}, + "aten.relu.default": {quant_config.get_output_act_qspec(): 1}, + } + pipeline = QuantizationPipeline[Tuple[torch.Tensor]]( + ConvBNRelu(), + ConvBNRelu().get_example_inputs(), + quantizer=quantizer, + qspecs=expected_annotations, + ) + pipeline.run() + + +def test_conv_relu_fusing_8a8w_tosa_INT_symmetric(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + symmetric_quant_config = get_symmetric_a8w8_quantization_config() + + quantizer.set_global(symmetric_quant_config) + expected_annotations = { + "aten.conv2d.default": {symmetric_quant_config.get_output_act_qspec(): 1}, + "aten.relu.default": {symmetric_quant_config.get_output_act_qspec(): 1}, + } + pipeline = QuantizationPipeline[Tuple[torch.Tensor]]( + ConvBNRelu(), + ConvBNRelu().get_example_inputs(), + quantizer=quantizer, + qspecs=expected_annotations, + ) + pipeline.run() + + +def test_conv_relu_fusing_16a8w_tosa_INT_symmetric(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT+int16") + quantizer = TOSAQuantizer(tosa_spec) + quant_config = get_symmetric_a16w8_quantization_config() + + quantizer.set_global(quant_config) + expected_annotations = { + "aten.conv2d.default": {quant_config.get_output_act_qspec(): 1}, + "aten.relu.default": {quant_config.get_output_act_qspec(): 1}, + } + pipeline = QuantizationPipeline[Tuple[torch.Tensor]]( + ConvBNRelu(), + ConvBNRelu().get_example_inputs(), + quantizer=quantizer, + qspecs=expected_annotations, + ) + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_generic_annotater.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_generic_annotater.py new file mode 100644 index 0000000..dd883e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_generic_annotater.py @@ -0,0 +1,109 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +import itertools + +from typing import Any, Callable, Tuple + +import torch +from executorch.backends.arm.quantizer import is_annotated +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT +from executorch.backends.test.harness.stages import StageType + +from torch.fx.passes.utils.source_matcher_utils import get_source_partitions + + +input_t1 = Tuple[torch.Tensor] # Input x + + +class SingleOpModel(torch.nn.Module): + def __init__( + self, + op: Callable[..., torch.Tensor], + example_input: Tuple[Any, ...], + **op_kwargs: Any, + ) -> None: + super().__init__() + self.op: Callable[..., torch.Tensor] = op + self._example_input: Tuple[Any, ...] = example_input + self.op_kwargs: dict[str, Any] = dict(op_kwargs) + + def forward(self, x: Any) -> torch.Tensor: + return self.op(x, **self.op_kwargs) + + def example_inputs(self) -> Tuple[Any, ...]: + return self._example_input + + +def check_annotation(model: SingleOpModel) -> None: + pipeline = TosaPipelineINT[input_t1](model, model.example_inputs(), [], []) + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + artifact = pipeline.tester.get_artifact(StageType.QUANTIZE) + + partitions = get_source_partitions(artifact.graph, [model.op]) + partitions = list(itertools.chain.from_iterable(partitions.values())) + + assert len(partitions) == 1 + partition = partitions[0] + assert all(is_annotated(node) for node in partition.nodes) + + +def test_squeeze_tosa_INT(): + check_annotation(SingleOpModel(torch.squeeze, (torch.rand(8, 8, 1),))) + check_annotation(SingleOpModel(torch.squeeze_copy, (torch.rand(8, 8, 1),))) + + +def test_unsqueeze_tosa_INT(): + check_annotation(SingleOpModel(torch.unsqueeze, (torch.rand(8, 8),), dim=0)) + check_annotation(SingleOpModel(torch.unsqueeze_copy, (torch.rand(8, 8),), dim=0)) + + +def test_reshape_tosa_INT(): + check_annotation( + SingleOpModel(torch.reshape, (torch.randn(8, 8),), shape=(64,)), + ) + + +def test_view_tosa_INT(): + check_annotation( + SingleOpModel(torch.view_copy, (torch.randn(4, 4),), size=(2, 8)), + ) + + +def test_slice_tosa_INT(): + check_annotation( + SingleOpModel(torch.slice_copy, (torch.randn(3, 4),)), + ) + + +def test_transpose_tosa_INT(): + check_annotation( + SingleOpModel(torch.transpose, (torch.randn(2, 3),), dim0=0, dim1=1), + ) + check_annotation( + SingleOpModel(torch.transpose_copy, (torch.randn(2, 3),), dim0=0, dim1=1), + ) + + +def test_tile_tosa_INT(): + check_annotation( + SingleOpModel(torch.tile, (torch.randn(4, 4),), dims=(2,)), + ) + + +def test_flip_tosa_INT(): + check_annotation( + SingleOpModel(torch.flip, (torch.randn(2, 4),), dims=(0, 1)), + ) + + +def test_concat_tosa_INT(): + check_annotation( + SingleOpModel( + torch.concatenate, ((torch.randn(2, 3), torch.randn(2, 3)),), dim=0 + ), + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_partial_quantization.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_partial_quantization.py new file mode 100644 index 0000000..43393c9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_partial_quantization.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from collections.abc import Iterable + +import torch +import torch.fx + +from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY +from executorch.backends.arm.test.tester.test_pipeline import TosaPipelineINT +from executorch.backends.test.harness.stages import StageType + + +def _collect_disallow_flags(graph: torch.fx.Graph) -> dict[str, bool | None]: + flags: dict[str, bool | None] = {} + for node in graph.nodes: + if DISALLOW_TFA_META_KEY in node.meta: + flags[node.name] = node.meta[DISALLOW_TFA_META_KEY] + return flags + + +def _run_quantization_pipeline( + module: torch.nn.Module, + unquantized_submodules: Iterable[type[torch.nn.Module]], +) -> torch.fx.Graph: + """Run the Arm TOSA quantization pipeline for ``module`` while keeping the + specified submodules in floating-point. + """ + pipeline = TosaPipelineINT[tuple[torch.Tensor]]( + module, + module.example_inputs(), # type: ignore[operator] + [], + [], + ) + + quant_stage = pipeline._stages[0].args[0] + for mod in unquantized_submodules: + quant_stage.quantizer.set_module_type(mod, None) + + pipeline.pop_stage("check_count.exir") + pipeline.pop_stage("run_method_and_compare_outputs") + pipeline.run() + + return pipeline.tester.get_artifact(StageType.QUANTIZE).graph + + +def test_disallow_tfa_for_skipped_module(): + """Ensure a softmax skipped for quantization is not decomposed and that its + node has `disallow_tfa` set.""" + + class TwoOpModel(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.softmax = torch.nn.Softmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.softmax(x) + 1 + + def example_inputs(self) -> tuple[torch.Tensor, ...]: + return (torch.randn(2, 3),) + + graph_after_quant_stage = _run_quantization_pipeline( + TwoOpModel(), [torch.nn.Softmax] + ) + + flags = _collect_disallow_flags(graph_after_quant_stage) + + assert flags.get("x") is False, "'x' should not be disallowed for TFA" + assert flags.get("softmax") is True, "'softmax' should be disallowed for TFA" + assert flags.get("add") is False, "'add' should not be disallowed for TFA" + assert flags.get("output") is False, "'output' should not be disallowed for TFA" + + +def test_disallow_tfa_for_two_skipped_modules(): + class LinearSoftmaxModel(torch.nn.Module): + def __init__(self) -> None: + super().__init__() + self.linear = torch.nn.Linear(10, 10) + self.softmax = torch.nn.Softmax(dim=1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.linear(x) + x = torch.abs(x) + x = self.softmax(x) + return x + 1 + + def example_inputs(self) -> tuple[torch.Tensor, ...]: + return (torch.randn(1, 10),) + + graph_after_quant_stage = _run_quantization_pipeline( + LinearSoftmaxModel(), + [torch.nn.Linear, torch.nn.Softmax], + ) + + flags = _collect_disallow_flags(graph_after_quant_stage) + + assert flags.get("x") is False, "'x' should not be disallowed for TFA" + assert flags.get("linear") is True, "'linear' should be disallowed for TFA" + assert flags.get("softmax") is True, "'softmax' should be disallowed for TFA" + assert flags.get("add") is False, "'add' should not be disallowed for TFA" + assert flags.get("abs_1") is False, "'abs_1' should not be disallowed for TFA" + assert flags.get("output") is False, "'output' should not be disallowed for TFA" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_selective_quantization.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_selective_quantization.py new file mode 100644 index 0000000..ae8892f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_selective_quantization.py @@ -0,0 +1,212 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Dict + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, +) +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from executorch.backends.arm.test import common +from executorch.backends.arm.test.tester.test_pipeline import QuantizationPipeline +from executorch.backends.arm.tosa import TosaSpecification +from torchvision import models, transforms # type: ignore[import-untyped] +from torchvision.ops.misc import Conv2dNormActivation # type: ignore[import-untyped] + + +def get_quantizer(): + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + quantizer.set_global(get_symmetric_quantization_config()) + return quantizer + + +def get_selective_quantizer_by_module( + module_types: Dict[torch.nn.Module, QuantizationConfig] +): + quantizer = get_quantizer() + quantizer.set_global(get_symmetric_quantization_config()) + for module_type, config in module_types.items(): + quantizer.set_module_type(module_type, config) + + return quantizer + + +def get_selective_quantizer_by_module_name(module_names: Dict[str, QuantizationConfig]): + quantizer = get_quantizer() + quantizer.set_global(get_symmetric_quantization_config()) + for module_name, config in module_names.items(): + quantizer.set_module_name(module_name, config) + + return quantizer + + +class Add(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return x + y + + +class AddSoftmaxAdd(torch.nn.Module): + module_names = {"add_0": None, "add_1": None} + module_types = { + Add: None, + } + quantized_aten_targets = {"aten.relu.default": 1} + non_quantized_aten_targets = {"aten.add.Tensor": 2} + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.softmax = torch.nn.Softmax(dim=-1) + self.relu = torch.nn.ReLU() + self.add_0 = Add() + self.add_1 = Add() + + def get_inputs(self): + return (torch.randn(1, 10), torch.randn(1, 10)) + + def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + z = self.add_0(x, y) + z = self.relu(z) + z = self.softmax(z) + return self.add_1(z, y) + + +test_models = { + "add_softmax_add": AddSoftmaxAdd, +} + + +@common.parametrize("model", test_models) +def test_selective_quant_module_name_tosa_INT(model): + model = model() + inputs = model.get_inputs() + quantzed_aten_targets = model.quantized_aten_targets + non_quantized_aten_targets = model.non_quantized_aten_targets + quantization_annotations = {} + for target, count in quantzed_aten_targets.items(): + quantization_annotations[target] = { + get_symmetric_quantization_config().output_activation: count + } + for target, count in non_quantized_aten_targets.items(): + quantization_annotations[target] = {None: count} + + pipeline = QuantizationPipeline[tuple[torch.Tensor, torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module_name(model.module_names), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +@common.parametrize("model", test_models) +def test_selective_quant_module_type_tosa_INT(model): + model = model() + inputs = model.get_inputs() + quantzed_aten_targets = model.quantized_aten_targets + non_quantized_aten_targets = model.non_quantized_aten_targets + quantization_annotations = {} + for target, count in quantzed_aten_targets.items(): + quantization_annotations[target] = { + get_symmetric_quantization_config().output_activation: count + } + for target, count in non_quantized_aten_targets.items(): + quantization_annotations[target] = {None: count} + + pipeline = QuantizationPipeline[tuple[torch.Tensor, torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module(model.module_types), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +mv3 = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights) +mv3.eval() +normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + + +def test_mv3_selective_quant_int16_tosa_INT(): + model = mv3 + inputs = (normalize(torch.randn(1, 3, 224, 224)),) + + a16w8_config = get_symmetric_a16w8_quantization_config() + quantization_annotations = { + "aten.conv2d.default": { + a16w8_config.output_activation: 34, + }, + "aten.hardswish_.default": { + a16w8_config.output_activation: 18, + }, + "aten.relu_.default": { + a16w8_config.output_activation: 5, + }, + } + + pipeline = QuantizationPipeline[tuple[torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module( + { + Conv2dNormActivation: a16w8_config, + } + ), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +def test_mv3_selective_quant_float32_tosa_INT(): + model = mv3 + inputs = (normalize(torch.randn(1, 3, 224, 224)),) + + quantization_annotations = { + "aten.adaptive_avg_pool2d.default": { + None: 1, + }, + } + + pipeline = QuantizationPipeline[tuple[torch.Tensor]]( + model, + inputs, + quantizer=get_selective_quantizer_by_module_name( + { + "features.11.block.2.avgpool": None, + } + ), + qspecs=quantization_annotations, + ) + + pipeline.run() + + +def test_mv3_io_quant_tosa_INT(): + model = mv3 + inputs = (normalize(torch.randn(1, 3, 224, 224)),) + + quantizer = get_quantizer() + # Workaround to disable quantization for all modules + quantizer.set_module_type(torch.nn.Module, None) + # Only quantize IO + quantizer.set_io(get_symmetric_quantization_config()) + + pipeline = QuantizationPipeline[tuple[torch.Tensor]]( + model, + inputs, + quantizer=quantizer, + input_qspecs={get_symmetric_quantization_config().input_activation: 1}, + output_qspecs={get_symmetric_quantization_config().output_activation: 1}, + ) + + pipeline.run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_set_module_name.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_set_module_name.py new file mode 100644 index 0000000..d0ca781 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_set_module_name.py @@ -0,0 +1,158 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.quantizer import ( + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + is_annotated, + QuantizationConfig, + TOSAQuantizer, +) +from executorch.backends.arm.quantizer.quantization_config import QuantizationSpec +from executorch.backends.arm.tosa import TosaSpecification +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + +DQ_PER_CHANNEL = torch.ops.quantized_decomposed.dequantize_per_channel.default +DQ_PER_TENSOR = torch.ops.quantized_decomposed.dequantize_per_tensor.default +Q_PER_TENSOR = torch.ops.quantized_decomposed.quantize_per_tensor.default + + +class ConvModel(torch.nn.Module): + def __init__(self): + super().__init__() + self.conv0 = torch.nn.Conv2d( + 3, + 16, + kernel_size=4, + ) + self.conv1 = torch.nn.Conv2d(16, 32, kernel_size=3, bias=False) + self.conv2 = torch.nn.Conv2d(32, 64, kernel_size=3) + + def forward(self, x): + x = self.conv0(x) + x = torch.sigmoid(x) + x = self.conv1(x) + x = torch.tanh(x) + x = self.conv2(x) + return x + + +test_inputs = (torch.randn(1, 3, 64, 64),) + + +def validate_per_tensor_quant(node: torch.fx.Node, qspec: QuantizationSpec): + _, _, zero_point, qmin, qmax, dtype = node.args + if qspec.qscheme == torch.per_tensor_symmetric: + assert ( + zero_point == 0 + ), f"Zero point {zero_point} is not zero for symmetric quantization" + assert ( + qmin == qspec.quant_min + ), f"Quant min {qmin} does not match expected {qspec.quant_min}" + assert ( + qmax == qspec.quant_max + ), f"Quant max {qmax} does not match expected {qspec.quant_max}" + assert dtype == qspec.dtype, f"Dtype {dtype} does not match expected {qspec.dtype}" + + +def validate_per_channel_quant(node: torch.fx.Node, qspec: QuantizationSpec): + _, _, _, channel_axis, qmin, qmax, dtype = node.args + assert ( + channel_axis == qspec.ch_axis + ), f"Channel axis {channel_axis} does not match expected {qspec.ch_axis}" + assert ( + qmin == qspec.quant_min + ), f"Quant min {qmin} does not match expected {qspec.quant_min}" + assert ( + qmax == qspec.quant_max + ), f"Quant max {qmax} does not match expected {qspec.quant_max}" + assert dtype == qspec.dtype, f"Dtype {dtype} does not match expected {qspec.dtype}" + + +def validate_input(input_node: torch.fx.Node, qspec: QuantizationSpec | None): + if qspec is None: + return + + per_channel = qspec.qscheme == torch.per_channel_symmetric + expected_dequant_op = DQ_PER_CHANNEL if per_channel else DQ_PER_TENSOR + assert ( + input_node.target == expected_dequant_op + ), f"Input node {input_node} is not quantized as expected" + if per_channel: + validate_per_channel_quant(input_node, qspec) + else: + validate_per_tensor_quant(input_node, qspec) + + +def validate_output(node: torch.fx.Node, qspec: QuantizationSpec | None): + if qspec is None: + return + users = list(node.users) + assert len(users) == 1, f"Node {node} should have exactly one user" + assert ( + users[0].target == Q_PER_TENSOR + ), f"Output node {users[0]} is not quantized as expected" + validate_per_tensor_quant(users[0], qspec) + + +def validate_node( + node: torch.fx.Node, quantization_config: QuantizationConfig | None +) -> None: + if quantization_config is None: + assert not is_annotated(node), f"Node {node} is unexpectedly annotated" + return + + assert is_annotated(node), f"Node {node} is not annotated" + input_qspec = quantization_config.get_input_act_qspec() + output_qspec = quantization_config.get_output_act_qspec() + weight_qspec = quantization_config.get_weight_qspec() + + if len(node.all_input_nodes) == 3: + input_node, weight_node, bias_node = node.all_input_nodes + bias_qspec = quantization_config.get_bias_qspec(node) + validate_input(bias_node, bias_qspec) + else: + input_node, weight_node = node.all_input_nodes + + validate_input(input_node, input_qspec) + validate_input(weight_node, weight_qspec) + validate_output(node, output_qspec) + + +def test_set_module_name_tosa_INT() -> None: + model = ConvModel() + model.eval() + + # Set up quantizer with different configs for different modules + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+INT") + quantizer = TOSAQuantizer(tosa_spec) + int8_config = get_symmetric_quantization_config(is_per_channel=False) + a16w8_config = get_symmetric_a16w8_quantization_config() + # Set module-specific configurations but don't set global config to test that + # only specified modules are quantized + quantizer.set_module_name("conv0", int8_config) + quantizer.set_module_name("conv1", a16w8_config) + + # Export model + exported_model = torch.export.export(model, test_inputs) + + # Prepare, calibrate and convert model + prepared_model = prepare_pt2e(exported_model.module(), quantizer) + prepared_model(*test_inputs) + converted_model = convert_pt2e(prepared_model) + + validate_node( + [node for node in converted_model.graph.nodes if node.name == "conv2d"][0], + int8_config, + ) + validate_node( + [node for node in converted_model.graph.nodes if node.name == "conv2d_1"][0], + a16w8_config, + ) + validate_node( + [node for node in converted_model.graph.nodes if node.name == "conv2d_2"][0], + None, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_tosa_quantizer_validate.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_tosa_quantizer_validate.py new file mode 100644 index 0000000..081e9ec --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/quantizer/test_tosa_quantizer_validate.py @@ -0,0 +1,55 @@ +# Copyright 2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch + +from executorch.backends.arm.quantizer import TOSAQuantizer +from executorch.backends.arm.tosa import TosaSpecification +from torch.fx import symbolic_trace + + +def _annotate_placeholders_with_devices(gm, device_map): + for node in gm.graph.nodes: + if node.op == "placeholder": + device = device_map[node.target] + node.meta["val"] = torch.empty(1, device=device) + + +def _get_quantizer(): + return TOSAQuantizer(TosaSpecification.create_from_string("TOSA-1.0+INT")) + + +class TwoIndependentAdds(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x + 1, y + 1 + + +class CrossDeviceAdd(torch.nn.Module): + + def forward(self, x: torch.Tensor, y: torch.Tensor): + return x + y + + +def test_validate_allows_different_devices_across_operators(): + gm = symbolic_trace(TwoIndependentAdds()) + _annotate_placeholders_with_devices( + gm, {"x": torch.device("cpu"), "y": torch.device("meta")} + ) + + quantizer = _get_quantizer() + quantizer.validate(gm) + + +def test_validate_rejects_mixed_devices_within_operator(): + gm = symbolic_trace(CrossDeviceAdd()) + _annotate_placeholders_with_devices( + gm, {"x": torch.device("cpu"), "y": torch.device("meta")} + ) + + quantizer = _get_quantizer() + with pytest.raises(ValueError, match="Quantizer detected operator"): + quantizer.validate(gm) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/runner_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/runner_utils.py new file mode 100644 index 0000000..44e9e75 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/runner_utils.py @@ -0,0 +1,840 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import importlib.resources as _resources +import json +import logging +import os +import re +import shutil +import subprocess # nosec B404 - invoked only for trusted toolchain binaries +import tempfile +from pathlib import Path + +from types import NoneType +from typing import Any, cast, Dict, List, Optional, Tuple + +import executorch.backends.arm.test as arm_test_package +import executorch.backends.arm.tosa.schemas as tosa_schemas_package + +import numpy as np +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.constants import ( + NHWC_INVERSE_ORDER, + NHWC_ORDER, + NNHWC_INVERSE_ORDER, + NNHWC_ORDER, +) + +from executorch.backends.arm.ethosu import EthosUCompileSpec +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.specification import Tosa_1_00, TosaSpecification +from executorch.backends.arm.vgf import VgfCompileSpec +from executorch.backends.arm.vgf.model_converter import find_model_converter_binary +from executorch.exir import ExecutorchProgramManager, ExportedProgram +from executorch.exir.lowered_backend_module import LoweredBackendModule +from torch.fx.node import Node + +from torch.overrides import TorchFunctionMode +from tosa.TosaGraph import TosaGraph # type: ignore[import-not-found, import-untyped] + +logger = logging.getLogger(__name__) + +# Copied from PyTorch. +# From torch/testing/_internal/common_utils.py:torch_to_numpy_dtype_dict +# To avoid a dependency on _internal stuff. +_torch_to_numpy_dtype_dict = { + torch.bool: np.bool_, + torch.uint8: np.uint8, + torch.uint16: np.uint16, + torch.uint32: np.uint32, + torch.uint64: np.uint64, + torch.int8: np.int8, + torch.int16: np.int16, + torch.int32: np.int32, + torch.int64: np.int64, + torch.float16: np.float16, + torch.float32: np.float32, + torch.float64: np.float64, + torch.bfloat16: np.float32, + torch.complex32: np.complex64, + torch.complex64: np.complex64, + torch.complex128: np.complex128, +} + +VALID_TARGET = {"corstone-300", "corstone-320", "vkml_emulation_layer"} + + +class QuantizationParams: + __slots__ = ["node_name", "zp", "scale", "qmin", "qmax", "dtype"] + + # todo: zps and scales can be per tensors or per channel => a list?? + def __init__( + self, + node_name: str, + zp: int, + scale: float, + qmin: int, + qmax: int, + dtype: torch.dtype, + ): + self.node_name = node_name # not need I think, but good for error check + self.zp = zp + self.scale = scale + self.qmin = qmin + self.qmax = qmax + self.dtype = dtype + + +def get_input_names(program: ExportedProgram) -> list[str]: + """ + Get a list[str] with the names of the inputs to this model. + + Args: + program (ExportedProgram): The program to get input names from. + Returns: + A list of strings with the names of the model input. + """ + return [spec.arg.name for spec in program.graph_signature.input_specs] + + +def get_input_quantization_params( + program: ExportedProgram, +) -> list[QuantizationParams]: + """ + Get input QuantizationParams in a program, maximum one per input to the program. + Args: + program (ExportedProgram): The program to get input quantization parameters from. + Returns: + list[QuantizationParams]: The found quantization parameters. + """ + + quant_params = [] + input_names = get_input_names(program) + num_inputs = len(input_names) + for node in program.graph.nodes: + if ( + node.target == torch.ops.quantized_decomposed.quantize_per_tensor.default + and node.args[0].name in input_names + ): + qp = QuantizationParams( + node_name=node.args[0].name, + scale=node.args[1], + zp=node.args[2], + qmin=node.args[3], + qmax=node.args[4], + dtype=node.args[5], + ) + quant_params.append(qp) + if ( + len(quant_params) == num_inputs + ): # break early if we have all the inputs quantized parameters + break + if len(quant_params) == 0: + logger.warning("No input quantization parameters found in exported model.") + return quant_params + + +def get_output_quantization_params( + output_node: Node, +) -> dict[Node, QuantizationParams | None]: + """ + Get output QuantizationParams from a program. + Args: + output_nodes (list(Node)): A list of output nodes to get output quantization parameters from. + Returns: + dictionary mapping the output nodes to the found quantization parameters. + If no quantization parameters were found, the entry is None. + Raises: + RuntimeError if no output quantization parameters are found. + """ + quant_params: dict[Node, QuantizationParams | None] = {} + for node in output_node.args[0]: # type: ignore[union-attr] + if ( + node.target # type: ignore[union-attr] + == torch.ops.quantized_decomposed.dequantize_per_tensor.default + ): + quant_params[node] = QuantizationParams( # type: ignore[index] + node_name=node.args[0].name, # type: ignore[arg-type, union-attr] + scale=node.args[1], # type: ignore[arg-type, union-attr] + zp=node.args[2], # type: ignore[arg-type, union-attr] + qmin=node.args[3], # type: ignore[arg-type, union-attr] + qmax=node.args[4], # type: ignore[arg-type, union-attr] + dtype=node.args[5], # type: ignore[arg-type, union-attr] + ) + else: + quant_params[node] = None # type: ignore[index] + return quant_params + + +def torch_tensor_to_numpy(tensor: torch.Tensor) -> np.ndarray: + dtype = _torch_to_numpy_dtype_dict[tensor.dtype] + array = tensor.detach().numpy().astype(dtype) # type: ignore[var-annotated] + dim_order = tensor.dim_order() + if dim_order == NHWC_ORDER: + a = array.transpose(NHWC_ORDER) + return a + elif dim_order == NNHWC_ORDER: + return array.transpose(NNHWC_ORDER) + else: + return array + + +def numpy_to_torch_tensor(array: np.ndarray, output_node: Node) -> torch.Tensor: + output_tensor = get_first_fake_tensor(output_node) + shape = output_tensor.shape + dim_order = output_tensor.dim_order() + if dim_order == NHWC_ORDER: + shape_with_dim_order = [shape[i] for i in NHWC_ORDER] + tensor = torch.from_numpy(array).reshape(shape_with_dim_order) + return tensor.permute(NHWC_INVERSE_ORDER).to(memory_format=torch.channels_last) + elif dim_order == NNHWC_ORDER: + shape_with_dim_order = [shape[i] for i in NNHWC_ORDER] + tensor = torch.from_numpy(array).reshape(shape_with_dim_order) + return tensor.permute(NNHWC_INVERSE_ORDER).to(memory_format=torch.channels_last) + else: + tensor = torch.from_numpy(array).reshape(shape) + return tensor + + +class TosaReferenceModelDispatch(TorchFunctionMode): + """A context manager for executing call_delegate nodes using the reference model""" + + def __init__(self): + self.ran_tosa_dispatch = False + super().__init__() + + def _tosa_dispatch(self, lowered_backend_module: LoweredBackendModule, inputs): + tosa_buffer = lowered_backend_module.processed_bytes + compile_spec = TosaCompileSpec.from_list(lowered_backend_module.compile_specs) + + output_node = lowered_backend_module.original_module.graph.output_node() + return run_tosa_graph(tosa_buffer, compile_spec.tosa_spec, inputs, output_node) + + def __exit__(self, exc_type, exc_val, exc_tb): + super().__exit__(exc_type, exc_val, exc_tb) + # Only raise this error if we ran the model without errors. + if not self.ran_tosa_dispatch and exc_type is None: + raise RuntimeError( + "Ran model with TosaReferenceModelDispatch but never ran TOSABackend delegate." + ) + + def __torch_function__(self, func, types, args=..., kwargs=None): + if func is torch._higher_order_ops.executorch_call_delegate: + lowered_backend_module = cast(LoweredBackendModule, args[0]) + if lowered_backend_module.backend_id == "TOSABackend": + self.ran_tosa_dispatch = True + return self._tosa_dispatch(lowered_backend_module, args[1:]) + else: + raise RuntimeError( + f"Ran model with TosaReferenceModelDispatch but call_delegate with {lowered_backend_module.backend_id=} != 'TOSABackend'." + ) + + kwargs = kwargs or {} + + # This is a hack since Q/DQ ops does not handle channels last input correctly: the simplest and most robust + # workaround is to simply run them in channels first format and then convert back to channels last. + if func in ( + torch.ops.quantized_decomposed.quantize_per_tensor.out, + torch.ops.quantized_decomposed.dequantize_per_tensor.out, + torch.ops.quantized_decomposed.quantize_per_channel.out, + torch.ops.quantized_decomposed.dequantize_per_channel.out, + ): + + input_dim_order = args[0].dim_order() + if input_dim_order in (NHWC_ORDER, NNHWC_ORDER): + args = [args[0].to(memory_format=torch.contiguous_format), *args[1:]] + res = func(*args, **kwargs) + return res.to(memory_format=torch.channels_last) + + return func(*args, **kwargs) + + +def run_target( + executorch_program_manager: ExecutorchProgramManager, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, + target_board: str, + elf_path: str | Path, + timeout: int = 120, # s +): + if target_board not in VALID_TARGET: + raise ValueError(f"Unsupported target: {target_board}") + + if target_board == "vkml_emulation_layer": + return run_vkml_emulation_layer( + executorch_program_manager, + inputs, + intermediate_path, + elf_path, + ) + return run_corstone( + executorch_program_manager, + inputs, + intermediate_path, + target_board, + elf_path, + timeout, + ) + + +def save_inputs_to_file( + exported_program: ExportedProgram, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, +): + input_file_paths: list[str] = [] + input_names = get_input_names(exported_program) + for input_name, input_ in zip(input_names, inputs): + input_path = save_bytes(intermediate_path, input_, input_name) # type: ignore[arg-type] + input_file_paths.append(input_path) + + return input_file_paths + + +def get_output_from_file( + exported_program: ExportedProgram, + intermediate_path: str | Path, + output_base_name: str, +): + output_np = [] + output_node = exported_program.graph_module.graph.output_node() + for i, node in enumerate(output_node.args[0]): # type: ignore[union-attr] + output_dtype = node.meta["val"].dtype + tosa_ref_output = np.fromfile( # type: ignore[var-annotated] + os.path.join(intermediate_path, f"{output_base_name}-{i}.bin"), + _torch_to_numpy_dtype_dict[output_dtype], + ) + + output_np.append(numpy_to_torch_tensor(tosa_ref_output, node)) + return tuple(output_np) + + +def run_vkml_emulation_layer( + executorch_program_manager: ExecutorchProgramManager, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, + elf_path: str | Path, +): + """Executes an inference of the exported_program on ML Emulation Layer for Vulkan + Args: + `executorch_program_manager`: The executorch program to run. + `intermediate_path`: Directory to save the .pte and capture outputs. + `elf_path`: Path to the Vulkan-capable executor_runner binary. + """ + exported_program = executorch_program_manager.exported_program() + intermediate_path = Path(intermediate_path) + intermediate_path.mkdir(exist_ok=True) + elf_path = Path(elf_path) + if not elf_path.exists(): + raise FileNotFoundError(f"Did not find elf file {elf_path}") + + # Save pte to file + pte_path = os.path.join(intermediate_path, "program.pte") + with open(pte_path, "wb") as f: + f.write(executorch_program_manager.buffer) + + output_base_name = "out" + out_path = os.path.join(intermediate_path, output_base_name) + + cmd_line = f"{elf_path} -model_path {pte_path} -output_file {out_path}" + + input_string = None + input_paths = save_inputs_to_file(exported_program, inputs, intermediate_path) + for input_path in input_paths: + if input_string is None: + input_string = f" -inputs={input_path}" + else: + input_string += f",{input_path}" + if input_string is not None: + cmd_line += input_string + cmd_line = cmd_line.split() + + result = _run_cmd(cmd_line) + + # TODO: MLETORCH-1234: Support VGF e2e tests in VgfPipeline + # TODO: Add regex to check for error or fault messages in stdout from Emulation Layer + result_stdout = result.stdout.decode() # noqa: F841 + + return get_output_from_file(exported_program, intermediate_path, output_base_name) + + +def run_corstone( + executorch_program_manager: ExecutorchProgramManager, + inputs: Tuple[torch.Tensor], + intermediate_path: str | Path, + target_board: str, + elf_path: str | Path, + timeout: int = 120, # s +) -> list[torch.Tensor]: + """Executes an inference of the exported_program on FVP. + Returns a list of tensors with the output. + Args: + `executorch_program_manager`: The executorch program to run. + The output of a EdgeProgramManager.to_executorch() call. + `inputs`: A list of tensors with the inputs of the inference. + `dump_path`: A directory where the .pte and inputs are saved to file. + The output tensors are saved in `dump_path`/out. + `target_board`: Whether to run the corstone-300 FVP or the corstone-320 FVP + `elf_path`: The path to the runtime elf. Needs to have semihosting enabled + and match the target_board. + `timeout`: The timeout until the FVP terminates the elf, in seconds. + A runtime with semihosting needs + Limitations: + Relies on the output tensors from the exported program + to figure out the shape and dtype of the buffer that was + output from the FVP. + """ + exported_program = executorch_program_manager.exported_program() + intermediate_path = Path(intermediate_path) + intermediate_path.mkdir(exist_ok=True) + elf_path = Path(elf_path) + if not elf_path.exists(): + raise FileNotFoundError(f"Did not find elf file {elf_path}") + + # Save pte to file + pte_path = os.path.join(intermediate_path, "program.pte") + with open(pte_path, "wb") as f: + f.write(executorch_program_manager.buffer) + + input_paths = save_inputs_to_file(exported_program, inputs, intermediate_path) + + output_base_name = "out" + + cmd_line = "executor_runner -m program.pte -o out" + for input_path in input_paths: + relative_path = os.path.relpath( + Path(input_path).resolve(), start=intermediate_path + ) + cmd_line += f" -i {relative_path}" + + if len(cmd_line) > 256: + raise ValueError( + "The argument passed to the FVP should be less than 256 characters long, otherwise it gets truncated" + ) + + match target_board: + case "corstone-300": + command_args = [ + "FVP_Corstone_SSE-300_Ethos-U55", + "-C", + "ethosu.num_macs=128", + "-C", + "mps3_board.visualisation.disable-visualisation=1", + "-C", + "mps3_board.telnetterminal0.start_telnet=0", + "-C", + "mps3_board.uart0.out_file='-'", + "-C", + "cpu0.semihosting-enable=1", + "-C", + "cpu0.semihosting-stack_base=0", + "-C", + "cpu0.semihosting-heap_limit=0", + "-C", + f"cpu0.semihosting-cwd={intermediate_path}", + "-C", + "ethosu.extra_args='--fast'", + "-C", + f"cpu0.semihosting-cmd_line='{cmd_line}'", + "-a", + str(elf_path), + "--timelimit", + f"{timeout}", + ] + case "corstone-320": + command_args = [ + "FVP_Corstone_SSE-320", + "-C", + "mps4_board.subsystem.ethosu.num_macs=128", + "-C", + "mps4_board.visualisation.disable-visualisation=1", + "-C", + "vis_hdlcd.disable_visualisation=1", + "-C", + "mps4_board.telnetterminal0.start_telnet=0", + "-C", + "mps4_board.uart0.out_file='-'", + "-C", + "mps4_board.uart0.unbuffered_output=1", + "-C", + "mps4_board.uart0.shutdown_on_eot=1", + "-C", + "mps4_board.subsystem.cpu0.semihosting-enable=1", + "-C", + "mps4_board.subsystem.cpu0.semihosting-stack_base=0", + "-C", + "mps4_board.subsystem.cpu0.semihosting-heap_limit=0", + "-C", + f"mps4_board.subsystem.cpu0.semihosting-cwd={intermediate_path}", + "-C", + "mps4_board.subsystem.ethosu.extra_args='--fast'", + "-C", + f"mps4_board.subsystem.cpu0.semihosting-cmd_line='{cmd_line}'", + "-a", + str(elf_path), + "--timelimit", + f"{timeout}", + ] + case _: + raise ValueError(f"Unknown target board {target_board}") + + result = _run_cmd(command_args) + + # Regex to check for error or fault messages in stdout from FVP + result_stdout = result.stdout.decode() + error_regex = r"(^[EF][: ].*$)|(^.*Hard fault.*$)|(^.*Assertion.*$)" + pattern = re.compile(error_regex, re.MULTILINE) + regex_matches = [m.group(0) for m in pattern.finditer(result_stdout)] + + if regex_matches: + logger.error( + f"Corstone simulation failed:\ncmd: {' '.join(command_args)}\nlog: \n {result_stdout}\n{result.stderr.decode()}" + ) + # Pretty-print regex matches + pretty_matches = "\n".join(f"{m.strip()}" for i, m in enumerate(regex_matches)) + logger.error( + f"Corstone simulation failed. Problems: {len(regex_matches)} found:\n{pretty_matches}" + ) + raise RuntimeError( + f"Corstone simulation failed. Problems: {len(regex_matches)} found:\n{pretty_matches}" + ) + else: + logger.info( + f"Corstone simulation:\ncmd: {' '.join(command_args)}\nlog: \n {result_stdout}\n{result.stderr.decode()}" + ) + + return get_output_from_file(exported_program, intermediate_path, output_base_name) + + +def prep_data_for_save( + data, + input_name: str, + quant_param: Optional[QuantizationParams] = None, +): + if isinstance(data, torch.Tensor): + data_np = torch_tensor_to_numpy(data) + elif isinstance(data, (int, float, bool, NoneType)): + return np.array(data) + else: + raise RuntimeError( + f"Input dtype {type(data)} could not be converted to numpy array." + ) + + if quant_param is not None: + assert quant_param.node_name in input_name, ( + f"The quantization params name '{quant_param.node_name}' does not " + f"match the input tensor name '{input_name}'." + ) + data_np = ( + ((data_np / np.float32(quant_param.scale)) + quant_param.zp) + .round() + .clip(quant_param.qmin, quant_param.qmax) + .astype( + f"{quant_param.dtype}".replace("torch.", "") + ) # Use string format of dtype to convert to numpy dtype + ) + + return data_np + + +def save_bytes( + path: str, + data, + input_name: str, + quant_param: Optional[QuantizationParams] = None, +) -> str: + """Serializes and saves 'data' in byte format, possibly quantizing it before. + + Parameters: + path: the directory where to save the data. + data: the data to save. + input_name: the name of the file, without file-ending. + quant_param: the parameters to use for quantization. + Returns: + the full file path of the output. + """ + data_np = prep_data_for_save(data, input_name, quant_param) + file_path = os.path.join(path, input_name + ".bin") + with open(file_path, "w+b") as f: + data_np_bytes = data_np.tobytes() + f.write(data_np_bytes) + + return file_path + + +def _run_cmd(cmd: List[str], check=True) -> subprocess.CompletedProcess[bytes]: + """ + Run a command and check for errors. + + Args: + cmd (List[str]): The command to run as a list. + """ + try: + result = subprocess.run( # nosec B603 - cmd constructed from trusted inputs + cmd, check=check, capture_output=True + ) + return result + except subprocess.CalledProcessError as e: + arg_string = " ".join(cmd) + raise RuntimeError( + f"Failed running command {arg_string}\nStderr: {e.stderr.decode()}\nStdout: {e.stdout.decode()}" + ) + + +# Name of an optional resource containing the `flatc` executable. +_FLATC_RESOURCE_NAME: str = "flatbuffers-flatc" + + +def _run_flatc(args: List[str]) -> None: + """Runs the `flatc` command with the provided args. + + If a resource matching _FLATC_RESOURCE_NAME exists, uses that executable. + Otherwise, expects the `flatc` tool to be available on the system path. + """ + flatc_resource = _resources.files(arm_test_package).joinpath(_FLATC_RESOURCE_NAME) + if flatc_resource.is_file(): + # Use the provided flatc binary from resources. + with _resources.as_file(flatc_resource) as flatc_path: + subprocess.run( # nosec B603 - cmd constructed from trusted inputs + [str(flatc_path)] + args, check=True + ) + else: + # Expect the `flatc` tool to be on the system path or set as an env var. + flatc_executable: str | None = os.getenv("FLATC_EXECUTABLE") + if not flatc_executable: + flatc_executable = shutil.which("flatc") + if not flatc_executable: + raise RuntimeError( + "flatc not found. Either add it to PATH, set FLATC_EXECUTABLE env var, " + "or ensure the flatbuffers-flatc resource is available." + ) + subprocess.run( # nosec B603 - cmd constructed from trusted inputs + [flatc_executable] + args, check=True + ) + + +def dbg_tosa_fb_to_json(tosa_fb: bytes) -> Dict: + """ + This function is used to dump the TOSA flatbuffer to a human readable + format, using flatc. It is used for debugging purposes. + """ + + tmp = tempfile.mkdtemp() + tosa_input_file = os.path.join(tmp, "output.tosa") + with open(tosa_input_file, "wb") as f: + f.write(tosa_fb) + tosa_graph = TosaGraph.GetRootAsTosaGraph(tosa_fb) + version = tosa_graph.Version() + major = version._Major() + minor = version._Minor() + patch = version._Patch() + if not ((major == 1 and minor == 0)): + raise RuntimeError( + f"Unsupported version in TOSA flatbuffer: version={major}.{minor}.{patch}" + ) + + # Write schema file to temp directory using importlib.resources + tosa_schema_file = os.path.join(tmp, f"tosa_{major}.{minor}.fbs") + with open(tosa_schema_file, "wb") as schema_file: + schema_file.write( + _resources.read_binary(tosa_schemas_package, f"tosa_{major}.{minor}.fbs") + ) + + flatc_args = [ + "--json", + "--strict-json", + "-o", + tmp, + "--raw-binary", + "-t", + tosa_schema_file, + "--", + tosa_input_file, + ] + _run_flatc(flatc_args) + with open(os.path.join(tmp, "output.json"), "r") as f: + json_out = json.load(f) + + # Cast float tensors to proper dtype. + try: + for region in json_out["regions"]: + for block in region["blocks"]: + for tensor in block["tensors"]: + if "data" in tensor: + if tensor["type"] == "FP32": + data = np.array(tensor["data"]) + data = data.astype(np.int8) + data = np.frombuffer(data, dtype=np.float32) + data = data.reshape(tensor["shape"]) + tensor["data"] = data + except Exception: # nosec B110 - best-effort casting for debug output only + pass + + return json_out + + +def _tosa_refmodel_loglevel(loglevel: int) -> str: + """Converts a logging loglevel to tosa_reference_model logginglevel, + returned as string. + """ + loglevel_map = { + logging.INFO: "INFO", + logging.CRITICAL: "LOW", + logging.ERROR: "LOW", + logging.WARNING: "MED", + logging.DEBUG: "HIGH", + logging.NOTSET: "MED", + } + clamped_logging_level = max(min(loglevel // 10 * 10, 50), 0) + return loglevel_map[clamped_logging_level] + + +def corstone300_installed() -> bool: + cmd = ["FVP_Corstone_SSE-300_Ethos-U55", "--version"] + try: + _run_cmd(cmd, check=True) + except: + return False + return True + + +def corstone320_installed() -> bool: + cmd = ["FVP_Corstone_SSE-320", "--version"] + try: + _run_cmd(cmd, check=True) + except: + return False + return True + + +def model_converter_installed() -> bool: + model_converter = find_model_converter_binary() + if model_converter is None: + return False + + try: + _run_cmd([model_converter, "--version"], check=True) + except Exception: + return False + + return True + + +def vkml_emulation_layer_installed() -> bool: + # Check VK_INSTANCE_LAYERS + vk_instance_layers = os.environ.get("VK_INSTANCE_LAYERS", "") + required_layers = { + "VK_LAYER_ML_Graph_Emulation", + "VK_LAYER_ML_Tensor_Emulation", + } + existing_layers = set(vk_instance_layers.split(":")) + layers_exists = required_layers.issubset(existing_layers) + + # Check LD_LIBRARY_PATH for "emulation-layer/deploy" + ld_library_path = os.environ.get("LD_LIBRARY_PATH", "") + deploy_exists = False + for path in ld_library_path.split(os.path.pathsep): + if "emulation-layer/deploy" in path and os.path.isdir(path): + deploy_exists = True + + return layers_exists and deploy_exists + + +def assert_elf_path_exists(elf_path): + if not os.path.exists(elf_path): + raise FileNotFoundError( + f"Did not find build arm_executor_runner or executor_runner in path {elf_path}, \ + run setup_testing.sh or setup_testing_vkml.sh?" + ) + + +def get_elf_path(target_board: str, use_portable_ops: bool = False) -> str: + elf_path = "" + + if target_board not in VALID_TARGET: + raise ValueError(f"Unsupported target: {target_board}") + + if use_portable_ops: + portable_ops_str = "portable-ops_" + else: + portable_ops_str = "" + + if target_board in ("corstone-300", "corstone-320"): + elf_path = os.path.join( + "arm_test", + f"arm_semihosting_executor_runner_{portable_ops_str}{target_board}", + "arm_executor_runner", + ) + elif target_board == "vkml_emulation_layer": + elf_path = os.path.join( + f"arm_test/arm_executor_runner_{portable_ops_str}vkml", + "executor_runner", + ) + + assert_elf_path_exists(elf_path) + return elf_path + + +def arm_executor_runner_exists(target_board: str, use_portable_ops: bool = False): + try: + get_elf_path(target_board, use_portable_ops=use_portable_ops) + except: + return False + else: + return True + + +def run_tosa_graph( + graph: Any, + tosa_version: TosaSpecification, + inputs: list[torch.Tensor], + output_node: Node, +) -> list[torch.Tensor]: + """Runs the TOSA reference model with inputs and returns the result.""" + + # Convert tensors to numpy arrays with correct dim_order + inputs_np = [torch_tensor_to_numpy(input_tensor) for input_tensor in inputs] + + if isinstance(tosa_version, Tosa_1_00): + import tosa_reference_model as reference_model # type: ignore[import-not-found, import-untyped] + + debug_mode = "ALL" if logger.getEffectiveLevel() <= logging.DEBUG else None + outputs_np, status = reference_model.run( + graph, + inputs_np, + verbosity=_tosa_refmodel_loglevel(logger.getEffectiveLevel()), + initialize_variable_tensor_from_numpy=True, + debug_mode=debug_mode, + ) + else: + raise ValueError( + f"Unknown TOSA specification: {tosa_version}. No refererence model available to run for this specification version" + ) + + assert ( + status == reference_model.GraphStatus.TOSA_VALID + ), "Non-valid TOSA given to reference model." + + # Convert output numpy arrays to tensors with same dim_order as the output nodes + result = [ + numpy_to_torch_tensor(output_array, node) + for output_array, node in zip(outputs_np, output_node.args[0]) # type: ignore[arg-type] + ] + + return result + + +def get_target_board(compile_spec: ArmCompileSpec) -> str | None: + if isinstance(compile_spec, VgfCompileSpec): + return "vkml_emulation_layer" + if isinstance(compile_spec, EthosUCompileSpec): + if "u55" in compile_spec.target: + return "corstone-300" + if "u85" in compile_spec.target: + return "corstone-320" + return None diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing.sh new file mode 100755 index 0000000..bb68361 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +et_root_dir=$(realpath "${script_dir}/../../..") +build_executor_runner=${et_root_dir}/backends/arm/scripts/build_executor_runner.sh +build_root_test_dir=${et_root_dir}/arm_test/arm_semihosting_executor_runner +extraflags="-DET_ARM_BAREMETAL_METHOD_ALLOCATOR_POOL_SIZE=83886080" + +# By default tests with an elf without any portable_ops +# If you supply use_portable_ops=True when creating the ArmTester() +# you will instead test with some portable ops compiled in, see list below. + +#--target --system_config --memory_mode should match the ArmTester used setup see backends/arm/test/common.py + +${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --system_config=Ethos_U55_High_End_Embedded --memory_mode=Shared_Sram --output="${build_root_test_dir}_corstone-300" --extra_build_flags=${extraflags} +${build_executor_runner} --pte=semihosting --target=ethos-u85-128 --system_config=Ethos_U85_SYS_DRAM_Mid --memory_mode=Dedicated_Sram_384KB --output="${build_root_test_dir}_corstone-320" --extra_build_flags=${extraflags} + +# List of portable ops used by testing, this is mainly used to test models in the flow +# test setup to make sure models that are not fully delegated can still be tested and run OK +# To use this you can set use_portable_ops=True when creating ArmTester() + +portable_ops_list_u55="aten::permute_copy.out,aten::convolution.out,aten::relu.out,aten::_native_batch_norm_legit_no_training.out,aten::as_strided_copy.out,aten::mean.out,aten::squeeze_copy.dims,dim_order_ops::_clone_dim_order.out" +portable_ops_list_u85="aten::permute_copy.out,aten::convolution.out,aten::relu.out,aten::_native_batch_norm_legit_no_training.out,aten::as_strided_copy.out,aten::mean.out,aten::full_like.out,aten::bmm.out,aten::scalar_tensor.out,aten::index.Tensor_out,aten::where.self_out" + +${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --system_config=Ethos_U55_High_End_Embedded --memory_mode=Shared_Sram --select_ops_list="${portable_ops_list_u55}" --output="${build_root_test_dir}_portable-ops_corstone-300" --extra_build_flags=${extraflags} +${build_executor_runner} --pte=semihosting --target=ethos-u85-128 --system_config=Ethos_U85_SYS_DRAM_Mid --memory_mode=Dedicated_Sram_384KB --select_ops_list="${portable_ops_list_u85}" --output="${build_root_test_dir}_portable-ops_corstone-320" --extra_build_flags=${extraflags} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing_vkml.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing_vkml.sh new file mode 100755 index 0000000..6edb2dc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/setup_testing_vkml.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +script_dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +et_root_dir=$(realpath "${script_dir}/../../..") +build_executor_runner=${et_root_dir}/backends/arm/scripts/build_executor_runner_vkml.sh +build_root_test_dir=${et_root_dir}/arm_test/arm_executor_runner_vkml + +${build_executor_runner} --output="${build_root_test_dir}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/targets.bzl new file mode 100644 index 0000000..14b4a37 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/targets.bzl @@ -0,0 +1,79 @@ +# load("//caffe2/test/fb:defs.bzl", "define_tests") +load("@fbsource//tools/build_defs:fbsource_utils.bzl", "is_fbcode") +load("@fbcode_macros//build_defs:python_pytest.bzl", "python_pytest") +load("@bazel_skylib//lib:paths.bzl", "paths") + +def define_arm_tests(): + # TODO [fbonly] Add more tests + test_files = [] + + # Passes + test_files += native.glob(["passes/test_*.py"]) + # https://github.com/pytorch/executorch/issues/8606 + test_files.remove("passes/test_ioquantization_pass.py") + + # Operators + test_files += [ + "ops/test_add.py", + "ops/test_addmm.py", + "ops/test_avg_pool2d.py", + "ops/test_cat.py", + "ops/test_conv2d.py", + "ops/test_linear.py", + "ops/test_mul.py", + "ops/test_permute.py", + "ops/test_rsqrt.py", + "ops/test_slice.py", + "ops/test_sigmoid.py", + "ops/test_sub.py", + "ops/test_tanh.py", + "ops/test_view.py", + "ops/test_cos.py", + "ops/test_to_copy.py", + ] + + # Quantization + test_files += [ + "quantizer/test_generic_annotater.py", + ] + + # Misc tests + test_files += [ + "misc/test_compile_spec.py", + "misc/test_tosa_spec.py", + "misc/test_bn_relu_folding_qat.py", + "misc/test_custom_partition.py", + "misc/test_debug_hook.py", + # "misc/test_dim_order.py", (TODO - T238390249) + "misc/test_outputs_order.py", + ] + + TESTS = {} + + for test_file in test_files: + test_file_name = paths.basename(test_file) + test_name = test_file_name.replace("test_", "").replace(".py", "") + + python_pytest( + name = test_name, + srcs = [test_file], + pytest_config = "pytest.ini", + resources = ["conftest.py"], + compile = "with-source", + typing = False, + preload_deps = [ + "//executorch/kernels/quantized:custom_ops_generated_lib", + ], + deps = [ + "//executorch/backends/arm/test/tester/fb:arm_tester_fb" if is_fbcode else "//executorch/backends/arm/test:arm_tester", + "//executorch/backends/arm/test:conftest", + "//executorch/backends/arm/test/misc:dw_convs_shared_weights_module", + "//executorch/backends/arm:ethosu", + "//executorch/backends/arm/tosa:compile_spec", + "//executorch/backends/arm/tosa:partitioner", + "//executorch/backends/arm:vgf", + "//executorch/exir:lib", + "fbsource//third-party/pypi/pytest:pytest", + "fbsource//third-party/pypi/parameterized:parameterized", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_baremetal.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_baremetal.sh new file mode 100755 index 0000000..4561e05 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_baremetal.sh @@ -0,0 +1,347 @@ +#!/bin/bash +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# TODO: Rename this script + +set -e + +script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) + +# Executorch root +et_root_dir=$(cd ${script_dir}/../../.. && pwd) +cd "${et_root_dir}" +pwd +scratch_dir=${et_root_dir}/examples/arm/arm-scratch +setup_path_script=${scratch_dir}/setup_path.sh +_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools." + + +TEST_SUITE=$1 + +# Source the tools +# This should be prepared by the setup.sh +[[ -f ${setup_path_script} ]] \ + || { echo "Missing ${setup_path_script}. ${_setup_msg}"; exit 1; } +source ${setup_path_script} + +help() { + echo "Usage:" + echo " $0 " + echo " where can be any of:" + # This will list all lines in this file that is starting with test_ remove () { and print it as a list. + # e,g, "test_pytest() { # Test ops and other things" -> test_pytest # Test ops and other things + echo "all # run all tests" + grep "^test_" $0 | sed 's/([^)]*)[[:space:]]*{*//g' + exit +} + +if [[ -z "${TEST_SUITE:-}" ]]; then + echo "Missing test suite name, exiting..." + help +else + echo "Run Arm baremetal test suite ${TEST_SUITE}" +fi + +TEST_SUITE_NAME="$(basename "$0") ${TEST_SUITE}" + +all() { # Run all tests + # This will list all lines in this file that is starting with test_ remove () { and add this script name in + # front of it and execute it in a sub shell + # e.g. from this file: + # + # test_pytest() { # Test ops and other things + # bla bla bla + # } + # test_pytest_ethosu_fvp() { # Same as test_pytest but ... + # bla bla bla + # } + #... + # become a small script: + # ---- + # backends/arm/test/test_arm_baremetal.sh test_pytest # Test ops and other things + # backends/arm/test/test_arm_baremetal.sh test_pytest_ethosu_fvp # Same as test_pytest but ... + # ... + # ---- + # That is executed + echo "${TEST_SUITE_NAME}: Run all tests" + grep "^test_" backends/arm/test/test_arm_baremetal.sh | sed 's/([^)]*)[[:space:]]*{*//g' | sed "s|^|$0 |" | sh + echo "${TEST_SUITE_NAME}: PASS" +} + +# ------------------------------------------- +# -------- Non target-specific tests -------- +# ------------------------------------------- +test_pytest_ops_no_target() { + echo "${TEST_SUITE_NAME}: Run pytest ops for target-less tests" + + # Run arm baremetal pytest tests without target + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k no_target + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_no_target() { + echo "${TEST_SUITE_NAME}: Run pytest models for target-less tests" + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + # Run arm baremetal pytest tests without FVP + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k no_target + echo "${TEST_SUITE_NAME}: PASS" +} + +# ------------------------------------- +# -------- TOSA specific tests -------- +# ------------------------------------- +test_pytest_ops_tosa() { + echo "${TEST_SUITE_NAME}: Run pytest ops for TOSA" + + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k tosa + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_tosa() { + echo "${TEST_SUITE_NAME}: Run pytest models for TOSA" + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k tosa + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_tosa() { + echo "${TEST_SUITE_NAME}: Test TOSA delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test target TOSA" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=TOSA-1.0+INT --model_name=add + examples/arm/run.sh --et_build_root=arm_test/test_run --target=TOSA-1.0+INT --model_name=mul + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ---------------------------------------------- +# -------- Arm Ethos-U55 specific tests -------- +# ---------------------------------------------- +test_pytest_ops_ethos_u55() { + echo "${TEST_SUITE_NAME}: Run pytest ops for Arm Ethos-U55" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k u55 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_ethos_u55() { + echo "${TEST_SUITE_NAME}: Run pytest models for Arm Ethos-U55" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k u55 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_ethos_u55() { + echo "${TEST_SUITE_NAME}: Test ethos-u55 delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test target Ethos-U55" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-64 --model_name=add + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-256 --model_name=add --bundleio --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=mul + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-256 --model_name=add --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=mul --bundleio --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=mul --bundleio --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --bundleio --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=examples/arm/example_modules/add.py + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=examples/arm/example_modules/add.py --bundleio + + # Cortex-M op tests + echo "${TEST_SUITE_NAME}: Test target Cortex-M55 (on Ethos-U55)" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=add --bundleio --no_delegate --select_ops_list="aten::add.out" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=qadd --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=qops --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u55-128 --model_name=qops --bundleio --no_delegate --select_ops_list="aten::sub.out,aten::add.out,aten::mul.out" + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ---------------------------------------------- +# -------- Arm Ethos-U85 specific tests -------- +# ---------------------------------------------- +test_pytest_ops_ethos_u85() { + echo "${TEST_SUITE_NAME}: Run pytest ops for Arm Ethos-U85" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + # Run arm baremetal pytest tests with FVP + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models -k u85 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_ethos_u85() { + echo "${TEST_SUITE_NAME}: Run pytest models for Arm Ethos-U85" + + backends/arm/scripts/build_executorch.sh + backends/arm/test/setup_testing.sh + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k u85 + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_ethos_u85() { + echo "${TEST_SUITE_NAME}: Test ethos-u85 delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=add + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-256 --model_name=add --bundleio + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-512 --model_name=add --bundleio --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-1024 --model_name=add --etdump + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-2048 --model_name=mul --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=mul --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=mul --bundleio --pte_placement=elf + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-256 --model_name=mul --bundleio --pte_placement=0x38000000 + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-1024 --model_name=examples/arm/example_modules/add.py --bundleio + + # Cortex-M op tests + echo "${TEST_SUITE_NAME}: Test target Cortex-M55 (on Ethos-U85)" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=qops --bundleio + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ---------------------------------------------------------- +# -------- Vulkan Graph Format (VGF) specific tests -------- +# ---------------------------------------------------------- +test_pytest_ops_vkml() { + echo "${TEST_SUITE_NAME}: Run pytest operator tests with VKML runtime" + + source backends/arm/test/setup_testing_vkml.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ \ + --ignore=backends/arm/test/models -k _vgf_ + echo "${TEST_SUITE_NAME}: PASS" +} + +test_pytest_models_vkml() { + echo "${TEST_SUITE_NAME}: Run pytest model tests with VKML runtime" + + source backends/arm/test/setup_testing_vkml.sh + + # Install model dependencies for pytest + source backends/arm/scripts/install_models_for_test.sh + + pytest --verbose --color=yes --numprocesses=auto --durations=0 backends/arm/test/models -k _vgf_ + echo "${TEST_SUITE_NAME}: PASS" +} + +test_run_vkml() { + echo "${TEST_SUITE_NAME}: Test VKML delegate examples with run.sh" + + echo "${TEST_SUITE_NAME}: Test VKML" + out_folder="arm_test/test_run" + + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=add --output=${out_folder}/runner + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=mul --output=${out_folder}/runner + + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=qadd --output=${out_folder}/runner + examples/arm/run.sh --et_build_root=${out_folder} --target=vgf --model_name=qops --output=${out_folder}/runner + + echo "${TEST_SUITE_NAME}: PASS" +} + +# ------------------------------------ +# -------- Miscelaneous tests -------- +# ------------------------------------ +test_model_smollm2-135M() { + echo "${TEST_SUITE_NAME}: Test SmolLM2-135M on Ethos-U85" + + # Build common libs once + python3 backends/arm/test/test_model.py --test_output=arm_test/test_model --build_libs + + python3 backends/arm/test/test_model.py --test_output=arm_test/test_model --target=ethos-u85-128 --model=smollm2 --extra_flags="-DEXECUTORCH_SELECT_OPS_LIST=dim_order_ops::_to_dim_order_copy.out" + + echo "${TEST_SUITE_NAME}: PASS" + + +} + +test_smaller_stories_llama() { + echo "${TEST_SUITE_NAME}: Test smaller_stories_llama" + + backends/arm/scripts/build_executorch.sh + + mkdir -p stories110M + pushd stories110M + wget -N https://huggingface.co/karpathy/tinyllamas/resolve/main/stories110M.pt + echo '{"dim": 768, "multiple_of": 32, "n_heads": 12, "n_layers": 12, "norm_eps": 1e-05, "vocab_size": 32000}' > params.json + popd + + # Get path to source directory + pytest \ + -c /dev/null \ + --verbose \ + --color=yes \ + --numprocesses=auto \ + --log-level=DEBUG \ + --junit-xml=stories110M/test-reports/unittest.xml \ + -s \ + backends/arm/test/models/test_llama.py \ + --llama_inputs stories110M/stories110M.pt stories110M/params.json stories110m + + echo "${TEST_SUITE_NAME}: PASS" +} + +test_memory_allocation() { + echo "${TEST_SUITE_NAME}: Test ethos-u memory allocation with run.sh" + + mkdir -p arm_test/test_run + # Ethos-U85 + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py &> arm_test/test_run/full.log + python3 backends/arm/test/test_memory_allocator_log.py --log arm_test/test_run/full.log \ + --require "model_pte_program_size" "<= 3100 B" \ + --require "method_allocator_planned" "<= 64 B" \ + --require "method_allocator_loaded" "<= 1024 B" \ + --require "method_allocator_input" "<= 16 B" \ + --require "Total DRAM used" "<= 0.06 KiB" + echo "${TEST_SUITE_NAME}: PASS" +} + +test_undefinedbehavior_sanitizer() { + echo "${TEST_SUITE_NAME}: Test ethos-u executor_runner with UBSAN" + + mkdir -p arm_test/test_run + # Ethos-U85 + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py --build_type=UndefinedSanitizer + echo "${TEST_SUITE_NAME}: PASS" +} + +test_address_sanitizer() { + echo "${TEST_SUITE_NAME}: Test ethos-u executor_runner with ASAN" + + mkdir -p arm_test/test_run + # Ethos-U85 + echo "${TEST_SUITE_NAME}: Test target Ethos-U85" + examples/arm/run.sh --et_build_root=arm_test/test_run --target=ethos-u85-128 --model_name=examples/arm/example_modules/add.py --build_type=AddressSanitizer + echo "${TEST_SUITE_NAME}: PASS" +} + + +${TEST_SUITE} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_ootb.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_ootb.sh new file mode 100755 index 0000000..43a1bff --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_arm_ootb.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash + +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -eo pipefail + +help() { + echo "Usage:" + echo " $0 [TESTNAME]" + echo "Without TESTNAME all tests will run; otherwise choose one of:" + # This will list all lines in this file that is starting with test_ remove () { and print it as a list. + # e,g, "test_pytest() { # Test ops and other things" -> test_pytest # Test ops and other things + grep "^run_" $0 | sed 's/([^)]*)[[:space:]]*{*//g' + exit +} + +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + help +fi + +if [[ $# -eq 0 ]]; then + TEST_SUITES=(run_ootb_tests_ethos_u run_ootb_tests_tosa run_deit_e2e_ethos_u) +else + TEST_SUITES=("$1") +fi + + +run_ootb_tests_ethos_u() { + echo "$FUNCNAME: Running out-of-the-box tests for Arm Ethos-U" + jupyter nbconvert \ + --to notebook \ + --execute examples/arm/ethos_u_minimal_example.ipynb + echo "${FUNCNAME}: PASS" +} + +run_ootb_tests_tosa() { + echo "$FUNCNAME: Running out-of-the-box tests for TOSA" + jupyter nbconvert \ + --to notebook \ + --execute backends/arm/scripts/TOSA_minimal_example.ipynb + echo "${FUNCNAME}: PASS" +} + +run_deit_e2e_ethos_u() { + echo "$FUNCNAME: Fine-tune, export, build, and run the DEiT e2e test" + + local script_dir + script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) + et_root_dir=$(cd "${script_dir}/../../.." && pwd) + local example_dir="${et_root_dir}/examples/arm/image_classification_example" + local work_root="${et_root_dir}/arm_test/deit_tiny_ootb_smoke" + local model_dir="${work_root}/deit_tiny_finetuned" + local export_dir="${work_root}/export" + local build_dir="${work_root}/simple_app_deit_tiny" + local image_path="${work_root}/dog.bmp" + local pte_path="${export_dir}/deit_tiny_smoke.pte" + local toolchain_file="${et_root_dir}/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake" + echo "${FUNCNAME}: Work root is ${work_root}; existing artifacts will be reused if present" + + mkdir -p "${model_dir}" "${export_dir}" "${build_dir}" + + setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh + source ${setup_path_script} + + source ${et_root_dir}/backends/arm/scripts/utils.sh + local n_proc="$(get_parallel_jobs)" + + # Build ExecuTorch + echo "${FUNCNAME}: Building ExecuTorch (if needed)" + cmake --preset arm-baremetal -B "${et_root_dir}/cmake-out-arm" + cmake --build "${et_root_dir}/cmake-out-arm" --target install -j"$n_proc" + + # Install requirements + pip install -r examples/arm/image_classification_example/requirements.txt + + # Get and finetune model + echo "${FUNCNAME}: Running DeiT fine-tuning script" + python3 "${example_dir}/model_export/train_deit.py" \ + --output-dir "${model_dir}" \ + --num-epochs 1 + + # Export model to pte + local final_model_dir="${model_dir}/final_model" + echo "${FUNCNAME}: Exporting quantized PTE from ${final_model_dir}" + python3 "${example_dir}/model_export/export_deit.py" \ + --model-path "${final_model_dir}" \ + --output-path "${pte_path}" \ + --num-calibration-samples 100 + + [[ -f "${pte_path}" ]] || { + echo "${FUNCNAME}: Missing PTE at ${pte_path}" + return 1 + } + + # Download demo image for inference + local image_url="https://gitlab.arm.com/artificial-intelligence/ethos-u/ml-embedded-evaluation-kit/-/raw/main/resources/img_class/samples/dog.bmp?ref_type=heads" + if [[ ! -f "${image_path}" ]]; then + echo "${FUNCNAME}: Downloading sample image from ${image_url}" + wget -O "${image_path}" "${image_url}" + else + echo "${FUNCNAME}: Reusing sample image at ${image_path}" + fi + + # Build application + echo "${FUNCNAME}: Configuring the minimal application" + cmake \ + -S "${example_dir}/runtime" \ + -B "${build_dir}" \ + -DCMAKE_TOOLCHAIN_FILE="${toolchain_file}" \ + -DET_PTE_FILE_PATH="${pte_path}" \ + -DIMAGE_PATH="${image_path}" \ + -DET_BUILD_DIR_PATH="${et_root_dir}/cmake-out-arm" + + echo "${FUNCNAME}: Building img_class_example" + cmake --build "${build_dir}" -j"$n_proc" --target img_class_example + + # Run application on FVP + local fvp_bin="${FVP_BINARY:-FVP_Corstone_SSE-320}" + local elf="${build_dir}/img_class_example" + + echo "${FUNCNAME}: Running on ${fvp_bin}" + "${fvp_bin}" \ + -C mps4_board.subsystem.ethosu.num_macs=256 \ + -C mps4_board.visualisation.disable-visualisation=1 \ + -C vis_hdlcd.disable_visualisation=1 \ + -C mps4_board.telnetterminal0.start_telnet=0 \ + -C mps4_board.uart0.out_file="-" \ + -C mps4_board.uart0.shutdown_on_eot=1 \ + -a "${elf}" \ + -C mps4_board.subsystem.ethosu.extra_args="--fast" + + echo "${FUNCNAME}: PASS" +} + +for suite in "${TEST_SUITES[@]}"; do + "${suite}" +done diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_memory_allocator_log.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_memory_allocator_log.py new file mode 100644 index 0000000..3853b60 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_memory_allocator_log.py @@ -0,0 +1,170 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +""" +Check log files for memory metrics and compare them against thresholds. + +Usage example: + python3 test_memory_allocator_log.py \ + --log path/to/log.txt \ + --require "Total SRAM used" "<= 310 KiB" \ + --require "method_allocator_input" "<= 4 B" +""" + +import argparse +import re +import sys +from typing import List, Optional, Tuple + + +def unit_factor(u: str) -> float: + if not u: + return 1.0 + ul = u.strip().lower() + table = { + "b": 1, + "byte": 1, + "bytes": 1, + "kb": 1000, + "mb": 1000**2, + "gb": 1000**3, + "kib": 1024, + "mib": 1024**2, + "gib": 1024**3, + } + if ul in table: + return float(table[ul]) + return 1.0 + + +def parse_value(text_num: str, text_unit: Optional[str]) -> float: + return float(text_num) * unit_factor(text_unit or "") + + +def parse_cond(cond: str) -> Tuple[str, float, str]: + # Regexp explained. Example of things it will parse: + # "< 310 KiB", ">=10MB", "== 42", "!=3 bytes", "<=0.5 MiB" + + # The regexp explained in detail: + # ^: anchor the match to the start and end of the string (no extra chars allowed). + # \s*: optional whitespace (spaces, tabs, etc.). + # (<=|>=|==|!=|<|>): capturing group 1. One of the comparison operators: <=, >=, ==, !=, <, >. + # \s*: optional whitespace. + # ([0-9]+(?:\.[0-9]+)?): capturing group 2. A number: + # [0-9]+: one or more digits (the integer part). + # (?:\.[0-9]+)?: optional non-capturing group for a fractional part like .25. + # \s*: optional whitespace between number and unit + # ([A-Za-z]+)?: capturing group 3, optional. A unit made of letters only (e.g., B, KB, KiB, MB, MiB). Case# insensitive by class choice. + # \s*: optional trailing whitespace. + m = re.match( + r"^\s*(<=|>=|==|!=|<|>)\s*([0-9]+(?:\.[0-9]+)?)\s*([A-Za-z]+)?\s*$", cond + ) + if not m: + raise ValueError(f"Invalid condition: {cond}") + op, num, unit = m.groups() + return op, float(num), (unit or "") + + +def compare(a: float, b: float, op: str) -> bool: + return { + "<": a < b, + "<=": a <= b, + ">": a > b, + ">=": a >= b, + "==": abs(a - b) < 1e-9, + "!=": abs(a - b) >= 1e-9, + }[op] + + +def find_metric_value(line: str, label: str) -> Tuple[Optional[str], Optional[str]]: + # Same regexp as parse_cond() but without the first group of matching comparison operators + # First go, search for the pattern but escape and ignore cases + # The regexp: + # ([0-9]+(?:\.[0-9]+)?) — capturing group 1: a decimal number + # [0-9]+ — one or more digits (integer part) + # (?:\.[0-9]+)? — optional fractional part like .25 (non-capturing) + # \s* — optional whitespace between number and unit + # ([A-Za-z]+)? — capturing group 2 (optional): a unit made only of letters (e.g., B, KB, KiB, MB) + m = re.search( + re.escape(label) + r".*?([0-9]+(?:\.[0-9]+)?)\s*([A-Za-z]+)?", + line, + flags=re.IGNORECASE, + ) + if m: + return m.group(1), m.group(2) + # Second go, same regexp as above but not caring about label. If + # no number was tied to a label be happy just salvaging it from + # the line + m = re.search(r"([0-9]+(?:\.[0-9]+)?)\s*([A-Za-z]+)?", line) + if m: + return m.group(1), m.group(2) + return None, None + + +def first_line_with_label(lines: List[str], label: str) -> Optional[str]: + label_lc = label.lower() + return next((ln for ln in lines if label_lc in ln.lower()), None) + + +def check_requirement(label: str, cond: str, lines: List[str]) -> Optional[str]: + op, thr_num, thr_unit = parse_cond(cond) + matched = first_line_with_label(lines, label) + if matched is None: + return f"{label}: not found in log" + + num_str, unit_str = find_metric_value(matched, label) + if num_str is None: + return f"{label}: value not found on line: {matched.strip()}" + + left_bytes = parse_value(num_str, unit_str) + right_bytes = parse_value(str(thr_num), thr_unit or (unit_str or "")) + ok = compare(left_bytes, right_bytes, op) + + human_left = f"{num_str} {unit_str or 'B'}" + human_right = f"{thr_num:g} {thr_unit or (unit_str or 'B')}" + print( + f"[check] {label}: {human_left} {op} {human_right} -> {'OK' if ok else 'FAIL'}" + ) + + if ok: + return None + return f"{label}: {human_left} not {op} {human_right}" + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--log", required=True, help="Path to log file") + parser.add_argument( + "--require", + action="append", + nargs=2, + metavar=("LABEL", "COND"), + default=[], + help="""Required label and condition consisting + of a number and unit. Example: \"Total DRAM + used\" \"<= 0.06 KiB\"""", + ) + args = parser.parse_args() + + with open(args.log, "r", encoding="utf-8", errors="ignore") as f: + lines = f.readlines() + + failures: List[str] = [] + for label, cond in args.require: + msg = check_requirement(label, cond, lines) + if msg: + failures.append(msg) + + if failures: + print("Failures:") + for msg in failures: + print(" - " + msg) + return 1 + + print("All checks passed.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_model.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_model.py new file mode 100755 index 0000000..87a92c2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/test_model.py @@ -0,0 +1,345 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os +import subprocess # nosec B404 - launches trusted build/test scripts +import sys +import time +from typing import Sequence + + +def get_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--build_libs", + action="store_true", + required=False, + default=False, + help="Flag for building executorch libs needed for this testing", + ) + parser.add_argument( + "--model", + required=False, + default=None, + help="Model to use that aot_arm_compiler.py can handle, can be a builtin, examples/models or a filename.", + ) + parser.add_argument( + "--target", + required=False, + default=None, + help="Target name", + ) + parser.add_argument( + "--test_output", + required=False, + default="arm_test", + help="Output folder used for build and test defults to arm_test", + ) + parser.add_argument( + "--system_config", + required=False, + default=None, + help="Target specific system_config (See Vela compiler)", + ) + parser.add_argument( + "--memory_mode", + required=False, + default=None, + help="Target specific memory_mode (See Vela compiler)", + ) + parser.add_argument( + "--no_intermediate", + action="store_true", + required=False, + default=False, + help="Don't save temporary files during compilation", + ) + parser.add_argument( + "--no_quantize", + action="store_true", + required=False, + default=False, + help="Don't quantize model", + ) + parser.add_argument( + "--extra_flags", + required=False, + default="", + help="Extra cmake flags to pass the when building the executor_runner", + ) + parser.add_argument( + "--extra_runtime_flags", + required=False, + default="", + help="Extra runtime flags to pass the final runner/executable", + ) + parser.add_argument( + "--timeout", + required=False, + default=60 * 20, + help="Timeout in seconds used when running the model", + ) + args = parser.parse_args() + + if args.model and "ethos-u" in args.target and args.system_config is None: + if "u55" in args.target: + args.system_config = "Ethos_U55_High_End_Embedded" + elif "u85" in args.target: + args.system_config = "Ethos_U85_SYS_DRAM_Mid" + else: + raise RuntimeError(f"Invalid target name {args.target}") + + if args.model and "ethos-u" in args.target and args.memory_mode is None: + if "u55" in args.target: + args.memory_mode = "Shared_Sram" + elif "u85" in args.target: + args.memory_mode = "Dedicated_Sram_384KB" + else: + raise RuntimeError(f"Invalid target name {args.target}") + + return args + + +def run_external_cmd(cmd: Sequence[str]) -> None: + print("CALL:", *cmd, sep=" ") + try: + subprocess.check_call( + cmd + ) # nosec B603 - cmd assembled from vetted scripts/flags + except subprocess.CalledProcessError as err: + print("ERROR called: ", *cmd, sep=" ") + print(f"Failed with: {err.returncode}") + sys.exit(err.returncode) + + +def build_libs(et_build_root: str, script_path: str): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "build_executorch.sh"), + f"--et_build_root={et_build_root}", + "--build_type=Release", + "--devtools", + "--etdump", + ] + ) + + +def build_pte( + et_build_root: str, + model_name: str, + target: str, + system_config: str, + memory_mode: str, + build_output: str, + no_intermediate: bool, + no_quantize: bool, +): + command_list = [ + "python3", + "-m", + "examples.arm.aot_arm_compiler", + "--delegate", + "--bundleio", + f"--model_name={model_name}", + f"--target={target}", + f"--output={build_output}", + ] + + if "vgf" != target: + command_list.append(f"--system_config={system_config}") + command_list.append(f"--memory_mode={memory_mode}") + + if not no_quantize: + command_list.append("--quantize") + + if not no_intermediate: + command_list.append(f"--intermediate={output}") + + run_external_cmd(command_list) + + pte_file_ending = "bpte" + pte_file = os.path.join( + output, f"{model_name}_arm_delegate_{args.target}.{pte_file_ending}" + ) + + return pte_file + + +def build_ethosu_runtime( + et_build_root: str, + script_path: str, + pte_file: str, + target: str, + system_config: str, + memory_mode: str, + extra_flags: str, + elf_build_path: str, +): + elf_build_path = os.path.join(elf_build_path, "cmake-out") + run_external_cmd( + [ + "bash", + os.path.join(script_path, "build_executor_runner.sh"), + f"--et_build_root={et_build_root}", + f"--pte={pte_file}", + "--bundleio", + "--etdump", + f"--target={target}", + "--build_type=Release", + f"--system_config={system_config}", + f"--memory_mode={memory_mode}", + f"--extra_build_flags=-DET_LOG_DUMP_OUTPUT=OFF {extra_flags}", + f"--output={elf_build_path}", + ] + ) + + elf_file = os.path.join(elf_build_path, "arm_executor_runner") + return elf_file + + +def run_elf_with_fvp(script_path: str, elf_file: str, target: str, timeout: int): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "run_fvp.sh"), + f"--elf={elf_file}", + f"--target={target}", + f"--timeout={timeout}", + ] + ) + + +def build_vkml_runtime( + et_build_root: str, + script_path: str, + extra_flags: str, + build_path: str, +): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "build_executor_runner_vkml.sh"), + f"--et_build_root={et_build_root}", + "--etdump", + "--bundleio", + "--build_type=Release", + f"--extra_build_flags=-DET_DUMP_OUTPUT=OFF {extra_flags}", + f"--output={build_path}", + ] + ) + + runner = os.path.join(build_path, "executor_runner") + return runner + + +def run_vkml(script_path: str, pte_file: str, runner_build_path: str, extra_flags: str): + run_external_cmd( + [ + "bash", + os.path.join(script_path, "run_vkml.sh"), + f"--model={pte_file}", + f"--build_path={runner_build_path}", + f"--optional_flags={extra_flags}", + ] + ) + + +if __name__ == "__main__": + total_start_time = time.perf_counter() + args = get_args() + script_path = os.path.join("backends", "arm", "scripts") + + if args.build_libs: + start_time = time.perf_counter() + build_libs(args.test_output, script_path) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] Build needed executorch libs" + ) + + if args.model: + model_name = args.model.split(" ")[0].split(";")[0] + if not model_name: + print("ERROR: Bad --model specified") + if not args.target: + print("ERROR: --model need --target to also be set") + + output = os.path.join( + args.test_output, f"{model_name}_arm_delegate_{args.target}" + ) + + start_time = time.perf_counter() + pte_file = build_pte( + args.test_output, + model_name, + args.target, + args.system_config, + args.memory_mode, + output, + args.no_intermediate, + args.no_quantize, + ) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] PTE file created: {pte_file}" + ) + + if "vgf" == args.target: + build_path = os.path.join( + output, f"{model_name}_arm_delegate_{args.target}" + ) + + start_time = time.perf_counter() + vkml_runner = build_vkml_runtime( + args.test_output, + script_path, + args.extra_flags, + build_path, + ) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] ELF file created: {vkml_runner}" + ) + + start_time = time.perf_counter() + run_vkml(script_path, pte_file, build_path, args.extra_runtime_flags) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] Tested VKML runner: {vkml_runner}" + ) + + elif "ethos-u" in args.target: + elf_build_path = os.path.join( + output, f"{model_name}_arm_delegate_{args.target}" + ) + + start_time = time.perf_counter() + elf_file = build_ethosu_runtime( + args.test_output, + script_path, + pte_file, + args.target, + args.system_config, + args.memory_mode, + args.extra_flags, + elf_build_path, + ) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] ELF file created: {elf_file}" + ) + + start_time = time.perf_counter() + run_elf_with_fvp(script_path, elf_file, args.target, args.timeout) + end_time = time.perf_counter() + print( + f"[Test model: {end_time - start_time:.2f} s] Tested elf on FVP {elf_file}" + ) + total_end_time = time.perf_counter() + print( + f"[Test model: {total_end_time - total_start_time:.2f} s total] Model: {model_name} on {args.target} -> PASS" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/__init__.py new file mode 100644 index 0000000..caafcc4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2024 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/analyze_output_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/analyze_output_utils.py new file mode 100644 index 0000000..527413e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/analyze_output_utils.py @@ -0,0 +1,346 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import tempfile +from typing import Any, cast, Sequence + +import torch +from executorch.backends.arm.test.runner_utils import ( + get_input_quantization_params, + get_output_quantization_params, +) + +from executorch.backends.test.harness.stages import StageType + +logger = logging.getLogger(__name__) + + +TensorLike = torch.Tensor | tuple[torch.Tensor, ...] + + +def _ensure_tensor(value: TensorLike) -> torch.Tensor: + if isinstance(value, torch.Tensor): + return value + if value and isinstance(value[0], torch.Tensor): + return value[0] + raise TypeError("Expected a Tensor or a non-empty tuple of Tensors") + + +def _print_channels( + result: torch.Tensor, + reference: torch.Tensor, + channels_close: Sequence[bool], + C: int, + H: int, + W: int, + rtol: float, + atol: float, +) -> str: + output_str = "" + exp = "000" + booldata = False + if reference.dtype == torch.bool or result.dtype == torch.bool: + booldata = True + + for c in range(C): + if channels_close[c]: + continue + if not booldata: + max_diff = torch.max(torch.abs(reference - result)) + exp = f"{max_diff:2e}"[-3:] + output_str += f"channel {c} (e{exp})\n" + else: + max_diff = torch.max(reference ^ result) + output_str += f"channel {c} (bool)\n" + + for y in range(H): + res = "[" + for x in range(W): + if torch.allclose(reference[c, y, x], result[c, y, x], rtol, atol): + if not booldata: + res += " . " + else: + res += " . " + else: + if not booldata: + diff = (reference[c, y, x] - result[c, y, x]) / 10 ** (int(exp)) + res += f"{diff: .2f} " + else: + diff = reference[c, y, x] ^ result[c, y, x] + res += " X " + + # Break early for large widths + if x == 16: + res += "..." + break + + res += "]\n" + output_str += res + + return output_str + + +def _print_elements( + result: torch.Tensor, + reference: torch.Tensor, + C: int, + H: int, + W: int, + rtol: float, + atol: float, +) -> str: + output_str = "" + for y in range(H): + res = "[" + for x in range(W): + result_channels = result[:, y, x] + reference_channels = reference[:, y, x] + + n_errors = 0 + for a, b in zip(result_channels, reference_channels): + if not torch.allclose(a, b, rtol, atol): + n_errors = n_errors + 1 + + if n_errors == 0: + res += ". " + else: + res += f"{n_errors} " + + # Break early for large widths + if x == 16: + res += "..." + break + + res += "]\n" + output_str += res + + return output_str + + +def print_error_diffs( # noqa: C901 + tester_or_result: Any, + result_or_reference: TensorLike, + reference: TensorLike | None = None, + # Force remaining args to be keyword-only to keep the two positional call patterns unambiguous. + *, + quantization_scale: float | None = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: float = 0, +) -> None: + """ + Prints the error difference between a result tensor and a reference tensor in NCHW format. + Certain formatting rules are applied to clarify errors: + + - Batches are only expanded if they contain errors. + -> Shows if errors are related to batch handling + - If errors appear in all channels, only the number of errors in each HW element are printed. + -> Shows if errors are related to HW handling + - If at least one channel is free from errors, or if C==1, errors are printed channel by channel + -> Shows if errors are related to channel handling or single errors such as rounding/quantization errors + + Example output of shape (3,3,2,2): + + ############################ ERROR DIFFERENCE ############################# + BATCH 0 + . + BATCH 1 + [. . ] + [. 3 ] + BATCH 2 + channel 1 (e-03) + [ 1.85 . ] + [ . 9.32 ] + + MEAN MEDIAN MAX MIN (error as % of reference output range) + 60.02% 55.73% 100.17% 19.91% + ########################################################################### + + + """ + if reference is None: + result = _ensure_tensor(cast(TensorLike, tester_or_result)) + reference_tensor = _ensure_tensor(result_or_reference) + else: + result = _ensure_tensor(result_or_reference) + reference_tensor = _ensure_tensor(reference) + + if result.shape != reference_tensor.shape: + raise ValueError( + f"Output needs to be of same shape: {result.shape} != {reference_tensor.shape}" + ) + shape = result.shape + rank = len(shape) + + if rank == 5: + N, C, D, H, W = shape + elif rank == 4: + N, C, H, W = shape + D = 1 + elif rank == 3: + C, H, W = shape + N, D = 1, 1 + elif rank == 2: + H, W = shape + N, C, D = 1, 1, 1 + elif rank == 1: + W = shape[0] + N, C, D, H = 1, 1, 1, 1 + elif rank == 0: + N = C = D = H = W = 1 + else: + raise ValueError("Invalid tensor rank") + + if rank < 3: + C = 1 + if rank < 2: + H = 1 + if rank < 1: + W = 1 + + if quantization_scale is not None: + atol += quantization_scale * qtol + + # Reshape tensors to 4D NCHW format, optionally folding depth into batch. + total_batches = N * D + result = torch.reshape(result, (total_batches, C, H, W)) + reference_tensor = torch.reshape(reference_tensor, (total_batches, C, H, W)) + + output_str = "" + for idx in range(total_batches): + batch_idx = idx // D if D > 0 else idx + depth_idx = idx % D if D > 0 else 0 + if D > 1: + output_str += f"BATCH {batch_idx} DEPTH {depth_idx}\n" + else: + output_str += f"BATCH {batch_idx}\n" + + result_batch = result[idx, :, :, :] + reference_batch = reference_tensor[idx, :, :, :] + + is_close = torch.allclose(result_batch, reference_batch, rtol, atol) + if is_close: + output_str += ".\n" + else: + channels_close: list[bool] = [False] * C + for c in range(C): + result_hw = result[idx, c, :, :] + reference_hw = reference_tensor[idx, c, :, :] + + channels_close[c] = torch.allclose(result_hw, reference_hw, rtol, atol) + + if any(channels_close) or len(channels_close) == 1: + output_str += _print_channels( + result[idx, :, :, :], + reference_tensor[idx, :, :, :], + channels_close, + C, + H, + W, + rtol, + atol, + ) + else: + output_str += _print_elements( + result[idx, :, :, :], + reference_tensor[idx, :, :, :], + C, + H, + W, + rtol, + atol, + ) + if reference_batch.dtype == torch.bool or result_batch.dtype == torch.bool: + mismatches = (reference_batch != result_batch).sum().item() + total = reference_batch.numel() + output_str += f"(BOOLEAN tensor) {mismatches} / {total} elements differ ({mismatches / total:.2%})\n" + + # Only compute numeric error metrics if tensor is not boolean + if reference_tensor.dtype != torch.bool and result.dtype != torch.bool: + reference_range = torch.max(reference_tensor) - torch.min(reference_tensor) + diff = torch.abs(reference_tensor - result).flatten() + diff = diff[diff.nonzero()] + if not len(diff) == 0: + diff_percent = diff / reference_range + output_str += "\nMEAN MEDIAN MAX MIN (error as % of reference output range)\n" + output_str += f"{torch.mean(diff_percent):<8.2%} {torch.median(diff_percent):<8.2%} {torch.max(diff_percent):<8.2%} {torch.min(diff_percent):<8.2%}\n" + + # Over-engineer separators to match output width + lines = output_str.split("\n") + line_length = [len(line) for line in lines] + longest_line = max(line_length) + title = "# ERROR DIFFERENCE #" + separator_length = max(longest_line, len(title)) + + pre_title_length = max(0, ((separator_length - len(title)) // 2)) + post_title_length = max(0, ((separator_length - len(title) + 1) // 2)) + start_separator = ( + "\n" + "#" * pre_title_length + title + "#" * post_title_length + "\n" + ) + output_str = start_separator + output_str + end_separator = "#" * separator_length + "\n" + output_str += end_separator + + logger.error(output_str) + + +def dump_error_output( + tester: Any, + reference_output: TensorLike, + stage_output: TensorLike, + quantization_scale: float | None = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: float = 0, +) -> None: + """ + Prints Quantization info and error tolerances, and saves the differing tensors to disc. + """ + # Capture assertion error and print more info + banner = "=" * 40 + "TOSA debug info" + "=" * 40 + logger.error(banner) + path_to_tosa_files = tester.compile_spec.get_intermediate_path() + + if path_to_tosa_files is None: + path_to_tosa_files = tempfile.mkdtemp(prefix="executorch_result_dump_") + + export_stage = tester.stages.get(StageType.EXPORT, None) + quantize_stage = tester.stages.get(StageType.QUANTIZE, None) + if export_stage is not None and quantize_stage is not None: + output_node = export_stage.artifact.graph_module.graph.output_node() + qp_input = get_input_quantization_params(export_stage.artifact) + qp_output = get_output_quantization_params(output_node) + logger.error(f"Input QuantArgs: {qp_input}") + logger.error(f"Output QuantArgs: {qp_output}") + + logger.error(f"{path_to_tosa_files=}") + import os + + torch.save( + stage_output, + os.path.join(path_to_tosa_files, "torch_tosa_output.pt"), + ) + torch.save( + reference_output, + os.path.join(path_to_tosa_files, "torch_ref_output.pt"), + ) + logger.error(f"{atol=}, {rtol=}, {qtol=}") + + +if __name__ == "__main__": + """This is expected to produce the example output of print_diff""" + torch.manual_seed(0) + a = torch.rand(3, 3, 2, 2) * 0.01 + b = a.clone().detach() + logger.info(b) + + # Errors in all channels in element (1,1) + a[1, :, 1, 1] = 0 + # Errors in (0,0) and (1,1) in channel 1 + a[2, 1, 1, 1] = 0 + a[2, 1, 0, 0] = 0 + + print_error_diffs(a, b) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/arm_tester.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/arm_tester.py new file mode 100644 index 0000000..66f90ea --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/arm_tester.py @@ -0,0 +1,1149 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import copy + +import logging +import shutil +import tempfile + +from collections import Counter, defaultdict +from pprint import pformat +from typing import ( + Any, + Callable, + cast, + Dict, + Iterable, + List, + no_type_check, + Optional, + Sequence, + Tuple, + Type, + Union, +) + +import executorch.backends.xnnpack.test.tester.tester as tester + +import torch.fx +import torch.utils._pytree as pytree + +import tosa_serializer as ts + +from executorch.backends.arm._passes.arm_pass_manager import ArmPassManager + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.ethosu import EthosUCompileSpec +from executorch.backends.arm.quantizer import get_symmetric_quantization_config +from executorch.backends.arm.test.runner_utils import ( + dbg_tosa_fb_to_json, + get_output_quantization_params, + TosaReferenceModelDispatch, +) + +from executorch.backends.arm.test.tester.analyze_output_utils import ( + dump_error_output, + print_error_diffs, +) +from executorch.backends.arm.test.tester.quantize import ArmQuantize as Quantize +from executorch.backends.arm.test.tester.serialize import Serialize + +from executorch.backends.arm.tosa import TosaSpecification +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.mapping import extract_tensor_meta + +from executorch.backends.arm.util._factory import ( + create_partitioner, + create_quantizer, + parse_compile_spec, +) +from executorch.backends.arm.vgf import VgfCompileSpec + +from executorch.backends.test.harness.error_statistics import ErrorStatistics +from executorch.backends.test.harness.stages import Stage, StageType +from executorch.backends.xnnpack.test.tester import ( + Partition as XnnpackPartitionStage, + Quantize as XnnpackQuantize, + Tester, + ToEdge as XnnpackToEdge, + ToEdgeTransformAndLower as XnnpackToEdgeTransformAndLower, + ToExecutorch as XnnpackToExecutorch, +) +from executorch.devtools.backend_debug import get_delegation_info + +from executorch.exir import ( + EdgeCompileConfig, + EdgeProgramManager, + ExecutorchProgramManager, + ExportedProgram, + to_edge_transform_and_lower, +) +from executorch.exir.backend.backend_api import validation_disabled +from executorch.exir.backend.operator_support import OperatorSupportBase +from executorch.exir.backend.partitioner import Partitioner +from executorch.exir.lowered_backend_module import LoweredBackendModule +from executorch.exir.pass_base import ExportPass +from executorch.exir.pass_manager import PassType +from executorch.exir.program._program import ( + _copy_module, + _update_exported_program_graph_module, +) +from tabulate import tabulate # type: ignore[import-untyped] + +from torch.export.graph_signature import ExportGraphSignature, InputSpec, OutputSpec +from torch.fx import Graph + +from torchao.quantization.pt2e.quantizer import QuantizationSpec, SharedQuantizationSpec +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + +logger = logging.getLogger(__name__) + + +def _dump_lowered_modules_artifact( + path_to_dump: Optional[str], + artifact: Union[EdgeProgramManager, ExecutorchProgramManager], + graph_module: torch.fx.GraphModule | None, +) -> None: + if graph_module is None: + logger.warning("No graph module available to dump lowered modules.") + return + + output = "Formated Graph Signature:\n" + output += _format_export_graph_signature( + artifact.exported_program().graph_signature + ) + + for node in graph_module.graph.nodes: + if node.op == "get_attr" and node.name.startswith("lowered_module_"): + lowered_module = getattr(graph_module, node.name) + assert isinstance( + lowered_module, LoweredBackendModule + ), f"Attribute {node.name} must be of type LoweredBackendModule." + + compile_spec = parse_compile_spec(lowered_module.compile_specs) + if isinstance(compile_spec, TosaCompileSpec): + tosa_fb = lowered_module.processed_bytes + to_print = dbg_tosa_fb_to_json(tosa_fb) + to_print = pformat(to_print, compact=True, indent=1) + output += f"\nTOSA deserialized {node.name}: \n{to_print}\n" + elif isinstance(compile_spec, EthosUCompileSpec): + vela_cmd_stream = lowered_module.processed_bytes + output += f"\nVela command stream {node.name}: \n{vela_cmd_stream!r}\n" + else: + logger.warning( + f"No TOSA nor Vela compile spec found in compile specs of {node.name}." + ) + continue + + if not output: + logger.warning("No output to print generated from artifact.") + return + + _dump_str(output, path_to_dump) + + +class Partition(tester.Partition): + def dump_artifact(self, path_to_dump: Optional[str]): + super().dump_artifact(path_to_dump) + artifact = cast(Optional[EdgeProgramManager], self.artifact) + graph_module = cast(Optional[torch.fx.GraphModule], self.graph_module) + if artifact is None: + logger.warning( + "Partition stage artifact missing; skipping lowered module dump." + ) + return + _dump_lowered_modules_artifact(path_to_dump, artifact, graph_module) + + +class ToEdgeTransformAndLower(tester.ToEdgeTransformAndLower): + def __init__( + self, + partitioners: Optional[List[Partitioner]] = None, + edge_compile_config: Optional[EdgeCompileConfig] = None, + constant_methods: Optional[Dict[str, Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + ): + super().__init__(partitioners, edge_compile_config) + self.constant_methods = constant_methods + self.transform_passes = transform_passes + + def dump_artifact(self, path_to_dump: Optional[str]): + super().dump_artifact(path_to_dump) + artifact = cast(Optional[EdgeProgramManager], self.artifact) + graph_module = cast(Optional[torch.fx.GraphModule], self.graph_module) + if artifact is None: + logger.warning( + "ToEdgeTransformAndLower stage artifact missing; skipping lowered module dump." + ) + return + _dump_lowered_modules_artifact(path_to_dump, artifact, graph_module) + + def run( + self, artifact: ExportedProgram, inputs=None, generate_etrecord: bool = False + ) -> None: + artifact_to_run = copy.deepcopy(artifact) + self.edge_dialect_program = to_edge_transform_and_lower( + artifact_to_run, + transform_passes=self.transform_passes, + compile_config=self.edge_compile_conf, + partitioner=self.partitioners, + constant_methods=self.constant_methods, + generate_etrecord=generate_etrecord, + ) + + +class ToExecutorch(tester.ToExecutorch): + def run_artifact(self, inputs): + with TosaReferenceModelDispatch(): + return super().run_artifact(inputs) + + +class RunPasses(tester.RunPasses): + @no_type_check + def __init__( + self, + pass_list: Optional[List[Type[PassType]]] = None, + pass_functions: Optional[List[Callable]] = None, + passes_with_exported_program: Optional[List[Type[ExportPass]]] = None, + ): + """Passes are run in the order they are passed: first pass_list, second pass_functions, + and lastly passes_with_exported_program.""" + self.pass_with_exported_program: Optional[List[Type[ExportPass]]] = ( + passes_with_exported_program + ) + + super().__init__(pass_list, pass_functions) + + def run( + self, artifact: Union[EdgeProgramManager, ExportedProgram], inputs=None + ) -> None: + if self.pass_with_exported_program is not None: + pass_functions = list(self.pass_functions or []) # type: ignore[has-type] + + # pass_function list from superclass expects functions that take in + # and return ExportedPrograms. + # Create a wrapper to fit pass_with_exported_program into this. + def wrap_ep_pass(ep_pass: Type[ExportPass]): + def wrapped_ep_pass(ep: ExportedProgram) -> ExportedProgram: + pass_instance = ep_pass(ep) # type: ignore[call-arg] + pass_result = pass_instance.call(ep.graph_module) + with validation_disabled(): + return _update_exported_program_graph_module( + ep, pass_result.graph_module + ) + + return wrapped_ep_pass + + pass_functions.extend( + [wrap_ep_pass(ep_pass) for ep_pass in self.pass_with_exported_program] + ) + self.pass_functions = pass_functions + super().run(artifact, inputs) + + +class InitialModel(Stage): + def __init__(self, model: torch.nn.Module): + self.model = model + + def stage_type(self) -> StageType: + return StageType.INITIAL_MODEL + + def run(self, artifact, inputs=None) -> None: + pass + + @property + def artifact(self) -> torch.nn.Module: + return self.model + + @property + def graph_module(self) -> None: + return None + + def artifact_str(self) -> str: + return str(self.model) + + def run_artifact(self, inputs): + return self.model.forward(*inputs) + + +class ArmTester(Tester): + def __init__( + self, + model: torch.nn.Module, + example_inputs: Tuple[Any, ...], + compile_spec: ArmCompileSpec, + tosa_ref_model_path: str | None = None, + dynamic_shapes: Optional[Tuple[Any]] = None, + constant_methods: Optional[Dict[str, Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + use_portable_ops: bool = False, + timeout: int = 600, + ): + """ + Args: + model (torch.nn.Module): The model to test + example_inputs (Tuple[torch.Tensor]): Example inputs to the model + compile_spec (ArmCompileSpec): The compile spec to use + """ + + self.transform_passes = transform_passes + self.constant_methods = constant_methods + self.compile_spec = compile_spec + super().__init__(model, example_inputs, dynamic_shapes) + self.pipeline[StageType.INITIAL_MODEL] = [ + StageType.QUANTIZE, + StageType.EXPORT, + ] + self.original_module.requires_grad_(False) + + # Initial model needs to be set as a *possible* but not yet added Stage, therefore add None entry. + self.stages[StageType.INITIAL_MODEL] = cast(Stage, None) + self._run_stage(InitialModel(self.original_module)) + self.use_portable_ops = use_portable_ops + self.timeout = timeout + + @no_type_check + def quantize( + self, + quantize_stage: Optional[XnnpackQuantize] = None, + ): + # Same stage type as parent but exposed via module alias + if quantize_stage is None: + quantizer = create_quantizer(self.compile_spec) + quantize_stage = Quantize( + quantizer, + get_symmetric_quantization_config(), + ) + return super().quantize(quantize_stage) + + @no_type_check + def to_edge( + self, + to_edge_stage: Optional[XnnpackToEdge] = None, + # Keep config keyword-only to avoid positional clashes with legacy calls. + *, + config: Optional[EdgeCompileConfig] = None, + ): + # Allow optional config override beyond base signature + if to_edge_stage is None: + to_edge_stage = tester.ToEdge(config) + else: + if config is not None: + to_edge_stage.edge_compile_conf = config + + return super().to_edge(to_edge_stage) + + @no_type_check + def partition(self, partition_stage: Optional[XnnpackPartitionStage] = None): + # Accept Arm-specific partition stage subclass + if partition_stage is None: + arm_partitioner = create_partitioner(self.compile_spec) + partition_stage = Partition(arm_partitioner) + return super().partition(partition_stage) + + @no_type_check + def to_edge_transform_and_lower( + self, + to_edge_and_lower_stage: Optional[XnnpackToEdgeTransformAndLower] = None, + generate_etrecord: bool = False, + # Force the optional tuning knobs to be keyword-only for readability/back-compat. + *, + partitioners: Optional[List[Partitioner]] = None, + edge_compile_config: Optional[EdgeCompileConfig] = None, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + ): + # Arm flow exposes extra stage wiring knobs + if transform_passes is not None: + raise RuntimeError( + "transform passes are given to ArmTester at construction." + ) + + if to_edge_and_lower_stage is None: + if partitioners is None: + operator_checks = ( + list(additional_checks) if additional_checks is not None else None + ) + arm_partitioner = create_partitioner(self.compile_spec, operator_checks) + partitioners = [arm_partitioner] + to_edge_and_lower_stage = ToEdgeTransformAndLower( + partitioners, + edge_compile_config, + constant_methods=self.constant_methods, + transform_passes=self.transform_passes, + ) + else: + if partitioners is not None: + to_edge_and_lower_stage.partitioners = partitioners + if edge_compile_config is not None: + to_edge_and_lower_stage.edge_compile_conf = edge_compile_config + return super().to_edge_transform_and_lower( + to_edge_and_lower_stage, generate_etrecord=generate_etrecord + ) + + @no_type_check + def to_executorch(self, to_executorch_stage: Optional[XnnpackToExecutorch] = None): + # Allow custom ExecuTorch stage subclass + if to_executorch_stage is None: + to_executorch_stage = ToExecutorch() + return super().to_executorch(to_executorch_stage) + + @no_type_check + def serialize( + self, + serialize_stage: Optional[Serialize] = None, + # Keep timeout keyword-only so positional usage matches the base class. + *, + timeout: int = 480, + ): + if serialize_stage is None: + serialize_stage = Serialize( + compile_spec=self.compile_spec, + module=self.original_module, + use_portable_ops=self.use_portable_ops, + timeout=self.timeout, + ) + assert ( + self.compile_spec.get_intermediate_path() is not None + ), "Can't dump serialized file when compile specs do not contain an artifact path." + + return super().serialize(serialize_stage) + + def is_quantized(self) -> bool: + return self.stages[StageType.QUANTIZE] is not None + + def run_method_and_compare_outputs( + self, + stage: Optional[StageType] = None, + inputs: Optional[Tuple[torch.Tensor, ...]] = None, + num_runs: int = 1, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 0, + statistics_callback: Callable[[ErrorStatistics], None] | None = None, + # Preserve positional compatibility while keeping new flags keyword-only. + *, + error_callbacks: Optional[Sequence[Callable[..., None]]] = None, + run_eager_mode: bool = False, + ): + """ + Compares the run_artifact output of 'stage' with the output of a reference stage. + If the model is quantized, the reference stage is the Quantize stage output. + Otherwise, the reference stage is the initial pytorch module. + + Asserts that the outputs are equal (within tolerances). + Returns self to allow the function to be run in a test chain. + + Args: + stage: (Optional[str]): The name of the stage to compare. + The default is the latest run stage. + inputs (Optional[Tuple[torch.Tensor]]): Allows you to input custom input data. + The default is random data. + """ + + # backward-compatible ordering (accept inputs as the first positional argument) + if inputs is None and isinstance(stage, tuple): + if all(isinstance(arg, torch.Tensor) for arg in stage): + inputs = cast(Tuple[torch.Tensor, ...], stage) + stage = None + + if not run_eager_mode: + edge_stage = self.stages[StageType.TO_EDGE] + if edge_stage is None: + edge_stage = self.stages[StageType.TO_EDGE_TRANSFORM_AND_LOWER] + assert ( + edge_stage is not None + ), "To compare outputs, at least the ToEdge or ToEdgeTransformAndLower stage needs to be run." + else: + # Run models in eager mode. We do this when we want to check that the passes + # are numerically accurate and the exported graph is correct. + export_stage = self.stages[StageType.EXPORT] + assert ( + export_stage is not None + ), "To compare outputs in eager mode, the model must be at Export stage" + + stage = stage or self.cur + if stage is None: + raise RuntimeError("No stage has been executed yet.") + test_stage = self.stages[stage] + is_quantized = self.is_quantized() + + if is_quantized: + reference_stage = self.stages[StageType.QUANTIZE] + else: + reference_stage = self.stages[StageType.INITIAL_MODEL] + + exported_stage = self.stages[StageType.EXPORT] + exported_program = cast(ExportedProgram, exported_stage.artifact) + output_node = exported_program.graph_module.graph.output_node() + output_qparams = get_output_quantization_params(output_node) + + quantization_scales = [] + for node in output_qparams: + quantization_scales.append(getattr(output_qparams[node], "scale", None)) + + logger.info( + f"Comparing Stage '{test_stage.stage_type()}' with Stage '{reference_stage.stage_type()}'" + ) + + # Loop inputs and compare reference stage with the compared stage. + number_of_runs = 1 if inputs is not None else num_runs + + for run_iteration in range(number_of_runs): + reference_input = inputs if inputs else next(self.generate_random_inputs()) + + # Avoid issues with inplace operators + test_input = copy.deepcopy(reference_input) + original_input = copy.deepcopy(reference_input) + + input_shapes = [ + generated_input.shape if hasattr(generated_input, "shape") else (1,) + for generated_input in reference_input + ] + input_shape_str = ", ".join([str(list(i)) for i in input_shapes]) + logger.info(f"Run #{run_iteration}, input shapes: {input_shape_str}") + + reference_outputs, _ = pytree.tree_flatten( + reference_stage.run_artifact(reference_input) + ) + if run_eager_mode: + # Run exported module directly + eager_output, _ = self._calculate_reference_output( + exported_program, test_input + ) + test_outputs, _ = pytree.tree_flatten(eager_output) + else: + # Run lowered model with target + test_outputs, _ = pytree.tree_flatten( + test_stage.run_artifact(test_input) + ) + + logger.info(f"\n Input: {original_input}") + logger.info(f"\n Ref output: {reference_outputs}") + logger.info(f"\nTest output: {test_outputs}") + + for reference_output, test_output, quantization_scale in zip( + reference_outputs, test_outputs, quantization_scales + ): + self._compare_outputs( + reference_output, + test_output, + quantization_scale, + atol, + rtol, + qtol, + statistics_callback=statistics_callback, + error_callbacks=error_callbacks, + ) + + return self + + def _get_output_qspec_from_node( + self, node: torch.fx.Node + ) -> QuantizationSpec | None: + if Q_ANNOTATION_KEY not in node.meta: + return None + annotation = node.meta[Q_ANNOTATION_KEY] + # If annotation.output_qspec is a SharedQuantizationSpec, we need to find + # the actual QuantizationSpec from one of the inputs. + if isinstance(annotation.output_qspec, SharedQuantizationSpec): + # First try to find a non-shared qspec from the inputs. + annotation_qspec = [ + qspec + for qspec in annotation.input_qspec_map.values() + if not isinstance(qspec, SharedQuantizationSpec) + ] + # If none of the inputs have a non-shared qspec, we need to + # find the source node of the shared qspec. + if len(annotation_qspec) == 0: + edge_or_node = annotation.output_qspec.edge_or_node + if isinstance(edge_or_node, tuple): + source_node = edge_or_node[0] + else: + source_node = edge_or_node + annotation_qspec = [source_node.meta[Q_ANNOTATION_KEY].output_qspec] + annotation_qspec = annotation_qspec[0] + else: + annotation_qspec = annotation.output_qspec + + return annotation_qspec + + def _get_input_qspecs_from_node( + self, node: torch.fx.Node + ) -> List[QuantizationSpec | None]: + if Q_ANNOTATION_KEY not in node.meta: + return [None] + annotation = node.meta[Q_ANNOTATION_KEY] + input_qspec_map = annotation.input_qspec_map + found_qspecs = [] + if len(input_qspec_map) == 0: + return [None] + for spec in input_qspec_map.values(): + # If spec is a SharedQuantizationSpec, we need to find + # the actual QuantizationSpec. + if isinstance(spec, SharedQuantizationSpec): + # First try to find a non-shared qspec from the inputs. + annotation_qspec = [ + qspec + for qspec in input_qspec_map.values() + if not isinstance(qspec, SharedQuantizationSpec) + ] + # If none of the inputs have a non-shared qspec, we need to + # find the source node of the shared qspec. + if len(annotation_qspec) == 0: + edge_or_node = annotation.output_qspec.edge_or_node + if isinstance(edge_or_node, tuple): + source_node = edge_or_node[0] + else: + source_node = edge_or_node + annotation_qspec = [source_node.meta[Q_ANNOTATION_KEY].output_qspec] + found_qspecs.append(annotation_qspec[0]) + else: + found_qspecs.append(spec) + + return found_qspecs + + def _check_input_qspecs(self, graph: Graph, input_qspecs): + if input_qspecs is None: + return + found_qspecs = [] + for node in graph.nodes: + if node.op != "placeholder": + continue + annotation_qspec = self._get_output_qspec_from_node(node) + found_qspecs.append(annotation_qspec) + found_qspecs_counter = Counter(found_qspecs) + for qspec in input_qspecs: + # check that each expected qspec is found + if qspec not in found_qspecs_counter: + raise AssertionError( + f"Expected to find input quantization annotation {qspec}, but it was not found. " + f"Found annotations: {found_qspecs_counter}" + ) + # check that number of occurrences of each qspec matches expected + if found_qspecs_counter[qspec] != input_qspecs[qspec]: + raise AssertionError( + f"Expected to find {input_qspecs[qspec]} instances of input quantization annotation {qspec}, but " + f"found {found_qspecs_counter[qspec]} instances." + ) + + def _check_output_qspecs(self, graph: Graph, output_qspecs): + if output_qspecs is None: + return + found_qspecs = [] + output_node = graph.output_node() + annotation_qspec = self._get_input_qspecs_from_node(output_node) + found_qspecs.extend(annotation_qspec) + found_qspecs_counter = Counter(found_qspecs) + for qspec in output_qspecs: + # check that each expected qspec is found + if qspec not in found_qspecs_counter: + raise AssertionError( + f"Expected to find output quantization annotation {qspec}, but it was not found. " + f"Found annotations: {found_qspecs_counter}" + ) + # check that number of occurrences of each qspec matches expected + if found_qspecs_counter[qspec] != output_qspecs[qspec]: + raise AssertionError( + f"Expected to find {output_qspecs[qspec]} instances of output quantization annotation {qspec}, but " + f"found {found_qspecs_counter[qspec]} instances." + ) + + def _check_qspecs(self, graph: Graph, quantization_annotations): + if quantization_annotations is None: + return self + + quantization_annotations_found: List[Tuple[str, QuantizationSpec | None]] = [] + for node in graph.nodes: + if node.op != "call_function": + continue + quantization_annotations_found.append( + (str(node.target), self._get_output_qspec_from_node(node)) + ) + + # Counter: (target, qspec) -> count + quantization_annotations_found_counter = Counter(quantization_annotations_found) + # Convert counter to Dict[target, Dict[qspec, count]] + quantization_annotations_found_dict: Dict[ + str, Dict[QuantizationSpec | None, int] + ] = defaultdict(dict) + for (target, qspec), count in quantization_annotations_found_counter.items(): + quantization_annotations_found_dict[target][qspec] = count + + for target, qspecs in quantization_annotations.items(): + # check if target is in found annotations + if target not in quantization_annotations_found_dict: + raise AssertionError( + f"Expected to find quantization annotation for operator {target}, but it was not found." + ) + for qspec in qspecs: + # check if qspec is in found annotations for target + if qspec not in quantization_annotations_found_dict[target]: + raise AssertionError( + f"Expected to find quantization annotation {qspec} for operator {target}, but it was not found. " + f"Found annotations: {quantization_annotations_found_dict[target]}" + ) + # check that number of occurrences of each qspec matches expected + if quantization_annotations_found_dict[target][qspec] != qspecs[qspec]: + raise AssertionError( + f"Expected to find {qspecs[qspec]} instances of quantization annotation {qspec} for operator " + f"{target}, but found {quantization_annotations_found_dict[target][qspec]} instances." + ) + + def check_quantization_annotation( + self, + quantization_annotations: Optional[ + Dict[str, Dict[QuantizationSpec | None, int]] + ] = None, + input_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + output_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + ): + """ + Check the quantization annotations in the graph of a quantized model. + + Args: + quantization_annotations: A dictionary mapping operator names to a dictionary of + QuantizationSpecs and their expected counts. + If None, the check is skipped. + input_qspecs: A dictionary of expected input QuantizationSpecs and their counts. + If None, the check is skipped. + output_qspecs: A dictionary of expected output QuantizationSpecs and their counts. + If None, the check is skipped. + + Returns self for daisy-chaining. + """ + if not self.is_quantized(): + raise RuntimeError( + f"{self.check_quantization_annotation.__name__} should be called after quantization stage." + ) + + graph = self.get_graph(StageType.QUANTIZE) + + self._check_input_qspecs(graph, input_qspecs) + self._check_output_qspecs(graph, output_qspecs) + self._check_qspecs(graph, quantization_annotations) + return self + + def get_graph(self, stage: StageType | None = None) -> Graph: + if stage is None: + stage = self.cur + if stage is None: + raise RuntimeError("No stage has been executed yet.") + artifact = self.get_artifact(stage) + if ( + self.cur == StageType.TO_EDGE + or self.cur == StageType.PARTITION + or self.cur == StageType.TO_EDGE_TRANSFORM_AND_LOWER + ): + graph = artifact.exported_program().graph + elif self.cur == StageType.EXPORT or self.cur == StageType.QUANTIZE: + graph = artifact.graph + else: + raise RuntimeError( + "Can only get a graph from Quantize, ToEdge, Export, and Partition stages." + ) + + return graph + + def dump_operator_distribution( + self, + path_to_dump: Optional[str] = None, + print_table: bool = True, + include_dtypes: bool = True, + ): + """Dump the distribution of operators in the current stage. + In the partition stage, additional information is included such as the number of + delegates and the distribution of TOSA operators. + Set parameter print_table to False to dump in a parseable format. + + + Returns self for daisy-chaining. + """ + line = "#" * 10 + to_print = f"\n{line} {self.cur} Operator Distribution {line}\n" + + if self.cur in ( + StageType.PARTITION, + StageType.TO_EDGE_TRANSFORM_AND_LOWER, + ): + graph_module = self.get_artifact().exported_program().graph_module + delegation_info = get_delegation_info(graph_module) + op_dist = _get_tosa_operator_distribution(graph_module, include_dtypes) + if print_table: + aten_op_dist = delegation_info.get_operator_delegation_dataframe() + to_print += "Aten operators:\n" + _format_dict( + dict(aten_op_dist), print_table + ) + + if include_dtypes: + op_dist_dict = { + "Operator": [op_type[0] for op_type, _ in op_dist], + "Dtype": [op_type[1] for op_type, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + op_dist_dict = { + "Operator": [op for op, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + if include_dtypes: + op_dtype_dist_dict: Dict[str, Dict[str, int]] = defaultdict(dict) + for op_dtype, count in op_dist: + op = op_dtype[0] + dtype = op_dtype[1] + op_dtype_dist_dict[op].update({dtype: count}) + op_dist_dict = dict(op_dtype_dist_dict) + else: + op_dist_dict = dict(op_dist) # type: ignore[arg-type] + to_print += "\nTOSA operators:\n" + _format_dict(op_dist_dict, print_table) + to_print += "\n" + delegation_info.get_summary() + else: + graph = self.get_graph(self.cur) + if include_dtypes: + op_dist = _get_operator_dtype_distribution(graph) + else: + op_dist = _get_operator_distribution(graph) + if print_table: + if include_dtypes: + op_dist_dict = { + "Operator": [op_dtype[0] for op_dtype, _ in op_dist], + "Dtype": [op_dtype[1] for op_dtype, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + op_dist_dict = { + "Operator": [op for op, _ in op_dist], + "Count": [count for _, count in op_dist], + } + else: + if include_dtypes: + op_dtype_dist_dict = defaultdict(dict) + for op_dtype, count in op_dist: + op = op_dtype[0] + dtype = op_dtype[1] + op_dtype_dist_dict[op].update({dtype: count}) + op_dist_dict = dict(op_dtype_dist_dict) + else: + op_dist_dict = dict(op_dist) # type: ignore[arg-type] + + to_print += _format_dict(op_dist_dict, print_table) + "\n" + + _dump_str(to_print, path_to_dump) + + return self + + def dump_dtype_distribution( + self, path_to_dump: Optional[str] = None, print_table: bool = True + ): + """Dump a the distributions of dtypes of nodes and placeholders in the current stage. + Set parameter print_table to False to dump in a parseable format. + + Returns self for daisy-chaining. + """ + + line = "#" * 10 + to_print = f"{line} {self.cur} Placeholder Dtype Distribution {line}\n" + + graph = self.get_graph(self.cur) + tosa_spec = self.compile_spec.tosa_spec + dtype_dist_placeholders, dtype_dirst_tensors = _get_dtype_distribution( + graph, tosa_spec + ) + all_dtypes = set(dtype_dist_placeholders.keys()) | set( + dtype_dirst_tensors.keys() + ) + dtype_dist: dict[str, Any] + if print_table: + dtype_dist = { + "Dtype": all_dtypes, + "Placeholder Count": [ + ( + dtype_dist_placeholders[key] + if key in dtype_dist_placeholders + else 0 + ) + for key in all_dtypes + ], + "Tensor Count": [ + (dtype_dirst_tensors[key] if key in dtype_dirst_tensors else 0) + for key in all_dtypes + ], + } + else: + combined_counts = dtype_dist_placeholders + dtype_dirst_tensors + dtype_dist = {key: combined_counts[key] for key in combined_counts} + to_print += _format_dict(dtype_dist, print_table) + "\n" + _dump_str(to_print, path_to_dump) + return self + + def run_transform_for_annotation_pipeline( + self, stage: StageType | None = None + ) -> torch.fx.GraphModule: + """Run transform_for_annotation_pipeline on exported program to ensure + passes do not break the initial model before quantization. + + There are caveats to this however. As we register buffers to the graph modules + the resulting exported graph can fail. Use this only to compare numerical correctness + in eager mode. + + Returns exported program with passes applied. + """ + + if stage is None: + stage = self.cur + if stage is None: + raise RuntimeError("No stage has been executed yet.") + # We need to clone the artifact in order to ensure that the state_dict is preserved after passes are run. + artifact = self.get_artifact(stage) + if self.cur == StageType.EXPORT: + new_gm = ArmPassManager( + self.compile_spec + ).transform_for_annotation_pipeline(graph_module=artifact.graph_module) + else: + raise RuntimeError("Can only run passes on Export stage.") + _copy_module(artifact.graph_module, new_gm) + return artifact + + @staticmethod + def _calculate_reference_output( + program: ExportedProgram, inputs: Tuple[Any, ...] + ) -> Tuple[torch.Tensor, Optional[float]]: + """ + Note: I'd prefer to use the base class method here, but since it use the + exported program, I can't. The partitioner stage clears the state_dict + of the exported program, which causes an issue when evaluating the + module. + """ + + module = program.module() + return module.forward(*inputs), None + + @no_type_check + def _compare_outputs( + self, + reference_output, + stage_output, + quantization_scale=None, + atol=1e-03, + rtol=1e-03, + qtol=0, + statistics_callback: Callable[[ErrorStatistics], None] | None = None, + # Extra debugging hooks are keyword-only to keep the signature stable. + *, + error_callbacks: Optional[Sequence[Callable[..., None]]] = None, + ): + # Accept extra error callback hook for debugging + try: + super()._compare_outputs( + reference_output, + stage_output, + quantization_scale, + atol, + rtol, + qtol, + statistics_callback=statistics_callback, + ) + except AssertionError as e: + callbacks = ( + list(error_callbacks) + if error_callbacks is not None + else [print_error_diffs, dump_error_output] + ) + for callback in callbacks: + callback( + self, + stage_output, + reference_output, + quantization_scale=quantization_scale, + atol=1e-03, + rtol=1e-03, + qtol=0, + ) + raise e + + def __del__(self): + intermediate_path = self.compile_spec.get_intermediate_path() + if not intermediate_path: + return + if len(tempdir := tempfile.gettempdir()) > 0: + if intermediate_path.startswith(tempdir): + shutil.rmtree(intermediate_path, ignore_errors=True) + + def check_dtype_count(self, dtype_dict: Dict[str, Dict[str, int]]): + if self.cur in ( + StageType.PARTITION, + StageType.TO_EDGE_TRANSFORM_AND_LOWER, + ): + graph_module = self.get_artifact().exported_program().graph_module + op_dist = _get_tosa_operator_distribution(graph_module, include_dtypes=True) + op_dist_dict: Dict[str, Dict[str, int]] = defaultdict(dict) + for op_dtype, count in op_dist: + if isinstance(op_dtype, str): + raise ValueError( + f"Expected {_get_tosa_operator_distribution.__name__} to return " + "Tuple[Tuple[str, str], int]." + ) + else: + op, dtype = op_dtype + + op_dist_dict[op].update({dtype: count}) + for op in dtype_dict.keys(): + if op not in op_dist_dict: + raise RuntimeError(f"Could not find op {op}.") + for dtype, count in dtype_dict[op].items(): + dtype_count = op_dist_dict[op].setdefault(dtype, 0) + if dtype_count != count: + raise RuntimeError( + f"Expected {count} occurencies of {op=}, {dtype=} but found {dtype_count}." + ) + + else: + + raise NotImplementedError(f"Cannot check dtypes for stage {self.cur}") + + +def _get_dtype_distribution( + graph: Graph, tosa_spec: TosaSpecification +) -> tuple[Counter[str], Counter[str]]: + """Counts the occurences of placeholder and call_function dtypes in a graph. + The result is a tuple of Counters (placeholder_distribution, call_function_distribution) + """ + placeholder_dtypes: list[str] = [] + call_function_dtypes: list[str] = [] + for node in graph.nodes: + if node.op == "placeholder": + placeholder_dtypes.append(str(node.meta["val"].dtype)) + if node.op == "call_function": + if "val" in node.meta and isinstance(node.meta["val"], torch.Tensor): + dtype, _, _ = extract_tensor_meta(node.meta, tosa_spec) + call_function_dtypes.append(ts.DTypeNames[dtype]) + return Counter(placeholder_dtypes), Counter(call_function_dtypes) + + +def _get_operator_distribution(graph: Graph) -> List[Tuple[str, int]]: + """Counts the occurences of operator names in a graph. + The result is a sorted list [('operator name':'number of nodes')] + """ + return sorted( + Counter( + [ + str(node.target) + for node in list(graph.nodes) + if node.op == "call_function" + ] + ).items() + ) + + +def _get_operator_dtype_distribution(graph: Graph) -> List[Tuple[Tuple[str, str], int]]: + """Counts the occurences of operator names and dtype pairs in a graph. + The result is a sorted list[(('operator name','dtype'),'number of nodes')] + """ + target_dtype_pairs = [] + for node in graph.nodes: + if node.op != "call_function": + continue + if "val" in node.meta and isinstance(node.meta["val"], torch.Tensor): + dtype = str(node.meta["val"].dtype) + else: + dtype = "UNKNOWN" + target_dtype_pairs.append((str(node.target), dtype)) + return sorted(Counter(target_dtype_pairs).items()) + + +def _format_export_graph_signature(signature: ExportGraphSignature) -> str: + def specs_dict(specs: Sequence[InputSpec | OutputSpec], title: str): + _dict: dict[str, list] = {title: [], "arg": [], "kind": [], "target": []} + for i, spec in enumerate(specs): + _dict[title].append(i) + _dict["arg"].append(spec.arg) + _dict["kind"].append(spec.kind) + _dict["target"].append(spec.target if spec.target else "-") + return _dict + + input_dict = specs_dict(signature.input_specs, "Inputs") + output_dict = specs_dict(signature.output_specs, "Outputs") + + return f"{_format_dict(input_dict)}\n{_format_dict(output_dict)}" + + +def _get_tosa_operator_distribution( + graph_module: torch.fx.GraphModule, include_dtypes=False +) -> list[Tuple[str, int]] | list[Tuple[Tuple[str, str], int]]: + """Counts the occurences of operator names of all lowered modules containing + a TOSA flatbuffer. + The result is a string with the operator distribution or an error message. + """ + id = 0 + unknown_dtype_str = "UNKNOWN" + op_list = [] + while lowered_module := getattr(graph_module, f"lowered_module_{id}", None): + compile_spec = parse_compile_spec(lowered_module.compile_specs) + if isinstance(compile_spec, TosaCompileSpec): + tosa_fb = lowered_module.processed_bytes + tosa_json = dbg_tosa_fb_to_json(tosa_fb) + for region in tosa_json["regions"]: + for block in region["blocks"]: + for operator in block["operators"]: + op = operator["op"] + if include_dtypes: + outputs = operator.get("outputs", []) + if outputs == []: + op_list.append((op, unknown_dtype_str)) + continue + tensor_block = block.get("tensors", {}) + tensors_with_matching_name = [ + t for t in tensor_block if t["name"] == outputs[0] + ] + dtype = ( + tensors_with_matching_name[0]["type"] + if len(tensors_with_matching_name) > 0 + else unknown_dtype_str + ) + op_list.append((op, dtype)) + else: + op_list.append(op) + + elif isinstance(compile_spec, EthosUCompileSpec): + raise NotImplementedError( + "Can not get operator distribution for Vela command stream." + ) + elif isinstance(compile_spec, VgfCompileSpec): + raise NotImplementedError("Can not get operator distribution for VGF.") + else: + raise NotImplementedError( + f"Unknown output format '{compile_spec.get_output_format()}'." + ) + id += 1 + if id == 0: + raise ValueError( + "No delegate with name 'lowered_module_0 found in graph module." + ) + return sorted(Counter(op_list).items()) + + +def _dump_str(to_print: str, path_to_dump: Optional[str] = None): + if path_to_dump: + with open(path_to_dump, "a") as fp: + fp.write(to_print) + else: + print(to_print) + + +def _format_dict(to_print: dict, print_table: bool = True) -> str: + if isinstance(list(to_print.items())[0], Iterable) and print_table: + return tabulate( + to_print, headers="keys", tablefmt="fancy_grid", maxcolwidths=35 + ) + else: + return pformat(to_print, compact=True, indent=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/quantize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/quantize.py new file mode 100644 index 0000000..18ecd40 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/quantize.py @@ -0,0 +1,43 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Optional, Tuple + +import torch +from executorch.backends.arm.quantizer import TOSAQuantizer +from executorch.backends.test.harness.stages.quantize import Quantize + +from executorch.backends.transforms.duplicate_dynamic_quant_chain import ( + DuplicateDynamicQuantChainPass, +) + +from torch.export import export + + +class ArmQuantize(Quantize): + + def run( + self, artifact: torch.nn.Module, inputs: Optional[Tuple[torch.Tensor]] + ) -> None: + assert inputs is not None + if self.is_qat: + artifact.train() + captured_graph = export(artifact, inputs, strict=True).module() + + if not isinstance(self.quantizer, TOSAQuantizer): + raise ValueError("ArmQuantizer can only run with TOSAQuantizer.") + + if self.calibration_samples is not None: + converted = self.quantizer.quantize_with_submodules( + captured_graph, self.calibration_samples, bool(self.is_qat) # type: ignore + ) + else: + converted = self.quantizer.quantize_with_submodules( + captured_graph, [inputs], bool(self.is_qat) + ) + + DuplicateDynamicQuantChainPass()(converted) + + self.converted_graph = converted diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/serialize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/serialize.py new file mode 100644 index 0000000..33e57cc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/serialize.py @@ -0,0 +1,78 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from typing import Optional + +import executorch.backends.xnnpack.test.tester.tester as tester + +import torch.fx + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec + +from executorch.backends.arm.test.runner_utils import ( + get_elf_path, + get_target_board, + run_target, +) + +from executorch.exir import ExecutorchProgramManager +from torch.utils._pytree import tree_flatten + + +logger = logging.getLogger(__name__) + + +class Serialize(tester.Serialize): + def __init__( + self, + compile_spec: ArmCompileSpec, + module: Optional[torch.nn.Module], + use_portable_ops: bool = False, + timeout: int = 120, + ): + """ + Args: + compile_spec: CompileSpecs to be used for serialization. + module: Original Module to be used for serialization. Optional - can be used for reference output generation. + portable_ops: If True tests with compiled in portable ops, default is to test without this to get error if not fully delegated + timeout: Timeout for fvp. Default is 120 seconds. + """ + super().__init__() + self.module = module + self.timeout = timeout + self.executorch_program_manager: ExecutorchProgramManager | None + self.compile_spec = compile_spec + self.use_portable_ops = use_portable_ops + + def run(self, artifact: ExecutorchProgramManager, inputs=None) -> None: + super().run(artifact, inputs) + # Keep the entire ExecutorchProgramManager for execution. + self.executorch_program_manager = artifact + + def run_artifact(self, inputs): + if self.executorch_program_manager is None: + raise RuntimeError( + "Tried running artifact from Serialize stage without running the stage." + ) + inputs_flattened, _ = tree_flatten(inputs) + intermediate_path = self.compile_spec.get_intermediate_path() + target_board = get_target_board(self.compile_spec) + elf_path = get_elf_path(target_board, self.use_portable_ops) + + if not os.path.exists(elf_path): + raise FileNotFoundError( + f"Did not find build arm_executor_runner in path {elf_path}, run setup_testing.sh?" + ) + + return run_target( + self.executorch_program_manager, + inputs_flattened, + intermediate_path, + target_board, + elf_path, + self.timeout, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/test_pipeline.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/test_pipeline.py new file mode 100644 index 0000000..3285d54 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/test/tester/test_pipeline.py @@ -0,0 +1,1190 @@ +# Copyright 2025-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import warnings as _warnings + +from typing import ( + Any, + Callable, + Dict, + Generic, + List, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, +) + +import torch +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.ethosu import EthosUCompileSpec + +from executorch.backends.arm.quantizer import ( + EthosUQuantizer, + get_symmetric_a16w8_quantization_config, + get_symmetric_quantization_config, + TOSAQuantizer, + VgfQuantizer, +) +from executorch.backends.arm.test import common, conftest +from executorch.backends.arm.test.tester.arm_tester import ArmTester, RunPasses + +from executorch.backends.arm.test.tester.quantize import ArmQuantize as Quantize +from executorch.backends.arm.tosa.specification import ( + TosaLoweringContext, + TosaSpecification, +) + +from executorch.backends.arm.util._factory import create_quantizer +from executorch.exir.pass_base import ExportPass +from torch._export.pass_base import PassType +from torchao.quantization.pt2e.quantizer import QuantizationSpec + +logger = logging.getLogger(__name__) +T = TypeVar("T", bound=Tuple[Any, ...]) +""" Generic type used for test data in the pipeline. Depends on which type the operator expects.""" + + +def _require_tosa_version() -> str: + version = conftest.get_option("tosa_version") + if not isinstance(version, str): + raise TypeError(f"TOSA version option must be a string, got {type(version)}.") + return version + + +def _has_quantizable_inputs(test_data: T) -> bool: + for data in test_data: + if isinstance(data, torch.Tensor) and data.is_floating_point(): + return True + return False + + +class PipelineStage: + """Container for a pipeline stage (callable plus arguments).""" + + def __init__(self, func: Callable, id: str, *args, **kwargs): + self.id: str = id + self.func: Callable = func + self.args = args + self.kwargs = kwargs + self.is_called = False + + def __call__(self): + if not self.is_called: + self.func(*self.args, **self.kwargs) + else: + raise RuntimeError(f"{self.id} called twice.") + self.is_called = True + + def update(self, *args, **kwargs): + if not self.is_called: + self.args = args + self.kwargs = kwargs + else: + raise RuntimeError(f"{self.id} args updated after being called.") + + +class BasePipeline(Generic[T]): + """ + The BasePipeline defines a list of stages to be applied to a torch.nn.module for lowering it + in the Arm backend. To be inherited and adjusted for particular targets. Importantly, the + pipeline list can be modified before running the pipeline to support various pipeline extensions + and debugging usecases. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + aten_ops: Aten dialect ops expected to be found in the graph after export. + compile_spec: The compile spec used in the lowering process. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge if not using + use_edge_to_transform_and_lower. + use_edge_to_transform_and_lower: Selects betweeen two possible routes for lowering: + tester.to_edge_transform_and_lower() + or + tester.to_edge().check(exir_ops).partition() + """ + + @staticmethod + def _normalize_ops(ops: str | Sequence[str] | None) -> list[str]: + if ops is None: + return [] + if isinstance(ops, str): + return [ops] + return list(ops) + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_ops: str | Sequence[str] | None, + compile_spec: ArmCompileSpec, + exir_ops: str | Sequence[str] | None = None, + use_to_edge_transform_and_lower: bool = True, + dynamic_shapes: Optional[Tuple[Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + ): + self.tester = ArmTester( + module, + example_inputs=test_data, + compile_spec=compile_spec, + dynamic_shapes=dynamic_shapes, + transform_passes=transform_passes, + ) + + self.aten_ops = self._normalize_ops(aten_ops) + self.exir_ops = self._normalize_ops(exir_ops) + self.test_data = test_data + self._stages: list[PipelineStage] = [] + + self.add_stage(self.tester.export) + self.add_stage(self.tester.check, self.aten_ops, suffix="aten") + if use_to_edge_transform_and_lower: + self.add_stage(self.tester.to_edge_transform_and_lower) + else: + self.add_stage(self.tester.to_edge) + self.add_stage(self.tester.check, self.exir_ops, suffix="exir") + self.add_stage(self.tester.partition) + self.add_stage(self.tester.check_not, self.exir_ops, suffix="exir") + self.add_stage( + self.tester.check_count, + {"torch.ops.higher_order.executorch_call_delegate": 1}, + suffix="exir", + ) + self.add_stage(self.tester.to_executorch) + + def add_stage(self, func: Callable, *args, **kwargs): + """ + Adds a stage defined by a function with args and kwargs. By default appends to the pipeline. + For stages which may be added multiple times to a pipeline, s.a. checks and debug stages, + a suffix is appended with a dot to make sure every id is unique, e.g. check becomes check.0 + + Special kwargs: + pos : specifies position in pipeline to add stage at. + suffix : specifies a custom suffix to identify non unique stages, instead of a number. + """ + pipeline_length = len(self._stages) + + pos = -1 + if "pos" in kwargs: + pos = kwargs.pop("pos") + + if pos < 0: + pos = pipeline_length + (pos + 1) + if not -pipeline_length <= pos <= pipeline_length: + raise ValueError( + f"Pos must be between [-{pipeline_length}, {pipeline_length}]" + ) + + stage_id = func.__name__ + suffix = None + if "suffix" in kwargs: + suffix = kwargs.pop("suffix") + if stage_id == "dump_artifact": + args = (*args, suffix) + + unique_stages = [ + "quantize", + "export", + "to_edge_transform_and_lower", + "to_edge", + "partition", + "to_executorch", + "serialize", + ] + id_list = [stage.id for stage in self._stages] + if stage_id in unique_stages: + if stage_id in id_list: + raise RuntimeError(f"Tried adding {stage_id} to pipeline twice.") + else: + if suffix is None: + stages_containing_stage_id = [ + id for id in id_list if stage_id == id.split(".")[0] + ] + + suffix = str(len(stages_containing_stage_id)) + + if not suffix == "0": + stage_id = stage_id + "." + suffix + + if stage_id in id_list: + raise ValueError("Suffix must be unique in pipeline") + + pipeline_stage = PipelineStage(func, stage_id, *args, **kwargs) + self._stages.insert(pos, pipeline_stage) + + logger.debug(f"Added stage {stage_id} to {type(self).__name__}") + + return self + + @property + def quantizer(self) -> TOSAQuantizer: + quantize_pipeline_stage = self._stages[self.find_pos("quantize")] + quantize_stage = quantize_pipeline_stage.args[0] + if isinstance(quantize_stage, Quantize): + quantizer = quantize_stage.quantizer + if isinstance(quantizer, TOSAQuantizer): + return quantizer + else: + raise RuntimeError( + f"Quantizer in pipeline was {type(quantizer).__name__}, not TOSAQuantizer as expected." + ) + else: + raise RuntimeError( + f"First argument of quantize stage was {type(quantize_stage).__name__}, not Quantize as expected." + ) + + def pop_stage(self, identifier: int | str): + """Removes and returns the stage at postion pos""" + if isinstance(identifier, int): + stage = self._stages.pop(identifier) + elif isinstance(identifier, str): + pos = self.find_pos(identifier) + stage = self._stages.pop(pos) + else: + raise TypeError("identifier must be an int or str") + + logger.debug(f"Removed stage {stage.id} from {type(self).__name__}") + + return stage + + def find_pos(self, stage_id: str): + """Returns the position of the stage id.""" + for i, stage in enumerate(self._stages): + if stage.id == stage_id: + return i + + raise Exception(f"Stage id {stage_id} not found in pipeline") + + def has_stage(self, stage_id: str): + try: + return self.find_pos(stage_id) >= 0 + except: + return False + + def add_stage_after(self, stage_id: str, func: Callable, *args, **kwargs): + """Adds a stage after the given stage id.""" + pos = self.find_pos(stage_id) + 1 + kwargs["pos"] = pos + + self.add_stage(func, *args, **kwargs) + return self + + def dump_artifact(self, stage_id: str, suffix: str | None = None): + """Adds a dump_artifact stage after the given stage id.""" + self.add_stage_after(stage_id, self.tester.dump_artifact, suffix=suffix) + return self + + def dump_operator_distribution( + self, stage_id: str, suffix: str | None = None, include_dtypes: bool = False + ): + """Adds a dump_operator_distribution stage after the given stage id.""" + self.add_stage_after( + stage_id, + self.tester.dump_operator_distribution, + suffix=suffix, + include_dtypes=include_dtypes, + ) + return self + + def visualize(self, stage_id: str, suffix: str | None = None): + """Adds a dump_operator_distribution stage after the given stage id.""" + self.add_stage_after(stage_id, self.tester.visualize, suffix=suffix) + return self + + def change_args(self, stage_id: str, *args, **kwargs): + """Updates the args to the given stage id.""" + pos = self.find_pos(stage_id) + pipeline_stage = self._stages[pos] + pipeline_stage.update(*args, **kwargs) + return self + + def run(self): + """Calls each stage in order.""" + stage_list = [stage.id for stage in self._stages] + logger.info(f"Running pipeline with stages:\n {stage_list}.") + + for stage in self._stages: + try: + stage() + except Exception as e: + logger.error(f"\nFailure in stage <{stage.id}>: \n {str(e)}") + raise e + + +class TOSAPipeline(BasePipeline, Generic[T]): + @staticmethod + def is_tosa_ref_model_available(): + """Checks if the TOSA reference model is available.""" + # Not all deployments of ET have the TOSA reference model available. + # Make sure we don't try to use it if it's not available. + try: + import tosa_reference_model # type: ignore[import-not-found, import-untyped] + + # Check if the module has content + return bool(dir(tosa_reference_model)) + except ImportError: + return False + + def run(self): + if ( + self.has_stage("run_method_and_compare_outputs") + and not self.is_tosa_ref_model_available() + ): + _warnings.warn( + "Warning: Skipping run_method_and_compare_outputs stage. TOSA reference model is not available." + ) + self.pop_stage("run_method_and_compare_outputs") + super().run() + + +class TosaPipelineINT(TOSAPipeline, Generic[T]): + """ + Lowers a graph to INT TOSA spec (with quantization) and tests it with the TOSA reference model. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + + aten_ops: Aten dialect ops expected to be found in the graph after export. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + + run_on_tosa_ref_model: Set to true to test the tosa file on the TOSA reference model. + + tosa_version: A string for identifying the TOSA version, see common.get_tosa_compile_spec for + options. + use_edge_to_transform_and_lower: Selects betweeen two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_op: str | List[str], + exir_op: Optional[str | List[str]] = None, + run_on_tosa_ref_model: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + dynamic_shapes: Optional[Tuple[Any]] = None, + tosa_extensions: Optional[List[str]] = None, + epsilon: float = 2**-12, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+INT" + "".join([f"+{ext}" for ext in tosa_extensions]) + ), + } + tosa_version = _require_tosa_version() + tosa_spec: TosaSpecification = tosa_profiles[tosa_version] + + compile_spec = common.get_tosa_compile_spec( + tosa_spec, + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + + quantizer = TOSAQuantizer(tosa_spec) + # choose 16A8W quantization config when int16 extension is requested + if "int16" in tosa_extensions: + quantization_config = get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=epsilon + ) + else: + quantization_config = get_symmetric_quantization_config( + is_per_channel=per_channel_quantization + ) + if symmetric_io_quantization: + quantizer.set_io(quantization_config) + quant_stage = Quantize(quantizer, quantization_config) + + super().__init__( + module, + test_data, + aten_op, + compile_spec, + exir_op, + use_to_edge_transform_and_lower, + dynamic_shapes, + ) + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + remove_torch_quant_nodes_stage = ( + "to_edge_transform_and_lower" + if use_to_edge_transform_and_lower + else "partition" + ) + + if _has_quantizable_inputs(test_data): + # only add stages if we have quantizable input + self.add_stage_after( + "quantize", + self.tester.check, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + # For pure INT lowering, outer exir Q/DQ nodes remain in the graph because we can't partition them. + # In INT+FP lowering, we partition these nodes, so a check is added to verify that. + if tosa_spec.support_integer() and tosa_spec.support_float(): + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_channel_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default", + ], + suffix="exir_quant_nodes", + ) + + if run_on_tosa_ref_model: + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + + +class TosaPipelineFP(TOSAPipeline, Generic[T]): + """ + Lowers a graph to FP TOSA spec and tests it with the TOSA reference model. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + + aten_ops: Aten dialect ops expected to be found in the graph after export. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + + run_on_tosa_ref_model: Set to true to test the tosa file on the TOSA reference model. + + tosa_version: A string for identifying the TOSA version, see common.get_tosa_compile_spec for + options. + use_edge_to_transform_and_lower: Selects betweeen two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_op: str | List[str], + exir_op: Optional[str | List[str]] = None, + run_on_tosa_ref_model: bool = True, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 0, + dynamic_shapes: Optional[Tuple[Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+FP" + "".join([f"+{ext}" for ext in tosa_extensions]) + ), + } + tosa_version = _require_tosa_version() + + compile_spec = common.get_tosa_compile_spec( + tosa_profiles[tosa_version], + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + super().__init__( + module, + test_data, + aten_op, + compile_spec, + exir_op, + use_to_edge_transform_and_lower, + dynamic_shapes=dynamic_shapes, + transform_passes=transform_passes, + ) + self.add_stage_after( + "export", + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + if run_on_tosa_ref_model: + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + + +class EthosUPipelineINTBase(BasePipeline, Generic[T]): + """Base class that encapsulates shared Ethos-U INT pipeline setup.""" + + def __init__( + self, + compile_spec: EthosUCompileSpec, + module: torch.nn.Module, + test_data: T, + aten_ops: str | List[str], + exir_ops: str | Sequence[str] | None, + run_on_fvp: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + a16w8_quantization: bool = False, + use_to_edge_transform_and_lower: bool = True, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + epsilon: float = 2**-12, + ): + super().__init__( + module, + test_data, + aten_ops, + compile_spec, + exir_ops, + use_to_edge_transform_and_lower, + ) + + quantizer = EthosUQuantizer(compile_spec) + # choose int8 or int16 activation quantization + if a16w8_quantization: + quantization_config = get_symmetric_a16w8_quantization_config( + is_per_channel=per_channel_quantization, epsilon=epsilon + ) + else: + quantization_config = get_symmetric_quantization_config( + is_per_channel=per_channel_quantization + ) + if symmetric_io_quantization: + quantizer.set_io(quantization_config) + quant_stage = Quantize(quantizer, quantization_config) + + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + remove_quant_nodes_stage = ( + "to_edge_transform_and_lower" + if use_to_edge_transform_and_lower + else "partition" + ) + + if _has_quantizable_inputs(test_data): + # only add stages if we have quantizable input + self.add_stage_after( + "quantize", + self.tester.check, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + self.add_stage_after( + remove_quant_nodes_stage, + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + if run_on_fvp: + self.add_stage(self.tester.serialize) + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + + +class EthosU55PipelineINT(EthosUPipelineINTBase, Generic[T]): + """ + Lowers a graph to u55 INT TOSA spec and tests it on the Corstone300 FVP, if run_on_fvp is true. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + aten_ops: Aten dialect ops expected to be found in the graph after export. + + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + run_on_fvp: Set to true to test the pte file on a fvp simulator. + use_edge_to_transform_and_lower: Selects between two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_ops: str | List[str], + exir_ops: str | Sequence[str] | None = None, + run_on_fvp: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + a16w8_quantization: bool = False, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + epsilon: float = 2**-12, + ): + compile_spec = common.get_u55_compile_spec( + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + super().__init__( + compile_spec, + module, + test_data, + aten_ops, + exir_ops, + run_on_fvp=run_on_fvp, + symmetric_io_quantization=symmetric_io_quantization, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=a16w8_quantization, + use_to_edge_transform_and_lower=use_to_edge_transform_and_lower, + atol=atol, + rtol=rtol, + qtol=qtol, + epsilon=epsilon, + ) + + +class EthosU85PipelineINT(EthosUPipelineINTBase, Generic[T]): + """ + Lowers a graph to u85 INT TOSA spec and tests it on the Corstone320 FVP, if run_on_fvp is true. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + aten_ops: Aten dialect ops expected to be found in the graph after export. + + exir_ops: Exir dialect ops expected to be found in the graph after to_edge if not using + use_edge_to_transform_and_lower. + run_on_fvp: Set to true to test the pte file on a fvp simulator. + use_edge_to_transform_and_lower: Selects between two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_ops: str | List[str], + exir_ops: str | Sequence[str] | None = None, + run_on_fvp: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + a16w8_quantization: bool = False, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + epsilon: float = 2**-12, + ): + compile_spec = common.get_u85_compile_spec( + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + super().__init__( + compile_spec, + module, + test_data, + aten_ops, + exir_ops, + run_on_fvp=run_on_fvp, + symmetric_io_quantization=symmetric_io_quantization, + per_channel_quantization=per_channel_quantization, + a16w8_quantization=a16w8_quantization, + use_to_edge_transform_and_lower=use_to_edge_transform_and_lower, + atol=atol, + rtol=rtol, + qtol=qtol, + epsilon=epsilon, + ) + + +class PassPipeline(TOSAPipeline, Generic[T]): + """ + Runs single passes directly on an edge_program and checks operators before/after. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + tosa_version: The TOSA-version which to test for. + + ops_before_pass : Ops expected to be found in the graph before passes. + ops_not_before_pass : Ops expected not to be found in the graph before passes. + ops_after_pass : Ops expected to be found in the graph after passes. + ops_notafter_pass : Ops expected not to be found in the graph after passes. + + pass_list: List of regular passes. + pass_functions: List of functions applied directly to the exported program. + passes_with_exported_program: List of passes initiated with an exported_program. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + + Passes are run in order pass_list -> pass_functions -> passes_with_exported_program. + See arm_tester.RunPasses() for more information. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + quantize: Optional[bool] = False, + ops_before_pass: Optional[Dict[str, int]] = None, + ops_not_before_pass: Optional[list[str]] = None, + ops_after_pass: Optional[Dict[str, int]] = None, + ops_not_after_pass: Optional[list[str]] = None, + pass_list: Optional[List[Type[PassType]]] = None, + pass_functions: Optional[List[Callable]] = None, + passes_with_exported_program: Optional[List[Type[ExportPass]]] = None, + custom_path: str | None = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+" + + ("INT" if quantize else "FP") + + "".join([f"+{ext}" for ext in tosa_extensions]), + ), + } + tosa_version = _require_tosa_version() + self.tosa_spec: TosaSpecification = tosa_profiles[tosa_version] + + compile_spec = common.get_tosa_compile_spec( + self.tosa_spec, custom_path=custom_path + ) + super().__init__( + module, + test_data, + None, + compile_spec, + None, + use_to_edge_transform_and_lower=False, + ) + + # Delete most of the pipeline + self.pop_stage("check.exir") + self.pop_stage("partition") + self.pop_stage("check_not.exir") + self.pop_stage("check_count.exir") + self.pop_stage("to_executorch") + self.pop_stage("check.aten") + + if quantize: + self.add_stage(self.tester.quantize, pos=0) + + # Add checks/check_not's if given + if ops_before_pass: + self.add_stage(self.tester.check_count, ops_before_pass, suffix="before") + if ops_not_before_pass: + self.add_stage(self.tester.check_not, ops_not_before_pass, suffix="before") + test_pass_stage = RunPasses( # type: ignore[arg-type] + pass_list, pass_functions, passes_with_exported_program # type: ignore[arg-type] + ) # Legacy pass APIs expose callable classes rather than ExportPass subclasses + + self.add_stage(self.tester.run_passes, test_pass_stage) + + if ops_after_pass: + self.add_stage(self.tester.check_count, ops_after_pass, suffix="after") + if ops_not_after_pass: + self.add_stage(self.tester.check_not, ops_not_after_pass, suffix="after") + self.add_stage( + self.tester.run_method_and_compare_outputs, + inputs=self.test_data, + ) + + def run(self): + with TosaLoweringContext(self.tosa_spec): + super().run() + + +class TransformAnnotationPassPipeline(TOSAPipeline, Generic[T]): + """ + Runs transform_for_annotation_pipeline passes directly on an exported program and checks output. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for testing the module. + + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + custom_path: str | None = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+INT" + "".join([f"+{ext}" for ext in tosa_extensions]), + ), + } + tosa_version = _require_tosa_version() + + compile_spec = common.get_tosa_compile_spec( + tosa_profiles[tosa_version], custom_path=custom_path + ) + super().__init__( + module, + test_data, + None, + compile_spec, + None, + use_to_edge_transform_and_lower=True, + ) + self.add_stage_after( + "export", self.tester.run_transform_for_annotation_pipeline + ) + + # Delete most of the pipeline + self.pop_stage("check_not.exir") + self.pop_stage("check_count.exir") + self.pop_stage("to_executorch") + self.pop_stage("to_edge_transform_and_lower") + self.pop_stage("check.aten") + self.add_stage( + self.tester.run_method_and_compare_outputs, + inputs=test_data, + run_eager_mode=True, + ) + + +class QuantizationPipeline(TOSAPipeline, Generic[T]): + """ + Runs quantization and checks that appropriate nodes are annotated with an expected + quantization-spec. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for testing the module. + quantizer: The quantizer to use for quantization. + qspecs: Annotations to check for after quantization. A dict mapping + operator names to a dict mapping QuantizationSpec (or None) to the number of times + that spec should appear in the graph. A None QuantizationSpec indicates that the + operator should not be quantized. + input_qspecs: Annotations to check for after quantization on inputs. + output_qspecs: Annotations to check for after quantization on outputs. + custom_path : Path to dump intermediate artifacts to. + + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + quantizer: TOSAQuantizer, + qspecs: Optional[Dict[str, Dict[QuantizationSpec | None, int]]] = None, + input_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + output_qspecs: Optional[Dict[QuantizationSpec | None, int]] = None, + custom_path: Optional[str] = None, + ): + tosa_spec = quantizer.tosa_spec + compile_spec = common.get_tosa_compile_spec(tosa_spec, custom_path=custom_path) + super().__init__( + module, + test_data, + None, + compile_spec, + None, + use_to_edge_transform_and_lower=True, + ) + # TODO sort out typing + quant_stage = Quantize(quantizer, quantization_config=quantizer.global_config) # type: ignore[arg-type] + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + # Delete most of the pipeline + self.pop_stage("check_count.exir") + self.pop_stage("to_executorch") + self.pop_stage("to_edge_transform_and_lower") + self.pop_stage("check.aten") + self.add_stage_after( + "export", + self.tester.check_quantization_annotation, + qspecs, + input_qspecs, + output_qspecs, + ) + + +class OpNotSupportedPipeline(TOSAPipeline, Generic[T]): + """ + Runs the partitioner on a module and checks that ops are not delegated to test + SupportedTOSAOperatorChecks. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data with a representative shape which the operator_check is performed on. + tosa_version: The TOSA-version which to test for. + + non_delegated_ops : Exir ops expected not to be delegated. + n_expected_delegates : Number of delegate calls (0 in the usual case). + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + non_delegated_ops: Dict[str, int], + n_expected_delegates: int = 0, + custom_path: str | None = None, + quantize: Optional[bool] = False, + u55_subset: Optional[bool] = False, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_profiles: dict[str, TosaSpecification] = { + "1.0": TosaSpecification.create_from_string( + "TOSA-1.0+" + + ("INT" if quantize else "FP") + + ("+u55" if u55_subset and quantize else "") + + "".join([f"+{ext}" for ext in tosa_extensions]), + ), + } + tosa_version = _require_tosa_version() + + tosa_spec = tosa_profiles[tosa_version] + + compile_spec: ArmCompileSpec = common.get_tosa_compile_spec( + tosa_spec, + custom_path=custom_path, + ) + super().__init__( + module, + test_data, + [], + compile_spec, + [], + ) + + if tosa_spec.support_integer(): + quantizer = create_quantizer(compile_spec) + quantizer.set_global(get_symmetric_quantization_config()) + quant_stage = Quantize(quantizer) + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + self.change_args("check_not.exir", []) + self.change_args( + "check_count.exir", + { + "torch.ops.higher_order.executorch_call_delegate": n_expected_delegates, + **non_delegated_ops, + }, + ) + self.pop_stage("to_executorch") + + +class VgfPipeline(BasePipeline, Generic[T]): + """ + Lowers a graph based on TOSA spec (with or without quantization) and converts TOSA to VFG. + + Attributes: + module: The module which the pipeline is applied to. + test_data: Data used for quantizing and testing the module. + + aten_ops: Aten dialect ops expected to be found in the graph after export. + exir_ops: Exir dialect ops expected to be found in the graph after to_edge. + if not using use_edge_to_transform_and_lower. + + run_on_vulkan_runtime: Whether to test VGF output on VKML runtime. + + vgf_compiler_flags: Optional compiler flags. + + tosa_version: A string for identifying the TOSA version. + + use_edge_to_transform_and_lower: Selects betweeen two possible ways of lowering the module. + custom_path : Path to dump intermediate artifacts such as tosa and pte to. + """ + + def __init__( + self, + module: torch.nn.Module, + test_data: T, + aten_op: str | List[str], + exir_op: Optional[str | List[str]] = None, + run_on_vulkan_runtime: bool = True, + vgf_compiler_flags: Optional[str] = "", + tosa_version: str = "TOSA-1.0+INT+FP", + quantize: bool = True, + symmetric_io_quantization: bool = False, + per_channel_quantization: bool = True, + use_to_edge_transform_and_lower: bool = True, + custom_path: str | None = None, + tosa_debug_mode: Optional[ArmCompileSpec.DebugMode] = None, + atol: float = 1e-03, + rtol: float = 1e-03, + qtol: int = 1, + dynamic_shapes: Optional[Tuple[Any]] = None, + transform_passes: Optional[ + Union[Sequence[PassType], Dict[str, Sequence[PassType]]] + ] = None, + tosa_extensions: Optional[List[str]] = None, + ): + if tosa_extensions is None: + tosa_extensions = [] + tosa_spec = TosaSpecification.create_from_string( + tosa_version + "".join([f"+{ext}" for ext in tosa_extensions]) + ) + compile_spec = common.get_vgf_compile_spec( + tosa_spec, + compiler_flags=vgf_compiler_flags, + custom_path=custom_path, + tosa_debug_mode=tosa_debug_mode, + ) + + super().__init__( + module, + test_data, + aten_op, + compile_spec, + exir_op, + use_to_edge_transform_and_lower, + dynamic_shapes, + transform_passes=transform_passes, + ) + + remove_torch_quant_nodes_stage = ( + "to_edge_transform_and_lower" + if use_to_edge_transform_and_lower + else "partition" + ) + + if quantize: + quantizer = VgfQuantizer(compile_spec) + quantization_config = get_symmetric_quantization_config( + is_per_channel=per_channel_quantization + ) + if symmetric_io_quantization: + quantizer.set_io(quantization_config) + quant_stage = Quantize(quantizer, quantization_config) + + self.add_stage(self.tester.quantize, quant_stage, pos=0) + + if _has_quantizable_inputs(test_data): + # only add stages if we have quantizable input + self.add_stage_after( + "quantize", + self.tester.check, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + else: + self.add_stage_after( + "export", + self.tester.check_not, + [ + "torch.ops.quantized_decomposed.dequantize_per_tensor.default", + "torch.ops.quantized_decomposed.quantize_per_tensor.default", + ], + suffix="quant_nodes", + ) + + # For pure INT lowering, outer exir Q/DQ nodes remain in the graph because we can't partition them. + # In INT+FP lowering, we partition these these nodes, so a check is added to verify that. + if tosa_spec.support_integer() and tosa_spec.support_float(): + self.add_stage_after( + remove_torch_quant_nodes_stage, + self.tester.check_not, + [ + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_channel_default", + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default", + ], + suffix="exir_quant_nodes", + ) + + if run_on_vulkan_runtime: + self.add_stage(self.tester.serialize) + self.add_stage( + self.tester.run_method_and_compare_outputs, + atol=atol, + rtol=rtol, + qtol=qtol, + inputs=self.test_data, + ) + self.run_on_vulkan_runtime = run_on_vulkan_runtime + + # TODO: Remove once CI fully working + def run(self): + import pytest + + if self.run_on_vulkan_runtime: + try: + super().run() + except FileNotFoundError as e: + pytest.skip(f"VKML executor_runner not found - not built - skip {e}") + else: + super().run() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.clang-format b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.clang-format new file mode 100644 index 0000000..9a7ae82 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.clang-format @@ -0,0 +1,144 @@ +# +# Copyright (c) 2019-2020 Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the License); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: true +BreakInheritanceList: AfterColon +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: AfterColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000000 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +... + diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.gitignore b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/.gitignore @@ -0,0 +1 @@ +/build diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt new file mode 100644 index 0000000..aeec47a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/CMakeLists.txt @@ -0,0 +1,114 @@ +# +# SPDX-FileCopyrightText: Copyright 2019-2021, 2023-2024 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the License); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required(VERSION 3.15.6) + +project(ethosu_core_driver VERSION 0.0.1) + +# +# Compile options +# + +add_compile_options(-Werror) + +# +# Build options +# + +set(CMSIS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmsis" CACHE PATH "Path to CMSIS.") + +set(LOG_NAMES err warning info debug) +set(ETHOSU_LOG_ENABLE ON CACHE BOOL "Toggle driver logs on/off (Defaults to ON)") +set(ETHOSU_LOG_SEVERITY "warning" CACHE STRING "Driver log severity level ${LOG_NAMES} (Defaults to 'warning')") +set(ETHOSU_TARGET_NPU_CONFIG "ethos-u55-128" CACHE STRING "Default NPU configuration") +set(ETHOSU_INFERENCE_TIMEOUT "" CACHE STRING "Inference timeout (unit is implementation defined)") +set_property(CACHE ETHOSU_LOG_SEVERITY PROPERTY STRINGS ${LOG_NAMES}) + +# +# Global settings +# + +# Check that ETHOSU_LOG_SEVERITY has one of the supported levels +list(FIND LOG_NAMES ${ETHOSU_LOG_SEVERITY} LOG_SEVERITY) +if (${LOG_SEVERITY} EQUAL -1) + message(FATAL_ERROR "Unsupported log level ${ETHOSU_LOG_SEVERITY}") +endif() + +# Make include directories available for current- and sub projects +include_directories(include src) +include_directories(${CMSIS_PATH}/CMSIS/Core/Include) + +# +# Build libraries +# + +# Build driver library +add_library(ethosu_core_driver STATIC) +target_include_directories(ethosu_core_driver PUBLIC include) +target_sources(ethosu_core_driver PRIVATE src/ethosu_driver.c src/ethosu_pmu.c) + +string(TOLOWER ${ETHOSU_TARGET_NPU_CONFIG} ETHOSU_TARGET_NPU_CONFIG) +if(ETHOSU_TARGET_NPU_CONFIG MATCHES "^ethos-(u[0-9]+)-([0-9]+$)") + set(ETHOSU_ARCH ${CMAKE_MATCH_1}) + set(ETHOSU_MACS ${CMAKE_MATCH_2}) +else() + message(FATAL_ERROR "Invalid Ethos-U target configuration '${ETHOSU_TARGET_NPU_CONFIG}") +endif() + +target_compile_definitions(ethosu_core_driver PUBLIC + ETHOSU_ARCH=${ETHOSU_ARCH} + ETHOSU_MACS=${ETHOSU_MACS} + ETHOS$) + +if (ETHOSU_ARCH STREQUAL "u55" OR ETHOSU_ARCH STREQUAL "u65") + target_sources(ethosu_core_driver PRIVATE src/ethosu_device_u55_u65.c) +elseif (ETHOSU_ARCH STREQUAL "u85") + target_sources(ethosu_core_driver PRIVATE src/ethosu_device_u85.c) +else() + message(FATAL_ERROR "Invalid NPU configuration") +endif() + +if(NOT "${ETHOSU_INFERENCE_TIMEOUT}" STREQUAL "") + target_compile_definitions(ethosu_core_driver PRIVATE + ETHOSU_SEMAPHORE_WAIT_INFERENCE=${ETHOSU_INFERENCE_TIMEOUT}) + set(ETHOSU_INFERENCE_TIMEOUT_TEXT ${ETHOSU_INFERENCE_TIMEOUT}) +else() + set(ETHOSU_INFERENCE_TIMEOUT_TEXT "Default (no timeout)") +endif() +# Set the log level for the target +target_compile_definitions(ethosu_core_driver PRIVATE + ETHOSU_LOG_SEVERITY=${LOG_SEVERITY} + ETHOSU_LOG_ENABLE=$) + +# Install library and include files +install(TARGETS ethosu_core_driver LIBRARY DESTINATION "lib") +install(FILES include/ethosu_device.h include/ethosu_driver.h include/pmu_ethosu.h + DESTINATION "include") + +# Define ETHOSU macro +target_compile_definitions(ethosu_core_driver PUBLIC ETHOSU) + +# Print build status +message(STATUS "*******************************************************") +message(STATUS "PROJECT_NAME : ${PROJECT_NAME}") +message(STATUS "ETHOSU_TARGET_NPU_CONFIG : ${ETHOSU_TARGET_NPU_CONFIG}") +message(STATUS "CMAKE_SYSTEM_PROCESSOR : ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS "CMSIS_PATH : ${CMSIS_PATH}") +message(STATUS "ETHOSU_LOG_ENABLE : ${ETHOSU_LOG_ENABLE}") +message(STATUS "ETHOSU_LOG_SEVERITY : ${ETHOSU_LOG_SEVERITY}") +message(STATUS "ETHOSU_INFERENCE_TIMEOUT : ${ETHOSU_INFERENCE_TIMEOUT_TEXT}") +message(STATUS "*******************************************************") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/README.md new file mode 100644 index 0000000..327a897 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/README.md @@ -0,0 +1,330 @@ +# Arm(R) Ethos(TM)-U core driver + +This repository contains a device driver for the Arm(R) Ethos(TM)-U NPU. + +## Building + +The source code comes with a CMake based build system. The driver is expected to +be cross compiled for any of the supported Arm Cortex(R)-M CPUs, which requires +the user to configure the build to match their system configuration. + + +One such requirement is to define the target CPU, normally by setting +`CMAKE_SYSTEM_PROCESSOR`. **Note** that when using the toolchain files provided +in [core_platform](https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-platform), +the variable `TARGET_CPU` must be used instead of `CMAKE_SYSTEM_PROCESSOR`. + +Target CPU is specified on the form "cortex-m", for example: +"cortex-m55+nodsp+nofp". + +Similarly the target NPU configuration is +controlled by setting `ETHOSU_TARGET_NPU_CONFIG`, for example "ethos-u55-128". + +The build configuration can be defined either in the toolchain file or +by passing options on the command line. + +```[bash] +$ cmake -B build \ + -DCMAKE_TOOLCHAIN_FILE= \ + -DCMAKE_SYSTEM_PROCESSOR=cortex-m \ + -DETHOSU_TARGET_NPU_CONFIG=ethos-u- +$ cmake --build build +``` + +or when using toolchain files from [core_platform](https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-platform) + +```[bash] +$ cmake -B build \ + -DCMAKE_TOOLCHAIN_FILE= \ + -DTARGET_CPU=cortex-m \ + -DETHOSU_TARGET_NPU_CONFIG=ethos-u- +$ cmake --build build +``` +## Compiler flags used + +The Arm Ethos-U core driver component adds the -Werror flag in addition +to the compiler flags specified in the toolchain file, or options passed +on the command line. + +## Driver APIs + +The driver APIs are defined in `include/ethosu_driver.h` and the related types +in `include/ethosu_types.h`. Inferences can be invoked in two manners: +synchronously or asynchronously. The two types of invocation can be freely mixed +in a single application. + +### Synchronous invocation + +A typical usage of the driver can be the following: + +```[C] +// reserve a driver to be used (this call could block until a driver is available) +struct ethosu_driver *drv = ethosu_reserve_driver(); +... +// run one or more inferences +int result = ethosu_invoke(drv, + custom_data_ptr, + custom_data_size, + base_addr, + base_addr_size, + num_base_addr); +... +// release the driver for others to use +ethosu_release_driver(drv); +``` + +### Asynchronous invocation + +A typical usage of the driver can be the following: + +```[C] +// reserve a driver to be used (this call could block until a driver is available) +struct ethosu_driver *drv = ethosu_reserve_driver(); +... +// run one or more inferences +int result = ethosu_invoke_async(drv, + custom_data_ptr, + custom_data_size, + base_addr, + base_addr_size, + num_base_addr, + user_arg); +... +// do some other work +... +int ret; +do { + // true = blocking, false = non-blocking + // ret > 0 means inference not completed (only for non-blocking mode) + ret = ethosu_wait(drv, ); +} while(ret > 0); +... +// release the driver for others to use +ethosu_release_driver(drv); +``` + +Note that if `ethosu_wait` is invoked from a different thread and concurrently +with `ethosu_invoke_async`, the user is responsible to guarantee that +`ethosu_wait` is called after a successful completion of `ethosu_invoke_async`. +Otherwise `ethosu_wait` might fail and not actually wait for the inference +completion. + +### Driver initialization + +In order to use a driver it first needs to be initialized by calling the `init` +function, which will also register the handle in the list of available drivers. +A driver can be torn down by using the `deinit` function, which also removes the +driver from the list. + +The correct mapping is one driver per NPU device. Note that the NPUs must have +the same configuration, indeed the NPU configuration can be only one, which is +defined at compile time. + +## Implementation design + +The driver is structured in two main parts: the driver, which is responsible to +provide an unified API to the user; and the device part, which deals with the +details at the hardware level. + +In order to do its task the driver needs a device implementation. There could be +multiple device implementation for different hardware model and/or +configurations. Note that the driver can be compiled to target only one NPU +configuration by specializing the device part at compile time. + +## Data caching + +For running the driver on Arm CPUs which are configured with data cache, certain +caution must be taken to ensure cache coherency. The driver expects that cache +clean/flush has been done by the user application before being invoked. The +driver does provide a deprecated weakly linked function `ethosu_flush_dcache` +that could be overriden, causing the driver to cache flush/clean base pointers +marked in the flush mask before each inference. By default the flush mask is set +to only clean the scratch base pointer containing RW data (IFM in particular). +It is recommended to not implement this function but have the user application +make sure that IFM data has been written to memory before invoking an inference +on the NPU. + +The driver also exposes a weakly linked symbol for cache invalidation called +`ethosu_invalidate_dcache`, that must be overriden when the data cache is used. +After starting an inference on the NPU, the driver will call this function to +invalidate the base pointers marked in the invalidation mask. By defaults it +invalidates the scratch base pointer keeping RW data, to ensure cache coherency +after the inference is done. The invalidation call is done before waiting for +the NPU to finish the inference so that depending on the network, the cycles +for invalidating the cache may be completely hidden (the CPU performs cache +invalidation before yielding while waiting for the NPU to finish). + +Make sure that any base pointers marked for flush/invalidation is aligned to the +cache line size of your CPU, typically 32 bytes. While not implemented, to the +really advanced user aiming for maximum performance, it is theoretically +possible to tell the network compiler to align the IFM/OFM to cache line size, +and modify the driver so that only OFM data is invalidated (and if left to the +driver, only IFM data is cache cleaned/flushed). Due to the uncertainty of +tensor alignment, the driver only flushes/invalidates on base pointer level. + +By default the cache flush- and invalidation mask is set to only mark the +default scratch base pointer (base pointer 1). For maximum flexibility, the +driver provides a function to modify the cache flush/invalidate masks called +`ethosu_set_basep_cache_mask`. This function sets the two 8 bit masks, one for +flush and one for invalidate, where bit 0 corresponds to base pointer 0, bit 1 +corresponds to base pointer 1 etc. See `include/ethosu_driver.h` for more +information. + +An example implementation for the weak functions, using CMSIS primitives could +look like below: + +```[C++] +extern "C" { +// Deprecated - recommended to flush/clean in application code +// p must be 32 byte aligned +void ethosu_flush_dcache(uint32_t *p, size_t bytes) { + SCB_CleanDCache_by_Addr(p, bytes); +} + +// p must be 32 byte aligned +void ethosu_invalidate_dcache(uint32_t *p, size_t bytes) { + SCB_InvalidateDCache_by_Addr(p, bytes); +} +} +``` +The NPU contain memory attributes that should be set to match the settings used +in the MPU configuration for the memories used. See `NPU_MEM_ATTR_[0-3]` for +Ethos-U85 and the `AXI_LIMIT[0-3]_MEM_TYPE` for Ethos-U55/Ethos-U65 in +corresponding `src/ethosu_config_uX5.h` files. + +## Mutex and semaphores + +To ensure the correct functionality of the driver mutexes and semaphores are +used internally. The default implementations of mutexes and semaphores are +designed for a single-threaded baremetal environment. Hence for integration in +environemnts where multi-threading is possible, e.g., RTOS, the user is +responsible to provide implementation for mutexes and semaphores to be used by +the driver. + +The mutex and semaphores are used as synchronisation mechanisms and unless +specified, the timeout is required to be 'forever'. + +The driver allows for an RTOS to set a timeout for the NPU interrupt semaphore. +The timeout can be set with the CMake variable `ETHOSU_INFERENCE_TIMEOUT`, which +is then used as `timeout` argument for the interrupt semaphore take call. Note +that the unit is implementation defined, the value is shipped as is to the +`ethosu_semaphore_take()` function and an override implementation should cast it +to the appropriate type and/or convert it to the unit desired. + +A macro `ETHOSU_SEMAPHORE_WAIT_FOREVER` is defined in the driver header file, +and should be made sure to map to the RTOS' equivalent of +'no timeout/wait forever'. Inference timeout value defaults to this if left +unset. The macro is used internally in the driver for the available NPU's, thus +the driver does NOT support setting a timeout other than forever when waiting +for an NPU to become available (global ethosu_semaphore). + +The mutex and semaphore APIs are defined as weak linked functions that can be +overridden by the user. The APIs are the usual ones and described below: + +```[C] +// create a mutex by returning back a handle +void *ethosu_mutex_create(void); +// lock the given mutex +int ethosu_mutex_lock(void *mutex); +// unlock the given mutex +int ethosu_mutex_unlock(void *mutex); + +// create a (binary) semaphore by returning back a handle +void *ethosu_semaphore_create(void); +// take from the given semaphore, accepting a timeout (unit impl. defined) +int ethosu_semaphore_take(void *sem, uint64_t timeout); +// give from the given semaphore +int ethosu_semaphore_give(void *sem); +``` + +## Begin/End inference callbacks + +The driver provide weak linked functions as hooks to receive callbacks whenever +an inference begins and ends. The user can override such functions when needed. +To avoid memory leaks, any allocations done in the ethosu_inference_begin() must +be balanced by a corresponding free of the memory in the ethosu_inference_end() +callback. + +The end callback will always be called if the begin callback has been called, +including in the event of an interrupt semaphore take timeout. + +```[C] +void ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg); +void ethosu_inference_end(struct ethosu_driver *drv, void *user_arg); +``` + +Note that the `void *user_arg` pointer passed to invoke() function is the same +pointer passed to the begin() and end() callbacks. For example: + +```[C] +void my_function() { + ... + struct my_data data = {...}; + int result = int ethosu_invoke_v3(drv, + custom_data_ptr, + custom_data_size, + base_addr, + base_addr_size, + num_base_addr, + (void *)&data); + .... +} + +void ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg) { + struct my_data *data = (struct my_data*) user_arg; + // use drv and data here +} + +void ethosu_inference_end(struct ethosu_driver *drv, void *user_arg) { + struct my_data *data = (struct my_data*) user_arg; + // use drv and data here +} +``` + +## License + +The Arm Ethos-U core driver is provided under an Apache-2.0 license. Please see +[LICENSE.txt](LICENSE.txt) for more information. + +## Contributions + +The Arm Ethos-U project welcomes contributions under the Apache-2.0 license. + +Before we can accept your contribution, you need to certify its origin and give +us your permission. For this process we use the Developer Certificate of Origin +(DCO) V1.1 (https://developercertificate.org). + +To indicate that you agree to the terms of the DCO, you "sign off" your +contribution by adding a line with your name and e-mail address to every git +commit message. You must use your real name, no pseudonyms or anonymous +contributions are accepted. If there are more than one contributor, everyone +adds their name and e-mail to the commit message. + +```[] +Author: John Doe \ +Date: Mon Feb 29 12:12:12 2016 +0000 + +Title of the commit + +Short description of the change. + +Signed-off-by: John Doe john.doe@example.org +Signed-off-by: Foo Bar foo.bar@example.org +``` + +The contributions will be code reviewed by Arm before they can be accepted into +the repository. + +In order to submit a contribution, submit a merge request to the +[core_driver](https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-driver) +repository. To do this you will need to sign-up at [gitlab.arm.com](https://gitlab.arm.com) +and add your SSH key under your settings. + +## Security + +Please see [Security](SECURITY.md). + +## Trademark notice + +Arm, Cortex and Ethos are registered trademarks of Arm Limited (or its +subsidiaries) in the US and/or elsewhere. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/SECURITY.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/SECURITY.md new file mode 100644 index 0000000..29c6ce4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/SECURITY.md @@ -0,0 +1,85 @@ +# Security + +If you believe you have identified a security related issue or vulnerability, +then we encourage you to responsibly disclose it to us as soon as possible. + +## Reporting vulnerabilities + +Arm takes security issues seriously and welcomes feedback from researchers and +the security community in order to improve the security of its products and +services. We operate a coordinated disclosure policy for disclosing +vulnerabilities and other security issues. + +Security issues can be complex and one single timescale doesn't fit all +circumstances. We will make best endeavours to inform you when we expect +security notifications and fixes to be available and facilitate coordinated +disclosure when notifications and patches/mitigations are available. + +### Report + +For all security issues, contact Arm by email at +[arm-security@arm.com](mailto:arm-security@arm.com). In the body of the email +include as much information as possible about the issue or vulnerability and any +additional contact details. + +### Secure submission using PGP + +We support and encourage secure submission of vulnerability reports using PGP, +using the key below. If you would like replies to be encrypted, please provide +your own public key through a secure mechanism. + +~~~none +-----BEGIN PGP PUBLIC KEY BLOCK----- +mQINBFr7/RMBEACjHR5QZL/z1t2aLCRNXLE4KJiQmCo7edU5Be+7MTjIJDzZNu68 +lNEUYRoLexeayif8eC4T19bUsSbGpxHiYsFFjV8ewLXDyDJRRuaBGPfQ5rn/mE6X +Nvu+9Pputr+mB1R3CXcvrNkhmzPkK7zVM15oeyBMhogqPssuT4OeMduQdip8smfK +xTMk91RrJTLb+G3eE1tf+81kXBYvzp2e24Sn0/VeYe0IWnBobjVBZk3TmcYxDvz5 +Y47fU9V6cNj3Zq4VYrgxuLoFCA2VtetyiFQm5IYa3Bt3SWcAwihr8nbR2HoNdWyA +u8wJYYVzSq3hvT5l/IjTHxEcY+6RBq8poDSsftzvX386u9hmw7sJQFlTw6/pUjdr +gbsZ2ZzRBzKtU17ercpn4kU6VgVP3WRB5HiTFFkEpZuqAznOYaHbMq4dfd/g7Quq +C0VTbWiJnhku2i+g4BdHHRDtIF6U3aVQAfbrDb1LjVTa65p5ULOeY3HRAWtMNtu/ +Cj8cD98JDanzXtcnisds8vMQ8LZ6iMFChEnF8K4V0eLw9Ju6CMNiFYY7SEBndD/H +M4KcU4li7mROSbJcshgEbe1SYkxdMuI9eY4DNYxl3VjxoPUGzeqXo/ADFKE9bHsi +GTyEoij4ku0HspLVKnYHXn/LqHGwEcwjF8zphS+w5cn/e01akYwz5EVSQwARAQAB +tB1Bcm0gU3VwcG9ydCA8c3VwcG9ydEBhcm0uY29tPokCTgQTAQgAOBYhBN9zqDwZ +RL/vF0ihcdfNKdz4bBRiBQJa+/0TAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA +AAoJENfNKdz4bBRibK0P/jLlJR/QYypcjb+8BnHT9tCDgcV2KFYXS15VpbSNviN9 +Xs/UOnSadoGUMGCXDyb1PRNn98yUn7JlNR9rtsqPRmkpbo5cuw46ehgxjVlfcHnk +CttaE8Davx6zo0fyrBib2+oVVW8usi9+uRK4vhhPUicO3oXwzldsVFz+RbpubZxc +Bg/CZ+dQ2jMKOv1zDtInOG6OBnbQZRAeiWXgGhcIoPZ4zBQOi8nr0+bLcfvMeZi2 +uz6uKnylpXwZbl4ijcG8MKV/ei+7du+SzA9NY0WOT2g3FXDREWUhjKs8bmEZgIx4 +QgvDNpxAUThF+TqQ7zrsA8nT8POvDD0MhN/Z+A3QdPTdcaZFaXzIdxbDg+0FKmzu +OgtQBH4C01RWrkmZlhO5w7/Qjt0vLlhfyQIL9BW/HeEPtjnH2Hnq8xYnZhlVqJEh +FJU7F9sMvyiJiKviobFTd6AmpVkhxhcJ3k2L2C03imTsmUwAoejQCXwiYcOhyQ2t +Z9Nk8YIZTEw2urGFi4HSQPwPq2j/2j7ABJ4rlzJvO6vs5ppGkumvzIIP9JnpVXbp +wcbK6Ev6KdkX4s14Mzd6Hsd8LpL8t5nHhxUey6G0xKe2eSlHVm5Mlfhoete9UmIZ +dzIOZkgTgWXlYXRIxwGQ2Pss7pURtofykvLklq4jcobQuHxurl9cteodETfbWk/J +uQINBFr7/RMBEADWZG8eqt5D22g3T7ehnH/T3fuTX8LPUBnODMWGAEUY8uv64To8 +46odvrXFgWBgCf0sROEyJchc3SGLyR9S4lJsVJRde3QLN3WZkHlB4pSn4IQHFyQd +wsLQi+S9uggHMPlQ6MNvc5n0P3k5bT9fLUmtJWJ3QVjW7k963ZXpzf1zbQJqs30w +rlqGUZllfRoYQTfcYxFEaUFhwRJ//skNImWH8Vz+PTnqg2zRtFn3usrBV4GpNvsM +6jy+YEsSvUa7IY8k4wpPzEhIfqDjGbZxFSQ1H1G+mLUL+DD7oGffej/ZoC86TIdM +p6ew1rGhJdQBLh9nx+1ADOLWjNo2R0h60u7VR5q/K6V4fwWmeGFipPXZCD92I+nR +t/cjznwNyD/6J9YrBMF7mbGrS1TyfLaLt4tpdcBnsgqDTodd5OmG65mroXsg/lNO +7YZdecLZ34krfaLrWTtKkqULXbppB+uQvbVj8p8ONRImn6bZ+iAhnNaH9wJ06ico +b1F0imJ2SJWnFr6PzPRr0gPStLgu9wrRKheaORwF/H/HxSyPZxNVxFqu81q518A/ +plhub9INQLaxHf/TTjXpqZCcfdNTYUAW8rwbQfW9doSIT4lHY8bJXktb6BsVjkFj +PzDeYpXeOoTWetQqsEuTdg/F+qg041QBLtNj9Lr3Vy3StgMciRUIP8m0XwARAQAB +iQI2BBgBCAAgFiEE33OoPBlEv+8XSKFx180p3PhsFGIFAlr7/RMCGwwACgkQ180p +3PhsFGLWMA//V/XKrnI2YBh/SptUrgg7knPXva45bb7tGSH1fJg8f/wqycOSFFCY +ES45boA5jlQ3z8uw6BYCz5KeOucGhxAMw+x5EDdxZ33ksY5zqXB35WaMXzEwGYYb +E113/yhOsTbzu4bBKABSXbJO98MdAWvWpyCpp2MHIR3S9+ycM7/FMZ5xi3czZNRg +9+WZP+7W4qWhJptQ0kBh5C3N/tiltju5WQ2Y7XIn+5dMOJdtseFS7CNerxXZGAtH +nfRxaD/4ENdbWOwaVJiVW7+ioUJz09OWgy0gLYSDW+hciDnW1QAaJLpdAbniGZ0S +JsTmaZla8JnUKqZPgbFfA2OcnH9H+DWc0pHv17c5tJzTMP7rgirgGRX/U2LOzmFZ +1UxjQj5nn3Oa5frXbIAzb8xKiR0VDaquCM/3sti1AesYiS0Gw0Sqnw8qpFypgFXN +CKVgYXppIT+TmbDbNJDOB2UycxeI4vbiBwU8fI4qSpW12WsGdAJt/rx3UsyhZ+02 +4aSqDHzhJmtDPQ6lnaKe1fUkC90tgp8loVGmriWQx82jAQMqATVjIklTpE4vm00f +ocQIWOKEE90mKNEoV6rNbfl5QevmapTVdV/pmrRBzhbsa1uAUS4HZdH0Nf/OXEyv +yYCr2gCFPymkkRYhPr2w5EgbWyzLaBIwqjyIbXaveuB3DYi2Lhbf64I= +=EaN7 +-----END PGP PUBLIC KEY BLOCK----- +~~~ + +For more information visit + \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h new file mode 100644 index 0000000..1e71791 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_driver.h @@ -0,0 +1,399 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_DRIVER_H +#define ETHOSU_DRIVER_H + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "ethosu_types.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define ETHOSU_DRIVER_VERSION_MAJOR 0 ///< Driver major version +#define ETHOSU_DRIVER_VERSION_MINOR 16 ///< Driver minor version +#define ETHOSU_DRIVER_VERSION_PATCH 0 ///< Driver patch version + +#define ETHOSU_SEMAPHORE_WAIT_FOREVER (UINT64_MAX) + +#ifndef ETHOSU_SEMAPHORE_WAIT_INFERENCE +#define ETHOSU_SEMAPHORE_WAIT_INFERENCE ETHOSU_SEMAPHORE_WAIT_FOREVER +#endif + +/****************************************************************************** + * Types + ******************************************************************************/ + +enum ethosu_job_state +{ + ETHOSU_JOB_IDLE = 0, + ETHOSU_JOB_RUNNING, + ETHOSU_JOB_DONE +}; + +enum ethosu_job_result +{ + ETHOSU_JOB_RESULT_OK = 0, + ETHOSU_JOB_RESULT_TIMEOUT, + ETHOSU_JOB_RESULT_ERROR +}; + +struct ethosu_job +{ + volatile enum ethosu_job_state state; + volatile enum ethosu_job_result result; + const void *custom_data_ptr; + int custom_data_size; + const uint64_t *base_addr; + const size_t *base_addr_size; + int num_base_addr; + void *user_arg; +}; + +struct ethosu_driver +{ + struct ethosu_device dev; + struct ethosu_driver *next; + struct ethosu_job job; + void *semaphore; + uint64_t fast_memory; + size_t fast_memory_size; + uint32_t power_request_counter; + bool reserved; + uint8_t basep_flush_mask; + uint8_t basep_invalidate_mask; +}; + +struct ethosu_driver_version +{ + uint8_t major; + uint8_t minor; + uint8_t patch; +}; + +enum ethosu_request_clients +{ + ETHOSU_PMU_REQUEST = 0, + ETHOSU_INFERENCE_REQUEST = 1, +}; + +/****************************************************************************** + * Prototypes (weak functions in driver) + ******************************************************************************/ + +/** + * Interrupt handler to be called on IRQ from Ethos-U + * + * @param drv Pointer to driver handle + */ +void ethosu_irq_handler(struct ethosu_driver *drv); + +/** + * Flush/clean the data cache by address and size. + * NOTE: It is not recommended to implement this, but let the application code + * make sure that any data needed by the NPU is flushed before invoking + * an inference. + * + * Addresses passed to this function must be 32 byte aligned. + * + * @param p 32 byte aligned address + * @param bytes Size of memory block in bytes + */ +void ethosu_flush_dcache(uint32_t *p, size_t bytes); + +/** + * Invalidate the data cache by address and size. + * NOTE: The driver will only call this for the scratch/tensor arena base + * pointer. + * + * Addresses passed to this function must be 32 byte aligned. + * + * @param p 32 byte aligned address + * @param bytes Size in bytes + */ +void ethosu_invalidate_dcache(uint32_t *p, size_t bytes); + +/** + * Minimal mutex implementation for baremetal applications. See + * ethosu_driver.c. + * + * @return Pointer to mutex handle + */ +void *ethosu_mutex_create(void); + +/** + * Destroy mutex. + * + * @param mutex Pointer to mutex handle + */ +void ethosu_mutex_destroy(void *mutex); + +/** + * Minimal sempahore implementation for baremetal applications. See + * ethosu_driver.c. + * + * @return Pointer to semaphore handle + */ +void *ethosu_semaphore_create(void); + +/** + * Destroy semaphore. + * + * @param sem Pointer to semaphore handle + */ +void ethosu_semaphore_destroy(void *sem); + +/** + * Lock mutex. + * + * @param mutex Pointer to mutex handle + * @returns 0 on success, else negative error code + */ +int ethosu_mutex_lock(void *mutex); + +/** + * Unlock mutex. + * + * @param mutex Pointer to mutex handle + * @returns 0 on success, else negative error code + */ +int ethosu_mutex_unlock(void *mutex); + +/** + * Take semaphore. + * + * @param sem Pointer to semaphore handle + * @param timeout Timeout value (unit impl. defined) + * @returns 0 on success else negative error code + */ +int ethosu_semaphore_take(void *sem, uint64_t timeout); + +/** + * Give semaphore. + * + * @param sem Pointer to semaphore handle + * @returns 0 on success, else negative error code + */ +int ethosu_semaphore_give(void *sem); + +/** + * Callback invoked just before the inference is started. + * + * @param drv Pointer to driver handle + * @param user_arg User argument provided to ethosu_invoke_*() + */ +void ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg); + +/** + * Callback invoked just after the inference has completed. + * + * @param drv Pointer to driver handle + * @param user_arg User argument provided to ethosu_invoke_*() + */ +void ethosu_inference_end(struct ethosu_driver *drv, void *user_arg); + +/** + * Remapping command stream and base pointer addresses. + * + * @param address Address to be remapped. + * @param index -1 command stream, 0-n base address index + * + * @return Remapped address + */ +uint64_t ethosu_address_remap(uint64_t address, int index); + +/****************************************************************************** + * Prototypes + ******************************************************************************/ + +/** + * Set cache mask for cache flush/clean and invalidation per base pointer. + * + * @param drv Pointer to driver handle + * @param flush_mask Base pointer cache flush mask (bit 0 == basep 0) + * @param invalidate_mask Base pointer cache invalidation mask (bit 0 == basep 0) + */ +void ethosu_set_basep_cache_mask(struct ethosu_driver *drv, uint8_t flush_mask, uint8_t invalidate_mask); + +/** + * Initialize the Ethos-U driver. + * + * @param drv Pointer to driver handle + * @param base_address NPU register base address + * @param fast_memory Fast memory area, used for Ethos-U65 with spilling + * @param fast_memory_size Size in bytes of fast memory area + * @param secure_enable Configure NPU in secure- or non-secure mode + * @param privilege_enable Configure NPU in privileged- or non-privileged mode + * @return 0 on success, else negative error code + */ +int ethosu_init(struct ethosu_driver *drv, + void *const base_address, + const void *fast_memory, + const size_t fast_memory_size, + uint32_t secure_enable, + uint32_t privilege_enable); + +/** + * Deinitialize the Ethos-U driver. + * + * @param drv Pointer to driver handle + */ +void ethosu_deinit(struct ethosu_driver *drv); + +/** + * Soft resets the Ethos-U device. + * + * @param drv Pointer to driver handle + * @return 0 on success, else negative error code + */ +int ethosu_soft_reset(struct ethosu_driver *drv); + +/** + * Request to disable Q-channel power gating of the Ethos-U device. + * Power requests are ref.counted. Increases count. + * (Note: clock gating is made to follow power gating) + * + * @param drv Pointer to driver handle + * @return 0 on success, else negative error code + */ +int ethosu_request_power(struct ethosu_driver *drv); + +/** + * Release disable request for Q-channel power gating of the Ethos-U device. + * Power requests are ref.counted. Decreases count. + * + * @param drv Pointer to driver handle + */ +void ethosu_release_power(struct ethosu_driver *drv); + +/** + * Get Ethos-U driver version. + * + * @param ver Driver version struct + */ +void ethosu_get_driver_version(struct ethosu_driver_version *ver); + +/** + * Get Ethos-U hardware information. + * + * @param drv Pointer to driver handle + * @param hw Hardware information struct + */ +void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw); + +/** + * Invoke command stream. + * + * @param drv Pointer to driver handle + * @param custom_data_ptr Custom data payload + * @param custom_data_size Size in bytes of custom data + * @param base_addr Array of base address pointers + * @param base_addr_size Size in bytes of each address in base_addr + * @param num_base_addr Number of elements in base_addr array + * @param user_arg User argument, will be passed to + * ethosu_inference_begin() and ethosu_inference_end() + * @return 0 on success, else negative error code + */ +int ethosu_invoke_v3(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg); + +#define ethosu_invoke(drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr) \ + ethosu_invoke_v3(drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr, 0) + +/** + * Invoke command stream using async interface. + * Must be followed by call(s) to ethosu_wait() upon successful return. + * + * @see ethosu_invoke_v3 for documentation. + */ +int ethosu_invoke_async(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg); + +/** + * Wait for inference to complete (block=true) + * Poll status or finish up if inference is complete (block=false) + * (This function is only intended to be used in conjuction with ethosu_invoke_async) + * + * @param drv Pointer to driver handle + * @param block If call should block if inference is running + * @return -2 on inference not invoked, -1 on inference error, 0 on success, 1 on inference running + */ +int ethosu_wait(struct ethosu_driver *drv, bool block); + +/** + * Reserves a driver to execute inference with. Call will block until a driver + * is available. + * + * @return Pointer to driver handle. + */ +struct ethosu_driver *ethosu_reserve_driver(void); + +/** + * Release driver that was previously reserved with @see ethosu_reserve_driver. + * + * @param drv Pointer to driver handle + */ +void ethosu_release_driver(struct ethosu_driver *drv); + +/** + * Static inline for backwards-compatibility. + * + * @see ethosu_invoke_v3 for documentation. + */ +static inline int ethosu_invoke_v2(const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr) +{ + struct ethosu_driver *drv = ethosu_reserve_driver(); + if (!drv) + { + return -1; + } + int result = ethosu_invoke_v3(drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr, 0); + ethosu_release_driver(drv); + return result; +} + +#ifdef __cplusplus +} +#endif + +#endif // ETHOSU_DRIVER_H diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h new file mode 100644 index 0000000..9d14a60 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/ethosu_types.h @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2021, 2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_TYPES_H +#define ETHOSU_TYPES_H + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include + +/****************************************************************************** + * Types + ******************************************************************************/ + +struct NPU_REG; // Forward declare, to be implemented by each device + +struct ethosu_device +{ + volatile struct NPU_REG *reg; // Register map + uint32_t secure; + uint32_t privileged; +}; + +enum ethosu_error_codes +{ + ETHOSU_SUCCESS = 0, ///< Success + ETHOSU_GENERIC_FAILURE = -1, ///< Generic failure + ETHOSU_INVALID_PARAM = -2 ///< Invalid parameter +}; + +enum ethosu_clock_q_request +{ + ETHOSU_CLOCK_Q_DISABLE = 0, ///< Disable NPU signal ready for clock off. + ETHOSU_CLOCK_Q_ENABLE = 1, ///< Enable NPU signal ready for clock off when stop+idle state reached. + ETHOSU_CLOCK_Q_UNCHANGED = 2 ///< Keep current clock q setting +}; + +enum ethosu_power_q_request +{ + ETHOSU_POWER_Q_DISABLE = 0, ///< Disable NPU signal ready for power off. + ETHOSU_POWER_Q_ENABLE = 1, ///< Enable NPU signal ready for power off when stop+idle state reached. + ETHOSU_POWER_Q_UNCHANGED = 2 ///< Keep current power q setting +}; + +struct ethosu_id +{ + uint32_t version_status; ///< Version status + uint32_t version_minor; ///< Version minor + uint32_t version_major; ///< Version major + uint32_t product_major; ///< Product major + uint32_t arch_patch_rev; ///< Architecture version patch + uint32_t arch_minor_rev; ///< Architecture version minor + uint32_t arch_major_rev; ///< Architecture version major +}; + +struct ethosu_config +{ + uint32_t macs_per_cc; ///< MACs per clock cycle + uint32_t cmd_stream_version; ///< NPU command stream version + uint32_t custom_dma; ///< Custom DMA enabled +}; + +struct ethosu_hw_info +{ + struct ethosu_id version; + struct ethosu_config cfg; +}; +#endif // ETHOSU_TYPES_H diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h new file mode 100644 index 0000000..76abc61 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/include/pmu_ethosu.h @@ -0,0 +1,515 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PMU_ETHOSU_H +#define PMU_ETHOSU_H + +/***************************************************************************** + * Includes + *****************************************************************************/ +#include + +#include "ethosu_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************** + * Defines + *****************************************************************************/ +#ifdef ETHOSU85 +#define ETHOSU_PMU_NCOUNTERS 8 +#else +#define ETHOSU_PMU_NCOUNTERS 4 +#endif + +#define ETHOSU_PMU_CNT1_Msk (1UL << 0) +#define ETHOSU_PMU_CNT2_Msk (1UL << 1) +#define ETHOSU_PMU_CNT3_Msk (1UL << 2) +#define ETHOSU_PMU_CNT4_Msk (1UL << 3) +#ifdef ETHOSU85 +#define ETHOSU_PMU_CNT5_Msk (1UL << 4) +#define ETHOSU_PMU_CNT6_Msk (1UL << 5) +#define ETHOSU_PMU_CNT7_Msk (1UL << 6) +#define ETHOSU_PMU_CNT8_Msk (1UL << 7) +#endif + +#define ETHOSU_PMU_CCNT_Msk (1UL << 31) + +/***************************************************************************** + * Types + *****************************************************************************/ + +/** \brief HW Supported ETHOSU PMU Events + * + * Note: These values are symbolic. Actual HW-values may change. I.e. always use API + * to set/get actual event-type value. + * */ +#if defined(ETHOSU55) || defined(ETHOSU65) +enum ethosu_pmu_event_type +{ + ETHOSU_PMU_NO_EVENT = 0, + ETHOSU_PMU_CYCLE, + ETHOSU_PMU_NPU_IDLE, + ETHOSU_PMU_CC_STALLED_ON_BLOCKDEP, + ETHOSU_PMU_CC_STALLED_ON_SHRAM_RECONFIG, + ETHOSU_PMU_NPU_ACTIVE, + ETHOSU_PMU_MAC_ACTIVE, + ETHOSU_PMU_MAC_ACTIVE_8BIT, + ETHOSU_PMU_MAC_ACTIVE_16BIT, + ETHOSU_PMU_MAC_DPU_ACTIVE, + ETHOSU_PMU_MAC_STALLED_BY_WD_ACC, + ETHOSU_PMU_MAC_STALLED_BY_WD, + ETHOSU_PMU_MAC_STALLED_BY_ACC, + ETHOSU_PMU_MAC_STALLED_BY_IB, + ETHOSU_PMU_MAC_ACTIVE_32BIT, + ETHOSU_PMU_MAC_STALLED_BY_INT_W, + ETHOSU_PMU_MAC_STALLED_BY_INT_ACC, + ETHOSU_PMU_AO_ACTIVE, + ETHOSU_PMU_AO_ACTIVE_8BIT, + ETHOSU_PMU_AO_ACTIVE_16BIT, + ETHOSU_PMU_AO_STALLED_BY_OFMP_OB, + ETHOSU_PMU_AO_STALLED_BY_OFMP, + ETHOSU_PMU_AO_STALLED_BY_OB, + ETHOSU_PMU_AO_STALLED_BY_ACC_IB, + ETHOSU_PMU_AO_STALLED_BY_ACC, + ETHOSU_PMU_AO_STALLED_BY_IB, + ETHOSU_PMU_WD_ACTIVE, + ETHOSU_PMU_WD_STALLED, + ETHOSU_PMU_WD_STALLED_BY_WS, + ETHOSU_PMU_WD_STALLED_BY_WD_BUF, + ETHOSU_PMU_WD_PARSE_ACTIVE, + ETHOSU_PMU_WD_PARSE_STALLED, + ETHOSU_PMU_WD_PARSE_STALLED_IN, + ETHOSU_PMU_WD_PARSE_STALLED_OUT, + ETHOSU_PMU_WD_TRANS_WS, + ETHOSU_PMU_WD_TRANS_WB, + ETHOSU_PMU_WD_TRANS_DW0, + ETHOSU_PMU_WD_TRANS_DW1, + ETHOSU_PMU_AXI0_RD_TRANS_ACCEPTED, + ETHOSU_PMU_AXI0_RD_TRANS_COMPLETED, + ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_AXI0_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI0_WR_TRANS_ACCEPTED, + ETHOSU_PMU_AXI0_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_AXI0_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_AXI0_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI0_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_AXI0_ENABLED_CYCLES, + ETHOSU_PMU_AXI0_RD_STALL_LIMIT, + ETHOSU_PMU_AXI0_WR_STALL_LIMIT, + ETHOSU_PMU_AXI_LATENCY_ANY, + ETHOSU_PMU_AXI_LATENCY_32, + ETHOSU_PMU_AXI_LATENCY_64, + ETHOSU_PMU_AXI_LATENCY_128, + ETHOSU_PMU_AXI_LATENCY_256, + ETHOSU_PMU_AXI_LATENCY_512, + ETHOSU_PMU_AXI_LATENCY_1024, + ETHOSU_PMU_ECC_DMA, + ETHOSU_PMU_ECC_SB0, + ETHOSU_PMU_AXI1_RD_TRANS_ACCEPTED, + ETHOSU_PMU_AXI1_RD_TRANS_COMPLETED, + ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_AXI1_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI1_WR_TRANS_ACCEPTED, + ETHOSU_PMU_AXI1_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_AXI1_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_AXI1_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_AXI1_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_AXI1_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_AXI1_ENABLED_CYCLES, + ETHOSU_PMU_AXI1_RD_STALL_LIMIT, + ETHOSU_PMU_AXI1_WR_STALL_LIMIT, + ETHOSU_PMU_ECC_SB1, + + ETHOSU_PMU_SENTINEL // End-marker (not event) +}; +#elif defined(ETHOSU85) +enum ethosu_pmu_event_type +{ + ETHOSU_PMU_NO_EVENT = 0, + ETHOSU_PMU_CYCLE, + ETHOSU_PMU_NPU_IDLE, + ETHOSU_PMU_CC_STALLED_ON_BLOCKDEP, + ETHOSU_PMU_NPU_ACTIVE, + ETHOSU_PMU_MAC_ACTIVE, + ETHOSU_PMU_MAC_DPU_ACTIVE, + ETHOSU_PMU_MAC_STALLED_BY_W_OR_ACC, + ETHOSU_PMU_MAC_STALLED_BY_W, + ETHOSU_PMU_MAC_STALLED_BY_ACC, + ETHOSU_PMU_MAC_STALLED_BY_IB, + ETHOSU_PMU_AO_ACTIVE, + ETHOSU_PMU_AO_STALLED_BY_BS_OR_OB, + ETHOSU_PMU_AO_STALLED_BY_BS, + ETHOSU_PMU_AO_STALLED_BY_OB, + ETHOSU_PMU_AO_STALLED_BY_AB_OR_CB, + ETHOSU_PMU_AO_STALLED_BY_AB, + ETHOSU_PMU_AO_STALLED_BY_CB, + ETHOSU_PMU_WD_ACTIVE, + ETHOSU_PMU_WD_STALLED, + ETHOSU_PMU_WD_STALLED_BY_WD_BUF, + ETHOSU_PMU_WD_STALLED_BY_WS_FC, + ETHOSU_PMU_WD_STALLED_BY_WS_TC, + ETHOSU_PMU_WD_TRANS_WBLK, + ETHOSU_PMU_WD_TRANS_WS_FC, + ETHOSU_PMU_WD_TRANS_WS_TC, + ETHOSU_PMU_WD_STALLED_BY_WS_SC0, + ETHOSU_PMU_WD_STALLED_BY_WS_SC1, + ETHOSU_PMU_WD_STALLED_BY_WS_SC2, + ETHOSU_PMU_WD_STALLED_BY_WS_SC3, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC0, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC1, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC2, + ETHOSU_PMU_WD_PARSE_ACTIVE_SC3, + ETHOSU_PMU_WD_PARSE_STALL_SC0, + ETHOSU_PMU_WD_PARSE_STALL_SC1, + ETHOSU_PMU_WD_PARSE_STALL_SC2, + ETHOSU_PMU_WD_PARSE_STALL_SC3, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC0, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC1, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC2, + ETHOSU_PMU_WD_PARSE_STALL_IN_SC3, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC0, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC1, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC2, + ETHOSU_PMU_WD_PARSE_STALL_OUT_SC3, + ETHOSU_PMU_WD_TRANS_WS_SC0, + ETHOSU_PMU_WD_TRANS_WS_SC1, + ETHOSU_PMU_WD_TRANS_WS_SC2, + ETHOSU_PMU_WD_TRANS_WS_SC3, + ETHOSU_PMU_WD_TRANS_WB0, + ETHOSU_PMU_WD_TRANS_WB1, + ETHOSU_PMU_WD_TRANS_WB2, + ETHOSU_PMU_WD_TRANS_WB3, + ETHOSU_PMU_SRAM_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM_ENABLED_CYCLES, + ETHOSU_PMU_SRAM_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM_WR_STALL_LIMIT, + ETHOSU_PMU_AXI_LATENCY_ANY, + ETHOSU_PMU_AXI_LATENCY_32, + ETHOSU_PMU_AXI_LATENCY_64, + ETHOSU_PMU_AXI_LATENCY_128, + ETHOSU_PMU_AXI_LATENCY_256, + ETHOSU_PMU_AXI_LATENCY_512, + ETHOSU_PMU_AXI_LATENCY_1024, + ETHOSU_PMU_ECC_DMA, + ETHOSU_PMU_ECC_MAC_IB, + ETHOSU_PMU_ECC_MAC_AB, + ETHOSU_PMU_ECC_AO_CB, + ETHOSU_PMU_ECC_AO_OB, + ETHOSU_PMU_ECC_AO_LUT, + ETHOSU_PMU_EXT_RD_TRANS_ACCEPTED, + ETHOSU_PMU_EXT_RD_TRANS_COMPLETED, + ETHOSU_PMU_EXT_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_EXT_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT_WR_TRANS_ACCEPTED, + ETHOSU_PMU_EXT_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_EXT_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_EXT_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_EXT_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_EXT_ENABLED_CYCLES, + ETHOSU_PMU_EXT_RD_STALL_LIMIT, + ETHOSU_PMU_EXT_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM0_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM0_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM0_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM0_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM0_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM0_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM0_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM0_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM0_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM0_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM0_ENABLED_CYCLES, + ETHOSU_PMU_SRAM0_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM0_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM1_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM1_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM1_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM1_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM1_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM1_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM1_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM1_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM1_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM1_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM1_ENABLED_CYCLES, + ETHOSU_PMU_SRAM1_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM1_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM2_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM2_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM2_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM2_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM2_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM2_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM2_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM2_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM2_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM2_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM2_ENABLED_CYCLES, + ETHOSU_PMU_SRAM2_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM2_WR_STALL_LIMIT, + ETHOSU_PMU_SRAM3_RD_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM3_RD_TRANS_COMPLETED, + ETHOSU_PMU_SRAM3_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_SRAM3_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM3_WR_TRANS_ACCEPTED, + ETHOSU_PMU_SRAM3_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_SRAM3_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_SRAM3_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_SRAM3_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_SRAM3_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_SRAM3_ENABLED_CYCLES, + ETHOSU_PMU_SRAM3_RD_STALL_LIMIT, + ETHOSU_PMU_SRAM3_WR_STALL_LIMIT, + ETHOSU_PMU_EXT0_RD_TRANS_ACCEPTED, + ETHOSU_PMU_EXT0_RD_TRANS_COMPLETED, + ETHOSU_PMU_EXT0_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_EXT0_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT0_WR_TRANS_ACCEPTED, + ETHOSU_PMU_EXT0_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_EXT0_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_EXT0_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_EXT0_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT0_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_EXT0_ENABLED_CYCLES, + ETHOSU_PMU_EXT0_RD_STALL_LIMIT, + ETHOSU_PMU_EXT0_WR_STALL_LIMIT, + ETHOSU_PMU_EXT1_RD_TRANS_ACCEPTED, + ETHOSU_PMU_EXT1_RD_TRANS_COMPLETED, + ETHOSU_PMU_EXT1_RD_DATA_BEAT_RECEIVED, + ETHOSU_PMU_EXT1_RD_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT1_WR_TRANS_ACCEPTED, + ETHOSU_PMU_EXT1_WR_TRANS_COMPLETED_M, + ETHOSU_PMU_EXT1_WR_TRANS_COMPLETED_S, + ETHOSU_PMU_EXT1_WR_DATA_BEAT_WRITTEN, + ETHOSU_PMU_EXT1_WR_TRAN_REQ_STALLED, + ETHOSU_PMU_EXT1_WR_DATA_BEAT_STALLED, + ETHOSU_PMU_EXT1_ENABLED_CYCLES, + ETHOSU_PMU_EXT1_RD_STALL_LIMIT, + ETHOSU_PMU_EXT1_WR_STALL_LIMIT, + + ETHOSU_PMU_SENTINEL // End-marker (not event) +}; +#else +#error No NPU target defined +#endif + +/***************************************************************************** + * Functions + *****************************************************************************/ + +/** + * \brief Enable the PMU + */ +void ETHOSU_PMU_Enable(struct ethosu_driver *drv); + +/** + * \brief Disable the PMU + */ +void ETHOSU_PMU_Disable(struct ethosu_driver *drv); + +/** + * \brief Set event to count for PMU eventer counter + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) to configure + * \param [in] type Event to count + */ +void ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type); + +/** + * \brief Get number of PMU event counters + * \return Number of event counters + */ +uint32_t ETHOSU_PMU_Get_NumEventCounters(void); + +/** + * \brief Get event to count for PMU eventer counter + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) to configure + * \return type Event to count + */ +enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(struct ethosu_driver *drv, uint32_t num); + +/** + * \brief Reset cycle counter + */ +void ETHOSU_PMU_CYCCNT_Reset(struct ethosu_driver *drv); + +/** + * \brief Reset all event counters + */ +void ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver *drv); + +/** + * \brief Enable counters + * \param [in] mask Counters to enable + * \note Enables one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_CNTR_Enable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Disable counters + * \param [in] mask Counters to disable + * \note Disables one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_CNTR_Disable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Determine counters activation + * + * \return Event count + * \param [in] mask Counters to enable + * \return a bitmask where bit-set means: + * - event counters activated (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter activate (bit 31) + * \note ETHOSU specific. Usage breaks CMSIS complience + */ +uint32_t ETHOSU_PMU_CNTR_Status(struct ethosu_driver *drv); + +/** + * \brief Read cycle counter (64 bit) + * \return Cycle count + * \note Two HW 32-bit registers that can increment independently in-between reads. + * To work-around raciness yet still avoid turning + * off the event both are read as one value twice. If the latter read + * is not greater than the former, it means overflow of LSW without + * incrementing MSW has occurred, in which case the former value is used. + */ +uint64_t ETHOSU_PMU_Get_CCNTR(struct ethosu_driver *drv); + +/** + * \brief Set cycle counter (64 bit) + * \param [in] val Conter value + * \note Two HW 32-bit registers that can increment independently in-between reads. + * To work-around raciness, counter is temporary disabled if enabled. + * \note ETHOSU specific. Usage breaks CMSIS complience + */ +void ETHOSU_PMU_Set_CCNTR(struct ethosu_driver *drv, uint64_t val); + +/** + * \brief Read event counter + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) + * \return Event count + */ +uint32_t ETHOSU_PMU_Get_EVCNTR(struct ethosu_driver *drv, uint32_t num); + +/** + * \brief Set event counter value + * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) + * \param [in] val Conter value + * \note ETHOSU specific. Usage breaks CMSIS complience + */ +void ETHOSU_PMU_Set_EVCNTR(struct ethosu_driver *drv, uint32_t num, uint32_t val); + +/** + * \brief Read counter overflow status + * \return Counter overflow status bits for the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS)) + * - cycle counter (bit 31) + */ +uint32_t ETHOSU_PMU_Get_CNTR_OVS(struct ethosu_driver *drv); + +/** + * \brief Clear counter overflow status + * \param [in] mask Counter overflow status bits to clear + * \note Clears overflow status bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_Set_CNTR_OVS(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Enable counter overflow interrupt request + * \param [in] mask Counter overflow interrupt request bits to set + * \note Sets overflow interrupt request bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_Set_CNTR_IRQ_Enable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Disable counter overflow interrupt request + * \param [in] mask Counter overflow interrupt request bits to clear + * \note Clears overflow interrupt request bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + */ +void ETHOSU_PMU_Set_CNTR_IRQ_Disable(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Get counters overflow interrupt request stiinings + * \return mask Counter overflow interrupt request bits + * \note Sets overflow interrupt request bits for one or more of the following: + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + * \note ETHOSU specific. Usage breaks CMSIS compliance + */ +uint32_t ETHOSU_PMU_Get_IRQ_Enable(struct ethosu_driver *drv); + +/** + * \brief Software increment event counter + * \param [in] mask Counters to increment + * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) + * - cycle counter (bit 31) + * \note Software increment bits for one or more event counters. + */ +void ETHOSU_PMU_CNTR_Increment(struct ethosu_driver *drv, uint32_t mask); + +/** + * \brief Set start event number for the cycle counter + * \param [in] start_event Event to trigger start of the cycle counter + * \note Sets the event number that starts the cycle counter. + */ +void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type start_event); + +/** + * \brief Set stop event number for the cycle counter + * \param [in] stop_event Event number + * \note Sets the event number that stops the cycle counter. + */ +void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type stop_event); + +/** + * \brief Read qread register + */ +uint32_t ETHOSU_PMU_Get_QREAD(struct ethosu_driver *drv); + +/** + * \brief Read status register + */ +uint32_t ETHOSU_PMU_Get_STATUS(struct ethosu_driver *drv); + +#ifdef __cplusplus +} +#endif + +#endif /* PMU_ETHOSU_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h new file mode 100644 index 0000000..37472b9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu55_interface.h @@ -0,0 +1,26197 @@ +/* + * Copyright (c) 2020-2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU55_INTERFACE_H +#define ETHOSU55_INTERFACE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#if !defined(__cplusplus) || __cplusplus < 201402L +#define CONSTEXPR +#else +#define CONSTEXPR constexpr +#endif + +#ifndef __cplusplus +#define STRUCT struct +#else +#define STRUCT +#endif + +#if defined(__cplusplus) && defined(NPU_DISASSEMBLE) +#include +#include +#include +#endif + +#if defined(__cplusplus) && !defined(NPU_NAMESPACE) +#define NPU_NAMESPACE npu +#endif + +#ifdef __cplusplus +#include +#include +#endif + +#ifdef __cplusplus +namespace NPU_NAMESPACE +{ +#endif +#define NNX_ARCH_VERSION_MAJOR 1 +#define NNX_ARCH_VERSION_MINOR 1 +#define NNX_ARCH_VERSION_PATCH 0 + +// Register offsets +// +// Register subpage BASE +// +#define NPU_REG_ID 0x0000 +#define NPU_REG_STATUS 0x0004 +#define NPU_REG_CMD 0x0008 +#define NPU_REG_RESET 0x000C +#define NPU_REG_QBASE 0x0010 +#define NPU_REG_QBASE_HI 0x0014 +#define NPU_REG_QREAD 0x0018 +#define NPU_REG_QCONFIG 0x001C +#define NPU_REG_QSIZE 0x0020 +#define NPU_REG_PROT 0x0024 +#define NPU_REG_CONFIG 0x0028 +#define NPU_REG_LOCK 0x002C +#define NPU_REG_REGIONCFG 0x003C +#define NPU_REG_AXI_LIMIT0 0x0040 +#define NPU_REG_AXI_LIMIT1 0x0044 +#define NPU_REG_AXI_LIMIT2 0x0048 +#define NPU_REG_AXI_LIMIT3 0x004C +#define BASE_REGISTERS_SIZE 0x0080 + +// +// Register subpage BASE_POINTERS +// +#define NPU_REG_BASEP_BASE 0x0080 +#define NPU_REG_BASEP_ARRLEN 0x0008 +#define BASE_POINTERS_REGISTERS_SIZE 0x0100 + +// +// Register subpage DEBUG +// +#define NPU_REG_WD_STATUS 0x0100 +#define NPU_REG_MAC_STATUS 0x0104 +#define NPU_REG_AO_STATUS 0x0108 +#define NPU_REG_DMA_STATUS0 0x0110 +#define NPU_REG_DMA_STATUS1 0x0114 +#define NPU_REG_CLKFORCE 0x0140 +#define NPU_REG_DEBUG_ADDRESS 0x0144 +#define NPU_REG_DEBUG_MISC 0x0148 +#define NPU_REG_DEBUG_BLOCK 0x0150 +#define DEBUG_REGISTERS_SIZE 0x0180 + +// +// Register subpage PMU +// +#define NPU_REG_PMCR 0x0180 +#define NPU_REG_PMCNTENSET 0x0184 +#define NPU_REG_PMCNTENCLR 0x0188 +#define NPU_REG_PMOVSSET 0x018C +#define NPU_REG_PMOVSCLR 0x0190 +#define NPU_REG_PMINTSET 0x0194 +#define NPU_REG_PMINTCLR 0x0198 +#define NPU_REG_PMCCNTR 0x01A0 +#define NPU_REG_PMCCNTR_HI 0x01A4 +#define NPU_REG_PMCCNTR_CFG 0x01A8 +#define NPU_REG_PMCAXI_CHAN 0x01AC +#define PMU_REGISTERS_SIZE 0x0200 + +// +// Register subpage TSU_DEBUG +// +#define NPU_REG_KERNEL_X 0x0200 +#define NPU_REG_KERNEL_Y 0x0204 +#define NPU_REG_KERNEL_W_M1 0x0208 +#define NPU_REG_KERNEL_H_M1 0x020C +#define NPU_REG_OFM_CBLK_WIDTH_M1 0x0210 +#define NPU_REG_OFM_CBLK_HEIGHT_M1 0x0214 +#define NPU_REG_OFM_CBLK_DEPTH_M1 0x0218 +#define NPU_REG_IFM_CBLK_DEPTH_M1 0x021C +#define NPU_REG_OFM_X 0x0220 +#define NPU_REG_OFM_Y 0x0224 +#define NPU_REG_OFM_Z 0x0228 +#define NPU_REG_IFM_Z 0x022C +#define NPU_REG_PAD_TOP 0x0230 +#define NPU_REG_PAD_LEFT 0x0234 +#define NPU_REG_IFM_CBLK_WIDTH 0x0238 +#define NPU_REG_IFM_CBLK_HEIGHT 0x023C +#define NPU_REG_DMA_IFM_SRC 0x0240 +#define NPU_REG_DMA_IFM_SRC_HI 0x0244 +#define NPU_REG_DMA_IFM_DST 0x0248 +#define NPU_REG_DMA_OFM_SRC 0x024C +#define NPU_REG_DMA_OFM_DST 0x0250 +#define NPU_REG_DMA_OFM_DST_HI 0x0254 +#define NPU_REG_DMA_WEIGHT_SRC 0x0258 +#define NPU_REG_DMA_WEIGHT_SRC_HI 0x025C +#define NPU_REG_DMA_CMD_SRC 0x0260 +#define NPU_REG_DMA_CMD_SRC_HI 0x0264 +#define NPU_REG_DMA_CMD_SIZE 0x0268 +#define NPU_REG_DMA_M2M_SRC 0x026C +#define NPU_REG_DMA_M2M_SRC_HI 0x0270 +#define NPU_REG_DMA_M2M_DST 0x0274 +#define NPU_REG_DMA_M2M_DST_HI 0x0278 +#define NPU_REG_CURRENT_QREAD 0x027C +#define NPU_REG_DMA_SCALE_SRC 0x0280 +#define NPU_REG_DMA_SCALE_SRC_HI 0x0284 +#define NPU_REG_CURRENT_BLOCK 0x02B4 +#define NPU_REG_CURRENT_OP 0x02B8 +#define NPU_REG_CURRENT_CMD 0x02BC +#define TSU_DEBUG_REGISTERS_SIZE 0x02C0 + +// +// Register subpage PMU_COUNTERS +// +#define NPU_REG_PMEVCNTR_BASE 0x0300 +#define NPU_REG_PMEVCNTR_ARRLEN 0x0004 +#define NPU_REG_PMEVTYPER_BASE 0x0380 +#define NPU_REG_PMEVTYPER_ARRLEN 0x0004 +#define PMU_COUNTERS_REGISTERS_SIZE 0x0400 + +// +// Register subpage SHARED_BUFFER +// +#define NPU_REG_SHARED_BUFFER_BASE 0x0400 +#define NPU_REG_SHARED_BUFFER_ARRLEN 0x0100 +#define SHARED_BUFFER_REGISTERS_SIZE 0x0800 + +// +// Register subpage TSU_IFM +// +#define NPU_REG_IFM_PAD_TOP 0x0800 +#define NPU_REG_IFM_PAD_LEFT 0x0804 +#define NPU_REG_IFM_PAD_RIGHT 0x0808 +#define NPU_REG_IFM_PAD_BOTTOM 0x080C +#define NPU_REG_IFM_DEPTH_M1 0x0810 +#define NPU_REG_IFM_PRECISION 0x0814 +#define NPU_REG_IFM_UPSCALE 0x081C +#define NPU_REG_IFM_ZERO_POINT 0x0824 +#define NPU_REG_IFM_WIDTH0_M1 0x0828 +#define NPU_REG_IFM_HEIGHT0_M1 0x082C +#define NPU_REG_IFM_HEIGHT1_M1 0x0830 +#define NPU_REG_IFM_IB_END 0x0834 +#define NPU_REG_IFM_REGION 0x083C +#define TSU_IFM_REGISTERS_SIZE 0x0840 + +// +// Register subpage TSU_OFM +// +#define NPU_REG_OFM_WIDTH_M1 0x0844 +#define NPU_REG_OFM_HEIGHT_M1 0x0848 +#define NPU_REG_OFM_DEPTH_M1 0x084C +#define NPU_REG_OFM_PRECISION 0x0850 +#define NPU_REG_OFM_BLK_WIDTH_M1 0x0854 +#define NPU_REG_OFM_BLK_HEIGHT_M1 0x0858 +#define NPU_REG_OFM_BLK_DEPTH_M1 0x085C +#define NPU_REG_OFM_ZERO_POINT 0x0860 +#define NPU_REG_OFM_WIDTH0_M1 0x0868 +#define NPU_REG_OFM_HEIGHT0_M1 0x086C +#define NPU_REG_OFM_HEIGHT1_M1 0x0870 +#define NPU_REG_OFM_REGION 0x087C +#define TSU_OFM_REGISTERS_SIZE 0x0880 + +// +// Register subpage TSU_KERNEL +// +#define NPU_REG_KERNEL_WIDTH_M1 0x0880 +#define NPU_REG_KERNEL_HEIGHT_M1 0x0884 +#define NPU_REG_KERNEL_STRIDE 0x0888 +#define NPU_REG_ACC_FORMAT 0x0890 +#define NPU_REG_ACTIVATION 0x0894 +#define NPU_REG_ACTIVATION_MIN 0x0898 +#define NPU_REG_ACTIVATION_MAX 0x089C +#define NPU_REG_WEIGHT_REGION 0x08A0 +#define NPU_REG_SCALE_REGION 0x08A4 +#define NPU_REG_AB_START 0x08B4 +#define NPU_REG_BLOCKDEP 0x08BC +#define TSU_KERNEL_REGISTERS_SIZE 0x08C0 + +// +// Register subpage TSU_DMA +// +#define NPU_REG_DMA0_SRC_REGION 0x08C0 +#define NPU_REG_DMA0_DST_REGION 0x08C4 +#define NPU_REG_DMA0_SIZE0 0x08C8 +#define NPU_REG_DMA0_SIZE1 0x08CC +#define TSU_DMA_REGISTERS_SIZE 0x0900 + +// +// Register subpage TSU_IFM2 +// +#define NPU_REG_IFM2_BROADCAST 0x0900 +#define NPU_REG_IFM2_SCALAR 0x0904 +#define NPU_REG_IFM2_PRECISION 0x0914 +#define NPU_REG_IFM2_ZERO_POINT 0x0924 +#define NPU_REG_IFM2_WIDTH0_M1 0x0928 +#define NPU_REG_IFM2_HEIGHT0_M1 0x092C +#define NPU_REG_IFM2_HEIGHT1_M1 0x0930 +#define NPU_REG_IFM2_IB_START 0x0934 +#define NPU_REG_IFM2_REGION 0x093C +#define TSU_IFM2_REGISTERS_SIZE 0x0940 + +// +// Register subpage TSU_IFM_BASE +// +#define NPU_REG_IFM_BASE0 0x0A00 +#define NPU_REG_IFM_BASE0_HI 0x0A04 +#define NPU_REG_IFM_BASE1 0x0A08 +#define NPU_REG_IFM_BASE1_HI 0x0A0C +#define NPU_REG_IFM_BASE2 0x0A10 +#define NPU_REG_IFM_BASE2_HI 0x0A14 +#define NPU_REG_IFM_BASE3 0x0A18 +#define NPU_REG_IFM_BASE3_HI 0x0A1C +#define NPU_REG_IFM_STRIDE_X 0x0A20 +#define NPU_REG_IFM_STRIDE_X_HI 0x0A24 +#define NPU_REG_IFM_STRIDE_Y 0x0A28 +#define NPU_REG_IFM_STRIDE_Y_HI 0x0A2C +#define NPU_REG_IFM_STRIDE_C 0x0A30 +#define NPU_REG_IFM_STRIDE_C_HI 0x0A34 +#define TSU_IFM_BASE_REGISTERS_SIZE 0x0A40 + +// +// Register subpage TSU_OFM_BASE +// +#define NPU_REG_OFM_BASE0 0x0A40 +#define NPU_REG_OFM_BASE0_HI 0x0A44 +#define NPU_REG_OFM_BASE1 0x0A48 +#define NPU_REG_OFM_BASE1_HI 0x0A4C +#define NPU_REG_OFM_BASE2 0x0A50 +#define NPU_REG_OFM_BASE2_HI 0x0A54 +#define NPU_REG_OFM_BASE3 0x0A58 +#define NPU_REG_OFM_BASE3_HI 0x0A5C +#define NPU_REG_OFM_STRIDE_X 0x0A60 +#define NPU_REG_OFM_STRIDE_X_HI 0x0A64 +#define NPU_REG_OFM_STRIDE_Y 0x0A68 +#define NPU_REG_OFM_STRIDE_Y_HI 0x0A6C +#define NPU_REG_OFM_STRIDE_C 0x0A70 +#define NPU_REG_OFM_STRIDE_C_HI 0x0A74 +#define TSU_OFM_BASE_REGISTERS_SIZE 0x0A80 + +// +// Register subpage TSU_WS_BASE +// +#define NPU_REG_WEIGHT_BASE 0x0A80 +#define NPU_REG_WEIGHT_BASE_HI 0x0A84 +#define NPU_REG_WEIGHT_LENGTH 0x0A88 +#define NPU_REG_WEIGHT_LENGTH_HI 0x0A8C +#define NPU_REG_SCALE_BASE 0x0A90 +#define NPU_REG_SCALE_BASE_HI 0x0A94 +#define NPU_REG_SCALE_LENGTH 0x0A98 +#define NPU_REG_SCALE_LENGTH_HI 0x0A9C +#define NPU_REG_OFM_SCALE 0x0AA0 +#define NPU_REG_OFM_SCALE_SHIFT 0x0AA4 +#define NPU_REG_OPA_SCALE 0x0AA8 +#define NPU_REG_OPA_SCALE_SHIFT 0x0AAC +#define NPU_REG_OPB_SCALE 0x0AB0 +#define TSU_WS_BASE_REGISTERS_SIZE 0x0AC0 + +// +// Register subpage TSU_DMA_BASE +// +#define NPU_REG_DMA0_SRC 0x0AC0 +#define NPU_REG_DMA0_SRC_HI 0x0AC4 +#define NPU_REG_DMA0_DST 0x0AC8 +#define NPU_REG_DMA0_DST_HI 0x0ACC +#define NPU_REG_DMA0_LEN 0x0AD0 +#define NPU_REG_DMA0_LEN_HI 0x0AD4 +#define TSU_DMA_BASE_REGISTERS_SIZE 0x0B00 + +// +// Register subpage TSU_IFM2_BASE +// +#define NPU_REG_IFM2_BASE0 0x0B00 +#define NPU_REG_IFM2_BASE0_HI 0x0B04 +#define NPU_REG_IFM2_BASE1 0x0B08 +#define NPU_REG_IFM2_BASE1_HI 0x0B0C +#define NPU_REG_IFM2_BASE2 0x0B10 +#define NPU_REG_IFM2_BASE2_HI 0x0B14 +#define NPU_REG_IFM2_BASE3 0x0B18 +#define NPU_REG_IFM2_BASE3_HI 0x0B1C +#define NPU_REG_IFM2_STRIDE_X 0x0B20 +#define NPU_REG_IFM2_STRIDE_X_HI 0x0B24 +#define NPU_REG_IFM2_STRIDE_Y 0x0B28 +#define NPU_REG_IFM2_STRIDE_Y_HI 0x0B2C +#define NPU_REG_IFM2_STRIDE_C 0x0B30 +#define NPU_REG_IFM2_STRIDE_C_HI 0x0B34 +#define TSU_IFM2_BASE_REGISTERS_SIZE 0x0B40 + +// +// Register subpage TSU_WS1_BASE +// +#define TSU_WS1_BASE_REGISTERS_SIZE 0x0B80 + +// +// Register subpage TSU_USER_BASE +// +#define NPU_REG_USER_DEFINED_BASE 0x0B80 +#define NPU_REG_USER_DEFINED_ARRLEN 0x0008 +#define TSU_USER_BASE_REGISTERS_SIZE 0x0BC0 + +// +// Register subpage TSU_DMA_EBASE +// +#define TSU_DMA_EBASE_REGISTERS_SIZE 0x0C00 + +// +// Register subpage ID +// +#define NPU_REG_REVISION 0x0FC0 +#define NPU_REG_PID4 0x0FD0 +#define NPU_REG_PID5 0x0FD4 +#define NPU_REG_PID6 0x0FD8 +#define NPU_REG_PID7 0x0FDC +#define NPU_REG_PID0 0x0FE0 +#define NPU_REG_PID1 0x0FE4 +#define NPU_REG_PID2 0x0FE8 +#define NPU_REG_PID3 0x0FEC +#define NPU_REG_CID0 0x0FF0 +#define NPU_REG_CID1 0x0FF4 +#define NPU_REG_CID2 0x0FF8 +#define NPU_REG_CID3 0x0FFC +#define ID_REGISTERS_SIZE 0x1000 + +#ifdef __cplusplus +// Enum types +enum class acc_format : uint8_t +{ + I32 = 0, + I40 = 1, + F16 = 2, +}; + +enum class activation_clip_range : uint8_t +{ + OFM_PRECISION = 0, + FORCE_UINT8 = 2, + FORCE_INT8 = 3, + FORCE_INT16 = 5, +}; + +enum class activation_format : uint8_t +{ + NHWC = 0, + NHCWB16 = 1, +}; + +enum class activation_function : uint8_t +{ + RELU = 0, + TANH = 3, + SIGMOID = 4, + TABLE_0 = 16, + TABLE_1 = 17, + TABLE_2 = 18, + TABLE_3 = 19, + TABLE_4 = 20, + TABLE_5 = 21, + TABLE_6 = 22, + TABLE_7 = 23, +}; + +enum class activation_precision : uint8_t +{ + B8 = 0, + B16 = 1, + B32 = 2, + B64 = 3, +}; + +enum class activation_type : uint8_t +{ + UNSIGNED = 0, + SIGNED = 1, +}; + +enum class axi_mem_encoding : uint8_t +{ + DEVICE_NON_BUFFERABLE = 0, + DEVICE_BUFFERABLE = 1, + NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + WRITE_THROUGH_NO_ALLOCATE = 4, + WRITE_THROUGH_READ_ALLOCATE = 5, + WRITE_THROUGH_WRITE_ALLOCATE = 6, + WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + WRITE_BACK_NO_ALLOCATE = 8, + WRITE_BACK_READ_ALLOCATE = 9, + WRITE_BACK_WRITE_ALLOCATE = 10, + WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum class broadcast_mode : uint8_t +{ + DISABLE = 0, + ENABLE = 1, +}; + +enum class cmd0_opcode : uint16_t +{ + NPU_OP_STOP = 0, + NPU_OP_IRQ = 1, + NPU_OP_CONV = 2, + NPU_OP_DEPTHWISE = 3, + NPU_OP_POOL = 5, + NPU_OP_ELEMENTWISE = 6, + NPU_OP_DMA_START = 16, + NPU_OP_DMA_WAIT = 17, + NPU_OP_KERNEL_WAIT = 18, + NPU_OP_PMU_MASK = 19, + NPU_SET_IFM_PAD_TOP = 256, + NPU_SET_IFM_PAD_LEFT = 257, + NPU_SET_IFM_PAD_RIGHT = 258, + NPU_SET_IFM_PAD_BOTTOM = 259, + NPU_SET_IFM_DEPTH_M1 = 260, + NPU_SET_IFM_PRECISION = 261, + NPU_SET_IFM_UPSCALE = 263, + NPU_SET_IFM_ZERO_POINT = 265, + NPU_SET_IFM_WIDTH0_M1 = 266, + NPU_SET_IFM_HEIGHT0_M1 = 267, + NPU_SET_IFM_HEIGHT1_M1 = 268, + NPU_SET_IFM_IB_END = 269, + NPU_SET_IFM_REGION = 271, + NPU_SET_OFM_WIDTH_M1 = 273, + NPU_SET_OFM_HEIGHT_M1 = 274, + NPU_SET_OFM_DEPTH_M1 = 275, + NPU_SET_OFM_PRECISION = 276, + NPU_SET_OFM_BLK_WIDTH_M1 = 277, + NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + NPU_SET_OFM_BLK_DEPTH_M1 = 279, + NPU_SET_OFM_ZERO_POINT = 280, + NPU_SET_OFM_WIDTH0_M1 = 282, + NPU_SET_OFM_HEIGHT0_M1 = 283, + NPU_SET_OFM_HEIGHT1_M1 = 284, + NPU_SET_OFM_REGION = 287, + NPU_SET_KERNEL_WIDTH_M1 = 288, + NPU_SET_KERNEL_HEIGHT_M1 = 289, + NPU_SET_KERNEL_STRIDE = 290, + NPU_SET_ACC_FORMAT = 292, + NPU_SET_ACTIVATION = 293, + NPU_SET_ACTIVATION_MIN = 294, + NPU_SET_ACTIVATION_MAX = 295, + NPU_SET_WEIGHT_REGION = 296, + NPU_SET_SCALE_REGION = 297, + NPU_SET_AB_START = 301, + NPU_SET_BLOCKDEP = 303, + NPU_SET_DMA0_SRC_REGION = 304, + NPU_SET_DMA0_DST_REGION = 305, + NPU_SET_DMA0_SIZE0 = 306, + NPU_SET_DMA0_SIZE1 = 307, + NPU_SET_IFM2_BROADCAST = 384, + NPU_SET_IFM2_SCALAR = 385, + NPU_SET_IFM2_PRECISION = 389, + NPU_SET_IFM2_ZERO_POINT = 393, + NPU_SET_IFM2_WIDTH0_M1 = 394, + NPU_SET_IFM2_HEIGHT0_M1 = 395, + NPU_SET_IFM2_HEIGHT1_M1 = 396, + NPU_SET_IFM2_IB_START = 397, + NPU_SET_IFM2_REGION = 399, +}; + +enum class cmd1_opcode : uint16_t +{ + NPU_SET_IFM_BASE0 = 0, + NPU_SET_IFM_BASE1 = 1, + NPU_SET_IFM_BASE2 = 2, + NPU_SET_IFM_BASE3 = 3, + NPU_SET_IFM_STRIDE_X = 4, + NPU_SET_IFM_STRIDE_Y = 5, + NPU_SET_IFM_STRIDE_C = 6, + NPU_SET_OFM_BASE0 = 16, + NPU_SET_OFM_BASE1 = 17, + NPU_SET_OFM_BASE2 = 18, + NPU_SET_OFM_BASE3 = 19, + NPU_SET_OFM_STRIDE_X = 20, + NPU_SET_OFM_STRIDE_Y = 21, + NPU_SET_OFM_STRIDE_C = 22, + NPU_SET_WEIGHT_BASE = 32, + NPU_SET_WEIGHT_LENGTH = 33, + NPU_SET_SCALE_BASE = 34, + NPU_SET_SCALE_LENGTH = 35, + NPU_SET_OFM_SCALE = 36, + NPU_SET_OPA_SCALE = 37, + NPU_SET_OPB_SCALE = 38, + NPU_SET_DMA0_SRC = 48, + NPU_SET_DMA0_DST = 49, + NPU_SET_DMA0_LEN = 50, + NPU_SET_IFM2_BASE0 = 128, + NPU_SET_IFM2_BASE1 = 129, + NPU_SET_IFM2_BASE2 = 130, + NPU_SET_IFM2_BASE3 = 131, + NPU_SET_IFM2_STRIDE_X = 132, + NPU_SET_IFM2_STRIDE_Y = 133, + NPU_SET_IFM2_STRIDE_C = 134, + NPU_SET_USER_DEFINED0 = 160, + NPU_SET_USER_DEFINED1 = 161, + NPU_SET_USER_DEFINED2 = 162, + NPU_SET_USER_DEFINED3 = 163, + NPU_SET_USER_DEFINED4 = 164, + NPU_SET_USER_DEFINED5 = 165, + NPU_SET_USER_DEFINED6 = 166, + NPU_SET_USER_DEFINED7 = 167, +}; + +enum class cmd_ctrl : uint8_t +{ + CMD0_CTRL = 0, + CMD1_CTRL = 1, +}; + +enum class custom_dma_cs : uint8_t +{ + DISABLE = 0, + ENABLE = 1, +}; + +enum class custom_dma : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class dma_fault_src : uint8_t +{ + AXI_M0 = 0, + AXI_M1 = 1, +}; + +enum class dma_region_mode : uint8_t +{ + EXTERNAL = 0, + INTERNAL = 1, +}; + +enum class dma_stride_mode : uint8_t +{ + D1 = 0, +}; + +enum class elementwise_mode : uint8_t +{ + MUL = 0, + ADD = 1, + SUB = 2, + MIN = 3, + MAX = 4, + LRELU = 5, + ABS = 6, + CLZ = 7, + SHR = 8, + SHL = 9, +}; + +enum class functional_safety : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class ifm2_operand_order : uint8_t +{ + ORDER_B = 0, + ORDER_A = 1, +}; + +enum class ifm_scale_mode : uint8_t +{ + OPA_OPB_16 = 0, + OPA_32 = 1, + OPB_32 = 2, +}; + +enum class ifm_upscale_mode : uint8_t +{ + NONE = 0, + NEAREST = 1, + ZEROS = 2, +}; + +enum class kernel_decomposition : uint8_t +{ + D8X8 = 0, + D4X4 = 1, +}; + +enum class kernel_dilation : uint8_t +{ + NONE = 0, + X2 = 1, +}; + +enum class max_beats : uint8_t +{ + B64 = 0, + B128 = 1, + B256 = 2, +}; + +enum class mem_attr : uint8_t +{ + AXI0_OUTSTANDING_COUNTER0 = 0, + AXI0_OUTSTANDING_COUNTER1 = 1, + AXI1_OUTSTANDING_COUNTER2 = 2, + AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum class ofm_scale_mode : uint8_t +{ + PER_CHANNEL = 0, + GLOBAL = 1, +}; + +enum class pmu_axi_channel : uint8_t +{ + RD_CMD = 0, + RD_IFM = 1, + RD_WEIGHTS = 2, + RD_SCALE_BIAS = 3, + RD_MEM2MEM = 4, + WR_OFM = 8, + WR_MEM2MEM = 9, +}; + +enum class pmu_event : uint16_t +{ + NO_EVENT = 0, + CYCLE = 17, + NPU_IDLE = 32, + CC_STALLED_ON_BLOCKDEP = 33, + CC_STALLED_ON_SHRAM_RECONFIG = 34, + NPU_ACTIVE = 35, + MAC_ACTIVE = 48, + MAC_ACTIVE_8BIT = 49, + MAC_ACTIVE_16BIT = 50, + MAC_DPU_ACTIVE = 51, + MAC_STALLED_BY_WD_ACC = 52, + MAC_STALLED_BY_WD = 53, + MAC_STALLED_BY_ACC = 54, + MAC_STALLED_BY_IB = 55, + MAC_ACTIVE_32BIT = 56, + MAC_STALLED_BY_INT_W = 57, + MAC_STALLED_BY_INT_ACC = 58, + AO_ACTIVE = 64, + AO_ACTIVE_8BIT = 65, + AO_ACTIVE_16BIT = 66, + AO_STALLED_BY_OFMP_OB = 67, + AO_STALLED_BY_OFMP = 68, + AO_STALLED_BY_OB = 69, + AO_STALLED_BY_ACC_IB = 70, + AO_STALLED_BY_ACC = 71, + AO_STALLED_BY_IB = 72, + WD_ACTIVE = 80, + WD_STALLED = 81, + WD_STALLED_BY_WS = 82, + WD_STALLED_BY_WD_BUF = 83, + WD_PARSE_ACTIVE = 84, + WD_PARSE_STALLED = 85, + WD_PARSE_STALLED_IN = 86, + WD_PARSE_STALLED_OUT = 87, + WD_TRANS_WS = 88, + WD_TRANS_WB = 89, + WD_TRANS_DW0 = 90, + WD_TRANS_DW1 = 91, + AXI0_RD_TRANS_ACCEPTED = 128, + AXI0_RD_TRANS_COMPLETED = 129, + AXI0_RD_DATA_BEAT_RECEIVED = 130, + AXI0_RD_TRAN_REQ_STALLED = 131, + AXI0_WR_TRANS_ACCEPTED = 132, + AXI0_WR_TRANS_COMPLETED_M = 133, + AXI0_WR_TRANS_COMPLETED_S = 134, + AXI0_WR_DATA_BEAT_WRITTEN = 135, + AXI0_WR_TRAN_REQ_STALLED = 136, + AXI0_WR_DATA_BEAT_STALLED = 137, + AXI0_ENABLED_CYCLES = 140, + AXI0_RD_STALL_LIMIT = 142, + AXI0_WR_STALL_LIMIT = 143, + AXI_LATENCY_ANY = 160, + AXI_LATENCY_32 = 161, + AXI_LATENCY_64 = 162, + AXI_LATENCY_128 = 163, + AXI_LATENCY_256 = 164, + AXI_LATENCY_512 = 165, + AXI_LATENCY_1024 = 166, + ECC_DMA = 176, + ECC_SB0 = 177, + AXI1_RD_TRANS_ACCEPTED = 384, + AXI1_RD_TRANS_COMPLETED = 385, + AXI1_RD_DATA_BEAT_RECEIVED = 386, + AXI1_RD_TRAN_REQ_STALLED = 387, + AXI1_WR_TRANS_ACCEPTED = 388, + AXI1_WR_TRANS_COMPLETED_M = 389, + AXI1_WR_TRANS_COMPLETED_S = 390, + AXI1_WR_DATA_BEAT_WRITTEN = 391, + AXI1_WR_TRAN_REQ_STALLED = 392, + AXI1_WR_DATA_BEAT_STALLED = 393, + AXI1_ENABLED_CYCLES = 396, + AXI1_RD_STALL_LIMIT = 398, + AXI1_WR_STALL_LIMIT = 399, + ECC_SB1 = 433, +}; + +enum class pooling_mode : uint8_t +{ + MAX = 0, + AVERAGE = 1, + REDUCE_SUM = 2, +}; + +enum class privilege_level : uint8_t +{ + USER = 0, + PRIVILEGED = 1, +}; + +enum class round_mode : uint8_t +{ + DBL = 0, + TRUNCATE = 1, + NATURAL = 2, +}; + +enum class security_level : uint8_t +{ + SECURE = 0, + NON_SECURE = 1, +}; + +enum class state : uint8_t +{ + STOPPED = 0, + RUNNING = 1, +}; + +enum class wd_core_slice_state : uint8_t +{ + HEADER = 0, + PALETTE = 1, + WEIGHTS = 2, +}; + +enum class wd_ctrl_state : uint8_t +{ + IDLE = 0, + DRAIN = 1, + OFD_INIT = 2, + OFD_RUN = 3, +}; + +enum class weight_order : uint8_t +{ + DEPTH_FIRST = 0, + PART_KERNEL_FIRST = 1, +}; + +#else + +enum acc_format +{ + ACC_FORMAT_I32 = 0, + ACC_FORMAT_I40 = 1, + ACC_FORMAT_F16 = 2, +}; + +enum activation_clip_range +{ + ACTIVATION_CLIP_RANGE_OFM_PRECISION = 0, + ACTIVATION_CLIP_RANGE_FORCE_UINT8 = 2, + ACTIVATION_CLIP_RANGE_FORCE_INT8 = 3, + ACTIVATION_CLIP_RANGE_FORCE_INT16 = 5, +}; + +enum activation_format +{ + ACTIVATION_FORMAT_NHWC = 0, + ACTIVATION_FORMAT_NHCWB16 = 1, +}; + +enum activation_function +{ + ACTIVATION_FUNCTION_RELU = 0, + ACTIVATION_FUNCTION_TANH = 3, + ACTIVATION_FUNCTION_SIGMOID = 4, + ACTIVATION_FUNCTION_TABLE_0 = 16, + ACTIVATION_FUNCTION_TABLE_1 = 17, + ACTIVATION_FUNCTION_TABLE_2 = 18, + ACTIVATION_FUNCTION_TABLE_3 = 19, + ACTIVATION_FUNCTION_TABLE_4 = 20, + ACTIVATION_FUNCTION_TABLE_5 = 21, + ACTIVATION_FUNCTION_TABLE_6 = 22, + ACTIVATION_FUNCTION_TABLE_7 = 23, +}; + +enum activation_precision +{ + ACTIVATION_PRECISION_B8 = 0, + ACTIVATION_PRECISION_B16 = 1, + ACTIVATION_PRECISION_B32 = 2, + ACTIVATION_PRECISION_B64 = 3, +}; + +enum activation_type +{ + ACTIVATION_TYPE_UNSIGNED = 0, + ACTIVATION_TYPE_SIGNED = 1, +}; + +enum axi_mem_encoding +{ + AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE = 0, + AXI_MEM_ENCODING_DEVICE_BUFFERABLE = 1, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE = 4, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE = 5, + AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE = 6, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE = 8, + AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE = 9, + AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE = 10, + AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum broadcast_mode +{ + BROADCAST_MODE_DISABLE = 0, + BROADCAST_MODE_ENABLE = 1, +}; + +enum cmd0_opcode +{ + CMD0_OPCODE_NPU_OP_STOP = 0, + CMD0_OPCODE_NPU_OP_IRQ = 1, + CMD0_OPCODE_NPU_OP_CONV = 2, + CMD0_OPCODE_NPU_OP_DEPTHWISE = 3, + CMD0_OPCODE_NPU_OP_POOL = 5, + CMD0_OPCODE_NPU_OP_ELEMENTWISE = 6, + CMD0_OPCODE_NPU_OP_DMA_START = 16, + CMD0_OPCODE_NPU_OP_DMA_WAIT = 17, + CMD0_OPCODE_NPU_OP_KERNEL_WAIT = 18, + CMD0_OPCODE_NPU_OP_PMU_MASK = 19, + CMD0_OPCODE_NPU_SET_IFM_PAD_TOP = 256, + CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT = 257, + CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT = 258, + CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM = 259, + CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1 = 260, + CMD0_OPCODE_NPU_SET_IFM_PRECISION = 261, + CMD0_OPCODE_NPU_SET_IFM_UPSCALE = 263, + CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT = 265, + CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1 = 266, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1 = 267, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1 = 268, + CMD0_OPCODE_NPU_SET_IFM_IB_END = 269, + CMD0_OPCODE_NPU_SET_IFM_REGION = 271, + CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1 = 273, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1 = 274, + CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1 = 275, + CMD0_OPCODE_NPU_SET_OFM_PRECISION = 276, + CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1 = 277, + CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1 = 279, + CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT = 280, + CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1 = 282, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1 = 283, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1 = 284, + CMD0_OPCODE_NPU_SET_OFM_REGION = 287, + CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1 = 288, + CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1 = 289, + CMD0_OPCODE_NPU_SET_KERNEL_STRIDE = 290, + CMD0_OPCODE_NPU_SET_ACC_FORMAT = 292, + CMD0_OPCODE_NPU_SET_ACTIVATION = 293, + CMD0_OPCODE_NPU_SET_ACTIVATION_MIN = 294, + CMD0_OPCODE_NPU_SET_ACTIVATION_MAX = 295, + CMD0_OPCODE_NPU_SET_WEIGHT_REGION = 296, + CMD0_OPCODE_NPU_SET_SCALE_REGION = 297, + CMD0_OPCODE_NPU_SET_AB_START = 301, + CMD0_OPCODE_NPU_SET_BLOCKDEP = 303, + CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION = 304, + CMD0_OPCODE_NPU_SET_DMA0_DST_REGION = 305, + CMD0_OPCODE_NPU_SET_DMA0_SIZE0 = 306, + CMD0_OPCODE_NPU_SET_DMA0_SIZE1 = 307, + CMD0_OPCODE_NPU_SET_IFM2_BROADCAST = 384, + CMD0_OPCODE_NPU_SET_IFM2_SCALAR = 385, + CMD0_OPCODE_NPU_SET_IFM2_PRECISION = 389, + CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT = 393, + CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1 = 394, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1 = 395, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1 = 396, + CMD0_OPCODE_NPU_SET_IFM2_IB_START = 397, + CMD0_OPCODE_NPU_SET_IFM2_REGION = 399, +}; + +enum cmd1_opcode +{ + CMD1_OPCODE_NPU_SET_IFM_BASE0 = 0, + CMD1_OPCODE_NPU_SET_IFM_BASE1 = 1, + CMD1_OPCODE_NPU_SET_IFM_BASE2 = 2, + CMD1_OPCODE_NPU_SET_IFM_BASE3 = 3, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_X = 4, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y = 5, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_C = 6, + CMD1_OPCODE_NPU_SET_OFM_BASE0 = 16, + CMD1_OPCODE_NPU_SET_OFM_BASE1 = 17, + CMD1_OPCODE_NPU_SET_OFM_BASE2 = 18, + CMD1_OPCODE_NPU_SET_OFM_BASE3 = 19, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_X = 20, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y = 21, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_C = 22, + CMD1_OPCODE_NPU_SET_WEIGHT_BASE = 32, + CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH = 33, + CMD1_OPCODE_NPU_SET_SCALE_BASE = 34, + CMD1_OPCODE_NPU_SET_SCALE_LENGTH = 35, + CMD1_OPCODE_NPU_SET_OFM_SCALE = 36, + CMD1_OPCODE_NPU_SET_OPA_SCALE = 37, + CMD1_OPCODE_NPU_SET_OPB_SCALE = 38, + CMD1_OPCODE_NPU_SET_DMA0_SRC = 48, + CMD1_OPCODE_NPU_SET_DMA0_DST = 49, + CMD1_OPCODE_NPU_SET_DMA0_LEN = 50, + CMD1_OPCODE_NPU_SET_IFM2_BASE0 = 128, + CMD1_OPCODE_NPU_SET_IFM2_BASE1 = 129, + CMD1_OPCODE_NPU_SET_IFM2_BASE2 = 130, + CMD1_OPCODE_NPU_SET_IFM2_BASE3 = 131, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X = 132, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y = 133, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C = 134, + CMD1_OPCODE_NPU_SET_USER_DEFINED0 = 160, + CMD1_OPCODE_NPU_SET_USER_DEFINED1 = 161, + CMD1_OPCODE_NPU_SET_USER_DEFINED2 = 162, + CMD1_OPCODE_NPU_SET_USER_DEFINED3 = 163, + CMD1_OPCODE_NPU_SET_USER_DEFINED4 = 164, + CMD1_OPCODE_NPU_SET_USER_DEFINED5 = 165, + CMD1_OPCODE_NPU_SET_USER_DEFINED6 = 166, + CMD1_OPCODE_NPU_SET_USER_DEFINED7 = 167, +}; + +enum cmd_ctrl +{ + CMD_CTRL_CMD0_CTRL = 0, + CMD_CTRL_CMD1_CTRL = 1, +}; + +enum custom_dma_cs +{ + CUSTOM_DMA_CS_DISABLE = 0, + CUSTOM_DMA_CS_ENABLE = 1, +}; + +enum custom_dma +{ + CUSTOM_DMA_NOT_IMPLEMENTED = 0, + CUSTOM_DMA_IMPLEMENTED = 1, +}; + +enum dma_fault_src +{ + DMA_FAULT_SRC_AXI_M0 = 0, + DMA_FAULT_SRC_AXI_M1 = 1, +}; + +enum dma_region_mode +{ + DMA_REGION_MODE_EXTERNAL = 0, + DMA_REGION_MODE_INTERNAL = 1, +}; + +enum dma_stride_mode +{ + DMA_STRIDE_MODE_D1 = 0, +}; + +enum elementwise_mode +{ + ELEMENTWISE_MODE_MUL = 0, + ELEMENTWISE_MODE_ADD = 1, + ELEMENTWISE_MODE_SUB = 2, + ELEMENTWISE_MODE_MIN = 3, + ELEMENTWISE_MODE_MAX = 4, + ELEMENTWISE_MODE_LRELU = 5, + ELEMENTWISE_MODE_ABS = 6, + ELEMENTWISE_MODE_CLZ = 7, + ELEMENTWISE_MODE_SHR = 8, + ELEMENTWISE_MODE_SHL = 9, +}; + +enum functional_safety +{ + FUNCTIONAL_SAFETY_NOT_IMPLEMENTED = 0, + FUNCTIONAL_SAFETY_IMPLEMENTED = 1, +}; + +enum ifm2_operand_order +{ + IFM2_OPERAND_ORDER_ORDER_B = 0, + IFM2_OPERAND_ORDER_ORDER_A = 1, +}; + +enum ifm_scale_mode +{ + IFM_SCALE_MODE_OPA_OPB_16 = 0, + IFM_SCALE_MODE_OPA_32 = 1, + IFM_SCALE_MODE_OPB_32 = 2, +}; + +enum ifm_upscale_mode +{ + IFM_UPSCALE_MODE_NONE = 0, + IFM_UPSCALE_MODE_NEAREST = 1, + IFM_UPSCALE_MODE_ZEROS = 2, +}; + +enum kernel_decomposition +{ + KERNEL_DECOMPOSITION_D8X8 = 0, + KERNEL_DECOMPOSITION_D4X4 = 1, +}; + +enum kernel_dilation +{ + KERNEL_DILATION_NONE = 0, + KERNEL_DILATION_X2 = 1, +}; + +enum max_beats +{ + MAX_BEATS_B64 = 0, + MAX_BEATS_B128 = 1, + MAX_BEATS_B256 = 2, +}; + +enum mem_attr +{ + MEM_ATTR_AXI0_OUTSTANDING_COUNTER0 = 0, + MEM_ATTR_AXI0_OUTSTANDING_COUNTER1 = 1, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER2 = 2, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum ofm_scale_mode +{ + OFM_SCALE_MODE_PER_CHANNEL = 0, + OFM_SCALE_MODE_GLOBAL = 1, +}; + +enum pmu_axi_channel +{ + PMU_AXI_CHANNEL_RD_CMD = 0, + PMU_AXI_CHANNEL_RD_IFM = 1, + PMU_AXI_CHANNEL_RD_WEIGHTS = 2, + PMU_AXI_CHANNEL_RD_SCALE_BIAS = 3, + PMU_AXI_CHANNEL_RD_MEM2MEM = 4, + PMU_AXI_CHANNEL_WR_OFM = 8, + PMU_AXI_CHANNEL_WR_MEM2MEM = 9, +}; + +enum pmu_event +{ + PMU_EVENT_NO_EVENT = 0, + PMU_EVENT_CYCLE = 17, + PMU_EVENT_NPU_IDLE = 32, + PMU_EVENT_CC_STALLED_ON_BLOCKDEP = 33, + PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG = 34, + PMU_EVENT_NPU_ACTIVE = 35, + PMU_EVENT_MAC_ACTIVE = 48, + PMU_EVENT_MAC_ACTIVE_8BIT = 49, + PMU_EVENT_MAC_ACTIVE_16BIT = 50, + PMU_EVENT_MAC_DPU_ACTIVE = 51, + PMU_EVENT_MAC_STALLED_BY_WD_ACC = 52, + PMU_EVENT_MAC_STALLED_BY_WD = 53, + PMU_EVENT_MAC_STALLED_BY_ACC = 54, + PMU_EVENT_MAC_STALLED_BY_IB = 55, + PMU_EVENT_MAC_ACTIVE_32BIT = 56, + PMU_EVENT_MAC_STALLED_BY_INT_W = 57, + PMU_EVENT_MAC_STALLED_BY_INT_ACC = 58, + PMU_EVENT_AO_ACTIVE = 64, + PMU_EVENT_AO_ACTIVE_8BIT = 65, + PMU_EVENT_AO_ACTIVE_16BIT = 66, + PMU_EVENT_AO_STALLED_BY_OFMP_OB = 67, + PMU_EVENT_AO_STALLED_BY_OFMP = 68, + PMU_EVENT_AO_STALLED_BY_OB = 69, + PMU_EVENT_AO_STALLED_BY_ACC_IB = 70, + PMU_EVENT_AO_STALLED_BY_ACC = 71, + PMU_EVENT_AO_STALLED_BY_IB = 72, + PMU_EVENT_WD_ACTIVE = 80, + PMU_EVENT_WD_STALLED = 81, + PMU_EVENT_WD_STALLED_BY_WS = 82, + PMU_EVENT_WD_STALLED_BY_WD_BUF = 83, + PMU_EVENT_WD_PARSE_ACTIVE = 84, + PMU_EVENT_WD_PARSE_STALLED = 85, + PMU_EVENT_WD_PARSE_STALLED_IN = 86, + PMU_EVENT_WD_PARSE_STALLED_OUT = 87, + PMU_EVENT_WD_TRANS_WS = 88, + PMU_EVENT_WD_TRANS_WB = 89, + PMU_EVENT_WD_TRANS_DW0 = 90, + PMU_EVENT_WD_TRANS_DW1 = 91, + PMU_EVENT_AXI0_RD_TRANS_ACCEPTED = 128, + PMU_EVENT_AXI0_RD_TRANS_COMPLETED = 129, + PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED = 130, + PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED = 131, + PMU_EVENT_AXI0_WR_TRANS_ACCEPTED = 132, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M = 133, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S = 134, + PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN = 135, + PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED = 136, + PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED = 137, + PMU_EVENT_AXI0_ENABLED_CYCLES = 140, + PMU_EVENT_AXI0_RD_STALL_LIMIT = 142, + PMU_EVENT_AXI0_WR_STALL_LIMIT = 143, + PMU_EVENT_AXI_LATENCY_ANY = 160, + PMU_EVENT_AXI_LATENCY_32 = 161, + PMU_EVENT_AXI_LATENCY_64 = 162, + PMU_EVENT_AXI_LATENCY_128 = 163, + PMU_EVENT_AXI_LATENCY_256 = 164, + PMU_EVENT_AXI_LATENCY_512 = 165, + PMU_EVENT_AXI_LATENCY_1024 = 166, + PMU_EVENT_ECC_DMA = 176, + PMU_EVENT_ECC_SB0 = 177, + PMU_EVENT_AXI1_RD_TRANS_ACCEPTED = 384, + PMU_EVENT_AXI1_RD_TRANS_COMPLETED = 385, + PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED = 386, + PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED = 387, + PMU_EVENT_AXI1_WR_TRANS_ACCEPTED = 388, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M = 389, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S = 390, + PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN = 391, + PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED = 392, + PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED = 393, + PMU_EVENT_AXI1_ENABLED_CYCLES = 396, + PMU_EVENT_AXI1_RD_STALL_LIMIT = 398, + PMU_EVENT_AXI1_WR_STALL_LIMIT = 399, + PMU_EVENT_ECC_SB1 = 433, +}; + +enum pooling_mode +{ + POOLING_MODE_MAX = 0, + POOLING_MODE_AVERAGE = 1, + POOLING_MODE_REDUCE_SUM = 2, +}; + +enum privilege_level +{ + PRIVILEGE_LEVEL_USER = 0, + PRIVILEGE_LEVEL_PRIVILEGED = 1, +}; + +enum round_mode +{ + ROUND_MODE_DBL = 0, + ROUND_MODE_TRUNCATE = 1, + ROUND_MODE_NATURAL = 2, +}; + +enum security_level +{ + SECURITY_LEVEL_SECURE = 0, + SECURITY_LEVEL_NON_SECURE = 1, +}; + +enum state +{ + STATE_STOPPED = 0, + STATE_RUNNING = 1, +}; + +enum wd_core_slice_state +{ + WD_CORE_SLICE_STATE_HEADER = 0, + WD_CORE_SLICE_STATE_PALETTE = 1, + WD_CORE_SLICE_STATE_WEIGHTS = 2, +}; + +enum wd_ctrl_state +{ + WD_CTRL_STATE_IDLE = 0, + WD_CTRL_STATE_DRAIN = 1, + WD_CTRL_STATE_OFD_INIT = 2, + WD_CTRL_STATE_OFD_RUN = 3, +}; + +enum weight_order +{ + WEIGHT_ORDER_DEPTH_FIRST = 0, + WEIGHT_ORDER_PART_KERNEL_FIRST = 1, +}; + +#endif + +#ifdef NPU_DISASSEMBLE + +static const char *acc_format_str[] = { + "ACC_FORMAT_I32", + "ACC_FORMAT_I40", + "ACC_FORMAT_F16", +}; + +static const char *activation_clip_range_str[] = { + "ACTIVATION_CLIP_RANGE_OFM_PRECISION", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_UINT8", + "ACTIVATION_CLIP_RANGE_FORCE_INT8", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_INT16", +}; + +static const char *activation_format_str[] = { + "ACTIVATION_FORMAT_NHWC", + "ACTIVATION_FORMAT_NHCWB16", +}; + +static const char *activation_function_str[] = { + "ACTIVATION_FUNCTION_RELU", + "****", + "****", + "ACTIVATION_FUNCTION_TANH", + "ACTIVATION_FUNCTION_SIGMOID", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "ACTIVATION_FUNCTION_TABLE_0", + "ACTIVATION_FUNCTION_TABLE_1", + "ACTIVATION_FUNCTION_TABLE_2", + "ACTIVATION_FUNCTION_TABLE_3", + "ACTIVATION_FUNCTION_TABLE_4", + "ACTIVATION_FUNCTION_TABLE_5", + "ACTIVATION_FUNCTION_TABLE_6", + "ACTIVATION_FUNCTION_TABLE_7", +}; + +static const char *activation_precision_str[] = { + "ACTIVATION_PRECISION_B8", + "ACTIVATION_PRECISION_B16", + "ACTIVATION_PRECISION_B32", + "ACTIVATION_PRECISION_B64", +}; + +static const char *activation_type_str[] = { + "ACTIVATION_TYPE_UNSIGNED", + "ACTIVATION_TYPE_SIGNED", +}; + +static const char *axi_mem_encoding_str[] = { + "AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_DEVICE_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE", + "AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE", +}; + +static const char *broadcast_mode_str[] = { + "BROADCAST_MODE_DISABLE", + "BROADCAST_MODE_ENABLE", +}; + +static const char *cmd0_opcode_str[] = { + "CMD0_OPCODE_NPU_OP_STOP", + "CMD0_OPCODE_NPU_OP_IRQ", + "CMD0_OPCODE_NPU_OP_CONV", + "CMD0_OPCODE_NPU_OP_DEPTHWISE", + "****", + "CMD0_OPCODE_NPU_OP_POOL", + "CMD0_OPCODE_NPU_OP_ELEMENTWISE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_OP_DMA_START", + "CMD0_OPCODE_NPU_OP_DMA_WAIT", + "CMD0_OPCODE_NPU_OP_KERNEL_WAIT", + "CMD0_OPCODE_NPU_OP_PMU_MASK", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_PAD_TOP", + "CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM", + "CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_IFM_PRECISION", + "****", + "CMD0_OPCODE_NPU_SET_IFM_UPSCALE", + "****", + "CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM_IB_END", + "****", + "CMD0_OPCODE_NPU_SET_IFM_REGION", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_PRECISION", + "CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_OFM_REGION", + "CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_STRIDE", + "****", + "CMD0_OPCODE_NPU_SET_ACC_FORMAT", + "CMD0_OPCODE_NPU_SET_ACTIVATION", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MIN", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MAX", + "CMD0_OPCODE_NPU_SET_WEIGHT_REGION", + "CMD0_OPCODE_NPU_SET_SCALE_REGION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_AB_START", + "****", + "CMD0_OPCODE_NPU_SET_BLOCKDEP", + "CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_DST_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE0", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_BROADCAST", + "CMD0_OPCODE_NPU_SET_IFM2_SCALAR", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_PRECISION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM2_IB_START", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_REGION", +}; + +static const char *cmd1_opcode_str[] = { + "CMD1_OPCODE_NPU_SET_IFM_BASE0", + "CMD1_OPCODE_NPU_SET_IFM_BASE1", + "CMD1_OPCODE_NPU_SET_IFM_BASE2", + "CMD1_OPCODE_NPU_SET_IFM_BASE3", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_OFM_BASE0", + "CMD1_OPCODE_NPU_SET_OFM_BASE1", + "CMD1_OPCODE_NPU_SET_OFM_BASE2", + "CMD1_OPCODE_NPU_SET_OFM_BASE3", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE_BASE", + "CMD1_OPCODE_NPU_SET_SCALE_LENGTH", + "CMD1_OPCODE_NPU_SET_OFM_SCALE", + "CMD1_OPCODE_NPU_SET_OPA_SCALE", + "CMD1_OPCODE_NPU_SET_OPB_SCALE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_DMA0_SRC", + "CMD1_OPCODE_NPU_SET_DMA0_DST", + "CMD1_OPCODE_NPU_SET_DMA0_LEN", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_IFM2_BASE0", + "CMD1_OPCODE_NPU_SET_IFM2_BASE1", + "CMD1_OPCODE_NPU_SET_IFM2_BASE2", + "CMD1_OPCODE_NPU_SET_IFM2_BASE3", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_USER_DEFINED0", + "CMD1_OPCODE_NPU_SET_USER_DEFINED1", + "CMD1_OPCODE_NPU_SET_USER_DEFINED2", + "CMD1_OPCODE_NPU_SET_USER_DEFINED3", + "CMD1_OPCODE_NPU_SET_USER_DEFINED4", + "CMD1_OPCODE_NPU_SET_USER_DEFINED5", + "CMD1_OPCODE_NPU_SET_USER_DEFINED6", + "CMD1_OPCODE_NPU_SET_USER_DEFINED7", +}; + +static const char *cmd_ctrl_str[] = { + "CMD_CTRL_CMD0_CTRL", + "CMD_CTRL_CMD1_CTRL", +}; + +static const char *custom_dma_cs_str[] = { + "CUSTOM_DMA_CS_DISABLE", + "CUSTOM_DMA_CS_ENABLE", +}; + +static const char *custom_dma_str[] = { + "CUSTOM_DMA_NOT_IMPLEMENTED", + "CUSTOM_DMA_IMPLEMENTED", +}; + +static const char *dma_fault_src_str[] = { + "DMA_FAULT_SRC_AXI_M0", + "DMA_FAULT_SRC_AXI_M1", +}; + +static const char *dma_region_mode_str[] = { + "DMA_REGION_MODE_EXTERNAL", + "DMA_REGION_MODE_INTERNAL", +}; + +static const char *dma_stride_mode_str[] = { + "DMA_STRIDE_MODE_D1", +}; + +static const char *elementwise_mode_str[] = { + "ELEMENTWISE_MODE_MUL", + "ELEMENTWISE_MODE_ADD", + "ELEMENTWISE_MODE_SUB", + "ELEMENTWISE_MODE_MIN", + "ELEMENTWISE_MODE_MAX", + "ELEMENTWISE_MODE_LRELU", + "ELEMENTWISE_MODE_ABS", + "ELEMENTWISE_MODE_CLZ", + "ELEMENTWISE_MODE_SHR", + "ELEMENTWISE_MODE_SHL", +}; + +static const char *functional_safety_str[] = { + "FUNCTIONAL_SAFETY_NOT_IMPLEMENTED", + "FUNCTIONAL_SAFETY_IMPLEMENTED", +}; + +static const char *ifm2_operand_order_str[] = { + "IFM2_OPERAND_ORDER_ORDER_B", + "IFM2_OPERAND_ORDER_ORDER_A", +}; + +static const char *ifm_scale_mode_str[] = { + "IFM_SCALE_MODE_OPA_OPB_16", + "IFM_SCALE_MODE_OPA_32", + "IFM_SCALE_MODE_OPB_32", +}; + +static const char *ifm_upscale_mode_str[] = { + "IFM_UPSCALE_MODE_NONE", + "IFM_UPSCALE_MODE_NEAREST", + "IFM_UPSCALE_MODE_ZEROS", +}; + +static const char *kernel_decomposition_str[] = { + "KERNEL_DECOMPOSITION_D8X8", + "KERNEL_DECOMPOSITION_D4X4", +}; + +static const char *kernel_dilation_str[] = { + "KERNEL_DILATION_NONE", + "KERNEL_DILATION_X2", +}; + +static const char *max_beats_str[] = { + "MAX_BEATS_B64", + "MAX_BEATS_B128", + "MAX_BEATS_B256", +}; + +static const char *mem_attr_str[] = { + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER0", + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER1", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER2", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER3", +}; + +static const char *ofm_scale_mode_str[] = { + "OFM_SCALE_MODE_PER_CHANNEL", + "OFM_SCALE_MODE_GLOBAL", +}; + +static const char *pmu_axi_channel_str[] = { + "PMU_AXI_CHANNEL_RD_CMD", + "PMU_AXI_CHANNEL_RD_IFM", + "PMU_AXI_CHANNEL_RD_WEIGHTS", + "PMU_AXI_CHANNEL_RD_SCALE_BIAS", + "PMU_AXI_CHANNEL_RD_MEM2MEM", + "****", + "****", + "****", + "PMU_AXI_CHANNEL_WR_OFM", + "PMU_AXI_CHANNEL_WR_MEM2MEM", +}; + +static const char *pmu_event_str[] = { + "PMU_EVENT_NO_EVENT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_CYCLE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_NPU_IDLE", + "PMU_EVENT_CC_STALLED_ON_BLOCKDEP", + "PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG", + "PMU_EVENT_NPU_ACTIVE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_MAC_ACTIVE", + "PMU_EVENT_MAC_ACTIVE_8BIT", + "PMU_EVENT_MAC_ACTIVE_16BIT", + "PMU_EVENT_MAC_DPU_ACTIVE", + "PMU_EVENT_MAC_STALLED_BY_WD_ACC", + "PMU_EVENT_MAC_STALLED_BY_WD", + "PMU_EVENT_MAC_STALLED_BY_ACC", + "PMU_EVENT_MAC_STALLED_BY_IB", + "PMU_EVENT_MAC_ACTIVE_32BIT", + "PMU_EVENT_MAC_STALLED_BY_INT_W", + "PMU_EVENT_MAC_STALLED_BY_INT_ACC", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AO_ACTIVE", + "PMU_EVENT_AO_ACTIVE_8BIT", + "PMU_EVENT_AO_ACTIVE_16BIT", + "PMU_EVENT_AO_STALLED_BY_OFMP_OB", + "PMU_EVENT_AO_STALLED_BY_OFMP", + "PMU_EVENT_AO_STALLED_BY_OB", + "PMU_EVENT_AO_STALLED_BY_ACC_IB", + "PMU_EVENT_AO_STALLED_BY_ACC", + "PMU_EVENT_AO_STALLED_BY_IB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_ACTIVE", + "PMU_EVENT_WD_STALLED", + "PMU_EVENT_WD_STALLED_BY_WS", + "PMU_EVENT_WD_STALLED_BY_WD_BUF", + "PMU_EVENT_WD_PARSE_ACTIVE", + "PMU_EVENT_WD_PARSE_STALLED", + "PMU_EVENT_WD_PARSE_STALLED_IN", + "PMU_EVENT_WD_PARSE_STALLED_OUT", + "PMU_EVENT_WD_TRANS_WS", + "PMU_EVENT_WD_TRANS_WB", + "PMU_EVENT_WD_TRANS_DW0", + "PMU_EVENT_WD_TRANS_DW1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI0_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI0_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI0_RD_STALL_LIMIT", + "PMU_EVENT_AXI0_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI_LATENCY_ANY", + "PMU_EVENT_AXI_LATENCY_32", + "PMU_EVENT_AXI_LATENCY_64", + "PMU_EVENT_AXI_LATENCY_128", + "PMU_EVENT_AXI_LATENCY_256", + "PMU_EVENT_AXI_LATENCY_512", + "PMU_EVENT_AXI_LATENCY_1024", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_DMA", + "PMU_EVENT_ECC_SB0", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI1_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI1_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI1_RD_STALL_LIMIT", + "PMU_EVENT_AXI1_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_SB1", +}; + +static const char *pooling_mode_str[] = { + "POOLING_MODE_MAX", + "POOLING_MODE_AVERAGE", + "POOLING_MODE_REDUCE_SUM", +}; + +static const char *privilege_level_str[] = { + "PRIVILEGE_LEVEL_USER", + "PRIVILEGE_LEVEL_PRIVILEGED", +}; + +static const char *round_mode_str[] = { + "ROUND_MODE_DBL", + "ROUND_MODE_TRUNCATE", + "ROUND_MODE_NATURAL", +}; + +static const char *security_level_str[] = { + "SECURITY_LEVEL_SECURE", + "SECURITY_LEVEL_NON_SECURE", +}; + +static const char *state_str[] = { + "STATE_STOPPED", + "STATE_RUNNING", +}; + +static const char *wd_core_slice_state_str[] = { + "WD_CORE_SLICE_STATE_HEADER", + "WD_CORE_SLICE_STATE_PALETTE", + "WD_CORE_SLICE_STATE_WEIGHTS", +}; + +static const char *wd_ctrl_state_str[] = { + "WD_CTRL_STATE_IDLE", + "WD_CTRL_STATE_DRAIN", + "WD_CTRL_STATE_OFD_INIT", + "WD_CTRL_STATE_OFD_RUN", +}; + +static const char *weight_order_str[] = { + "WEIGHT_ORDER_DEPTH_FIRST", + "WEIGHT_ORDER_PART_KERNEL_FIRST", +}; + +#endif + +// Register type structs +// id_r - ID register +struct id_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t version_status : 4; // This is the version of the product + uint32_t version_minor : 4; // This is the n for the P part of an RnPn release number + uint32_t version_major : 4; // This is the n for the R part of an RnPn release number + uint32_t product_major : 4; // Product major ID number (unique per base product) + uint32_t arch_patch_rev : 4; // This is the patch number of the architecture version a.b + uint32_t + arch_minor_rev : 8; // This is the minor architecture version number, b in the architecture version a.b + uint32_t + arch_major_rev : 4; // This is the major architecture version number, a in the architecture version a.b + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR id_r() : word0(269500929) {} + CONSTEXPR id_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + id_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_version_status() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_version_status() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR id_r &set_version_status(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile id_r &set_version_status(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_version_minor() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_version_minor() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR id_r &set_version_minor(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile id_r &set_version_minor(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_version_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + uint32_t get_version_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR id_r &set_version_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + volatile id_r &set_version_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_product_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_product_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR id_r &set_product_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile id_r &set_product_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_arch_patch_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + uint32_t get_arch_patch_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR id_r &set_arch_patch_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + volatile id_r &set_arch_patch_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_arch_minor_rev() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + uint32_t get_arch_minor_rev() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR id_r &set_arch_minor_rev(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + volatile id_r &set_arch_minor_rev(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_arch_major_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_arch_major_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR id_r &set_arch_major_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile id_r &set_arch_major_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// status_r - Register describes the current operating status of the NPU +struct status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t state : 1; // NPU state, 0 = Stopped, 1 = Running + uint32_t irq_raised : 1; // Raw IRQ status, 0 = IRQ not raised, 1 = IRQ raised. IRQ is cleared using command + // register bit 1 + uint32_t + bus_status : 1; // 0=OK, 1=Bus abort detected and processing halted (NPU will reach IDLE state and not + // to start process any more commands/AXI transactions). Can only be cleared by a reset + uint32_t reset_status : 1; // Reset is ongoing and only this register can be read (other registers read as 0 + // and writes are ignored.) A value of 0 means NPU is not being reset and can be + // accessed as normal + uint32_t + cmd_parse_error : 1; // 0=No error 1=Command stream parsing error detected. Can only be cleared by reset + uint32_t cmd_end_reached : 1; // 0=Not reached, 1=Reached. Cleared by writing QBASE or QSIZE when NPU is in + // stopped state + uint32_t pmu_irq_raised : 1; // 0=No PMU IRQ, 1=PMU IRQ raised. Cleared by using command register bit 1 + uint32_t wd_fault : 1; // Weight decoder state: 0=no fault 1=weight decoder decompression fault. Can only be + // cleared by reset + uint32_t ecc_fault : 1; // ECC state for internal RAMs: 0=no fault 1=ECC fault signalled. Can only be + // cleared by reset + uint32_t reserved0 : 2; + uint32_t faulting_interface : 1; // Faulting interface on bus abort + uint32_t faulting_channel : 4; // Faulting channel on a bus abort. Read: 0=Cmd 1=IFM 2=Weights 3=Scale+Bias + // 4=Mem2Mem; Write: 8=OFM 9=Mem2Mem + uint32_t irq_history_mask : 16; // IRQ History mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR status_r() : word0(8) {} + CONSTEXPR status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::state get_state() const + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::state get_state() const volatile + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR status_r &set_state(NPU_NAMESPACE::state value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile status_r &set_state(NPU_NAMESPACE::state value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR status_r &set_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile status_r &set_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_bus_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_bus_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR status_r &set_bus_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile status_r &set_bus_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_reset_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_reset_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR status_r &set_reset_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile status_r &set_reset_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_parse_error() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_parse_error() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR status_r &set_cmd_parse_error(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile status_r &set_cmd_parse_error(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_end_reached() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_end_reached() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR status_r &set_cmd_end_reached(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile status_r &set_cmd_end_reached(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_pmu_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_pmu_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR status_r &set_pmu_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile status_r &set_pmu_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wd_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wd_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR status_r &set_wd_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile status_r &set_wd_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ecc_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ecc_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR status_r &set_ecc_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile status_r &set_ecc_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_fault_src get_faulting_interface() const + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + NPU_NAMESPACE::dma_fault_src get_faulting_interface() const volatile + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + CONSTEXPR status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + volatile status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + CONSTEXPR uint32_t get_faulting_channel() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_faulting_channel() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR status_r &set_faulting_channel(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile status_r &set_faulting_channel(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_irq_history_mask() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_irq_history_mask() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR status_r &set_irq_history_mask(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile status_r &set_irq_history_mask(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// cmd_r - Command register, reads as last written command +struct cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t transition_to_running_state : 1; // Write 1 to transition the NPU to running state. Writing 0 has + // no effect + uint32_t clear_irq : 1; // Write 1 to clear the IRQ status in the STATUS register. Writing 0 has no effect + uint32_t clock_q_enable : 1; // Write 1 to this bit to enable clock off using clock q-interface and enable + // the requester clock gate + uint32_t power_q_enable : 1; // Write 1 to this bit to enable power off using power q-interface + uint32_t + stop_request : 1; // Write 1 to this bit to request STOP after completing any already-started commands + uint32_t reserved0 : 11; + uint32_t clear_irq_history : 16; // Clears the IRQ history mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cmd_r() : word0(12) {} + CONSTEXPR cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_transition_to_running_state() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_transition_to_running_state() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR cmd_r &set_transition_to_running_state(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile cmd_r &set_transition_to_running_state(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_clear_irq() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_clear_irq() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR cmd_r &set_clear_irq(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile cmd_r &set_clear_irq(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_clock_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_clock_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR cmd_r &set_clock_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile cmd_r &set_clock_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_power_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_power_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR cmd_r &set_power_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile cmd_r &set_power_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_stop_request() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_stop_request() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR cmd_r &set_stop_request(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile cmd_r &set_stop_request(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_clear_irq_history() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_clear_irq_history() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR cmd_r &set_clear_irq_history(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile cmd_r &set_clear_irq_history(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// reset_r - Request Reset and new security mode +struct reset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t pending_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t pending_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR reset_r() : word0(0) {} + CONSTEXPR reset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + reset_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_pending_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_pending_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_pending_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_pending_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// qbase_r - Base address of the command stream in bytes +struct qbase_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR qbase_r() : word0(0), word1(0) {} + CONSTEXPR qbase_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + qbase_r copy() volatile + { + return *this; + } +#endif +}; + +// qread_r - Read offset in the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QREAD : 32; // The read offset of the current command under execution + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qread_r() : word0(0) {} + CONSTEXPR qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QREAD() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QREAD() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qread_r &set_QREAD(uint32_t value) + { + word0 = value; + return *this; + } + volatile qread_r &set_QREAD(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// qconfig_r - AXI configuration for the command stream in the range 0-3. Same encoding as for REGIONCFG +struct qconfig_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_region0 : 2; // Command region configuration + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qconfig_r() : word0(0) {} + CONSTEXPR qconfig_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qconfig_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_cmd_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_cmd_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// qsize_r - Size of the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qsize_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QSIZE : 32; // Size of the next command stream to be executed by the NPU + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qsize_r() : word0(0) {} + CONSTEXPR qsize_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qsize_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QSIZE() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QSIZE() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qsize_r &set_QSIZE(uint32_t value) + { + word0 = value; + return *this; + } + volatile qsize_r &set_QSIZE(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// prot_r - Protection level configured for the NPU when acting as an AXI requester +struct prot_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t active_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t active_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR prot_r() : word0(0) {} + CONSTEXPR prot_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + prot_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_active_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_active_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_active_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_active_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// config_r - RTL configuration +struct config_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t macs_per_cc : 4; // The log2(macs/clock cycle) + uint32_t cmd_stream_version : 4; // command stream version accepted by this NPU + uint32_t shram_size : 8; // Total size in KB of internal SHRAM + uint32_t reserved0 : 10; + uint32_t functional_safety : 1; // Functional safety configuration + uint32_t custom_dma : 1; // Custom DMA configuration + uint32_t product : 4; // Product configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR config_r() : word0(0) {} + CONSTEXPR config_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + config_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_macs_per_cc() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_macs_per_cc() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR config_r &set_macs_per_cc(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile config_r &set_macs_per_cc(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_stream_version() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_stream_version() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR config_r &set_cmd_stream_version(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile config_r &set_cmd_stream_version(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_shram_size() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + uint32_t get_shram_size() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR config_r &set_shram_size(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + volatile config_r &set_shram_size(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::functional_safety get_functional_safety() const + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + NPU_NAMESPACE::functional_safety get_functional_safety() const volatile + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + CONSTEXPR config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + volatile config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma get_custom_dma() const + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + NPU_NAMESPACE::custom_dma get_custom_dma() const volatile + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + CONSTEXPR config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + volatile config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + CONSTEXPR uint32_t get_product() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_product() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR config_r &set_product(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile config_r &set_product(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// lock_r - Lock register. This register is designed for driver use and does not affect NPU functionality +struct lock_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t LOCK : 32; // 32 bit value for LOCK configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR lock_r() : word0(0) {} + CONSTEXPR lock_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + lock_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_LOCK() const + { + uint32_t value = word0; + return value; + } + uint32_t get_LOCK() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR lock_r &set_LOCK(uint32_t value) + { + word0 = value; + return *this; + } + volatile lock_r &set_LOCK(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// regioncfg_r - Region memory type configuration. Bits[2*k+1:2*k] give the memory type for REGION[k] +struct regioncfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t region0 : 2; // Bits for Region0 Configuration + uint32_t region1 : 2; // Bits for Region1 Configuration + uint32_t region2 : 2; // Bits for Region2 Configuration + uint32_t region3 : 2; // Bits for Region3 Configuration + uint32_t region4 : 2; // Bits for Region4 Configuration + uint32_t region5 : 2; // Bits for Region5 Configuration + uint32_t region6 : 2; // Bits for Region6 Configuration + uint32_t region7 : 2; // Bits for Region7 Configuration + uint32_t reserved0 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR regioncfg_r() : word0(0) {} + CONSTEXPR regioncfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + regioncfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region1() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + NPU_NAMESPACE::mem_attr get_region1() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + CONSTEXPR regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + volatile regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region2() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::mem_attr get_region2() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + volatile regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region3() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + NPU_NAMESPACE::mem_attr get_region3() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + CONSTEXPR regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + volatile regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region4() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + NPU_NAMESPACE::mem_attr get_region4() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + CONSTEXPR regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + volatile regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region5() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + NPU_NAMESPACE::mem_attr get_region5() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + CONSTEXPR regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + volatile regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region6() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + NPU_NAMESPACE::mem_attr get_region6() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + CONSTEXPR regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + volatile regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region7() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + NPU_NAMESPACE::mem_attr get_region7() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + CONSTEXPR regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } + volatile regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } +#endif +}; + +// axi_limit0_r - AXI limits for port 0 counter 0 +struct axi_limit0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit0_r() : word0(0) {} + CONSTEXPR axi_limit0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit0_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit1_r - AXI limits for port 0 counter 1 +struct axi_limit1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit1_r() : word0(0) {} + CONSTEXPR axi_limit1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit1_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit2_r - AXI limits for port 1 counter 2 +struct axi_limit2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit2_r() : word0(0) {} + CONSTEXPR axi_limit2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit2_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit3_r - AXI limits for port 1 counter 3 +struct axi_limit3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 5; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 31 + uint32_t reserved2 : 3; + uint32_t max_outstanding_write_m1 : 4; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 15 + uint32_t reserved3 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit3_r() : word0(0) {} + CONSTEXPR axi_limit3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit3_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 16) & word0) | ((((1U << 5) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 24) & word0) | ((((1U << 4) - 1) & value) << 24); + return *this; + } +#endif +}; + +// basep_r - The driver can use this address to relocate the command stream on region 0. If the region contains data +// requiring A-byte alignment then the base must be a multiple of A +struct basep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR basep_r() : word0(0), word1(0) {} + CONSTEXPR basep_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + basep_r copy() volatile + { + return *this; + } +#endif +}; + +// wd_status_r - WD_STATUS +struct wd_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t core_slice_state : 2; // WD core slice parser state + uint32_t core_idle : 1; // Core idle + uint32_t ctrl_state : 2; // WD control state + uint32_t ctrl_idle : 1; // All stripe jobs idle (all weights consumed) + uint32_t write_buf_index0 : 3; // current write index for next data from core + uint32_t write_buf_valid0 : 1; // write buf valid (full) + uint32_t write_buf_idle0 : 1; // write buf idle (empty) + uint32_t write_buf_index1 : 3; // current write index for next data from core + uint32_t write_buf_valid1 : 1; // write buf valid (full) + uint32_t write_buf_idle1 : 1; // write buf idle (empty) + uint32_t events : 12; // WD events mapped as appendix A + uint32_t reserved0 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR wd_status_r() : word0(0) {} + CONSTEXPR wd_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + wd_status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const volatile + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_core_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_core_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR wd_status_r &set_core_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile wd_status_r &set_core_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const volatile + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + volatile wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + CONSTEXPR uint32_t get_ctrl_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ctrl_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile wd_status_r &set_ctrl_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index0() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + uint32_t get_write_buf_index0() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index0(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + volatile wd_status_r &set_write_buf_index0(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_write_buf_valid0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile wd_status_r &set_write_buf_valid0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_write_buf_idle0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile wd_status_r &set_write_buf_idle0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index1() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + uint32_t get_write_buf_index1() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index1(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + volatile wd_status_r &set_write_buf_index1(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_write_buf_valid1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile wd_status_r &set_write_buf_valid1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_write_buf_idle1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile wd_status_r &set_write_buf_idle1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR wd_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } + volatile wd_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } +#endif +}; + +// mac_status_r - MAC_STATUS +struct mac_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block_cfg_valid : 1; // MAC has a valid block configuration + uint32_t trav_en : 1; // MAC is doing block traversal + uint32_t wait_for_ib : 1; // MAC is waiting for an Input Buffer to become available + uint32_t wait_for_acc_buf : 1; // MAC is waiting for an Accumulator Buffer to become available + uint32_t wait_for_weights : 1; // MAC is waiting for a Weight Block to become available + uint32_t stall_stripe : 1; // MAC is stalling between two stripes + uint32_t dw_sel : 1; // Currently used weight interface in MAC AI + uint32_t wait_for_dw0_ready : 1; // MAC AI is waiting for MAC DPU to send dw0_ready to WD + uint32_t wait_for_dw1_ready : 1; // MAC AI is waiting for MAC DPU to send dw1_ready to WD + uint32_t acc_buf_sel_ai : 1; // Currently used AccBuf interface in MAC AI + uint32_t wait_for_acc0_ready : 1; // MAC AI is waiting for acc0_ready from AO + uint32_t wait_for_acc1_ready : 1; // MAC AI is waiting for acc1_ready from AO + uint32_t acc_buf_sel_aa : 1; // Currently used AccBuf interface in MAC ADDER_ARRAY + uint32_t acc0_valid : 1; // MAC outgoing value of acc0_valid + uint32_t acc1_valid : 1; // MAC outgoing value of acc1_valid + uint32_t reserved0 : 1; + uint32_t events : 11; // Mapped to MAC events described in Appendix A + uint32_t reserved1 : 5; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR mac_status_r() : word0(0) {} + CONSTEXPR mac_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + mac_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block_cfg_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_block_cfg_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR mac_status_r &set_block_cfg_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile mac_status_r &set_block_cfg_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_trav_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_trav_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR mac_status_r &set_trav_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile mac_status_r &set_trav_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wait_for_ib() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wait_for_ib() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_ib(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile mac_status_r &set_wait_for_ib(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc_buf() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_wait_for_acc_buf() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc_buf(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile mac_status_r &set_wait_for_acc_buf(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_wait_for_weights() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_wait_for_weights() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_weights(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile mac_status_r &set_wait_for_weights(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_stall_stripe() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_stall_stripe() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR mac_status_r &set_stall_stripe(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile mac_status_r &set_stall_stripe(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_dw_sel() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_dw_sel() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR mac_status_r &set_dw_sel(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile mac_status_r &set_dw_sel(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wait_for_dw0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile mac_status_r &set_wait_for_dw0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_wait_for_dw1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile mac_status_r &set_wait_for_dw1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_ai() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_acc_buf_sel_ai() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_ai(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_ai(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_wait_for_acc0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile mac_status_r &set_wait_for_acc0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_wait_for_acc1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile mac_status_r &set_wait_for_acc1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_aa() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_acc_buf_sel_aa() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_aa(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_aa(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_acc0_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_acc0_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR mac_status_r &set_acc0_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile mac_status_r &set_acc0_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_acc1_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_acc1_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR mac_status_r &set_acc1_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile mac_status_r &set_acc1_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR mac_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } + volatile mac_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } +#endif +}; + +// ao_status_r - AO_STATUS +struct ao_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_sbw_valid : 1; // Block command to shared buffer write module is valid + uint32_t cmd_act_valid : 1; // Block command to activation function module is valid + uint32_t cmd_ctl_valid : 1; // Block command to control module is valid + uint32_t cmd_scl_valid : 1; // Block command to scale module is valid + uint32_t cmd_sbr_valid : 1; // Block command to shared buffer read module is valid + uint32_t cmd_ofm_valid : 1; // Block command to ofm parameter module is valid + uint32_t blk_cmd_ready : 1; // Ready to accept block command + uint32_t blk_cmd_valid : 1; // Block command from CC is valid + uint32_t reserved0 : 8; + uint32_t events : 8; // Mapped to AO events described in Appendix A + uint32_t reserved1 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ao_status_r() : word0(0) {} + CONSTEXPR ao_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ao_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_sbw_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_sbw_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbw_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile ao_status_r &set_cmd_sbw_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_act_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cmd_act_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR ao_status_r &set_cmd_act_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile ao_status_r &set_cmd_act_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cmd_ctl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cmd_ctl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ctl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile ao_status_r &set_cmd_ctl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_cmd_scl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_cmd_scl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR ao_status_r &set_cmd_scl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile ao_status_r &set_cmd_scl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_sbr_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_sbr_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbr_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile ao_status_r &set_cmd_sbr_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_ofm_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_ofm_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ofm_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile ao_status_r &set_cmd_ofm_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_blk_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile ao_status_r &set_blk_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_blk_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile ao_status_r &set_blk_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR ao_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } + volatile ao_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } +#endif +}; + +// dma_status0_r - DMA_STATUS0 +struct dma_status0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_idle : 1; // When this bit is high means that the CMD block is not busy in generating addresses + // for a CMD job + uint32_t ifm_idle : 1; // When this bit is high means that there are no ongoing IFM jobs + uint32_t wgt_idle_c0 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c0 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t m2m_idle : 1; // When this bit is high means that there are no ongoing M2M jobs + uint32_t ofm_idle : 1; // When this bit is high means that there are no ongoing OFM jobs + uint32_t halt_req : 1; // CPM has requested to HALT AXI bus before soft reset + uint32_t halt_ack : 1; // DMA is in condition to halt the AXI bus since there are no pending transactions + uint32_t pause_req : 1; // CC has requested to pause the AXI + uint32_t pause_ack : 1; // DMA is in condition to pause the AXI bus since there are no pending transactions + uint32_t ib0_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 0 - Core 0 + uint32_t ib1_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 1 - Core 0 + uint32_t ib1_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 1 - Core 0 + uint32_t ib0_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 1 - Core 0 + uint32_t ob0_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 0 + uint32_t ob0_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 0 + uint32_t ob1_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 0 + uint32_t ob1_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 0 + uint32_t cmd_valid : 1; // New command word for CC to be consumed + uint32_t cmd_ready : 1; // command word consumed by CC + uint32_t wd_bitstream_valid_c0 : 1; // New weight word for WD to be consumed - Core 0 + uint32_t wd_bitstream_ready_c0 : 1; // Weight word consumed by WD - Core 0 + uint32_t bs_bitstream_valid_c0 : 1; // New BaS word for AO to be consumed - Core 0 + uint32_t bs_bitstream_ready_c0 : 1; // BaS word consumed by AO - Core 0 + uint32_t axi0_ar_stalled : 1; // Read transfer request stalled on arready low AXI0 (due to memory system) + uint32_t axi0_rd_limit_stall : 1; // Read stalled due to one AXI0 limit counter being reached + uint32_t axi0_aw_stalled : 1; // Write transfer request stalled on awready low AXI0 (due to memory system) + uint32_t axi0_w_stalled : 1; // Write transfer stalled on awready low AXI0 (due to memory system) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status0_r() : word0(0) {} + CONSTEXPR dma_status0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status0_r &set_cmd_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ifm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_ifm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status0_r &set_ifm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status0_r &set_ifm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wgt_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status0_r &set_wgt_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status0_r &set_wgt_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_bas_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status0_r &set_bas_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status0_r &set_bas_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_m2m_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_m2m_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status0_r &set_m2m_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status0_r &set_m2m_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_ofm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ofm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status0_r &set_ofm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status0_r &set_ofm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_halt_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_halt_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status0_r &set_halt_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status0_r &set_halt_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_halt_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_halt_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status0_r &set_halt_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status0_r &set_halt_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_pause_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_pause_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status0_r &set_pause_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status0_r &set_pause_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_pause_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_pause_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status0_r &set_pause_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status0_r &set_pause_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib0_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib0_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib1_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib1_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib0_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib0_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ib1_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ib1_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob0_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status0_r &set_ob0_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob0_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status0_r &set_ob0_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_ob1_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status0_r &set_ob1_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_ob1_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status0_r &set_ob1_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status0_r &set_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status0_r &set_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + uint32_t get_wd_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + uint32_t get_wd_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + uint32_t get_bs_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + uint32_t get_bs_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_axi0_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + uint32_t get_axi0_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + volatile dma_status0_r &set_axi0_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_axi0_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + uint32_t get_axi0_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + volatile dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + CONSTEXPR uint32_t get_axi0_aw_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + uint32_t get_axi0_aw_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_aw_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + volatile dma_status0_r &set_axi0_aw_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + CONSTEXPR uint32_t get_axi0_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_axi0_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile dma_status0_r &set_axi0_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// dma_status1_r - DMA_STATUS1 +struct dma_status1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t axi0_wr_limit_stall : 1; // Write stalled due to one AXI0 limit counter being reached + uint32_t axi1_ar_stalled : 1; // Read transfer request stalled on arready low AXI1 (due to memory system) + uint32_t axi1_rd_limit_stall : 1; // Read stalled due to one AXI1 limit counter being reached + uint32_t axi1_wr_stalled : 1; // Write transfer request stalled on awready low AXI1 (due to memory system) + uint32_t axi1_w_stalled : 1; // Write transfer stalled on wready low AXI1 (due to memory system) + uint32_t axi1_wr_limit_stall : 1; // Write stalled due to one AXI1 limit counter being reached + uint32_t wgt_idle_c1 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c1 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t ib0_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 0 - Core 1 + uint32_t ib1_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 1 - Core 1 + uint32_t ib1_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 1 - Core 1 + uint32_t ib0_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 1 - Core 1 + uint32_t ob0_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 1 + uint32_t ob0_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 1 + uint32_t ob1_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 1 + uint32_t ob1_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 1 + uint32_t wd_bitstream_valid_c1 : 1; // New weight word for WD to be consumed - Core 1 + uint32_t wd_bitstream_ready_c1 : 1; // Weight word consumed by WD - Core 1 + uint32_t bs_bitstream_valid_c1 : 1; // New BaS word for AO to be consumed - Core 1 + uint32_t bs_bitstream_ready_c1 : 1; // BaS word consumed by AO - Core 1 + uint32_t reserved0 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status1_r() : word0(0) {} + CONSTEXPR dma_status1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_axi0_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_axi0_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_axi1_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_axi1_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status1_r &set_axi1_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_axi1_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_axi1_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_axi1_wr_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status1_r &set_axi1_wr_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_axi1_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_axi1_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status1_r &set_axi1_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_axi1_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_wgt_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status1_r &set_wgt_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status1_r &set_wgt_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_bas_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status1_r &set_bas_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status1_r &set_bas_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ib0_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_ib0_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib1_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib1_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib0_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib0_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib1_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib1_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ob0_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status1_r &set_ob0_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ob0_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status1_r &set_ob0_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob1_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status1_r &set_ob1_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob1_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status1_r &set_ob1_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_wd_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_wd_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_bs_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_bs_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } +#endif +}; + +// clkforce_r - Force clocks on for clock gating +struct clkforce_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t top_level_clk : 1; // set to 1 to force on TOP level clock + uint32_t cc_clk : 1; // set to 1 to force on CC clock + uint32_t dma_clk : 1; // set to 1 to force on DMA clock + uint32_t mac_clk : 1; // set to 1 to force on MAC clock + uint32_t ao_clk : 1; // set to 1 to force on AO clock + uint32_t wd_clk : 1; // set to 1 to force on WD clock + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR clkforce_r() : word0(0) {} + CONSTEXPR clkforce_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + clkforce_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_top_level_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_top_level_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR clkforce_r &set_top_level_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile clkforce_r &set_top_level_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cc_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cc_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR clkforce_r &set_cc_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile clkforce_r &set_cc_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_dma_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_dma_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR clkforce_r &set_dma_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile clkforce_r &set_dma_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mac_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mac_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR clkforce_r &set_mac_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile clkforce_r &set_mac_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_ao_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR clkforce_r &set_ao_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile clkforce_r &set_ao_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_wd_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_wd_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR clkforce_r &set_wd_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile clkforce_r &set_wd_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } +#endif +}; + +// debug_address_r - Set debug address for register reads 0x400-0x7FF. The address must be 1KB aligned +struct debug_address_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t addr : 32; // Register address + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_address_r() : word0(0) {} + CONSTEXPR debug_address_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_address_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + uint32_t value = word0; + return value; + } + uint32_t get_addr() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_address_r &set_addr(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_address_r &set_addr(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_misc_r - 32-bit read/write register for driver debug use. This does not affect NPU function +struct debug_misc_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t misc : 32; // Debug misc + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_misc_r() : word0(0) {} + CONSTEXPR debug_misc_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_misc_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_misc() const + { + uint32_t value = word0; + return value; + } + uint32_t get_misc() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_misc_r &set_misc(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_misc_r &set_misc(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_block_r - Set from which of four block banks the TSU registers are read. 0 = read from the current bank 256+n = +// force to read from bank n where n is in the range 0 to 3 +struct debug_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block : 32; // Debug block + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_block_r() : word0(0) {} + CONSTEXPR debug_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block() const + { + uint32_t value = word0; + return value; + } + uint32_t get_block() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_block_r &set_block(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_block_r &set_block(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmcr_r - PMU Register control +struct pmcr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cnt_en : 1; // Enable counter + uint32_t event_cnt_rst : 1; // Reset event counter + uint32_t cycle_cnt_rst : 1; // Reset cycle counter + uint32_t mask_en : 1; // PMU can be enabled/disabled by command stream operation NPU_OP_PMU_MASK + uint32_t reserved0 : 7; + uint32_t num_event_cnt : 5; // Number of event counters + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcr_r() : word0(8192) {} + CONSTEXPR pmcr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cnt_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cnt_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcr_r &set_cnt_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcr_r &set_cnt_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_event_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_event_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcr_r &set_event_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcr_r &set_event_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cycle_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cycle_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcr_r &set_cycle_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcr_r &set_cycle_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mask_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mask_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcr_r &set_mask_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcr_r &set_mask_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_num_event_cnt() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + uint32_t get_num_event_cnt() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR pmcr_r &set_num_event_cnt(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } + volatile pmcr_r &set_num_event_cnt(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } +#endif +}; + +// pmcntenset_r - Count enable set register +struct pmcntenset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenset_r() : word0(0) {} + CONSTEXPR pmcntenset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenset_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenset_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmcntenclr_r - Count enable clear register +struct pmcntenclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenclr_r() : word0(0) {} + CONSTEXPR pmcntenclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenclr_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenclr_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsset_r - Overflow flag status set register +struct pmovsset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow set bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow set bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow set bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow set bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow set bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsset_r() : word0(0) {} + CONSTEXPR pmovsset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsclr_r - Overflow flag status clear register +struct pmovsclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow clear bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow clear bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow clear bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow clear bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow clear bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsclr_r() : word0(0) {} + CONSTEXPR pmovsclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintset_r - Interrupt enable set register +struct pmintset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintset_r() : word0(0) {} + CONSTEXPR pmintset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintset_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintset_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintclr_r - Interrupt enable clear register +struct pmintclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintclr_r() : word0(0) {} + CONSTEXPR pmintclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmccntr_r - Performance monitor cycle count register +struct pmccntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_LO : 32; // Cycle count - LSB + uint32_t CYCLE_CNT_HI : 16; // Cycle count - MSB + uint32_t reserved0 : 16; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR pmccntr_r() : word0(0), word1(0) {} + CONSTEXPR pmccntr_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + pmccntr_r copy() volatile + { + return *this; + } +#endif +}; + +// pmccntr_cfg_r - Set start/stop event on the cycle counter +struct pmccntr_cfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_CFG_START : 10; // Cycle counter start event + uint32_t reserved0 : 6; + uint32_t CYCLE_CNT_CFG_STOP : 10; // Cycle counter stop event + uint32_t reserved1 : 6; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmccntr_cfg_r() : word0(0) {} + CONSTEXPR pmccntr_cfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmccntr_cfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// pmcaxi_chan_r - Set which AXI channel to monitor for latency measurements in PMU +struct pmcaxi_chan_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CH_SEL : 4; // Channel select for latency measurements + uint32_t reserved0 : 4; + uint32_t AXI_CNT_SEL : 2; // AXI counter to monitor for latency measurements + uint32_t BW_CH_SEL_EN : 1; // Bandwidth channel selector + uint32_t reserved1 : 21; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcaxi_chan_r() : word0(0) {} + CONSTEXPR pmcaxi_chan_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcaxi_chan_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const volatile + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_AXI_CNT_SEL() const + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + uint32_t get_AXI_CNT_SEL() const volatile + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + volatile pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_BW_CH_SEL_EN() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_BW_CH_SEL_EN() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } +#endif +}; + +// kernel_x_r - Kernel X offset of in kernel decomposition +struct kernel_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_x_r() : word0(0) {} + CONSTEXPR kernel_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_y_r - Kernel Y offset of in kernel decomposition +struct kernel_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_y_r() : word0(0) {} + CONSTEXPR kernel_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_w_m1_r - Kernel (width-1) of current block +struct kernel_w_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_w_m1_r() : word0(0) {} + CONSTEXPR kernel_w_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_w_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_w_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_w_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_h_m1_r - Kernel (height-1) of current block +struct kernel_h_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_h_m1_r() : word0(0) {} + CONSTEXPR kernel_h_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_h_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_h_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_h_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_width_m1_r - OFM current block (width-1) +struct ofm_cblk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_height_m1_r - OFM current block (height-1) +struct ofm_cblk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_depth_m1_r - OFM current block (depth-1) +struct ofm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_depth_m1_r - IFM current block (depth-1) +struct ifm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_x_r - Block X coordinate in OFM +struct ofm_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_x_r() : word0(0) {} + CONSTEXPR ofm_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_y_r - Block Y coordinate in OFM +struct ofm_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_y_r() : word0(0) {} + CONSTEXPR ofm_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_z_r - Block Z (channel) coordinate in OFM +struct ofm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_z_r() : word0(0) {} + CONSTEXPR ofm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_z_r - Block Z (channel) coordinate in IFM +struct ifm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_z_r() : word0(0) {} + CONSTEXPR ifm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_top_r - Block top pad +struct pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_top_r() : word0(0) {} + CONSTEXPR pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_left_r - Block left pad +struct pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_left_r() : word0(0) {} + CONSTEXPR pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_width_r - IFM current block derived width +struct ifm_cblk_width_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_width_r() : word0(0) {} + CONSTEXPR ifm_cblk_width_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_width_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_width_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_width_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_height_r - IFM current block derived height +struct ifm_cblk_height_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_height_r() : word0(0) {} + CONSTEXPR ifm_cblk_height_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_height_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_height_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_height_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ifm_src_r - DMA IFM channel source position on AXI +struct dma_ifm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ifm_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_ifm_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ifm_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_ifm_dst_r - DMA IFM channel destination position in SHRAM +struct dma_ifm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ifm_dst_r() : word0(0) {} + CONSTEXPR dma_ifm_dst_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ifm_dst_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ifm_dst_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ifm_dst_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_src_r - DMA OFM channel source position in SHRAM +struct dma_ofm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ofm_src_r() : word0(0) {} + CONSTEXPR dma_ofm_src_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ofm_src_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ofm_src_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ofm_src_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_dst_r - DMA OFM channel destination position on AXI +struct dma_ofm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ofm_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_ofm_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ofm_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_weight_src_r - DMA weight channel source position on AXI +struct dma_weight_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_weight_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_weight_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_weight_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_src_r - DMA command channel source position on AXI +struct dma_cmd_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_cmd_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_cmd_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_cmd_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_size_r - DMA command channel number of bytes buffered +struct dma_cmd_size_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_cmd_size_r() : word0(0) {} + CONSTEXPR dma_cmd_size_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_cmd_size_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_cmd_size_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_cmd_size_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_m2m_src_r - DMA memory to memory source position on AXI +struct dma_m2m_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_m2m_dst_r - DMA memory to memory destination position on AXI +struct dma_m2m_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// current_qread_r - QREAD position being issued (rather than completed) +struct current_qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_qread_r() : word0(0) {} + CONSTEXPR current_qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_qread_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_qread_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_scale_src_r - DMA scale and bias channel source position on AXI +struct dma_scale_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset : 32; // Offset + uint32_t reserved0 : 32; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_scale_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_scale_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_scale_src_r copy() volatile + { + return *this; + } +#endif +}; + +// current_block_r - 0-3. Current block bank being executed by the TSU or last one executed if TSU is stopped +struct current_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_block_r() : word0(0) {} + CONSTEXPR current_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_block_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_block_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_op_r - Current NPU OP command being executed by the TSU +struct current_op_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_op_r() : word0(0) {} + CONSTEXPR current_op_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_op_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_op_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_op_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_cmd_r - Current 32-bit command being parsed by the command stream parser +struct current_cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_cmd_r() : word0(0) {} + CONSTEXPR current_cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_cmd_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_cmd_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevcntr_r - Performance monitor event 0 count register +struct pmevcntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t count : 32; // Count word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevcntr_r() : word0(0) {} + CONSTEXPR pmevcntr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevcntr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_count() const + { + uint32_t value = word0; + return value; + } + uint32_t get_count() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pmevcntr_r &set_count(uint32_t value) + { + word0 = value; + return *this; + } + volatile pmevcntr_r &set_count(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevtyper_r - Performance monitor event type register 0 +struct pmevtyper_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EV_TYPE : 10; // Event Type + uint32_t reserved0 : 22; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevtyper_r() : word0(0) {} + CONSTEXPR pmevtyper_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevtyper_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_EV_TYPE() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_EV_TYPE() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// shared_buffer_r - Shared buffer debug access. Only valid in STOPPED state +struct shared_buffer_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_word : 32; // Memory word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR shared_buffer_r() : word0(0) {} + CONSTEXPR shared_buffer_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + shared_buffer_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_mem_word() const + { + uint32_t value = word0; + return value; + } + uint32_t get_mem_word() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR shared_buffer_r &set_mem_word(uint32_t value) + { + word0 = value; + return *this; + } + volatile shared_buffer_r &set_mem_word(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_top_r - None +struct ifm_pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_top_r() : word0(0) {} + CONSTEXPR ifm_pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_left_r - None +struct ifm_pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_left_r() : word0(0) {} + CONSTEXPR ifm_pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_right_r - None +struct ifm_pad_right_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_right_r() : word0(0) {} + CONSTEXPR ifm_pad_right_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_right_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_right_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_right_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_bottom_r - None +struct ifm_pad_bottom_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_bottom_r() : word0(0) {} + CONSTEXPR ifm_pad_bottom_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_bottom_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_bottom_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_bottom_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_depth_m1_r - None +struct ifm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_precision_r - None +struct ifm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_precision_r() : word0(0) {} + CONSTEXPR ifm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_upscale_r - None +struct ifm_upscale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_upscale_r() : word0(0) {} + CONSTEXPR ifm_upscale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_upscale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_upscale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_upscale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_zero_point_r - None +struct ifm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_zero_point_r() : word0(0) {} + CONSTEXPR ifm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_width0_m1_r - None +struct ifm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_width0_m1_r() : word0(0) {} + CONSTEXPR ifm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height0_m1_r - None +struct ifm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height0_m1_r() : word0(0) {} + CONSTEXPR ifm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height1_m1_r - None +struct ifm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height1_m1_r() : word0(0) {} + CONSTEXPR ifm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_ib_end_r - None +struct ifm_ib_end_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_ib_end_r() : word0(0) {} + CONSTEXPR ifm_ib_end_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_ib_end_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_ib_end_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_ib_end_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_region_r - None +struct ifm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_region_r() : word0(0) {} + CONSTEXPR ifm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width_m1_r - None +struct ofm_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width_m1_r() : word0(0) {} + CONSTEXPR ofm_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height_m1_r - None +struct ofm_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height_m1_r() : word0(0) {} + CONSTEXPR ofm_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_depth_m1_r - None +struct ofm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_precision_r - None +struct ofm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_precision_r() : word0(0) {} + CONSTEXPR ofm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_width_m1_r - None +struct ofm_blk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_height_m1_r - None +struct ofm_blk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_depth_m1_r - None +struct ofm_blk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_zero_point_r - None +struct ofm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_zero_point_r() : word0(0) {} + CONSTEXPR ofm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width0_m1_r - None +struct ofm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width0_m1_r() : word0(0) {} + CONSTEXPR ofm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height0_m1_r - None +struct ofm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height0_m1_r() : word0(0) {} + CONSTEXPR ofm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height1_m1_r - None +struct ofm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height1_m1_r() : word0(0) {} + CONSTEXPR ofm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_region_r - None +struct ofm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_region_r() : word0(0) {} + CONSTEXPR ofm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_width_m1_r - None +struct kernel_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_width_m1_r() : word0(0) {} + CONSTEXPR kernel_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_height_m1_r - None +struct kernel_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_height_m1_r() : word0(0) {} + CONSTEXPR kernel_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_stride_r - None +struct kernel_stride_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_stride_r() : word0(0) {} + CONSTEXPR kernel_stride_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_stride_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_stride_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_stride_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// acc_format_r - None +struct acc_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR acc_format_r() : word0(0) {} + CONSTEXPR acc_format_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + acc_format_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR acc_format_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile acc_format_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_r - None +struct activation_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_r() : word0(0) {} + CONSTEXPR activation_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_min_r - None +struct activation_min_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_min_r() : word0(0) {} + CONSTEXPR activation_min_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_min_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_min_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_min_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_max_r - None +struct activation_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_max_r() : word0(0) {} + CONSTEXPR activation_max_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_max_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_max_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_max_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// weight_region_r - None +struct weight_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR weight_region_r() : word0(0) {} + CONSTEXPR weight_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + weight_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR weight_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile weight_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// scale_region_r - None +struct scale_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR scale_region_r() : word0(0) {} + CONSTEXPR scale_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + scale_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR scale_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile scale_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ab_start_r - None +struct ab_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ab_start_r() : word0(0) {} + CONSTEXPR ab_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ab_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ab_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ab_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// blockdep_r - None +struct blockdep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR blockdep_r() : word0(0) {} + CONSTEXPR blockdep_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + blockdep_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR blockdep_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile blockdep_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_region_r - None +struct dma0_src_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_src_region_r() : word0(0) {} + CONSTEXPR dma0_src_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_src_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_src_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_src_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_dst_region_r - None +struct dma0_dst_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_dst_region_r() : word0(0) {} + CONSTEXPR dma0_dst_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_dst_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_dst_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_dst_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size0_r - None +struct dma0_size0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size0_r() : word0(0) {} + CONSTEXPR dma0_size0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size0_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size0_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size1_r - None +struct dma0_size1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size1_r() : word0(0) {} + CONSTEXPR dma0_size1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_broadcast_r - None +struct ifm2_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_broadcast_r() : word0(0) {} + CONSTEXPR ifm2_broadcast_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_broadcast_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_broadcast_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_broadcast_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_scalar_r - None +struct ifm2_scalar_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_scalar_r() : word0(0) {} + CONSTEXPR ifm2_scalar_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_scalar_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_scalar_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_scalar_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_precision_r - None +struct ifm2_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_precision_r() : word0(0) {} + CONSTEXPR ifm2_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_zero_point_r - None +struct ifm2_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_zero_point_r() : word0(0) {} + CONSTEXPR ifm2_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_width0_m1_r - None +struct ifm2_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_width0_m1_r() : word0(0) {} + CONSTEXPR ifm2_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height0_m1_r - None +struct ifm2_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height0_m1_r() : word0(0) {} + CONSTEXPR ifm2_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height1_m1_r - None +struct ifm2_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height1_m1_r() : word0(0) {} + CONSTEXPR ifm2_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_ib_start_r - None +struct ifm2_ib_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_ib_start_r() : word0(0) {} + CONSTEXPR ifm2_ib_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_ib_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_ib_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_ib_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_region_r - None +struct ifm2_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_region_r() : word0(0) {} + CONSTEXPR ifm2_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_base0_r - None +struct ifm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base1_r - None +struct ifm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base2_r - None +struct ifm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base3_r - None +struct ifm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_x_r - None +struct ifm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_y_r - None +struct ifm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_c_r - None +struct ifm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base0_r - None +struct ofm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base1_r - None +struct ofm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base2_r - None +struct ofm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base3_r - None +struct ofm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_x_r - None +struct ofm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_y_r - None +struct ofm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_c_r - None +struct ofm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_base_r - None +struct weight_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_base_r() : word0(0), word1(0) {} + CONSTEXPR weight_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_base_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_length_r - None +struct weight_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_length_r() : word0(0), word1(0) {} + CONSTEXPR weight_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_length_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_base_r - None +struct scale_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_base_r() : word0(0), word1(0) {} + CONSTEXPR scale_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_base_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_length_r - None +struct scale_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_length_r() : word0(0), word1(0) {} + CONSTEXPR scale_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_length_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_scale_r - None +struct ofm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_r() : word0(0) {} + CONSTEXPR ofm_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_scale_shift_r - None +struct ofm_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_shift_r() : word0(0) {} + CONSTEXPR ofm_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_r - None +struct opa_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_r() : word0(0) {} + CONSTEXPR opa_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_shift_r - None +struct opa_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_shift_r() : word0(0) {} + CONSTEXPR opa_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opb_scale_r - None +struct opb_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opb_scale_r() : word0(0) {} + CONSTEXPR opb_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opb_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opb_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opb_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_r - None +struct dma0_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_src_r() : word0(0), word1(0) {} + CONSTEXPR dma0_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_dst_r - None +struct dma0_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma0_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_len_r - None +struct dma0_len_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_len_r() : word0(0), word1(0) {} + CONSTEXPR dma0_len_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_len_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base0_r - None +struct ifm2_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base1_r - None +struct ifm2_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base2_r - None +struct ifm2_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base3_r - None +struct ifm2_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_x_r - None +struct ifm2_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_y_r - None +struct ifm2_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_c_r - None +struct ifm2_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// revision_r - Internal FPGA build revision: first 32-bits of the Ultan Git hash used for the build +struct revision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR revision_r() : word0(0) {} + CONSTEXPR revision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + revision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR revision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile revision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid4_r - Peripheral ID byte 4 (Arm=code 4) +struct pid4_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID4 : 32; // Byte 4 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid4_r() : word0(4) {} + CONSTEXPR pid4_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid4_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID4() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID4() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid4_r &set_PID4(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid4_r &set_PID4(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid5_r - Peripheral ID byte 5 (reserved) +struct pid5_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID5 : 32; // Byte 5 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid5_r() : word0(0) {} + CONSTEXPR pid5_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid5_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID5() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID5() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid5_r &set_PID5(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid5_r &set_PID5(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid6_r - Peripheral ID byte 6 (reserved) +struct pid6_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID6 : 32; // Byte 6 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid6_r() : word0(0) {} + CONSTEXPR pid6_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid6_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID6() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID6() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid6_r &set_PID6(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid6_r &set_PID6(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid7_r - Peripheral ID byte 7 (reserved) +struct pid7_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID7 : 32; // Byte 7 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid7_r() : word0(0) {} + CONSTEXPR pid7_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid7_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID7() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID7() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid7_r &set_PID7(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid7_r &set_PID7(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid0_r - Peripheral ID byte 0. This is bits[7:0] of the part number +struct pid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID0 : 32; // Byte 0 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid0_r() : word0(128) {} + CONSTEXPR pid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid0_r &set_PID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid0_r &set_PID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid1_r - Peripheral ID byte 1. This is bits[11:8] of the part number in bits[3:0], and bits[3:0] of the Arm ID in +// bits[7:4] +struct pid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID1 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid1_r() : word0(181) {} + CONSTEXPR pid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid1_r &set_PID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid1_r &set_PID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid2_r - Peripheral ID byte 2. This is bits[6:4] of the Arm ID in bits[2:0], and bit 3 indicates format B +struct pid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID2 : 32; // Byte 2 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid2_r() : word0(11) {} + CONSTEXPR pid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid2_r &set_PID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid2_r &set_PID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid3_r - Peripheral ID byte 3 +struct pid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID3 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid3_r() : word0(0) {} + CONSTEXPR pid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid3_r &set_PID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid3_r &set_PID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid0_r - Component ID byte 0 +struct cid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID0 : 32; // Byte 0 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid0_r() : word0(13) {} + CONSTEXPR cid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid0_r &set_CID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid0_r &set_CID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid1_r - Component ID byte 1 +struct cid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID1 : 32; // Byte 1 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid1_r() : word0(240) {} + CONSTEXPR cid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid1_r &set_CID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid1_r &set_CID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid2_r - Component ID byte 2 +struct cid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID2 : 32; // Byte 2 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid2_r() : word0(5) {} + CONSTEXPR cid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid2_r &set_CID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid2_r &set_CID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid3_r - Component ID byte 3 +struct cid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID3 : 32; // Byte 3 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid3_r() : word0(177) {} + CONSTEXPR cid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid3_r &set_CID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid3_r &set_CID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +struct NPU_REG +{ + STRUCT id_r ID; // 0x0000 + STRUCT status_r STATUS; // 0x0004 + STRUCT cmd_r CMD; // 0x0008 + STRUCT reset_r RESET; // 0x000C + STRUCT qbase_r QBASE; // 0x0010 + STRUCT qread_r QREAD; // 0x0018 + STRUCT qconfig_r QCONFIG; // 0x001C + STRUCT qsize_r QSIZE; // 0x0020 + STRUCT prot_r PROT; // 0x0024 + STRUCT config_r CONFIG; // 0x0028 + STRUCT lock_r LOCK; // 0x002C + uint32_t unused0[3]; + STRUCT regioncfg_r REGIONCFG; // 0x003C + STRUCT axi_limit0_r AXI_LIMIT0; // 0x0040 + STRUCT axi_limit1_r AXI_LIMIT1; // 0x0044 + STRUCT axi_limit2_r AXI_LIMIT2; // 0x0048 + STRUCT axi_limit3_r AXI_LIMIT3; // 0x004C + uint32_t unused1[12]; + STRUCT basep_r BASEP[8]; // 0x0080 + uint32_t unused2[16]; + STRUCT wd_status_r WD_STATUS; // 0x0100 + STRUCT mac_status_r MAC_STATUS; // 0x0104 + STRUCT ao_status_r AO_STATUS; // 0x0108 + uint32_t unused3[1]; + STRUCT dma_status0_r DMA_STATUS0; // 0x0110 + STRUCT dma_status1_r DMA_STATUS1; // 0x0114 + uint32_t unused4[10]; + STRUCT clkforce_r CLKFORCE; // 0x0140 + STRUCT debug_address_r DEBUG_ADDRESS; // 0x0144 + STRUCT debug_misc_r DEBUG_MISC; // 0x0148 + uint32_t unused5[1]; + STRUCT debug_block_r DEBUG_BLOCK; // 0x0150 + uint32_t unused6[11]; + STRUCT pmcr_r PMCR; // 0x0180 + STRUCT pmcntenset_r PMCNTENSET; // 0x0184 + STRUCT pmcntenclr_r PMCNTENCLR; // 0x0188 + STRUCT pmovsset_r PMOVSSET; // 0x018C + STRUCT pmovsclr_r PMOVSCLR; // 0x0190 + STRUCT pmintset_r PMINTSET; // 0x0194 + STRUCT pmintclr_r PMINTCLR; // 0x0198 + uint32_t unused7[1]; + STRUCT pmccntr_r PMCCNTR; // 0x01A0 + STRUCT pmccntr_cfg_r PMCCNTR_CFG; // 0x01A8 + STRUCT pmcaxi_chan_r PMCAXI_CHAN; // 0x01AC + uint32_t unused8[20]; + STRUCT kernel_x_r KERNEL_X; // 0x0200 + STRUCT kernel_y_r KERNEL_Y; // 0x0204 + STRUCT kernel_w_m1_r KERNEL_W_M1; // 0x0208 + STRUCT kernel_h_m1_r KERNEL_H_M1; // 0x020C + STRUCT ofm_cblk_width_m1_r OFM_CBLK_WIDTH_M1; // 0x0210 + STRUCT ofm_cblk_height_m1_r OFM_CBLK_HEIGHT_M1; // 0x0214 + STRUCT ofm_cblk_depth_m1_r OFM_CBLK_DEPTH_M1; // 0x0218 + STRUCT ifm_cblk_depth_m1_r IFM_CBLK_DEPTH_M1; // 0x021C + STRUCT ofm_x_r OFM_X; // 0x0220 + STRUCT ofm_y_r OFM_Y; // 0x0224 + STRUCT ofm_z_r OFM_Z; // 0x0228 + STRUCT ifm_z_r IFM_Z; // 0x022C + STRUCT pad_top_r PAD_TOP; // 0x0230 + STRUCT pad_left_r PAD_LEFT; // 0x0234 + STRUCT ifm_cblk_width_r IFM_CBLK_WIDTH; // 0x0238 + STRUCT ifm_cblk_height_r IFM_CBLK_HEIGHT; // 0x023C + STRUCT dma_ifm_src_r DMA_IFM_SRC; // 0x0240 + STRUCT dma_ifm_dst_r DMA_IFM_DST; // 0x0248 + STRUCT dma_ofm_src_r DMA_OFM_SRC; // 0x024C + STRUCT dma_ofm_dst_r DMA_OFM_DST; // 0x0250 + STRUCT dma_weight_src_r DMA_WEIGHT_SRC; // 0x0258 + STRUCT dma_cmd_src_r DMA_CMD_SRC; // 0x0260 + STRUCT dma_cmd_size_r DMA_CMD_SIZE; // 0x0268 + STRUCT dma_m2m_src_r DMA_M2M_SRC; // 0x026C + STRUCT dma_m2m_dst_r DMA_M2M_DST; // 0x0274 + STRUCT current_qread_r CURRENT_QREAD; // 0x027C + STRUCT dma_scale_src_r DMA_SCALE_SRC; // 0x0280 + uint32_t unused9[11]; + STRUCT current_block_r CURRENT_BLOCK; // 0x02B4 + STRUCT current_op_r CURRENT_OP; // 0x02B8 + STRUCT current_cmd_r CURRENT_CMD; // 0x02BC + uint32_t unused10[16]; + STRUCT pmevcntr_r PMEVCNTR[4]; // 0x0300 + uint32_t unused11[28]; + STRUCT pmevtyper_r PMEVTYPER[4]; // 0x0380 + uint32_t unused12[28]; + STRUCT shared_buffer_r SHARED_BUFFER[256]; // 0x0400 + STRUCT ifm_pad_top_r IFM_PAD_TOP; // 0x0800 + STRUCT ifm_pad_left_r IFM_PAD_LEFT; // 0x0804 + STRUCT ifm_pad_right_r IFM_PAD_RIGHT; // 0x0808 + STRUCT ifm_pad_bottom_r IFM_PAD_BOTTOM; // 0x080C + STRUCT ifm_depth_m1_r IFM_DEPTH_M1; // 0x0810 + STRUCT ifm_precision_r IFM_PRECISION; // 0x0814 + uint32_t unused13[1]; + STRUCT ifm_upscale_r IFM_UPSCALE; // 0x081C + uint32_t unused14[1]; + STRUCT ifm_zero_point_r IFM_ZERO_POINT; // 0x0824 + STRUCT ifm_width0_m1_r IFM_WIDTH0_M1; // 0x0828 + STRUCT ifm_height0_m1_r IFM_HEIGHT0_M1; // 0x082C + STRUCT ifm_height1_m1_r IFM_HEIGHT1_M1; // 0x0830 + STRUCT ifm_ib_end_r IFM_IB_END; // 0x0834 + uint32_t unused15[1]; + STRUCT ifm_region_r IFM_REGION; // 0x083C + uint32_t unused16[1]; + STRUCT ofm_width_m1_r OFM_WIDTH_M1; // 0x0844 + STRUCT ofm_height_m1_r OFM_HEIGHT_M1; // 0x0848 + STRUCT ofm_depth_m1_r OFM_DEPTH_M1; // 0x084C + STRUCT ofm_precision_r OFM_PRECISION; // 0x0850 + STRUCT ofm_blk_width_m1_r OFM_BLK_WIDTH_M1; // 0x0854 + STRUCT ofm_blk_height_m1_r OFM_BLK_HEIGHT_M1; // 0x0858 + STRUCT ofm_blk_depth_m1_r OFM_BLK_DEPTH_M1; // 0x085C + STRUCT ofm_zero_point_r OFM_ZERO_POINT; // 0x0860 + uint32_t unused17[1]; + STRUCT ofm_width0_m1_r OFM_WIDTH0_M1; // 0x0868 + STRUCT ofm_height0_m1_r OFM_HEIGHT0_M1; // 0x086C + STRUCT ofm_height1_m1_r OFM_HEIGHT1_M1; // 0x0870 + uint32_t unused18[2]; + STRUCT ofm_region_r OFM_REGION; // 0x087C + STRUCT kernel_width_m1_r KERNEL_WIDTH_M1; // 0x0880 + STRUCT kernel_height_m1_r KERNEL_HEIGHT_M1; // 0x0884 + STRUCT kernel_stride_r KERNEL_STRIDE; // 0x0888 + uint32_t unused19[1]; + STRUCT acc_format_r ACC_FORMAT; // 0x0890 + STRUCT activation_r ACTIVATION; // 0x0894 + STRUCT activation_min_r ACTIVATION_MIN; // 0x0898 + STRUCT activation_max_r ACTIVATION_MAX; // 0x089C + STRUCT weight_region_r WEIGHT_REGION; // 0x08A0 + STRUCT scale_region_r SCALE_REGION; // 0x08A4 + uint32_t unused20[3]; + STRUCT ab_start_r AB_START; // 0x08B4 + uint32_t unused21[1]; + STRUCT blockdep_r BLOCKDEP; // 0x08BC + STRUCT dma0_src_region_r DMA0_SRC_REGION; // 0x08C0 + STRUCT dma0_dst_region_r DMA0_DST_REGION; // 0x08C4 + STRUCT dma0_size0_r DMA0_SIZE0; // 0x08C8 + STRUCT dma0_size1_r DMA0_SIZE1; // 0x08CC + uint32_t unused22[12]; + STRUCT ifm2_broadcast_r IFM2_BROADCAST; // 0x0900 + STRUCT ifm2_scalar_r IFM2_SCALAR; // 0x0904 + uint32_t unused23[3]; + STRUCT ifm2_precision_r IFM2_PRECISION; // 0x0914 + uint32_t unused24[3]; + STRUCT ifm2_zero_point_r IFM2_ZERO_POINT; // 0x0924 + STRUCT ifm2_width0_m1_r IFM2_WIDTH0_M1; // 0x0928 + STRUCT ifm2_height0_m1_r IFM2_HEIGHT0_M1; // 0x092C + STRUCT ifm2_height1_m1_r IFM2_HEIGHT1_M1; // 0x0930 + STRUCT ifm2_ib_start_r IFM2_IB_START; // 0x0934 + uint32_t unused25[1]; + STRUCT ifm2_region_r IFM2_REGION; // 0x093C + uint32_t unused26[48]; + STRUCT ifm_base0_r IFM_BASE0; // 0x0A00 + STRUCT ifm_base1_r IFM_BASE1; // 0x0A08 + STRUCT ifm_base2_r IFM_BASE2; // 0x0A10 + STRUCT ifm_base3_r IFM_BASE3; // 0x0A18 + STRUCT ifm_stride_x_r IFM_STRIDE_X; // 0x0A20 + STRUCT ifm_stride_y_r IFM_STRIDE_Y; // 0x0A28 + STRUCT ifm_stride_c_r IFM_STRIDE_C; // 0x0A30 + uint32_t unused27[2]; + STRUCT ofm_base0_r OFM_BASE0; // 0x0A40 + STRUCT ofm_base1_r OFM_BASE1; // 0x0A48 + STRUCT ofm_base2_r OFM_BASE2; // 0x0A50 + STRUCT ofm_base3_r OFM_BASE3; // 0x0A58 + STRUCT ofm_stride_x_r OFM_STRIDE_X; // 0x0A60 + STRUCT ofm_stride_y_r OFM_STRIDE_Y; // 0x0A68 + STRUCT ofm_stride_c_r OFM_STRIDE_C; // 0x0A70 + uint32_t unused28[2]; + STRUCT weight_base_r WEIGHT_BASE; // 0x0A80 + STRUCT weight_length_r WEIGHT_LENGTH; // 0x0A88 + STRUCT scale_base_r SCALE_BASE; // 0x0A90 + STRUCT scale_length_r SCALE_LENGTH; // 0x0A98 + STRUCT ofm_scale_r OFM_SCALE; // 0x0AA0 + STRUCT ofm_scale_shift_r OFM_SCALE_SHIFT; // 0x0AA4 + STRUCT opa_scale_r OPA_SCALE; // 0x0AA8 + STRUCT opa_scale_shift_r OPA_SCALE_SHIFT; // 0x0AAC + STRUCT opb_scale_r OPB_SCALE; // 0x0AB0 + uint32_t unused29[3]; + STRUCT dma0_src_r DMA0_SRC; // 0x0AC0 + STRUCT dma0_dst_r DMA0_DST; // 0x0AC8 + STRUCT dma0_len_r DMA0_LEN; // 0x0AD0 + uint32_t unused30[10]; + STRUCT ifm2_base0_r IFM2_BASE0; // 0x0B00 + STRUCT ifm2_base1_r IFM2_BASE1; // 0x0B08 + STRUCT ifm2_base2_r IFM2_BASE2; // 0x0B10 + STRUCT ifm2_base3_r IFM2_BASE3; // 0x0B18 + STRUCT ifm2_stride_x_r IFM2_STRIDE_X; // 0x0B20 + STRUCT ifm2_stride_y_r IFM2_STRIDE_Y; // 0x0B28 + STRUCT ifm2_stride_c_r IFM2_STRIDE_C; // 0x0B30 + uint32_t unused31[18]; + uint32_t USER_DEFINED[16]; // 0x0B80 + uint32_t unused32[256]; + STRUCT revision_r REVISION; // 0x0FC0 + uint32_t unused33[3]; + STRUCT pid4_r PID4; // 0x0FD0 + STRUCT pid5_r PID5; // 0x0FD4 + STRUCT pid6_r PID6; // 0x0FD8 + STRUCT pid7_r PID7; // 0x0FDC + STRUCT pid0_r PID0; // 0x0FE0 + STRUCT pid1_r PID1; // 0x0FE4 + STRUCT pid2_r PID2; // 0x0FE8 + STRUCT pid3_r PID3; // 0x0FEC + STRUCT cid0_r CID0; // 0x0FF0 + STRUCT cid1_r CID1; // 0x0FF4 + STRUCT cid2_r CID2; // 0x0FF8 + STRUCT cid3_r CID3; // 0x0FFC + +#ifdef __cplusplus + enum class access_type_t : uint8_t + { + RW, + RO, + WO + }; + NPU_REG() + { + reset(); + } + void reset() + { + ID = 269500929; + STATUS = 8; + CMD = 12; + RESET = 0; + QBASE = 0; + QREAD = 0; + QCONFIG = 0; + QSIZE = 0; + PROT = 0; + CONFIG = 0; + LOCK = 0; + REGIONCFG = 0; + AXI_LIMIT0 = 0; + AXI_LIMIT1 = 0; + AXI_LIMIT2 = 0; + AXI_LIMIT3 = 0; + for (size_t i = 0; i < (sizeof(BASEP) / sizeof(BASEP[0])); ++i) + BASEP[i] = 0; + WD_STATUS = 0; + MAC_STATUS = 0; + AO_STATUS = 0; + DMA_STATUS0 = 0; + DMA_STATUS1 = 0; + CLKFORCE = 0; + DEBUG_ADDRESS = 0; + DEBUG_MISC = 0; + DEBUG_BLOCK = 0; + PMCR = 8192; + PMCNTENSET = 0; + PMCNTENCLR = 0; + PMOVSSET = 0; + PMOVSCLR = 0; + PMINTSET = 0; + PMINTCLR = 0; + PMCCNTR = 0; + PMCCNTR_CFG = 0; + PMCAXI_CHAN = 0; + KERNEL_X = 0; + KERNEL_Y = 0; + KERNEL_W_M1 = 0; + KERNEL_H_M1 = 0; + OFM_CBLK_WIDTH_M1 = 0; + OFM_CBLK_HEIGHT_M1 = 0; + OFM_CBLK_DEPTH_M1 = 0; + IFM_CBLK_DEPTH_M1 = 0; + OFM_X = 0; + OFM_Y = 0; + OFM_Z = 0; + IFM_Z = 0; + PAD_TOP = 0; + PAD_LEFT = 0; + IFM_CBLK_WIDTH = 0; + IFM_CBLK_HEIGHT = 0; + DMA_IFM_SRC = 0; + DMA_IFM_DST = 0; + DMA_OFM_SRC = 0; + DMA_OFM_DST = 0; + DMA_WEIGHT_SRC = 0; + DMA_CMD_SRC = 0; + DMA_CMD_SIZE = 0; + DMA_M2M_SRC = 0; + DMA_M2M_DST = 0; + CURRENT_QREAD = 0; + DMA_SCALE_SRC = 0; + CURRENT_BLOCK = 0; + CURRENT_OP = 0; + CURRENT_CMD = 0; + for (size_t i = 0; i < (sizeof(PMEVCNTR) / sizeof(PMEVCNTR[0])); ++i) + PMEVCNTR[i] = 0; + for (size_t i = 0; i < (sizeof(PMEVTYPER) / sizeof(PMEVTYPER[0])); ++i) + PMEVTYPER[i] = 0; + for (size_t i = 0; i < (sizeof(SHARED_BUFFER) / sizeof(SHARED_BUFFER[0])); ++i) + SHARED_BUFFER[i] = 0; + IFM_PAD_TOP = 0; + IFM_PAD_LEFT = 0; + IFM_PAD_RIGHT = 0; + IFM_PAD_BOTTOM = 0; + IFM_DEPTH_M1 = 0; + IFM_PRECISION = 0; + IFM_UPSCALE = 0; + IFM_ZERO_POINT = 0; + IFM_WIDTH0_M1 = 0; + IFM_HEIGHT0_M1 = 0; + IFM_HEIGHT1_M1 = 0; + IFM_IB_END = 0; + IFM_REGION = 0; + OFM_WIDTH_M1 = 0; + OFM_HEIGHT_M1 = 0; + OFM_DEPTH_M1 = 0; + OFM_PRECISION = 0; + OFM_BLK_WIDTH_M1 = 0; + OFM_BLK_HEIGHT_M1 = 0; + OFM_BLK_DEPTH_M1 = 0; + OFM_ZERO_POINT = 0; + OFM_WIDTH0_M1 = 0; + OFM_HEIGHT0_M1 = 0; + OFM_HEIGHT1_M1 = 0; + OFM_REGION = 0; + KERNEL_WIDTH_M1 = 0; + KERNEL_HEIGHT_M1 = 0; + KERNEL_STRIDE = 0; + ACC_FORMAT = 0; + ACTIVATION = 0; + ACTIVATION_MIN = 0; + ACTIVATION_MAX = 0; + WEIGHT_REGION = 0; + SCALE_REGION = 0; + AB_START = 0; + BLOCKDEP = 0; + DMA0_SRC_REGION = 0; + DMA0_DST_REGION = 0; + DMA0_SIZE0 = 0; + DMA0_SIZE1 = 0; + IFM2_BROADCAST = 0; + IFM2_SCALAR = 0; + IFM2_PRECISION = 0; + IFM2_ZERO_POINT = 0; + IFM2_WIDTH0_M1 = 0; + IFM2_HEIGHT0_M1 = 0; + IFM2_HEIGHT1_M1 = 0; + IFM2_IB_START = 0; + IFM2_REGION = 0; + IFM_BASE0 = 0; + IFM_BASE1 = 0; + IFM_BASE2 = 0; + IFM_BASE3 = 0; + IFM_STRIDE_X = 0; + IFM_STRIDE_Y = 0; + IFM_STRIDE_C = 0; + OFM_BASE0 = 0; + OFM_BASE1 = 0; + OFM_BASE2 = 0; + OFM_BASE3 = 0; + OFM_STRIDE_X = 0; + OFM_STRIDE_Y = 0; + OFM_STRIDE_C = 0; + WEIGHT_BASE = 0; + WEIGHT_LENGTH = 0; + SCALE_BASE = 0; + SCALE_LENGTH = 0; + OFM_SCALE = 0; + OFM_SCALE_SHIFT = 0; + OPA_SCALE = 0; + OPA_SCALE_SHIFT = 0; + OPB_SCALE = 0; + DMA0_SRC = 0; + DMA0_DST = 0; + DMA0_LEN = 0; + IFM2_BASE0 = 0; + IFM2_BASE1 = 0; + IFM2_BASE2 = 0; + IFM2_BASE3 = 0; + IFM2_STRIDE_X = 0; + IFM2_STRIDE_Y = 0; + IFM2_STRIDE_C = 0; + for (size_t i = 0; i < (sizeof(USER_DEFINED) / sizeof(USER_DEFINED[0])); ++i) + USER_DEFINED[i] = 0; + REVISION = 0; + PID4 = 4; + PID5 = 0; + PID6 = 0; + PID7 = 0; + PID0 = 128; + PID1 = 181; + PID2 = 11; + PID3 = 0; + CID0 = 13; + CID1 = 240; + CID2 = 5; + CID3 = 177; + } + uint32_t &operator[](const int addr_offset) + { + return reinterpret_cast(this)[addr_offset / 4]; + } + access_type_t get_access_type(uint32_t offset) + { + switch (offset) + { + case 0: + return access_type_t::RO; + case 4: + return access_type_t::RO; + case 8: + return access_type_t::RW; + case 12: + return access_type_t::RW; + case 16: + return access_type_t::RW; + case 24: + return access_type_t::RO; + case 28: + return access_type_t::RW; + case 32: + return access_type_t::RW; + case 36: + return access_type_t::RO; + case 40: + return access_type_t::RO; + case 44: + return access_type_t::RW; + case 60: + return access_type_t::RW; + case 64: + return access_type_t::RW; + case 68: + return access_type_t::RW; + case 72: + return access_type_t::RW; + case 76: + return access_type_t::RW; + case 128: + return access_type_t::RW; + case 136: + return access_type_t::RW; + case 144: + return access_type_t::RW; + case 152: + return access_type_t::RW; + case 160: + return access_type_t::RW; + case 168: + return access_type_t::RW; + case 176: + return access_type_t::RW; + case 184: + return access_type_t::RW; + case 256: + return access_type_t::RO; + case 260: + return access_type_t::RO; + case 264: + return access_type_t::RO; + case 272: + return access_type_t::RO; + case 276: + return access_type_t::RO; + case 320: + return access_type_t::RW; + case 324: + return access_type_t::RW; + case 328: + return access_type_t::RW; + case 336: + return access_type_t::RW; + case 384: + return access_type_t::RW; + case 388: + return access_type_t::RW; + case 392: + return access_type_t::RW; + case 396: + return access_type_t::RW; + case 400: + return access_type_t::RW; + case 404: + return access_type_t::RW; + case 408: + return access_type_t::RW; + case 416: + return access_type_t::RW; + case 424: + return access_type_t::RW; + case 428: + return access_type_t::RW; + case 512: + return access_type_t::RO; + case 516: + return access_type_t::RO; + case 520: + return access_type_t::RO; + case 524: + return access_type_t::RO; + case 528: + return access_type_t::RO; + case 532: + return access_type_t::RO; + case 536: + return access_type_t::RO; + case 540: + return access_type_t::RO; + case 544: + return access_type_t::RO; + case 548: + return access_type_t::RO; + case 552: + return access_type_t::RO; + case 556: + return access_type_t::RO; + case 560: + return access_type_t::RO; + case 564: + return access_type_t::RO; + case 568: + return access_type_t::RO; + case 572: + return access_type_t::RO; + case 576: + return access_type_t::RO; + case 584: + return access_type_t::RO; + case 588: + return access_type_t::RO; + case 592: + return access_type_t::RO; + case 600: + return access_type_t::RO; + case 608: + return access_type_t::RO; + case 616: + return access_type_t::RO; + case 620: + return access_type_t::RO; + case 628: + return access_type_t::RO; + case 636: + return access_type_t::RO; + case 640: + return access_type_t::RO; + case 692: + return access_type_t::RO; + case 696: + return access_type_t::RO; + case 700: + return access_type_t::RO; + case 768: + return access_type_t::RW; + case 772: + return access_type_t::RW; + case 776: + return access_type_t::RW; + case 780: + return access_type_t::RW; + case 896: + return access_type_t::RW; + case 900: + return access_type_t::RW; + case 904: + return access_type_t::RW; + case 908: + return access_type_t::RW; + case 1024: + return access_type_t::RW; + case 1028: + return access_type_t::RW; + case 1032: + return access_type_t::RW; + case 1036: + return access_type_t::RW; + case 1040: + return access_type_t::RW; + case 1044: + return access_type_t::RW; + case 1048: + return access_type_t::RW; + case 1052: + return access_type_t::RW; + case 1056: + return access_type_t::RW; + case 1060: + return access_type_t::RW; + case 1064: + return access_type_t::RW; + case 1068: + return access_type_t::RW; + case 1072: + return access_type_t::RW; + case 1076: + return access_type_t::RW; + case 1080: + return access_type_t::RW; + case 1084: + return access_type_t::RW; + case 1088: + return access_type_t::RW; + case 1092: + return access_type_t::RW; + case 1096: + return access_type_t::RW; + case 1100: + return access_type_t::RW; + case 1104: + return access_type_t::RW; + case 1108: + return access_type_t::RW; + case 1112: + return access_type_t::RW; + case 1116: + return access_type_t::RW; + case 1120: + return access_type_t::RW; + case 1124: + return access_type_t::RW; + case 1128: + return access_type_t::RW; + case 1132: + return access_type_t::RW; + case 1136: + return access_type_t::RW; + case 1140: + return access_type_t::RW; + case 1144: + return access_type_t::RW; + case 1148: + return access_type_t::RW; + case 1152: + return access_type_t::RW; + case 1156: + return access_type_t::RW; + case 1160: + return access_type_t::RW; + case 1164: + return access_type_t::RW; + case 1168: + return access_type_t::RW; + case 1172: + return access_type_t::RW; + case 1176: + return access_type_t::RW; + case 1180: + return access_type_t::RW; + case 1184: + return access_type_t::RW; + case 1188: + return access_type_t::RW; + case 1192: + return access_type_t::RW; + case 1196: + return access_type_t::RW; + case 1200: + return access_type_t::RW; + case 1204: + return access_type_t::RW; + case 1208: + return access_type_t::RW; + case 1212: + return access_type_t::RW; + case 1216: + return access_type_t::RW; + case 1220: + return access_type_t::RW; + case 1224: + return access_type_t::RW; + case 1228: + return access_type_t::RW; + case 1232: + return access_type_t::RW; + case 1236: + return access_type_t::RW; + case 1240: + return access_type_t::RW; + case 1244: + return access_type_t::RW; + case 1248: + return access_type_t::RW; + case 1252: + return access_type_t::RW; + case 1256: + return access_type_t::RW; + case 1260: + return access_type_t::RW; + case 1264: + return access_type_t::RW; + case 1268: + return access_type_t::RW; + case 1272: + return access_type_t::RW; + case 1276: + return access_type_t::RW; + case 1280: + return access_type_t::RW; + case 1284: + return access_type_t::RW; + case 1288: + return access_type_t::RW; + case 1292: + return access_type_t::RW; + case 1296: + return access_type_t::RW; + case 1300: + return access_type_t::RW; + case 1304: + return access_type_t::RW; + case 1308: + return access_type_t::RW; + case 1312: + return access_type_t::RW; + case 1316: + return access_type_t::RW; + case 1320: + return access_type_t::RW; + case 1324: + return access_type_t::RW; + case 1328: + return access_type_t::RW; + case 1332: + return access_type_t::RW; + case 1336: + return access_type_t::RW; + case 1340: + return access_type_t::RW; + case 1344: + return access_type_t::RW; + case 1348: + return access_type_t::RW; + case 1352: + return access_type_t::RW; + case 1356: + return access_type_t::RW; + case 1360: + return access_type_t::RW; + case 1364: + return access_type_t::RW; + case 1368: + return access_type_t::RW; + case 1372: + return access_type_t::RW; + case 1376: + return access_type_t::RW; + case 1380: + return access_type_t::RW; + case 1384: + return access_type_t::RW; + case 1388: + return access_type_t::RW; + case 1392: + return access_type_t::RW; + case 1396: + return access_type_t::RW; + case 1400: + return access_type_t::RW; + case 1404: + return access_type_t::RW; + case 1408: + return access_type_t::RW; + case 1412: + return access_type_t::RW; + case 1416: + return access_type_t::RW; + case 1420: + return access_type_t::RW; + case 1424: + return access_type_t::RW; + case 1428: + return access_type_t::RW; + case 1432: + return access_type_t::RW; + case 1436: + return access_type_t::RW; + case 1440: + return access_type_t::RW; + case 1444: + return access_type_t::RW; + case 1448: + return access_type_t::RW; + case 1452: + return access_type_t::RW; + case 1456: + return access_type_t::RW; + case 1460: + return access_type_t::RW; + case 1464: + return access_type_t::RW; + case 1468: + return access_type_t::RW; + case 1472: + return access_type_t::RW; + case 1476: + return access_type_t::RW; + case 1480: + return access_type_t::RW; + case 1484: + return access_type_t::RW; + case 1488: + return access_type_t::RW; + case 1492: + return access_type_t::RW; + case 1496: + return access_type_t::RW; + case 1500: + return access_type_t::RW; + case 1504: + return access_type_t::RW; + case 1508: + return access_type_t::RW; + case 1512: + return access_type_t::RW; + case 1516: + return access_type_t::RW; + case 1520: + return access_type_t::RW; + case 1524: + return access_type_t::RW; + case 1528: + return access_type_t::RW; + case 1532: + return access_type_t::RW; + case 1536: + return access_type_t::RW; + case 1540: + return access_type_t::RW; + case 1544: + return access_type_t::RW; + case 1548: + return access_type_t::RW; + case 1552: + return access_type_t::RW; + case 1556: + return access_type_t::RW; + case 1560: + return access_type_t::RW; + case 1564: + return access_type_t::RW; + case 1568: + return access_type_t::RW; + case 1572: + return access_type_t::RW; + case 1576: + return access_type_t::RW; + case 1580: + return access_type_t::RW; + case 1584: + return access_type_t::RW; + case 1588: + return access_type_t::RW; + case 1592: + return access_type_t::RW; + case 1596: + return access_type_t::RW; + case 1600: + return access_type_t::RW; + case 1604: + return access_type_t::RW; + case 1608: + return access_type_t::RW; + case 1612: + return access_type_t::RW; + case 1616: + return access_type_t::RW; + case 1620: + return access_type_t::RW; + case 1624: + return access_type_t::RW; + case 1628: + return access_type_t::RW; + case 1632: + return access_type_t::RW; + case 1636: + return access_type_t::RW; + case 1640: + return access_type_t::RW; + case 1644: + return access_type_t::RW; + case 1648: + return access_type_t::RW; + case 1652: + return access_type_t::RW; + case 1656: + return access_type_t::RW; + case 1660: + return access_type_t::RW; + case 1664: + return access_type_t::RW; + case 1668: + return access_type_t::RW; + case 1672: + return access_type_t::RW; + case 1676: + return access_type_t::RW; + case 1680: + return access_type_t::RW; + case 1684: + return access_type_t::RW; + case 1688: + return access_type_t::RW; + case 1692: + return access_type_t::RW; + case 1696: + return access_type_t::RW; + case 1700: + return access_type_t::RW; + case 1704: + return access_type_t::RW; + case 1708: + return access_type_t::RW; + case 1712: + return access_type_t::RW; + case 1716: + return access_type_t::RW; + case 1720: + return access_type_t::RW; + case 1724: + return access_type_t::RW; + case 1728: + return access_type_t::RW; + case 1732: + return access_type_t::RW; + case 1736: + return access_type_t::RW; + case 1740: + return access_type_t::RW; + case 1744: + return access_type_t::RW; + case 1748: + return access_type_t::RW; + case 1752: + return access_type_t::RW; + case 1756: + return access_type_t::RW; + case 1760: + return access_type_t::RW; + case 1764: + return access_type_t::RW; + case 1768: + return access_type_t::RW; + case 1772: + return access_type_t::RW; + case 1776: + return access_type_t::RW; + case 1780: + return access_type_t::RW; + case 1784: + return access_type_t::RW; + case 1788: + return access_type_t::RW; + case 1792: + return access_type_t::RW; + case 1796: + return access_type_t::RW; + case 1800: + return access_type_t::RW; + case 1804: + return access_type_t::RW; + case 1808: + return access_type_t::RW; + case 1812: + return access_type_t::RW; + case 1816: + return access_type_t::RW; + case 1820: + return access_type_t::RW; + case 1824: + return access_type_t::RW; + case 1828: + return access_type_t::RW; + case 1832: + return access_type_t::RW; + case 1836: + return access_type_t::RW; + case 1840: + return access_type_t::RW; + case 1844: + return access_type_t::RW; + case 1848: + return access_type_t::RW; + case 1852: + return access_type_t::RW; + case 1856: + return access_type_t::RW; + case 1860: + return access_type_t::RW; + case 1864: + return access_type_t::RW; + case 1868: + return access_type_t::RW; + case 1872: + return access_type_t::RW; + case 1876: + return access_type_t::RW; + case 1880: + return access_type_t::RW; + case 1884: + return access_type_t::RW; + case 1888: + return access_type_t::RW; + case 1892: + return access_type_t::RW; + case 1896: + return access_type_t::RW; + case 1900: + return access_type_t::RW; + case 1904: + return access_type_t::RW; + case 1908: + return access_type_t::RW; + case 1912: + return access_type_t::RW; + case 1916: + return access_type_t::RW; + case 1920: + return access_type_t::RW; + case 1924: + return access_type_t::RW; + case 1928: + return access_type_t::RW; + case 1932: + return access_type_t::RW; + case 1936: + return access_type_t::RW; + case 1940: + return access_type_t::RW; + case 1944: + return access_type_t::RW; + case 1948: + return access_type_t::RW; + case 1952: + return access_type_t::RW; + case 1956: + return access_type_t::RW; + case 1960: + return access_type_t::RW; + case 1964: + return access_type_t::RW; + case 1968: + return access_type_t::RW; + case 1972: + return access_type_t::RW; + case 1976: + return access_type_t::RW; + case 1980: + return access_type_t::RW; + case 1984: + return access_type_t::RW; + case 1988: + return access_type_t::RW; + case 1992: + return access_type_t::RW; + case 1996: + return access_type_t::RW; + case 2000: + return access_type_t::RW; + case 2004: + return access_type_t::RW; + case 2008: + return access_type_t::RW; + case 2012: + return access_type_t::RW; + case 2016: + return access_type_t::RW; + case 2020: + return access_type_t::RW; + case 2024: + return access_type_t::RW; + case 2028: + return access_type_t::RW; + case 2032: + return access_type_t::RW; + case 2036: + return access_type_t::RW; + case 2040: + return access_type_t::RW; + case 2044: + return access_type_t::RW; + case 2048: + return access_type_t::RW; + case 2052: + return access_type_t::RW; + case 2056: + return access_type_t::RW; + case 2060: + return access_type_t::RW; + case 2064: + return access_type_t::RW; + case 2068: + return access_type_t::RW; + case 2076: + return access_type_t::RW; + case 2084: + return access_type_t::RW; + case 2088: + return access_type_t::RW; + case 2092: + return access_type_t::RW; + case 2096: + return access_type_t::RW; + case 2100: + return access_type_t::RW; + case 2108: + return access_type_t::RW; + case 2116: + return access_type_t::RW; + case 2120: + return access_type_t::RW; + case 2124: + return access_type_t::RW; + case 2128: + return access_type_t::RW; + case 2132: + return access_type_t::RW; + case 2136: + return access_type_t::RW; + case 2140: + return access_type_t::RW; + case 2144: + return access_type_t::RW; + case 2152: + return access_type_t::RW; + case 2156: + return access_type_t::RW; + case 2160: + return access_type_t::RW; + case 2172: + return access_type_t::RW; + case 2176: + return access_type_t::RW; + case 2180: + return access_type_t::RW; + case 2184: + return access_type_t::RW; + case 2192: + return access_type_t::RW; + case 2196: + return access_type_t::RW; + case 2200: + return access_type_t::RW; + case 2204: + return access_type_t::RW; + case 2208: + return access_type_t::RW; + case 2212: + return access_type_t::RW; + case 2228: + return access_type_t::RW; + case 2236: + return access_type_t::RW; + case 2240: + return access_type_t::RW; + case 2244: + return access_type_t::RW; + case 2248: + return access_type_t::RW; + case 2252: + return access_type_t::RW; + case 2304: + return access_type_t::RW; + case 2308: + return access_type_t::RW; + case 2324: + return access_type_t::RW; + case 2340: + return access_type_t::RW; + case 2344: + return access_type_t::RW; + case 2348: + return access_type_t::RW; + case 2352: + return access_type_t::RW; + case 2356: + return access_type_t::RW; + case 2364: + return access_type_t::RW; + case 2560: + return access_type_t::RW; + case 2568: + return access_type_t::RW; + case 2576: + return access_type_t::RW; + case 2584: + return access_type_t::RW; + case 2592: + return access_type_t::RW; + case 2600: + return access_type_t::RW; + case 2608: + return access_type_t::RW; + case 2624: + return access_type_t::RW; + case 2632: + return access_type_t::RW; + case 2640: + return access_type_t::RW; + case 2648: + return access_type_t::RW; + case 2656: + return access_type_t::RW; + case 2664: + return access_type_t::RW; + case 2672: + return access_type_t::RW; + case 2688: + return access_type_t::RW; + case 2696: + return access_type_t::RW; + case 2704: + return access_type_t::RW; + case 2712: + return access_type_t::RW; + case 2720: + return access_type_t::RW; + case 2724: + return access_type_t::RW; + case 2728: + return access_type_t::RW; + case 2732: + return access_type_t::RW; + case 2736: + return access_type_t::RW; + case 2752: + return access_type_t::RW; + case 2760: + return access_type_t::RW; + case 2768: + return access_type_t::RW; + case 2816: + return access_type_t::RW; + case 2824: + return access_type_t::RW; + case 2832: + return access_type_t::RW; + case 2840: + return access_type_t::RW; + case 2848: + return access_type_t::RW; + case 2856: + return access_type_t::RW; + case 2864: + return access_type_t::RW; + case 2944: + return access_type_t::RW; + case 2952: + return access_type_t::RW; + case 2960: + return access_type_t::RW; + case 2968: + return access_type_t::RW; + case 2976: + return access_type_t::RW; + case 2984: + return access_type_t::RW; + case 2992: + return access_type_t::RW; + case 3000: + return access_type_t::RW; + case 4032: + return access_type_t::RO; + case 4048: + return access_type_t::RO; + case 4052: + return access_type_t::RO; + case 4056: + return access_type_t::RO; + case 4060: + return access_type_t::RO; + case 4064: + return access_type_t::RO; + case 4068: + return access_type_t::RO; + case 4072: + return access_type_t::RO; + case 4076: + return access_type_t::RO; + case 4080: + return access_type_t::RO; + case 4084: + return access_type_t::RO; + case 4088: + return access_type_t::RO; + case 4092: + return access_type_t::RO; + default: + return access_type_t::RO; + } + } +#endif +}; + +#ifdef __cplusplus +struct isa +{ +#ifdef NPU_DISASSEMBLE + static int disassemble(const uint32_t *in, + std::string &op, + std::vector> &fields) + { + switch (*in & 0xffff) + { + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP): + { + const npu_op_stop_t &v = *reinterpret_cast(in); + op = "NPU_OP_STOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ): + { + const npu_op_irq_t &v = *reinterpret_cast(in); + op = "NPU_OP_IRQ"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV): + { + const npu_op_conv_t &v = *reinterpret_cast(in); + op = "NPU_OP_CONV"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE): + { + const npu_op_depthwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_DEPTHWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL): + { + const npu_op_pool_t &v = *reinterpret_cast(in); + op = "NPU_OP_POOL"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE): + { + const npu_op_elementwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_ELEMENTWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START): + { + const npu_op_dma_start_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT): + { + const npu_op_dma_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT): + { + const npu_op_kernel_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_KERNEL_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK): + { + const npu_op_pmu_mask_t &v = *reinterpret_cast(in); + op = "NPU_OP_PMU_MASK"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP): + { + const npu_set_ifm_pad_top_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_TOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT): + { + const npu_set_ifm_pad_left_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_LEFT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT): + { + const npu_set_ifm_pad_right_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_RIGHT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM): + { + const npu_set_ifm_pad_bottom_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_BOTTOM"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1): + { + const npu_set_ifm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION): + { + const npu_set_ifm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE): + { + const npu_set_ifm_upscale_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_UPSCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT): + { + const npu_set_ifm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1): + { + const npu_set_ifm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1): + { + const npu_set_ifm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1): + { + const npu_set_ifm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END): + { + const npu_set_ifm_ib_end_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_IB_END"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION): + { + const npu_set_ifm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1): + { + const npu_set_ofm_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1): + { + const npu_set_ofm_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1): + { + const npu_set_ofm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION): + { + const npu_set_ofm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1): + { + const npu_set_ofm_blk_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1): + { + const npu_set_ofm_blk_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1): + { + const npu_set_ofm_blk_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT): + { + const npu_set_ofm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1): + { + const npu_set_ofm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1): + { + const npu_set_ofm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1): + { + const npu_set_ofm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION): + { + const npu_set_ofm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1): + { + const npu_set_kernel_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1): + { + const npu_set_kernel_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE): + { + const npu_set_kernel_stride_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_STRIDE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT): + { + const npu_set_acc_format_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACC_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION): + { + const npu_set_activation_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN): + { + const npu_set_activation_min_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MIN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX): + { + const npu_set_activation_max_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION): + { + const npu_set_weight_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION): + { + const npu_set_scale_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START): + { + const npu_set_ab_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_AB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP): + { + const npu_set_blockdep_t &v = *reinterpret_cast(in); + op = "NPU_SET_BLOCKDEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION): + { + const npu_set_dma0_src_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION): + { + const npu_set_dma0_dst_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0): + { + const npu_set_dma0_size0_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1): + { + const npu_set_dma0_size1_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST): + { + const npu_set_ifm2_broadcast_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR): + { + const npu_set_ifm2_scalar_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_SCALAR"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION): + { + const npu_set_ifm2_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT): + { + const npu_set_ifm2_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1): + { + const npu_set_ifm2_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1): + { + const npu_set_ifm2_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1): + { + const npu_set_ifm2_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START): + { + const npu_set_ifm2_ib_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_IB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION): + { + const npu_set_ifm2_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0): + { + const npu_set_ifm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1): + { + const npu_set_ifm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2): + { + const npu_set_ifm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3): + { + const npu_set_ifm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X): + { + const npu_set_ifm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y): + { + const npu_set_ifm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C): + { + const npu_set_ifm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0): + { + const npu_set_ofm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1): + { + const npu_set_ofm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2): + { + const npu_set_ofm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3): + { + const npu_set_ofm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X): + { + const npu_set_ofm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y): + { + const npu_set_ofm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C): + { + const npu_set_ofm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE): + { + const npu_set_weight_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH): + { + const npu_set_weight_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE): + { + const npu_set_scale_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH): + { + const npu_set_scale_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE): + { + const npu_set_ofm_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE): + { + const npu_set_opa_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPA_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE): + { + const npu_set_opb_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPB_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC): + { + const npu_set_dma0_src_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST): + { + const npu_set_dma0_dst_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN): + { + const npu_set_dma0_len_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_LEN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0): + { + const npu_set_ifm2_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1): + { + const npu_set_ifm2_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2): + { + const npu_set_ifm2_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3): + { + const npu_set_ifm2_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X): + { + const npu_set_ifm2_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y): + { + const npu_set_ifm2_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C): + { + const npu_set_ifm2_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0): + { + const npu_set_user_defined0_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1): + { + const npu_set_user_defined1_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2): + { + const npu_set_user_defined2_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3): + { + const npu_set_user_defined3_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4): + { + const npu_set_user_defined4_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED4"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5): + { + const npu_set_user_defined5_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED5"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6): + { + const npu_set_user_defined6_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED6"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7): + { + const npu_set_user_defined7_t &v = *reinterpret_cast(in); + op = "NPU_SET_USER_DEFINED7"; + v.disassemble(fields); + break; + } + } + return (*in & (3 << 14)) != 0 ? 2 : 1; + } +#endif +#endif + // Signal the end of command stream + struct npu_op_stop_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_stop_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_stop_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_stop_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_stop_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_stop_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // Raises an IRQ to the host + struct npu_op_irq_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_irq_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_irq_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_irq_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_irq_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_irq_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // 2D convolution + struct npu_op_conv_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_conv_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_conv_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_conv_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Depth-wise 2D convolution + struct npu_op_depthwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_depthwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_depthwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_depthwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Pooling + struct npu_op_pool_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pooling_mode : 3; // Pooling mode + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_op_pool_t(NPU_NAMESPACE::pooling_mode _pooling_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(static_cast(_pooling_mode) & ((1U << 3) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_pool_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pooling_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pool_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pool_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pooling_mode get_pooling_mode() const + { + return static_cast(pooling_mode); + } + CONSTEXPR npu_op_pool_t &set_pooling_mode(NPU_NAMESPACE::pooling_mode value) + { + pooling_mode = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "pooling_mode", + (pooling_mode < (sizeof(pooling_mode_str) / sizeof(pooling_mode_str[0])) ? + pooling_mode_str[pooling_mode] : + "****"))); + } +#endif +#endif + }; + // Elementwise operation + struct npu_op_elementwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t elementwise_mode : 6; // Elementwise mode + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_op_elementwise_t(NPU_NAMESPACE::elementwise_mode _elementwise_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(static_cast(_elementwise_mode) & ((1U << 6) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_elementwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), elementwise_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_elementwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_elementwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::elementwise_mode get_elementwise_mode() const + { + return static_cast(elementwise_mode); + } + CONSTEXPR npu_op_elementwise_t &set_elementwise_mode(NPU_NAMESPACE::elementwise_mode value) + { + elementwise_mode = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "elementwise_mode", + (elementwise_mode < (sizeof(elementwise_mode_str) / sizeof(elementwise_mode_str[0])) ? + elementwise_mode_str[elementwise_mode] : + "****"))); + } +#endif +#endif + }; + // Queue new DMA for the given channel + struct npu_op_dma_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_dma_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Wait for the DMA channel to have k or fewer active descriptors outstanding + struct npu_op_dma_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t k : 4; // Number of outstanding descriptors + uint32_t reserved1 : 12; +#ifdef __cplusplus + public: + npu_op_dma_wait_t(uint32_t _k) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(_k & ((1U << 4) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_dma_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_k() const + { + return static_cast(k); + } + CONSTEXPR npu_op_dma_wait_t &set_k(uint32_t value) + { + k = static_cast(value) & ((1U << 4) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("k", std::to_string(k))); + } +#endif +#endif + }; + // Wait for n or fewer kernel operations to be remaining + struct npu_op_kernel_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t n : 2; // Number of kernel operations in range 0-3 + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_op_kernel_wait_t(uint32_t _n) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(_n & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_kernel_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_kernel_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_kernel_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_n() const + { + return static_cast(n); + } + CONSTEXPR npu_op_kernel_wait_t &set_n(uint32_t value) + { + n = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("n", std::to_string(n))); + } +#endif +#endif + }; + // Enable or disable PMU counting (debug feature only) + struct npu_op_pmu_mask_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t enable : 1; // Enable or disable PMU mask + uint32_t reserved1 : 15; +#ifdef __cplusplus + public: + npu_op_pmu_mask_t(uint32_t _enable) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(_enable & ((1U << 1) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_op_pmu_mask_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pmu_mask_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pmu_mask_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_enable() const + { + return static_cast(enable); + } + CONSTEXPR npu_op_pmu_mask_t &set_enable(uint32_t value) + { + enable = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("enable", std::to_string(enable))); + } +#endif +#endif + }; + // IFM top pad + struct npu_set_ifm_pad_top_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM top pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_top_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_top_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM left pad + struct npu_set_ifm_pad_left_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM left pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_left_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_left_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM right pad + struct npu_set_ifm_pad_right_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM right pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_right_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_right_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM bottom pad + struct npu_set_ifm_pad_bottom_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM bottom pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_bottom_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_bottom_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // Number of input channels for convolution + struct npu_set_ifm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Number of input channels for convolution +#ifdef __cplusplus + public: + npu_set_ifm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // IFM Precision + struct npu_set_ifm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t scale_mode : 2; // IFM scale mode + uint32_t reserved3 : 4; + uint32_t round_mode : 2; // IFM round mode +#ifdef __cplusplus + public: + npu_set_ifm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ifm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 2) - 1)), reserved3(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ifm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), scale_mode(0), reserved3(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_scale_mode(NPU_NAMESPACE::ifm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ifm_scale_mode_str) / sizeof(ifm_scale_mode_str[0])) ? + ifm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // IFM upscale mode + struct npu_set_ifm_upscale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mode : 2; // IFM upscale mode + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_ifm_upscale_t(NPU_NAMESPACE::ifm_upscale_mode _mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(static_cast(_mode) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_upscale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_upscale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_upscale_mode get_mode() const + { + return static_cast(mode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_mode(NPU_NAMESPACE::ifm_upscale_mode value) + { + mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "mode", + (mode < (sizeof(ifm_upscale_mode_str) / sizeof(ifm_upscale_mode_str[0])) ? ifm_upscale_mode_str[mode] : + "****"))); + } +#endif +#endif + }; + // IFM zero point + struct npu_set_ifm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM Tile 0 and tile 2 width + struct npu_set_ifm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM Tile 0 height + struct npu_set_ifm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM Tile 1 height + struct npu_set_ifm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // End of IB0,IB1 buffers + struct npu_set_ifm_ib_end_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_end : 6; // End of IB0,IB1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm_ib_end_t(uint32_t _ib_end) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(_ib_end & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm_ib_end_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_end() const + { + return static_cast(ib_end); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_ib_end(uint32_t value) + { + ib_end = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_end", std::to_string(ib_end))); + } +#endif +#endif + }; + // Index n for IFM access + struct npu_set_ifm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number n + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_ifm_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_ifm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_ifm_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Output feature map width + struct npu_set_ofm_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Output feature map width +#ifdef __cplusplus + public: + npu_set_ofm_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Output feature map height + struct npu_set_ofm_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Output feature map height +#ifdef __cplusplus + public: + npu_set_ofm_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Output feature map depth + struct npu_set_ofm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Output feature map depth +#ifdef __cplusplus + public: + npu_set_ofm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM Precision + struct npu_set_ofm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // OFM type + uint32_t activation_precision : 2; // OFM precision + uint32_t reserved1 : 3; + uint32_t activation_format : 2; // OFM format + uint32_t scale_mode : 1; // OFM scale mode + uint32_t reserved2 : 5; + uint32_t round_mode : 2; // OFM round mode +#ifdef __cplusplus + public: + npu_set_ofm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ofm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved1(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 1) - 1)), reserved2(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ofm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), + activation_precision(0), reserved1(0), activation_format(0), scale_mode(0), reserved2(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ofm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_scale_mode(NPU_NAMESPACE::ofm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ofm_scale_mode_str) / sizeof(ofm_scale_mode_str[0])) ? + ofm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // OFM block width + struct npu_set_ofm_blk_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 6; // OFM block width + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ofm_blk_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM block height + struct npu_set_ofm_blk_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 5; // OFM block height + uint32_t reserved1 : 11; +#ifdef __cplusplus + public: + npu_set_ofm_blk_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 5) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 5) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM block depth + struct npu_set_ofm_blk_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 7; // OFM block depth + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ofm_blk_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 7) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM zero point + struct npu_set_ofm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ofm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // OFM Tile 0 and tile 2 width + struct npu_set_ofm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // OFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ofm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM Tile 0 height + struct npu_set_ofm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ofm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM Tile 1 height + struct npu_set_ofm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ofm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Index n for OFM access + struct npu_set_ofm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for OFM access + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_ofm_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_ofm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ofm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_ofm_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Kernel width + struct npu_set_kernel_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Kernel width +#ifdef __cplusplus + public: + npu_set_kernel_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Kernel height + struct npu_set_kernel_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Kernel height +#ifdef __cplusplus + public: + npu_set_kernel_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Kernel stride + struct npu_set_kernel_stride_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t stride_x_lsb : 1; // Stride x LSB. (kernel_x_stride - 1)[0] + uint32_t stride_y_lsb : 1; // Stride y LSB. (kernel_y_stride - 1)[0] + uint32_t weight_order : 1; // Weight ordering mode + uint32_t dilation_x : 1; // Kernel x dilation + uint32_t dilation_y : 1; // Kernel y dilation + uint32_t decomposition : 1; // Kernel decomposition + uint32_t stride_x_msb : 1; // Stride x MSB. (kernel_x_stride - 1) >> 1 + uint32_t reserved1 : 2; + uint32_t stride_y_msb : 1; // Stride y MSB. (kernel_y_stride - 1) >> 1 + uint32_t reserved2 : 6; +#ifdef __cplusplus + public: + npu_set_kernel_stride_t(uint32_t _stride_x_lsb, + uint32_t _stride_y_lsb, + NPU_NAMESPACE::weight_order _weight_order, + NPU_NAMESPACE::kernel_dilation _dilation_x, + NPU_NAMESPACE::kernel_dilation _dilation_y, + NPU_NAMESPACE::kernel_decomposition _decomposition, + uint32_t _stride_x_msb, + uint32_t _stride_y_msb) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(_stride_x_lsb & ((1U << 1) - 1)), stride_y_lsb(_stride_y_lsb & ((1U << 1) - 1)), + weight_order(static_cast(_weight_order) & ((1U << 1) - 1)), + dilation_x(static_cast(_dilation_x) & ((1U << 1) - 1)), + dilation_y(static_cast(_dilation_y) & ((1U << 1) - 1)), + decomposition(static_cast(_decomposition) & ((1U << 1) - 1)), + stride_x_msb(_stride_x_msb & ((1U << 1) - 1)), reserved1(0), stride_y_msb(_stride_y_msb & ((1U << 1) - 1)), + reserved2(0) + { + } + CONSTEXPR npu_set_kernel_stride_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), stride_x_lsb(0), stride_y_lsb(0), + weight_order(0), dilation_x(0), dilation_y(0), decomposition(0), stride_x_msb(0), reserved1(0), + stride_y_msb(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_stride_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_stride_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_lsb() const + { + return static_cast(stride_x_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_lsb(uint32_t value) + { + stride_x_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_lsb() const + { + return static_cast(stride_y_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_lsb(uint32_t value) + { + stride_y_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_order get_weight_order() const + { + return static_cast(weight_order); + } + CONSTEXPR npu_set_kernel_stride_t &set_weight_order(NPU_NAMESPACE::weight_order value) + { + weight_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_x() const + { + return static_cast(dilation_x); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_x(NPU_NAMESPACE::kernel_dilation value) + { + dilation_x = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_y() const + { + return static_cast(dilation_y); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_y(NPU_NAMESPACE::kernel_dilation value) + { + dilation_y = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_decomposition get_decomposition() const + { + return static_cast(decomposition); + } + CONSTEXPR npu_set_kernel_stride_t &set_decomposition(NPU_NAMESPACE::kernel_decomposition value) + { + decomposition = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_msb() const + { + return static_cast(stride_x_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_msb(uint32_t value) + { + stride_x_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_msb() const + { + return static_cast(stride_y_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_msb(uint32_t value) + { + stride_y_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("stride_x_lsb", std::to_string(stride_x_lsb))); + fields.push_back(std::make_pair("stride_y_lsb", std::to_string(stride_y_lsb))); + fields.push_back(std::make_pair( + "weight_order", + (weight_order < (sizeof(weight_order_str) / sizeof(weight_order_str[0])) ? + weight_order_str[weight_order] : + "****"))); + fields.push_back(std::make_pair( + "dilation_x", + (dilation_x < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_x] : + "****"))); + fields.push_back(std::make_pair( + "dilation_y", + (dilation_y < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_y] : + "****"))); + fields.push_back(std::make_pair( + "decomposition", + (decomposition < (sizeof(kernel_decomposition_str) / sizeof(kernel_decomposition_str[0])) ? + kernel_decomposition_str[decomposition] : + "****"))); + fields.push_back(std::make_pair("stride_x_msb", std::to_string(stride_x_msb))); + fields.push_back(std::make_pair("stride_y_msb", std::to_string(stride_y_msb))); + } +#endif +#endif + }; + // Accumulator format + struct npu_set_acc_format_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t acc_format : 2; // Accumulator format + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_acc_format_t(NPU_NAMESPACE::acc_format _acc_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(static_cast(_acc_format) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_acc_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), acc_format(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_acc_format_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_acc_format_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_format get_acc_format() const + { + return static_cast(acc_format); + } + CONSTEXPR npu_set_acc_format_t &set_acc_format(NPU_NAMESPACE::acc_format value) + { + acc_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "acc_format", + (acc_format < (sizeof(acc_format_str) / sizeof(acc_format_str[0])) ? acc_format_str[acc_format] : + "****"))); + } +#endif +#endif + }; + // Activation function and clip range + struct npu_set_activation_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_function : 5; // Activation function (before table lookup) + uint32_t reserved1 : 7; + uint32_t activation_clip_range : 3; // Activation clip range. This must be set to 0 if table lookup is not used + uint32_t reserved2 : 1; +#ifdef __cplusplus + public: + npu_set_activation_t(NPU_NAMESPACE::activation_function _activation_function, + NPU_NAMESPACE::activation_clip_range _activation_clip_range) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(static_cast(_activation_function) & ((1U << 5) - 1)), reserved1(0), + activation_clip_range(static_cast(_activation_clip_range) & ((1U << 3) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_activation_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_function(0), reserved1(0), + activation_clip_range(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_function get_activation_function() const + { + return static_cast(activation_function); + } + CONSTEXPR npu_set_activation_t &set_activation_function(NPU_NAMESPACE::activation_function value) + { + activation_function = static_cast(value) & ((1U << 5) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_clip_range get_activation_clip_range() const + { + return static_cast(activation_clip_range); + } + CONSTEXPR npu_set_activation_t &set_activation_clip_range(NPU_NAMESPACE::activation_clip_range value) + { + activation_clip_range = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_function", + (activation_function < (sizeof(activation_function_str) / sizeof(activation_function_str[0])) ? + activation_function_str[activation_function] : + "****"))); + fields.push_back(std::make_pair( + "activation_clip_range", + (activation_clip_range < (sizeof(activation_clip_range_str) / sizeof(activation_clip_range_str[0])) ? + activation_clip_range_str[activation_clip_range] : + "****"))); + } +#endif +#endif + }; + // Lower bound clip + struct npu_set_activation_min_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_min_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_min_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_min_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_min_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_min_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Upper bound clip + struct npu_set_activation_max_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_max_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_max_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_max_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_max_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Index n for weight stream access + struct npu_set_weight_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for weight stream access + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_weight_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_weight_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_weight_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_weight_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Index n for scale stream access + struct npu_set_scale_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for scale stream access + uint32_t reserved1 : 12; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_scale_region_t(uint32_t _region, NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0), custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_scale_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_scale_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_scale_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Start of ACC0,ACC1 buffers + struct npu_set_ab_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ab_start : 6; // Start of ACC0,ACC1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ab_start_t(uint32_t _ab_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(_ab_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ab_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ab_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ab_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ab_start() const + { + return static_cast(ab_start); + } + CONSTEXPR npu_set_ab_start_t &set_ab_start(uint32_t value) + { + ab_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ab_start", std::to_string(ab_start))); + } +#endif +#endif + }; + // Block number of blocks dependency + struct npu_set_blockdep_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t blockdep : 2; // Block number of blocks dependency between kernel operations + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_blockdep_t(uint32_t _blockdep) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(_blockdep & ((1U << 2) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_blockdep_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_blockdep_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_blockdep_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_blockdep() const + { + return static_cast(blockdep); + } + CONSTEXPR npu_set_blockdep_t &set_blockdep(uint32_t value) + { + blockdep = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("blockdep", std::to_string(blockdep))); + } +#endif +#endif + }; + // DMA0 source region + struct npu_set_dma0_src_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 4; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_dma0_src_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode, + NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0), + custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_dma0_src_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_dma0_src_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // DMA0 destination region + struct npu_set_dma0_dst_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number if region_mode is region_mode_external. Else core mask to write to (bit k + // set for core k=0,1) + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 4; + uint32_t custom_dma_cs : 1; // Custom DMA select +#ifdef __cplusplus + public: + npu_set_dma0_dst_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode, + NPU_NAMESPACE::custom_dma_cs _custom_dma_cs) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0), + custom_dma_cs(static_cast(_custom_dma_cs) & ((1U << 1) - 1)) + { + } + CONSTEXPR npu_set_dma0_dst_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0), custom_dma_cs(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma_cs get_custom_dma_cs() const + { + return static_cast(custom_dma_cs); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_custom_dma_cs(NPU_NAMESPACE::custom_dma_cs value) + { + custom_dma_cs = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + fields.push_back(std::make_pair( + "custom_dma_cs", + (custom_dma_cs < (sizeof(custom_dma_cs_str) / sizeof(custom_dma_cs_str[0])) ? + custom_dma_cs_str[custom_dma_cs] : + "****"))); + } +#endif +#endif + }; + // Size of second dimension for 2D/3D transfers + struct npu_set_dma0_size0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of second dimension for 2D/3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size0_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size0_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size0_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // Size of third dimension for 3D transfers + struct npu_set_dma0_size1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of third dimension for 3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size1_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size1_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // IFM2 broadcast configuration + struct npu_set_ifm2_broadcast_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t + broadcast_h : 1; // Broadcast H dimension (if set then any accesses to IFM2 sets y=0 and IFM2 height=1) + uint32_t broadcast_w : 1; // Broadcast W dimension (if set then any accesses to IFM2 sets x=0 and IFM2 width=1) + uint32_t broadcast_c : 1; // Broadcast C dimension (if set then any accesses to IFM2 sets c=0 and IFM2 depth=1) + uint32_t reserved1 : 3; + uint32_t operand_order : 1; // Operand order + uint32_t broadcast_constant : 1; // Broadcast constant given by NPU_SET_IFM2_SCALAR and so ignore BH, BW and BC + uint32_t reserved2 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_h, + NPU_NAMESPACE::broadcast_mode _broadcast_w, + NPU_NAMESPACE::broadcast_mode _broadcast_c, + NPU_NAMESPACE::ifm2_operand_order _operand_order, + NPU_NAMESPACE::broadcast_mode _broadcast_constant) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_h(static_cast(_broadcast_h) & ((1U << 1) - 1)), + broadcast_w(static_cast(_broadcast_w) & ((1U << 1) - 1)), + broadcast_c(static_cast(_broadcast_c) & ((1U << 1) - 1)), reserved1(0), + operand_order(static_cast(_operand_order) & ((1U << 1) - 1)), + broadcast_constant(static_cast(_broadcast_constant) & ((1U << 1) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_ifm2_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), broadcast_h(0), broadcast_w(0), + broadcast_c(0), reserved1(0), operand_order(0), broadcast_constant(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_h() const + { + return static_cast(broadcast_h); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_h(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_h = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_w() const + { + return static_cast(broadcast_w); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_w(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_w = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_c() const + { + return static_cast(broadcast_c); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_c(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_c = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm2_operand_order get_operand_order() const + { + return static_cast(operand_order); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_operand_order(NPU_NAMESPACE::ifm2_operand_order value) + { + operand_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_constant() const + { + return static_cast(broadcast_constant); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_constant(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_constant = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "broadcast_h", + (broadcast_h < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_h] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_w", + (broadcast_w < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_w] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_c", + (broadcast_c < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_c] : + "****"))); + fields.push_back(std::make_pair( + "operand_order", + (operand_order < (sizeof(ifm2_operand_order_str) / sizeof(ifm2_operand_order_str[0])) ? + ifm2_operand_order_str[operand_order] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_constant", + (broadcast_constant < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_constant] : + "****"))); + } +#endif +#endif + }; + // IFM2 scalar value + struct npu_set_ifm2_scalar_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t scalar : 16; // int16 or uint16 depending on ifm2_precision.type +#ifdef __cplusplus + public: + npu_set_ifm2_scalar_t(uint32_t _scalar) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(_scalar & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_scalar_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scalar() const + { + return static_cast(scalar); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_scalar(uint32_t value) + { + scalar = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scalar", std::to_string(scalar))); + } +#endif +#endif + }; + // IFM2 Precision + struct npu_set_ifm2_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type - MUST MATCH IFM + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision - MUST MATCH IFM + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t reserved3 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), reserved3(0) + { + } + CONSTEXPR npu_set_ifm2_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), reserved3(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + } +#endif +#endif + }; + // IFM2 zero point + struct npu_set_ifm2_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm2_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM2 Tile 0 and tile 2 width + struct npu_set_ifm2_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM2 Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm2_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM2 Tile 0 height + struct npu_set_ifm2_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm2_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM2 Tile 1 height + struct npu_set_ifm2_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm2_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Start of IB0,IB1 buffers for IFM2 + struct npu_set_ifm2_ib_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_start : 6; // Start of IB0,IB1 buffers for IFM2 in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm2_ib_start_t(uint32_t _ib_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(_ib_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_ib_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_start() const + { + return static_cast(ib_start); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_ib_start(uint32_t value) + { + ib_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_start", std::to_string(ib_start))); + } +#endif +#endif + }; + // Index n for IFM2 access + struct npu_set_ifm2_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for IFM2 access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ifm2_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm2_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // IFM Tile 0 address + struct npu_set_ifm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base0_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base0_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 1 address + struct npu_set_ifm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base1_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base1_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 2 address + struct npu_set_ifm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base2_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base2_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 3 address + struct npu_set_ifm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base3_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_base3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_base3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_base3_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between horizontal values + struct npu_set_ifm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_x_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_stride_x_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_stride_x_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_stride_x_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between vertical values + struct npu_set_ifm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_y_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_stride_y_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_stride_y_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_stride_y_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_c_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_stride_c_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_stride_c_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm_stride_c_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 0 address + struct npu_set_ofm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base0_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base0_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 1 address + struct npu_set_ofm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base1_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base1_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 2 address + struct npu_set_ofm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base2_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base2_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 3 address + struct npu_set_ofm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base3_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_base3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_base3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_base3_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between horizontal values + struct npu_set_ofm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_x_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_stride_x_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_stride_x_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_stride_x_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between vertical values + struct npu_set_ofm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_y_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_stride_y_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_stride_y_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_stride_y_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ofm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_c_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ofm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_stride_c_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_stride_c_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ofm_stride_c_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte offset in WEIGHT_REGION + struct npu_set_weight_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_weight_base_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_weight_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_base_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_base_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_weight_base_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte length + struct npu_set_weight_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 32; // Weight stream byte length +#ifdef __cplusplus + public: + npu_set_weight_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(_length) + { + } + CONSTEXPR npu_set_weight_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight_length_t &set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // Scale and bias stream input byte offset from SCALE_REGION + struct npu_set_scale_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_scale_base_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_scale_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_base_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_base_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_scale_base_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Scale and bias stream input byte length + struct npu_set_scale_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 20; // Scale and bias stream byte length + uint32_t reserved2 : 12; +#ifdef __cplusplus + public: + npu_set_scale_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + length(_length & ((1U << 20) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_scale_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale_length_t &set_length(uint32_t value) + { + length = value & ((1U << 20) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // OFM scale + struct npu_set_ofm_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. Not applied for 32-bit operations +#ifdef __cplusplus + public: + npu_set_ofm_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_ofm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ofm_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ofm_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand A scale + struct npu_set_opa_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift. Ignored if IFM scale mode is 0 + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. 16-bit if IFM scale mode is 0 +#ifdef __cplusplus + public: + npu_set_opa_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_opa_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opa_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opa_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_opa_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opa_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand B scale + struct npu_set_opb_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t scale : 16; // Scale. Not used if IFM scale mode is 1 or 2 + uint32_t reserved2 : 16; +#ifdef __cplusplus + public: + npu_set_opb_scale_t(uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + scale(_scale & ((1U << 16) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_opb_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), scale(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opb_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opb_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opb_scale_t &set_scale(uint32_t value) + { + scale = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // DMA user channel 0 source byte offset from DMA0_SRC_REGION + struct npu_set_dma0_src_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_src_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_dma0_src_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_dma0_src_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 destination byte offset from DMA0_DST_REGION + struct npu_set_dma0_dst_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_dst_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_dma0_dst_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_dma0_dst_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 transfer length in bytes for each 1D transfer + struct npu_set_dma0_len_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_len_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_dma0_len_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_len_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_len_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_dma0_len_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 0 address + struct npu_set_ifm2_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base0_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base0_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 1 address + struct npu_set_ifm2_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base1_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base1_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 2 address + struct npu_set_ifm2_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base2_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base2_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 3 address + struct npu_set_ifm2_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base3_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_base3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_base3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_base3_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between horizontal values + struct npu_set_ifm2_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_x_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between vertical values + struct npu_set_ifm2_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_y_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm2_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t addr : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_c_t(uint32_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(_addr) + { + } + CONSTEXPR npu_set_ifm2_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), addr(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + return static_cast(addr); + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_addr(uint32_t value) + { + addr = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // User defined register 0 + struct npu_set_user_defined0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined0_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined0_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined0_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 1 + struct npu_set_user_defined1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined1_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined1_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined1_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 2 + struct npu_set_user_defined2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined2_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined2_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined2_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined2_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 3 + struct npu_set_user_defined3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined3_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined3_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined3_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined3_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 4 + struct npu_set_user_defined4_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined4_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined4_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED4); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined4_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined4_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined4_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 5 + struct npu_set_user_defined5_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined5_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined5_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED5); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined5_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined5_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined5_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 6 + struct npu_set_user_defined6_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined6_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined6_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED6); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined6_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined6_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined6_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; + // User defined register 7 + struct npu_set_user_defined7_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t user_reg : 32; // User defined register +#ifdef __cplusplus + public: + npu_set_user_defined7_t(uint32_t _user_reg) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(_user_reg) + { + } + CONSTEXPR npu_set_user_defined7_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), user_reg(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_USER_DEFINED7); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_user_defined7_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_user_defined7_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_user_reg() const + { + return static_cast(user_reg); + } + CONSTEXPR npu_set_user_defined7_t &set_user_reg(uint32_t value) + { + user_reg = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("user_reg", std::to_string(user_reg))); + } +#endif +#endif + }; +#ifdef __cplusplus +}; +#endif +#define NPU_OP_STRUCTS \ + NPU_OP_(stop) \ + NPU_OP_(irq) \ + NPU_OP_(conv) \ + NPU_OP_(depthwise) \ + NPU_OP_(pool) \ + NPU_OP_(elementwise) \ + NPU_OP_(dma_start) \ + NPU_OP_(dma_wait) \ + NPU_OP_(kernel_wait) \ + NPU_OP_(pmu_mask) + +#define NPU_SET_STRUCTS \ + NPU_SET_(ifm_pad_top) \ + NPU_SET_(ifm_pad_left) \ + NPU_SET_(ifm_pad_right) \ + NPU_SET_(ifm_pad_bottom) \ + NPU_SET_(ifm_depth_m1) \ + NPU_SET_(ifm_precision) \ + NPU_SET_(ifm_upscale) \ + NPU_SET_(ifm_zero_point) \ + NPU_SET_(ifm_width0_m1) \ + NPU_SET_(ifm_height0_m1) \ + NPU_SET_(ifm_height1_m1) \ + NPU_SET_(ifm_ib_end) \ + NPU_SET_(ifm_region) \ + NPU_SET_(ofm_width_m1) \ + NPU_SET_(ofm_height_m1) \ + NPU_SET_(ofm_depth_m1) \ + NPU_SET_(ofm_precision) \ + NPU_SET_(ofm_blk_width_m1) \ + NPU_SET_(ofm_blk_height_m1) \ + NPU_SET_(ofm_blk_depth_m1) \ + NPU_SET_(ofm_zero_point) \ + NPU_SET_(ofm_width0_m1) \ + NPU_SET_(ofm_height0_m1) \ + NPU_SET_(ofm_height1_m1) \ + NPU_SET_(ofm_region) \ + NPU_SET_(kernel_width_m1) \ + NPU_SET_(kernel_height_m1) \ + NPU_SET_(kernel_stride) \ + NPU_SET_(acc_format) \ + NPU_SET_(activation) \ + NPU_SET_(activation_min) \ + NPU_SET_(activation_max) \ + NPU_SET_(weight_region) \ + NPU_SET_(scale_region) \ + NPU_SET_(ab_start) \ + NPU_SET_(blockdep) \ + NPU_SET_(dma0_src_region) \ + NPU_SET_(dma0_dst_region) \ + NPU_SET_(dma0_size0) \ + NPU_SET_(dma0_size1) \ + NPU_SET_(ifm2_broadcast) \ + NPU_SET_(ifm2_scalar) \ + NPU_SET_(ifm2_precision) \ + NPU_SET_(ifm2_zero_point) \ + NPU_SET_(ifm2_width0_m1) \ + NPU_SET_(ifm2_height0_m1) \ + NPU_SET_(ifm2_height1_m1) \ + NPU_SET_(ifm2_ib_start) \ + NPU_SET_(ifm2_region) \ + NPU_SET_(ifm_base0) \ + NPU_SET_(ifm_base1) \ + NPU_SET_(ifm_base2) \ + NPU_SET_(ifm_base3) \ + NPU_SET_(ifm_stride_x) \ + NPU_SET_(ifm_stride_y) \ + NPU_SET_(ifm_stride_c) \ + NPU_SET_(ofm_base0) \ + NPU_SET_(ofm_base1) \ + NPU_SET_(ofm_base2) \ + NPU_SET_(ofm_base3) \ + NPU_SET_(ofm_stride_x) \ + NPU_SET_(ofm_stride_y) \ + NPU_SET_(ofm_stride_c) \ + NPU_SET_(weight_base) \ + NPU_SET_(weight_length) \ + NPU_SET_(scale_base) \ + NPU_SET_(scale_length) \ + NPU_SET_(ofm_scale) \ + NPU_SET_(opa_scale) \ + NPU_SET_(opb_scale) \ + NPU_SET_(dma0_src) \ + NPU_SET_(dma0_dst) \ + NPU_SET_(dma0_len) \ + NPU_SET_(ifm2_base0) \ + NPU_SET_(ifm2_base1) \ + NPU_SET_(ifm2_base2) \ + NPU_SET_(ifm2_base3) \ + NPU_SET_(ifm2_stride_x) \ + NPU_SET_(ifm2_stride_y) \ + NPU_SET_(ifm2_stride_c) \ + NPU_SET_(user_defined0) \ + NPU_SET_(user_defined1) \ + NPU_SET_(user_defined2) \ + NPU_SET_(user_defined3) \ + NPU_SET_(user_defined4) \ + NPU_SET_(user_defined5) \ + NPU_SET_(user_defined6) \ + NPU_SET_(user_defined7) + +#define EXPAND_ACC_FORMAT(FUNC, SEP) FUNC(acc_format, I32) SEP FUNC(acc_format, I40) SEP FUNC(acc_format, F16) + +#define EXPAND_ACTIVATION_CLIP_RANGE(FUNC, SEP) \ + FUNC(activation_clip_range, OFM_PRECISION) \ + SEP FUNC(activation_clip_range, FORCE_UINT8) SEP FUNC(activation_clip_range, FORCE_INT8) \ + SEP FUNC(activation_clip_range, FORCE_INT16) + +#define EXPAND_ACTIVATION_FORMAT(FUNC, SEP) FUNC(activation_format, NHWC) SEP FUNC(activation_format, NHCWB16) + +#define EXPAND_ACTIVATION_FUNCTION(FUNC, SEP) \ + FUNC(activation_function, RELU) \ + SEP FUNC(activation_function, TANH) SEP FUNC(activation_function, SIGMOID) SEP FUNC(activation_function, TABLE_0) \ + SEP FUNC(activation_function, TABLE_1) SEP FUNC(activation_function, TABLE_2) \ + SEP FUNC(activation_function, TABLE_3) SEP FUNC(activation_function, TABLE_4) \ + SEP FUNC(activation_function, TABLE_5) SEP FUNC(activation_function, TABLE_6) \ + SEP FUNC(activation_function, TABLE_7) + +#define EXPAND_ACTIVATION_PRECISION(FUNC, SEP) \ + FUNC(activation_precision, B8) \ + SEP FUNC(activation_precision, B16) SEP FUNC(activation_precision, B32) SEP FUNC(activation_precision, B64) + +#define EXPAND_ACTIVATION_TYPE(FUNC, SEP) FUNC(activation_type, UNSIGNED) SEP FUNC(activation_type, SIGNED) + +#define EXPAND_AXI_MEM_ENCODING(FUNC, SEP) \ + FUNC(axi_mem_encoding, DEVICE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, DEVICE_BUFFERABLE) SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_AND_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_AND_WRITE_ALLOCATE) + +#define EXPAND_BROADCAST_MODE(FUNC, SEP) FUNC(broadcast_mode, DISABLE) SEP FUNC(broadcast_mode, ENABLE) + +#define EXPAND_CMD0_OPCODE(FUNC, SEP) \ + FUNC(cmd0_opcode, NPU_OP_STOP) \ + SEP FUNC(cmd0_opcode, NPU_OP_IRQ) SEP FUNC(cmd0_opcode, NPU_OP_CONV) SEP FUNC( \ + cmd0_opcode, NPU_OP_DEPTHWISE) SEP FUNC(cmd0_opcode, NPU_OP_POOL) SEP FUNC(cmd0_opcode, NPU_OP_ELEMENTWISE) \ + SEP FUNC(cmd0_opcode, NPU_OP_DMA_START) SEP FUNC(cmd0_opcode, NPU_OP_DMA_WAIT) SEP FUNC( \ + cmd0_opcode, NPU_OP_KERNEL_WAIT) SEP FUNC(cmd0_opcode, NPU_OP_PMU_MASK) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PAD_TOP) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_LEFT) SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_RIGHT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_PAD_BOTTOM) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_DEPTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PRECISION) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_UPSCALE) SEP FUNC(cmd0_opcode, NPU_SET_IFM_ZERO_POINT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_WIDTH0_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_IB_END) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_REGION) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_DEPTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_PRECISION) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_BLK_WIDTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_OFM_BLK_HEIGHT_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_BLK_DEPTH_M1) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_ZERO_POINT) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT0_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_OFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_REGION) \ + SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_WIDTH_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_KERNEL_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_STRIDE) \ + SEP FUNC(cmd0_opcode, NPU_SET_ACC_FORMAT) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_ACTIVATION) SEP FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MIN) \ + SEP FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MAX) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_WEIGHT_REGION) SEP FUNC(cmd0_opcode, NPU_SET_SCALE_REGION) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_AB_START) SEP FUNC(cmd0_opcode, NPU_SET_BLOCKDEP) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SRC_REGION) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_DMA0_DST_REGION) SEP FUNC(cmd0_opcode, \ + NPU_SET_DMA0_SIZE0) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_BROADCAST) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM2_SCALAR) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_PRECISION) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM2_ZERO_POINT) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM2_WIDTH0_M1) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT0_M1) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT1_M1) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_IB_START) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM2_REGION) + +#define EXPAND_CMD1_OPCODE(FUNC, SEP) \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE0) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE1) SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE2) SEP FUNC( \ + cmd1_opcode, NPU_SET_IFM_BASE3) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_Y) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_C) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_BASE0) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE1) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE2) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE3) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_STRIDE_X) SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_C) SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT_BASE) SEP FUNC( \ + cmd1_opcode, NPU_SET_WEIGHT_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_SCALE_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_OFM_SCALE) SEP FUNC( \ + cmd1_opcode, NPU_SET_OPA_SCALE) SEP FUNC(cmd1_opcode, NPU_SET_OPB_SCALE) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SRC) SEP FUNC(cmd1_opcode, NPU_SET_DMA0_DST) SEP FUNC( \ + cmd1_opcode, NPU_SET_DMA0_LEN) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE0) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE1) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE2) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE3) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_C) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED0) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED1) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED2) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED3) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED4) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED5) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED6) \ + SEP FUNC(cmd1_opcode, NPU_SET_USER_DEFINED7) + +#define EXPAND_CMD_CTRL(FUNC, SEP) FUNC(cmd_ctrl, CMD0_CTRL) SEP FUNC(cmd_ctrl, CMD1_CTRL) + +#define EXPAND_CUSTOM_DMA_CS(FUNC, SEP) FUNC(custom_dma_cs, DISABLE) SEP FUNC(custom_dma_cs, ENABLE) + +#define EXPAND_CUSTOM_DMA(FUNC, SEP) FUNC(custom_dma, NOT_IMPLEMENTED) SEP FUNC(custom_dma, IMPLEMENTED) + +#define EXPAND_DMA_FAULT_SRC(FUNC, SEP) FUNC(dma_fault_src, AXI_M0) SEP FUNC(dma_fault_src, AXI_M1) + +#define EXPAND_DMA_REGION_MODE(FUNC, SEP) FUNC(dma_region_mode, EXTERNAL) SEP FUNC(dma_region_mode, INTERNAL) + +#define EXPAND_DMA_STRIDE_MODE(FUNC, SEP) FUNC(dma_stride_mode, D1) + +#define EXPAND_ELEMENTWISE_MODE(FUNC, SEP) \ + FUNC(elementwise_mode, MUL) \ + SEP FUNC(elementwise_mode, ADD) SEP FUNC(elementwise_mode, SUB) SEP FUNC(elementwise_mode, MIN) \ + SEP FUNC(elementwise_mode, MAX) SEP FUNC(elementwise_mode, LRELU) SEP FUNC(elementwise_mode, ABS) \ + SEP FUNC(elementwise_mode, CLZ) SEP FUNC(elementwise_mode, SHR) SEP FUNC(elementwise_mode, SHL) + +#define EXPAND_FUNCTIONAL_SAFETY(FUNC, SEP) \ + FUNC(functional_safety, NOT_IMPLEMENTED) SEP FUNC(functional_safety, IMPLEMENTED) + +#define EXPAND_IFM2_OPERAND_ORDER(FUNC, SEP) FUNC(ifm2_operand_order, ORDER_B) SEP FUNC(ifm2_operand_order, ORDER_A) + +#define EXPAND_IFM_SCALE_MODE(FUNC, SEP) \ + FUNC(ifm_scale_mode, OPA_OPB_16) SEP FUNC(ifm_scale_mode, OPA_32) SEP FUNC(ifm_scale_mode, OPB_32) + +#define EXPAND_IFM_UPSCALE_MODE(FUNC, SEP) \ + FUNC(ifm_upscale_mode, NONE) SEP FUNC(ifm_upscale_mode, NEAREST) SEP FUNC(ifm_upscale_mode, ZEROS) + +#define EXPAND_KERNEL_DECOMPOSITION(FUNC, SEP) FUNC(kernel_decomposition, D8X8) SEP FUNC(kernel_decomposition, D4X4) + +#define EXPAND_KERNEL_DILATION(FUNC, SEP) FUNC(kernel_dilation, NONE) SEP FUNC(kernel_dilation, X2) + +#define EXPAND_MAX_BEATS(FUNC, SEP) FUNC(max_beats, B64) SEP FUNC(max_beats, B128) SEP FUNC(max_beats, B256) + +#define EXPAND_MEM_ATTR(FUNC, SEP) \ + FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER0) \ + SEP FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER1) SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER2) \ + SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER3) + +#define EXPAND_OFM_SCALE_MODE(FUNC, SEP) FUNC(ofm_scale_mode, PER_CHANNEL) SEP FUNC(ofm_scale_mode, GLOBAL) + +#define EXPAND_PMU_AXI_CHANNEL(FUNC, SEP) \ + FUNC(pmu_axi_channel, RD_CMD) \ + SEP FUNC(pmu_axi_channel, RD_IFM) SEP FUNC(pmu_axi_channel, RD_WEIGHTS) SEP FUNC(pmu_axi_channel, RD_SCALE_BIAS) \ + SEP FUNC(pmu_axi_channel, RD_MEM2MEM) SEP FUNC(pmu_axi_channel, WR_OFM) SEP FUNC(pmu_axi_channel, WR_MEM2MEM) + +#define EXPAND_PMU_EVENT(FUNC, SEP) \ + FUNC(pmu_event, NO_EVENT) \ + SEP FUNC(pmu_event, CYCLE) SEP FUNC(pmu_event, NPU_IDLE) SEP FUNC(pmu_event, CC_STALLED_ON_BLOCKDEP) SEP FUNC( \ + pmu_event, CC_STALLED_ON_SHRAM_RECONFIG) SEP FUNC(pmu_event, NPU_ACTIVE) SEP FUNC(pmu_event, MAC_ACTIVE) \ + SEP FUNC(pmu_event, MAC_ACTIVE_8BIT) SEP FUNC(pmu_event, MAC_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, MAC_DPU_ACTIVE) SEP FUNC(pmu_event, MAC_STALLED_BY_WD_ACC) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_WD) \ + SEP FUNC(pmu_event, MAC_STALLED_BY_ACC) SEP FUNC(pmu_event, MAC_STALLED_BY_IB) SEP FUNC( \ + pmu_event, \ + MAC_ACTIVE_32BIT) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_W) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_ACC) SEP FUNC(pmu_event, \ + AO_ACTIVE) \ + SEP FUNC(pmu_event, AO_ACTIVE_8BIT) SEP FUNC(pmu_event, AO_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, AO_STALLED_BY_OFMP_OB) SEP FUNC(pmu_event, AO_STALLED_BY_OFMP) SEP \ + FUNC(pmu_event, AO_STALLED_BY_OB) SEP FUNC(pmu_event, AO_STALLED_BY_ACC_IB) SEP FUNC( \ + pmu_event, AO_STALLED_BY_ACC) SEP FUNC(pmu_event, AO_STALLED_BY_IB) SEP \ + FUNC(pmu_event, WD_ACTIVE) SEP FUNC(pmu_event, WD_STALLED) SEP FUNC(pmu_event, WD_STALLED_BY_WS) SEP FUNC( \ + pmu_event, WD_STALLED_BY_WD_BUF) SEP FUNC(pmu_event, \ + WD_PARSE_ACTIVE) SEP \ + FUNC(pmu_event, WD_PARSE_STALLED) SEP FUNC(pmu_event, WD_PARSE_STALLED_IN) SEP FUNC( \ + pmu_event, WD_PARSE_STALLED_OUT) SEP FUNC(pmu_event, \ + WD_TRANS_WS) SEP \ + FUNC(pmu_event, WD_TRANS_WB) SEP FUNC(pmu_event, WD_TRANS_DW0) SEP FUNC( \ + pmu_event, WD_TRANS_DW1) SEP FUNC(pmu_event, \ + AXI0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_RD_TRANS_COMPLETED) SEP FUNC(pmu_event, AXI0_RD_DATA_BEAT_RECEIVED) SEP FUNC( \ + pmu_event, AXI0_RD_TRAN_REQ_STALLED) SEP FUNC(pmu_event, \ + AXI0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, AXI0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_WRITTEN) SEP FUNC( \ + pmu_event, AXI0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_STALLED) SEP FUNC( \ + pmu_event, \ + AXI0_ENABLED_CYCLES) SEP FUNC(pmu_event, \ + AXI0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, AXI0_WR_STALL_LIMIT) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_ANY) SEP FUNC(pmu_event, \ + AXI_LATENCY_32) SEP \ + FUNC(pmu_event, \ + AXI_LATENCY_64) SEP FUNC(pmu_event, \ + AXI_LATENCY_128) SEP \ + FUNC(pmu_event, AXI_LATENCY_256) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_512) SEP FUNC(pmu_event, \ + AXI_LATENCY_1024) SEP \ + FUNC(pmu_event, ECC_DMA) SEP FUNC( \ + pmu_event, \ + ECC_SB0) SEP FUNC(pmu_event, \ + AXI1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_RD_TRANS_COMPLETED) SEP FUNC( \ + pmu_event, AXI1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, AXI1_RD_TRAN_REQ_STALLED) SEP FUNC( \ + pmu_event, AXI1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, \ + AXI1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, \ + AXI1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, \ + AXI1_WR_TRAN_REQ_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_DATA_BEAT_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_ENABLED_CYCLES) SEP \ + FUNC( \ + pmu_event, \ + AXI1_RD_STALL_LIMIT) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_STALL_LIMIT) \ + SEP FUNC( \ + pmu_event, \ + ECC_SB1) + +#define EXPAND_POOLING_MODE(FUNC, SEP) \ + FUNC(pooling_mode, MAX) SEP FUNC(pooling_mode, AVERAGE) SEP FUNC(pooling_mode, REDUCE_SUM) + +#define EXPAND_PRIVILEGE_LEVEL(FUNC, SEP) FUNC(privilege_level, USER) SEP FUNC(privilege_level, PRIVILEGED) + +#define EXPAND_ROUND_MODE(FUNC, SEP) FUNC(round_mode, DBL) SEP FUNC(round_mode, TRUNCATE) SEP FUNC(round_mode, NATURAL) + +#define EXPAND_SECURITY_LEVEL(FUNC, SEP) FUNC(security_level, SECURE) SEP FUNC(security_level, NON_SECURE) + +#define EXPAND_STATE(FUNC, SEP) FUNC(state, STOPPED) SEP FUNC(state, RUNNING) + +#define EXPAND_WD_CORE_SLICE_STATE(FUNC, SEP) \ + FUNC(wd_core_slice_state, HEADER) SEP FUNC(wd_core_slice_state, PALETTE) SEP FUNC(wd_core_slice_state, WEIGHTS) + +#define EXPAND_WD_CTRL_STATE(FUNC, SEP) \ + FUNC(wd_ctrl_state, IDLE) \ + SEP FUNC(wd_ctrl_state, DRAIN) SEP FUNC(wd_ctrl_state, OFD_INIT) SEP FUNC(wd_ctrl_state, OFD_RUN) + +#define EXPAND_WEIGHT_ORDER(FUNC, SEP) FUNC(weight_order, DEPTH_FIRST) SEP FUNC(weight_order, PART_KERNEL_FIRST) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h new file mode 100644 index 0000000..c4e3d2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu65_interface.h @@ -0,0 +1,26060 @@ +/* + * Copyright (c) 2020-2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU65_INTERFACE_H +#define ETHOSU65_INTERFACE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#if !defined(__cplusplus) || __cplusplus < 201402L +#define CONSTEXPR +#else +#define CONSTEXPR constexpr +#endif + +#ifndef __cplusplus +#define STRUCT struct +#else +#define STRUCT +#endif + +#if defined(__cplusplus) && defined(NPU_DISASSEMBLE) +#include +#include +#include +#endif + +#if defined(__cplusplus) && !defined(NPU_NAMESPACE) +#define NPU_NAMESPACE npu +#endif + +#ifdef __cplusplus +#include +#include +#endif + +#ifdef __cplusplus +namespace NPU_NAMESPACE +{ +#endif +#define NNX_ARCH_VERSION_MAJOR 1 +#define NNX_ARCH_VERSION_MINOR 0 +#define NNX_ARCH_VERSION_PATCH 6 + +// Register offsets +// +// Register subpage BASE +// +#define NPU_REG_ID 0x0000 +#define NPU_REG_STATUS 0x0004 +#define NPU_REG_CMD 0x0008 +#define NPU_REG_RESET 0x000C +#define NPU_REG_QBASE 0x0010 +#define NPU_REG_QBASE_HI 0x0014 +#define NPU_REG_QREAD 0x0018 +#define NPU_REG_QCONFIG 0x001C +#define NPU_REG_QSIZE 0x0020 +#define NPU_REG_PROT 0x0024 +#define NPU_REG_CONFIG 0x0028 +#define NPU_REG_LOCK 0x002C +#define NPU_REG_REGIONCFG 0x003C +#define NPU_REG_AXI_LIMIT0 0x0040 +#define NPU_REG_AXI_LIMIT1 0x0044 +#define NPU_REG_AXI_LIMIT2 0x0048 +#define NPU_REG_AXI_LIMIT3 0x004C +#define BASE_REGISTERS_SIZE 0x0080 + +// +// Register subpage BASE_POINTERS +// +#define NPU_REG_BASEP_BASE 0x0080 +#define NPU_REG_BASEP_ARRLEN 0x0008 +#define BASE_POINTERS_REGISTERS_SIZE 0x0100 + +// +// Register subpage DEBUG +// +#define NPU_REG_WD_STATUS 0x0100 +#define NPU_REG_MAC_STATUS 0x0104 +#define NPU_REG_AO_STATUS 0x0108 +#define NPU_REG_DMA_STATUS0 0x0110 +#define NPU_REG_DMA_STATUS1 0x0114 +#define NPU_REG_CLKFORCE 0x0140 +#define NPU_REG_DEBUG_ADDRESS 0x0144 +#define NPU_REG_DEBUG_MISC 0x0148 +#define NPU_REG_DEBUGCORE 0x014C +#define NPU_REG_DEBUG_BLOCK 0x0150 +#define DEBUG_REGISTERS_SIZE 0x0180 + +// +// Register subpage PMU +// +#define NPU_REG_PMCR 0x0180 +#define NPU_REG_PMCNTENSET 0x0184 +#define NPU_REG_PMCNTENCLR 0x0188 +#define NPU_REG_PMOVSSET 0x018C +#define NPU_REG_PMOVSCLR 0x0190 +#define NPU_REG_PMINTSET 0x0194 +#define NPU_REG_PMINTCLR 0x0198 +#define NPU_REG_PMCCNTR 0x01A0 +#define NPU_REG_PMCCNTR_HI 0x01A4 +#define NPU_REG_PMCCNTR_CFG 0x01A8 +#define NPU_REG_PMCAXI_CHAN 0x01AC +#define PMU_REGISTERS_SIZE 0x0200 + +// +// Register subpage TSU_DEBUG +// +#define NPU_REG_KERNEL_X 0x0200 +#define NPU_REG_KERNEL_Y 0x0204 +#define NPU_REG_KERNEL_W_M1 0x0208 +#define NPU_REG_KERNEL_H_M1 0x020C +#define NPU_REG_OFM_CBLK_WIDTH_M1 0x0210 +#define NPU_REG_OFM_CBLK_HEIGHT_M1 0x0214 +#define NPU_REG_OFM_CBLK_DEPTH_M1 0x0218 +#define NPU_REG_IFM_CBLK_DEPTH_M1 0x021C +#define NPU_REG_OFM_X 0x0220 +#define NPU_REG_OFM_Y 0x0224 +#define NPU_REG_OFM_Z 0x0228 +#define NPU_REG_IFM_Z 0x022C +#define NPU_REG_PAD_TOP 0x0230 +#define NPU_REG_PAD_LEFT 0x0234 +#define NPU_REG_IFM_CBLK_WIDTH 0x0238 +#define NPU_REG_IFM_CBLK_HEIGHT 0x023C +#define NPU_REG_DMA_IFM_SRC 0x0240 +#define NPU_REG_DMA_IFM_SRC_HI 0x0244 +#define NPU_REG_DMA_IFM_DST 0x0248 +#define NPU_REG_DMA_OFM_SRC 0x024C +#define NPU_REG_DMA_OFM_DST 0x0250 +#define NPU_REG_DMA_OFM_DST_HI 0x0254 +#define NPU_REG_DMA_WEIGHT_SRC 0x0258 +#define NPU_REG_DMA_WEIGHT_SRC_HI 0x025C +#define NPU_REG_DMA_CMD_SRC 0x0260 +#define NPU_REG_DMA_CMD_SRC_HI 0x0264 +#define NPU_REG_DMA_CMD_SIZE 0x0268 +#define NPU_REG_DMA_M2M_SRC 0x026C +#define NPU_REG_DMA_M2M_SRC_HI 0x0270 +#define NPU_REG_DMA_M2M_DST 0x0274 +#define NPU_REG_DMA_M2M_DST_HI 0x0278 +#define NPU_REG_CURRENT_QREAD 0x027C +#define NPU_REG_DMA_SCALE_SRC 0x0280 +#define NPU_REG_DMA_SCALE_SRC_HI 0x0284 +#define NPU_REG_CURRENT_BLOCK 0x02B4 +#define NPU_REG_CURRENT_OP 0x02B8 +#define NPU_REG_CURRENT_CMD 0x02BC +#define TSU_DEBUG_REGISTERS_SIZE 0x02C0 + +// +// Register subpage PMU_COUNTERS +// +#define NPU_REG_PMEVCNTR_BASE 0x0300 +#define NPU_REG_PMEVCNTR_ARRLEN 0x0004 +#define NPU_REG_PMEVTYPER_BASE 0x0380 +#define NPU_REG_PMEVTYPER_ARRLEN 0x0004 +#define PMU_COUNTERS_REGISTERS_SIZE 0x0400 + +// +// Register subpage SHARED_BUFFER +// +#define NPU_REG_SHARED_BUFFER_BASE 0x0400 +#define NPU_REG_SHARED_BUFFER_ARRLEN 0x0100 +#define SHARED_BUFFER_REGISTERS_SIZE 0x0800 + +// +// Register subpage TSU_IFM +// +#define NPU_REG_IFM_PAD_TOP 0x0800 +#define NPU_REG_IFM_PAD_LEFT 0x0804 +#define NPU_REG_IFM_PAD_RIGHT 0x0808 +#define NPU_REG_IFM_PAD_BOTTOM 0x080C +#define NPU_REG_IFM_DEPTH_M1 0x0810 +#define NPU_REG_IFM_PRECISION 0x0814 +#define NPU_REG_IFM_UPSCALE 0x081C +#define NPU_REG_IFM_ZERO_POINT 0x0824 +#define NPU_REG_IFM_WIDTH0_M1 0x0828 +#define NPU_REG_IFM_HEIGHT0_M1 0x082C +#define NPU_REG_IFM_HEIGHT1_M1 0x0830 +#define NPU_REG_IFM_IB_END 0x0834 +#define NPU_REG_IFM_REGION 0x083C +#define TSU_IFM_REGISTERS_SIZE 0x0840 + +// +// Register subpage TSU_OFM +// +#define NPU_REG_OFM_WIDTH_M1 0x0844 +#define NPU_REG_OFM_HEIGHT_M1 0x0848 +#define NPU_REG_OFM_DEPTH_M1 0x084C +#define NPU_REG_OFM_PRECISION 0x0850 +#define NPU_REG_OFM_BLK_WIDTH_M1 0x0854 +#define NPU_REG_OFM_BLK_HEIGHT_M1 0x0858 +#define NPU_REG_OFM_BLK_DEPTH_M1 0x085C +#define NPU_REG_OFM_ZERO_POINT 0x0860 +#define NPU_REG_OFM_WIDTH0_M1 0x0868 +#define NPU_REG_OFM_HEIGHT0_M1 0x086C +#define NPU_REG_OFM_HEIGHT1_M1 0x0870 +#define NPU_REG_OFM_REGION 0x087C +#define TSU_OFM_REGISTERS_SIZE 0x0880 + +// +// Register subpage TSU_KERNEL +// +#define NPU_REG_KERNEL_WIDTH_M1 0x0880 +#define NPU_REG_KERNEL_HEIGHT_M1 0x0884 +#define NPU_REG_KERNEL_STRIDE 0x0888 +#define NPU_REG_PARALLEL_MODE 0x088C +#define NPU_REG_ACC_FORMAT 0x0890 +#define NPU_REG_ACTIVATION 0x0894 +#define NPU_REG_ACTIVATION_MIN 0x0898 +#define NPU_REG_ACTIVATION_MAX 0x089C +#define NPU_REG_WEIGHT_REGION 0x08A0 +#define NPU_REG_SCALE_REGION 0x08A4 +#define NPU_REG_AB_START 0x08B4 +#define NPU_REG_BLOCKDEP 0x08BC +#define TSU_KERNEL_REGISTERS_SIZE 0x08C0 + +// +// Register subpage TSU_DMA +// +#define NPU_REG_DMA0_SRC_REGION 0x08C0 +#define NPU_REG_DMA0_DST_REGION 0x08C4 +#define NPU_REG_DMA0_SIZE0 0x08C8 +#define NPU_REG_DMA0_SIZE1 0x08CC +#define TSU_DMA_REGISTERS_SIZE 0x0900 + +// +// Register subpage TSU_IFM2 +// +#define NPU_REG_IFM2_BROADCAST 0x0900 +#define NPU_REG_IFM2_SCALAR 0x0904 +#define NPU_REG_IFM2_PRECISION 0x0914 +#define NPU_REG_IFM2_ZERO_POINT 0x0924 +#define NPU_REG_IFM2_WIDTH0_M1 0x0928 +#define NPU_REG_IFM2_HEIGHT0_M1 0x092C +#define NPU_REG_IFM2_HEIGHT1_M1 0x0930 +#define NPU_REG_IFM2_IB_START 0x0934 +#define NPU_REG_IFM2_REGION 0x093C +#define TSU_IFM2_REGISTERS_SIZE 0x0940 + +// +// Register subpage TSU_IFM_BASE +// +#define NPU_REG_IFM_BASE0 0x0A00 +#define NPU_REG_IFM_BASE0_HI 0x0A04 +#define NPU_REG_IFM_BASE1 0x0A08 +#define NPU_REG_IFM_BASE1_HI 0x0A0C +#define NPU_REG_IFM_BASE2 0x0A10 +#define NPU_REG_IFM_BASE2_HI 0x0A14 +#define NPU_REG_IFM_BASE3 0x0A18 +#define NPU_REG_IFM_BASE3_HI 0x0A1C +#define NPU_REG_IFM_STRIDE_X 0x0A20 +#define NPU_REG_IFM_STRIDE_X_HI 0x0A24 +#define NPU_REG_IFM_STRIDE_Y 0x0A28 +#define NPU_REG_IFM_STRIDE_Y_HI 0x0A2C +#define NPU_REG_IFM_STRIDE_C 0x0A30 +#define NPU_REG_IFM_STRIDE_C_HI 0x0A34 +#define TSU_IFM_BASE_REGISTERS_SIZE 0x0A40 + +// +// Register subpage TSU_OFM_BASE +// +#define NPU_REG_OFM_BASE0 0x0A40 +#define NPU_REG_OFM_BASE0_HI 0x0A44 +#define NPU_REG_OFM_BASE1 0x0A48 +#define NPU_REG_OFM_BASE1_HI 0x0A4C +#define NPU_REG_OFM_BASE2 0x0A50 +#define NPU_REG_OFM_BASE2_HI 0x0A54 +#define NPU_REG_OFM_BASE3 0x0A58 +#define NPU_REG_OFM_BASE3_HI 0x0A5C +#define NPU_REG_OFM_STRIDE_X 0x0A60 +#define NPU_REG_OFM_STRIDE_X_HI 0x0A64 +#define NPU_REG_OFM_STRIDE_Y 0x0A68 +#define NPU_REG_OFM_STRIDE_Y_HI 0x0A6C +#define NPU_REG_OFM_STRIDE_C 0x0A70 +#define NPU_REG_OFM_STRIDE_C_HI 0x0A74 +#define TSU_OFM_BASE_REGISTERS_SIZE 0x0A80 + +// +// Register subpage TSU_WS_BASE +// +#define NPU_REG_WEIGHT_BASE 0x0A80 +#define NPU_REG_WEIGHT_BASE_HI 0x0A84 +#define NPU_REG_WEIGHT_LENGTH 0x0A88 +#define NPU_REG_WEIGHT_LENGTH_HI 0x0A8C +#define NPU_REG_SCALE_BASE 0x0A90 +#define NPU_REG_SCALE_BASE_HI 0x0A94 +#define NPU_REG_SCALE_LENGTH 0x0A98 +#define NPU_REG_SCALE_LENGTH_HI 0x0A9C +#define NPU_REG_OFM_SCALE 0x0AA0 +#define NPU_REG_OFM_SCALE_SHIFT 0x0AA4 +#define NPU_REG_OPA_SCALE 0x0AA8 +#define NPU_REG_OPA_SCALE_SHIFT 0x0AAC +#define NPU_REG_OPB_SCALE 0x0AB0 +#define TSU_WS_BASE_REGISTERS_SIZE 0x0AC0 + +// +// Register subpage TSU_DMA_BASE +// +#define NPU_REG_DMA0_SRC 0x0AC0 +#define NPU_REG_DMA0_SRC_HI 0x0AC4 +#define NPU_REG_DMA0_DST 0x0AC8 +#define NPU_REG_DMA0_DST_HI 0x0ACC +#define NPU_REG_DMA0_LEN 0x0AD0 +#define NPU_REG_DMA0_LEN_HI 0x0AD4 +#define NPU_REG_DMA0_SKIP0 0x0AD8 +#define NPU_REG_DMA0_SKIP0_HI 0x0ADC +#define NPU_REG_DMA0_SKIP1 0x0AE0 +#define NPU_REG_DMA0_SKIP1_HI 0x0AE4 +#define TSU_DMA_BASE_REGISTERS_SIZE 0x0B00 + +// +// Register subpage TSU_IFM2_BASE +// +#define NPU_REG_IFM2_BASE0 0x0B00 +#define NPU_REG_IFM2_BASE0_HI 0x0B04 +#define NPU_REG_IFM2_BASE1 0x0B08 +#define NPU_REG_IFM2_BASE1_HI 0x0B0C +#define NPU_REG_IFM2_BASE2 0x0B10 +#define NPU_REG_IFM2_BASE2_HI 0x0B14 +#define NPU_REG_IFM2_BASE3 0x0B18 +#define NPU_REG_IFM2_BASE3_HI 0x0B1C +#define NPU_REG_IFM2_STRIDE_X 0x0B20 +#define NPU_REG_IFM2_STRIDE_X_HI 0x0B24 +#define NPU_REG_IFM2_STRIDE_Y 0x0B28 +#define NPU_REG_IFM2_STRIDE_Y_HI 0x0B2C +#define NPU_REG_IFM2_STRIDE_C 0x0B30 +#define NPU_REG_IFM2_STRIDE_C_HI 0x0B34 +#define TSU_IFM2_BASE_REGISTERS_SIZE 0x0B40 + +// +// Register subpage TSU_WS1_BASE +// +#define NPU_REG_WEIGHT1_BASE 0x0B40 +#define NPU_REG_WEIGHT1_BASE_HI 0x0B44 +#define NPU_REG_WEIGHT1_LENGTH 0x0B48 +#define NPU_REG_WEIGHT1_LENGTH_HI 0x0B4C +#define NPU_REG_SCALE1_BASE 0x0B50 +#define NPU_REG_SCALE1_BASE_HI 0x0B54 +#define NPU_REG_SCALE1_LENGTH 0x0B58 +#define NPU_REG_SCALE1_LENGTH_HI 0x0B5C +#define TSU_WS1_BASE_REGISTERS_SIZE 0x0B80 + +// +// Register subpage TSU_USER_BASE +// +#define TSU_USER_BASE_REGISTERS_SIZE 0x0BC0 + +// +// Register subpage TSU_DMA_EBASE +// +#define TSU_DMA_EBASE_REGISTERS_SIZE 0x0C00 + +// +// Register subpage ID +// +#define NPU_REG_REVISION 0x0FC0 +#define NPU_REG_PID4 0x0FD0 +#define NPU_REG_PID5 0x0FD4 +#define NPU_REG_PID6 0x0FD8 +#define NPU_REG_PID7 0x0FDC +#define NPU_REG_PID0 0x0FE0 +#define NPU_REG_PID1 0x0FE4 +#define NPU_REG_PID2 0x0FE8 +#define NPU_REG_PID3 0x0FEC +#define NPU_REG_CID0 0x0FF0 +#define NPU_REG_CID1 0x0FF4 +#define NPU_REG_CID2 0x0FF8 +#define NPU_REG_CID3 0x0FFC +#define ID_REGISTERS_SIZE 0x1000 + +#ifdef __cplusplus +// Enum types +enum class acc_format : uint8_t +{ + I32 = 0, + I40 = 1, + F16 = 2, +}; + +enum class activation_clip_range : uint8_t +{ + OFM_PRECISION = 0, + FORCE_UINT8 = 2, + FORCE_INT8 = 3, + FORCE_INT16 = 5, +}; + +enum class activation_format : uint8_t +{ + NHWC = 0, + NHCWB16 = 1, +}; + +enum class activation_function : uint8_t +{ + RELU = 0, + TANH = 3, + SIGMOID = 4, + TABLE_0 = 16, + TABLE_1 = 17, + TABLE_2 = 18, + TABLE_3 = 19, + TABLE_4 = 20, + TABLE_5 = 21, + TABLE_6 = 22, + TABLE_7 = 23, +}; + +enum class activation_precision : uint8_t +{ + B8 = 0, + B16 = 1, + B32 = 2, + B64 = 3, +}; + +enum class activation_type : uint8_t +{ + UNSIGNED = 0, + SIGNED = 1, +}; + +enum class axi_mem_encoding : uint8_t +{ + DEVICE_NON_BUFFERABLE = 0, + DEVICE_BUFFERABLE = 1, + NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + WRITE_THROUGH_NO_ALLOCATE = 4, + WRITE_THROUGH_READ_ALLOCATE = 5, + WRITE_THROUGH_WRITE_ALLOCATE = 6, + WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + WRITE_BACK_NO_ALLOCATE = 8, + WRITE_BACK_READ_ALLOCATE = 9, + WRITE_BACK_WRITE_ALLOCATE = 10, + WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum class broadcast_mode : uint8_t +{ + DISABLE = 0, + ENABLE = 1, +}; + +enum class cmd0_opcode : uint16_t +{ + NPU_OP_STOP = 0, + NPU_OP_IRQ = 1, + NPU_OP_CONV = 2, + NPU_OP_DEPTHWISE = 3, + NPU_OP_POOL = 5, + NPU_OP_ELEMENTWISE = 6, + NPU_OP_DMA_START = 16, + NPU_OP_DMA_WAIT = 17, + NPU_OP_KERNEL_WAIT = 18, + NPU_OP_PMU_MASK = 19, + NPU_SET_IFM_PAD_TOP = 256, + NPU_SET_IFM_PAD_LEFT = 257, + NPU_SET_IFM_PAD_RIGHT = 258, + NPU_SET_IFM_PAD_BOTTOM = 259, + NPU_SET_IFM_DEPTH_M1 = 260, + NPU_SET_IFM_PRECISION = 261, + NPU_SET_IFM_UPSCALE = 263, + NPU_SET_IFM_ZERO_POINT = 265, + NPU_SET_IFM_WIDTH0_M1 = 266, + NPU_SET_IFM_HEIGHT0_M1 = 267, + NPU_SET_IFM_HEIGHT1_M1 = 268, + NPU_SET_IFM_IB_END = 269, + NPU_SET_IFM_REGION = 271, + NPU_SET_OFM_WIDTH_M1 = 273, + NPU_SET_OFM_HEIGHT_M1 = 274, + NPU_SET_OFM_DEPTH_M1 = 275, + NPU_SET_OFM_PRECISION = 276, + NPU_SET_OFM_BLK_WIDTH_M1 = 277, + NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + NPU_SET_OFM_BLK_DEPTH_M1 = 279, + NPU_SET_OFM_ZERO_POINT = 280, + NPU_SET_OFM_WIDTH0_M1 = 282, + NPU_SET_OFM_HEIGHT0_M1 = 283, + NPU_SET_OFM_HEIGHT1_M1 = 284, + NPU_SET_OFM_REGION = 287, + NPU_SET_KERNEL_WIDTH_M1 = 288, + NPU_SET_KERNEL_HEIGHT_M1 = 289, + NPU_SET_KERNEL_STRIDE = 290, + NPU_SET_PARALLEL_MODE = 291, + NPU_SET_ACC_FORMAT = 292, + NPU_SET_ACTIVATION = 293, + NPU_SET_ACTIVATION_MIN = 294, + NPU_SET_ACTIVATION_MAX = 295, + NPU_SET_WEIGHT_REGION = 296, + NPU_SET_SCALE_REGION = 297, + NPU_SET_AB_START = 301, + NPU_SET_BLOCKDEP = 303, + NPU_SET_DMA0_SRC_REGION = 304, + NPU_SET_DMA0_DST_REGION = 305, + NPU_SET_DMA0_SIZE0 = 306, + NPU_SET_DMA0_SIZE1 = 307, + NPU_SET_IFM2_BROADCAST = 384, + NPU_SET_IFM2_SCALAR = 385, + NPU_SET_IFM2_PRECISION = 389, + NPU_SET_IFM2_ZERO_POINT = 393, + NPU_SET_IFM2_WIDTH0_M1 = 394, + NPU_SET_IFM2_HEIGHT0_M1 = 395, + NPU_SET_IFM2_HEIGHT1_M1 = 396, + NPU_SET_IFM2_IB_START = 397, + NPU_SET_IFM2_REGION = 399, +}; + +enum class cmd1_opcode : uint16_t +{ + NPU_SET_IFM_BASE0 = 0, + NPU_SET_IFM_BASE1 = 1, + NPU_SET_IFM_BASE2 = 2, + NPU_SET_IFM_BASE3 = 3, + NPU_SET_IFM_STRIDE_X = 4, + NPU_SET_IFM_STRIDE_Y = 5, + NPU_SET_IFM_STRIDE_C = 6, + NPU_SET_OFM_BASE0 = 16, + NPU_SET_OFM_BASE1 = 17, + NPU_SET_OFM_BASE2 = 18, + NPU_SET_OFM_BASE3 = 19, + NPU_SET_OFM_STRIDE_X = 20, + NPU_SET_OFM_STRIDE_Y = 21, + NPU_SET_OFM_STRIDE_C = 22, + NPU_SET_WEIGHT_BASE = 32, + NPU_SET_WEIGHT_LENGTH = 33, + NPU_SET_SCALE_BASE = 34, + NPU_SET_SCALE_LENGTH = 35, + NPU_SET_OFM_SCALE = 36, + NPU_SET_OPA_SCALE = 37, + NPU_SET_OPB_SCALE = 38, + NPU_SET_DMA0_SRC = 48, + NPU_SET_DMA0_DST = 49, + NPU_SET_DMA0_LEN = 50, + NPU_SET_DMA0_SKIP0 = 51, + NPU_SET_DMA0_SKIP1 = 52, + NPU_SET_IFM2_BASE0 = 128, + NPU_SET_IFM2_BASE1 = 129, + NPU_SET_IFM2_BASE2 = 130, + NPU_SET_IFM2_BASE3 = 131, + NPU_SET_IFM2_STRIDE_X = 132, + NPU_SET_IFM2_STRIDE_Y = 133, + NPU_SET_IFM2_STRIDE_C = 134, + NPU_SET_WEIGHT1_BASE = 144, + NPU_SET_WEIGHT1_LENGTH = 145, + NPU_SET_SCALE1_BASE = 146, + NPU_SET_SCALE1_LENGTH = 147, +}; + +enum class cmd_ctrl : uint8_t +{ + CMD0_CTRL = 0, + CMD1_CTRL = 1, +}; + +enum class custom_dma : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class dma_fault_src : uint8_t +{ + AXI_M0 = 0, + AXI_M1 = 1, +}; + +enum class dma_region_mode : uint8_t +{ + EXTERNAL = 0, + INTERNAL = 1, +}; + +enum class dma_stride_mode : uint8_t +{ + D1 = 0, + D2 = 1, + D3 = 2, +}; + +enum class elementwise_mode : uint8_t +{ + MUL = 0, + ADD = 1, + SUB = 2, + MIN = 3, + MAX = 4, + LRELU = 5, + ABS = 6, + CLZ = 7, + SHR = 8, + SHL = 9, +}; + +enum class functional_safety : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class ifm2_operand_order : uint8_t +{ + ORDER_B = 0, + ORDER_A = 1, +}; + +enum class ifm_scale_mode : uint8_t +{ + OPA_OPB_16 = 0, + OPA_32 = 1, + OPB_32 = 2, +}; + +enum class ifm_upscale_mode : uint8_t +{ + NONE = 0, + NEAREST = 1, + ZEROS = 2, +}; + +enum class kernel_decomposition : uint8_t +{ + D8X8 = 0, + D4X4 = 1, +}; + +enum class kernel_dilation : uint8_t +{ + NONE = 0, + X2 = 1, +}; + +enum class max_beats : uint8_t +{ + B64 = 0, + B128 = 1, + B256 = 2, +}; + +enum class mem_attr : uint8_t +{ + AXI0_OUTSTANDING_COUNTER0 = 0, + AXI0_OUTSTANDING_COUNTER1 = 1, + AXI1_OUTSTANDING_COUNTER2 = 2, + AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum class ofm_scale_mode : uint8_t +{ + PER_CHANNEL = 0, + GLOBAL = 1, +}; + +enum class parallel_mode : uint8_t +{ + SINGLE_CORE = 0, + DUAL_CORE_DEPTH = 1, +}; + +enum class pmu_axi_channel : uint8_t +{ + RD_CMD = 0, + RD_IFM = 1, + RD_WEIGHTS = 2, + RD_SCALE_BIAS = 3, + RD_MEM2MEM = 4, + WR_OFM = 8, + WR_MEM2MEM = 9, +}; + +enum class pmu_event : uint16_t +{ + NO_EVENT = 0, + CYCLE = 17, + NPU_IDLE = 32, + CC_STALLED_ON_BLOCKDEP = 33, + CC_STALLED_ON_SHRAM_RECONFIG = 34, + NPU_ACTIVE = 35, + MAC_ACTIVE = 48, + MAC_ACTIVE_8BIT = 49, + MAC_ACTIVE_16BIT = 50, + MAC_DPU_ACTIVE = 51, + MAC_STALLED_BY_WD_ACC = 52, + MAC_STALLED_BY_WD = 53, + MAC_STALLED_BY_ACC = 54, + MAC_STALLED_BY_IB = 55, + MAC_ACTIVE_32BIT = 56, + MAC_STALLED_BY_INT_W = 57, + MAC_STALLED_BY_INT_ACC = 58, + AO_ACTIVE = 64, + AO_ACTIVE_8BIT = 65, + AO_ACTIVE_16BIT = 66, + AO_STALLED_BY_OFMP_OB = 67, + AO_STALLED_BY_OFMP = 68, + AO_STALLED_BY_OB = 69, + AO_STALLED_BY_ACC_IB = 70, + AO_STALLED_BY_ACC = 71, + AO_STALLED_BY_IB = 72, + WD_ACTIVE = 80, + WD_STALLED = 81, + WD_STALLED_BY_WS = 82, + WD_STALLED_BY_WD_BUF = 83, + WD_PARSE_ACTIVE = 84, + WD_PARSE_STALLED = 85, + WD_PARSE_STALLED_IN = 86, + WD_PARSE_STALLED_OUT = 87, + WD_TRANS_WS = 88, + WD_TRANS_WB = 89, + WD_TRANS_DW0 = 90, + WD_TRANS_DW1 = 91, + AXI0_RD_TRANS_ACCEPTED = 128, + AXI0_RD_TRANS_COMPLETED = 129, + AXI0_RD_DATA_BEAT_RECEIVED = 130, + AXI0_RD_TRAN_REQ_STALLED = 131, + AXI0_WR_TRANS_ACCEPTED = 132, + AXI0_WR_TRANS_COMPLETED_M = 133, + AXI0_WR_TRANS_COMPLETED_S = 134, + AXI0_WR_DATA_BEAT_WRITTEN = 135, + AXI0_WR_TRAN_REQ_STALLED = 136, + AXI0_WR_DATA_BEAT_STALLED = 137, + AXI0_ENABLED_CYCLES = 140, + AXI0_RD_STALL_LIMIT = 142, + AXI0_WR_STALL_LIMIT = 143, + AXI_LATENCY_ANY = 160, + AXI_LATENCY_32 = 161, + AXI_LATENCY_64 = 162, + AXI_LATENCY_128 = 163, + AXI_LATENCY_256 = 164, + AXI_LATENCY_512 = 165, + AXI_LATENCY_1024 = 166, + ECC_DMA = 176, + ECC_SB0 = 177, + AXI1_RD_TRANS_ACCEPTED = 384, + AXI1_RD_TRANS_COMPLETED = 385, + AXI1_RD_DATA_BEAT_RECEIVED = 386, + AXI1_RD_TRAN_REQ_STALLED = 387, + AXI1_WR_TRANS_ACCEPTED = 388, + AXI1_WR_TRANS_COMPLETED_M = 389, + AXI1_WR_TRANS_COMPLETED_S = 390, + AXI1_WR_DATA_BEAT_WRITTEN = 391, + AXI1_WR_TRAN_REQ_STALLED = 392, + AXI1_WR_DATA_BEAT_STALLED = 393, + AXI1_ENABLED_CYCLES = 396, + AXI1_RD_STALL_LIMIT = 398, + AXI1_WR_STALL_LIMIT = 399, + ECC_SB1 = 433, +}; + +enum class pooling_mode : uint8_t +{ + MAX = 0, + AVERAGE = 1, + REDUCE_SUM = 2, +}; + +enum class privilege_level : uint8_t +{ + USER = 0, + PRIVILEGED = 1, +}; + +enum class round_mode : uint8_t +{ + DBL = 0, + TRUNCATE = 1, + NATURAL = 2, +}; + +enum class security_level : uint8_t +{ + SECURE = 0, + NON_SECURE = 1, +}; + +enum class state : uint8_t +{ + STOPPED = 0, + RUNNING = 1, +}; + +enum class wd_core_slice_state : uint8_t +{ + HEADER = 0, + PALETTE = 1, + WEIGHTS = 2, +}; + +enum class wd_ctrl_state : uint8_t +{ + IDLE = 0, + DRAIN = 1, + OFD_INIT = 2, + OFD_RUN = 3, +}; + +enum class weight_order : uint8_t +{ + DEPTH_FIRST = 0, + PART_KERNEL_FIRST = 1, +}; + +#else + +enum acc_format +{ + ACC_FORMAT_I32 = 0, + ACC_FORMAT_I40 = 1, + ACC_FORMAT_F16 = 2, +}; + +enum activation_clip_range +{ + ACTIVATION_CLIP_RANGE_OFM_PRECISION = 0, + ACTIVATION_CLIP_RANGE_FORCE_UINT8 = 2, + ACTIVATION_CLIP_RANGE_FORCE_INT8 = 3, + ACTIVATION_CLIP_RANGE_FORCE_INT16 = 5, +}; + +enum activation_format +{ + ACTIVATION_FORMAT_NHWC = 0, + ACTIVATION_FORMAT_NHCWB16 = 1, +}; + +enum activation_function +{ + ACTIVATION_FUNCTION_RELU = 0, + ACTIVATION_FUNCTION_TANH = 3, + ACTIVATION_FUNCTION_SIGMOID = 4, + ACTIVATION_FUNCTION_TABLE_0 = 16, + ACTIVATION_FUNCTION_TABLE_1 = 17, + ACTIVATION_FUNCTION_TABLE_2 = 18, + ACTIVATION_FUNCTION_TABLE_3 = 19, + ACTIVATION_FUNCTION_TABLE_4 = 20, + ACTIVATION_FUNCTION_TABLE_5 = 21, + ACTIVATION_FUNCTION_TABLE_6 = 22, + ACTIVATION_FUNCTION_TABLE_7 = 23, +}; + +enum activation_precision +{ + ACTIVATION_PRECISION_B8 = 0, + ACTIVATION_PRECISION_B16 = 1, + ACTIVATION_PRECISION_B32 = 2, + ACTIVATION_PRECISION_B64 = 3, +}; + +enum activation_type +{ + ACTIVATION_TYPE_UNSIGNED = 0, + ACTIVATION_TYPE_SIGNED = 1, +}; + +enum axi_mem_encoding +{ + AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE = 0, + AXI_MEM_ENCODING_DEVICE_BUFFERABLE = 1, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE = 4, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE = 5, + AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE = 6, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE = 8, + AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE = 9, + AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE = 10, + AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum broadcast_mode +{ + BROADCAST_MODE_DISABLE = 0, + BROADCAST_MODE_ENABLE = 1, +}; + +enum cmd0_opcode +{ + CMD0_OPCODE_NPU_OP_STOP = 0, + CMD0_OPCODE_NPU_OP_IRQ = 1, + CMD0_OPCODE_NPU_OP_CONV = 2, + CMD0_OPCODE_NPU_OP_DEPTHWISE = 3, + CMD0_OPCODE_NPU_OP_POOL = 5, + CMD0_OPCODE_NPU_OP_ELEMENTWISE = 6, + CMD0_OPCODE_NPU_OP_DMA_START = 16, + CMD0_OPCODE_NPU_OP_DMA_WAIT = 17, + CMD0_OPCODE_NPU_OP_KERNEL_WAIT = 18, + CMD0_OPCODE_NPU_OP_PMU_MASK = 19, + CMD0_OPCODE_NPU_SET_IFM_PAD_TOP = 256, + CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT = 257, + CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT = 258, + CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM = 259, + CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1 = 260, + CMD0_OPCODE_NPU_SET_IFM_PRECISION = 261, + CMD0_OPCODE_NPU_SET_IFM_UPSCALE = 263, + CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT = 265, + CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1 = 266, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1 = 267, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1 = 268, + CMD0_OPCODE_NPU_SET_IFM_IB_END = 269, + CMD0_OPCODE_NPU_SET_IFM_REGION = 271, + CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1 = 273, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1 = 274, + CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1 = 275, + CMD0_OPCODE_NPU_SET_OFM_PRECISION = 276, + CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1 = 277, + CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1 = 279, + CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT = 280, + CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1 = 282, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1 = 283, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1 = 284, + CMD0_OPCODE_NPU_SET_OFM_REGION = 287, + CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1 = 288, + CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1 = 289, + CMD0_OPCODE_NPU_SET_KERNEL_STRIDE = 290, + CMD0_OPCODE_NPU_SET_PARALLEL_MODE = 291, + CMD0_OPCODE_NPU_SET_ACC_FORMAT = 292, + CMD0_OPCODE_NPU_SET_ACTIVATION = 293, + CMD0_OPCODE_NPU_SET_ACTIVATION_MIN = 294, + CMD0_OPCODE_NPU_SET_ACTIVATION_MAX = 295, + CMD0_OPCODE_NPU_SET_WEIGHT_REGION = 296, + CMD0_OPCODE_NPU_SET_SCALE_REGION = 297, + CMD0_OPCODE_NPU_SET_AB_START = 301, + CMD0_OPCODE_NPU_SET_BLOCKDEP = 303, + CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION = 304, + CMD0_OPCODE_NPU_SET_DMA0_DST_REGION = 305, + CMD0_OPCODE_NPU_SET_DMA0_SIZE0 = 306, + CMD0_OPCODE_NPU_SET_DMA0_SIZE1 = 307, + CMD0_OPCODE_NPU_SET_IFM2_BROADCAST = 384, + CMD0_OPCODE_NPU_SET_IFM2_SCALAR = 385, + CMD0_OPCODE_NPU_SET_IFM2_PRECISION = 389, + CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT = 393, + CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1 = 394, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1 = 395, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1 = 396, + CMD0_OPCODE_NPU_SET_IFM2_IB_START = 397, + CMD0_OPCODE_NPU_SET_IFM2_REGION = 399, +}; + +enum cmd1_opcode +{ + CMD1_OPCODE_NPU_SET_IFM_BASE0 = 0, + CMD1_OPCODE_NPU_SET_IFM_BASE1 = 1, + CMD1_OPCODE_NPU_SET_IFM_BASE2 = 2, + CMD1_OPCODE_NPU_SET_IFM_BASE3 = 3, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_X = 4, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y = 5, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_C = 6, + CMD1_OPCODE_NPU_SET_OFM_BASE0 = 16, + CMD1_OPCODE_NPU_SET_OFM_BASE1 = 17, + CMD1_OPCODE_NPU_SET_OFM_BASE2 = 18, + CMD1_OPCODE_NPU_SET_OFM_BASE3 = 19, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_X = 20, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y = 21, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_C = 22, + CMD1_OPCODE_NPU_SET_WEIGHT_BASE = 32, + CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH = 33, + CMD1_OPCODE_NPU_SET_SCALE_BASE = 34, + CMD1_OPCODE_NPU_SET_SCALE_LENGTH = 35, + CMD1_OPCODE_NPU_SET_OFM_SCALE = 36, + CMD1_OPCODE_NPU_SET_OPA_SCALE = 37, + CMD1_OPCODE_NPU_SET_OPB_SCALE = 38, + CMD1_OPCODE_NPU_SET_DMA0_SRC = 48, + CMD1_OPCODE_NPU_SET_DMA0_DST = 49, + CMD1_OPCODE_NPU_SET_DMA0_LEN = 50, + CMD1_OPCODE_NPU_SET_DMA0_SKIP0 = 51, + CMD1_OPCODE_NPU_SET_DMA0_SKIP1 = 52, + CMD1_OPCODE_NPU_SET_IFM2_BASE0 = 128, + CMD1_OPCODE_NPU_SET_IFM2_BASE1 = 129, + CMD1_OPCODE_NPU_SET_IFM2_BASE2 = 130, + CMD1_OPCODE_NPU_SET_IFM2_BASE3 = 131, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X = 132, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y = 133, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C = 134, + CMD1_OPCODE_NPU_SET_WEIGHT1_BASE = 144, + CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH = 145, + CMD1_OPCODE_NPU_SET_SCALE1_BASE = 146, + CMD1_OPCODE_NPU_SET_SCALE1_LENGTH = 147, +}; + +enum cmd_ctrl +{ + CMD_CTRL_CMD0_CTRL = 0, + CMD_CTRL_CMD1_CTRL = 1, +}; + +enum custom_dma +{ + CUSTOM_DMA_NOT_IMPLEMENTED = 0, + CUSTOM_DMA_IMPLEMENTED = 1, +}; + +enum dma_fault_src +{ + DMA_FAULT_SRC_AXI_M0 = 0, + DMA_FAULT_SRC_AXI_M1 = 1, +}; + +enum dma_region_mode +{ + DMA_REGION_MODE_EXTERNAL = 0, + DMA_REGION_MODE_INTERNAL = 1, +}; + +enum dma_stride_mode +{ + DMA_STRIDE_MODE_D1 = 0, + DMA_STRIDE_MODE_D2 = 1, + DMA_STRIDE_MODE_D3 = 2, +}; + +enum elementwise_mode +{ + ELEMENTWISE_MODE_MUL = 0, + ELEMENTWISE_MODE_ADD = 1, + ELEMENTWISE_MODE_SUB = 2, + ELEMENTWISE_MODE_MIN = 3, + ELEMENTWISE_MODE_MAX = 4, + ELEMENTWISE_MODE_LRELU = 5, + ELEMENTWISE_MODE_ABS = 6, + ELEMENTWISE_MODE_CLZ = 7, + ELEMENTWISE_MODE_SHR = 8, + ELEMENTWISE_MODE_SHL = 9, +}; + +enum functional_safety +{ + FUNCTIONAL_SAFETY_NOT_IMPLEMENTED = 0, + FUNCTIONAL_SAFETY_IMPLEMENTED = 1, +}; + +enum ifm2_operand_order +{ + IFM2_OPERAND_ORDER_ORDER_B = 0, + IFM2_OPERAND_ORDER_ORDER_A = 1, +}; + +enum ifm_scale_mode +{ + IFM_SCALE_MODE_OPA_OPB_16 = 0, + IFM_SCALE_MODE_OPA_32 = 1, + IFM_SCALE_MODE_OPB_32 = 2, +}; + +enum ifm_upscale_mode +{ + IFM_UPSCALE_MODE_NONE = 0, + IFM_UPSCALE_MODE_NEAREST = 1, + IFM_UPSCALE_MODE_ZEROS = 2, +}; + +enum kernel_decomposition +{ + KERNEL_DECOMPOSITION_D8X8 = 0, + KERNEL_DECOMPOSITION_D4X4 = 1, +}; + +enum kernel_dilation +{ + KERNEL_DILATION_NONE = 0, + KERNEL_DILATION_X2 = 1, +}; + +enum max_beats +{ + MAX_BEATS_B64 = 0, + MAX_BEATS_B128 = 1, + MAX_BEATS_B256 = 2, +}; + +enum mem_attr +{ + MEM_ATTR_AXI0_OUTSTANDING_COUNTER0 = 0, + MEM_ATTR_AXI0_OUTSTANDING_COUNTER1 = 1, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER2 = 2, + MEM_ATTR_AXI1_OUTSTANDING_COUNTER3 = 3, +}; + +enum ofm_scale_mode +{ + OFM_SCALE_MODE_PER_CHANNEL = 0, + OFM_SCALE_MODE_GLOBAL = 1, +}; + +enum parallel_mode +{ + PARALLEL_MODE_SINGLE_CORE = 0, + PARALLEL_MODE_DUAL_CORE_DEPTH = 1, +}; + +enum pmu_axi_channel +{ + PMU_AXI_CHANNEL_RD_CMD = 0, + PMU_AXI_CHANNEL_RD_IFM = 1, + PMU_AXI_CHANNEL_RD_WEIGHTS = 2, + PMU_AXI_CHANNEL_RD_SCALE_BIAS = 3, + PMU_AXI_CHANNEL_RD_MEM2MEM = 4, + PMU_AXI_CHANNEL_WR_OFM = 8, + PMU_AXI_CHANNEL_WR_MEM2MEM = 9, +}; + +enum pmu_event +{ + PMU_EVENT_NO_EVENT = 0, + PMU_EVENT_CYCLE = 17, + PMU_EVENT_NPU_IDLE = 32, + PMU_EVENT_CC_STALLED_ON_BLOCKDEP = 33, + PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG = 34, + PMU_EVENT_NPU_ACTIVE = 35, + PMU_EVENT_MAC_ACTIVE = 48, + PMU_EVENT_MAC_ACTIVE_8BIT = 49, + PMU_EVENT_MAC_ACTIVE_16BIT = 50, + PMU_EVENT_MAC_DPU_ACTIVE = 51, + PMU_EVENT_MAC_STALLED_BY_WD_ACC = 52, + PMU_EVENT_MAC_STALLED_BY_WD = 53, + PMU_EVENT_MAC_STALLED_BY_ACC = 54, + PMU_EVENT_MAC_STALLED_BY_IB = 55, + PMU_EVENT_MAC_ACTIVE_32BIT = 56, + PMU_EVENT_MAC_STALLED_BY_INT_W = 57, + PMU_EVENT_MAC_STALLED_BY_INT_ACC = 58, + PMU_EVENT_AO_ACTIVE = 64, + PMU_EVENT_AO_ACTIVE_8BIT = 65, + PMU_EVENT_AO_ACTIVE_16BIT = 66, + PMU_EVENT_AO_STALLED_BY_OFMP_OB = 67, + PMU_EVENT_AO_STALLED_BY_OFMP = 68, + PMU_EVENT_AO_STALLED_BY_OB = 69, + PMU_EVENT_AO_STALLED_BY_ACC_IB = 70, + PMU_EVENT_AO_STALLED_BY_ACC = 71, + PMU_EVENT_AO_STALLED_BY_IB = 72, + PMU_EVENT_WD_ACTIVE = 80, + PMU_EVENT_WD_STALLED = 81, + PMU_EVENT_WD_STALLED_BY_WS = 82, + PMU_EVENT_WD_STALLED_BY_WD_BUF = 83, + PMU_EVENT_WD_PARSE_ACTIVE = 84, + PMU_EVENT_WD_PARSE_STALLED = 85, + PMU_EVENT_WD_PARSE_STALLED_IN = 86, + PMU_EVENT_WD_PARSE_STALLED_OUT = 87, + PMU_EVENT_WD_TRANS_WS = 88, + PMU_EVENT_WD_TRANS_WB = 89, + PMU_EVENT_WD_TRANS_DW0 = 90, + PMU_EVENT_WD_TRANS_DW1 = 91, + PMU_EVENT_AXI0_RD_TRANS_ACCEPTED = 128, + PMU_EVENT_AXI0_RD_TRANS_COMPLETED = 129, + PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED = 130, + PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED = 131, + PMU_EVENT_AXI0_WR_TRANS_ACCEPTED = 132, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M = 133, + PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S = 134, + PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN = 135, + PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED = 136, + PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED = 137, + PMU_EVENT_AXI0_ENABLED_CYCLES = 140, + PMU_EVENT_AXI0_RD_STALL_LIMIT = 142, + PMU_EVENT_AXI0_WR_STALL_LIMIT = 143, + PMU_EVENT_AXI_LATENCY_ANY = 160, + PMU_EVENT_AXI_LATENCY_32 = 161, + PMU_EVENT_AXI_LATENCY_64 = 162, + PMU_EVENT_AXI_LATENCY_128 = 163, + PMU_EVENT_AXI_LATENCY_256 = 164, + PMU_EVENT_AXI_LATENCY_512 = 165, + PMU_EVENT_AXI_LATENCY_1024 = 166, + PMU_EVENT_ECC_DMA = 176, + PMU_EVENT_ECC_SB0 = 177, + PMU_EVENT_AXI1_RD_TRANS_ACCEPTED = 384, + PMU_EVENT_AXI1_RD_TRANS_COMPLETED = 385, + PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED = 386, + PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED = 387, + PMU_EVENT_AXI1_WR_TRANS_ACCEPTED = 388, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M = 389, + PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S = 390, + PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN = 391, + PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED = 392, + PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED = 393, + PMU_EVENT_AXI1_ENABLED_CYCLES = 396, + PMU_EVENT_AXI1_RD_STALL_LIMIT = 398, + PMU_EVENT_AXI1_WR_STALL_LIMIT = 399, + PMU_EVENT_ECC_SB1 = 433, +}; + +enum pooling_mode +{ + POOLING_MODE_MAX = 0, + POOLING_MODE_AVERAGE = 1, + POOLING_MODE_REDUCE_SUM = 2, +}; + +enum privilege_level +{ + PRIVILEGE_LEVEL_USER = 0, + PRIVILEGE_LEVEL_PRIVILEGED = 1, +}; + +enum round_mode +{ + ROUND_MODE_DBL = 0, + ROUND_MODE_TRUNCATE = 1, + ROUND_MODE_NATURAL = 2, +}; + +enum security_level +{ + SECURITY_LEVEL_SECURE = 0, + SECURITY_LEVEL_NON_SECURE = 1, +}; + +enum state +{ + STATE_STOPPED = 0, + STATE_RUNNING = 1, +}; + +enum wd_core_slice_state +{ + WD_CORE_SLICE_STATE_HEADER = 0, + WD_CORE_SLICE_STATE_PALETTE = 1, + WD_CORE_SLICE_STATE_WEIGHTS = 2, +}; + +enum wd_ctrl_state +{ + WD_CTRL_STATE_IDLE = 0, + WD_CTRL_STATE_DRAIN = 1, + WD_CTRL_STATE_OFD_INIT = 2, + WD_CTRL_STATE_OFD_RUN = 3, +}; + +enum weight_order +{ + WEIGHT_ORDER_DEPTH_FIRST = 0, + WEIGHT_ORDER_PART_KERNEL_FIRST = 1, +}; + +#endif + +#ifdef NPU_DISASSEMBLE + +static const char *acc_format_str[] = { + "ACC_FORMAT_I32", + "ACC_FORMAT_I40", + "ACC_FORMAT_F16", +}; + +static const char *activation_clip_range_str[] = { + "ACTIVATION_CLIP_RANGE_OFM_PRECISION", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_UINT8", + "ACTIVATION_CLIP_RANGE_FORCE_INT8", + "****", + "ACTIVATION_CLIP_RANGE_FORCE_INT16", +}; + +static const char *activation_format_str[] = { + "ACTIVATION_FORMAT_NHWC", + "ACTIVATION_FORMAT_NHCWB16", +}; + +static const char *activation_function_str[] = { + "ACTIVATION_FUNCTION_RELU", + "****", + "****", + "ACTIVATION_FUNCTION_TANH", + "ACTIVATION_FUNCTION_SIGMOID", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "ACTIVATION_FUNCTION_TABLE_0", + "ACTIVATION_FUNCTION_TABLE_1", + "ACTIVATION_FUNCTION_TABLE_2", + "ACTIVATION_FUNCTION_TABLE_3", + "ACTIVATION_FUNCTION_TABLE_4", + "ACTIVATION_FUNCTION_TABLE_5", + "ACTIVATION_FUNCTION_TABLE_6", + "ACTIVATION_FUNCTION_TABLE_7", +}; + +static const char *activation_precision_str[] = { + "ACTIVATION_PRECISION_B8", + "ACTIVATION_PRECISION_B16", + "ACTIVATION_PRECISION_B32", + "ACTIVATION_PRECISION_B64", +}; + +static const char *activation_type_str[] = { + "ACTIVATION_TYPE_UNSIGNED", + "ACTIVATION_TYPE_SIGNED", +}; + +static const char *axi_mem_encoding_str[] = { + "AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_DEVICE_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE", + "AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE", +}; + +static const char *broadcast_mode_str[] = { + "BROADCAST_MODE_DISABLE", + "BROADCAST_MODE_ENABLE", +}; + +static const char *cmd0_opcode_str[] = { + "CMD0_OPCODE_NPU_OP_STOP", + "CMD0_OPCODE_NPU_OP_IRQ", + "CMD0_OPCODE_NPU_OP_CONV", + "CMD0_OPCODE_NPU_OP_DEPTHWISE", + "****", + "CMD0_OPCODE_NPU_OP_POOL", + "CMD0_OPCODE_NPU_OP_ELEMENTWISE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_OP_DMA_START", + "CMD0_OPCODE_NPU_OP_DMA_WAIT", + "CMD0_OPCODE_NPU_OP_KERNEL_WAIT", + "CMD0_OPCODE_NPU_OP_PMU_MASK", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_PAD_TOP", + "CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM", + "CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_IFM_PRECISION", + "****", + "CMD0_OPCODE_NPU_SET_IFM_UPSCALE", + "****", + "CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM_IB_END", + "****", + "CMD0_OPCODE_NPU_SET_IFM_REGION", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_PRECISION", + "CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_OFM_REGION", + "CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_STRIDE", + "CMD0_OPCODE_NPU_SET_PARALLEL_MODE", + "CMD0_OPCODE_NPU_SET_ACC_FORMAT", + "CMD0_OPCODE_NPU_SET_ACTIVATION", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MIN", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MAX", + "CMD0_OPCODE_NPU_SET_WEIGHT_REGION", + "CMD0_OPCODE_NPU_SET_SCALE_REGION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_AB_START", + "****", + "CMD0_OPCODE_NPU_SET_BLOCKDEP", + "CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_DST_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE0", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_BROADCAST", + "CMD0_OPCODE_NPU_SET_IFM2_SCALAR", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_PRECISION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1", + "CMD0_OPCODE_NPU_SET_IFM2_IB_START", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_REGION", +}; + +static const char *cmd1_opcode_str[] = { + "CMD1_OPCODE_NPU_SET_IFM_BASE0", + "CMD1_OPCODE_NPU_SET_IFM_BASE1", + "CMD1_OPCODE_NPU_SET_IFM_BASE2", + "CMD1_OPCODE_NPU_SET_IFM_BASE3", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_OFM_BASE0", + "CMD1_OPCODE_NPU_SET_OFM_BASE1", + "CMD1_OPCODE_NPU_SET_OFM_BASE2", + "CMD1_OPCODE_NPU_SET_OFM_BASE3", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE_BASE", + "CMD1_OPCODE_NPU_SET_SCALE_LENGTH", + "CMD1_OPCODE_NPU_SET_OFM_SCALE", + "CMD1_OPCODE_NPU_SET_OPA_SCALE", + "CMD1_OPCODE_NPU_SET_OPB_SCALE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_DMA0_SRC", + "CMD1_OPCODE_NPU_SET_DMA0_DST", + "CMD1_OPCODE_NPU_SET_DMA0_LEN", + "CMD1_OPCODE_NPU_SET_DMA0_SKIP0", + "CMD1_OPCODE_NPU_SET_DMA0_SKIP1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_IFM2_BASE0", + "CMD1_OPCODE_NPU_SET_IFM2_BASE1", + "CMD1_OPCODE_NPU_SET_IFM2_BASE2", + "CMD1_OPCODE_NPU_SET_IFM2_BASE3", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT1_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE1_BASE", + "CMD1_OPCODE_NPU_SET_SCALE1_LENGTH", +}; + +static const char *cmd_ctrl_str[] = { + "CMD_CTRL_CMD0_CTRL", + "CMD_CTRL_CMD1_CTRL", +}; + +static const char *custom_dma_str[] = { + "CUSTOM_DMA_NOT_IMPLEMENTED", + "CUSTOM_DMA_IMPLEMENTED", +}; + +static const char *dma_fault_src_str[] = { + "DMA_FAULT_SRC_AXI_M0", + "DMA_FAULT_SRC_AXI_M1", +}; + +static const char *dma_region_mode_str[] = { + "DMA_REGION_MODE_EXTERNAL", + "DMA_REGION_MODE_INTERNAL", +}; + +static const char *dma_stride_mode_str[] = { + "DMA_STRIDE_MODE_D1", + "DMA_STRIDE_MODE_D2", + "DMA_STRIDE_MODE_D3", +}; + +static const char *elementwise_mode_str[] = { + "ELEMENTWISE_MODE_MUL", + "ELEMENTWISE_MODE_ADD", + "ELEMENTWISE_MODE_SUB", + "ELEMENTWISE_MODE_MIN", + "ELEMENTWISE_MODE_MAX", + "ELEMENTWISE_MODE_LRELU", + "ELEMENTWISE_MODE_ABS", + "ELEMENTWISE_MODE_CLZ", + "ELEMENTWISE_MODE_SHR", + "ELEMENTWISE_MODE_SHL", +}; + +static const char *functional_safety_str[] = { + "FUNCTIONAL_SAFETY_NOT_IMPLEMENTED", + "FUNCTIONAL_SAFETY_IMPLEMENTED", +}; + +static const char *ifm2_operand_order_str[] = { + "IFM2_OPERAND_ORDER_ORDER_B", + "IFM2_OPERAND_ORDER_ORDER_A", +}; + +static const char *ifm_scale_mode_str[] = { + "IFM_SCALE_MODE_OPA_OPB_16", + "IFM_SCALE_MODE_OPA_32", + "IFM_SCALE_MODE_OPB_32", +}; + +static const char *ifm_upscale_mode_str[] = { + "IFM_UPSCALE_MODE_NONE", + "IFM_UPSCALE_MODE_NEAREST", + "IFM_UPSCALE_MODE_ZEROS", +}; + +static const char *kernel_decomposition_str[] = { + "KERNEL_DECOMPOSITION_D8X8", + "KERNEL_DECOMPOSITION_D4X4", +}; + +static const char *kernel_dilation_str[] = { + "KERNEL_DILATION_NONE", + "KERNEL_DILATION_X2", +}; + +static const char *max_beats_str[] = { + "MAX_BEATS_B64", + "MAX_BEATS_B128", + "MAX_BEATS_B256", +}; + +static const char *mem_attr_str[] = { + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER0", + "MEM_ATTR_AXI0_OUTSTANDING_COUNTER1", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER2", + "MEM_ATTR_AXI1_OUTSTANDING_COUNTER3", +}; + +static const char *ofm_scale_mode_str[] = { + "OFM_SCALE_MODE_PER_CHANNEL", + "OFM_SCALE_MODE_GLOBAL", +}; + +static const char *parallel_mode_str[] = { + "PARALLEL_MODE_SINGLE_CORE", + "PARALLEL_MODE_DUAL_CORE_DEPTH", +}; + +static const char *pmu_axi_channel_str[] = { + "PMU_AXI_CHANNEL_RD_CMD", + "PMU_AXI_CHANNEL_RD_IFM", + "PMU_AXI_CHANNEL_RD_WEIGHTS", + "PMU_AXI_CHANNEL_RD_SCALE_BIAS", + "PMU_AXI_CHANNEL_RD_MEM2MEM", + "****", + "****", + "****", + "PMU_AXI_CHANNEL_WR_OFM", + "PMU_AXI_CHANNEL_WR_MEM2MEM", +}; + +static const char *pmu_event_str[] = { + "PMU_EVENT_NO_EVENT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_CYCLE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_NPU_IDLE", + "PMU_EVENT_CC_STALLED_ON_BLOCKDEP", + "PMU_EVENT_CC_STALLED_ON_SHRAM_RECONFIG", + "PMU_EVENT_NPU_ACTIVE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_MAC_ACTIVE", + "PMU_EVENT_MAC_ACTIVE_8BIT", + "PMU_EVENT_MAC_ACTIVE_16BIT", + "PMU_EVENT_MAC_DPU_ACTIVE", + "PMU_EVENT_MAC_STALLED_BY_WD_ACC", + "PMU_EVENT_MAC_STALLED_BY_WD", + "PMU_EVENT_MAC_STALLED_BY_ACC", + "PMU_EVENT_MAC_STALLED_BY_IB", + "PMU_EVENT_MAC_ACTIVE_32BIT", + "PMU_EVENT_MAC_STALLED_BY_INT_W", + "PMU_EVENT_MAC_STALLED_BY_INT_ACC", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AO_ACTIVE", + "PMU_EVENT_AO_ACTIVE_8BIT", + "PMU_EVENT_AO_ACTIVE_16BIT", + "PMU_EVENT_AO_STALLED_BY_OFMP_OB", + "PMU_EVENT_AO_STALLED_BY_OFMP", + "PMU_EVENT_AO_STALLED_BY_OB", + "PMU_EVENT_AO_STALLED_BY_ACC_IB", + "PMU_EVENT_AO_STALLED_BY_ACC", + "PMU_EVENT_AO_STALLED_BY_IB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_ACTIVE", + "PMU_EVENT_WD_STALLED", + "PMU_EVENT_WD_STALLED_BY_WS", + "PMU_EVENT_WD_STALLED_BY_WD_BUF", + "PMU_EVENT_WD_PARSE_ACTIVE", + "PMU_EVENT_WD_PARSE_STALLED", + "PMU_EVENT_WD_PARSE_STALLED_IN", + "PMU_EVENT_WD_PARSE_STALLED_OUT", + "PMU_EVENT_WD_TRANS_WS", + "PMU_EVENT_WD_TRANS_WB", + "PMU_EVENT_WD_TRANS_DW0", + "PMU_EVENT_WD_TRANS_DW1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI0_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI0_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI0_RD_STALL_LIMIT", + "PMU_EVENT_AXI0_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI_LATENCY_ANY", + "PMU_EVENT_AXI_LATENCY_32", + "PMU_EVENT_AXI_LATENCY_64", + "PMU_EVENT_AXI_LATENCY_128", + "PMU_EVENT_AXI_LATENCY_256", + "PMU_EVENT_AXI_LATENCY_512", + "PMU_EVENT_AXI_LATENCY_1024", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_DMA", + "PMU_EVENT_ECC_SB0", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI1_RD_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_RD_TRANS_COMPLETED", + "PMU_EVENT_AXI1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_AXI1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_TRANS_ACCEPTED", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_AXI1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_AXI1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_AXI1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_AXI1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_AXI1_ENABLED_CYCLES", + "****", + "PMU_EVENT_AXI1_RD_STALL_LIMIT", + "PMU_EVENT_AXI1_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_SB1", +}; + +static const char *pooling_mode_str[] = { + "POOLING_MODE_MAX", + "POOLING_MODE_AVERAGE", + "POOLING_MODE_REDUCE_SUM", +}; + +static const char *privilege_level_str[] = { + "PRIVILEGE_LEVEL_USER", + "PRIVILEGE_LEVEL_PRIVILEGED", +}; + +static const char *round_mode_str[] = { + "ROUND_MODE_DBL", + "ROUND_MODE_TRUNCATE", + "ROUND_MODE_NATURAL", +}; + +static const char *security_level_str[] = { + "SECURITY_LEVEL_SECURE", + "SECURITY_LEVEL_NON_SECURE", +}; + +static const char *state_str[] = { + "STATE_STOPPED", + "STATE_RUNNING", +}; + +static const char *wd_core_slice_state_str[] = { + "WD_CORE_SLICE_STATE_HEADER", + "WD_CORE_SLICE_STATE_PALETTE", + "WD_CORE_SLICE_STATE_WEIGHTS", +}; + +static const char *wd_ctrl_state_str[] = { + "WD_CTRL_STATE_IDLE", + "WD_CTRL_STATE_DRAIN", + "WD_CTRL_STATE_OFD_INIT", + "WD_CTRL_STATE_OFD_RUN", +}; + +static const char *weight_order_str[] = { + "WEIGHT_ORDER_DEPTH_FIRST", + "WEIGHT_ORDER_PART_KERNEL_FIRST", +}; + +#endif + +// Register type structs +// id_r - ID register +struct id_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t version_status : 4; // This is the version of the product + uint32_t version_minor : 4; // This is the n for the P part of an RnPn release number + uint32_t version_major : 4; // This is the n for the R part of an RnPn release number + uint32_t product_major : 4; // Product major ID number (unique per base product) + uint32_t arch_patch_rev : 4; // This is the patch number of the architecture version a.b + uint32_t + arch_minor_rev : 8; // This is the minor architecture version number, b in the architecture version a.b + uint32_t + arch_major_rev : 4; // This is the major architecture version number, a in the architecture version a.b + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR id_r() : word0(268853249) {} + CONSTEXPR id_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + id_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_version_status() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_version_status() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR id_r &set_version_status(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile id_r &set_version_status(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_version_minor() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_version_minor() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR id_r &set_version_minor(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile id_r &set_version_minor(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_version_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + uint32_t get_version_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR id_r &set_version_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + volatile id_r &set_version_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_product_major() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_product_major() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR id_r &set_product_major(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile id_r &set_product_major(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_arch_patch_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + uint32_t get_arch_patch_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR id_r &set_arch_patch_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + volatile id_r &set_arch_patch_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_arch_minor_rev() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + uint32_t get_arch_minor_rev() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR id_r &set_arch_minor_rev(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + volatile id_r &set_arch_minor_rev(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_arch_major_rev() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_arch_major_rev() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR id_r &set_arch_major_rev(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile id_r &set_arch_major_rev(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// status_r - Register describes the current operating status of the NPU +struct status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t state : 1; // NPU state, 0 = Stopped, 1 = Running + uint32_t irq_raised : 1; // Raw IRQ status, 0 = IRQ not raised, 1 = IRQ raised. IRQ is cleared using command + // register bit 1 + uint32_t + bus_status : 1; // 0=OK, 1=Bus abort detected and processing halted (NPU will reach IDLE state and not + // to start process any more commands/AXI transactions). Can only be cleared by a reset + uint32_t reset_status : 1; // Reset is ongoing and only this register can be read (other registers read as 0 + // and writes are ignored.) A value of 0 means NPU is not being reset and can be + // accessed as normal + uint32_t + cmd_parse_error : 1; // 0=No error 1=Command stream parsing error detected. Can only be cleared by reset + uint32_t cmd_end_reached : 1; // 0=Not reached, 1=Reached. Cleared by writing QBASE or QSIZE when NPU is in + // stopped state + uint32_t pmu_irq_raised : 1; // 0=No PMU IRQ, 1=PMU IRQ raised. Cleared by using command register bit 1 + uint32_t wd_fault : 1; // Weight decoder state: 0=no fault 1=weight decoder decompression fault. Can only be + // cleared by reset + uint32_t ecc_fault : 1; // ECC state for internal RAMs: 0=no fault 1=ECC fault signalled. Can only be + // cleared by reset + uint32_t reserved0 : 2; + uint32_t faulting_interface : 1; // Faulting interface on bus abort + uint32_t faulting_channel : 4; // Faulting channel on a bus abort. Read: 0=Cmd 1=IFM 2=Weights 3=Scale+Bias + // 4=Mem2Mem; Write: 8=OFM 9=Mem2Mem + uint32_t irq_history_mask : 16; // IRQ History mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR status_r() : word0(8) {} + CONSTEXPR status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::state get_state() const + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::state get_state() const volatile + { + NPU_NAMESPACE::state value = static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR status_r &set_state(NPU_NAMESPACE::state value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile status_r &set_state(NPU_NAMESPACE::state value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR status_r &set_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile status_r &set_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_bus_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_bus_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR status_r &set_bus_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile status_r &set_bus_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_reset_status() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_reset_status() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR status_r &set_reset_status(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile status_r &set_reset_status(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_parse_error() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_parse_error() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR status_r &set_cmd_parse_error(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile status_r &set_cmd_parse_error(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_end_reached() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_end_reached() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR status_r &set_cmd_end_reached(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile status_r &set_cmd_end_reached(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_pmu_irq_raised() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_pmu_irq_raised() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR status_r &set_pmu_irq_raised(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile status_r &set_pmu_irq_raised(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wd_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wd_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR status_r &set_wd_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile status_r &set_wd_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ecc_fault() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ecc_fault() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR status_r &set_ecc_fault(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile status_r &set_ecc_fault(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_fault_src get_faulting_interface() const + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + NPU_NAMESPACE::dma_fault_src get_faulting_interface() const volatile + { + NPU_NAMESPACE::dma_fault_src value = static_cast(((1U << 1) - 1) & (word0 >> 11)); + return value; + } + CONSTEXPR status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + volatile status_r &set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + CONSTEXPR uint32_t get_faulting_channel() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + uint32_t get_faulting_channel() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR status_r &set_faulting_channel(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + volatile status_r &set_faulting_channel(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_irq_history_mask() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_irq_history_mask() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR status_r &set_irq_history_mask(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile status_r &set_irq_history_mask(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// cmd_r - Command register, reads as last written command +struct cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t transition_to_running_state : 1; // Write 1 to transition the NPU to running state. Writing 0 has + // no effect + uint32_t clear_irq : 1; // Write 1 to clear the IRQ status in the STATUS register. Writing 0 has no effect + uint32_t clock_q_enable : 1; // Write 1 to this bit to enable clock off using clock q-interface and enable + // the requester clock gate + uint32_t power_q_enable : 1; // Write 1 to this bit to enable power off using power q-interface + uint32_t + stop_request : 1; // Write 1 to this bit to request STOP after completing any already-started commands + uint32_t reserved0 : 11; + uint32_t clear_irq_history : 16; // Clears the IRQ history mask + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cmd_r() : word0(12) {} + CONSTEXPR cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_transition_to_running_state() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_transition_to_running_state() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR cmd_r &set_transition_to_running_state(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile cmd_r &set_transition_to_running_state(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_clear_irq() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_clear_irq() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR cmd_r &set_clear_irq(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile cmd_r &set_clear_irq(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_clock_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_clock_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR cmd_r &set_clock_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile cmd_r &set_clock_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_power_q_enable() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_power_q_enable() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR cmd_r &set_power_q_enable(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile cmd_r &set_power_q_enable(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_stop_request() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_stop_request() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR cmd_r &set_stop_request(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile cmd_r &set_stop_request(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_clear_irq_history() const + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + uint32_t get_clear_irq_history() const volatile + { + uint32_t value = ((1U << 16) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR cmd_r &set_clear_irq_history(uint32_t value) + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } + volatile cmd_r &set_clear_irq_history(uint32_t value) volatile + { + word0 = (((~((1U << 16) - 1)) << 16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// reset_r - Request Reset and new security mode +struct reset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t pending_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t pending_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR reset_r() : word0(0) {} + CONSTEXPR reset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + reset_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_pending_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_pending_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile reset_r &set_pending_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_pending_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_pending_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile reset_r &set_pending_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// qbase_r - Base address of the command stream in bytes +struct qbase_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR qbase_r() : word0(0), word1(0) {} + CONSTEXPR qbase_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + qbase_r copy() volatile + { + return *this; + } +#endif +}; + +// qread_r - Read offset in the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QREAD : 32; // The read offset of the current command under execution + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qread_r() : word0(0) {} + CONSTEXPR qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QREAD() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QREAD() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qread_r &set_QREAD(uint32_t value) + { + word0 = value; + return *this; + } + volatile qread_r &set_QREAD(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// qconfig_r - AXI configuration for the command stream in the range 0-3. Same encoding as for REGIONCFG +struct qconfig_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_region0 : 2; // Command region configuration + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qconfig_r() : word0(0) {} + CONSTEXPR qconfig_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qconfig_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_cmd_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_cmd_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile qconfig_r &set_cmd_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// qsize_r - Size of the command stream in bytes. Multiple of 4 in the range 0 to 16 MB +struct qsize_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QSIZE : 32; // Size of the next command stream to be executed by the NPU + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR qsize_r() : word0(0) {} + CONSTEXPR qsize_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + qsize_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_QSIZE() const + { + uint32_t value = word0; + return value; + } + uint32_t get_QSIZE() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR qsize_r &set_QSIZE(uint32_t value) + { + word0 = value; + return *this; + } + volatile qsize_r &set_QSIZE(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// prot_r - Protection level configured for the NPU when acting as an AXI requester +struct prot_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t active_CPL : 1; // Current privilege level 0=User 1=Privileged + uint32_t active_CSL : 1; // Current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR prot_r() : word0(0) {} + CONSTEXPR prot_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + prot_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_active_CPL() const + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::privilege_level get_active_CPL() const volatile + { + NPU_NAMESPACE::privilege_level value = + static_cast(((1U << 1) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + volatile prot_r &set_active_CPL(NPU_NAMESPACE::privilege_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_active_CSL() const + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + NPU_NAMESPACE::security_level get_active_CSL() const volatile + { + NPU_NAMESPACE::security_level value = + static_cast(((1U << 1) - 1) & (word0 >> 1)); + return value; + } + CONSTEXPR prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } + volatile prot_r &set_active_CSL(NPU_NAMESPACE::security_level value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// config_r - RTL configuration +struct config_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t macs_per_cc : 4; // The log2(macs/clock cycle) + uint32_t cmd_stream_version : 4; // command stream version accepted by this NPU + uint32_t shram_size : 8; // Total size in KB of internal SHRAM + uint32_t reserved0 : 10; + uint32_t functional_safety : 1; // Functional safety configuration + uint32_t custom_dma : 1; // Custom DMA configuration + uint32_t product : 4; // Product configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR config_r() : word0(268435456) {} + CONSTEXPR config_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + config_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_macs_per_cc() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + uint32_t get_macs_per_cc() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR config_r &set_macs_per_cc(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + volatile config_r &set_macs_per_cc(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_stream_version() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_stream_version() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR config_r &set_cmd_stream_version(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + volatile config_r &set_cmd_stream_version(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_shram_size() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + uint32_t get_shram_size() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR config_r &set_shram_size(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + volatile config_r &set_shram_size(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 8) & word0) | ((((1U << 8) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::functional_safety get_functional_safety() const + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + NPU_NAMESPACE::functional_safety get_functional_safety() const volatile + { + NPU_NAMESPACE::functional_safety value = + static_cast(((1U << 1) - 1) & (word0 >> 26)); + return value; + } + CONSTEXPR config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + volatile config_r &set_functional_safety(NPU_NAMESPACE::functional_safety value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 26); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma get_custom_dma() const + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + NPU_NAMESPACE::custom_dma get_custom_dma() const volatile + { + NPU_NAMESPACE::custom_dma value = static_cast(((1U << 1) - 1) & (word0 >> 27)); + return value; + } + CONSTEXPR config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + volatile config_r &set_custom_dma(NPU_NAMESPACE::custom_dma value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + CONSTEXPR uint32_t get_product() const + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + uint32_t get_product() const volatile + { + uint32_t value = ((1U << 4) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR config_r &set_product(uint32_t value) + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } + volatile config_r &set_product(uint32_t value) volatile + { + word0 = (((~((1U << 4) - 1)) << 28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// lock_r - Lock register. This register is designed for driver use and does not affect NPU functionality +struct lock_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t LOCK : 32; // 32 bit value for LOCK configuration + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR lock_r() : word0(0) {} + CONSTEXPR lock_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + lock_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_LOCK() const + { + uint32_t value = word0; + return value; + } + uint32_t get_LOCK() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR lock_r &set_LOCK(uint32_t value) + { + word0 = value; + return *this; + } + volatile lock_r &set_LOCK(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// regioncfg_r - Region memory type configuration. Bits[2*k+1:2*k] give the memory type for REGION[k] +struct regioncfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t region0 : 2; // Bits for Region0 Configuration + uint32_t region1 : 2; // Bits for Region1 Configuration + uint32_t region2 : 2; // Bits for Region2 Configuration + uint32_t region3 : 2; // Bits for Region3 Configuration + uint32_t region4 : 2; // Bits for Region4 Configuration + uint32_t region5 : 2; // Bits for Region5 Configuration + uint32_t region6 : 2; // Bits for Region6 Configuration + uint32_t region7 : 2; // Bits for Region7 Configuration + uint32_t reserved0 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR regioncfg_r() : word0(0) {} + CONSTEXPR regioncfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + regioncfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region0() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::mem_attr get_region0() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile regioncfg_r &set_region0(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region1() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + NPU_NAMESPACE::mem_attr get_region1() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 2)); + return value; + } + CONSTEXPR regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + volatile regioncfg_r &set_region1(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region2() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::mem_attr get_region2() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + volatile regioncfg_r &set_region2(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 4) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region3() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + NPU_NAMESPACE::mem_attr get_region3() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 6)); + return value; + } + CONSTEXPR regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + volatile regioncfg_r &set_region3(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 6) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 6); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region4() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + NPU_NAMESPACE::mem_attr get_region4() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 8)); + return value; + } + CONSTEXPR regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + volatile regioncfg_r &set_region4(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region5() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + NPU_NAMESPACE::mem_attr get_region5() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 10)); + return value; + } + CONSTEXPR regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + volatile regioncfg_r &set_region5(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 10) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 10); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region6() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + NPU_NAMESPACE::mem_attr get_region6() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 12)); + return value; + } + CONSTEXPR regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + volatile regioncfg_r &set_region6(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 12) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::mem_attr get_region7() const + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + NPU_NAMESPACE::mem_attr get_region7() const volatile + { + NPU_NAMESPACE::mem_attr value = static_cast(((1U << 2) - 1) & (word0 >> 14)); + return value; + } + CONSTEXPR regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } + volatile regioncfg_r &set_region7(NPU_NAMESPACE::mem_attr value) volatile + { + word0 = (((~((1U << 2) - 1)) << 14) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 14); + return *this; + } +#endif +}; + +// axi_limit0_r - AXI limits for port 0 counter 0 +struct axi_limit0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit0_r() : word0(0) {} + CONSTEXPR axi_limit0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit0_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit0_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit0_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit0_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit1_r - AXI limits for port 0 counter 1 +struct axi_limit1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit1_r() : word0(0) {} + CONSTEXPR axi_limit1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit1_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit1_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit1_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit1_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit2_r - AXI limits for port 1 counter 2 +struct axi_limit2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit2_r() : word0(0) {} + CONSTEXPR axi_limit2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit2_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit2_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit2_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit2_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// axi_limit3_r - AXI limits for port 1 counter 3 +struct axi_limit3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved0 : 2; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 8; + uint32_t + max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions - 1 in range 0 to 63 + uint32_t reserved2 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions - 1 in range + // 0 to 31 + uint32_t reserved3 : 3; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR axi_limit3_r() : word0(0) {} + CONSTEXPR axi_limit3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + axi_limit3_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::max_beats get_max_beats() const volatile + { + NPU_NAMESPACE::max_beats value = static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile axi_limit3_r &set_max_beats(NPU_NAMESPACE::max_beats value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + NPU_NAMESPACE::axi_mem_encoding get_memtype() const volatile + { + NPU_NAMESPACE::axi_mem_encoding value = + static_cast(((1U << 4) - 1) & (word0 >> 4)); + return value; + } + CONSTEXPR axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + volatile axi_limit3_r &set_memtype(NPU_NAMESPACE::axi_mem_encoding value) volatile + { + word0 = (((~((1U << 4) - 1)) << 4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + uint32_t get_max_outstanding_read_m1() const volatile + { + uint32_t value = ((1U << 6) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_read_m1(uint32_t value) volatile + { + word0 = (((~((1U << 6) - 1)) << 16) & word0) | ((((1U << 6) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + uint32_t get_max_outstanding_write_m1() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } + volatile axi_limit3_r &set_max_outstanding_write_m1(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 24) & word0) | ((((1U << 5) - 1) & value) << 24); + return *this; + } +#endif +}; + +// basep_r - The driver can use this address to relocate the command stream on region 0. If the region contains data +// requiring A-byte alignment then the base must be a multiple of A +struct basep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR basep_r() : word0(0), word1(0) {} + CONSTEXPR basep_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + basep_r copy() volatile + { + return *this; + } +#endif +}; + +// wd_status_r - WD_STATUS +struct wd_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t core_slice_state : 2; // WD core slice parser state + uint32_t core_idle : 1; // Core idle + uint32_t ctrl_state : 2; // WD control state + uint32_t ctrl_idle : 1; // All stripe jobs idle (all weights consumed) + uint32_t write_buf_index0 : 3; // current write index for next data from core + uint32_t write_buf_valid0 : 1; // write buf valid (full) + uint32_t write_buf_idle0 : 1; // write buf idle (empty) + uint32_t write_buf_index1 : 3; // current write index for next data from core + uint32_t write_buf_valid1 : 1; // write buf valid (full) + uint32_t write_buf_idle1 : 1; // write buf idle (empty) + uint32_t events : 12; // WD events mapped as appendix A + uint32_t reserved0 : 4; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR wd_status_r() : word0(0) {} + CONSTEXPR wd_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + wd_status_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::wd_core_slice_state get_core_slice_state() const volatile + { + NPU_NAMESPACE::wd_core_slice_state value = + static_cast(((1U << 2) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + volatile wd_status_r &set_core_slice_state(NPU_NAMESPACE::wd_core_slice_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_core_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_core_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR wd_status_r &set_core_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile wd_status_r &set_core_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + NPU_NAMESPACE::wd_ctrl_state get_ctrl_state() const volatile + { + NPU_NAMESPACE::wd_ctrl_state value = static_cast(((1U << 2) - 1) & (word0 >> 3)); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + volatile wd_status_r &set_ctrl_state(NPU_NAMESPACE::wd_ctrl_state value) volatile + { + word0 = (((~((1U << 2) - 1)) << 3) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 3); + return *this; + } + CONSTEXPR uint32_t get_ctrl_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ctrl_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR wd_status_r &set_ctrl_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile wd_status_r &set_ctrl_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index0() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + uint32_t get_write_buf_index0() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index0(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + volatile wd_status_r &set_write_buf_index0(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 6) & word0) | ((((1U << 3) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_write_buf_valid0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile wd_status_r &set_write_buf_valid0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_write_buf_idle0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile wd_status_r &set_write_buf_idle0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_write_buf_index1() const + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + uint32_t get_write_buf_index1() const volatile + { + uint32_t value = ((1U << 3) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_index1(uint32_t value) + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + volatile wd_status_r &set_write_buf_index1(uint32_t value) volatile + { + word0 = (((~((1U << 3) - 1)) << 11) & word0) | ((((1U << 3) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_write_buf_valid1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_write_buf_valid1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_valid1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile wd_status_r &set_write_buf_valid1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_write_buf_idle1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_write_buf_idle1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR wd_status_r &set_write_buf_idle1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile wd_status_r &set_write_buf_idle1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 12) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR wd_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } + volatile wd_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 12) - 1)) << 16) & word0) | ((((1U << 12) - 1) & value) << 16); + return *this; + } +#endif +}; + +// mac_status_r - MAC_STATUS +struct mac_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block_cfg_valid : 1; // MAC has a valid block configuration + uint32_t trav_en : 1; // MAC is doing block traversal + uint32_t wait_for_ib : 1; // MAC is waiting for an Input Buffer to become available + uint32_t wait_for_acc_buf : 1; // MAC is waiting for an Accumulator Buffer to become available + uint32_t wait_for_weights : 1; // MAC is waiting for a Weight Block to become available + uint32_t stall_stripe : 1; // MAC is stalling between two stripes + uint32_t dw_sel : 1; // Currently used weight interface in MAC AI + uint32_t wait_for_dw0_ready : 1; // MAC AI is waiting for MAC DPU to send dw0_ready to WD + uint32_t wait_for_dw1_ready : 1; // MAC AI is waiting for MAC DPU to send dw1_ready to WD + uint32_t acc_buf_sel_ai : 1; // Currently used AccBuf interface in MAC AI + uint32_t wait_for_acc0_ready : 1; // MAC AI is waiting for acc0_ready from AO + uint32_t wait_for_acc1_ready : 1; // MAC AI is waiting for acc1_ready from AO + uint32_t acc_buf_sel_aa : 1; // Currently used AccBuf interface in MAC ADDER_ARRAY + uint32_t acc0_valid : 1; // MAC outgoing value of acc0_valid + uint32_t acc1_valid : 1; // MAC outgoing value of acc1_valid + uint32_t reserved0 : 1; + uint32_t events : 11; // Mapped to MAC events described in Appendix A + uint32_t reserved1 : 5; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR mac_status_r() : word0(0) {} + CONSTEXPR mac_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + mac_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block_cfg_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_block_cfg_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR mac_status_r &set_block_cfg_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile mac_status_r &set_block_cfg_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_trav_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_trav_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR mac_status_r &set_trav_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile mac_status_r &set_trav_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wait_for_ib() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wait_for_ib() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_ib(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile mac_status_r &set_wait_for_ib(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc_buf() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_wait_for_acc_buf() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc_buf(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile mac_status_r &set_wait_for_acc_buf(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_wait_for_weights() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_wait_for_weights() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_weights(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile mac_status_r &set_wait_for_weights(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_stall_stripe() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_stall_stripe() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR mac_status_r &set_stall_stripe(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile mac_status_r &set_stall_stripe(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_dw_sel() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_dw_sel() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR mac_status_r &set_dw_sel(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile mac_status_r &set_dw_sel(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_wait_for_dw0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile mac_status_r &set_wait_for_dw0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_wait_for_dw1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_wait_for_dw1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_dw1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile mac_status_r &set_wait_for_dw1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_ai() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_acc_buf_sel_ai() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_ai(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_ai(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc0_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_wait_for_acc0_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc0_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile mac_status_r &set_wait_for_acc0_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_wait_for_acc1_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_wait_for_acc1_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR mac_status_r &set_wait_for_acc1_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile mac_status_r &set_wait_for_acc1_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_acc_buf_sel_aa() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_acc_buf_sel_aa() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR mac_status_r &set_acc_buf_sel_aa(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile mac_status_r &set_acc_buf_sel_aa(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_acc0_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_acc0_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR mac_status_r &set_acc0_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile mac_status_r &set_acc0_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_acc1_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_acc1_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR mac_status_r &set_acc1_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile mac_status_r &set_acc1_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 11) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR mac_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } + volatile mac_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 11) - 1)) << 16) & word0) | ((((1U << 11) - 1) & value) << 16); + return *this; + } +#endif +}; + +// ao_status_r - AO_STATUS +struct ao_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_sbw_valid : 1; // Block command to shared buffer write module is valid + uint32_t cmd_act_valid : 1; // Block command to activation function module is valid + uint32_t cmd_ctl_valid : 1; // Block command to control module is valid + uint32_t cmd_scl_valid : 1; // Block command to scale module is valid + uint32_t cmd_sbr_valid : 1; // Block command to shared buffer read module is valid + uint32_t cmd_ofm_valid : 1; // Block command to ofm parameter module is valid + uint32_t blk_cmd_ready : 1; // Ready to accept block command + uint32_t blk_cmd_valid : 1; // Block command from CC is valid + uint32_t reserved0 : 8; + uint32_t events : 8; // Mapped to AO events described in Appendix A + uint32_t reserved1 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ao_status_r() : word0(0) {} + CONSTEXPR ao_status_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ao_status_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_sbw_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_sbw_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbw_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile ao_status_r &set_cmd_sbw_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_act_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cmd_act_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR ao_status_r &set_cmd_act_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile ao_status_r &set_cmd_act_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cmd_ctl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cmd_ctl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ctl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile ao_status_r &set_cmd_ctl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_cmd_scl_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_cmd_scl_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR ao_status_r &set_cmd_scl_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile ao_status_r &set_cmd_scl_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_sbr_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_cmd_sbr_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR ao_status_r &set_cmd_sbr_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile ao_status_r &set_cmd_sbr_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_ofm_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_cmd_ofm_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR ao_status_r &set_cmd_ofm_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile ao_status_r &set_cmd_ofm_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_blk_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile ao_status_r &set_blk_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_blk_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_blk_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR ao_status_r &set_blk_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile ao_status_r &set_blk_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_events() const + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + uint32_t get_events() const volatile + { + uint32_t value = ((1U << 8) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR ao_status_r &set_events(uint32_t value) + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } + volatile ao_status_r &set_events(uint32_t value) volatile + { + word0 = (((~((1U << 8) - 1)) << 16) & word0) | ((((1U << 8) - 1) & value) << 16); + return *this; + } +#endif +}; + +// dma_status0_r - DMA_STATUS0 +struct dma_status0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_idle : 1; // When this bit is high means that the CMD block is not busy in generating addresses + // for a CMD job + uint32_t ifm_idle : 1; // When this bit is high means that there are no ongoing IFM jobs + uint32_t wgt_idle_c0 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c0 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t m2m_idle : 1; // When this bit is high means that there are no ongoing M2M jobs + uint32_t ofm_idle : 1; // When this bit is high means that there are no ongoing OFM jobs + uint32_t halt_req : 1; // CPM has requested to HALT AXI bus before soft reset + uint32_t halt_ack : 1; // DMA is in condition to halt the AXI bus since there are no pending transactions + uint32_t pause_req : 1; // CC has requested to pause the AXI + uint32_t pause_ack : 1; // DMA is in condition to pause the AXI bus since there are no pending transactions + uint32_t ib0_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 0 - Core 0 + uint32_t ib1_ai_valid_c0 : 1; // Data for AI to be read in IFM input buffer 1 - Core 0 + uint32_t ib1_ai_ready_c0 : 1; // Data consumed from AI in IFM input buffer 1 - Core 0 + uint32_t ib0_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib0_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_valid_c0 : 1; // Data for AO to be read in IFM input buffer 0 - Core 0 + uint32_t ib1_ao_ready_c0 : 1; // Data consumed from AO in IFM input buffer 1 - Core 0 + uint32_t ob0_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 0 + uint32_t ob0_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 0 + uint32_t ob1_valid_c0 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 0 + uint32_t ob1_ready_c0 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 0 + uint32_t cmd_valid : 1; // New command word for CC to be consumed + uint32_t cmd_ready : 1; // command word consumed by CC + uint32_t wd_bitstream_valid_c0 : 1; // New weight word for WD to be consumed - Core 0 + uint32_t wd_bitstream_ready_c0 : 1; // Weight word consumed by WD - Core 0 + uint32_t bs_bitstream_valid_c0 : 1; // New BaS word for AO to be consumed - Core 0 + uint32_t bs_bitstream_ready_c0 : 1; // BaS word consumed by AO - Core 0 + uint32_t axi0_ar_stalled : 1; // Read transfer request stalled on arready low AXI0 (due to memory system) + uint32_t axi0_rd_limit_stall : 1; // Read stalled due to one AXI0 limit counter being reached + uint32_t axi0_aw_stalled : 1; // Write transfer request stalled on awready low AXI0 (due to memory system) + uint32_t axi0_w_stalled : 1; // Write transfer stalled on awready low AXI0 (due to memory system) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status0_r() : word0(0) {} + CONSTEXPR dma_status0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cmd_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cmd_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status0_r &set_cmd_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ifm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_ifm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status0_r &set_ifm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status0_r &set_ifm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_wgt_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status0_r &set_wgt_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status0_r &set_wgt_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_bas_idle_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status0_r &set_bas_idle_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status0_r &set_bas_idle_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_m2m_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_m2m_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status0_r &set_m2m_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status0_r &set_m2m_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_ofm_idle() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_ofm_idle() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status0_r &set_ofm_idle(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status0_r &set_ofm_idle(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_halt_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_halt_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status0_r &set_halt_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status0_r &set_halt_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_halt_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_halt_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status0_r &set_halt_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status0_r &set_halt_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_pause_req() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_pause_req() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status0_r &set_pause_req(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status0_r &set_pause_req(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_pause_ack() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_pause_ack() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status0_r &set_pause_ack(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status0_r &set_pause_ack(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib0_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status0_r &set_ib0_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib0_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status0_r &set_ib0_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib1_ai_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status0_r &set_ib1_ai_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib1_ai_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status0_r &set_ib1_ai_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib0_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status0_r &set_ib0_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib0_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status0_r &set_ib0_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ib1_ao_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status0_r &set_ib1_ao_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ib1_ao_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status0_r &set_ib1_ao_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob0_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status0_r &set_ob0_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob0_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status0_r &set_ob0_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status0_r &set_ob0_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_ob1_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status0_r &set_ob1_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_ob1_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status0_r &set_ob1_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status0_r &set_ob1_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_cmd_valid() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_cmd_valid() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_valid(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status0_r &set_cmd_valid(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_cmd_ready() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_cmd_ready() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status0_r &set_cmd_ready(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status0_r &set_cmd_ready(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + uint32_t get_wd_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 24); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + uint32_t get_wd_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 25); + return value; + } + CONSTEXPR dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + volatile dma_status0_r &set_wd_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + uint32_t get_bs_bitstream_valid_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 26); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_valid_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + uint32_t get_bs_bitstream_ready_c0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 27); + return value; + } + CONSTEXPR dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + volatile dma_status0_r &set_bs_bitstream_ready_c0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_axi0_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + uint32_t get_axi0_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 28); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + volatile dma_status0_r &set_axi0_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_axi0_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + uint32_t get_axi0_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 29); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + volatile dma_status0_r &set_axi0_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + CONSTEXPR uint32_t get_axi0_aw_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + uint32_t get_axi0_aw_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 30); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_aw_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + volatile dma_status0_r &set_axi0_aw_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } + CONSTEXPR uint32_t get_axi0_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_axi0_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR dma_status0_r &set_axi0_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile dma_status0_r &set_axi0_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// dma_status1_r - DMA_STATUS1 +struct dma_status1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t axi0_wr_limit_stall : 1; // Write stalled due to one AXI0 limit counter being reached + uint32_t axi1_ar_stalled : 1; // Read transfer request stalled on arready low AXI1 (due to memory system) + uint32_t axi1_rd_limit_stall : 1; // Read stalled due to one AXI1 limit counter being reached + uint32_t axi1_wr_stalled : 1; // Write transfer request stalled on awready low AXI1 (due to memory system) + uint32_t axi1_w_stalled : 1; // Write transfer stalled on wready low AXI1 (due to memory system) + uint32_t axi1_wr_limit_stall : 1; // Write stalled due to one AXI1 limit counter being reached + uint32_t wgt_idle_c1 : 1; // When this bit is high means that the WGT block is not busy in generating + // addresses for a WGT job + uint32_t bas_idle_c1 : 1; // When this bit is high means that the BAS block is not busy in generating + // addresses for a BAS job + uint32_t ib0_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 0 - Core 1 + uint32_t ib1_ai_valid_c1 : 1; // Data for AI to be read in IFM input buffer 1 - Core 1 + uint32_t ib1_ai_ready_c1 : 1; // Data consumed from AI in IFM input buffer 1 - Core 1 + uint32_t ib0_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib0_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_valid_c1 : 1; // Data for AO to be read in IFM input buffer 0 - Core 1 + uint32_t ib1_ao_ready_c1 : 1; // Data consumed from AO in IFM input buffer 1 - Core 1 + uint32_t ob0_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 0 - Core 1 + uint32_t ob0_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 0 - Core 1 + uint32_t ob1_valid_c1 : 1; // Data for DMA ready to be consumed in OFM output buffer 1 - Core 1 + uint32_t ob1_ready_c1 : 1; // Data consumed from DMA in OFM output buffer 1 - Core 1 + uint32_t wd_bitstream_valid_c1 : 1; // New weight word for WD to be consumed - Core 1 + uint32_t wd_bitstream_ready_c1 : 1; // Weight word consumed by WD - Core 1 + uint32_t bs_bitstream_valid_c1 : 1; // New BaS word for AO to be consumed - Core 1 + uint32_t bs_bitstream_ready_c1 : 1; // BaS word consumed by AO - Core 1 + uint32_t reserved0 : 8; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_status1_r() : word0(0) {} + CONSTEXPR dma_status1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_status1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_axi0_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_axi0_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile dma_status1_r &set_axi0_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_axi1_ar_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_axi1_ar_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_ar_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile dma_status1_r &set_axi1_ar_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_axi1_rd_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_axi1_rd_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile dma_status1_r &set_axi1_rd_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_axi1_wr_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile dma_status1_r &set_axi1_wr_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_axi1_w_stalled() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_axi1_w_stalled() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_w_stalled(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile dma_status1_r &set_axi1_w_stalled(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_axi1_wr_limit_stall() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_axi1_wr_limit_stall() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile dma_status1_r &set_axi1_wr_limit_stall(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_wgt_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + uint32_t get_wgt_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 6); + return value; + } + CONSTEXPR dma_status1_r &set_wgt_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + volatile dma_status1_r &set_wgt_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_bas_idle_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + uint32_t get_bas_idle_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 7); + return value; + } + CONSTEXPR dma_status1_r &set_bas_idle_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + volatile dma_status1_r &set_bas_idle_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + uint32_t get_ib0_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + volatile dma_status1_r &set_ib0_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_ib0_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + uint32_t get_ib0_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 9); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + volatile dma_status1_r &set_ib0_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_ib1_ai_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile dma_status1_r &set_ib1_ai_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_ib1_ai_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + uint32_t get_ib1_ai_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + volatile dma_status1_r &set_ib1_ai_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + uint32_t get_ib0_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 12); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + volatile dma_status1_r &set_ib0_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ib0_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + uint32_t get_ib0_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 13); + return value; + } + CONSTEXPR dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + volatile dma_status1_r &set_ib0_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + uint32_t get_ib1_ao_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 14); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + volatile dma_status1_r &set_ib1_ao_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ib1_ao_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + uint32_t get_ib1_ao_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 15); + return value; + } + CONSTEXPR dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + volatile dma_status1_r &set_ib1_ao_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ob0_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + uint32_t get_ob0_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 16); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + volatile dma_status1_r &set_ob0_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_ob0_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + uint32_t get_ob0_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 17); + return value; + } + CONSTEXPR dma_status1_r &set_ob0_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + volatile dma_status1_r &set_ob0_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_ob1_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + uint32_t get_ob1_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 18); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + volatile dma_status1_r &set_ob1_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_ob1_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + uint32_t get_ob1_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 19); + return value; + } + CONSTEXPR dma_status1_r &set_ob1_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + volatile dma_status1_r &set_ob1_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + uint32_t get_wd_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 20); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wd_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + uint32_t get_wd_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 21); + return value; + } + CONSTEXPR dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + volatile dma_status1_r &set_wd_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_valid_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + uint32_t get_bs_bitstream_valid_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 22); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_valid_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_bs_bitstream_ready_c1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + uint32_t get_bs_bitstream_ready_c1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 23); + return value; + } + CONSTEXPR dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + volatile dma_status1_r &set_bs_bitstream_ready_c1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } +#endif +}; + +// clkforce_r - Force clocks on for clock gating +struct clkforce_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t top_level_clk : 1; // set to 1 to force on TOP level clock + uint32_t cc_clk : 1; // set to 1 to force on CC clock + uint32_t dma_clk : 1; // set to 1 to force on DMA clock + uint32_t mac_clk : 1; // set to 1 to force on MAC clock + uint32_t ao_clk : 1; // set to 1 to force on AO clock + uint32_t wd_clk : 1; // set to 1 to force on WD clock + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR clkforce_r() : word0(0) {} + CONSTEXPR clkforce_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + clkforce_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_top_level_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_top_level_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR clkforce_r &set_top_level_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile clkforce_r &set_top_level_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cc_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_cc_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR clkforce_r &set_cc_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile clkforce_r &set_cc_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_dma_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_dma_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR clkforce_r &set_dma_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile clkforce_r &set_dma_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mac_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mac_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR clkforce_r &set_mac_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile clkforce_r &set_mac_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + uint32_t get_ao_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 4); + return value; + } + CONSTEXPR clkforce_r &set_ao_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + volatile clkforce_r &set_ao_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_wd_clk() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + uint32_t get_wd_clk() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 5); + return value; + } + CONSTEXPR clkforce_r &set_wd_clk(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + volatile clkforce_r &set_wd_clk(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } +#endif +}; + +// debug_address_r - Set debug address for register reads 0x400-0x7FF. The address must be 1KB aligned +struct debug_address_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t addr : 32; // Register address + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_address_r() : word0(0) {} + CONSTEXPR debug_address_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_address_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + uint32_t value = word0; + return value; + } + uint32_t get_addr() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_address_r &set_addr(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_address_r &set_addr(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_misc_r - 32-bit read/write register for driver debug use. This does not affect NPU function +struct debug_misc_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t misc : 32; // Debug misc + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_misc_r() : word0(0) {} + CONSTEXPR debug_misc_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_misc_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_misc() const + { + uint32_t value = word0; + return value; + } + uint32_t get_misc() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_misc_r &set_misc(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_misc_r &set_misc(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debugcore_r - Select core number for debug registers (0x200-0x2FF) and RAM reads (0x400-0x7FF). Value is 0 or 1 +struct debugcore_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t core : 32; // Debug core + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debugcore_r() : word0(0) {} + CONSTEXPR debugcore_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debugcore_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_core() const + { + uint32_t value = word0; + return value; + } + uint32_t get_core() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debugcore_r &set_core(uint32_t value) + { + word0 = value; + return *this; + } + volatile debugcore_r &set_core(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// debug_block_r - Set from which of four block banks the TSU registers are read. 0 = read from the current bank 256+n = +// force to read from bank n where n is in the range 0 to 3 +struct debug_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t block : 32; // Debug block + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR debug_block_r() : word0(0) {} + CONSTEXPR debug_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + debug_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_block() const + { + uint32_t value = word0; + return value; + } + uint32_t get_block() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR debug_block_r &set_block(uint32_t value) + { + word0 = value; + return *this; + } + volatile debug_block_r &set_block(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmcr_r - PMU Register control +struct pmcr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cnt_en : 1; // Enable counter + uint32_t event_cnt_rst : 1; // Reset event counter + uint32_t cycle_cnt_rst : 1; // Reset cycle counter + uint32_t mask_en : 1; // PMU can be enabled/disabled by command stream operation NPU_OP_PMU_MASK + uint32_t reserved0 : 7; + uint32_t num_event_cnt : 5; // Number of event counters + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcr_r() : word0(8192) {} + CONSTEXPR pmcr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_cnt_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_cnt_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcr_r &set_cnt_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcr_r &set_cnt_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_event_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_event_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcr_r &set_event_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcr_r &set_event_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cycle_cnt_rst() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_cycle_cnt_rst() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcr_r &set_cycle_cnt_rst(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcr_r &set_cycle_cnt_rst(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mask_en() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_mask_en() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcr_r &set_mask_en(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcr_r &set_mask_en(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_num_event_cnt() const + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + uint32_t get_num_event_cnt() const volatile + { + uint32_t value = ((1U << 5) - 1) & (word0 >> 11); + return value; + } + CONSTEXPR pmcr_r &set_num_event_cnt(uint32_t value) + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } + volatile pmcr_r &set_num_event_cnt(uint32_t value) volatile + { + word0 = (((~((1U << 5) - 1)) << 11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } +#endif +}; + +// pmcntenset_r - Count enable set register +struct pmcntenset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenset_r() : word0(0) {} + CONSTEXPR pmcntenset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenset_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenset_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenset_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenset_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmcntenclr_r - Count enable clear register +struct pmcntenclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT : 1; // PMCCNTR disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcntenclr_r() : word0(0) {} + CONSTEXPR pmcntenclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcntenclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_0(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_1(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_2(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmcntenclr_r &set_EVENT_CNT_3(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmcntenclr_r &set_CYCLE_CNT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmcntenclr_r &set_CYCLE_CNT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsset_r - Overflow flag status set register +struct pmovsset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow set bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow set bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow set bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow set bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow set bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsset_r() : word0(0) {} + CONSTEXPR pmovsset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsset_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsset_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsclr_r - Overflow flag status clear register +struct pmovsclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow clear bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow clear bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow clear bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow clear bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow clear bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmovsclr_r() : word0(0) {} + CONSTEXPR pmovsclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmovsclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_0_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_1_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_2_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmovsclr_r &set_EVENT_CNT_3_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_OVF() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmovsclr_r &set_CYCLE_CNT_OVF(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintset_r - Interrupt enable set register +struct pmintset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request enable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintset_r() : word0(0) {} + CONSTEXPR pmintset_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintset_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintset_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintset_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintset_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintclr_r - Interrupt enable clear register +struct pmintclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR3 + uint32_t reserved0 : 27; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request disable bit + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmintclr_r() : word0(0) {} + CONSTEXPR pmintclr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmintclr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + uint32_t get_EVENT_CNT_0_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 0); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_0_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + uint32_t get_EVENT_CNT_1_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 1); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_1_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + uint32_t get_EVENT_CNT_2_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 2); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_2_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + uint32_t get_EVENT_CNT_3_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 3); + return value; + } + CONSTEXPR pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + volatile pmintclr_r &set_EVENT_CNT_3_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + uint32_t get_CYCLE_CNT_INT() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 31); + return value; + } + CONSTEXPR pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } + volatile pmintclr_r &set_CYCLE_CNT_INT(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmccntr_r - Performance monitor cycle count register +struct pmccntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_LO : 32; // Cycle count - LSB + uint32_t CYCLE_CNT_HI : 16; // Cycle count - MSB + uint32_t reserved0 : 16; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR pmccntr_r() : word0(0), word1(0) {} + CONSTEXPR pmccntr_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + pmccntr_r copy() volatile + { + return *this; + } +#endif +}; + +// pmccntr_cfg_r - Set start/stop event on the cycle counter +struct pmccntr_cfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_CFG_START : 10; // Cycle counter start event + uint32_t reserved0 : 6; + uint32_t CYCLE_CNT_CFG_STOP : 10; // Cycle counter stop event + uint32_t reserved1 : 6; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmccntr_cfg_r() : word0(0) {} + CONSTEXPR pmccntr_cfg_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmccntr_cfg_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 16)); + return value; + } + CONSTEXPR pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } + volatile pmccntr_cfg_r &set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// pmcaxi_chan_r - Set which AXI channel to monitor for latency measurements in PMU +struct pmcaxi_chan_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CH_SEL : 4; // Channel select for latency measurements + uint32_t reserved0 : 4; + uint32_t AXI_CNT_SEL : 2; // AXI counter to monitor for latency measurements + uint32_t BW_CH_SEL_EN : 1; // Bandwidth channel selector + uint32_t reserved1 : 21; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmcaxi_chan_r() : word0(0) {} + CONSTEXPR pmcaxi_chan_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmcaxi_chan_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const volatile + { + NPU_NAMESPACE::pmu_axi_channel value = + static_cast(((1U << 4) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmcaxi_chan_r &set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) volatile + { + word0 = (((~((1U << 4) - 1)) << 0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_AXI_CNT_SEL() const + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + uint32_t get_AXI_CNT_SEL() const volatile + { + uint32_t value = ((1U << 2) - 1) & (word0 >> 8); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + volatile pmcaxi_chan_r &set_AXI_CNT_SEL(uint32_t value) volatile + { + word0 = (((~((1U << 2) - 1)) << 8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_BW_CH_SEL_EN() const + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + uint32_t get_BW_CH_SEL_EN() const volatile + { + uint32_t value = ((1U << 1) - 1) & (word0 >> 10); + return value; + } + CONSTEXPR pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + volatile pmcaxi_chan_r &set_BW_CH_SEL_EN(uint32_t value) volatile + { + word0 = (((~((1U << 1) - 1)) << 10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } +#endif +}; + +// kernel_x_r - Kernel X offset of in kernel decomposition +struct kernel_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_x_r() : word0(0) {} + CONSTEXPR kernel_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_y_r - Kernel Y offset of in kernel decomposition +struct kernel_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_y_r() : word0(0) {} + CONSTEXPR kernel_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_w_m1_r - Kernel (width-1) of current block +struct kernel_w_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_w_m1_r() : word0(0) {} + CONSTEXPR kernel_w_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_w_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_w_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_w_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_h_m1_r - Kernel (height-1) of current block +struct kernel_h_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_h_m1_r() : word0(0) {} + CONSTEXPR kernel_h_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_h_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_h_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_h_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_width_m1_r - OFM current block (width-1) +struct ofm_cblk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_height_m1_r - OFM current block (height-1) +struct ofm_cblk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_cblk_depth_m1_r - OFM current block (depth-1) +struct ofm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_depth_m1_r - IFM current block (depth-1) +struct ifm_cblk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_cblk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_x_r - Block X coordinate in OFM +struct ofm_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_x_r() : word0(0) {} + CONSTEXPR ofm_x_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_x_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_x_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_x_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_y_r - Block Y coordinate in OFM +struct ofm_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_y_r() : word0(0) {} + CONSTEXPR ofm_y_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_y_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_y_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_y_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_z_r - Block Z (channel) coordinate in OFM +struct ofm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_z_r() : word0(0) {} + CONSTEXPR ofm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_z_r - Block Z (channel) coordinate in IFM +struct ifm_z_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_z_r() : word0(0) {} + CONSTEXPR ifm_z_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_z_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_z_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_z_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_top_r - Block top pad +struct pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_top_r() : word0(0) {} + CONSTEXPR pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pad_left_r - Block left pad +struct pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pad_left_r() : word0(0) {} + CONSTEXPR pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_width_r - IFM current block derived width +struct ifm_cblk_width_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_width_r() : word0(0) {} + CONSTEXPR ifm_cblk_width_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_width_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_width_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_width_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_cblk_height_r - IFM current block derived height +struct ifm_cblk_height_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_cblk_height_r() : word0(0) {} + CONSTEXPR ifm_cblk_height_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_cblk_height_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_cblk_height_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_cblk_height_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ifm_src_r - DMA IFM channel source position on AXI +struct dma_ifm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ifm_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_ifm_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ifm_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_ifm_dst_r - DMA IFM channel destination position in SHRAM +struct dma_ifm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ifm_dst_r() : word0(0) {} + CONSTEXPR dma_ifm_dst_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ifm_dst_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ifm_dst_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ifm_dst_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_src_r - DMA OFM channel source position in SHRAM +struct dma_ofm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_ofm_src_r() : word0(0) {} + CONSTEXPR dma_ofm_src_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_ofm_src_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_ofm_src_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_ofm_src_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_ofm_dst_r - DMA OFM channel destination position on AXI +struct dma_ofm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_ofm_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_ofm_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_ofm_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_weight_src_r - DMA weight channel source position on AXI +struct dma_weight_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_weight_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_weight_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_weight_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_src_r - DMA command channel source position on AXI +struct dma_cmd_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_cmd_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_cmd_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_cmd_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_cmd_size_r - DMA command channel number of bytes buffered +struct dma_cmd_size_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma_cmd_size_r() : word0(0) {} + CONSTEXPR dma_cmd_size_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma_cmd_size_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma_cmd_size_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma_cmd_size_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_m2m_src_r - DMA memory to memory source position on AXI +struct dma_m2m_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma_m2m_dst_r - DMA memory to memory destination position on AXI +struct dma_m2m_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_m2m_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma_m2m_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// current_qread_r - QREAD position being issued (rather than completed) +struct current_qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_qread_r() : word0(0) {} + CONSTEXPR current_qread_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_qread_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_qread_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_qread_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma_scale_src_r - DMA scale and bias channel source position on AXI +struct dma_scale_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma_scale_src_r() : word0(0), word1(0) {} + CONSTEXPR dma_scale_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma_scale_src_r copy() volatile + { + return *this; + } +#endif +}; + +// current_block_r - 0-3. Current block bank being executed by the TSU or last one executed if TSU is stopped +struct current_block_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_block_r() : word0(0) {} + CONSTEXPR current_block_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_block_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_block_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_block_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_op_r - Current NPU OP command being executed by the TSU +struct current_op_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_op_r() : word0(0) {} + CONSTEXPR current_op_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_op_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_op_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_op_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// current_cmd_r - Current 32-bit command being parsed by the command stream parser +struct current_cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR current_cmd_r() : word0(0) {} + CONSTEXPR current_cmd_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + current_cmd_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR current_cmd_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile current_cmd_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevcntr_r - Performance monitor event 0 count register +struct pmevcntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t count : 32; // Count word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevcntr_r() : word0(0) {} + CONSTEXPR pmevcntr_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevcntr_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_count() const + { + uint32_t value = word0; + return value; + } + uint32_t get_count() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pmevcntr_r &set_count(uint32_t value) + { + word0 = value; + return *this; + } + volatile pmevcntr_r &set_count(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pmevtyper_r - Performance monitor event type register 0 +struct pmevtyper_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EV_TYPE : 10; // Event Type + uint32_t reserved0 : 22; + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pmevtyper_r() : word0(0) {} + CONSTEXPR pmevtyper_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pmevtyper_r copy() volatile + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_EV_TYPE() const + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + NPU_NAMESPACE::pmu_event get_EV_TYPE() const volatile + { + NPU_NAMESPACE::pmu_event value = static_cast(((1U << 10) - 1) & (word0 >> 0)); + return value; + } + CONSTEXPR pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + volatile pmevtyper_r &set_EV_TYPE(NPU_NAMESPACE::pmu_event value) volatile + { + word0 = (((~((1U << 10) - 1)) << 0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } +#endif +}; + +// shared_buffer_r - Shared buffer debug access. Only valid in STOPPED state +struct shared_buffer_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_word : 32; // Memory word + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR shared_buffer_r() : word0(0) {} + CONSTEXPR shared_buffer_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + shared_buffer_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_mem_word() const + { + uint32_t value = word0; + return value; + } + uint32_t get_mem_word() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR shared_buffer_r &set_mem_word(uint32_t value) + { + word0 = value; + return *this; + } + volatile shared_buffer_r &set_mem_word(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_top_r - None +struct ifm_pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_top_r() : word0(0) {} + CONSTEXPR ifm_pad_top_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_top_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_top_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_top_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_left_r - None +struct ifm_pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_left_r() : word0(0) {} + CONSTEXPR ifm_pad_left_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_left_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_left_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_left_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_right_r - None +struct ifm_pad_right_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_right_r() : word0(0) {} + CONSTEXPR ifm_pad_right_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_right_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_right_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_right_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_bottom_r - None +struct ifm_pad_bottom_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_pad_bottom_r() : word0(0) {} + CONSTEXPR ifm_pad_bottom_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_pad_bottom_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_pad_bottom_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_pad_bottom_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_depth_m1_r - None +struct ifm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_depth_m1_r() : word0(0) {} + CONSTEXPR ifm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_precision_r - None +struct ifm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_precision_r() : word0(0) {} + CONSTEXPR ifm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_upscale_r - None +struct ifm_upscale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_upscale_r() : word0(0) {} + CONSTEXPR ifm_upscale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_upscale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_upscale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_upscale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_zero_point_r - None +struct ifm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_zero_point_r() : word0(0) {} + CONSTEXPR ifm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_width0_m1_r - None +struct ifm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_width0_m1_r() : word0(0) {} + CONSTEXPR ifm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height0_m1_r - None +struct ifm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height0_m1_r() : word0(0) {} + CONSTEXPR ifm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height1_m1_r - None +struct ifm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_height1_m1_r() : word0(0) {} + CONSTEXPR ifm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_ib_end_r - None +struct ifm_ib_end_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_ib_end_r() : word0(0) {} + CONSTEXPR ifm_ib_end_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_ib_end_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_ib_end_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_ib_end_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_region_r - None +struct ifm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm_region_r() : word0(0) {} + CONSTEXPR ifm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width_m1_r - None +struct ofm_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width_m1_r() : word0(0) {} + CONSTEXPR ofm_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height_m1_r - None +struct ofm_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height_m1_r() : word0(0) {} + CONSTEXPR ofm_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_depth_m1_r - None +struct ofm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_precision_r - None +struct ofm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_precision_r() : word0(0) {} + CONSTEXPR ofm_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_width_m1_r - None +struct ofm_blk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_width_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_height_m1_r - None +struct ofm_blk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_height_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_depth_m1_r - None +struct ofm_blk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_blk_depth_m1_r() : word0(0) {} + CONSTEXPR ofm_blk_depth_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_blk_depth_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_blk_depth_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_blk_depth_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_zero_point_r - None +struct ofm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_zero_point_r() : word0(0) {} + CONSTEXPR ofm_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width0_m1_r - None +struct ofm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_width0_m1_r() : word0(0) {} + CONSTEXPR ofm_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height0_m1_r - None +struct ofm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height0_m1_r() : word0(0) {} + CONSTEXPR ofm_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height1_m1_r - None +struct ofm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_height1_m1_r() : word0(0) {} + CONSTEXPR ofm_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_region_r - None +struct ofm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_region_r() : word0(0) {} + CONSTEXPR ofm_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_width_m1_r - None +struct kernel_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_width_m1_r() : word0(0) {} + CONSTEXPR kernel_width_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_width_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_width_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_width_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_height_m1_r - None +struct kernel_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_height_m1_r() : word0(0) {} + CONSTEXPR kernel_height_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_height_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_height_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_height_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_stride_r - None +struct kernel_stride_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR kernel_stride_r() : word0(0) {} + CONSTEXPR kernel_stride_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + kernel_stride_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR kernel_stride_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile kernel_stride_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// parallel_mode_r - None +struct parallel_mode_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR parallel_mode_r() : word0(0) {} + CONSTEXPR parallel_mode_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + parallel_mode_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR parallel_mode_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile parallel_mode_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// acc_format_r - None +struct acc_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR acc_format_r() : word0(0) {} + CONSTEXPR acc_format_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + acc_format_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR acc_format_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile acc_format_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_r - None +struct activation_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_r() : word0(0) {} + CONSTEXPR activation_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_min_r - None +struct activation_min_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_min_r() : word0(0) {} + CONSTEXPR activation_min_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_min_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_min_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_min_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// activation_max_r - None +struct activation_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR activation_max_r() : word0(0) {} + CONSTEXPR activation_max_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + activation_max_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR activation_max_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile activation_max_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// weight_region_r - None +struct weight_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR weight_region_r() : word0(0) {} + CONSTEXPR weight_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + weight_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR weight_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile weight_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// scale_region_r - None +struct scale_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR scale_region_r() : word0(0) {} + CONSTEXPR scale_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + scale_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR scale_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile scale_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ab_start_r - None +struct ab_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ab_start_r() : word0(0) {} + CONSTEXPR ab_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ab_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ab_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ab_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// blockdep_r - None +struct blockdep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR blockdep_r() : word0(0) {} + CONSTEXPR blockdep_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + blockdep_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR blockdep_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile blockdep_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_region_r - None +struct dma0_src_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_src_region_r() : word0(0) {} + CONSTEXPR dma0_src_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_src_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_src_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_src_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_dst_region_r - None +struct dma0_dst_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_dst_region_r() : word0(0) {} + CONSTEXPR dma0_dst_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_dst_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_dst_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_dst_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size0_r - None +struct dma0_size0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size0_r() : word0(0) {} + CONSTEXPR dma0_size0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size0_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size0_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size1_r - None +struct dma0_size1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR dma0_size1_r() : word0(0) {} + CONSTEXPR dma0_size1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + dma0_size1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR dma0_size1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile dma0_size1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_broadcast_r - None +struct ifm2_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_broadcast_r() : word0(0) {} + CONSTEXPR ifm2_broadcast_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_broadcast_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_broadcast_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_broadcast_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_scalar_r - None +struct ifm2_scalar_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_scalar_r() : word0(0) {} + CONSTEXPR ifm2_scalar_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_scalar_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_scalar_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_scalar_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_precision_r - None +struct ifm2_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_precision_r() : word0(0) {} + CONSTEXPR ifm2_precision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_precision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_precision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_precision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_zero_point_r - None +struct ifm2_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_zero_point_r() : word0(0) {} + CONSTEXPR ifm2_zero_point_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_zero_point_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_zero_point_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_zero_point_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_width0_m1_r - None +struct ifm2_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_width0_m1_r() : word0(0) {} + CONSTEXPR ifm2_width0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_width0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_width0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_width0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height0_m1_r - None +struct ifm2_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height0_m1_r() : word0(0) {} + CONSTEXPR ifm2_height0_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height0_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height0_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height0_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height1_m1_r - None +struct ifm2_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_height1_m1_r() : word0(0) {} + CONSTEXPR ifm2_height1_m1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_height1_m1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_height1_m1_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_height1_m1_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_ib_start_r - None +struct ifm2_ib_start_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_ib_start_r() : word0(0) {} + CONSTEXPR ifm2_ib_start_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_ib_start_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_ib_start_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_ib_start_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_region_r - None +struct ifm2_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ifm2_region_r() : word0(0) {} + CONSTEXPR ifm2_region_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ifm2_region_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ifm2_region_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ifm2_region_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_base0_r - None +struct ifm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base1_r - None +struct ifm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base2_r - None +struct ifm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_base3_r - None +struct ifm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_x_r - None +struct ifm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_y_r - None +struct ifm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm_stride_c_r - None +struct ifm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base0_r - None +struct ofm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base0_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base1_r - None +struct ofm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base1_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base2_r - None +struct ofm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base2_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_base3_r - None +struct ofm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_base3_r() : word0(0), word1(0) {} + CONSTEXPR ofm_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_x_r - None +struct ofm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_y_r - None +struct ofm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_stride_c_r - None +struct ofm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ofm_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ofm_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_base_r - None +struct weight_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_base_r() : word0(0), word1(0) {} + CONSTEXPR weight_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_base_r copy() volatile + { + return *this; + } +#endif +}; + +// weight_length_r - None +struct weight_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight_length_r() : word0(0), word1(0) {} + CONSTEXPR weight_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight_length_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_base_r - None +struct scale_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_base_r() : word0(0), word1(0) {} + CONSTEXPR scale_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_base_r copy() volatile + { + return *this; + } +#endif +}; + +// scale_length_r - None +struct scale_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale_length_r() : word0(0), word1(0) {} + CONSTEXPR scale_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale_length_r copy() volatile + { + return *this; + } +#endif +}; + +// ofm_scale_r - None +struct ofm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_r() : word0(0) {} + CONSTEXPR ofm_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_scale_shift_r - None +struct ofm_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR ofm_scale_shift_r() : word0(0) {} + CONSTEXPR ofm_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + ofm_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR ofm_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile ofm_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_r - None +struct opa_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_r() : word0(0) {} + CONSTEXPR opa_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opa_scale_shift_r - None +struct opa_scale_shift_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opa_scale_shift_r() : word0(0) {} + CONSTEXPR opa_scale_shift_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opa_scale_shift_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opa_scale_shift_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opa_scale_shift_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// opb_scale_r - None +struct opb_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR opb_scale_r() : word0(0) {} + CONSTEXPR opb_scale_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + opb_scale_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR opb_scale_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile opb_scale_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_r - None +struct dma0_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_src_r() : word0(0), word1(0) {} + CONSTEXPR dma0_src_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_dst_r - None +struct dma0_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_dst_r() : word0(0), word1(0) {} + CONSTEXPR dma0_dst_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_len_r - None +struct dma0_len_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_len_r() : word0(0), word1(0) {} + CONSTEXPR dma0_len_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_len_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_skip0_r - None +struct dma0_skip0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_skip0_r() : word0(0), word1(0) {} + CONSTEXPR dma0_skip0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_skip0_r copy() volatile + { + return *this; + } +#endif +}; + +// dma0_skip1_r - None +struct dma0_skip1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR dma0_skip1_r() : word0(0), word1(0) {} + CONSTEXPR dma0_skip1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + dma0_skip1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base0_r - None +struct ifm2_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base0_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base0_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base0_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base1_r - None +struct ifm2_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base1_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base1_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base1_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base2_r - None +struct ifm2_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base2_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base2_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base2_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_base3_r - None +struct ifm2_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_base3_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_base3_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base3_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_x_r - None +struct ifm2_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_x_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_x_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_x_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_y_r - None +struct ifm2_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_y_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_y_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_y_r copy() volatile + { + return *this; + } +#endif +}; + +// ifm2_stride_c_r - None +struct ifm2_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR ifm2_stride_c_r() : word0(0), word1(0) {} + CONSTEXPR ifm2_stride_c_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_c_r copy() volatile + { + return *this; + } +#endif +}; + +// weight1_base_r - None +struct weight1_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight1_base_r() : word0(0), word1(0) {} + CONSTEXPR weight1_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight1_base_r copy() volatile + { + return *this; + } +#endif +}; + +// weight1_length_r - None +struct weight1_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR weight1_length_r() : word0(0), word1(0) {} + CONSTEXPR weight1_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + weight1_length_r copy() volatile + { + return *this; + } +#endif +}; + +// scale1_base_r - None +struct scale1_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale1_base_r() : word0(0), word1(0) {} + CONSTEXPR scale1_base_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale1_base_r copy() volatile + { + return *this; + } +#endif +}; + +// scale1_length_r - None +struct scale1_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else + private: + uint32_t word0; + uint32_t word1; + + public: + CONSTEXPR scale1_length_r() : word0(0), word1(0) {} + CONSTEXPR scale1_length_r(uint64_t init) : + word0(static_cast((init)&std::numeric_limits::max())), + word1(static_cast((init >> 32) & std::numeric_limits::max())) + { + } + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + void operator=(uint64_t value) volatile + { + word0 = static_cast((value)&std::numeric_limits::max()); + word1 = static_cast((value >> 32) & std::numeric_limits::max()); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + operator uint64_t() volatile + { + return (static_cast(word1) << 32) | word0; + } + scale1_length_r copy() volatile + { + return *this; + } +#endif +}; + +// revision_r - Internal FPGA build revision: first 32-bits of the Ultan Git hash used for the build +struct revision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR revision_r() : word0(0) {} + CONSTEXPR revision_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + revision_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + uint32_t value = word0; + return value; + } + uint32_t get_value() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR revision_r &set_value(uint32_t value) + { + word0 = value; + return *this; + } + volatile revision_r &set_value(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid4_r - Peripheral ID byte 4 (Arm=code 4) +struct pid4_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID4 : 32; // Byte 4 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid4_r() : word0(4) {} + CONSTEXPR pid4_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid4_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID4() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID4() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid4_r &set_PID4(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid4_r &set_PID4(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid5_r - Peripheral ID byte 5 (reserved) +struct pid5_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID5 : 32; // Byte 5 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid5_r() : word0(0) {} + CONSTEXPR pid5_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid5_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID5() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID5() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid5_r &set_PID5(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid5_r &set_PID5(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid6_r - Peripheral ID byte 6 (reserved) +struct pid6_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID6 : 32; // Byte 6 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid6_r() : word0(0) {} + CONSTEXPR pid6_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid6_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID6() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID6() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid6_r &set_PID6(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid6_r &set_PID6(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid7_r - Peripheral ID byte 7 (reserved) +struct pid7_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID7 : 32; // Byte 7 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid7_r() : word0(0) {} + CONSTEXPR pid7_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid7_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID7() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID7() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid7_r &set_PID7(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid7_r &set_PID7(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid0_r - Peripheral ID byte 0. This is bits[7:0] of the part number +struct pid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID0 : 32; // Byte 0 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid0_r() : word0(129) {} + CONSTEXPR pid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid0_r &set_PID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid0_r &set_PID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid1_r - Peripheral ID byte 1. This is bits[11:8] of the part number in bits[3:0], and bits[3:0] of the Arm ID in +// bits[7:4] +struct pid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID1 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid1_r() : word0(181) {} + CONSTEXPR pid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid1_r &set_PID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid1_r &set_PID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid2_r - Peripheral ID byte 2. This is bits[6:4] of the Arm ID in bits[2:0], and bit 3 indicates format B +struct pid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID2 : 32; // Byte 2 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid2_r() : word0(11) {} + CONSTEXPR pid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid2_r &set_PID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid2_r &set_PID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// pid3_r - Peripheral ID byte 3 +struct pid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID3 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR pid3_r() : word0(0) {} + CONSTEXPR pid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + pid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_PID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_PID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR pid3_r &set_PID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile pid3_r &set_PID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid0_r - Component ID byte 0 +struct cid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID0 : 32; // Byte 0 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid0_r() : word0(13) {} + CONSTEXPR cid0_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid0_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID0() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID0() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid0_r &set_CID0(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid0_r &set_CID0(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid1_r - Component ID byte 1 +struct cid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID1 : 32; // Byte 1 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid1_r() : word0(240) {} + CONSTEXPR cid1_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid1_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID1() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID1() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid1_r &set_CID1(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid1_r &set_CID1(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid2_r - Component ID byte 2 +struct cid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID2 : 32; // Byte 2 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid2_r() : word0(5) {} + CONSTEXPR cid2_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid2_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID2() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID2() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid2_r &set_CID2(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid2_r &set_CID2(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +// cid3_r - Component ID byte 3 +struct cid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID3 : 32; // Byte 3 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else + private: + uint32_t word0; + + public: + CONSTEXPR cid3_r() : word0(177) {} + CONSTEXPR cid3_r(uint32_t init) : word0(init) {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + void operator=(uint32_t value) volatile + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + operator uint32_t() volatile + { + return word0; + } + cid3_r copy() volatile + { + return *this; + } + CONSTEXPR uint32_t get_CID3() const + { + uint32_t value = word0; + return value; + } + uint32_t get_CID3() const volatile + { + uint32_t value = word0; + return value; + } + CONSTEXPR cid3_r &set_CID3(uint32_t value) + { + word0 = value; + return *this; + } + volatile cid3_r &set_CID3(uint32_t value) volatile + { + word0 = value; + return *this; + } +#endif +}; + +struct NPU_REG +{ + STRUCT id_r ID; // 0x0000 + STRUCT status_r STATUS; // 0x0004 + STRUCT cmd_r CMD; // 0x0008 + STRUCT reset_r RESET; // 0x000C + STRUCT qbase_r QBASE; // 0x0010 + STRUCT qread_r QREAD; // 0x0018 + STRUCT qconfig_r QCONFIG; // 0x001C + STRUCT qsize_r QSIZE; // 0x0020 + STRUCT prot_r PROT; // 0x0024 + STRUCT config_r CONFIG; // 0x0028 + STRUCT lock_r LOCK; // 0x002C + uint32_t unused0[3]; + STRUCT regioncfg_r REGIONCFG; // 0x003C + STRUCT axi_limit0_r AXI_LIMIT0; // 0x0040 + STRUCT axi_limit1_r AXI_LIMIT1; // 0x0044 + STRUCT axi_limit2_r AXI_LIMIT2; // 0x0048 + STRUCT axi_limit3_r AXI_LIMIT3; // 0x004C + uint32_t unused1[12]; + STRUCT basep_r BASEP[8]; // 0x0080 + uint32_t unused2[16]; + STRUCT wd_status_r WD_STATUS; // 0x0100 + STRUCT mac_status_r MAC_STATUS; // 0x0104 + STRUCT ao_status_r AO_STATUS; // 0x0108 + uint32_t unused3[1]; + STRUCT dma_status0_r DMA_STATUS0; // 0x0110 + STRUCT dma_status1_r DMA_STATUS1; // 0x0114 + uint32_t unused4[10]; + STRUCT clkforce_r CLKFORCE; // 0x0140 + STRUCT debug_address_r DEBUG_ADDRESS; // 0x0144 + STRUCT debug_misc_r DEBUG_MISC; // 0x0148 + STRUCT debugcore_r DEBUGCORE; // 0x014C + STRUCT debug_block_r DEBUG_BLOCK; // 0x0150 + uint32_t unused5[11]; + STRUCT pmcr_r PMCR; // 0x0180 + STRUCT pmcntenset_r PMCNTENSET; // 0x0184 + STRUCT pmcntenclr_r PMCNTENCLR; // 0x0188 + STRUCT pmovsset_r PMOVSSET; // 0x018C + STRUCT pmovsclr_r PMOVSCLR; // 0x0190 + STRUCT pmintset_r PMINTSET; // 0x0194 + STRUCT pmintclr_r PMINTCLR; // 0x0198 + uint32_t unused6[1]; + STRUCT pmccntr_r PMCCNTR; // 0x01A0 + STRUCT pmccntr_cfg_r PMCCNTR_CFG; // 0x01A8 + STRUCT pmcaxi_chan_r PMCAXI_CHAN; // 0x01AC + uint32_t unused7[20]; + STRUCT kernel_x_r KERNEL_X; // 0x0200 + STRUCT kernel_y_r KERNEL_Y; // 0x0204 + STRUCT kernel_w_m1_r KERNEL_W_M1; // 0x0208 + STRUCT kernel_h_m1_r KERNEL_H_M1; // 0x020C + STRUCT ofm_cblk_width_m1_r OFM_CBLK_WIDTH_M1; // 0x0210 + STRUCT ofm_cblk_height_m1_r OFM_CBLK_HEIGHT_M1; // 0x0214 + STRUCT ofm_cblk_depth_m1_r OFM_CBLK_DEPTH_M1; // 0x0218 + STRUCT ifm_cblk_depth_m1_r IFM_CBLK_DEPTH_M1; // 0x021C + STRUCT ofm_x_r OFM_X; // 0x0220 + STRUCT ofm_y_r OFM_Y; // 0x0224 + STRUCT ofm_z_r OFM_Z; // 0x0228 + STRUCT ifm_z_r IFM_Z; // 0x022C + STRUCT pad_top_r PAD_TOP; // 0x0230 + STRUCT pad_left_r PAD_LEFT; // 0x0234 + STRUCT ifm_cblk_width_r IFM_CBLK_WIDTH; // 0x0238 + STRUCT ifm_cblk_height_r IFM_CBLK_HEIGHT; // 0x023C + STRUCT dma_ifm_src_r DMA_IFM_SRC; // 0x0240 + STRUCT dma_ifm_dst_r DMA_IFM_DST; // 0x0248 + STRUCT dma_ofm_src_r DMA_OFM_SRC; // 0x024C + STRUCT dma_ofm_dst_r DMA_OFM_DST; // 0x0250 + STRUCT dma_weight_src_r DMA_WEIGHT_SRC; // 0x0258 + STRUCT dma_cmd_src_r DMA_CMD_SRC; // 0x0260 + STRUCT dma_cmd_size_r DMA_CMD_SIZE; // 0x0268 + STRUCT dma_m2m_src_r DMA_M2M_SRC; // 0x026C + STRUCT dma_m2m_dst_r DMA_M2M_DST; // 0x0274 + STRUCT current_qread_r CURRENT_QREAD; // 0x027C + STRUCT dma_scale_src_r DMA_SCALE_SRC; // 0x0280 + uint32_t unused8[11]; + STRUCT current_block_r CURRENT_BLOCK; // 0x02B4 + STRUCT current_op_r CURRENT_OP; // 0x02B8 + STRUCT current_cmd_r CURRENT_CMD; // 0x02BC + uint32_t unused9[16]; + STRUCT pmevcntr_r PMEVCNTR[4]; // 0x0300 + uint32_t unused10[28]; + STRUCT pmevtyper_r PMEVTYPER[4]; // 0x0380 + uint32_t unused11[28]; + STRUCT shared_buffer_r SHARED_BUFFER[256]; // 0x0400 + STRUCT ifm_pad_top_r IFM_PAD_TOP; // 0x0800 + STRUCT ifm_pad_left_r IFM_PAD_LEFT; // 0x0804 + STRUCT ifm_pad_right_r IFM_PAD_RIGHT; // 0x0808 + STRUCT ifm_pad_bottom_r IFM_PAD_BOTTOM; // 0x080C + STRUCT ifm_depth_m1_r IFM_DEPTH_M1; // 0x0810 + STRUCT ifm_precision_r IFM_PRECISION; // 0x0814 + uint32_t unused12[1]; + STRUCT ifm_upscale_r IFM_UPSCALE; // 0x081C + uint32_t unused13[1]; + STRUCT ifm_zero_point_r IFM_ZERO_POINT; // 0x0824 + STRUCT ifm_width0_m1_r IFM_WIDTH0_M1; // 0x0828 + STRUCT ifm_height0_m1_r IFM_HEIGHT0_M1; // 0x082C + STRUCT ifm_height1_m1_r IFM_HEIGHT1_M1; // 0x0830 + STRUCT ifm_ib_end_r IFM_IB_END; // 0x0834 + uint32_t unused14[1]; + STRUCT ifm_region_r IFM_REGION; // 0x083C + uint32_t unused15[1]; + STRUCT ofm_width_m1_r OFM_WIDTH_M1; // 0x0844 + STRUCT ofm_height_m1_r OFM_HEIGHT_M1; // 0x0848 + STRUCT ofm_depth_m1_r OFM_DEPTH_M1; // 0x084C + STRUCT ofm_precision_r OFM_PRECISION; // 0x0850 + STRUCT ofm_blk_width_m1_r OFM_BLK_WIDTH_M1; // 0x0854 + STRUCT ofm_blk_height_m1_r OFM_BLK_HEIGHT_M1; // 0x0858 + STRUCT ofm_blk_depth_m1_r OFM_BLK_DEPTH_M1; // 0x085C + STRUCT ofm_zero_point_r OFM_ZERO_POINT; // 0x0860 + uint32_t unused16[1]; + STRUCT ofm_width0_m1_r OFM_WIDTH0_M1; // 0x0868 + STRUCT ofm_height0_m1_r OFM_HEIGHT0_M1; // 0x086C + STRUCT ofm_height1_m1_r OFM_HEIGHT1_M1; // 0x0870 + uint32_t unused17[2]; + STRUCT ofm_region_r OFM_REGION; // 0x087C + STRUCT kernel_width_m1_r KERNEL_WIDTH_M1; // 0x0880 + STRUCT kernel_height_m1_r KERNEL_HEIGHT_M1; // 0x0884 + STRUCT kernel_stride_r KERNEL_STRIDE; // 0x0888 + STRUCT parallel_mode_r PARALLEL_MODE; // 0x088C + STRUCT acc_format_r ACC_FORMAT; // 0x0890 + STRUCT activation_r ACTIVATION; // 0x0894 + STRUCT activation_min_r ACTIVATION_MIN; // 0x0898 + STRUCT activation_max_r ACTIVATION_MAX; // 0x089C + STRUCT weight_region_r WEIGHT_REGION; // 0x08A0 + STRUCT scale_region_r SCALE_REGION; // 0x08A4 + uint32_t unused18[3]; + STRUCT ab_start_r AB_START; // 0x08B4 + uint32_t unused19[1]; + STRUCT blockdep_r BLOCKDEP; // 0x08BC + STRUCT dma0_src_region_r DMA0_SRC_REGION; // 0x08C0 + STRUCT dma0_dst_region_r DMA0_DST_REGION; // 0x08C4 + STRUCT dma0_size0_r DMA0_SIZE0; // 0x08C8 + STRUCT dma0_size1_r DMA0_SIZE1; // 0x08CC + uint32_t unused20[12]; + STRUCT ifm2_broadcast_r IFM2_BROADCAST; // 0x0900 + STRUCT ifm2_scalar_r IFM2_SCALAR; // 0x0904 + uint32_t unused21[3]; + STRUCT ifm2_precision_r IFM2_PRECISION; // 0x0914 + uint32_t unused22[3]; + STRUCT ifm2_zero_point_r IFM2_ZERO_POINT; // 0x0924 + STRUCT ifm2_width0_m1_r IFM2_WIDTH0_M1; // 0x0928 + STRUCT ifm2_height0_m1_r IFM2_HEIGHT0_M1; // 0x092C + STRUCT ifm2_height1_m1_r IFM2_HEIGHT1_M1; // 0x0930 + STRUCT ifm2_ib_start_r IFM2_IB_START; // 0x0934 + uint32_t unused23[1]; + STRUCT ifm2_region_r IFM2_REGION; // 0x093C + uint32_t unused24[48]; + STRUCT ifm_base0_r IFM_BASE0; // 0x0A00 + STRUCT ifm_base1_r IFM_BASE1; // 0x0A08 + STRUCT ifm_base2_r IFM_BASE2; // 0x0A10 + STRUCT ifm_base3_r IFM_BASE3; // 0x0A18 + STRUCT ifm_stride_x_r IFM_STRIDE_X; // 0x0A20 + STRUCT ifm_stride_y_r IFM_STRIDE_Y; // 0x0A28 + STRUCT ifm_stride_c_r IFM_STRIDE_C; // 0x0A30 + uint32_t unused25[2]; + STRUCT ofm_base0_r OFM_BASE0; // 0x0A40 + STRUCT ofm_base1_r OFM_BASE1; // 0x0A48 + STRUCT ofm_base2_r OFM_BASE2; // 0x0A50 + STRUCT ofm_base3_r OFM_BASE3; // 0x0A58 + STRUCT ofm_stride_x_r OFM_STRIDE_X; // 0x0A60 + STRUCT ofm_stride_y_r OFM_STRIDE_Y; // 0x0A68 + STRUCT ofm_stride_c_r OFM_STRIDE_C; // 0x0A70 + uint32_t unused26[2]; + STRUCT weight_base_r WEIGHT_BASE; // 0x0A80 + STRUCT weight_length_r WEIGHT_LENGTH; // 0x0A88 + STRUCT scale_base_r SCALE_BASE; // 0x0A90 + STRUCT scale_length_r SCALE_LENGTH; // 0x0A98 + STRUCT ofm_scale_r OFM_SCALE; // 0x0AA0 + STRUCT ofm_scale_shift_r OFM_SCALE_SHIFT; // 0x0AA4 + STRUCT opa_scale_r OPA_SCALE; // 0x0AA8 + STRUCT opa_scale_shift_r OPA_SCALE_SHIFT; // 0x0AAC + STRUCT opb_scale_r OPB_SCALE; // 0x0AB0 + uint32_t unused27[3]; + STRUCT dma0_src_r DMA0_SRC; // 0x0AC0 + STRUCT dma0_dst_r DMA0_DST; // 0x0AC8 + STRUCT dma0_len_r DMA0_LEN; // 0x0AD0 + STRUCT dma0_skip0_r DMA0_SKIP0; // 0x0AD8 + STRUCT dma0_skip1_r DMA0_SKIP1; // 0x0AE0 + uint32_t unused28[6]; + STRUCT ifm2_base0_r IFM2_BASE0; // 0x0B00 + STRUCT ifm2_base1_r IFM2_BASE1; // 0x0B08 + STRUCT ifm2_base2_r IFM2_BASE2; // 0x0B10 + STRUCT ifm2_base3_r IFM2_BASE3; // 0x0B18 + STRUCT ifm2_stride_x_r IFM2_STRIDE_X; // 0x0B20 + STRUCT ifm2_stride_y_r IFM2_STRIDE_Y; // 0x0B28 + STRUCT ifm2_stride_c_r IFM2_STRIDE_C; // 0x0B30 + uint32_t unused29[2]; + STRUCT weight1_base_r WEIGHT1_BASE; // 0x0B40 + STRUCT weight1_length_r WEIGHT1_LENGTH; // 0x0B48 + STRUCT scale1_base_r SCALE1_BASE; // 0x0B50 + STRUCT scale1_length_r SCALE1_LENGTH; // 0x0B58 + uint32_t unused30[280]; + STRUCT revision_r REVISION; // 0x0FC0 + uint32_t unused31[3]; + STRUCT pid4_r PID4; // 0x0FD0 + STRUCT pid5_r PID5; // 0x0FD4 + STRUCT pid6_r PID6; // 0x0FD8 + STRUCT pid7_r PID7; // 0x0FDC + STRUCT pid0_r PID0; // 0x0FE0 + STRUCT pid1_r PID1; // 0x0FE4 + STRUCT pid2_r PID2; // 0x0FE8 + STRUCT pid3_r PID3; // 0x0FEC + STRUCT cid0_r CID0; // 0x0FF0 + STRUCT cid1_r CID1; // 0x0FF4 + STRUCT cid2_r CID2; // 0x0FF8 + STRUCT cid3_r CID3; // 0x0FFC + +#ifdef __cplusplus + enum class access_type_t : uint8_t + { + RW, + RO, + WO + }; + NPU_REG() + { + reset(); + } + void reset() + { + ID = 268853249; + STATUS = 8; + CMD = 12; + RESET = 0; + QBASE = 0; + QREAD = 0; + QCONFIG = 0; + QSIZE = 0; + PROT = 0; + CONFIG = 268435456; + LOCK = 0; + REGIONCFG = 0; + AXI_LIMIT0 = 0; + AXI_LIMIT1 = 0; + AXI_LIMIT2 = 0; + AXI_LIMIT3 = 0; + for (size_t i = 0; i < (sizeof(BASEP) / sizeof(BASEP[0])); ++i) + BASEP[i] = 0; + WD_STATUS = 0; + MAC_STATUS = 0; + AO_STATUS = 0; + DMA_STATUS0 = 0; + DMA_STATUS1 = 0; + CLKFORCE = 0; + DEBUG_ADDRESS = 0; + DEBUG_MISC = 0; + DEBUGCORE = 0; + DEBUG_BLOCK = 0; + PMCR = 8192; + PMCNTENSET = 0; + PMCNTENCLR = 0; + PMOVSSET = 0; + PMOVSCLR = 0; + PMINTSET = 0; + PMINTCLR = 0; + PMCCNTR = 0; + PMCCNTR_CFG = 0; + PMCAXI_CHAN = 0; + KERNEL_X = 0; + KERNEL_Y = 0; + KERNEL_W_M1 = 0; + KERNEL_H_M1 = 0; + OFM_CBLK_WIDTH_M1 = 0; + OFM_CBLK_HEIGHT_M1 = 0; + OFM_CBLK_DEPTH_M1 = 0; + IFM_CBLK_DEPTH_M1 = 0; + OFM_X = 0; + OFM_Y = 0; + OFM_Z = 0; + IFM_Z = 0; + PAD_TOP = 0; + PAD_LEFT = 0; + IFM_CBLK_WIDTH = 0; + IFM_CBLK_HEIGHT = 0; + DMA_IFM_SRC = 0; + DMA_IFM_DST = 0; + DMA_OFM_SRC = 0; + DMA_OFM_DST = 0; + DMA_WEIGHT_SRC = 0; + DMA_CMD_SRC = 0; + DMA_CMD_SIZE = 0; + DMA_M2M_SRC = 0; + DMA_M2M_DST = 0; + CURRENT_QREAD = 0; + DMA_SCALE_SRC = 0; + CURRENT_BLOCK = 0; + CURRENT_OP = 0; + CURRENT_CMD = 0; + for (size_t i = 0; i < (sizeof(PMEVCNTR) / sizeof(PMEVCNTR[0])); ++i) + PMEVCNTR[i] = 0; + for (size_t i = 0; i < (sizeof(PMEVTYPER) / sizeof(PMEVTYPER[0])); ++i) + PMEVTYPER[i] = 0; + for (size_t i = 0; i < (sizeof(SHARED_BUFFER) / sizeof(SHARED_BUFFER[0])); ++i) + SHARED_BUFFER[i] = 0; + IFM_PAD_TOP = 0; + IFM_PAD_LEFT = 0; + IFM_PAD_RIGHT = 0; + IFM_PAD_BOTTOM = 0; + IFM_DEPTH_M1 = 0; + IFM_PRECISION = 0; + IFM_UPSCALE = 0; + IFM_ZERO_POINT = 0; + IFM_WIDTH0_M1 = 0; + IFM_HEIGHT0_M1 = 0; + IFM_HEIGHT1_M1 = 0; + IFM_IB_END = 0; + IFM_REGION = 0; + OFM_WIDTH_M1 = 0; + OFM_HEIGHT_M1 = 0; + OFM_DEPTH_M1 = 0; + OFM_PRECISION = 0; + OFM_BLK_WIDTH_M1 = 0; + OFM_BLK_HEIGHT_M1 = 0; + OFM_BLK_DEPTH_M1 = 0; + OFM_ZERO_POINT = 0; + OFM_WIDTH0_M1 = 0; + OFM_HEIGHT0_M1 = 0; + OFM_HEIGHT1_M1 = 0; + OFM_REGION = 0; + KERNEL_WIDTH_M1 = 0; + KERNEL_HEIGHT_M1 = 0; + KERNEL_STRIDE = 0; + PARALLEL_MODE = 0; + ACC_FORMAT = 0; + ACTIVATION = 0; + ACTIVATION_MIN = 0; + ACTIVATION_MAX = 0; + WEIGHT_REGION = 0; + SCALE_REGION = 0; + AB_START = 0; + BLOCKDEP = 0; + DMA0_SRC_REGION = 0; + DMA0_DST_REGION = 0; + DMA0_SIZE0 = 0; + DMA0_SIZE1 = 0; + IFM2_BROADCAST = 0; + IFM2_SCALAR = 0; + IFM2_PRECISION = 0; + IFM2_ZERO_POINT = 0; + IFM2_WIDTH0_M1 = 0; + IFM2_HEIGHT0_M1 = 0; + IFM2_HEIGHT1_M1 = 0; + IFM2_IB_START = 0; + IFM2_REGION = 0; + IFM_BASE0 = 0; + IFM_BASE1 = 0; + IFM_BASE2 = 0; + IFM_BASE3 = 0; + IFM_STRIDE_X = 0; + IFM_STRIDE_Y = 0; + IFM_STRIDE_C = 0; + OFM_BASE0 = 0; + OFM_BASE1 = 0; + OFM_BASE2 = 0; + OFM_BASE3 = 0; + OFM_STRIDE_X = 0; + OFM_STRIDE_Y = 0; + OFM_STRIDE_C = 0; + WEIGHT_BASE = 0; + WEIGHT_LENGTH = 0; + SCALE_BASE = 0; + SCALE_LENGTH = 0; + OFM_SCALE = 0; + OFM_SCALE_SHIFT = 0; + OPA_SCALE = 0; + OPA_SCALE_SHIFT = 0; + OPB_SCALE = 0; + DMA0_SRC = 0; + DMA0_DST = 0; + DMA0_LEN = 0; + DMA0_SKIP0 = 0; + DMA0_SKIP1 = 0; + IFM2_BASE0 = 0; + IFM2_BASE1 = 0; + IFM2_BASE2 = 0; + IFM2_BASE3 = 0; + IFM2_STRIDE_X = 0; + IFM2_STRIDE_Y = 0; + IFM2_STRIDE_C = 0; + WEIGHT1_BASE = 0; + WEIGHT1_LENGTH = 0; + SCALE1_BASE = 0; + SCALE1_LENGTH = 0; + REVISION = 0; + PID4 = 4; + PID5 = 0; + PID6 = 0; + PID7 = 0; + PID0 = 129; + PID1 = 181; + PID2 = 11; + PID3 = 0; + CID0 = 13; + CID1 = 240; + CID2 = 5; + CID3 = 177; + } + uint32_t &operator[](const int addr_offset) + { + return reinterpret_cast(this)[addr_offset / 4]; + } + access_type_t get_access_type(uint32_t offset) + { + switch (offset) + { + case 0: + return access_type_t::RO; + case 4: + return access_type_t::RO; + case 8: + return access_type_t::RW; + case 12: + return access_type_t::RW; + case 16: + return access_type_t::RW; + case 24: + return access_type_t::RO; + case 28: + return access_type_t::RW; + case 32: + return access_type_t::RW; + case 36: + return access_type_t::RO; + case 40: + return access_type_t::RO; + case 44: + return access_type_t::RW; + case 60: + return access_type_t::RW; + case 64: + return access_type_t::RW; + case 68: + return access_type_t::RW; + case 72: + return access_type_t::RW; + case 76: + return access_type_t::RW; + case 128: + return access_type_t::RW; + case 136: + return access_type_t::RW; + case 144: + return access_type_t::RW; + case 152: + return access_type_t::RW; + case 160: + return access_type_t::RW; + case 168: + return access_type_t::RW; + case 176: + return access_type_t::RW; + case 184: + return access_type_t::RW; + case 256: + return access_type_t::RO; + case 260: + return access_type_t::RO; + case 264: + return access_type_t::RO; + case 272: + return access_type_t::RO; + case 276: + return access_type_t::RO; + case 320: + return access_type_t::RW; + case 324: + return access_type_t::RW; + case 328: + return access_type_t::RW; + case 332: + return access_type_t::RW; + case 336: + return access_type_t::RW; + case 384: + return access_type_t::RW; + case 388: + return access_type_t::RW; + case 392: + return access_type_t::RW; + case 396: + return access_type_t::RW; + case 400: + return access_type_t::RW; + case 404: + return access_type_t::RW; + case 408: + return access_type_t::RW; + case 416: + return access_type_t::RW; + case 424: + return access_type_t::RW; + case 428: + return access_type_t::RW; + case 512: + return access_type_t::RO; + case 516: + return access_type_t::RO; + case 520: + return access_type_t::RO; + case 524: + return access_type_t::RO; + case 528: + return access_type_t::RO; + case 532: + return access_type_t::RO; + case 536: + return access_type_t::RO; + case 540: + return access_type_t::RO; + case 544: + return access_type_t::RO; + case 548: + return access_type_t::RO; + case 552: + return access_type_t::RO; + case 556: + return access_type_t::RO; + case 560: + return access_type_t::RO; + case 564: + return access_type_t::RO; + case 568: + return access_type_t::RO; + case 572: + return access_type_t::RO; + case 576: + return access_type_t::RO; + case 584: + return access_type_t::RO; + case 588: + return access_type_t::RO; + case 592: + return access_type_t::RO; + case 600: + return access_type_t::RO; + case 608: + return access_type_t::RO; + case 616: + return access_type_t::RO; + case 620: + return access_type_t::RO; + case 628: + return access_type_t::RO; + case 636: + return access_type_t::RO; + case 640: + return access_type_t::RO; + case 692: + return access_type_t::RO; + case 696: + return access_type_t::RO; + case 700: + return access_type_t::RO; + case 768: + return access_type_t::RW; + case 772: + return access_type_t::RW; + case 776: + return access_type_t::RW; + case 780: + return access_type_t::RW; + case 896: + return access_type_t::RW; + case 900: + return access_type_t::RW; + case 904: + return access_type_t::RW; + case 908: + return access_type_t::RW; + case 1024: + return access_type_t::RW; + case 1028: + return access_type_t::RW; + case 1032: + return access_type_t::RW; + case 1036: + return access_type_t::RW; + case 1040: + return access_type_t::RW; + case 1044: + return access_type_t::RW; + case 1048: + return access_type_t::RW; + case 1052: + return access_type_t::RW; + case 1056: + return access_type_t::RW; + case 1060: + return access_type_t::RW; + case 1064: + return access_type_t::RW; + case 1068: + return access_type_t::RW; + case 1072: + return access_type_t::RW; + case 1076: + return access_type_t::RW; + case 1080: + return access_type_t::RW; + case 1084: + return access_type_t::RW; + case 1088: + return access_type_t::RW; + case 1092: + return access_type_t::RW; + case 1096: + return access_type_t::RW; + case 1100: + return access_type_t::RW; + case 1104: + return access_type_t::RW; + case 1108: + return access_type_t::RW; + case 1112: + return access_type_t::RW; + case 1116: + return access_type_t::RW; + case 1120: + return access_type_t::RW; + case 1124: + return access_type_t::RW; + case 1128: + return access_type_t::RW; + case 1132: + return access_type_t::RW; + case 1136: + return access_type_t::RW; + case 1140: + return access_type_t::RW; + case 1144: + return access_type_t::RW; + case 1148: + return access_type_t::RW; + case 1152: + return access_type_t::RW; + case 1156: + return access_type_t::RW; + case 1160: + return access_type_t::RW; + case 1164: + return access_type_t::RW; + case 1168: + return access_type_t::RW; + case 1172: + return access_type_t::RW; + case 1176: + return access_type_t::RW; + case 1180: + return access_type_t::RW; + case 1184: + return access_type_t::RW; + case 1188: + return access_type_t::RW; + case 1192: + return access_type_t::RW; + case 1196: + return access_type_t::RW; + case 1200: + return access_type_t::RW; + case 1204: + return access_type_t::RW; + case 1208: + return access_type_t::RW; + case 1212: + return access_type_t::RW; + case 1216: + return access_type_t::RW; + case 1220: + return access_type_t::RW; + case 1224: + return access_type_t::RW; + case 1228: + return access_type_t::RW; + case 1232: + return access_type_t::RW; + case 1236: + return access_type_t::RW; + case 1240: + return access_type_t::RW; + case 1244: + return access_type_t::RW; + case 1248: + return access_type_t::RW; + case 1252: + return access_type_t::RW; + case 1256: + return access_type_t::RW; + case 1260: + return access_type_t::RW; + case 1264: + return access_type_t::RW; + case 1268: + return access_type_t::RW; + case 1272: + return access_type_t::RW; + case 1276: + return access_type_t::RW; + case 1280: + return access_type_t::RW; + case 1284: + return access_type_t::RW; + case 1288: + return access_type_t::RW; + case 1292: + return access_type_t::RW; + case 1296: + return access_type_t::RW; + case 1300: + return access_type_t::RW; + case 1304: + return access_type_t::RW; + case 1308: + return access_type_t::RW; + case 1312: + return access_type_t::RW; + case 1316: + return access_type_t::RW; + case 1320: + return access_type_t::RW; + case 1324: + return access_type_t::RW; + case 1328: + return access_type_t::RW; + case 1332: + return access_type_t::RW; + case 1336: + return access_type_t::RW; + case 1340: + return access_type_t::RW; + case 1344: + return access_type_t::RW; + case 1348: + return access_type_t::RW; + case 1352: + return access_type_t::RW; + case 1356: + return access_type_t::RW; + case 1360: + return access_type_t::RW; + case 1364: + return access_type_t::RW; + case 1368: + return access_type_t::RW; + case 1372: + return access_type_t::RW; + case 1376: + return access_type_t::RW; + case 1380: + return access_type_t::RW; + case 1384: + return access_type_t::RW; + case 1388: + return access_type_t::RW; + case 1392: + return access_type_t::RW; + case 1396: + return access_type_t::RW; + case 1400: + return access_type_t::RW; + case 1404: + return access_type_t::RW; + case 1408: + return access_type_t::RW; + case 1412: + return access_type_t::RW; + case 1416: + return access_type_t::RW; + case 1420: + return access_type_t::RW; + case 1424: + return access_type_t::RW; + case 1428: + return access_type_t::RW; + case 1432: + return access_type_t::RW; + case 1436: + return access_type_t::RW; + case 1440: + return access_type_t::RW; + case 1444: + return access_type_t::RW; + case 1448: + return access_type_t::RW; + case 1452: + return access_type_t::RW; + case 1456: + return access_type_t::RW; + case 1460: + return access_type_t::RW; + case 1464: + return access_type_t::RW; + case 1468: + return access_type_t::RW; + case 1472: + return access_type_t::RW; + case 1476: + return access_type_t::RW; + case 1480: + return access_type_t::RW; + case 1484: + return access_type_t::RW; + case 1488: + return access_type_t::RW; + case 1492: + return access_type_t::RW; + case 1496: + return access_type_t::RW; + case 1500: + return access_type_t::RW; + case 1504: + return access_type_t::RW; + case 1508: + return access_type_t::RW; + case 1512: + return access_type_t::RW; + case 1516: + return access_type_t::RW; + case 1520: + return access_type_t::RW; + case 1524: + return access_type_t::RW; + case 1528: + return access_type_t::RW; + case 1532: + return access_type_t::RW; + case 1536: + return access_type_t::RW; + case 1540: + return access_type_t::RW; + case 1544: + return access_type_t::RW; + case 1548: + return access_type_t::RW; + case 1552: + return access_type_t::RW; + case 1556: + return access_type_t::RW; + case 1560: + return access_type_t::RW; + case 1564: + return access_type_t::RW; + case 1568: + return access_type_t::RW; + case 1572: + return access_type_t::RW; + case 1576: + return access_type_t::RW; + case 1580: + return access_type_t::RW; + case 1584: + return access_type_t::RW; + case 1588: + return access_type_t::RW; + case 1592: + return access_type_t::RW; + case 1596: + return access_type_t::RW; + case 1600: + return access_type_t::RW; + case 1604: + return access_type_t::RW; + case 1608: + return access_type_t::RW; + case 1612: + return access_type_t::RW; + case 1616: + return access_type_t::RW; + case 1620: + return access_type_t::RW; + case 1624: + return access_type_t::RW; + case 1628: + return access_type_t::RW; + case 1632: + return access_type_t::RW; + case 1636: + return access_type_t::RW; + case 1640: + return access_type_t::RW; + case 1644: + return access_type_t::RW; + case 1648: + return access_type_t::RW; + case 1652: + return access_type_t::RW; + case 1656: + return access_type_t::RW; + case 1660: + return access_type_t::RW; + case 1664: + return access_type_t::RW; + case 1668: + return access_type_t::RW; + case 1672: + return access_type_t::RW; + case 1676: + return access_type_t::RW; + case 1680: + return access_type_t::RW; + case 1684: + return access_type_t::RW; + case 1688: + return access_type_t::RW; + case 1692: + return access_type_t::RW; + case 1696: + return access_type_t::RW; + case 1700: + return access_type_t::RW; + case 1704: + return access_type_t::RW; + case 1708: + return access_type_t::RW; + case 1712: + return access_type_t::RW; + case 1716: + return access_type_t::RW; + case 1720: + return access_type_t::RW; + case 1724: + return access_type_t::RW; + case 1728: + return access_type_t::RW; + case 1732: + return access_type_t::RW; + case 1736: + return access_type_t::RW; + case 1740: + return access_type_t::RW; + case 1744: + return access_type_t::RW; + case 1748: + return access_type_t::RW; + case 1752: + return access_type_t::RW; + case 1756: + return access_type_t::RW; + case 1760: + return access_type_t::RW; + case 1764: + return access_type_t::RW; + case 1768: + return access_type_t::RW; + case 1772: + return access_type_t::RW; + case 1776: + return access_type_t::RW; + case 1780: + return access_type_t::RW; + case 1784: + return access_type_t::RW; + case 1788: + return access_type_t::RW; + case 1792: + return access_type_t::RW; + case 1796: + return access_type_t::RW; + case 1800: + return access_type_t::RW; + case 1804: + return access_type_t::RW; + case 1808: + return access_type_t::RW; + case 1812: + return access_type_t::RW; + case 1816: + return access_type_t::RW; + case 1820: + return access_type_t::RW; + case 1824: + return access_type_t::RW; + case 1828: + return access_type_t::RW; + case 1832: + return access_type_t::RW; + case 1836: + return access_type_t::RW; + case 1840: + return access_type_t::RW; + case 1844: + return access_type_t::RW; + case 1848: + return access_type_t::RW; + case 1852: + return access_type_t::RW; + case 1856: + return access_type_t::RW; + case 1860: + return access_type_t::RW; + case 1864: + return access_type_t::RW; + case 1868: + return access_type_t::RW; + case 1872: + return access_type_t::RW; + case 1876: + return access_type_t::RW; + case 1880: + return access_type_t::RW; + case 1884: + return access_type_t::RW; + case 1888: + return access_type_t::RW; + case 1892: + return access_type_t::RW; + case 1896: + return access_type_t::RW; + case 1900: + return access_type_t::RW; + case 1904: + return access_type_t::RW; + case 1908: + return access_type_t::RW; + case 1912: + return access_type_t::RW; + case 1916: + return access_type_t::RW; + case 1920: + return access_type_t::RW; + case 1924: + return access_type_t::RW; + case 1928: + return access_type_t::RW; + case 1932: + return access_type_t::RW; + case 1936: + return access_type_t::RW; + case 1940: + return access_type_t::RW; + case 1944: + return access_type_t::RW; + case 1948: + return access_type_t::RW; + case 1952: + return access_type_t::RW; + case 1956: + return access_type_t::RW; + case 1960: + return access_type_t::RW; + case 1964: + return access_type_t::RW; + case 1968: + return access_type_t::RW; + case 1972: + return access_type_t::RW; + case 1976: + return access_type_t::RW; + case 1980: + return access_type_t::RW; + case 1984: + return access_type_t::RW; + case 1988: + return access_type_t::RW; + case 1992: + return access_type_t::RW; + case 1996: + return access_type_t::RW; + case 2000: + return access_type_t::RW; + case 2004: + return access_type_t::RW; + case 2008: + return access_type_t::RW; + case 2012: + return access_type_t::RW; + case 2016: + return access_type_t::RW; + case 2020: + return access_type_t::RW; + case 2024: + return access_type_t::RW; + case 2028: + return access_type_t::RW; + case 2032: + return access_type_t::RW; + case 2036: + return access_type_t::RW; + case 2040: + return access_type_t::RW; + case 2044: + return access_type_t::RW; + case 2048: + return access_type_t::RW; + case 2052: + return access_type_t::RW; + case 2056: + return access_type_t::RW; + case 2060: + return access_type_t::RW; + case 2064: + return access_type_t::RW; + case 2068: + return access_type_t::RW; + case 2076: + return access_type_t::RW; + case 2084: + return access_type_t::RW; + case 2088: + return access_type_t::RW; + case 2092: + return access_type_t::RW; + case 2096: + return access_type_t::RW; + case 2100: + return access_type_t::RW; + case 2108: + return access_type_t::RW; + case 2116: + return access_type_t::RW; + case 2120: + return access_type_t::RW; + case 2124: + return access_type_t::RW; + case 2128: + return access_type_t::RW; + case 2132: + return access_type_t::RW; + case 2136: + return access_type_t::RW; + case 2140: + return access_type_t::RW; + case 2144: + return access_type_t::RW; + case 2152: + return access_type_t::RW; + case 2156: + return access_type_t::RW; + case 2160: + return access_type_t::RW; + case 2172: + return access_type_t::RW; + case 2176: + return access_type_t::RW; + case 2180: + return access_type_t::RW; + case 2184: + return access_type_t::RW; + case 2188: + return access_type_t::RW; + case 2192: + return access_type_t::RW; + case 2196: + return access_type_t::RW; + case 2200: + return access_type_t::RW; + case 2204: + return access_type_t::RW; + case 2208: + return access_type_t::RW; + case 2212: + return access_type_t::RW; + case 2228: + return access_type_t::RW; + case 2236: + return access_type_t::RW; + case 2240: + return access_type_t::RW; + case 2244: + return access_type_t::RW; + case 2248: + return access_type_t::RW; + case 2252: + return access_type_t::RW; + case 2304: + return access_type_t::RW; + case 2308: + return access_type_t::RW; + case 2324: + return access_type_t::RW; + case 2340: + return access_type_t::RW; + case 2344: + return access_type_t::RW; + case 2348: + return access_type_t::RW; + case 2352: + return access_type_t::RW; + case 2356: + return access_type_t::RW; + case 2364: + return access_type_t::RW; + case 2560: + return access_type_t::RW; + case 2568: + return access_type_t::RW; + case 2576: + return access_type_t::RW; + case 2584: + return access_type_t::RW; + case 2592: + return access_type_t::RW; + case 2600: + return access_type_t::RW; + case 2608: + return access_type_t::RW; + case 2624: + return access_type_t::RW; + case 2632: + return access_type_t::RW; + case 2640: + return access_type_t::RW; + case 2648: + return access_type_t::RW; + case 2656: + return access_type_t::RW; + case 2664: + return access_type_t::RW; + case 2672: + return access_type_t::RW; + case 2688: + return access_type_t::RW; + case 2696: + return access_type_t::RW; + case 2704: + return access_type_t::RW; + case 2712: + return access_type_t::RW; + case 2720: + return access_type_t::RW; + case 2724: + return access_type_t::RW; + case 2728: + return access_type_t::RW; + case 2732: + return access_type_t::RW; + case 2736: + return access_type_t::RW; + case 2752: + return access_type_t::RW; + case 2760: + return access_type_t::RW; + case 2768: + return access_type_t::RW; + case 2776: + return access_type_t::RW; + case 2784: + return access_type_t::RW; + case 2816: + return access_type_t::RW; + case 2824: + return access_type_t::RW; + case 2832: + return access_type_t::RW; + case 2840: + return access_type_t::RW; + case 2848: + return access_type_t::RW; + case 2856: + return access_type_t::RW; + case 2864: + return access_type_t::RW; + case 2880: + return access_type_t::RW; + case 2888: + return access_type_t::RW; + case 2896: + return access_type_t::RW; + case 2904: + return access_type_t::RW; + case 4032: + return access_type_t::RO; + case 4048: + return access_type_t::RO; + case 4052: + return access_type_t::RO; + case 4056: + return access_type_t::RO; + case 4060: + return access_type_t::RO; + case 4064: + return access_type_t::RO; + case 4068: + return access_type_t::RO; + case 4072: + return access_type_t::RO; + case 4076: + return access_type_t::RO; + case 4080: + return access_type_t::RO; + case 4084: + return access_type_t::RO; + case 4088: + return access_type_t::RO; + case 4092: + return access_type_t::RO; + default: + return access_type_t::RO; + } + } +#endif +}; + +#ifdef __cplusplus +struct isa +{ +#ifdef NPU_DISASSEMBLE + static int disassemble(const uint32_t *in, + std::string &op, + std::vector> &fields) + { + switch (*in & 0xffff) + { + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP): + { + const npu_op_stop_t &v = *reinterpret_cast(in); + op = "NPU_OP_STOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ): + { + const npu_op_irq_t &v = *reinterpret_cast(in); + op = "NPU_OP_IRQ"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV): + { + const npu_op_conv_t &v = *reinterpret_cast(in); + op = "NPU_OP_CONV"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE): + { + const npu_op_depthwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_DEPTHWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL): + { + const npu_op_pool_t &v = *reinterpret_cast(in); + op = "NPU_OP_POOL"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE): + { + const npu_op_elementwise_t &v = *reinterpret_cast(in); + op = "NPU_OP_ELEMENTWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START): + { + const npu_op_dma_start_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT): + { + const npu_op_dma_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_DMA_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT): + { + const npu_op_kernel_wait_t &v = *reinterpret_cast(in); + op = "NPU_OP_KERNEL_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK): + { + const npu_op_pmu_mask_t &v = *reinterpret_cast(in); + op = "NPU_OP_PMU_MASK"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP): + { + const npu_set_ifm_pad_top_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_TOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT): + { + const npu_set_ifm_pad_left_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_LEFT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT): + { + const npu_set_ifm_pad_right_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_RIGHT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM): + { + const npu_set_ifm_pad_bottom_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_BOTTOM"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1): + { + const npu_set_ifm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION): + { + const npu_set_ifm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE): + { + const npu_set_ifm_upscale_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_UPSCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT): + { + const npu_set_ifm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1): + { + const npu_set_ifm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1): + { + const npu_set_ifm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1): + { + const npu_set_ifm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END): + { + const npu_set_ifm_ib_end_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_IB_END"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION): + { + const npu_set_ifm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1): + { + const npu_set_ofm_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1): + { + const npu_set_ofm_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1): + { + const npu_set_ofm_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION): + { + const npu_set_ofm_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1): + { + const npu_set_ofm_blk_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1): + { + const npu_set_ofm_blk_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1): + { + const npu_set_ofm_blk_depth_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT): + { + const npu_set_ofm_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1): + { + const npu_set_ofm_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1): + { + const npu_set_ofm_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1): + { + const npu_set_ofm_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION): + { + const npu_set_ofm_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1): + { + const npu_set_kernel_width_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1): + { + const npu_set_kernel_height_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE): + { + const npu_set_kernel_stride_t &v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_STRIDE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE): + { + const npu_set_parallel_mode_t &v = *reinterpret_cast(in); + op = "NPU_SET_PARALLEL_MODE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT): + { + const npu_set_acc_format_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACC_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION): + { + const npu_set_activation_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN): + { + const npu_set_activation_min_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MIN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX): + { + const npu_set_activation_max_t &v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION): + { + const npu_set_weight_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION): + { + const npu_set_scale_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START): + { + const npu_set_ab_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_AB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP): + { + const npu_set_blockdep_t &v = *reinterpret_cast(in); + op = "NPU_SET_BLOCKDEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION): + { + const npu_set_dma0_src_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION): + { + const npu_set_dma0_dst_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0): + { + const npu_set_dma0_size0_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1): + { + const npu_set_dma0_size1_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST): + { + const npu_set_ifm2_broadcast_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR): + { + const npu_set_ifm2_scalar_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_SCALAR"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION): + { + const npu_set_ifm2_precision_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT): + { + const npu_set_ifm2_zero_point_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1): + { + const npu_set_ifm2_width0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1): + { + const npu_set_ifm2_height0_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1): + { + const npu_set_ifm2_height1_m1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START): + { + const npu_set_ifm2_ib_start_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_IB_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION): + { + const npu_set_ifm2_region_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0): + { + const npu_set_ifm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1): + { + const npu_set_ifm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2): + { + const npu_set_ifm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3): + { + const npu_set_ifm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X): + { + const npu_set_ifm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y): + { + const npu_set_ifm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C): + { + const npu_set_ifm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0): + { + const npu_set_ofm_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1): + { + const npu_set_ofm_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2): + { + const npu_set_ofm_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3): + { + const npu_set_ofm_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X): + { + const npu_set_ofm_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y): + { + const npu_set_ofm_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C): + { + const npu_set_ofm_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE): + { + const npu_set_weight_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH): + { + const npu_set_weight_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE): + { + const npu_set_scale_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH): + { + const npu_set_scale_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE): + { + const npu_set_ofm_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE): + { + const npu_set_opa_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPA_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE): + { + const npu_set_opb_scale_t &v = *reinterpret_cast(in); + op = "NPU_SET_OPB_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC): + { + const npu_set_dma0_src_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST): + { + const npu_set_dma0_dst_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN): + { + const npu_set_dma0_len_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_LEN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0): + { + const npu_set_dma0_skip0_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SKIP0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1): + { + const npu_set_dma0_skip1_t &v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SKIP1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0): + { + const npu_set_ifm2_base0_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1): + { + const npu_set_ifm2_base1_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2): + { + const npu_set_ifm2_base2_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3): + { + const npu_set_ifm2_base3_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X): + { + const npu_set_ifm2_stride_x_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y): + { + const npu_set_ifm2_stride_y_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C): + { + const npu_set_ifm2_stride_c_t &v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE): + { + const npu_set_weight1_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH): + { + const npu_set_weight1_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE): + { + const npu_set_scale1_base_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE1_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | + static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH): + { + const npu_set_scale1_length_t &v = *reinterpret_cast(in); + op = "NPU_SET_SCALE1_LENGTH"; + v.disassemble(fields); + break; + } + } + return (*in & (3 << 14)) != 0 ? 2 : 1; + } +#endif +#endif + // Signal the end of command stream + struct npu_op_stop_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_stop_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_stop_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_stop_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_stop_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_stop_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // Raises an IRQ to the host + struct npu_op_irq_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mask : 16; // Encoding for 16-bit mask value +#ifdef __cplusplus + public: + npu_op_irq_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(_mask & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_op_irq_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mask(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_irq_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_irq_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_irq_t &set_mask(uint32_t value) + { + mask = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif + }; + // 2D convolution + struct npu_op_conv_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_conv_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_conv_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_conv_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Depth-wise 2D convolution + struct npu_op_depthwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_depthwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_depthwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_depthwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Pooling + struct npu_op_pool_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pooling_mode : 3; // Pooling mode + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_op_pool_t(NPU_NAMESPACE::pooling_mode _pooling_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(static_cast(_pooling_mode) & ((1U << 3) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_pool_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pooling_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pool_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pool_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pooling_mode get_pooling_mode() const + { + return static_cast(pooling_mode); + } + CONSTEXPR npu_op_pool_t &set_pooling_mode(NPU_NAMESPACE::pooling_mode value) + { + pooling_mode = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "pooling_mode", + (pooling_mode < (sizeof(pooling_mode_str) / sizeof(pooling_mode_str[0])) ? + pooling_mode_str[pooling_mode] : + "****"))); + } +#endif +#endif + }; + // Elementwise operation + struct npu_op_elementwise_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t elementwise_mode : 6; // Elementwise mode + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_op_elementwise_t(NPU_NAMESPACE::elementwise_mode _elementwise_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(static_cast(_elementwise_mode) & ((1U << 6) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_elementwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), elementwise_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_elementwise_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_elementwise_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::elementwise_mode get_elementwise_mode() const + { + return static_cast(elementwise_mode); + } + CONSTEXPR npu_op_elementwise_t &set_elementwise_mode(NPU_NAMESPACE::elementwise_mode value) + { + elementwise_mode = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "elementwise_mode", + (elementwise_mode < (sizeof(elementwise_mode_str) / sizeof(elementwise_mode_str[0])) ? + elementwise_mode_str[elementwise_mode] : + "****"))); + } +#endif +#endif + }; + // Queue new DMA for the given channel + struct npu_op_dma_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; +#ifdef __cplusplus + public: + CONSTEXPR npu_op_dma_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const {} +#endif +#endif + }; + // Wait for the DMA channel to have k or fewer active descriptors outstanding + struct npu_op_dma_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t k : 4; // Number of outstanding descriptors + uint32_t reserved1 : 12; +#ifdef __cplusplus + public: + npu_op_dma_wait_t(uint32_t _k) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(_k & ((1U << 4) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_dma_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), k(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_k() const + { + return static_cast(k); + } + CONSTEXPR npu_op_dma_wait_t &set_k(uint32_t value) + { + k = static_cast(value) & ((1U << 4) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("k", std::to_string(k))); + } +#endif +#endif + }; + // Wait for n or fewer kernel operations to be remaining + struct npu_op_kernel_wait_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t n : 2; // Number of kernel operations in range 0-3 + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_op_kernel_wait_t(uint32_t _n) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(_n & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_op_kernel_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), n(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_kernel_wait_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_kernel_wait_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_n() const + { + return static_cast(n); + } + CONSTEXPR npu_op_kernel_wait_t &set_n(uint32_t value) + { + n = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("n", std::to_string(n))); + } +#endif +#endif + }; + // Enable or disable PMU counting (debug feature only) + struct npu_op_pmu_mask_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t enable : 1; // Enable or disable PMU mask + uint32_t reserved1 : 15; +#ifdef __cplusplus + public: + npu_op_pmu_mask_t(uint32_t _enable) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(_enable & ((1U << 1) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_op_pmu_mask_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), enable(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pmu_mask_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pmu_mask_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_enable() const + { + return static_cast(enable); + } + CONSTEXPR npu_op_pmu_mask_t &set_enable(uint32_t value) + { + enable = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("enable", std::to_string(enable))); + } +#endif +#endif + }; + // IFM top pad + struct npu_set_ifm_pad_top_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM top pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_top_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_top_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_top_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM left pad + struct npu_set_ifm_pad_left_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 7; // IFM left pad + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ifm_pad_left_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 7) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_left_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_left_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM right pad + struct npu_set_ifm_pad_right_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM right pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_right_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_right_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_right_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // IFM bottom pad + struct npu_set_ifm_pad_bottom_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t pad : 8; // IFM bottom pad. Max value is 128 + uint32_t reserved1 : 8; +#ifdef __cplusplus + public: + npu_set_ifm_pad_bottom_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(_pad & ((1U << 8) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_pad_bottom_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), pad(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_bottom_t &set_pad(uint32_t value) + { + pad = static_cast(value) & ((1U << 8) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif + }; + // Number of input channels for convolution + struct npu_set_ifm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Number of input channels for convolution +#ifdef __cplusplus + public: + npu_set_ifm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ifm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // IFM Precision + struct npu_set_ifm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t scale_mode : 2; // IFM scale mode + uint32_t reserved3 : 4; + uint32_t round_mode : 2; // IFM round mode +#ifdef __cplusplus + public: + npu_set_ifm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ifm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 2) - 1)), reserved3(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ifm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), scale_mode(0), reserved3(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_scale_mode(NPU_NAMESPACE::ifm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ifm_scale_mode_str) / sizeof(ifm_scale_mode_str[0])) ? + ifm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // IFM upscale mode + struct npu_set_ifm_upscale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t mode : 2; // IFM upscale mode + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_ifm_upscale_t(NPU_NAMESPACE::ifm_upscale_mode _mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(static_cast(_mode) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_ifm_upscale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_upscale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_upscale_mode get_mode() const + { + return static_cast(mode); + } + CONSTEXPR npu_set_ifm_upscale_t &set_mode(NPU_NAMESPACE::ifm_upscale_mode value) + { + mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "mode", + (mode < (sizeof(ifm_upscale_mode_str) / sizeof(ifm_upscale_mode_str[0])) ? ifm_upscale_mode_str[mode] : + "****"))); + } +#endif +#endif + }; + // IFM zero point + struct npu_set_ifm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM Tile 0 and tile 2 width + struct npu_set_ifm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM Tile 0 height + struct npu_set_ifm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM Tile 1 height + struct npu_set_ifm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // End of IB0,IB1 buffers + struct npu_set_ifm_ib_end_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_end : 6; // End of IB0,IB1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm_ib_end_t(uint32_t _ib_end) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(_ib_end & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm_ib_end_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_end(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_IB_END); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_end() const + { + return static_cast(ib_end); + } + CONSTEXPR npu_set_ifm_ib_end_t &set_ib_end(uint32_t value) + { + ib_end = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_end", std::to_string(ib_end))); + } +#endif +#endif + }; + // Index n for IFM access + struct npu_set_ifm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number n + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ifm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Output feature map width + struct npu_set_ofm_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Output feature map width +#ifdef __cplusplus + public: + npu_set_ofm_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Output feature map height + struct npu_set_ofm_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Output feature map height +#ifdef __cplusplus + public: + npu_set_ofm_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Output feature map depth + struct npu_set_ofm_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 16; // Output feature map depth +#ifdef __cplusplus + public: + npu_set_ofm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM Precision + struct npu_set_ofm_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // OFM type + uint32_t activation_precision : 2; // OFM precision + uint32_t reserved1 : 3; + uint32_t activation_format : 2; // OFM format + uint32_t scale_mode : 1; // OFM scale mode + uint32_t reserved2 : 5; + uint32_t round_mode : 2; // OFM round mode +#ifdef __cplusplus + public: + npu_set_ofm_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format, + NPU_NAMESPACE::ofm_scale_mode _scale_mode, + NPU_NAMESPACE::round_mode _round_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved1(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), + scale_mode(static_cast(_scale_mode) & ((1U << 1) - 1)), reserved2(0), + round_mode(static_cast(_round_mode) & ((1U << 2) - 1)) + { + } + CONSTEXPR npu_set_ofm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), + activation_precision(0), reserved1(0), activation_format(0), scale_mode(0), reserved2(0), round_mode(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ofm_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ofm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_scale_mode(NPU_NAMESPACE::ofm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ofm_precision_t &set_round_mode(NPU_NAMESPACE::round_mode value) + { + round_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + fields.push_back(std::make_pair( + "scale_mode", + (scale_mode < (sizeof(ofm_scale_mode_str) / sizeof(ofm_scale_mode_str[0])) ? + ofm_scale_mode_str[scale_mode] : + "****"))); + fields.push_back(std::make_pair( + "round_mode", + (round_mode < (sizeof(round_mode_str) / sizeof(round_mode_str[0])) ? round_mode_str[round_mode] : + "****"))); + } +#endif +#endif + }; + // OFM block width + struct npu_set_ofm_blk_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 6; // OFM block width + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ofm_blk_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM block height + struct npu_set_ofm_blk_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 5; // OFM block height + uint32_t reserved1 : 11; +#ifdef __cplusplus + public: + npu_set_ofm_blk_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 5) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 5) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM block depth + struct npu_set_ofm_blk_depth_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t depth_m1 : 7; // OFM block depth + uint32_t reserved1 : 9; +#ifdef __cplusplus + public: + npu_set_ofm_blk_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(_depth_m1 & ((1U << 7) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), depth_m1(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t &set_depth_m1(uint32_t value) + { + depth_m1 = static_cast(value) & ((1U << 7) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif + }; + // OFM zero point + struct npu_set_ofm_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ofm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ofm_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // OFM Tile 0 and tile 2 width + struct npu_set_ofm_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // OFM Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ofm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // OFM Tile 0 height + struct npu_set_ofm_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 0 height +#ifdef __cplusplus + public: + npu_set_ofm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // OFM Tile 1 height + struct npu_set_ofm_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // OFM Tile 1 height +#ifdef __cplusplus + public: + npu_set_ofm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ofm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Index n for OFM access + struct npu_set_ofm_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for OFM access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ofm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ofm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ofm_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Kernel width + struct npu_set_kernel_width_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // Kernel width +#ifdef __cplusplus + public: + npu_set_kernel_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_kernel_width_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // Kernel height + struct npu_set_kernel_height_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // Kernel height +#ifdef __cplusplus + public: + npu_set_kernel_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_kernel_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_kernel_height_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Kernel stride + struct npu_set_kernel_stride_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t stride_x_lsb : 1; // Stride x LSB. (kernel_x_stride - 1)[0] + uint32_t stride_y_lsb : 1; // Stride y LSB. (kernel_y_stride - 1)[0] + uint32_t weight_order : 1; // Weight ordering mode + uint32_t dilation_x : 1; // Kernel x dilation + uint32_t dilation_y : 1; // Kernel y dilation + uint32_t decomposition : 1; // Kernel decomposition + uint32_t stride_x_msb : 1; // Stride x MSB. (kernel_x_stride - 1) >> 1 + uint32_t reserved1 : 2; + uint32_t stride_y_msb : 1; // Stride y MSB. (kernel_y_stride - 1) >> 1 + uint32_t reserved2 : 6; +#ifdef __cplusplus + public: + npu_set_kernel_stride_t(uint32_t _stride_x_lsb, + uint32_t _stride_y_lsb, + NPU_NAMESPACE::weight_order _weight_order, + NPU_NAMESPACE::kernel_dilation _dilation_x, + NPU_NAMESPACE::kernel_dilation _dilation_y, + NPU_NAMESPACE::kernel_decomposition _decomposition, + uint32_t _stride_x_msb, + uint32_t _stride_y_msb) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(_stride_x_lsb & ((1U << 1) - 1)), stride_y_lsb(_stride_y_lsb & ((1U << 1) - 1)), + weight_order(static_cast(_weight_order) & ((1U << 1) - 1)), + dilation_x(static_cast(_dilation_x) & ((1U << 1) - 1)), + dilation_y(static_cast(_dilation_y) & ((1U << 1) - 1)), + decomposition(static_cast(_decomposition) & ((1U << 1) - 1)), + stride_x_msb(_stride_x_msb & ((1U << 1) - 1)), reserved1(0), stride_y_msb(_stride_y_msb & ((1U << 1) - 1)), + reserved2(0) + { + } + CONSTEXPR npu_set_kernel_stride_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), stride_x_lsb(0), stride_y_lsb(0), + weight_order(0), dilation_x(0), dilation_y(0), decomposition(0), stride_x_msb(0), reserved1(0), + stride_y_msb(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_stride_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_stride_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_lsb() const + { + return static_cast(stride_x_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_lsb(uint32_t value) + { + stride_x_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_lsb() const + { + return static_cast(stride_y_lsb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_lsb(uint32_t value) + { + stride_y_lsb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_order get_weight_order() const + { + return static_cast(weight_order); + } + CONSTEXPR npu_set_kernel_stride_t &set_weight_order(NPU_NAMESPACE::weight_order value) + { + weight_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_x() const + { + return static_cast(dilation_x); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_x(NPU_NAMESPACE::kernel_dilation value) + { + dilation_x = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_y() const + { + return static_cast(dilation_y); + } + CONSTEXPR npu_set_kernel_stride_t &set_dilation_y(NPU_NAMESPACE::kernel_dilation value) + { + dilation_y = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_decomposition get_decomposition() const + { + return static_cast(decomposition); + } + CONSTEXPR npu_set_kernel_stride_t &set_decomposition(NPU_NAMESPACE::kernel_decomposition value) + { + decomposition = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_msb() const + { + return static_cast(stride_x_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_x_msb(uint32_t value) + { + stride_x_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR uint32_t get_stride_y_msb() const + { + return static_cast(stride_y_msb); + } + CONSTEXPR npu_set_kernel_stride_t &set_stride_y_msb(uint32_t value) + { + stride_y_msb = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("stride_x_lsb", std::to_string(stride_x_lsb))); + fields.push_back(std::make_pair("stride_y_lsb", std::to_string(stride_y_lsb))); + fields.push_back(std::make_pair( + "weight_order", + (weight_order < (sizeof(weight_order_str) / sizeof(weight_order_str[0])) ? + weight_order_str[weight_order] : + "****"))); + fields.push_back(std::make_pair( + "dilation_x", + (dilation_x < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_x] : + "****"))); + fields.push_back(std::make_pair( + "dilation_y", + (dilation_y < (sizeof(kernel_dilation_str) / sizeof(kernel_dilation_str[0])) ? + kernel_dilation_str[dilation_y] : + "****"))); + fields.push_back(std::make_pair( + "decomposition", + (decomposition < (sizeof(kernel_decomposition_str) / sizeof(kernel_decomposition_str[0])) ? + kernel_decomposition_str[decomposition] : + "****"))); + fields.push_back(std::make_pair("stride_x_msb", std::to_string(stride_x_msb))); + fields.push_back(std::make_pair("stride_y_msb", std::to_string(stride_y_msb))); + } +#endif +#endif + }; + // Multi-core parallel mode + struct npu_set_parallel_mode_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t parallel_mode : 1; // Multi-core parallel mode + uint32_t reserved1 : 15; +#ifdef __cplusplus + public: + npu_set_parallel_mode_t(NPU_NAMESPACE::parallel_mode _parallel_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + parallel_mode(static_cast(_parallel_mode) & ((1U << 1) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_parallel_mode_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), parallel_mode(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_PARALLEL_MODE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_parallel_mode_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_parallel_mode_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::parallel_mode get_parallel_mode() const + { + return static_cast(parallel_mode); + } + CONSTEXPR npu_set_parallel_mode_t &set_parallel_mode(NPU_NAMESPACE::parallel_mode value) + { + parallel_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "parallel_mode", + (parallel_mode < (sizeof(parallel_mode_str) / sizeof(parallel_mode_str[0])) ? + parallel_mode_str[parallel_mode] : + "****"))); + } +#endif +#endif + }; + // Accumulator format + struct npu_set_acc_format_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t acc_format : 2; // Accumulator format + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_acc_format_t(NPU_NAMESPACE::acc_format _acc_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(static_cast(_acc_format) & ((1U << 2) - 1)), reserved1(0) + { + } + CONSTEXPR npu_set_acc_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), acc_format(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_acc_format_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_acc_format_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_format get_acc_format() const + { + return static_cast(acc_format); + } + CONSTEXPR npu_set_acc_format_t &set_acc_format(NPU_NAMESPACE::acc_format value) + { + acc_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "acc_format", + (acc_format < (sizeof(acc_format_str) / sizeof(acc_format_str[0])) ? acc_format_str[acc_format] : + "****"))); + } +#endif +#endif + }; + // Activation function and clip range + struct npu_set_activation_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_function : 5; // Activation function (before table lookup) + uint32_t reserved1 : 7; + uint32_t activation_clip_range : 3; // Activation clip range. This must be set to 0 if table lookup is not used + uint32_t reserved2 : 1; +#ifdef __cplusplus + public: + npu_set_activation_t(NPU_NAMESPACE::activation_function _activation_function, + NPU_NAMESPACE::activation_clip_range _activation_clip_range) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(static_cast(_activation_function) & ((1U << 5) - 1)), reserved1(0), + activation_clip_range(static_cast(_activation_clip_range) & ((1U << 3) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_activation_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_function(0), reserved1(0), + activation_clip_range(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_function get_activation_function() const + { + return static_cast(activation_function); + } + CONSTEXPR npu_set_activation_t &set_activation_function(NPU_NAMESPACE::activation_function value) + { + activation_function = static_cast(value) & ((1U << 5) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_clip_range get_activation_clip_range() const + { + return static_cast(activation_clip_range); + } + CONSTEXPR npu_set_activation_t &set_activation_clip_range(NPU_NAMESPACE::activation_clip_range value) + { + activation_clip_range = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_function", + (activation_function < (sizeof(activation_function_str) / sizeof(activation_function_str[0])) ? + activation_function_str[activation_function] : + "****"))); + fields.push_back(std::make_pair( + "activation_clip_range", + (activation_clip_range < (sizeof(activation_clip_range_str) / sizeof(activation_clip_range_str[0])) ? + activation_clip_range_str[activation_clip_range] : + "****"))); + } +#endif +#endif + }; + // Lower bound clip + struct npu_set_activation_min_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_min_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_min_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_min_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_min_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_min_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Upper bound clip + struct npu_set_activation_max_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t clip_boundary : 16; // Clip boundary for OFM activations +#ifdef __cplusplus + public: + npu_set_activation_max_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_activation_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), clip_boundary(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_max_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_max_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_max_t &set_clip_boundary(uint32_t value) + { + clip_boundary = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif + }; + // Index n for weight stream access + struct npu_set_weight_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for weight stream access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_weight_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_weight_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_weight_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Index n for scale stream access + struct npu_set_scale_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for scale stream access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_scale_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_scale_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_scale_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // Start of ACC0,ACC1 buffers + struct npu_set_ab_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ab_start : 6; // Start of ACC0,ACC1 buffers in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ab_start_t(uint32_t _ab_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(_ab_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ab_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ab_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_AB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ab_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ab_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ab_start() const + { + return static_cast(ab_start); + } + CONSTEXPR npu_set_ab_start_t &set_ab_start(uint32_t value) + { + ab_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ab_start", std::to_string(ab_start))); + } +#endif +#endif + }; + // Block number of blocks dependency + struct npu_set_blockdep_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t blockdep : 2; // Block number of blocks dependency between kernel operations + uint32_t reserved1 : 14; +#ifdef __cplusplus + public: + npu_set_blockdep_t(uint32_t _blockdep) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(_blockdep & ((1U << 2) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_blockdep_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), blockdep(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_blockdep_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_blockdep_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_blockdep() const + { + return static_cast(blockdep); + } + CONSTEXPR npu_set_blockdep_t &set_blockdep(uint32_t value) + { + blockdep = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("blockdep", std::to_string(blockdep))); + } +#endif +#endif + }; + // DMA0 source region + struct npu_set_dma0_src_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 5; +#ifdef __cplusplus + public: + npu_set_dma0_src_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_dma0_src_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_src_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + } +#endif +#endif + }; + // DMA0 destination region + struct npu_set_dma0_dst_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Region number if region_mode is region_mode_external. Else core mask to write to (bit k + // set for core k=0,1) + uint32_t reserved1 : 5; + uint32_t region_mode : 1; // Region mode + uint32_t stride_mode : 2; // Stride mode + uint32_t reserved2 : 5; +#ifdef __cplusplus + public: + npu_set_dma0_dst_region_t(uint32_t _region, + NPU_NAMESPACE::dma_region_mode _region_mode, + NPU_NAMESPACE::dma_stride_mode _stride_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3) - 1)), reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1) - 1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_dma0_dst_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0), region_mode(0), + stride_mode(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t &set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair( + "region_mode", + (region_mode < (sizeof(dma_region_mode_str) / sizeof(dma_region_mode_str[0])) ? + dma_region_mode_str[region_mode] : + "****"))); + fields.push_back(std::make_pair( + "stride_mode", + (stride_mode < (sizeof(dma_stride_mode_str) / sizeof(dma_stride_mode_str[0])) ? + dma_stride_mode_str[stride_mode] : + "****"))); + } +#endif +#endif + }; + // Size of second dimension for 2D/3D transfers + struct npu_set_dma0_size0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of second dimension for 2D/3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size0_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size0_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size0_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size0_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // Size of third dimension for 3D transfers + struct npu_set_dma0_size1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t size : 16; // Size of third dimension for 3D transfers +#ifdef __cplusplus + public: + npu_set_dma0_size1_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(_size & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_dma0_size1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), size(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size1_t &set_size(uint32_t value) + { + size = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif + }; + // IFM2 broadcast configuration + struct npu_set_ifm2_broadcast_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t + broadcast_h : 1; // Broadcast H dimension (if set then any accesses to IFM2 sets y=0 and IFM2 height=1) + uint32_t broadcast_w : 1; // Broadcast W dimension (if set then any accesses to IFM2 sets x=0 and IFM2 width=1) + uint32_t broadcast_c : 1; // Broadcast C dimension (if set then any accesses to IFM2 sets c=0 and IFM2 depth=1) + uint32_t reserved1 : 3; + uint32_t operand_order : 1; // Operand order + uint32_t broadcast_constant : 1; // Broadcast constant given by NPU_SET_IFM2_SCALAR and so ignore BH, BW and BC + uint32_t reserved2 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_h, + NPU_NAMESPACE::broadcast_mode _broadcast_w, + NPU_NAMESPACE::broadcast_mode _broadcast_c, + NPU_NAMESPACE::ifm2_operand_order _operand_order, + NPU_NAMESPACE::broadcast_mode _broadcast_constant) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_h(static_cast(_broadcast_h) & ((1U << 1) - 1)), + broadcast_w(static_cast(_broadcast_w) & ((1U << 1) - 1)), + broadcast_c(static_cast(_broadcast_c) & ((1U << 1) - 1)), reserved1(0), + operand_order(static_cast(_operand_order) & ((1U << 1) - 1)), + broadcast_constant(static_cast(_broadcast_constant) & ((1U << 1) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_ifm2_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), broadcast_h(0), broadcast_w(0), + broadcast_c(0), reserved1(0), operand_order(0), broadcast_constant(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_h() const + { + return static_cast(broadcast_h); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_h(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_h = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_w() const + { + return static_cast(broadcast_w); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_w(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_w = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_c() const + { + return static_cast(broadcast_c); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_c(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_c = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm2_operand_order get_operand_order() const + { + return static_cast(operand_order); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_operand_order(NPU_NAMESPACE::ifm2_operand_order value) + { + operand_order = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_constant() const + { + return static_cast(broadcast_constant); + } + CONSTEXPR npu_set_ifm2_broadcast_t &set_broadcast_constant(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_constant = static_cast(value) & ((1U << 1) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "broadcast_h", + (broadcast_h < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_h] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_w", + (broadcast_w < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_w] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_c", + (broadcast_c < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_c] : + "****"))); + fields.push_back(std::make_pair( + "operand_order", + (operand_order < (sizeof(ifm2_operand_order_str) / sizeof(ifm2_operand_order_str[0])) ? + ifm2_operand_order_str[operand_order] : + "****"))); + fields.push_back(std::make_pair( + "broadcast_constant", + (broadcast_constant < (sizeof(broadcast_mode_str) / sizeof(broadcast_mode_str[0])) ? + broadcast_mode_str[broadcast_constant] : + "****"))); + } +#endif +#endif + }; + // IFM2 scalar value + struct npu_set_ifm2_scalar_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t scalar : 16; // int16 or uint16 depending on ifm2_precision.type +#ifdef __cplusplus + public: + npu_set_ifm2_scalar_t(uint32_t _scalar) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(_scalar & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_scalar_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), scalar(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_SCALAR); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scalar() const + { + return static_cast(scalar); + } + CONSTEXPR npu_set_ifm2_scalar_t &set_scalar(uint32_t value) + { + scalar = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scalar", std::to_string(scalar))); + } +#endif +#endif + }; + // IFM2 Precision + struct npu_set_ifm2_precision_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t activation_type : 1; // IFM type - MUST MATCH IFM + uint32_t reserved1 : 1; + uint32_t activation_precision : 2; // IFM precision - MUST MATCH IFM + uint32_t reserved2 : 2; + uint32_t activation_format : 2; // IFM format + uint32_t reserved3 : 8; +#ifdef __cplusplus + public: + npu_set_ifm2_precision_t(NPU_NAMESPACE::activation_type _activation_type, + NPU_NAMESPACE::activation_precision _activation_precision, + NPU_NAMESPACE::activation_format _activation_format) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1) - 1)), reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2) - 1)), reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2) - 1)), reserved3(0) + { + } + CONSTEXPR npu_set_ifm2_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), activation_type(0), reserved1(0), + activation_precision(0), reserved2(0), activation_format(0), reserved3(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_precision_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_precision_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm2_precision_t &set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair( + "activation_type", + (activation_type < (sizeof(activation_type_str) / sizeof(activation_type_str[0])) ? + activation_type_str[activation_type] : + "****"))); + fields.push_back(std::make_pair( + "activation_precision", + (activation_precision < (sizeof(activation_precision_str) / sizeof(activation_precision_str[0])) ? + activation_precision_str[activation_precision] : + "****"))); + fields.push_back(std::make_pair( + "activation_format", + (activation_format < (sizeof(activation_format_str) / sizeof(activation_format_str[0])) ? + activation_format_str[activation_format] : + "****"))); + } +#endif +#endif + }; + // IFM2 zero point + struct npu_set_ifm2_zero_point_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t zero_point : 16; // Zero point offset +#ifdef __cplusplus + public: + npu_set_ifm2_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), zero_point(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm2_zero_point_t &set_zero_point(uint32_t value) + { + zero_point = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif + }; + // IFM2 Tile 0 and tile 2 width + struct npu_set_ifm2_width0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t width_m1 : 16; // IFM2 Tile 0 and tile 2 width +#ifdef __cplusplus + public: + npu_set_ifm2_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(_width_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), width_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm2_width0_m1_t &set_width_m1(uint32_t value) + { + width_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif + }; + // IFM2 Tile 0 height + struct npu_set_ifm2_height0_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 0 height +#ifdef __cplusplus + public: + npu_set_ifm2_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height0_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // IFM2 Tile 1 height + struct npu_set_ifm2_height1_m1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t height_m1 : 16; // IFM2 Tile 1 height +#ifdef __cplusplus + public: + npu_set_ifm2_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(_height_m1 & ((1U << 16) - 1)) + { + } + CONSTEXPR npu_set_ifm2_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), height_m1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height1_m1_t &set_height_m1(uint32_t value) + { + height_m1 = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif + }; + // Start of IB0,IB1 buffers for IFM2 + struct npu_set_ifm2_ib_start_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t ib_start : 6; // Start of IB0,IB1 buffers for IFM2 in the SHRAM in KB units. Multiple of 2 + uint32_t reserved1 : 10; +#ifdef __cplusplus + public: + npu_set_ifm2_ib_start_t(uint32_t _ib_start) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(_ib_start & ((1U << 6) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_ib_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), ib_start(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_IB_START); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_ib_start() const + { + return static_cast(ib_start); + } + CONSTEXPR npu_set_ifm2_ib_start_t &set_ib_start(uint32_t value) + { + ib_start = static_cast(value) & ((1U << 6) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("ib_start", std::to_string(ib_start))); + } +#endif +#endif + }; + // Index n for IFM2 access + struct npu_set_ifm2_region_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t region : 3; // Index n for IFM2 access + uint32_t reserved1 : 13; +#ifdef __cplusplus + public: + npu_set_ifm2_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(_region & ((1U << 3) - 1)), + reserved1(0) + { + } + CONSTEXPR npu_set_ifm2_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), region(0), reserved1(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION) && + control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_region_t &set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_region_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm2_region_t &set_region(uint32_t value) + { + region = static_cast(value) & ((1U << 3) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif + }; + // IFM Tile 0 address + struct npu_set_ifm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 1 address + struct npu_set_ifm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 2 address + struct npu_set_ifm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base2_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM Tile 3 address + struct npu_set_ifm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base3_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between horizontal values + struct npu_set_ifm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_x_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between vertical values + struct npu_set_ifm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_y_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_c_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 0 address + struct npu_set_ofm_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 1 address + struct npu_set_ofm_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 2 address + struct npu_set_ofm_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base2_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM Tile 3 address + struct npu_set_ofm_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base3_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between horizontal values + struct npu_set_ofm_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_x_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between vertical values + struct npu_set_ofm_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_y_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // OFM byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ofm_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ofm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ofm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_c_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte offset in WEIGHT_REGION + struct npu_set_weight_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_weight_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_weight_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte length + struct npu_set_weight_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 32; // Weight stream byte length +#ifdef __cplusplus + public: + npu_set_weight_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(_length) + { + } + CONSTEXPR npu_set_weight_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight_length_t &set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // Scale and bias stream input byte offset from SCALE_REGION + struct npu_set_scale_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_scale_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_scale_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_scale_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Scale and bias stream input byte length + struct npu_set_scale_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 20; // Scale and bias stream byte length + uint32_t reserved2 : 12; +#ifdef __cplusplus + public: + npu_set_scale_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + length(_length & ((1U << 20) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_scale_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale_length_t &set_length(uint32_t value) + { + length = value & ((1U << 20) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // OFM scale + struct npu_set_ofm_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. Not applied for 32-bit operations +#ifdef __cplusplus + public: + npu_set_ofm_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_ofm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ofm_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ofm_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand A scale + struct npu_set_opa_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t shift : 6; // Shift. Ignored if IFM scale mode is 0 + uint32_t reserved1 : 10; + uint32_t scale : 32; // Scale. 16-bit if IFM scale mode is 0 +#ifdef __cplusplus + public: + npu_set_opa_scale_t(uint32_t _shift, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(_shift & ((1U << 6) - 1)), + reserved1(0), scale(_scale) + { + } + CONSTEXPR npu_set_opa_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), shift(0), reserved1(0), scale(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPA_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opa_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opa_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_opa_scale_t &set_shift(uint32_t value) + { + shift = static_cast(value) & ((1U << 6) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opa_scale_t &set_scale(uint32_t value) + { + scale = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // Input operand B scale + struct npu_set_opb_scale_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t scale : 16; // Scale. Not used if IFM scale mode is 1 or 2 + uint32_t reserved2 : 16; +#ifdef __cplusplus + public: + npu_set_opb_scale_t(uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + scale(_scale & ((1U << 16) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_opb_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), scale(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OPB_SCALE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_opb_scale_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_opb_scale_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_opb_scale_t &set_scale(uint32_t value) + { + scale = static_cast(value) & ((1U << 16) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif + }; + // DMA user channel 0 source byte offset from DMA0_SRC_REGION + struct npu_set_dma0_src_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_src_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_src_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 destination byte offset from DMA0_DST_REGION + struct npu_set_dma0_dst_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_dst_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_dst_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // DMA user channel 0 transfer length in bytes for each 1D transfer + struct npu_set_dma0_len_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_len_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_len_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_len_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // byte distance to skip after each inner (1D) transfer (2D/3D mode) (any alignment) + struct npu_set_dma0_skip0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_skip0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_skip0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_skip0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // byte distance to skip after each 2D transfer (3D mode) (any alignment) + struct npu_set_dma0_skip1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_dma0_skip1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_dma0_skip1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SKIP1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_skip1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 0 address + struct npu_set_ifm2_base0_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base0_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 1 address + struct npu_set_ifm2_base1_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base1_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 2 address + struct npu_set_ifm2_base2_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base2_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 Tile 3 address + struct npu_set_ifm2_base3_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base3_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between horizontal values + struct npu_set_ifm2_stride_x_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_x_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between vertical values + struct npu_set_ifm2_stride_y_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_y_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // IFM2 byte stride between channel blocks (of 16 bytes each block) + struct npu_set_ifm2_stride_c_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_ifm2_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_ifm2_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_c_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte offset in WEIGHT_REGION for core 1 + struct npu_set_weight1_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_weight1_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_weight1_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight1_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Weight stream byte length for core 1 + struct npu_set_weight1_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 32; // Weight stream byte length +#ifdef __cplusplus + public: + npu_set_weight1_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(_length) + { + } + CONSTEXPR npu_set_weight1_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH) && + control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight1_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight1_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight1_length_t &set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; + // Scale and bias stream input byte offset from SCALE_REGION for core 1 + struct npu_set_scale1_base_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t addr_hi : 8; // address extension + uint32_t reserved1 : 8; + uint32_t addr_lo : 32; // address offset +#ifdef __cplusplus + public: + npu_set_scale1_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & std::numeric_limits::max())), reserved1(0), + addr_lo(static_cast((_addr)&std::numeric_limits::max())) + { + } + CONSTEXPR npu_set_scale1_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), addr_hi(0), reserved1(0), addr_lo(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_BASE); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_scale1_base_t &set_addr(uint64_t value) + { + addr_lo = static_cast((value)&std::numeric_limits::max()); + addr_hi = static_cast((value >> 32) & std::numeric_limits::max()); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + std::stringstream saddr; + saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif + }; + // Scale and bias stream input byte length for core 1 + struct npu_set_scale1_length_t + { +#ifdef __cplusplus + private: +#endif + uint32_t opcode : 10; // opcode + uint32_t reserved0 : 4; + uint32_t control : 2; // control + uint32_t reserved1 : 16; + uint32_t length : 20; // Scale and bias stream byte length + uint32_t reserved2 : 12; +#ifdef __cplusplus + public: + npu_set_scale1_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), + length(_length & ((1U << 20) - 1)), reserved2(0) + { + } + CONSTEXPR npu_set_scale1_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH)), reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), reserved1(0), length(0), reserved2(0) + { + } + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH) && control >= 1 && + control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE1_LENGTH); + control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word; + std::memcpy(&word, this, sizeof(word)); + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale1_length_t &set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10) - 1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale1_length_t &set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2) - 1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale1_length_t &set_length(uint32_t value) + { + length = value & ((1U << 20) - 1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector> &fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif + }; +#ifdef __cplusplus +}; +#endif +#define NPU_OP_STRUCTS \ + NPU_OP_(stop) \ + NPU_OP_(irq) \ + NPU_OP_(conv) \ + NPU_OP_(depthwise) \ + NPU_OP_(pool) \ + NPU_OP_(elementwise) \ + NPU_OP_(dma_start) \ + NPU_OP_(dma_wait) \ + NPU_OP_(kernel_wait) \ + NPU_OP_(pmu_mask) + +#define NPU_SET_STRUCTS \ + NPU_SET_(ifm_pad_top) \ + NPU_SET_(ifm_pad_left) \ + NPU_SET_(ifm_pad_right) \ + NPU_SET_(ifm_pad_bottom) \ + NPU_SET_(ifm_depth_m1) \ + NPU_SET_(ifm_precision) \ + NPU_SET_(ifm_upscale) \ + NPU_SET_(ifm_zero_point) \ + NPU_SET_(ifm_width0_m1) \ + NPU_SET_(ifm_height0_m1) \ + NPU_SET_(ifm_height1_m1) \ + NPU_SET_(ifm_ib_end) \ + NPU_SET_(ifm_region) \ + NPU_SET_(ofm_width_m1) \ + NPU_SET_(ofm_height_m1) \ + NPU_SET_(ofm_depth_m1) \ + NPU_SET_(ofm_precision) \ + NPU_SET_(ofm_blk_width_m1) \ + NPU_SET_(ofm_blk_height_m1) \ + NPU_SET_(ofm_blk_depth_m1) \ + NPU_SET_(ofm_zero_point) \ + NPU_SET_(ofm_width0_m1) \ + NPU_SET_(ofm_height0_m1) \ + NPU_SET_(ofm_height1_m1) \ + NPU_SET_(ofm_region) \ + NPU_SET_(kernel_width_m1) \ + NPU_SET_(kernel_height_m1) \ + NPU_SET_(kernel_stride) \ + NPU_SET_(parallel_mode) \ + NPU_SET_(acc_format) \ + NPU_SET_(activation) \ + NPU_SET_(activation_min) \ + NPU_SET_(activation_max) \ + NPU_SET_(weight_region) \ + NPU_SET_(scale_region) \ + NPU_SET_(ab_start) \ + NPU_SET_(blockdep) \ + NPU_SET_(dma0_src_region) \ + NPU_SET_(dma0_dst_region) \ + NPU_SET_(dma0_size0) \ + NPU_SET_(dma0_size1) \ + NPU_SET_(ifm2_broadcast) \ + NPU_SET_(ifm2_scalar) \ + NPU_SET_(ifm2_precision) \ + NPU_SET_(ifm2_zero_point) \ + NPU_SET_(ifm2_width0_m1) \ + NPU_SET_(ifm2_height0_m1) \ + NPU_SET_(ifm2_height1_m1) \ + NPU_SET_(ifm2_ib_start) \ + NPU_SET_(ifm2_region) \ + NPU_SET_(ifm_base0) \ + NPU_SET_(ifm_base1) \ + NPU_SET_(ifm_base2) \ + NPU_SET_(ifm_base3) \ + NPU_SET_(ifm_stride_x) \ + NPU_SET_(ifm_stride_y) \ + NPU_SET_(ifm_stride_c) \ + NPU_SET_(ofm_base0) \ + NPU_SET_(ofm_base1) \ + NPU_SET_(ofm_base2) \ + NPU_SET_(ofm_base3) \ + NPU_SET_(ofm_stride_x) \ + NPU_SET_(ofm_stride_y) \ + NPU_SET_(ofm_stride_c) \ + NPU_SET_(weight_base) \ + NPU_SET_(weight_length) \ + NPU_SET_(scale_base) \ + NPU_SET_(scale_length) \ + NPU_SET_(ofm_scale) \ + NPU_SET_(opa_scale) \ + NPU_SET_(opb_scale) \ + NPU_SET_(dma0_src) \ + NPU_SET_(dma0_dst) \ + NPU_SET_(dma0_len) \ + NPU_SET_(dma0_skip0) \ + NPU_SET_(dma0_skip1) \ + NPU_SET_(ifm2_base0) \ + NPU_SET_(ifm2_base1) \ + NPU_SET_(ifm2_base2) \ + NPU_SET_(ifm2_base3) \ + NPU_SET_(ifm2_stride_x) \ + NPU_SET_(ifm2_stride_y) \ + NPU_SET_(ifm2_stride_c) \ + NPU_SET_(weight1_base) \ + NPU_SET_(weight1_length) \ + NPU_SET_(scale1_base) \ + NPU_SET_(scale1_length) + +#define EXPAND_ACC_FORMAT(FUNC, SEP) FUNC(acc_format, I32) SEP FUNC(acc_format, I40) SEP FUNC(acc_format, F16) + +#define EXPAND_ACTIVATION_CLIP_RANGE(FUNC, SEP) \ + FUNC(activation_clip_range, OFM_PRECISION) \ + SEP FUNC(activation_clip_range, FORCE_UINT8) SEP FUNC(activation_clip_range, FORCE_INT8) \ + SEP FUNC(activation_clip_range, FORCE_INT16) + +#define EXPAND_ACTIVATION_FORMAT(FUNC, SEP) FUNC(activation_format, NHWC) SEP FUNC(activation_format, NHCWB16) + +#define EXPAND_ACTIVATION_FUNCTION(FUNC, SEP) \ + FUNC(activation_function, RELU) \ + SEP FUNC(activation_function, TANH) SEP FUNC(activation_function, SIGMOID) SEP FUNC(activation_function, TABLE_0) \ + SEP FUNC(activation_function, TABLE_1) SEP FUNC(activation_function, TABLE_2) \ + SEP FUNC(activation_function, TABLE_3) SEP FUNC(activation_function, TABLE_4) \ + SEP FUNC(activation_function, TABLE_5) SEP FUNC(activation_function, TABLE_6) \ + SEP FUNC(activation_function, TABLE_7) + +#define EXPAND_ACTIVATION_PRECISION(FUNC, SEP) \ + FUNC(activation_precision, B8) \ + SEP FUNC(activation_precision, B16) SEP FUNC(activation_precision, B32) SEP FUNC(activation_precision, B64) + +#define EXPAND_ACTIVATION_TYPE(FUNC, SEP) FUNC(activation_type, UNSIGNED) SEP FUNC(activation_type, SIGNED) + +#define EXPAND_AXI_MEM_ENCODING(FUNC, SEP) \ + FUNC(axi_mem_encoding, DEVICE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, DEVICE_BUFFERABLE) SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_NON_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_BUFFERABLE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_THROUGH_READ_AND_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_NO_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_WRITE_ALLOCATE) \ + SEP FUNC(axi_mem_encoding, WRITE_BACK_READ_AND_WRITE_ALLOCATE) + +#define EXPAND_BROADCAST_MODE(FUNC, SEP) FUNC(broadcast_mode, DISABLE) SEP FUNC(broadcast_mode, ENABLE) + +#define EXPAND_CMD0_OPCODE(FUNC, SEP) \ + FUNC(cmd0_opcode, NPU_OP_STOP) \ + SEP FUNC(cmd0_opcode, NPU_OP_IRQ) SEP FUNC(cmd0_opcode, NPU_OP_CONV) SEP FUNC( \ + cmd0_opcode, NPU_OP_DEPTHWISE) SEP FUNC(cmd0_opcode, NPU_OP_POOL) SEP FUNC(cmd0_opcode, NPU_OP_ELEMENTWISE) \ + SEP FUNC(cmd0_opcode, NPU_OP_DMA_START) SEP FUNC(cmd0_opcode, NPU_OP_DMA_WAIT) SEP FUNC( \ + cmd0_opcode, NPU_OP_KERNEL_WAIT) SEP FUNC(cmd0_opcode, NPU_OP_PMU_MASK) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PAD_TOP) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_LEFT) SEP FUNC(cmd0_opcode, NPU_SET_IFM_PAD_RIGHT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_PAD_BOTTOM) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_DEPTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_IFM_PRECISION) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_UPSCALE) SEP FUNC(cmd0_opcode, NPU_SET_IFM_ZERO_POINT) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_WIDTH0_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_IFM_IB_END) SEP FUNC( \ + cmd0_opcode, NPU_SET_IFM_REGION) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_DEPTH_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_PRECISION) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_BLK_WIDTH_M1) SEP FUNC(cmd0_opcode, \ + NPU_SET_OFM_BLK_HEIGHT_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_BLK_DEPTH_M1) SEP FUNC( \ + cmd0_opcode, NPU_SET_OFM_ZERO_POINT) SEP FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH0_M1) \ + SEP FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT0_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_OFM_HEIGHT1_M1) SEP FUNC(cmd0_opcode, NPU_SET_OFM_REGION) \ + SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_WIDTH_M1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_KERNEL_HEIGHT_M1) SEP FUNC(cmd0_opcode, NPU_SET_KERNEL_STRIDE) \ + SEP FUNC(cmd0_opcode, NPU_SET_PARALLEL_MODE) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_ACC_FORMAT) SEP FUNC(cmd0_opcode, NPU_SET_ACTIVATION) \ + SEP FUNC(cmd0_opcode, \ + NPU_SET_ACTIVATION_MIN) SEP FUNC(cmd0_opcode, \ + NPU_SET_ACTIVATION_MAX) \ + SEP FUNC(cmd0_opcode, NPU_SET_WEIGHT_REGION) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_SCALE_REGION) SEP FUNC(cmd0_opcode, NPU_SET_AB_START) \ + SEP FUNC(cmd0_opcode, NPU_SET_BLOCKDEP) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SRC_REGION) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_DMA0_DST_REGION) SEP FUNC(cmd0_opcode, \ + NPU_SET_DMA0_SIZE0) \ + SEP FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE1) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_BROADCAST) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_SCALAR) SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, \ + NPU_SET_IFM2_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, \ + NPU_SET_IFM2_HEIGHT1_M1) \ + SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_IB_START) \ + SEP FUNC( \ + cmd0_opcode, \ + NPU_SET_IFM2_REGION) + +#define EXPAND_CMD1_OPCODE(FUNC, SEP) \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE0) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE1) SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE2) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_BASE3) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_Y) SEP FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_C) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_BASE0) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE1) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE2) SEP FUNC(cmd1_opcode, NPU_SET_OFM_BASE3) SEP FUNC( \ + cmd1_opcode, NPU_SET_OFM_STRIDE_X) SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_C) SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT_BASE) SEP FUNC( \ + cmd1_opcode, NPU_SET_WEIGHT_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_SCALE_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE_LENGTH) SEP FUNC(cmd1_opcode, NPU_SET_OFM_SCALE) \ + SEP FUNC(cmd1_opcode, NPU_SET_OPA_SCALE) SEP FUNC(cmd1_opcode, NPU_SET_OPB_SCALE) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SRC) SEP FUNC(cmd1_opcode, NPU_SET_DMA0_DST) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_LEN) SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SKIP0) \ + SEP FUNC(cmd1_opcode, NPU_SET_DMA0_SKIP1) SEP FUNC( \ + cmd1_opcode, NPU_SET_IFM2_BASE0) SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE1) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_BASE2) SEP FUNC(cmd1_opcode, \ + NPU_SET_IFM2_BASE3) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_X) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_Y) \ + SEP FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_C) \ + SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT1_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_WEIGHT1_LENGTH) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE1_BASE) \ + SEP FUNC(cmd1_opcode, NPU_SET_SCALE1_LENGTH) + +#define EXPAND_CMD_CTRL(FUNC, SEP) FUNC(cmd_ctrl, CMD0_CTRL) SEP FUNC(cmd_ctrl, CMD1_CTRL) + +#define EXPAND_CUSTOM_DMA(FUNC, SEP) FUNC(custom_dma, NOT_IMPLEMENTED) SEP FUNC(custom_dma, IMPLEMENTED) + +#define EXPAND_DMA_FAULT_SRC(FUNC, SEP) FUNC(dma_fault_src, AXI_M0) SEP FUNC(dma_fault_src, AXI_M1) + +#define EXPAND_DMA_REGION_MODE(FUNC, SEP) FUNC(dma_region_mode, EXTERNAL) SEP FUNC(dma_region_mode, INTERNAL) + +#define EXPAND_DMA_STRIDE_MODE(FUNC, SEP) \ + FUNC(dma_stride_mode, D1) SEP FUNC(dma_stride_mode, D2) SEP FUNC(dma_stride_mode, D3) + +#define EXPAND_ELEMENTWISE_MODE(FUNC, SEP) \ + FUNC(elementwise_mode, MUL) \ + SEP FUNC(elementwise_mode, ADD) SEP FUNC(elementwise_mode, SUB) SEP FUNC(elementwise_mode, MIN) \ + SEP FUNC(elementwise_mode, MAX) SEP FUNC(elementwise_mode, LRELU) SEP FUNC(elementwise_mode, ABS) \ + SEP FUNC(elementwise_mode, CLZ) SEP FUNC(elementwise_mode, SHR) SEP FUNC(elementwise_mode, SHL) + +#define EXPAND_FUNCTIONAL_SAFETY(FUNC, SEP) \ + FUNC(functional_safety, NOT_IMPLEMENTED) SEP FUNC(functional_safety, IMPLEMENTED) + +#define EXPAND_IFM2_OPERAND_ORDER(FUNC, SEP) FUNC(ifm2_operand_order, ORDER_B) SEP FUNC(ifm2_operand_order, ORDER_A) + +#define EXPAND_IFM_SCALE_MODE(FUNC, SEP) \ + FUNC(ifm_scale_mode, OPA_OPB_16) SEP FUNC(ifm_scale_mode, OPA_32) SEP FUNC(ifm_scale_mode, OPB_32) + +#define EXPAND_IFM_UPSCALE_MODE(FUNC, SEP) \ + FUNC(ifm_upscale_mode, NONE) SEP FUNC(ifm_upscale_mode, NEAREST) SEP FUNC(ifm_upscale_mode, ZEROS) + +#define EXPAND_KERNEL_DECOMPOSITION(FUNC, SEP) FUNC(kernel_decomposition, D8X8) SEP FUNC(kernel_decomposition, D4X4) + +#define EXPAND_KERNEL_DILATION(FUNC, SEP) FUNC(kernel_dilation, NONE) SEP FUNC(kernel_dilation, X2) + +#define EXPAND_MAX_BEATS(FUNC, SEP) FUNC(max_beats, B64) SEP FUNC(max_beats, B128) SEP FUNC(max_beats, B256) + +#define EXPAND_MEM_ATTR(FUNC, SEP) \ + FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER0) \ + SEP FUNC(mem_attr, AXI0_OUTSTANDING_COUNTER1) SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER2) \ + SEP FUNC(mem_attr, AXI1_OUTSTANDING_COUNTER3) + +#define EXPAND_OFM_SCALE_MODE(FUNC, SEP) FUNC(ofm_scale_mode, PER_CHANNEL) SEP FUNC(ofm_scale_mode, GLOBAL) + +#define EXPAND_PARALLEL_MODE(FUNC, SEP) FUNC(parallel_mode, SINGLE_CORE) SEP FUNC(parallel_mode, DUAL_CORE_DEPTH) + +#define EXPAND_PMU_AXI_CHANNEL(FUNC, SEP) \ + FUNC(pmu_axi_channel, RD_CMD) \ + SEP FUNC(pmu_axi_channel, RD_IFM) SEP FUNC(pmu_axi_channel, RD_WEIGHTS) SEP FUNC(pmu_axi_channel, RD_SCALE_BIAS) \ + SEP FUNC(pmu_axi_channel, RD_MEM2MEM) SEP FUNC(pmu_axi_channel, WR_OFM) SEP FUNC(pmu_axi_channel, WR_MEM2MEM) + +#define EXPAND_PMU_EVENT(FUNC, SEP) \ + FUNC(pmu_event, NO_EVENT) \ + SEP FUNC(pmu_event, CYCLE) SEP FUNC(pmu_event, NPU_IDLE) SEP FUNC(pmu_event, CC_STALLED_ON_BLOCKDEP) SEP FUNC( \ + pmu_event, CC_STALLED_ON_SHRAM_RECONFIG) SEP FUNC(pmu_event, NPU_ACTIVE) SEP FUNC(pmu_event, MAC_ACTIVE) \ + SEP FUNC(pmu_event, MAC_ACTIVE_8BIT) SEP FUNC(pmu_event, MAC_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, MAC_DPU_ACTIVE) SEP FUNC(pmu_event, MAC_STALLED_BY_WD_ACC) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_WD) \ + SEP FUNC(pmu_event, MAC_STALLED_BY_ACC) SEP FUNC(pmu_event, MAC_STALLED_BY_IB) SEP FUNC( \ + pmu_event, \ + MAC_ACTIVE_32BIT) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_W) SEP FUNC(pmu_event, \ + MAC_STALLED_BY_INT_ACC) SEP FUNC(pmu_event, \ + AO_ACTIVE) \ + SEP FUNC(pmu_event, AO_ACTIVE_8BIT) SEP FUNC(pmu_event, AO_ACTIVE_16BIT) SEP FUNC( \ + pmu_event, AO_STALLED_BY_OFMP_OB) SEP FUNC(pmu_event, AO_STALLED_BY_OFMP) SEP \ + FUNC(pmu_event, AO_STALLED_BY_OB) SEP FUNC(pmu_event, AO_STALLED_BY_ACC_IB) SEP FUNC( \ + pmu_event, AO_STALLED_BY_ACC) SEP FUNC(pmu_event, AO_STALLED_BY_IB) SEP \ + FUNC(pmu_event, WD_ACTIVE) SEP FUNC(pmu_event, WD_STALLED) SEP FUNC(pmu_event, WD_STALLED_BY_WS) SEP FUNC( \ + pmu_event, WD_STALLED_BY_WD_BUF) SEP FUNC(pmu_event, \ + WD_PARSE_ACTIVE) SEP \ + FUNC(pmu_event, WD_PARSE_STALLED) SEP FUNC(pmu_event, WD_PARSE_STALLED_IN) SEP FUNC( \ + pmu_event, WD_PARSE_STALLED_OUT) SEP FUNC(pmu_event, \ + WD_TRANS_WS) SEP \ + FUNC(pmu_event, WD_TRANS_WB) SEP FUNC(pmu_event, WD_TRANS_DW0) SEP FUNC( \ + pmu_event, WD_TRANS_DW1) SEP FUNC(pmu_event, \ + AXI0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_RD_TRANS_COMPLETED) SEP FUNC(pmu_event, AXI0_RD_DATA_BEAT_RECEIVED) SEP FUNC( \ + pmu_event, AXI0_RD_TRAN_REQ_STALLED) SEP FUNC(pmu_event, \ + AXI0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI0_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, AXI0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_WRITTEN) SEP FUNC( \ + pmu_event, AXI0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, AXI0_WR_DATA_BEAT_STALLED) SEP FUNC( \ + pmu_event, \ + AXI0_ENABLED_CYCLES) SEP FUNC(pmu_event, \ + AXI0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, AXI0_WR_STALL_LIMIT) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_ANY) SEP FUNC(pmu_event, \ + AXI_LATENCY_32) SEP \ + FUNC(pmu_event, \ + AXI_LATENCY_64) SEP FUNC(pmu_event, \ + AXI_LATENCY_128) SEP \ + FUNC(pmu_event, AXI_LATENCY_256) SEP FUNC( \ + pmu_event, \ + AXI_LATENCY_512) SEP FUNC(pmu_event, \ + AXI_LATENCY_1024) SEP \ + FUNC(pmu_event, ECC_DMA) SEP FUNC( \ + pmu_event, \ + ECC_SB0) SEP FUNC(pmu_event, \ + AXI1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_RD_TRANS_COMPLETED) SEP FUNC( \ + pmu_event, AXI1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, AXI1_RD_TRAN_REQ_STALLED) SEP FUNC( \ + pmu_event, AXI1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, AXI1_WR_TRANS_COMPLETED_M) SEP FUNC( \ + pmu_event, \ + AXI1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, \ + AXI1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, \ + AXI1_WR_TRAN_REQ_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_DATA_BEAT_STALLED) SEP \ + FUNC( \ + pmu_event, \ + AXI1_ENABLED_CYCLES) SEP \ + FUNC( \ + pmu_event, \ + AXI1_RD_STALL_LIMIT) SEP \ + FUNC( \ + pmu_event, \ + AXI1_WR_STALL_LIMIT) \ + SEP FUNC( \ + pmu_event, \ + ECC_SB1) + +#define EXPAND_POOLING_MODE(FUNC, SEP) \ + FUNC(pooling_mode, MAX) SEP FUNC(pooling_mode, AVERAGE) SEP FUNC(pooling_mode, REDUCE_SUM) + +#define EXPAND_PRIVILEGE_LEVEL(FUNC, SEP) FUNC(privilege_level, USER) SEP FUNC(privilege_level, PRIVILEGED) + +#define EXPAND_ROUND_MODE(FUNC, SEP) FUNC(round_mode, DBL) SEP FUNC(round_mode, TRUNCATE) SEP FUNC(round_mode, NATURAL) + +#define EXPAND_SECURITY_LEVEL(FUNC, SEP) FUNC(security_level, SECURE) SEP FUNC(security_level, NON_SECURE) + +#define EXPAND_STATE(FUNC, SEP) FUNC(state, STOPPED) SEP FUNC(state, RUNNING) + +#define EXPAND_WD_CORE_SLICE_STATE(FUNC, SEP) \ + FUNC(wd_core_slice_state, HEADER) SEP FUNC(wd_core_slice_state, PALETTE) SEP FUNC(wd_core_slice_state, WEIGHTS) + +#define EXPAND_WD_CTRL_STATE(FUNC, SEP) \ + FUNC(wd_ctrl_state, IDLE) \ + SEP FUNC(wd_ctrl_state, DRAIN) SEP FUNC(wd_ctrl_state, OFD_INIT) SEP FUNC(wd_ctrl_state, OFD_RUN) + +#define EXPAND_WEIGHT_ORDER(FUNC, SEP) FUNC(weight_order, DEPTH_FIRST) SEP FUNC(weight_order, PART_KERNEL_FIRST) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h new file mode 100644 index 0000000..18c9d6c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu85_interface.h @@ -0,0 +1,24620 @@ +/* + * SPDX-FileCopyrightText: Copyright 2020-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// clang-format off + +#ifndef ETHOSU85_INTERFACE_H +#define ETHOSU85_INTERFACE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#if !defined(__cplusplus) || __cplusplus < 201402L +#define CONSTEXPR +#else +#define CONSTEXPR constexpr +#endif + +#ifndef __cplusplus +#define STRUCT struct +#else +#define STRUCT +#endif + +#if defined(__cplusplus) && defined(NPU_DISASSEMBLE) +#include +#include +#include +#endif + +#if defined(__cplusplus) && !defined(NPU_NAMESPACE) +#define NPU_NAMESPACE npu +#endif + +#ifdef __cplusplus +#include +#include +#include +#endif + +#ifdef __cplusplus +namespace NPU_NAMESPACE +{ +#endif +#define NNX_ARCH_VERSION_MAJOR 2 +#define NNX_ARCH_VERSION_MINOR 0 +#define NNX_ARCH_VERSION_PATCH 0 + +// Register offsets +// +// Register subpage BASE +// +#define NPU_REG_ID 0x0000 +#define NPU_REG_STATUS 0x0004 +#define NPU_REG_CMD 0x0008 +#define NPU_REG_RESET 0x000C +#define NPU_REG_QBASE 0x0010 +#define NPU_REG_QBASE_HI 0x0014 +#define NPU_REG_QREAD 0x0018 +#define NPU_REG_QCONFIG 0x001C +#define NPU_REG_QSIZE 0x0020 +#define NPU_REG_PROT 0x0024 +#define NPU_REG_CONFIG 0x0028 +#define NPU_REG_COND_STATUS 0x0030 +#define NPU_REG_POWER_CTRL 0x0038 +#define NPU_REG_REGIONCFG 0x003C +#define NPU_REG_MEM_ATTR_BASE 0x0040 +#define NPU_REG_MEM_ATTR_ARRLEN 0x0004 +#define NPU_REG_AXI_SRAM 0x0050 +#define NPU_REG_AXI_EXT 0x0054 +#define NPU_REG_CFG_SRAM_CAP 0x0060 +#define NPU_REG_CFG_EXT_CAP 0x0064 +#define NPU_REG_CFG_SRAM_HASH0 0x0068 +#define NPU_REG_CFG_SRAM_HASH0_HI 0x006C +#define NPU_REG_CFG_SRAM_HASH1 0x0070 +#define NPU_REG_CFG_SRAM_HASH1_HI 0x0074 +#define NPU_REG_CFG_EXT_HASH0 0x0078 +#define NPU_REG_CFG_EXT_HASH0_HI 0x007C +#define BASE_REGISTERS_SIZE 0x0080 + +// +// Register subpage BASE_POINTERS +// +#define NPU_REG_BASEP_BASE 0x0080 +#define NPU_REG_BASEP_ARRLEN 0x0008 +#define BASE_POINTERS_REGISTERS_SIZE 0x0100 + +// +// Register subpage DEBUG +// +#define NPU_REG_CLKFORCE 0x0140 +#define NPU_REG_DEBUG_ADDRESS 0x0144 +#define NPU_REG_DEBUG_MISC 0x0148 +#define NPU_REG_FEATURE_DISABLE 0x0154 +#define DEBUG_REGISTERS_SIZE 0x0180 + +// +// Register subpage TSU_DEBUG +// +#define NPU_REG_DMA_IFM_SRC 0x0240 +#define NPU_REG_DMA_IFM_SRC_HI 0x0244 +#define NPU_REG_DMA_OFM_DST 0x0250 +#define NPU_REG_DMA_OFM_DST_HI 0x0254 +#define NPU_REG_DMA_WEIGHT_SRC 0x0258 +#define NPU_REG_DMA_WEIGHT_SRC_HI 0x025C +#define NPU_REG_DMA_CMD_SRC 0x0260 +#define NPU_REG_DMA_CMD_SRC_HI 0x0264 +#define NPU_REG_DMA_CMD_SIZE 0x0268 +#define NPU_REG_DMA_M2M_SRC 0x026C +#define NPU_REG_DMA_M2M_SRC_HI 0x0270 +#define NPU_REG_DMA_M2M_DST 0x0274 +#define NPU_REG_DMA_M2M_DST_HI 0x0278 +#define NPU_REG_CURRENT_QREAD 0x027C +#define NPU_REG_DMA_SCALE_SRC 0x0280 +#define NPU_REG_DMA_SCALE_SRC_HI 0x0284 +#define NPU_REG_DMA_WEIGHT1_SRC 0x0288 +#define NPU_REG_DMA_WEIGHT1_SRC_HI 0x028C +#define NPU_REG_DMA_WEIGHT2_SRC 0x0290 +#define NPU_REG_DMA_WEIGHT2_SRC_HI 0x0294 +#define NPU_REG_DMA_WEIGHT3_SRC 0x0298 +#define NPU_REG_DMA_WEIGHT3_SRC_HI 0x029C +#define NPU_REG_CURRENT_OP 0x02B8 +#define NPU_REG_CURRENT_CMD 0x02BC +#define TSU_DEBUG_REGISTERS_SIZE 0x0300 + +// +// Register subpage INTERNAL_MEMORY +// +#define NPU_REG_INTERNAL_MEMORY_BASE 0x0400 +#define NPU_REG_INTERNAL_MEMORY_ARRLEN 0x0100 +#define INTERNAL_MEMORY_REGISTERS_SIZE 0x0800 + +// +// Register subpage TSU_IFM +// +#define NPU_REG_IFM_PAD_TOP 0x0800 +#define NPU_REG_IFM_PAD_LEFT 0x0804 +#define NPU_REG_IFM_PAD_RIGHT 0x0808 +#define NPU_REG_IFM_PAD_BOTTOM 0x080C +#define NPU_REG_IFM_DEPTH_M1 0x0810 +#define NPU_REG_IFM_PRECISION 0x0814 +#define NPU_REG_IFM_UPSCALE 0x081C +#define NPU_REG_IFM_BROADCAST 0x0820 +#define NPU_REG_IFM_ZERO_POINT 0x0824 +#define NPU_REG_IFM_WIDTH0_M1 0x0828 +#define NPU_REG_IFM_HEIGHT0_M1 0x082C +#define NPU_REG_IFM_HEIGHT1_M1 0x0830 +#define NPU_REG_IFM_REGION 0x083C +#define TSU_IFM_REGISTERS_SIZE 0x0840 + +// +// Register subpage TSU_OFM +// +#define NPU_REG_OFM_WIDTH_M1 0x0844 +#define NPU_REG_OFM_HEIGHT_M1 0x0848 +#define NPU_REG_OFM_DEPTH_M1 0x084C +#define NPU_REG_OFM_PRECISION 0x0850 +#define NPU_REG_OFM_BLK_WIDTH_M1 0x0854 +#define NPU_REG_OFM_BLK_HEIGHT_M1 0x0858 +#define NPU_REG_OFM_BLK_DEPTH_M1 0x085C +#define NPU_REG_OFM_ZERO_POINT 0x0860 +#define NPU_REG_OFM_WIDTH0_M1 0x0868 +#define NPU_REG_OFM_HEIGHT0_M1 0x086C +#define NPU_REG_OFM_HEIGHT1_M1 0x0870 +#define NPU_REG_OFM_REGION 0x087C +#define TSU_OFM_REGISTERS_SIZE 0x0880 + +// +// Register subpage TSU_KERNEL +// +#define NPU_REG_KERNEL_WIDTH_M1 0x0880 +#define NPU_REG_KERNEL_HEIGHT_M1 0x0884 +#define NPU_REG_KERNEL_STRIDE 0x0888 +#define NPU_REG_ACC_FORMAT 0x0890 +#define NPU_REG_ACTIVATION 0x0894 +#define NPU_REG_ACTIVATION_MIN 0x0898 +#define NPU_REG_ACTIVATION_MAX 0x089C +#define NPU_REG_WEIGHT_REGION 0x08A0 +#define NPU_REG_SCALE_REGION 0x08A4 +#define NPU_REG_RESIZE_X_SCALE_N_M1 0x08A8 +#define NPU_REG_RESIZE_Y_SCALE_N_M1 0x08AC +#define NPU_REG_RESIZE_X_OFFSET 0x08B0 +#define NPU_REG_RESIZE_Y_OFFSET 0x08B4 +#define NPU_REG_WEIGHT_FORMAT 0x08B8 +#define NPU_REG_BLOCKDEP 0x08BC +#define TSU_KERNEL_REGISTERS_SIZE 0x08C0 + +// +// Register subpage TSU_DMA +// +#define NPU_REG_DMA0_SRC_REGION 0x08C0 +#define NPU_REG_DMA0_DST_REGION 0x08C4 +#define NPU_REG_DMA0_SIZE0 0x08C8 +#define NPU_REG_DMA0_SIZE1 0x08CC +#define NPU_REG_DMA0_IDX_REGION 0x08D0 +#define TSU_DMA_REGISTERS_SIZE 0x0900 + +// +// Register subpage TSU_IFM2 +// +#define NPU_REG_IFM2_BROADCAST 0x0900 +#define NPU_REG_IFM2_PRECISION 0x0914 +#define NPU_REG_IFM2_ZERO_POINT 0x0924 +#define NPU_REG_IFM2_WIDTH0_M1 0x0928 +#define NPU_REG_IFM2_HEIGHT0_M1 0x092C +#define NPU_REG_IFM2_HEIGHT1_M1 0x0930 +#define NPU_REG_IFM2_REGION 0x093C +#define TSU_IFM2_REGISTERS_SIZE 0x0940 + +// +// Register subpage TSU_IFM_BASE +// +#define NPU_REG_IFM_BASE0 0x0A00 +#define NPU_REG_IFM_BASE0_HI 0x0A04 +#define NPU_REG_IFM_BASE1 0x0A08 +#define NPU_REG_IFM_BASE1_HI 0x0A0C +#define NPU_REG_IFM_BASE2 0x0A10 +#define NPU_REG_IFM_BASE2_HI 0x0A14 +#define NPU_REG_IFM_BASE3 0x0A18 +#define NPU_REG_IFM_BASE3_HI 0x0A1C +#define NPU_REG_IFM_STRIDE_X 0x0A20 +#define NPU_REG_IFM_STRIDE_X_HI 0x0A24 +#define NPU_REG_IFM_STRIDE_Y 0x0A28 +#define NPU_REG_IFM_STRIDE_Y_HI 0x0A2C +#define NPU_REG_IFM_STRIDE_C 0x0A30 +#define NPU_REG_IFM_STRIDE_C_HI 0x0A34 +#define TSU_IFM_BASE_REGISTERS_SIZE 0x0A40 + +// +// Register subpage TSU_OFM_BASE +// +#define NPU_REG_OFM_BASE0 0x0A40 +#define NPU_REG_OFM_BASE0_HI 0x0A44 +#define NPU_REG_OFM_BASE1 0x0A48 +#define NPU_REG_OFM_BASE1_HI 0x0A4C +#define NPU_REG_OFM_BASE2 0x0A50 +#define NPU_REG_OFM_BASE2_HI 0x0A54 +#define NPU_REG_OFM_BASE3 0x0A58 +#define NPU_REG_OFM_BASE3_HI 0x0A5C +#define NPU_REG_OFM_STRIDE_X 0x0A60 +#define NPU_REG_OFM_STRIDE_X_HI 0x0A64 +#define NPU_REG_OFM_STRIDE_Y 0x0A68 +#define NPU_REG_OFM_STRIDE_Y_HI 0x0A6C +#define NPU_REG_OFM_STRIDE_C 0x0A70 +#define NPU_REG_OFM_STRIDE_C_HI 0x0A74 +#define TSU_OFM_BASE_REGISTERS_SIZE 0x0A80 + +// +// Register subpage TSU_WS_BASE +// +#define NPU_REG_WEIGHT_BASE 0x0A80 +#define NPU_REG_WEIGHT_BASE_HI 0x0A84 +#define NPU_REG_WEIGHT_LENGTH 0x0A88 +#define NPU_REG_WEIGHT_LENGTH_HI 0x0A8C +#define NPU_REG_SCALE_BASE 0x0A90 +#define NPU_REG_SCALE_BASE_HI 0x0A94 +#define NPU_REG_SCALE_LENGTH 0x0A98 +#define NPU_REG_SCALE_LENGTH_HI 0x0A9C +#define NPU_REG_OFM_SCALE 0x0AA0 +#define NPU_REG_OFM_SCALE_HI 0x0AA4 +#define NPU_REG_IFM_SCALE 0x0AA8 +#define NPU_REG_IFM_SCALE_HI 0x0AAC +#define NPU_REG_IFM2_SCALE 0x0AB0 +#define NPU_REG_IFM2_SCALE_HI 0x0AB4 +#define NPU_REG_OP_SCALAR 0x0AB8 +#define NPU_REG_OP_SCALAR_HI 0x0ABC +#define TSU_WS_BASE_REGISTERS_SIZE 0x0AC0 + +// +// Register subpage TSU_DMA_BASE +// +#define NPU_REG_DMA0_SRC 0x0AC0 +#define NPU_REG_DMA0_SRC_HI 0x0AC4 +#define NPU_REG_DMA0_DST 0x0AC8 +#define NPU_REG_DMA0_DST_HI 0x0ACC +#define NPU_REG_DMA0_LEN 0x0AD0 +#define NPU_REG_DMA0_LEN_HI 0x0AD4 +#define NPU_REG_DMA0_SRC_STRIDE0 0x0AD8 +#define NPU_REG_DMA0_SRC_STRIDE0_HI 0x0ADC +#define NPU_REG_DMA0_SRC_STRIDE1 0x0AE0 +#define NPU_REG_DMA0_SRC_STRIDE1_HI 0x0AE4 +#define NPU_REG_DMA0_DST_STRIDE0 0x0AE8 +#define NPU_REG_DMA0_DST_STRIDE0_HI 0x0AEC +#define NPU_REG_DMA0_DST_STRIDE1 0x0AF0 +#define NPU_REG_DMA0_DST_STRIDE1_HI 0x0AF4 +#define NPU_REG_DMA0_IDX 0x0AF8 +#define NPU_REG_DMA0_IDX_HI 0x0AFC +#define TSU_DMA_BASE_REGISTERS_SIZE 0x0B00 + +// +// Register subpage TSU_IFM2_BASE +// +#define NPU_REG_IFM2_BASE0 0x0B00 +#define NPU_REG_IFM2_BASE0_HI 0x0B04 +#define NPU_REG_IFM2_BASE1 0x0B08 +#define NPU_REG_IFM2_BASE1_HI 0x0B0C +#define NPU_REG_IFM2_BASE2 0x0B10 +#define NPU_REG_IFM2_BASE2_HI 0x0B14 +#define NPU_REG_IFM2_BASE3 0x0B18 +#define NPU_REG_IFM2_BASE3_HI 0x0B1C +#define NPU_REG_IFM2_STRIDE_X 0x0B20 +#define NPU_REG_IFM2_STRIDE_X_HI 0x0B24 +#define NPU_REG_IFM2_STRIDE_Y 0x0B28 +#define NPU_REG_IFM2_STRIDE_Y_HI 0x0B2C +#define NPU_REG_IFM2_STRIDE_C 0x0B30 +#define NPU_REG_IFM2_STRIDE_C_HI 0x0B34 +#define TSU_IFM2_BASE_REGISTERS_SIZE 0x0B40 + +// +// Register subpage TSU_WS1_BASE +// +#define NPU_REG_WEIGHT1_BASE 0x0B40 +#define NPU_REG_WEIGHT1_BASE_HI 0x0B44 +#define NPU_REG_WEIGHT1_LENGTH 0x0B48 +#define NPU_REG_WEIGHT1_LENGTH_HI 0x0B4C +#define NPU_REG_WEIGHT2_BASE 0x0B50 +#define NPU_REG_WEIGHT2_BASE_HI 0x0B54 +#define NPU_REG_WEIGHT2_LENGTH 0x0B58 +#define NPU_REG_WEIGHT2_LENGTH_HI 0x0B5C +#define NPU_REG_WEIGHT3_BASE 0x0B60 +#define NPU_REG_WEIGHT3_BASE_HI 0x0B64 +#define NPU_REG_WEIGHT3_LENGTH 0x0B68 +#define NPU_REG_WEIGHT3_LENGTH_HI 0x0B6C +#define NPU_REG_RESIZE_X_STEP 0x0B70 +#define NPU_REG_RESIZE_X_STEP_HI 0x0B74 +#define NPU_REG_RESIZE_Y_STEP 0x0B78 +#define NPU_REG_RESIZE_Y_STEP_HI 0x0B7C +#define TSU_WS1_BASE_REGISTERS_SIZE 0x0B80 + +// +// Register subpage TSU_USER_BASE +// +#define TSU_USER_BASE_REGISTERS_SIZE 0x0BC0 + +// +// Register subpage TSU_DMA_EBASE +// +#define NPU_REG_DMA0_IDX_MAX 0x0BC0 +#define NPU_REG_DMA0_IDX_MAX_HI 0x0BC4 +#define NPU_REG_DMA0_IDX_SKIP1 0x0BC8 +#define NPU_REG_DMA0_IDX_SKIP1_HI 0x0BCC +#define TSU_DMA_EBASE_REGISTERS_SIZE 0x0C00 + +// +// Register subpage ID +// +#define NPU_REG_REVISION 0x0FC0 +#define NPU_REG_PID4 0x0FD0 +#define NPU_REG_PID5 0x0FD4 +#define NPU_REG_PID6 0x0FD8 +#define NPU_REG_PID7 0x0FDC +#define NPU_REG_PID0 0x0FE0 +#define NPU_REG_PID1 0x0FE4 +#define NPU_REG_PID2 0x0FE8 +#define NPU_REG_PID3 0x0FEC +#define NPU_REG_CID0 0x0FF0 +#define NPU_REG_CID1 0x0FF4 +#define NPU_REG_CID2 0x0FF8 +#define NPU_REG_CID3 0x0FFC +#define ID_REGISTERS_SIZE 0x1000 + +// +// Register subpage DEBUG_STATUS +// +#define NPU_REG_WD_STATUS 0x1100 +#define NPU_REG_MAC_STATUS 0x1104 +#define NPU_REG_AO_STATUS 0x1108 +#define NPU_REG_DMA_STATUS0 0x1110 +#define NPU_REG_DMA_STATUS1 0x1114 +#define DEBUG_STATUS_REGISTERS_SIZE 0x1180 + +// +// Register subpage PMU +// +#define NPU_REG_PMCR 0x1180 +#define NPU_REG_PMCNTENSET 0x1184 +#define NPU_REG_PMCNTENCLR 0x1188 +#define NPU_REG_PMOVSSET 0x118C +#define NPU_REG_PMOVSCLR 0x1190 +#define NPU_REG_PMINTSET 0x1194 +#define NPU_REG_PMINTCLR 0x1198 +#define NPU_REG_PMCCNTR 0x11A0 +#define NPU_REG_PMCCNTR_HI 0x11A4 +#define NPU_REG_PMCCNTR_CFG 0x11A8 +#define NPU_REG_PMCAXI_CHAN 0x11AC +#define NPU_REG_PMCLUT 0x11B0 +#define PMU_REGISTERS_SIZE 0x1200 + +// +// Register subpage PMU_COUNTERS +// +#define NPU_REG_PMEVCNTR_BASE 0x1300 +#define NPU_REG_PMEVCNTR_ARRLEN 0x0008 +#define NPU_REG_PMEVTYPER_BASE 0x1380 +#define NPU_REG_PMEVTYPER_ARRLEN 0x0008 +#define PMU_COUNTERS_REGISTERS_SIZE 0x1400 + +#ifdef __cplusplus +// Enum types +enum class acc_format : uint8_t +{ + I32 = 0, + I48 = 1, +}; + +enum class acc_input : uint8_t +{ + RESET = 0, + KEEP = 1, + IFM2 = 2, +}; + +enum class acc_output : uint8_t +{ + ENABLE = 0, + DISABLE = 1, +}; + +enum class activation_clip_range : uint8_t +{ + B16 = 0, + NONE = 1, +}; + +enum class activation_format : uint8_t +{ + NHWC = 0, + NHCWB16 = 1, +}; + +enum class activation_function : uint8_t +{ + LUT_NONE = 0, + LUT_U8_U8 = 1, + LUT_S8_S8 = 4, + LUT_S8_S16 = 5, + LUT_S8_S32 = 7, + LUT_S16_S16 = 8, + LUT_S16_S32 = 9, + LUT_TANH = 10, + LUT_SIGMOID = 11, +}; + +enum class activation_precision : uint8_t +{ + B8 = 0, + B16 = 1, + B32 = 2, + B64 = 3, +}; + +enum class activation_reverse : uint8_t +{ + NONE = 0, + H = 1, + W = 2, + C = 3, +}; + +enum class activation_storage : uint8_t +{ + TILE2X2 = 0, + TILE3X1 = 1, + CHAINED = 2, + NONE = 3, +}; + +enum class activation_transpose : uint8_t +{ + HWC = 0, + WHC = 1, + HCW = 2, + WCH = 3, + CHW = 6, + CWH = 7, +}; + +enum class activation_type : uint8_t +{ + UNSIGNED = 0, + SIGNED = 1, +}; + +enum class axi_mem_domain : uint8_t +{ + NON_SHARABLE = 0, + INNER_SHARABLE = 1, + OUTER_SHARABLE = 2, + SYSTEM = 3, +}; + +enum class axi_mem_encoding : uint8_t +{ + DEVICE_NON_BUFFERABLE = 0, + DEVICE_BUFFERABLE = 1, + NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + WRITE_THROUGH_NO_ALLOCATE = 4, + WRITE_THROUGH_READ_ALLOCATE = 5, + WRITE_THROUGH_WRITE_ALLOCATE = 6, + WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + WRITE_BACK_NO_ALLOCATE = 8, + WRITE_BACK_READ_ALLOCATE = 9, + WRITE_BACK_WRITE_ALLOCATE = 10, + WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum class axi_port : uint8_t +{ + SRAM = 0, + EXT = 1, +}; + +enum class branch_cond : uint8_t +{ + ALWAYS = 0, + RF_TRUE = 1, +}; + +enum class broadcast_mode : uint8_t +{ + NONE = 0, + H = 1, + W = 2, + HW = 3, + C = 4, + CH = 5, + CW = 6, + CWH = 7, + SCALAR = 8, +}; + +enum class cmd0_opcode : uint16_t +{ + NPU_OP_STOP = 0, + NPU_OP_IRQ = 1, + NPU_OP_CONV = 2, + NPU_OP_DEPTHWISE = 3, + NPU_OP_POOL = 5, + NPU_OP_ELEMENTWISE = 6, + NPU_OP_RESIZE = 7, + NPU_OP_DMA_START = 16, + NPU_OP_DMA_WAIT = 17, + NPU_OP_KERNEL_WAIT = 18, + NPU_OP_PMU_MASK = 19, + NPU_SET_IFM_PAD_TOP = 256, + NPU_SET_IFM_PAD_LEFT = 257, + NPU_SET_IFM_PAD_RIGHT = 258, + NPU_SET_IFM_PAD_BOTTOM = 259, + NPU_SET_IFM_DEPTH_M1 = 260, + NPU_SET_IFM_PRECISION = 261, + NPU_SET_IFM_UPSCALE = 263, + NPU_SET_IFM_BROADCAST = 264, + NPU_SET_IFM_ZERO_POINT = 265, + NPU_SET_IFM_WIDTH0_M1 = 266, + NPU_SET_IFM_HEIGHT0_M1 = 267, + NPU_SET_IFM_HEIGHT1_M1 = 268, + NPU_SET_IFM_REGION = 271, + NPU_SET_OFM_WIDTH_M1 = 273, + NPU_SET_OFM_HEIGHT_M1 = 274, + NPU_SET_OFM_DEPTH_M1 = 275, + NPU_SET_OFM_PRECISION = 276, + NPU_SET_OFM_BLK_WIDTH_M1 = 277, + NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + NPU_SET_OFM_BLK_DEPTH_M1 = 279, + NPU_SET_OFM_ZERO_POINT = 280, + NPU_SET_OFM_WIDTH0_M1 = 282, + NPU_SET_OFM_HEIGHT0_M1 = 283, + NPU_SET_OFM_HEIGHT1_M1 = 284, + NPU_SET_OFM_REGION = 287, + NPU_SET_KERNEL_WIDTH_M1 = 288, + NPU_SET_KERNEL_HEIGHT_M1 = 289, + NPU_SET_KERNEL_STRIDE = 290, + NPU_SET_ACC_FORMAT = 292, + NPU_SET_ACTIVATION = 293, + NPU_SET_ACTIVATION_MIN = 294, + NPU_SET_ACTIVATION_MAX = 295, + NPU_SET_WEIGHT_REGION = 296, + NPU_SET_SCALE_REGION = 297, + NPU_SET_RESIZE_X_SCALE_N_M1 = 298, + NPU_SET_RESIZE_Y_SCALE_N_M1 = 299, + NPU_SET_RESIZE_X_OFFSET = 300, + NPU_SET_RESIZE_Y_OFFSET = 301, + NPU_SET_WEIGHT_FORMAT = 302, + NPU_SET_BLOCKDEP = 303, + NPU_SET_DMA0_SRC_REGION = 304, + NPU_SET_DMA0_DST_REGION = 305, + NPU_SET_DMA0_SIZE0 = 306, + NPU_SET_DMA0_SIZE1 = 307, + NPU_SET_DMA0_IDX_REGION = 308, + NPU_SET_IFM2_BROADCAST = 384, + NPU_SET_IFM2_PRECISION = 389, + NPU_SET_IFM2_ZERO_POINT = 393, + NPU_SET_IFM2_WIDTH0_M1 = 394, + NPU_SET_IFM2_HEIGHT0_M1 = 395, + NPU_SET_IFM2_HEIGHT1_M1 = 396, + NPU_SET_IFM2_REGION = 399, +}; + +enum class cmd1_opcode : uint16_t +{ + NPU_SET_IFM_BASE0 = 0, + NPU_SET_IFM_BASE1 = 1, + NPU_SET_IFM_BASE2 = 2, + NPU_SET_IFM_BASE3 = 3, + NPU_SET_IFM_STRIDE_X = 4, + NPU_SET_IFM_STRIDE_Y = 5, + NPU_SET_IFM_STRIDE_C = 6, + NPU_SET_OFM_BASE0 = 16, + NPU_SET_OFM_BASE1 = 17, + NPU_SET_OFM_BASE2 = 18, + NPU_SET_OFM_BASE3 = 19, + NPU_SET_OFM_STRIDE_X = 20, + NPU_SET_OFM_STRIDE_Y = 21, + NPU_SET_OFM_STRIDE_C = 22, + NPU_SET_WEIGHT_BASE = 32, + NPU_SET_WEIGHT_LENGTH = 33, + NPU_SET_SCALE_BASE = 34, + NPU_SET_SCALE_LENGTH = 35, + NPU_SET_OFM_SCALE = 36, + NPU_SET_IFM_SCALE = 37, + NPU_SET_IFM2_SCALE = 38, + NPU_SET_OP_SCALAR = 39, + NPU_SET_DMA0_SRC = 48, + NPU_SET_DMA0_DST = 49, + NPU_SET_DMA0_LEN = 50, + NPU_SET_DMA0_SRC_STRIDE0 = 51, + NPU_SET_DMA0_SRC_STRIDE1 = 52, + NPU_SET_DMA0_DST_STRIDE0 = 53, + NPU_SET_DMA0_DST_STRIDE1 = 54, + NPU_SET_DMA0_IDX = 55, + NPU_SET_DMA0_IDX_MAX = 56, + NPU_SET_DMA0_IDX_SKIP1 = 57, + NPU_SET_IFM2_BASE0 = 128, + NPU_SET_IFM2_BASE1 = 129, + NPU_SET_IFM2_BASE2 = 130, + NPU_SET_IFM2_BASE3 = 131, + NPU_SET_IFM2_STRIDE_X = 132, + NPU_SET_IFM2_STRIDE_Y = 133, + NPU_SET_IFM2_STRIDE_C = 134, + NPU_SET_WEIGHT1_BASE = 144, + NPU_SET_WEIGHT1_LENGTH = 145, + NPU_SET_WEIGHT2_BASE = 146, + NPU_SET_WEIGHT2_LENGTH = 147, + NPU_SET_WEIGHT3_BASE = 148, + NPU_SET_WEIGHT3_LENGTH = 149, + NPU_SET_RESIZE_X = 150, + NPU_SET_RESIZE_Y = 151, + NPU_OP_BRANCH = 256, +}; + +enum class cmd_ctrl : uint8_t +{ + CMD0_CTRL = 0, + CMD1_CTRL = 1, +}; + +enum class custom_dma : uint8_t +{ + NOT_IMPLEMENTED = 0, + IMPLEMENTED = 1, +}; + +enum class dma_fault_src : uint8_t +{ + SRAM = 0, + EXT = 1, +}; + +enum class dma_idx_mode : uint8_t +{ + DISABLED = 0, + ENABLED = 1, +}; + +enum class dma_region_mode : uint8_t +{ + EXTERNAL = 0, + INTERNAL = 1, +}; + +enum class dma_stride_mode : uint8_t +{ + D1 = 0, + D2 = 1, + D3 = 2, +}; + +enum class elementwise_mode : uint8_t +{ + MUL = 0, + ADD = 1, + SUB = 2, + MIN = 3, + MAX = 4, + LRELU = 5, + ABS = 6, + CLZ = 7, + SHR = 8, + SHL = 9, + LSR = 10, + DIV = 11, + CMP_EQ = 16, + CMP_NE = 17, + CMP_GE = 18, + CMP_GT = 19, + AND = 33, + OR = 34, + XOR = 35, + NOT = 36, + AND_NOT = 42, +}; + +enum class ifm_upscale_mode : uint8_t +{ + NONE = 0, + NEAREST = 1, + ZEROS = 2, +}; + +enum class kernel_decomposition : uint8_t +{ + D8X8 = 0, + D4X4 = 1, +}; + +enum class kernel_dilation : uint8_t +{ + NONE = 0, + X2 = 1, +}; + +enum class max_beats : uint8_t +{ + B64 = 0, + B128 = 1, + B256 = 2, +}; + +enum class microblock : uint8_t +{ + U1X1 = 0, + U1X2 = 1, + U1X4 = 2, + U2X2 = 3, + U2X4 = 4, + U4X4 = 5, +}; + +enum class ofm_scale_mode : uint8_t +{ + PER_CHANNEL = 0, + GLOBAL = 1, +}; + +enum class pmu_axi_channel : uint8_t +{ + RD_CMD = 0, + RD_IFM = 1, + RD_WEIGHTS = 2, + RD_SCALE_BIAS = 3, + RD_MEM2MEM = 4, + RD_IFM_STREAM = 5, + RD_MEM2MEM_IDX = 6, + WR_OFM = 8, + WR_MEM2MEM = 9, +}; + +enum class pmu_event : uint16_t +{ + NO_EVENT = 0, + CYCLE = 17, + NPU_IDLE = 32, + CC_STALLED_ON_BLOCKDEP = 33, + NPU_ACTIVE = 35, + MAC_ACTIVE = 48, + MAC_DPU_ACTIVE = 51, + MAC_STALLED_BY_W_OR_ACC = 52, + MAC_STALLED_BY_W = 53, + MAC_STALLED_BY_ACC = 54, + MAC_STALLED_BY_IB = 55, + AO_ACTIVE = 64, + AO_STALLED_BY_BS_OR_OB = 67, + AO_STALLED_BY_BS = 68, + AO_STALLED_BY_OB = 69, + AO_STALLED_BY_AB_OR_CB = 70, + AO_STALLED_BY_AB = 71, + AO_STALLED_BY_CB = 72, + WD_ACTIVE = 80, + WD_STALLED = 81, + WD_STALLED_BY_WD_BUF = 83, + WD_STALLED_BY_WS_FC = 84, + WD_STALLED_BY_WS_TC = 85, + WD_TRANS_WBLK = 89, + WD_TRANS_WS_FC = 90, + WD_TRANS_WS_TC = 91, + WD_STALLED_BY_WS_SC0 = 96, + WD_STALLED_BY_WS_SC1 = 97, + WD_STALLED_BY_WS_SC2 = 98, + WD_STALLED_BY_WS_SC3 = 99, + WD_PARSE_ACTIVE_SC0 = 100, + WD_PARSE_ACTIVE_SC1 = 101, + WD_PARSE_ACTIVE_SC2 = 102, + WD_PARSE_ACTIVE_SC3 = 103, + WD_PARSE_STALL_SC0 = 104, + WD_PARSE_STALL_SC1 = 105, + WD_PARSE_STALL_SC2 = 106, + WD_PARSE_STALL_SC3 = 107, + WD_PARSE_STALL_IN_SC0 = 108, + WD_PARSE_STALL_IN_SC1 = 109, + WD_PARSE_STALL_IN_SC2 = 110, + WD_PARSE_STALL_IN_SC3 = 111, + WD_PARSE_STALL_OUT_SC0 = 112, + WD_PARSE_STALL_OUT_SC1 = 113, + WD_PARSE_STALL_OUT_SC2 = 114, + WD_PARSE_STALL_OUT_SC3 = 115, + WD_TRANS_WS_SC0 = 116, + WD_TRANS_WS_SC1 = 117, + WD_TRANS_WS_SC2 = 118, + WD_TRANS_WS_SC3 = 119, + WD_TRANS_WB0 = 120, + WD_TRANS_WB1 = 121, + WD_TRANS_WB2 = 122, + WD_TRANS_WB3 = 123, + SRAM_RD_TRANS_ACCEPTED = 128, + SRAM_RD_TRANS_COMPLETED = 129, + SRAM_RD_DATA_BEAT_RECEIVED = 130, + SRAM_RD_TRAN_REQ_STALLED = 131, + SRAM_WR_TRANS_ACCEPTED = 132, + SRAM_WR_TRANS_COMPLETED_M = 133, + SRAM_WR_TRANS_COMPLETED_S = 134, + SRAM_WR_DATA_BEAT_WRITTEN = 135, + SRAM_WR_TRAN_REQ_STALLED = 136, + SRAM_WR_DATA_BEAT_STALLED = 137, + SRAM_ENABLED_CYCLES = 140, + SRAM_RD_STALL_LIMIT = 142, + SRAM_WR_STALL_LIMIT = 143, + AXI_LATENCY_ANY = 160, + AXI_LATENCY_32 = 161, + AXI_LATENCY_64 = 162, + AXI_LATENCY_128 = 163, + AXI_LATENCY_256 = 164, + AXI_LATENCY_512 = 165, + AXI_LATENCY_1024 = 166, + ECC_DMA = 176, + ECC_MAC_IB = 177, + ECC_MAC_AB = 178, + ECC_AO_CB = 179, + ECC_AO_OB = 180, + ECC_AO_LUT = 181, + EXT_RD_TRANS_ACCEPTED = 384, + EXT_RD_TRANS_COMPLETED = 385, + EXT_RD_DATA_BEAT_RECEIVED = 386, + EXT_RD_TRAN_REQ_STALLED = 387, + EXT_WR_TRANS_ACCEPTED = 388, + EXT_WR_TRANS_COMPLETED_M = 389, + EXT_WR_TRANS_COMPLETED_S = 390, + EXT_WR_DATA_BEAT_WRITTEN = 391, + EXT_WR_TRAN_REQ_STALLED = 392, + EXT_WR_DATA_BEAT_STALLED = 393, + EXT_ENABLED_CYCLES = 396, + EXT_RD_STALL_LIMIT = 398, + EXT_WR_STALL_LIMIT = 399, + SRAM0_RD_TRANS_ACCEPTED = 512, + SRAM0_RD_TRANS_COMPLETED = 513, + SRAM0_RD_DATA_BEAT_RECEIVED = 514, + SRAM0_RD_TRAN_REQ_STALLED = 515, + SRAM0_WR_TRANS_ACCEPTED = 516, + SRAM0_WR_TRANS_COMPLETED_M = 517, + SRAM0_WR_TRANS_COMPLETED_S = 518, + SRAM0_WR_DATA_BEAT_WRITTEN = 519, + SRAM0_WR_TRAN_REQ_STALLED = 520, + SRAM0_WR_DATA_BEAT_STALLED = 521, + SRAM0_ENABLED_CYCLES = 524, + SRAM0_RD_STALL_LIMIT = 526, + SRAM0_WR_STALL_LIMIT = 527, + SRAM1_RD_TRANS_ACCEPTED = 528, + SRAM1_RD_TRANS_COMPLETED = 529, + SRAM1_RD_DATA_BEAT_RECEIVED = 530, + SRAM1_RD_TRAN_REQ_STALLED = 531, + SRAM1_WR_TRANS_ACCEPTED = 532, + SRAM1_WR_TRANS_COMPLETED_M = 533, + SRAM1_WR_TRANS_COMPLETED_S = 534, + SRAM1_WR_DATA_BEAT_WRITTEN = 535, + SRAM1_WR_TRAN_REQ_STALLED = 536, + SRAM1_WR_DATA_BEAT_STALLED = 537, + SRAM1_ENABLED_CYCLES = 540, + SRAM1_RD_STALL_LIMIT = 542, + SRAM1_WR_STALL_LIMIT = 543, + SRAM2_RD_TRANS_ACCEPTED = 544, + SRAM2_RD_TRANS_COMPLETED = 545, + SRAM2_RD_DATA_BEAT_RECEIVED = 546, + SRAM2_RD_TRAN_REQ_STALLED = 547, + SRAM2_WR_TRANS_ACCEPTED = 548, + SRAM2_WR_TRANS_COMPLETED_M = 549, + SRAM2_WR_TRANS_COMPLETED_S = 550, + SRAM2_WR_DATA_BEAT_WRITTEN = 551, + SRAM2_WR_TRAN_REQ_STALLED = 552, + SRAM2_WR_DATA_BEAT_STALLED = 553, + SRAM2_ENABLED_CYCLES = 556, + SRAM2_RD_STALL_LIMIT = 558, + SRAM2_WR_STALL_LIMIT = 559, + SRAM3_RD_TRANS_ACCEPTED = 560, + SRAM3_RD_TRANS_COMPLETED = 561, + SRAM3_RD_DATA_BEAT_RECEIVED = 562, + SRAM3_RD_TRAN_REQ_STALLED = 563, + SRAM3_WR_TRANS_ACCEPTED = 564, + SRAM3_WR_TRANS_COMPLETED_M = 565, + SRAM3_WR_TRANS_COMPLETED_S = 566, + SRAM3_WR_DATA_BEAT_WRITTEN = 567, + SRAM3_WR_TRAN_REQ_STALLED = 568, + SRAM3_WR_DATA_BEAT_STALLED = 569, + SRAM3_ENABLED_CYCLES = 572, + SRAM3_RD_STALL_LIMIT = 574, + SRAM3_WR_STALL_LIMIT = 575, + EXT0_RD_TRANS_ACCEPTED = 640, + EXT0_RD_TRANS_COMPLETED = 641, + EXT0_RD_DATA_BEAT_RECEIVED = 642, + EXT0_RD_TRAN_REQ_STALLED = 643, + EXT0_WR_TRANS_ACCEPTED = 644, + EXT0_WR_TRANS_COMPLETED_M = 645, + EXT0_WR_TRANS_COMPLETED_S = 646, + EXT0_WR_DATA_BEAT_WRITTEN = 647, + EXT0_WR_TRAN_REQ_STALLED = 648, + EXT0_WR_DATA_BEAT_STALLED = 649, + EXT0_ENABLED_CYCLES = 652, + EXT0_RD_STALL_LIMIT = 654, + EXT0_WR_STALL_LIMIT = 655, + EXT1_RD_TRANS_ACCEPTED = 656, + EXT1_RD_TRANS_COMPLETED = 657, + EXT1_RD_DATA_BEAT_RECEIVED = 658, + EXT1_RD_TRAN_REQ_STALLED = 659, + EXT1_WR_TRANS_ACCEPTED = 660, + EXT1_WR_TRANS_COMPLETED_M = 661, + EXT1_WR_TRANS_COMPLETED_S = 662, + EXT1_WR_DATA_BEAT_WRITTEN = 663, + EXT1_WR_TRAN_REQ_STALLED = 664, + EXT1_WR_DATA_BEAT_STALLED = 665, + EXT1_ENABLED_CYCLES = 668, + EXT1_RD_STALL_LIMIT = 670, + EXT1_WR_STALL_LIMIT = 671, +}; + +enum class pmu_port_disable : uint8_t +{ + ENABLE = 0, + DISABLE = 1, +}; + +enum class pooling_mode : uint8_t +{ + MAX = 0, + AVERAGE = 1, + REDUCE_SUM = 2, + SUM = 3, + NONE = 4, + MIN = 5, + ARGMAX_X = 6, + ARGMAX_Y = 7, +}; + +enum class privilege_level : uint8_t +{ + USER = 0, + PRIVILEGED = 1, +}; + +enum class ram_id : uint8_t +{ + LUT = 0, + IB = 1, + AB = 2, + CB = 3, + OB = 4, +}; + +enum class resize_mode : uint8_t +{ + BILINEAR = 0, + REPLICATE = 1, + NEAREST = 2, +}; + +enum class round_mode_ifm : uint8_t +{ + DOUBLE_SYMMETRIC = 0, + NATURAL = 1, +}; + +enum class round_mode_ofm : uint8_t +{ + DOUBLE_SYMMETRIC = 0, + NATURAL = 1, + DOUBLE_ASYMMETRIC = 2, + SYMMETRIC = 3, + TRUNCATE_TO_ZERO = 4, + TRUNCATE_TO_LOWER = 5, +}; + +enum class security_level : uint8_t +{ + SECURE = 0, + NON_SECURE = 1, +}; + +enum class state : uint8_t +{ + STOPPED = 0, + RUNNING = 1, +}; + +enum class wd_active_core : uint8_t +{ + NONE = 0, + STANDARD = 1, + FAST = 2, + TENSOR = 3, +}; + +enum class weight_format : uint8_t +{ + SWD = 0, + FWD = 1, +}; + +enum class weight_order : uint8_t +{ + DEPTH_FIRST = 0, + PART_KERNEL_FIRST = 1, +}; + +enum class weight_sparsity : uint8_t +{ + NONE = 0, + SPARSE_2_4 = 1, +}; + +#else + +enum acc_format +{ + ACC_FORMAT_I32 = 0, + ACC_FORMAT_I48 = 1, +}; + +enum acc_input +{ + ACC_INPUT_RESET = 0, + ACC_INPUT_KEEP = 1, + ACC_INPUT_IFM2 = 2, +}; + +enum acc_output +{ + ACC_OUTPUT_ENABLE = 0, + ACC_OUTPUT_DISABLE = 1, +}; + +enum activation_clip_range +{ + ACTIVATION_CLIP_RANGE_B16 = 0, + ACTIVATION_CLIP_RANGE_NONE = 1, +}; + +enum activation_format +{ + ACTIVATION_FORMAT_NHWC = 0, + ACTIVATION_FORMAT_NHCWB16 = 1, +}; + +enum activation_function +{ + ACTIVATION_FUNCTION_LUT_NONE = 0, + ACTIVATION_FUNCTION_LUT_U8_U8 = 1, + ACTIVATION_FUNCTION_LUT_S8_S8 = 4, + ACTIVATION_FUNCTION_LUT_S8_S16 = 5, + ACTIVATION_FUNCTION_LUT_S8_S32 = 7, + ACTIVATION_FUNCTION_LUT_S16_S16 = 8, + ACTIVATION_FUNCTION_LUT_S16_S32 = 9, + ACTIVATION_FUNCTION_LUT_TANH = 10, + ACTIVATION_FUNCTION_LUT_SIGMOID = 11, +}; + +enum activation_precision +{ + ACTIVATION_PRECISION_B8 = 0, + ACTIVATION_PRECISION_B16 = 1, + ACTIVATION_PRECISION_B32 = 2, + ACTIVATION_PRECISION_B64 = 3, +}; + +enum activation_reverse +{ + ACTIVATION_REVERSE_NONE = 0, + ACTIVATION_REVERSE_H = 1, + ACTIVATION_REVERSE_W = 2, + ACTIVATION_REVERSE_C = 3, +}; + +enum activation_storage +{ + ACTIVATION_STORAGE_TILE2X2 = 0, + ACTIVATION_STORAGE_TILE3X1 = 1, + ACTIVATION_STORAGE_CHAINED = 2, + ACTIVATION_STORAGE_NONE = 3, +}; + +enum activation_transpose +{ + ACTIVATION_TRANSPOSE_HWC = 0, + ACTIVATION_TRANSPOSE_WHC = 1, + ACTIVATION_TRANSPOSE_HCW = 2, + ACTIVATION_TRANSPOSE_WCH = 3, + ACTIVATION_TRANSPOSE_CHW = 6, + ACTIVATION_TRANSPOSE_CWH = 7, +}; + +enum activation_type +{ + ACTIVATION_TYPE_UNSIGNED = 0, + ACTIVATION_TYPE_SIGNED = 1, +}; + +enum axi_mem_domain +{ + AXI_MEM_DOMAIN_NON_SHARABLE = 0, + AXI_MEM_DOMAIN_INNER_SHARABLE = 1, + AXI_MEM_DOMAIN_OUTER_SHARABLE = 2, + AXI_MEM_DOMAIN_SYSTEM = 3, +}; + +enum axi_mem_encoding +{ + AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE = 0, + AXI_MEM_ENCODING_DEVICE_BUFFERABLE = 1, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 2, + AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE = 3, + AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE = 4, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE = 5, + AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE = 6, + AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE = 7, + AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE = 8, + AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE = 9, + AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE = 10, + AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE = 11, +}; + +enum axi_port +{ + AXI_PORT_SRAM = 0, + AXI_PORT_EXT = 1, +}; + +enum branch_cond +{ + BRANCH_COND_ALWAYS = 0, + BRANCH_COND_RF_TRUE = 1, +}; + +enum broadcast_mode +{ + BROADCAST_MODE_NONE = 0, + BROADCAST_MODE_H = 1, + BROADCAST_MODE_W = 2, + BROADCAST_MODE_HW = 3, + BROADCAST_MODE_C = 4, + BROADCAST_MODE_CH = 5, + BROADCAST_MODE_CW = 6, + BROADCAST_MODE_CWH = 7, + BROADCAST_MODE_SCALAR = 8, +}; + +enum cmd0_opcode +{ + CMD0_OPCODE_NPU_OP_STOP = 0, + CMD0_OPCODE_NPU_OP_IRQ = 1, + CMD0_OPCODE_NPU_OP_CONV = 2, + CMD0_OPCODE_NPU_OP_DEPTHWISE = 3, + CMD0_OPCODE_NPU_OP_POOL = 5, + CMD0_OPCODE_NPU_OP_ELEMENTWISE = 6, + CMD0_OPCODE_NPU_OP_RESIZE = 7, + CMD0_OPCODE_NPU_OP_DMA_START = 16, + CMD0_OPCODE_NPU_OP_DMA_WAIT = 17, + CMD0_OPCODE_NPU_OP_KERNEL_WAIT = 18, + CMD0_OPCODE_NPU_OP_PMU_MASK = 19, + CMD0_OPCODE_NPU_SET_IFM_PAD_TOP = 256, + CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT = 257, + CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT = 258, + CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM = 259, + CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1 = 260, + CMD0_OPCODE_NPU_SET_IFM_PRECISION = 261, + CMD0_OPCODE_NPU_SET_IFM_UPSCALE = 263, + CMD0_OPCODE_NPU_SET_IFM_BROADCAST = 264, + CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT = 265, + CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1 = 266, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1 = 267, + CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1 = 268, + CMD0_OPCODE_NPU_SET_IFM_REGION = 271, + CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1 = 273, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1 = 274, + CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1 = 275, + CMD0_OPCODE_NPU_SET_OFM_PRECISION = 276, + CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1 = 277, + CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1 = 278, + CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1 = 279, + CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT = 280, + CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1 = 282, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1 = 283, + CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1 = 284, + CMD0_OPCODE_NPU_SET_OFM_REGION = 287, + CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1 = 288, + CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1 = 289, + CMD0_OPCODE_NPU_SET_KERNEL_STRIDE = 290, + CMD0_OPCODE_NPU_SET_ACC_FORMAT = 292, + CMD0_OPCODE_NPU_SET_ACTIVATION = 293, + CMD0_OPCODE_NPU_SET_ACTIVATION_MIN = 294, + CMD0_OPCODE_NPU_SET_ACTIVATION_MAX = 295, + CMD0_OPCODE_NPU_SET_WEIGHT_REGION = 296, + CMD0_OPCODE_NPU_SET_SCALE_REGION = 297, + CMD0_OPCODE_NPU_SET_RESIZE_X_SCALE_N_M1 = 298, + CMD0_OPCODE_NPU_SET_RESIZE_Y_SCALE_N_M1 = 299, + CMD0_OPCODE_NPU_SET_RESIZE_X_OFFSET = 300, + CMD0_OPCODE_NPU_SET_RESIZE_Y_OFFSET = 301, + CMD0_OPCODE_NPU_SET_WEIGHT_FORMAT = 302, + CMD0_OPCODE_NPU_SET_BLOCKDEP = 303, + CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION = 304, + CMD0_OPCODE_NPU_SET_DMA0_DST_REGION = 305, + CMD0_OPCODE_NPU_SET_DMA0_SIZE0 = 306, + CMD0_OPCODE_NPU_SET_DMA0_SIZE1 = 307, + CMD0_OPCODE_NPU_SET_DMA0_IDX_REGION = 308, + CMD0_OPCODE_NPU_SET_IFM2_BROADCAST = 384, + CMD0_OPCODE_NPU_SET_IFM2_PRECISION = 389, + CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT = 393, + CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1 = 394, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1 = 395, + CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1 = 396, + CMD0_OPCODE_NPU_SET_IFM2_REGION = 399, +}; + +enum cmd1_opcode +{ + CMD1_OPCODE_NPU_SET_IFM_BASE0 = 0, + CMD1_OPCODE_NPU_SET_IFM_BASE1 = 1, + CMD1_OPCODE_NPU_SET_IFM_BASE2 = 2, + CMD1_OPCODE_NPU_SET_IFM_BASE3 = 3, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_X = 4, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y = 5, + CMD1_OPCODE_NPU_SET_IFM_STRIDE_C = 6, + CMD1_OPCODE_NPU_SET_OFM_BASE0 = 16, + CMD1_OPCODE_NPU_SET_OFM_BASE1 = 17, + CMD1_OPCODE_NPU_SET_OFM_BASE2 = 18, + CMD1_OPCODE_NPU_SET_OFM_BASE3 = 19, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_X = 20, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y = 21, + CMD1_OPCODE_NPU_SET_OFM_STRIDE_C = 22, + CMD1_OPCODE_NPU_SET_WEIGHT_BASE = 32, + CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH = 33, + CMD1_OPCODE_NPU_SET_SCALE_BASE = 34, + CMD1_OPCODE_NPU_SET_SCALE_LENGTH = 35, + CMD1_OPCODE_NPU_SET_OFM_SCALE = 36, + CMD1_OPCODE_NPU_SET_IFM_SCALE = 37, + CMD1_OPCODE_NPU_SET_IFM2_SCALE = 38, + CMD1_OPCODE_NPU_SET_OP_SCALAR = 39, + CMD1_OPCODE_NPU_SET_DMA0_SRC = 48, + CMD1_OPCODE_NPU_SET_DMA0_DST = 49, + CMD1_OPCODE_NPU_SET_DMA0_LEN = 50, + CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE0 = 51, + CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE1 = 52, + CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE0 = 53, + CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE1 = 54, + CMD1_OPCODE_NPU_SET_DMA0_IDX = 55, + CMD1_OPCODE_NPU_SET_DMA0_IDX_MAX = 56, + CMD1_OPCODE_NPU_SET_DMA0_IDX_SKIP1 = 57, + CMD1_OPCODE_NPU_SET_IFM2_BASE0 = 128, + CMD1_OPCODE_NPU_SET_IFM2_BASE1 = 129, + CMD1_OPCODE_NPU_SET_IFM2_BASE2 = 130, + CMD1_OPCODE_NPU_SET_IFM2_BASE3 = 131, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X = 132, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y = 133, + CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C = 134, + CMD1_OPCODE_NPU_SET_WEIGHT1_BASE = 144, + CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH = 145, + CMD1_OPCODE_NPU_SET_WEIGHT2_BASE = 146, + CMD1_OPCODE_NPU_SET_WEIGHT2_LENGTH = 147, + CMD1_OPCODE_NPU_SET_WEIGHT3_BASE = 148, + CMD1_OPCODE_NPU_SET_WEIGHT3_LENGTH = 149, + CMD1_OPCODE_NPU_SET_RESIZE_X = 150, + CMD1_OPCODE_NPU_SET_RESIZE_Y = 151, + CMD1_OPCODE_NPU_OP_BRANCH = 256, +}; + +enum cmd_ctrl +{ + CMD_CTRL_CMD0_CTRL = 0, + CMD_CTRL_CMD1_CTRL = 1, +}; + +enum custom_dma +{ + CUSTOM_DMA_NOT_IMPLEMENTED = 0, + CUSTOM_DMA_IMPLEMENTED = 1, +}; + +enum dma_fault_src +{ + DMA_FAULT_SRC_SRAM = 0, + DMA_FAULT_SRC_EXT = 1, +}; + +enum dma_idx_mode +{ + DMA_IDX_MODE_DISABLED = 0, + DMA_IDX_MODE_ENABLED = 1, +}; + +enum dma_region_mode +{ + DMA_REGION_MODE_EXTERNAL = 0, + DMA_REGION_MODE_INTERNAL = 1, +}; + +enum dma_stride_mode +{ + DMA_STRIDE_MODE_D1 = 0, + DMA_STRIDE_MODE_D2 = 1, + DMA_STRIDE_MODE_D3 = 2, +}; + +enum elementwise_mode +{ + ELEMENTWISE_MODE_MUL = 0, + ELEMENTWISE_MODE_ADD = 1, + ELEMENTWISE_MODE_SUB = 2, + ELEMENTWISE_MODE_MIN = 3, + ELEMENTWISE_MODE_MAX = 4, + ELEMENTWISE_MODE_LRELU = 5, + ELEMENTWISE_MODE_ABS = 6, + ELEMENTWISE_MODE_CLZ = 7, + ELEMENTWISE_MODE_SHR = 8, + ELEMENTWISE_MODE_SHL = 9, + ELEMENTWISE_MODE_LSR = 10, + ELEMENTWISE_MODE_DIV = 11, + ELEMENTWISE_MODE_CMP_EQ = 16, + ELEMENTWISE_MODE_CMP_NE = 17, + ELEMENTWISE_MODE_CMP_GE = 18, + ELEMENTWISE_MODE_CMP_GT = 19, + ELEMENTWISE_MODE_AND = 33, + ELEMENTWISE_MODE_OR = 34, + ELEMENTWISE_MODE_XOR = 35, + ELEMENTWISE_MODE_NOT = 36, + ELEMENTWISE_MODE_AND_NOT = 42, +}; + +enum ifm_upscale_mode +{ + IFM_UPSCALE_MODE_NONE = 0, + IFM_UPSCALE_MODE_NEAREST = 1, + IFM_UPSCALE_MODE_ZEROS = 2, +}; + +enum kernel_decomposition +{ + KERNEL_DECOMPOSITION_D8X8 = 0, + KERNEL_DECOMPOSITION_D4X4 = 1, +}; + +enum kernel_dilation +{ + KERNEL_DILATION_NONE = 0, + KERNEL_DILATION_X2 = 1, +}; + +enum max_beats +{ + MAX_BEATS_B64 = 0, + MAX_BEATS_B128 = 1, + MAX_BEATS_B256 = 2, +}; + +enum microblock +{ + MICROBLOCK_U1X1 = 0, + MICROBLOCK_U1X2 = 1, + MICROBLOCK_U1X4 = 2, + MICROBLOCK_U2X2 = 3, + MICROBLOCK_U2X4 = 4, + MICROBLOCK_U4X4 = 5, +}; + +enum ofm_scale_mode +{ + OFM_SCALE_MODE_PER_CHANNEL = 0, + OFM_SCALE_MODE_GLOBAL = 1, +}; + +enum pmu_axi_channel +{ + PMU_AXI_CHANNEL_RD_CMD = 0, + PMU_AXI_CHANNEL_RD_IFM = 1, + PMU_AXI_CHANNEL_RD_WEIGHTS = 2, + PMU_AXI_CHANNEL_RD_SCALE_BIAS = 3, + PMU_AXI_CHANNEL_RD_MEM2MEM = 4, + PMU_AXI_CHANNEL_RD_IFM_STREAM = 5, + PMU_AXI_CHANNEL_RD_MEM2MEM_IDX = 6, + PMU_AXI_CHANNEL_WR_OFM = 8, + PMU_AXI_CHANNEL_WR_MEM2MEM = 9, +}; + +enum pmu_event +{ + PMU_EVENT_NO_EVENT = 0, + PMU_EVENT_CYCLE = 17, + PMU_EVENT_NPU_IDLE = 32, + PMU_EVENT_CC_STALLED_ON_BLOCKDEP = 33, + PMU_EVENT_NPU_ACTIVE = 35, + PMU_EVENT_MAC_ACTIVE = 48, + PMU_EVENT_MAC_DPU_ACTIVE = 51, + PMU_EVENT_MAC_STALLED_BY_W_OR_ACC = 52, + PMU_EVENT_MAC_STALLED_BY_W = 53, + PMU_EVENT_MAC_STALLED_BY_ACC = 54, + PMU_EVENT_MAC_STALLED_BY_IB = 55, + PMU_EVENT_AO_ACTIVE = 64, + PMU_EVENT_AO_STALLED_BY_BS_OR_OB = 67, + PMU_EVENT_AO_STALLED_BY_BS = 68, + PMU_EVENT_AO_STALLED_BY_OB = 69, + PMU_EVENT_AO_STALLED_BY_AB_OR_CB = 70, + PMU_EVENT_AO_STALLED_BY_AB = 71, + PMU_EVENT_AO_STALLED_BY_CB = 72, + PMU_EVENT_WD_ACTIVE = 80, + PMU_EVENT_WD_STALLED = 81, + PMU_EVENT_WD_STALLED_BY_WD_BUF = 83, + PMU_EVENT_WD_STALLED_BY_WS_FC = 84, + PMU_EVENT_WD_STALLED_BY_WS_TC = 85, + PMU_EVENT_WD_TRANS_WBLK = 89, + PMU_EVENT_WD_TRANS_WS_FC = 90, + PMU_EVENT_WD_TRANS_WS_TC = 91, + PMU_EVENT_WD_STALLED_BY_WS_SC0 = 96, + PMU_EVENT_WD_STALLED_BY_WS_SC1 = 97, + PMU_EVENT_WD_STALLED_BY_WS_SC2 = 98, + PMU_EVENT_WD_STALLED_BY_WS_SC3 = 99, + PMU_EVENT_WD_PARSE_ACTIVE_SC0 = 100, + PMU_EVENT_WD_PARSE_ACTIVE_SC1 = 101, + PMU_EVENT_WD_PARSE_ACTIVE_SC2 = 102, + PMU_EVENT_WD_PARSE_ACTIVE_SC3 = 103, + PMU_EVENT_WD_PARSE_STALL_SC0 = 104, + PMU_EVENT_WD_PARSE_STALL_SC1 = 105, + PMU_EVENT_WD_PARSE_STALL_SC2 = 106, + PMU_EVENT_WD_PARSE_STALL_SC3 = 107, + PMU_EVENT_WD_PARSE_STALL_IN_SC0 = 108, + PMU_EVENT_WD_PARSE_STALL_IN_SC1 = 109, + PMU_EVENT_WD_PARSE_STALL_IN_SC2 = 110, + PMU_EVENT_WD_PARSE_STALL_IN_SC3 = 111, + PMU_EVENT_WD_PARSE_STALL_OUT_SC0 = 112, + PMU_EVENT_WD_PARSE_STALL_OUT_SC1 = 113, + PMU_EVENT_WD_PARSE_STALL_OUT_SC2 = 114, + PMU_EVENT_WD_PARSE_STALL_OUT_SC3 = 115, + PMU_EVENT_WD_TRANS_WS_SC0 = 116, + PMU_EVENT_WD_TRANS_WS_SC1 = 117, + PMU_EVENT_WD_TRANS_WS_SC2 = 118, + PMU_EVENT_WD_TRANS_WS_SC3 = 119, + PMU_EVENT_WD_TRANS_WB0 = 120, + PMU_EVENT_WD_TRANS_WB1 = 121, + PMU_EVENT_WD_TRANS_WB2 = 122, + PMU_EVENT_WD_TRANS_WB3 = 123, + PMU_EVENT_SRAM_RD_TRANS_ACCEPTED = 128, + PMU_EVENT_SRAM_RD_TRANS_COMPLETED = 129, + PMU_EVENT_SRAM_RD_DATA_BEAT_RECEIVED = 130, + PMU_EVENT_SRAM_RD_TRAN_REQ_STALLED = 131, + PMU_EVENT_SRAM_WR_TRANS_ACCEPTED = 132, + PMU_EVENT_SRAM_WR_TRANS_COMPLETED_M = 133, + PMU_EVENT_SRAM_WR_TRANS_COMPLETED_S = 134, + PMU_EVENT_SRAM_WR_DATA_BEAT_WRITTEN = 135, + PMU_EVENT_SRAM_WR_TRAN_REQ_STALLED = 136, + PMU_EVENT_SRAM_WR_DATA_BEAT_STALLED = 137, + PMU_EVENT_SRAM_ENABLED_CYCLES = 140, + PMU_EVENT_SRAM_RD_STALL_LIMIT = 142, + PMU_EVENT_SRAM_WR_STALL_LIMIT = 143, + PMU_EVENT_AXI_LATENCY_ANY = 160, + PMU_EVENT_AXI_LATENCY_32 = 161, + PMU_EVENT_AXI_LATENCY_64 = 162, + PMU_EVENT_AXI_LATENCY_128 = 163, + PMU_EVENT_AXI_LATENCY_256 = 164, + PMU_EVENT_AXI_LATENCY_512 = 165, + PMU_EVENT_AXI_LATENCY_1024 = 166, + PMU_EVENT_ECC_DMA = 176, + PMU_EVENT_ECC_MAC_IB = 177, + PMU_EVENT_ECC_MAC_AB = 178, + PMU_EVENT_ECC_AO_CB = 179, + PMU_EVENT_ECC_AO_OB = 180, + PMU_EVENT_ECC_AO_LUT = 181, + PMU_EVENT_EXT_RD_TRANS_ACCEPTED = 384, + PMU_EVENT_EXT_RD_TRANS_COMPLETED = 385, + PMU_EVENT_EXT_RD_DATA_BEAT_RECEIVED = 386, + PMU_EVENT_EXT_RD_TRAN_REQ_STALLED = 387, + PMU_EVENT_EXT_WR_TRANS_ACCEPTED = 388, + PMU_EVENT_EXT_WR_TRANS_COMPLETED_M = 389, + PMU_EVENT_EXT_WR_TRANS_COMPLETED_S = 390, + PMU_EVENT_EXT_WR_DATA_BEAT_WRITTEN = 391, + PMU_EVENT_EXT_WR_TRAN_REQ_STALLED = 392, + PMU_EVENT_EXT_WR_DATA_BEAT_STALLED = 393, + PMU_EVENT_EXT_ENABLED_CYCLES = 396, + PMU_EVENT_EXT_RD_STALL_LIMIT = 398, + PMU_EVENT_EXT_WR_STALL_LIMIT = 399, + PMU_EVENT_SRAM0_RD_TRANS_ACCEPTED = 512, + PMU_EVENT_SRAM0_RD_TRANS_COMPLETED = 513, + PMU_EVENT_SRAM0_RD_DATA_BEAT_RECEIVED = 514, + PMU_EVENT_SRAM0_RD_TRAN_REQ_STALLED = 515, + PMU_EVENT_SRAM0_WR_TRANS_ACCEPTED = 516, + PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_M = 517, + PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_S = 518, + PMU_EVENT_SRAM0_WR_DATA_BEAT_WRITTEN = 519, + PMU_EVENT_SRAM0_WR_TRAN_REQ_STALLED = 520, + PMU_EVENT_SRAM0_WR_DATA_BEAT_STALLED = 521, + PMU_EVENT_SRAM0_ENABLED_CYCLES = 524, + PMU_EVENT_SRAM0_RD_STALL_LIMIT = 526, + PMU_EVENT_SRAM0_WR_STALL_LIMIT = 527, + PMU_EVENT_SRAM1_RD_TRANS_ACCEPTED = 528, + PMU_EVENT_SRAM1_RD_TRANS_COMPLETED = 529, + PMU_EVENT_SRAM1_RD_DATA_BEAT_RECEIVED = 530, + PMU_EVENT_SRAM1_RD_TRAN_REQ_STALLED = 531, + PMU_EVENT_SRAM1_WR_TRANS_ACCEPTED = 532, + PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_M = 533, + PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_S = 534, + PMU_EVENT_SRAM1_WR_DATA_BEAT_WRITTEN = 535, + PMU_EVENT_SRAM1_WR_TRAN_REQ_STALLED = 536, + PMU_EVENT_SRAM1_WR_DATA_BEAT_STALLED = 537, + PMU_EVENT_SRAM1_ENABLED_CYCLES = 540, + PMU_EVENT_SRAM1_RD_STALL_LIMIT = 542, + PMU_EVENT_SRAM1_WR_STALL_LIMIT = 543, + PMU_EVENT_SRAM2_RD_TRANS_ACCEPTED = 544, + PMU_EVENT_SRAM2_RD_TRANS_COMPLETED = 545, + PMU_EVENT_SRAM2_RD_DATA_BEAT_RECEIVED = 546, + PMU_EVENT_SRAM2_RD_TRAN_REQ_STALLED = 547, + PMU_EVENT_SRAM2_WR_TRANS_ACCEPTED = 548, + PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_M = 549, + PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_S = 550, + PMU_EVENT_SRAM2_WR_DATA_BEAT_WRITTEN = 551, + PMU_EVENT_SRAM2_WR_TRAN_REQ_STALLED = 552, + PMU_EVENT_SRAM2_WR_DATA_BEAT_STALLED = 553, + PMU_EVENT_SRAM2_ENABLED_CYCLES = 556, + PMU_EVENT_SRAM2_RD_STALL_LIMIT = 558, + PMU_EVENT_SRAM2_WR_STALL_LIMIT = 559, + PMU_EVENT_SRAM3_RD_TRANS_ACCEPTED = 560, + PMU_EVENT_SRAM3_RD_TRANS_COMPLETED = 561, + PMU_EVENT_SRAM3_RD_DATA_BEAT_RECEIVED = 562, + PMU_EVENT_SRAM3_RD_TRAN_REQ_STALLED = 563, + PMU_EVENT_SRAM3_WR_TRANS_ACCEPTED = 564, + PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_M = 565, + PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_S = 566, + PMU_EVENT_SRAM3_WR_DATA_BEAT_WRITTEN = 567, + PMU_EVENT_SRAM3_WR_TRAN_REQ_STALLED = 568, + PMU_EVENT_SRAM3_WR_DATA_BEAT_STALLED = 569, + PMU_EVENT_SRAM3_ENABLED_CYCLES = 572, + PMU_EVENT_SRAM3_RD_STALL_LIMIT = 574, + PMU_EVENT_SRAM3_WR_STALL_LIMIT = 575, + PMU_EVENT_EXT0_RD_TRANS_ACCEPTED = 640, + PMU_EVENT_EXT0_RD_TRANS_COMPLETED = 641, + PMU_EVENT_EXT0_RD_DATA_BEAT_RECEIVED = 642, + PMU_EVENT_EXT0_RD_TRAN_REQ_STALLED = 643, + PMU_EVENT_EXT0_WR_TRANS_ACCEPTED = 644, + PMU_EVENT_EXT0_WR_TRANS_COMPLETED_M = 645, + PMU_EVENT_EXT0_WR_TRANS_COMPLETED_S = 646, + PMU_EVENT_EXT0_WR_DATA_BEAT_WRITTEN = 647, + PMU_EVENT_EXT0_WR_TRAN_REQ_STALLED = 648, + PMU_EVENT_EXT0_WR_DATA_BEAT_STALLED = 649, + PMU_EVENT_EXT0_ENABLED_CYCLES = 652, + PMU_EVENT_EXT0_RD_STALL_LIMIT = 654, + PMU_EVENT_EXT0_WR_STALL_LIMIT = 655, + PMU_EVENT_EXT1_RD_TRANS_ACCEPTED = 656, + PMU_EVENT_EXT1_RD_TRANS_COMPLETED = 657, + PMU_EVENT_EXT1_RD_DATA_BEAT_RECEIVED = 658, + PMU_EVENT_EXT1_RD_TRAN_REQ_STALLED = 659, + PMU_EVENT_EXT1_WR_TRANS_ACCEPTED = 660, + PMU_EVENT_EXT1_WR_TRANS_COMPLETED_M = 661, + PMU_EVENT_EXT1_WR_TRANS_COMPLETED_S = 662, + PMU_EVENT_EXT1_WR_DATA_BEAT_WRITTEN = 663, + PMU_EVENT_EXT1_WR_TRAN_REQ_STALLED = 664, + PMU_EVENT_EXT1_WR_DATA_BEAT_STALLED = 665, + PMU_EVENT_EXT1_ENABLED_CYCLES = 668, + PMU_EVENT_EXT1_RD_STALL_LIMIT = 670, + PMU_EVENT_EXT1_WR_STALL_LIMIT = 671, +}; + +enum pmu_port_disable +{ + PMU_PORT_DISABLE_ENABLE = 0, + PMU_PORT_DISABLE_DISABLE = 1, +}; + +enum pooling_mode +{ + POOLING_MODE_MAX = 0, + POOLING_MODE_AVERAGE = 1, + POOLING_MODE_REDUCE_SUM = 2, + POOLING_MODE_SUM = 3, + POOLING_MODE_NONE = 4, + POOLING_MODE_MIN = 5, + POOLING_MODE_ARGMAX_X = 6, + POOLING_MODE_ARGMAX_Y = 7, +}; + +enum privilege_level +{ + PRIVILEGE_LEVEL_USER = 0, + PRIVILEGE_LEVEL_PRIVILEGED = 1, +}; + +enum ram_id +{ + RAM_ID_LUT = 0, + RAM_ID_IB = 1, + RAM_ID_AB = 2, + RAM_ID_CB = 3, + RAM_ID_OB = 4, +}; + +enum resize_mode +{ + RESIZE_MODE_BILINEAR = 0, + RESIZE_MODE_REPLICATE = 1, + RESIZE_MODE_NEAREST = 2, +}; + +enum round_mode_ifm +{ + ROUND_MODE_IFM_DOUBLE_SYMMETRIC = 0, + ROUND_MODE_IFM_NATURAL = 1, +}; + +enum round_mode_ofm +{ + ROUND_MODE_OFM_DOUBLE_SYMMETRIC = 0, + ROUND_MODE_OFM_NATURAL = 1, + ROUND_MODE_OFM_DOUBLE_ASYMMETRIC = 2, + ROUND_MODE_OFM_SYMMETRIC = 3, + ROUND_MODE_OFM_TRUNCATE_TO_ZERO = 4, + ROUND_MODE_OFM_TRUNCATE_TO_LOWER = 5, +}; + +enum security_level +{ + SECURITY_LEVEL_SECURE = 0, + SECURITY_LEVEL_NON_SECURE = 1, +}; + +enum state +{ + STATE_STOPPED = 0, + STATE_RUNNING = 1, +}; + +enum wd_active_core +{ + WD_ACTIVE_CORE_NONE = 0, + WD_ACTIVE_CORE_STANDARD = 1, + WD_ACTIVE_CORE_FAST = 2, + WD_ACTIVE_CORE_TENSOR = 3, +}; + +enum weight_format +{ + WEIGHT_FORMAT_SWD = 0, + WEIGHT_FORMAT_FWD = 1, +}; + +enum weight_order +{ + WEIGHT_ORDER_DEPTH_FIRST = 0, + WEIGHT_ORDER_PART_KERNEL_FIRST = 1, +}; + +enum weight_sparsity +{ + WEIGHT_SPARSITY_NONE = 0, + WEIGHT_SPARSITY_SPARSE_2_4 = 1, +}; + +#endif + +#ifdef NPU_DISASSEMBLE + +static const char* acc_format_str[] = +{ + "ACC_FORMAT_I32", + "ACC_FORMAT_I48", +}; + +static const char* acc_input_str[] = +{ + "ACC_INPUT_RESET", + "ACC_INPUT_KEEP", + "ACC_INPUT_IFM2", +}; + +static const char* acc_output_str[] = +{ + "ACC_OUTPUT_ENABLE", + "ACC_OUTPUT_DISABLE", +}; + +static const char* activation_clip_range_str[] = +{ + "ACTIVATION_CLIP_RANGE_B16", + "ACTIVATION_CLIP_RANGE_NONE", +}; + +static const char* activation_format_str[] = +{ + "ACTIVATION_FORMAT_NHWC", + "ACTIVATION_FORMAT_NHCWB16", +}; + +static const char* activation_function_str[] = +{ + "ACTIVATION_FUNCTION_LUT_NONE", + "ACTIVATION_FUNCTION_LUT_U8_U8", + "****", + "****", + "ACTIVATION_FUNCTION_LUT_S8_S8", + "ACTIVATION_FUNCTION_LUT_S8_S16", + "****", + "ACTIVATION_FUNCTION_LUT_S8_S32", + "ACTIVATION_FUNCTION_LUT_S16_S16", + "ACTIVATION_FUNCTION_LUT_S16_S32", + "ACTIVATION_FUNCTION_LUT_TANH", + "ACTIVATION_FUNCTION_LUT_SIGMOID", +}; + +static const char* activation_precision_str[] = +{ + "ACTIVATION_PRECISION_B8", + "ACTIVATION_PRECISION_B16", + "ACTIVATION_PRECISION_B32", + "ACTIVATION_PRECISION_B64", +}; + +static const char* activation_reverse_str[] = +{ + "ACTIVATION_REVERSE_NONE", + "ACTIVATION_REVERSE_H", + "ACTIVATION_REVERSE_W", + "ACTIVATION_REVERSE_C", +}; + +static const char* activation_storage_str[] = +{ + "ACTIVATION_STORAGE_TILE2X2", + "ACTIVATION_STORAGE_TILE3X1", + "ACTIVATION_STORAGE_CHAINED", + "ACTIVATION_STORAGE_NONE", +}; + +static const char* activation_transpose_str[] = +{ + "ACTIVATION_TRANSPOSE_HWC", + "ACTIVATION_TRANSPOSE_WHC", + "ACTIVATION_TRANSPOSE_HCW", + "ACTIVATION_TRANSPOSE_WCH", + "****", + "****", + "ACTIVATION_TRANSPOSE_CHW", + "ACTIVATION_TRANSPOSE_CWH", +}; + +static const char* activation_type_str[] = +{ + "ACTIVATION_TYPE_UNSIGNED", + "ACTIVATION_TYPE_SIGNED", +}; + +static const char* axi_mem_domain_str[] = +{ + "AXI_MEM_DOMAIN_NON_SHARABLE", + "AXI_MEM_DOMAIN_INNER_SHARABLE", + "AXI_MEM_DOMAIN_OUTER_SHARABLE", + "AXI_MEM_DOMAIN_SYSTEM", +}; + +static const char* axi_mem_encoding_str[] = +{ + "AXI_MEM_ENCODING_DEVICE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_DEVICE_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_NON_BUFFERABLE", + "AXI_MEM_ENCODING_NORMAL_NON_CACHEABLE_BUFFERABLE", + "AXI_MEM_ENCODING_WRITE_THROUGH_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_NO_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_WRITE_ALLOCATE", + "AXI_MEM_ENCODING_WRITE_BACK_READ_AND_WRITE_ALLOCATE", +}; + +static const char* axi_port_str[] = +{ + "AXI_PORT_SRAM", + "AXI_PORT_EXT", +}; + +static const char* branch_cond_str[] = +{ + "BRANCH_COND_ALWAYS", + "BRANCH_COND_RF_TRUE", +}; + +static const char* broadcast_mode_str[] = +{ + "BROADCAST_MODE_NONE", + "BROADCAST_MODE_H", + "BROADCAST_MODE_W", + "BROADCAST_MODE_HW", + "BROADCAST_MODE_C", + "BROADCAST_MODE_CH", + "BROADCAST_MODE_CW", + "BROADCAST_MODE_CWH", + "BROADCAST_MODE_SCALAR", +}; + +static const char* cmd0_opcode_str[] = +{ + "CMD0_OPCODE_NPU_OP_STOP", + "CMD0_OPCODE_NPU_OP_IRQ", + "CMD0_OPCODE_NPU_OP_CONV", + "CMD0_OPCODE_NPU_OP_DEPTHWISE", + "****", + "CMD0_OPCODE_NPU_OP_POOL", + "CMD0_OPCODE_NPU_OP_ELEMENTWISE", + "CMD0_OPCODE_NPU_OP_RESIZE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_OP_DMA_START", + "CMD0_OPCODE_NPU_OP_DMA_WAIT", + "CMD0_OPCODE_NPU_OP_KERNEL_WAIT", + "CMD0_OPCODE_NPU_OP_PMU_MASK", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_PAD_TOP", + "CMD0_OPCODE_NPU_SET_IFM_PAD_LEFT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_RIGHT", + "CMD0_OPCODE_NPU_SET_IFM_PAD_BOTTOM", + "CMD0_OPCODE_NPU_SET_IFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_IFM_PRECISION", + "****", + "CMD0_OPCODE_NPU_SET_IFM_UPSCALE", + "CMD0_OPCODE_NPU_SET_IFM_BROADCAST", + "CMD0_OPCODE_NPU_SET_IFM_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM_REGION", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_PRECISION", + "CMD0_OPCODE_NPU_SET_OFM_BLK_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_OFM_BLK_DEPTH_M1", + "CMD0_OPCODE_NPU_SET_OFM_ZERO_POINT", + "****", + "CMD0_OPCODE_NPU_SET_OFM_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_OFM_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_OFM_REGION", + "CMD0_OPCODE_NPU_SET_KERNEL_WIDTH_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_HEIGHT_M1", + "CMD0_OPCODE_NPU_SET_KERNEL_STRIDE", + "****", + "CMD0_OPCODE_NPU_SET_ACC_FORMAT", + "CMD0_OPCODE_NPU_SET_ACTIVATION", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MIN", + "CMD0_OPCODE_NPU_SET_ACTIVATION_MAX", + "CMD0_OPCODE_NPU_SET_WEIGHT_REGION", + "CMD0_OPCODE_NPU_SET_SCALE_REGION", + "CMD0_OPCODE_NPU_SET_RESIZE_X_SCALE_N_M1", + "CMD0_OPCODE_NPU_SET_RESIZE_Y_SCALE_N_M1", + "CMD0_OPCODE_NPU_SET_RESIZE_X_OFFSET", + "CMD0_OPCODE_NPU_SET_RESIZE_Y_OFFSET", + "CMD0_OPCODE_NPU_SET_WEIGHT_FORMAT", + "CMD0_OPCODE_NPU_SET_BLOCKDEP", + "CMD0_OPCODE_NPU_SET_DMA0_SRC_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_DST_REGION", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE0", + "CMD0_OPCODE_NPU_SET_DMA0_SIZE1", + "CMD0_OPCODE_NPU_SET_DMA0_IDX_REGION", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_BROADCAST", + "****", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_PRECISION", + "****", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_ZERO_POINT", + "CMD0_OPCODE_NPU_SET_IFM2_WIDTH0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT0_M1", + "CMD0_OPCODE_NPU_SET_IFM2_HEIGHT1_M1", + "****", + "****", + "CMD0_OPCODE_NPU_SET_IFM2_REGION", +}; + +static const char* cmd1_opcode_str[] = +{ + "CMD1_OPCODE_NPU_SET_IFM_BASE0", + "CMD1_OPCODE_NPU_SET_IFM_BASE1", + "CMD1_OPCODE_NPU_SET_IFM_BASE2", + "CMD1_OPCODE_NPU_SET_IFM_BASE3", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_OFM_BASE0", + "CMD1_OPCODE_NPU_SET_OFM_BASE1", + "CMD1_OPCODE_NPU_SET_OFM_BASE2", + "CMD1_OPCODE_NPU_SET_OFM_BASE3", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_X", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_OFM_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT_LENGTH", + "CMD1_OPCODE_NPU_SET_SCALE_BASE", + "CMD1_OPCODE_NPU_SET_SCALE_LENGTH", + "CMD1_OPCODE_NPU_SET_OFM_SCALE", + "CMD1_OPCODE_NPU_SET_IFM_SCALE", + "CMD1_OPCODE_NPU_SET_IFM2_SCALE", + "CMD1_OPCODE_NPU_SET_OP_SCALAR", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_DMA0_SRC", + "CMD1_OPCODE_NPU_SET_DMA0_DST", + "CMD1_OPCODE_NPU_SET_DMA0_LEN", + "CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE0", + "CMD1_OPCODE_NPU_SET_DMA0_SRC_STRIDE1", + "CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE0", + "CMD1_OPCODE_NPU_SET_DMA0_DST_STRIDE1", + "CMD1_OPCODE_NPU_SET_DMA0_IDX", + "CMD1_OPCODE_NPU_SET_DMA0_IDX_MAX", + "CMD1_OPCODE_NPU_SET_DMA0_IDX_SKIP1", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_IFM2_BASE0", + "CMD1_OPCODE_NPU_SET_IFM2_BASE1", + "CMD1_OPCODE_NPU_SET_IFM2_BASE2", + "CMD1_OPCODE_NPU_SET_IFM2_BASE3", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_X", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_Y", + "CMD1_OPCODE_NPU_SET_IFM2_STRIDE_C", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_SET_WEIGHT1_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT1_LENGTH", + "CMD1_OPCODE_NPU_SET_WEIGHT2_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT2_LENGTH", + "CMD1_OPCODE_NPU_SET_WEIGHT3_BASE", + "CMD1_OPCODE_NPU_SET_WEIGHT3_LENGTH", + "CMD1_OPCODE_NPU_SET_RESIZE_X", + "CMD1_OPCODE_NPU_SET_RESIZE_Y", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "CMD1_OPCODE_NPU_OP_BRANCH", +}; + +static const char* cmd_ctrl_str[] = +{ + "CMD_CTRL_CMD0_CTRL", + "CMD_CTRL_CMD1_CTRL", +}; + +static const char* custom_dma_str[] = +{ + "CUSTOM_DMA_NOT_IMPLEMENTED", + "CUSTOM_DMA_IMPLEMENTED", +}; + +static const char* dma_fault_src_str[] = +{ + "DMA_FAULT_SRC_SRAM", + "DMA_FAULT_SRC_EXT", +}; + +static const char* dma_idx_mode_str[] = +{ + "DMA_IDX_MODE_DISABLED", + "DMA_IDX_MODE_ENABLED", +}; + +static const char* dma_region_mode_str[] = +{ + "DMA_REGION_MODE_EXTERNAL", + "DMA_REGION_MODE_INTERNAL", +}; + +static const char* dma_stride_mode_str[] = +{ + "DMA_STRIDE_MODE_D1", + "DMA_STRIDE_MODE_D2", + "DMA_STRIDE_MODE_D3", +}; + +static const char* elementwise_mode_str[] = +{ + "ELEMENTWISE_MODE_MUL", + "ELEMENTWISE_MODE_ADD", + "ELEMENTWISE_MODE_SUB", + "ELEMENTWISE_MODE_MIN", + "ELEMENTWISE_MODE_MAX", + "ELEMENTWISE_MODE_LRELU", + "ELEMENTWISE_MODE_ABS", + "ELEMENTWISE_MODE_CLZ", + "ELEMENTWISE_MODE_SHR", + "ELEMENTWISE_MODE_SHL", + "ELEMENTWISE_MODE_LSR", + "ELEMENTWISE_MODE_DIV", + "****", + "****", + "****", + "****", + "ELEMENTWISE_MODE_CMP_EQ", + "ELEMENTWISE_MODE_CMP_NE", + "ELEMENTWISE_MODE_CMP_GE", + "ELEMENTWISE_MODE_CMP_GT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "ELEMENTWISE_MODE_AND", + "ELEMENTWISE_MODE_OR", + "ELEMENTWISE_MODE_XOR", + "ELEMENTWISE_MODE_NOT", + "****", + "****", + "****", + "****", + "****", + "ELEMENTWISE_MODE_AND_NOT", +}; + +static const char* ifm_upscale_mode_str[] = +{ + "IFM_UPSCALE_MODE_NONE", + "IFM_UPSCALE_MODE_NEAREST", + "IFM_UPSCALE_MODE_ZEROS", +}; + +static const char* kernel_decomposition_str[] = +{ + "KERNEL_DECOMPOSITION_D8X8", + "KERNEL_DECOMPOSITION_D4X4", +}; + +static const char* kernel_dilation_str[] = +{ + "KERNEL_DILATION_NONE", + "KERNEL_DILATION_X2", +}; + +static const char* max_beats_str[] = +{ + "MAX_BEATS_B64", + "MAX_BEATS_B128", + "MAX_BEATS_B256", +}; + +static const char* microblock_str[] = +{ + "MICROBLOCK_U1X1", + "MICROBLOCK_U1X2", + "MICROBLOCK_U1X4", + "MICROBLOCK_U2X2", + "MICROBLOCK_U2X4", + "MICROBLOCK_U4X4", +}; + +static const char* ofm_scale_mode_str[] = +{ + "OFM_SCALE_MODE_PER_CHANNEL", + "OFM_SCALE_MODE_GLOBAL", +}; + +static const char* pmu_axi_channel_str[] = +{ + "PMU_AXI_CHANNEL_RD_CMD", + "PMU_AXI_CHANNEL_RD_IFM", + "PMU_AXI_CHANNEL_RD_WEIGHTS", + "PMU_AXI_CHANNEL_RD_SCALE_BIAS", + "PMU_AXI_CHANNEL_RD_MEM2MEM", + "PMU_AXI_CHANNEL_RD_IFM_STREAM", + "PMU_AXI_CHANNEL_RD_MEM2MEM_IDX", + "****", + "PMU_AXI_CHANNEL_WR_OFM", + "PMU_AXI_CHANNEL_WR_MEM2MEM", +}; + +static const char* pmu_event_str[] = +{ + "PMU_EVENT_NO_EVENT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_CYCLE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_NPU_IDLE", + "PMU_EVENT_CC_STALLED_ON_BLOCKDEP", + "****", + "PMU_EVENT_NPU_ACTIVE", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_MAC_ACTIVE", + "****", + "****", + "PMU_EVENT_MAC_DPU_ACTIVE", + "PMU_EVENT_MAC_STALLED_BY_W_OR_ACC", + "PMU_EVENT_MAC_STALLED_BY_W", + "PMU_EVENT_MAC_STALLED_BY_ACC", + "PMU_EVENT_MAC_STALLED_BY_IB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AO_ACTIVE", + "****", + "****", + "PMU_EVENT_AO_STALLED_BY_BS_OR_OB", + "PMU_EVENT_AO_STALLED_BY_BS", + "PMU_EVENT_AO_STALLED_BY_OB", + "PMU_EVENT_AO_STALLED_BY_AB_OR_CB", + "PMU_EVENT_AO_STALLED_BY_AB", + "PMU_EVENT_AO_STALLED_BY_CB", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_ACTIVE", + "PMU_EVENT_WD_STALLED", + "****", + "PMU_EVENT_WD_STALLED_BY_WD_BUF", + "PMU_EVENT_WD_STALLED_BY_WS_FC", + "PMU_EVENT_WD_STALLED_BY_WS_TC", + "****", + "****", + "****", + "PMU_EVENT_WD_TRANS_WBLK", + "PMU_EVENT_WD_TRANS_WS_FC", + "PMU_EVENT_WD_TRANS_WS_TC", + "****", + "****", + "****", + "****", + "PMU_EVENT_WD_STALLED_BY_WS_SC0", + "PMU_EVENT_WD_STALLED_BY_WS_SC1", + "PMU_EVENT_WD_STALLED_BY_WS_SC2", + "PMU_EVENT_WD_STALLED_BY_WS_SC3", + "PMU_EVENT_WD_PARSE_ACTIVE_SC0", + "PMU_EVENT_WD_PARSE_ACTIVE_SC1", + "PMU_EVENT_WD_PARSE_ACTIVE_SC2", + "PMU_EVENT_WD_PARSE_ACTIVE_SC3", + "PMU_EVENT_WD_PARSE_STALL_SC0", + "PMU_EVENT_WD_PARSE_STALL_SC1", + "PMU_EVENT_WD_PARSE_STALL_SC2", + "PMU_EVENT_WD_PARSE_STALL_SC3", + "PMU_EVENT_WD_PARSE_STALL_IN_SC0", + "PMU_EVENT_WD_PARSE_STALL_IN_SC1", + "PMU_EVENT_WD_PARSE_STALL_IN_SC2", + "PMU_EVENT_WD_PARSE_STALL_IN_SC3", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC0", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC1", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC2", + "PMU_EVENT_WD_PARSE_STALL_OUT_SC3", + "PMU_EVENT_WD_TRANS_WS_SC0", + "PMU_EVENT_WD_TRANS_WS_SC1", + "PMU_EVENT_WD_TRANS_WS_SC2", + "PMU_EVENT_WD_TRANS_WS_SC3", + "PMU_EVENT_WD_TRANS_WB0", + "PMU_EVENT_WD_TRANS_WB1", + "PMU_EVENT_WD_TRANS_WB2", + "PMU_EVENT_WD_TRANS_WB3", + "****", + "****", + "****", + "****", + "PMU_EVENT_SRAM_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM_RD_STALL_LIMIT", + "PMU_EVENT_SRAM_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_AXI_LATENCY_ANY", + "PMU_EVENT_AXI_LATENCY_32", + "PMU_EVENT_AXI_LATENCY_64", + "PMU_EVENT_AXI_LATENCY_128", + "PMU_EVENT_AXI_LATENCY_256", + "PMU_EVENT_AXI_LATENCY_512", + "PMU_EVENT_AXI_LATENCY_1024", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_ECC_DMA", + "PMU_EVENT_ECC_MAC_IB", + "PMU_EVENT_ECC_MAC_AB", + "PMU_EVENT_ECC_AO_CB", + "PMU_EVENT_ECC_AO_OB", + "PMU_EVENT_ECC_AO_LUT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_EXT_RD_TRANS_ACCEPTED", + "PMU_EVENT_EXT_RD_TRANS_COMPLETED", + "PMU_EVENT_EXT_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_EXT_RD_TRAN_REQ_STALLED", + "PMU_EVENT_EXT_WR_TRANS_ACCEPTED", + "PMU_EVENT_EXT_WR_TRANS_COMPLETED_M", + "PMU_EVENT_EXT_WR_TRANS_COMPLETED_S", + "PMU_EVENT_EXT_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_EXT_WR_TRAN_REQ_STALLED", + "PMU_EVENT_EXT_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_EXT_ENABLED_CYCLES", + "****", + "PMU_EVENT_EXT_RD_STALL_LIMIT", + "PMU_EVENT_EXT_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_SRAM0_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM0_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM0_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM0_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM0_RD_STALL_LIMIT", + "PMU_EVENT_SRAM0_WR_STALL_LIMIT", + "PMU_EVENT_SRAM1_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM1_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM1_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM1_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM1_RD_STALL_LIMIT", + "PMU_EVENT_SRAM1_WR_STALL_LIMIT", + "PMU_EVENT_SRAM2_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM2_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM2_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM2_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM2_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM2_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM2_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM2_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM2_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM2_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM2_RD_STALL_LIMIT", + "PMU_EVENT_SRAM2_WR_STALL_LIMIT", + "PMU_EVENT_SRAM3_RD_TRANS_ACCEPTED", + "PMU_EVENT_SRAM3_RD_TRANS_COMPLETED", + "PMU_EVENT_SRAM3_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_SRAM3_RD_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM3_WR_TRANS_ACCEPTED", + "PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_M", + "PMU_EVENT_SRAM3_WR_TRANS_COMPLETED_S", + "PMU_EVENT_SRAM3_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_SRAM3_WR_TRAN_REQ_STALLED", + "PMU_EVENT_SRAM3_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_SRAM3_ENABLED_CYCLES", + "****", + "PMU_EVENT_SRAM3_RD_STALL_LIMIT", + "PMU_EVENT_SRAM3_WR_STALL_LIMIT", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "****", + "PMU_EVENT_EXT0_RD_TRANS_ACCEPTED", + "PMU_EVENT_EXT0_RD_TRANS_COMPLETED", + "PMU_EVENT_EXT0_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_EXT0_RD_TRAN_REQ_STALLED", + "PMU_EVENT_EXT0_WR_TRANS_ACCEPTED", + "PMU_EVENT_EXT0_WR_TRANS_COMPLETED_M", + "PMU_EVENT_EXT0_WR_TRANS_COMPLETED_S", + "PMU_EVENT_EXT0_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_EXT0_WR_TRAN_REQ_STALLED", + "PMU_EVENT_EXT0_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_EXT0_ENABLED_CYCLES", + "****", + "PMU_EVENT_EXT0_RD_STALL_LIMIT", + "PMU_EVENT_EXT0_WR_STALL_LIMIT", + "PMU_EVENT_EXT1_RD_TRANS_ACCEPTED", + "PMU_EVENT_EXT1_RD_TRANS_COMPLETED", + "PMU_EVENT_EXT1_RD_DATA_BEAT_RECEIVED", + "PMU_EVENT_EXT1_RD_TRAN_REQ_STALLED", + "PMU_EVENT_EXT1_WR_TRANS_ACCEPTED", + "PMU_EVENT_EXT1_WR_TRANS_COMPLETED_M", + "PMU_EVENT_EXT1_WR_TRANS_COMPLETED_S", + "PMU_EVENT_EXT1_WR_DATA_BEAT_WRITTEN", + "PMU_EVENT_EXT1_WR_TRAN_REQ_STALLED", + "PMU_EVENT_EXT1_WR_DATA_BEAT_STALLED", + "****", + "****", + "PMU_EVENT_EXT1_ENABLED_CYCLES", + "****", + "PMU_EVENT_EXT1_RD_STALL_LIMIT", + "PMU_EVENT_EXT1_WR_STALL_LIMIT", +}; + +static const char* pmu_port_disable_str[] = +{ + "PMU_PORT_DISABLE_ENABLE", + "PMU_PORT_DISABLE_DISABLE", +}; + +static const char* pooling_mode_str[] = +{ + "POOLING_MODE_MAX", + "POOLING_MODE_AVERAGE", + "POOLING_MODE_REDUCE_SUM", + "POOLING_MODE_SUM", + "POOLING_MODE_NONE", + "POOLING_MODE_MIN", + "POOLING_MODE_ARGMAX_X", + "POOLING_MODE_ARGMAX_Y", +}; + +static const char* privilege_level_str[] = +{ + "PRIVILEGE_LEVEL_USER", + "PRIVILEGE_LEVEL_PRIVILEGED", +}; + +static const char* ram_id_str[] = +{ + "RAM_ID_LUT", + "RAM_ID_IB", + "RAM_ID_AB", + "RAM_ID_CB", + "RAM_ID_OB", +}; + +static const char* resize_mode_str[] = +{ + "RESIZE_MODE_BILINEAR", + "RESIZE_MODE_REPLICATE", + "RESIZE_MODE_NEAREST", +}; + +static const char* round_mode_ifm_str[] = +{ + "ROUND_MODE_IFM_DOUBLE_SYMMETRIC", + "ROUND_MODE_IFM_NATURAL", +}; + +static const char* round_mode_ofm_str[] = +{ + "ROUND_MODE_OFM_DOUBLE_SYMMETRIC", + "ROUND_MODE_OFM_NATURAL", + "ROUND_MODE_OFM_DOUBLE_ASYMMETRIC", + "ROUND_MODE_OFM_SYMMETRIC", + "ROUND_MODE_OFM_TRUNCATE_TO_ZERO", + "ROUND_MODE_OFM_TRUNCATE_TO_LOWER", +}; + +static const char* security_level_str[] = +{ + "SECURITY_LEVEL_SECURE", + "SECURITY_LEVEL_NON_SECURE", +}; + +static const char* state_str[] = +{ + "STATE_STOPPED", + "STATE_RUNNING", +}; + +static const char* wd_active_core_str[] = +{ + "WD_ACTIVE_CORE_NONE", + "WD_ACTIVE_CORE_STANDARD", + "WD_ACTIVE_CORE_FAST", + "WD_ACTIVE_CORE_TENSOR", +}; + +static const char* weight_format_str[] = +{ + "WEIGHT_FORMAT_SWD", + "WEIGHT_FORMAT_FWD", +}; + +static const char* weight_order_str[] = +{ + "WEIGHT_ORDER_DEPTH_FIRST", + "WEIGHT_ORDER_PART_KERNEL_FIRST", +}; + +static const char* weight_sparsity_str[] = +{ + "WEIGHT_SPARSITY_NONE", + "WEIGHT_SPARSITY_SPARSE_2_4", +}; + +#endif + +// Register type structs +// id_r - ID register +struct id_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t version_status : 4; // This value is the version of the product + uint32_t version_minor : 4; // This value is the n for the P part of an RnPn release number + uint32_t version_major : 4; // This value is the n for the R part of an RnPn release number + uint32_t product_major : 4; // Product major ID number (unique per base product) + uint32_t arch_patch_rev : 4; // This value is the patch number of the architecture version a.b + uint32_t arch_minor_rev : 8; // This value is the minor architecture version number, b in the architecture version a.b + uint32_t arch_major_rev : 4; // This value is the major architecture version number, a in the architecture version a.b + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR id_r() : + word0(536899585) + {} + CONSTEXPR id_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + id_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_version_status() const + { + auto v = ((1U << 4) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR id_r& set_version_status(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_version_minor() const + { + auto v = ((1U << 4) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR id_r& set_version_minor(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_version_major() const + { + auto v = ((1U << 4) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR id_r& set_version_major(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<8) & word0) | ((((1U << 4) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_product_major() const + { + auto v = ((1U << 4) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR id_r& set_product_major(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<12) & word0) | ((((1U << 4) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_arch_patch_rev() const + { + auto v = ((1U << 4) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR id_r& set_arch_patch_rev(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<16) & word0) | ((((1U << 4) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_arch_minor_rev() const + { + auto v = ((1U << 8) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR id_r& set_arch_minor_rev(uint32_t value) + { + word0 = (~(((1U << 8) - 1)<<20) & word0) | ((((1U << 8) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_arch_major_rev() const + { + auto v = ((1U << 4) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR id_r& set_arch_major_rev(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// status_r - Register describes the current operating status of the NPU +struct status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t state : 1; // 0 = NPU is in stopped state. 1 = NPU is in running state + uint32_t irq_raised : 1; // 0 = IRQ not raised. 1 = IRQ raised + uint32_t bus_status : 1; // 0 = No bus fault. 1 = Bus abort detected and processing halted + uint32_t reset_status : 1; // 0 = No reset in progress. 1 = Reset in progress + uint32_t cmd_parse_error : 1; // 0 = No parsing error. 1 = Command stream parsing error detected + uint32_t cmd_end_reached : 1; // 0 = Command stream end is not reached. 1 = Command stream end is reached + uint32_t pmu_irq_raised : 1; // 0 = No PMU IRQ raised. 1 = PMU IRQ raised + uint32_t reserved0 : 1; + uint32_t ecc_fault : 1; // 0 = No ECC fault detected. 1 = ECC fault detected + uint32_t branch_fault : 1; // 0 = No branch fault. 1 = Branch fault detected + uint32_t reserved1 : 1; + uint32_t faulting_interface : 1; // The faulting interface on bus abort + uint32_t faulting_channel : 4; // The faulting channel on a bus abort + uint32_t irq_history_mask : 16; // The IRQ History mask + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR status_r() : + word0(8) + {} + CONSTEXPR status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + status_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::state get_state() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR status_r& set_state(NPU_NAMESPACE::state value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR uint32_t get_irq_raised() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR status_r& set_irq_raised(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_bus_status() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR status_r& set_bus_status(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_reset_status() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR status_r& set_reset_status(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_cmd_parse_error() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR status_r& set_cmd_parse_error(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_cmd_end_reached() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR status_r& set_cmd_end_reached(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_pmu_irq_raised() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR status_r& set_pmu_irq_raised(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_ecc_fault() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR status_r& set_ecc_fault(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_branch_fault() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR status_r& set_branch_fault(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_fault_src get_faulting_interface() const + { + auto v = ((1U << 1) - 1) & (word0 >> 11); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR status_r& set_faulting_interface(NPU_NAMESPACE::dma_fault_src value) + { + word0 = (~(((1U << 1) - 1)<<11) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 11); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_faulting_channel() const + { + auto v = ((1U << 4) - 1) & (word0 >> 12); + assert(v <= 9); + return static_cast(v); + } + CONSTEXPR status_r& set_faulting_channel(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (~(((1U << 4) - 1)<<12) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR uint32_t get_irq_history_mask() const + { + auto v = ((1U << 16) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR status_r& set_irq_history_mask(uint32_t value) + { + word0 = (~(((1U << 16) - 1)<<16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// cmd_r - The command register. This register reads as last written command +struct cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t transition_to_running_state : 1; // Write 1 to transition the NPU to running state. Writing 0 has no effect + uint32_t clear_irq : 1; // Write 1 to clear the IRQ status in the STATUS register. Writing 0 has no effect + uint32_t clock_q_enable : 1; // Write 1 to this bit to enable clock off using clock q-interface and enable the requester clock gate + uint32_t power_q_enable : 1; // Write 1 to this bit to enable power off using power q-interface + uint32_t stop_request : 1; // Write 1 to this bit to request STOP after completing any already-started commands + uint32_t reserved0 : 11; + uint32_t clear_irq_history : 16; // Clears the IRQ history mask + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cmd_r() : + word0(12) + {} + CONSTEXPR cmd_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cmd_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_transition_to_running_state() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cmd_r& set_transition_to_running_state(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_clear_irq() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR cmd_r& set_clear_irq(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_clock_q_enable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR cmd_r& set_clock_q_enable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_power_q_enable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR cmd_r& set_power_q_enable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_stop_request() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR cmd_r& set_stop_request(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_clear_irq_history() const + { + auto v = ((1U << 16) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR cmd_r& set_clear_irq_history(uint32_t value) + { + word0 = (~(((1U << 16) - 1)<<16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// reset_r - Request reset and new security mode +struct reset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t pending_CPL : 1; // Current privilege level. 0 = User and 1 = Privileged + uint32_t pending_CSL : 1; // Current security level. 0 = Secure and 1 = Non-secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR reset_r() : + word0(0) + {} + CONSTEXPR reset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + reset_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_pending_CPL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR reset_r& set_pending_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_pending_CSL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR reset_r& set_pending_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// qbase_r - The base address of the command stream in bytes +struct qbase_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR qbase_r() : + word0(0), + word1(0) + {} + CONSTEXPR qbase_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + qbase_r copy() + { + return *this; + } +#endif +}; + +// qread_r - The read offset in the command stream in bytes. Multiple of four in the range 0-16MB +struct qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QREAD : 32; // The read offset of the current command under execution + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR qread_r() : + word0(0) + {} + CONSTEXPR qread_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + qread_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_QREAD() const + { + auto v = word0; + return v; + } + CONSTEXPR qread_r& set_QREAD(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// qconfig_r - The AXI configuration for the command stream in the range 0-3. Same encoding as for REGIONCFG +struct qconfig_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_region0 : 2; // The command region configuration number + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR qconfig_r() : + word0(0) + {} + CONSTEXPR qconfig_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + qconfig_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_cmd_region0() const + { + auto v = ((1U << 2) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR qconfig_r& set_cmd_region0(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<0) & word0) | ((((1U << 2) - 1) & value) << 0); + return *this; + } +#endif +}; + +// qsize_r - The size of the command stream in bytes. Multiple of four in the range 0-16MB +struct qsize_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t QSIZE : 32; // The size of the next command stream to be executed by the NPU + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR qsize_r() : + word0(0) + {} + CONSTEXPR qsize_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + qsize_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_QSIZE() const + { + auto v = word0; + return v; + } + CONSTEXPR qsize_r& set_QSIZE(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// prot_r - The protection level configured for the NPU when acting as an AXI Requester +struct prot_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t active_CPL : 1; // The current privilege level. 0 = User and 1 = Privileged + uint32_t active_CSL : 1; // The current security level 0=Secure 1=Non secure + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR prot_r() : + word0(0) + {} + CONSTEXPR prot_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + prot_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::privilege_level get_active_CPL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR prot_r& set_active_CPL(NPU_NAMESPACE::privilege_level value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::security_level get_active_CSL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR prot_r& set_active_CSL(NPU_NAMESPACE::security_level value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 1); + return *this; + } +#endif +}; + +// config_r - RTL configuration +struct config_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t macs_per_cc : 4; // The log2(macs/clock cycle) + uint32_t cmd_stream_version : 4; // The command stream version accepted by this NPU + uint32_t num_axi_sram : 2; // The log2 of the number of AXI SRAM interfaces + uint32_t num_axi_ext : 1; // The log2 of the number of AXI External memory interfaces + uint32_t reserved0 : 1; + uint32_t num_wd : 2; // The log2 of the number of standard weight decoders + uint32_t reserved1 : 13; + uint32_t custom_dma : 1; // The custom DMA configuration + uint32_t product : 4; // The product configuration + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR config_r() : + word0(536870928) + {} + CONSTEXPR config_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + config_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_macs_per_cc() const + { + auto v = ((1U << 4) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR config_r& set_macs_per_cc(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<0) & word0) | ((((1U << 4) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cmd_stream_version() const + { + auto v = ((1U << 4) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR config_r& set_cmd_stream_version(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<4) & word0) | ((((1U << 4) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_num_axi_sram() const + { + auto v = ((1U << 2) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR config_r& set_num_axi_sram(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_num_axi_ext() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR config_r& set_num_axi_ext(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_num_wd() const + { + auto v = ((1U << 2) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR config_r& set_num_wd(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<12) & word0) | ((((1U << 2) - 1) & value) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::custom_dma get_custom_dma() const + { + auto v = ((1U << 1) - 1) & (word0 >> 27); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR config_r& set_custom_dma(NPU_NAMESPACE::custom_dma value) + { + word0 = (~(((1U << 1) - 1)<<27) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 27); + return *this; + } + CONSTEXPR uint32_t get_product() const + { + auto v = ((1U << 4) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR config_r& set_product(uint32_t value) + { + word0 = (~(((1U << 4) - 1)<<28) & word0) | ((((1U << 4) - 1) & value) << 28); + return *this; + } +#endif +}; + +// cond_status_r - Condition status of the NPU +struct cond_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t result_flag : 1; // The tensor result flag. For OFM with a single element, this is bit 0 of the value. Otherwise UNPREDICTABLE + uint32_t reserved0 : 31; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cond_status_r() : + word0(0) + {} + CONSTEXPR cond_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cond_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_result_flag() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cond_status_r& set_result_flag(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } +#endif +}; + +// power_ctrl_r - Power control register +struct power_ctrl_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mac_step_cycles : 6; // MAC power ramping up/down control + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR power_ctrl_r() : + word0(0) + {} + CONSTEXPR power_ctrl_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + power_ctrl_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_mac_step_cycles() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR power_ctrl_r& set_mac_step_cycles(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } +#endif +}; + +// regioncfg_r - Specify which MEM_ATTR register applies to each region +struct regioncfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t region0 : 2; // Bits for Region0 Configuration + uint32_t region1 : 2; // Bits for Region1 Configuration + uint32_t region2 : 2; // Bits for Region2 Configuration + uint32_t region3 : 2; // Bits for Region3 Configuration + uint32_t region4 : 2; // Bits for Region4 Configuration + uint32_t region5 : 2; // Bits for Region5 Configuration + uint32_t region6 : 2; // Bits for Region6 Configuration + uint32_t region7 : 2; // Bits for Region7 Configuration + uint32_t reserved0 : 16; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR regioncfg_r() : + word0(0) + {} + CONSTEXPR regioncfg_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + regioncfg_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_region0() const + { + auto v = ((1U << 2) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR regioncfg_r& set_region0(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<0) & word0) | ((((1U << 2) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_region1() const + { + auto v = ((1U << 2) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR regioncfg_r& set_region1(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<2) & word0) | ((((1U << 2) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_region2() const + { + auto v = ((1U << 2) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR regioncfg_r& set_region2(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<4) & word0) | ((((1U << 2) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_region3() const + { + auto v = ((1U << 2) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR regioncfg_r& set_region3(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<6) & word0) | ((((1U << 2) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_region4() const + { + auto v = ((1U << 2) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR regioncfg_r& set_region4(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<8) & word0) | ((((1U << 2) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_region5() const + { + auto v = ((1U << 2) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR regioncfg_r& set_region5(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<10) & word0) | ((((1U << 2) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_region6() const + { + auto v = ((1U << 2) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR regioncfg_r& set_region6(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<12) & word0) | ((((1U << 2) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_region7() const + { + auto v = ((1U << 2) - 1) & (word0 >> 14); + return v; + } + CONSTEXPR regioncfg_r& set_region7(uint32_t value) + { + word0 = (~(((1U << 2) - 1)<<14) & word0) | ((((1U << 2) - 1) & value) << 14); + return *this; + } +#endif +}; + +// mem_attr_r - Memory attributes 0 +struct mem_attr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_domain : 2; // Memory domain + uint32_t axi_port : 1; // AXI port select + uint32_t reserved0 : 1; + uint32_t memtype : 4; // Memtype to be used to encode AxCACHE signals + uint32_t reserved1 : 24; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR mem_attr_r() : + word0(0) + {} + CONSTEXPR mem_attr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + mem_attr_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_domain get_mem_domain() const + { + auto v = ((1U << 2) - 1) & (word0 >> 0); + assert(v <= 3); + return static_cast(v); + } + CONSTEXPR mem_attr_r& set_mem_domain(NPU_NAMESPACE::axi_mem_domain value) + { + word0 = (~(((1U << 2) - 1)<<0) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_port get_axi_port() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR mem_attr_r& set_axi_port(NPU_NAMESPACE::axi_port value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_mem_encoding get_memtype() const + { + auto v = ((1U << 4) - 1) & (word0 >> 4); + assert(v <= 11); + return static_cast(v); + } + CONSTEXPR mem_attr_r& set_memtype(NPU_NAMESPACE::axi_mem_encoding value) + { + word0 = (~(((1U << 4) - 1)<<4) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 4); + return *this; + } +#endif +}; + +// axi_sram_r - The AXI configuration for SRAM ports +struct axi_sram_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR axi_sram_r() : + word0(0) + {} + CONSTEXPR axi_sram_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + axi_sram_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR axi_sram_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR axi_sram_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR axi_sram_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// axi_ext_r - The AXI configuration for EXT ports +struct axi_ext_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR axi_ext_r() : + word0(0) + {} + CONSTEXPR axi_ext_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + axi_ext_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR axi_ext_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR axi_ext_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR axi_ext_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// cfg_sram_cap_r - The value of the CFGSRAMCAP pins, SRAM AXI ports cap +struct cfg_sram_cap_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cfg_sram_cap_r() : + word0(0) + {} + CONSTEXPR cfg_sram_cap_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cfg_sram_cap_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cfg_sram_cap_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR cfg_sram_cap_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR cfg_sram_cap_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// cfg_ext_cap_r - The value of the CFGEXTCAP pins, EXT AXI ports cap +struct cfg_ext_cap_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t max_outstanding_read_m1 : 6; // Maximum number of outstanding AXI read transactions per port - 1 + uint32_t reserved0 : 2; + uint32_t max_outstanding_write_m1 : 5; // Maximum number of outstanding AXI write transactions per port - 1 + uint32_t reserved1 : 3; + uint32_t max_beats : 2; // Burst split alignment + uint32_t reserved2 : 14; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cfg_ext_cap_r() : + word0(0) + {} + CONSTEXPR cfg_ext_cap_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cfg_ext_cap_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_read_m1() const + { + auto v = ((1U << 6) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR cfg_ext_cap_r& set_max_outstanding_read_m1(uint32_t value) + { + word0 = (~(((1U << 6) - 1)<<0) & word0) | ((((1U << 6) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_max_outstanding_write_m1() const + { + auto v = ((1U << 5) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR cfg_ext_cap_r& set_max_outstanding_write_m1(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<8) & word0) | ((((1U << 5) - 1) & value) << 8); + return *this; + } + CONSTEXPR NPU_NAMESPACE::max_beats get_max_beats() const + { + auto v = ((1U << 2) - 1) & (word0 >> 16); + assert(v <= 2); + return static_cast(v); + } + CONSTEXPR cfg_ext_cap_r& set_max_beats(NPU_NAMESPACE::max_beats value) + { + word0 = (~(((1U << 2) - 1)<<16) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 16); + return *this; + } +#endif +}; + +// cfg_sram_hash0_r - The value of the CFGSRAMHASH0 pins, SRAM AXI port select bit 0 hash +struct cfg_sram_hash0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t zero : 6; // Must be zero + uint32_t hash_LO : 26; // Hash function - LSB + uint32_t hash_HI : 8; // Hash function - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR cfg_sram_hash0_r() : + word0(0), + word1(0) + {} + CONSTEXPR cfg_sram_hash0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + cfg_sram_hash0_r copy() + { + return *this; + } +#endif +}; + +// cfg_sram_hash1_r - The value of the CFGSRAMHASH1 pins, SRAM AXI port select bit 1 hash +struct cfg_sram_hash1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t zero : 6; // Must be zero + uint32_t hash_LO : 26; // Hash function - LSB + uint32_t hash_HI : 8; // Hash function - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR cfg_sram_hash1_r() : + word0(0), + word1(0) + {} + CONSTEXPR cfg_sram_hash1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + cfg_sram_hash1_r copy() + { + return *this; + } +#endif +}; + +// cfg_ext_hash0_r - The value of the CFGEXTHASH0 pins, EXT AXI port select bit 0 hash +struct cfg_ext_hash0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t zero : 6; // Must be zero + uint32_t hash_LO : 26; // Hash function - LSB + uint32_t hash_HI : 8; // Hash function - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR cfg_ext_hash0_r() : + word0(0), + word1(0) + {} + CONSTEXPR cfg_ext_hash0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + cfg_ext_hash0_r copy() + { + return *this; + } +#endif +}; + +// basep_r - AXI base address of the respective region number 0 - 7 +struct basep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR basep_r() : + word0(0), + word1(0) + {} + CONSTEXPR basep_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + basep_r copy() + { + return *this; + } +#endif +}; + +// clkforce_r - Force clocks on for clock gating +struct clkforce_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t top_level_clk : 1; // set to 1 to force on TOP level clock + uint32_t cc_clk : 1; // set to 1 to force on CC clock + uint32_t dma_clk : 1; // set to 1 to force on DMA clock + uint32_t mac_clk : 1; // set to 1 to force on MAC clock + uint32_t ao_clk : 1; // set to 1 to force on AO clock + uint32_t wd_clk : 1; // set to 1 to force on WD clock + uint32_t reserved0 : 26; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR clkforce_r() : + word0(0) + {} + CONSTEXPR clkforce_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + clkforce_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_top_level_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR clkforce_r& set_top_level_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_cc_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR clkforce_r& set_cc_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_dma_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR clkforce_r& set_dma_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mac_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR clkforce_r& set_mac_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR clkforce_r& set_ao_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_wd_clk() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR clkforce_r& set_wd_clk(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } +#endif +}; + +// debug_address_r - Set debug address for register reads 0x400-0x7FF. The address must be 1KB aligned +struct debug_address_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t addr : 28; // Address in the RAM, 1KB aligned + uint32_t ram_id : 4; // RAM to access + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR debug_address_r() : + word0(0) + {} + CONSTEXPR debug_address_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + debug_address_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_addr() const + { + auto v = ((1U << 28) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR debug_address_r& set_addr(uint32_t value) + { + word0 = (~(((1U << 28) - 1)<<0) & word0) | ((((1U << 28) - 1) & value) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ram_id get_ram_id() const + { + auto v = ((1U << 4) - 1) & (word0 >> 28); + assert(v <= 4); + return static_cast(v); + } + CONSTEXPR debug_address_r& set_ram_id(NPU_NAMESPACE::ram_id value) + { + word0 = (~(((1U << 4) - 1)<<28) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 28); + return *this; + } +#endif +}; + +// debug_misc_r - 32-bit read/write register for driver debug use. This does not affect NPU function +struct debug_misc_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t misc : 32; // Debug misc + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR debug_misc_r() : + word0(0) + {} + CONSTEXPR debug_misc_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + debug_misc_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_misc() const + { + auto v = word0; + return v; + } + CONSTEXPR debug_misc_r& set_misc(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// feature_disable_r - Disable micro-architectural features +struct feature_disable_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t ib_reuse_kd_disable : 1; // Setting to 1 will disable the optimization to reuse IFM data when using kernel decomposition for large kernels + uint32_t ib_reuse_ifm_depth_disable : 1; // Setting to 1 will disable the optimization to reuse IFM data when performing convolution operations + uint32_t reserved0 : 30; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR feature_disable_r() : + word0(0) + {} + CONSTEXPR feature_disable_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + feature_disable_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_ib_reuse_kd_disable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR feature_disable_r& set_ib_reuse_kd_disable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ib_reuse_ifm_depth_disable() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR feature_disable_r& set_ib_reuse_ifm_depth_disable(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } +#endif +}; + +// dma_ifm_src_r - DMA IFM channel source position on AXI +struct dma_ifm_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_ifm_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_ifm_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_ifm_src_r copy() + { + return *this; + } +#endif +}; + +// dma_ofm_dst_r - DMA OFM channel destination position on AXI +struct dma_ofm_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_ofm_dst_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_ofm_dst_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_ofm_dst_r copy() + { + return *this; + } +#endif +}; + +// dma_weight_src_r - DMA weight channel source position on AXI +struct dma_weight_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight_src_r copy() + { + return *this; + } +#endif +}; + +// dma_cmd_src_r - DMA command channel source position on AXI +struct dma_cmd_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_cmd_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_cmd_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_cmd_src_r copy() + { + return *this; + } +#endif +}; + +// dma_cmd_size_r - DMA command channel number of bytes buffered +struct dma_cmd_size_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma_cmd_size_r() : + word0(0) + {} + CONSTEXPR dma_cmd_size_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma_cmd_size_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma_cmd_size_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma_m2m_src_r - DMA memory to memory source position on AXI +struct dma_m2m_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_m2m_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_m2m_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_src_r copy() + { + return *this; + } +#endif +}; + +// dma_m2m_dst_r - DMA memory to memory destination position on AXI +struct dma_m2m_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_m2m_dst_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_m2m_dst_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_m2m_dst_r copy() + { + return *this; + } +#endif +}; + +// current_qread_r - QREAD position being issued (rather than completed) +struct current_qread_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR current_qread_r() : + word0(0) + {} + CONSTEXPR current_qread_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + current_qread_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR current_qread_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma_scale_src_r - DMA scale and bias channel source position on AXI +struct dma_scale_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_scale_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_scale_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_scale_src_r copy() + { + return *this; + } +#endif +}; + +// dma_weight1_src_r - DMA weight1 channel source position on AXI +struct dma_weight1_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight1_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight1_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight1_src_r copy() + { + return *this; + } +#endif +}; + +// dma_weight2_src_r - DMA weight2 channel source position on AXI +struct dma_weight2_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight2_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight2_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight2_src_r copy() + { + return *this; + } +#endif +}; + +// dma_weight3_src_r - DMA weight3 channel source position on AXI +struct dma_weight3_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t offset_LO : 32; // Offset - LSB + uint32_t offset_HI : 8; // Offset - MSB + uint32_t reserved0 : 24; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma_weight3_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma_weight3_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma_weight3_src_r copy() + { + return *this; + } +#endif +}; + +// current_op_r - Latest NPU OP command issued by the parser +struct current_op_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR current_op_r() : + word0(0) + {} + CONSTEXPR current_op_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + current_op_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR current_op_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// current_cmd_r - Current 32-bit command being parsed by the command stream parser +struct current_cmd_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR current_cmd_r() : + word0(0) + {} + CONSTEXPR current_cmd_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + current_cmd_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR current_cmd_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// internal_memory_r - 1KB window onto internal memory as set by DEBUG_ADDRESS +struct internal_memory_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mem_word : 32; // Memory word + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR internal_memory_r() : + word0(0) + {} + CONSTEXPR internal_memory_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + internal_memory_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_mem_word() const + { + auto v = word0; + return v; + } + CONSTEXPR internal_memory_r& set_mem_word(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_top_r - State managed by NPU_SET_IFM_PAD_TOP +struct ifm_pad_top_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_top_r() : + word0(0) + {} + CONSTEXPR ifm_pad_top_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_top_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_top_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_left_r - State managed by NPU_SET_IFM_PAD_LEFT +struct ifm_pad_left_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_left_r() : + word0(0) + {} + CONSTEXPR ifm_pad_left_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_left_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_left_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_right_r - State managed by NPU_SET_IFM_PAD_RIGHT +struct ifm_pad_right_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_right_r() : + word0(0) + {} + CONSTEXPR ifm_pad_right_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_right_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_right_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_pad_bottom_r - State managed by NPU_SET_IFM_PAD_BOTTOM +struct ifm_pad_bottom_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_pad_bottom_r() : + word0(0) + {} + CONSTEXPR ifm_pad_bottom_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_pad_bottom_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_pad_bottom_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_depth_m1_r - State managed by NPU_SET_IFM_DEPTH_M1 +struct ifm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_depth_m1_r() : + word0(0) + {} + CONSTEXPR ifm_depth_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_depth_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_depth_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_precision_r - State managed by NPU_SET_IFM_PRECISION +struct ifm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_precision_r() : + word0(0) + {} + CONSTEXPR ifm_precision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_precision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_precision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_upscale_r - State managed by NPU_SET_IFM_UPSCALE +struct ifm_upscale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_upscale_r() : + word0(0) + {} + CONSTEXPR ifm_upscale_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_upscale_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_upscale_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_broadcast_r - State managed by NPU_SET_IFM_BROADCAST +struct ifm_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_broadcast_r() : + word0(0) + {} + CONSTEXPR ifm_broadcast_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_broadcast_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_broadcast_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_zero_point_r - State managed by NPU_SET_IFM_ZERO_POINT +struct ifm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_zero_point_r() : + word0(0) + {} + CONSTEXPR ifm_zero_point_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_zero_point_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_zero_point_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_width0_m1_r - State managed by NPU_SET_IFM_WIDTH0_M1 +struct ifm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_width0_m1_r() : + word0(0) + {} + CONSTEXPR ifm_width0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_width0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_width0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height0_m1_r - State managed by NPU_SET_IFM_HEIGHT0_M1 +struct ifm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_height0_m1_r() : + word0(0) + {} + CONSTEXPR ifm_height0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_height0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_height0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_height1_m1_r - State managed by NPU_SET_IFM_HEIGHT1_M1 +struct ifm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_height1_m1_r() : + word0(0) + {} + CONSTEXPR ifm_height1_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_height1_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_height1_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_region_r - State managed by NPU_SET_IFM_REGION +struct ifm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm_region_r() : + word0(0) + {} + CONSTEXPR ifm_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width_m1_r - State managed by NPU_SET_OFM_WIDTH_M1 +struct ofm_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_width_m1_r() : + word0(0) + {} + CONSTEXPR ofm_width_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_width_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_width_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height_m1_r - State managed by NPU_SET_OFM_HEIGHT_M1 +struct ofm_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_height_m1_r() : + word0(0) + {} + CONSTEXPR ofm_height_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_height_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_height_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_depth_m1_r - State managed by NPU_SET_OFM_DEPTH_M1 +struct ofm_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_depth_m1_r() : + word0(0) + {} + CONSTEXPR ofm_depth_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_depth_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_depth_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_precision_r - State managed by NPU_SET_OFM_PRECISION +struct ofm_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_precision_r() : + word0(0) + {} + CONSTEXPR ofm_precision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_precision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_precision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_width_m1_r - State managed by NPU_SET_OFM_BLK_WIDTH_M1 +struct ofm_blk_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_blk_width_m1_r() : + word0(0) + {} + CONSTEXPR ofm_blk_width_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_blk_width_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_blk_width_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_height_m1_r - State managed by NPU_SET_OFM_BLK_HEIGHT_M1 +struct ofm_blk_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_blk_height_m1_r() : + word0(0) + {} + CONSTEXPR ofm_blk_height_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_blk_height_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_blk_height_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_blk_depth_m1_r - State managed by NPU_SET_OFM_BLK_DEPTH_M1 +struct ofm_blk_depth_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_blk_depth_m1_r() : + word0(0) + {} + CONSTEXPR ofm_blk_depth_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_blk_depth_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_blk_depth_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_zero_point_r - State managed by NPU_SET_OFM_ZERO_POINT +struct ofm_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_zero_point_r() : + word0(0) + {} + CONSTEXPR ofm_zero_point_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_zero_point_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_zero_point_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_width0_m1_r - State managed by NPU_SET_OFM_WIDTH0_M1 +struct ofm_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_width0_m1_r() : + word0(0) + {} + CONSTEXPR ofm_width0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_width0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_width0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height0_m1_r - State managed by NPU_SET_OFM_HEIGHT0_M1 +struct ofm_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_height0_m1_r() : + word0(0) + {} + CONSTEXPR ofm_height0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_height0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_height0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_height1_m1_r - State managed by NPU_SET_OFM_HEIGHT1_M1 +struct ofm_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_height1_m1_r() : + word0(0) + {} + CONSTEXPR ofm_height1_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_height1_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_height1_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ofm_region_r - State managed by NPU_SET_OFM_REGION +struct ofm_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ofm_region_r() : + word0(0) + {} + CONSTEXPR ofm_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ofm_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ofm_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_width_m1_r - State managed by NPU_SET_KERNEL_WIDTH_M1 +struct kernel_width_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR kernel_width_m1_r() : + word0(0) + {} + CONSTEXPR kernel_width_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + kernel_width_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR kernel_width_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_height_m1_r - State managed by NPU_SET_KERNEL_HEIGHT_M1 +struct kernel_height_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR kernel_height_m1_r() : + word0(0) + {} + CONSTEXPR kernel_height_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + kernel_height_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR kernel_height_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// kernel_stride_r - State managed by NPU_SET_KERNEL_STRIDE +struct kernel_stride_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR kernel_stride_r() : + word0(0) + {} + CONSTEXPR kernel_stride_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + kernel_stride_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR kernel_stride_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// acc_format_r - State managed by NPU_SET_ACC_FORMAT +struct acc_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR acc_format_r() : + word0(0) + {} + CONSTEXPR acc_format_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + acc_format_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR acc_format_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// activation_r - State managed by NPU_SET_ACTIVATION +struct activation_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR activation_r() : + word0(0) + {} + CONSTEXPR activation_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + activation_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR activation_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// activation_min_r - State managed by NPU_SET_ACTIVATION_MIN +struct activation_min_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR activation_min_r() : + word0(0) + {} + CONSTEXPR activation_min_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + activation_min_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR activation_min_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// activation_max_r - State managed by NPU_SET_ACTIVATION_MAX +struct activation_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR activation_max_r() : + word0(0) + {} + CONSTEXPR activation_max_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + activation_max_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR activation_max_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// weight_region_r - State managed by NPU_SET_WEIGHT_REGION +struct weight_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR weight_region_r() : + word0(0) + {} + CONSTEXPR weight_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + weight_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR weight_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// scale_region_r - State managed by NPU_SET_SCALE_REGION +struct scale_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR scale_region_r() : + word0(0) + {} + CONSTEXPR scale_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + scale_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR scale_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_x_scale_n_m1_r - State managed by NPU_SET_RESIZE_X_SCALE_N_M1 +struct resize_x_scale_n_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_x_scale_n_m1_r() : + word0(0) + {} + CONSTEXPR resize_x_scale_n_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_x_scale_n_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_x_scale_n_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_y_scale_n_m1_r - State managed by NPU_SET_RESIZE_Y_SCALE_N_M1 +struct resize_y_scale_n_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_y_scale_n_m1_r() : + word0(0) + {} + CONSTEXPR resize_y_scale_n_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_y_scale_n_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_y_scale_n_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_x_offset_r - State managed by NPU_SET_RESIZE_X_OFFSET +struct resize_x_offset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_x_offset_r() : + word0(0) + {} + CONSTEXPR resize_x_offset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_x_offset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_x_offset_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// resize_y_offset_r - State managed by NPU_SET_RESIZE_Y_OFFSET +struct resize_y_offset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR resize_y_offset_r() : + word0(0) + {} + CONSTEXPR resize_y_offset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + resize_y_offset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR resize_y_offset_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// weight_format_r - State managed by NPU_SET_WEIGHT_FORMAT +struct weight_format_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR weight_format_r() : + word0(0) + {} + CONSTEXPR weight_format_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + weight_format_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR weight_format_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// blockdep_r - State managed by NPU_SET_BLOCKDEP +struct blockdep_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR blockdep_r() : + word0(0) + {} + CONSTEXPR blockdep_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + blockdep_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR blockdep_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_src_region_r - State managed by NPU_SET_DMA0_SRC_REGION +struct dma0_src_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_src_region_r() : + word0(0) + {} + CONSTEXPR dma0_src_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_src_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_src_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_dst_region_r - State managed by NPU_SET_DMA0_DST_REGION +struct dma0_dst_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_dst_region_r() : + word0(0) + {} + CONSTEXPR dma0_dst_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_dst_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_dst_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size0_r - State managed by NPU_SET_DMA0_SIZE0 +struct dma0_size0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_size0_r() : + word0(0) + {} + CONSTEXPR dma0_size0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_size0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_size0_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_size1_r - State managed by NPU_SET_DMA0_SIZE1 +struct dma0_size1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_size1_r() : + word0(0) + {} + CONSTEXPR dma0_size1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_size1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_size1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// dma0_idx_region_r - State managed by NPU_SET_DMA0_IDX_REGION +struct dma0_idx_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma0_idx_region_r() : + word0(0) + {} + CONSTEXPR dma0_idx_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma0_idx_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR dma0_idx_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_broadcast_r - State managed by NPU_SET_IFM2_BROADCAST +struct ifm2_broadcast_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_broadcast_r() : + word0(0) + {} + CONSTEXPR ifm2_broadcast_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_broadcast_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_broadcast_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_precision_r - State managed by NPU_SET_IFM2_PRECISION +struct ifm2_precision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_precision_r() : + word0(0) + {} + CONSTEXPR ifm2_precision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_precision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_precision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_zero_point_r - State managed by NPU_SET_IFM2_ZERO_POINT +struct ifm2_zero_point_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_zero_point_r() : + word0(0) + {} + CONSTEXPR ifm2_zero_point_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_zero_point_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_zero_point_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_width0_m1_r - State managed by NPU_SET_IFM2_WIDTH0_M1 +struct ifm2_width0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_width0_m1_r() : + word0(0) + {} + CONSTEXPR ifm2_width0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_width0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_width0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height0_m1_r - State managed by NPU_SET_IFM2_HEIGHT0_M1 +struct ifm2_height0_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_height0_m1_r() : + word0(0) + {} + CONSTEXPR ifm2_height0_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_height0_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_height0_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_height1_m1_r - State managed by NPU_SET_IFM2_HEIGHT1_M1 +struct ifm2_height1_m1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_height1_m1_r() : + word0(0) + {} + CONSTEXPR ifm2_height1_m1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_height1_m1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_height1_m1_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm2_region_r - State managed by NPU_SET_IFM2_REGION +struct ifm2_region_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ifm2_region_r() : + word0(0) + {} + CONSTEXPR ifm2_region_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ifm2_region_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR ifm2_region_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// ifm_base0_r - State managed by NPU_SET_IFM_BASE0 +struct ifm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base0_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base0_r copy() + { + return *this; + } +#endif +}; + +// ifm_base1_r - State managed by NPU_SET_IFM_BASE1 +struct ifm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base1_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base1_r copy() + { + return *this; + } +#endif +}; + +// ifm_base2_r - State managed by NPU_SET_IFM_BASE2 +struct ifm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base2_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base2_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base2_r copy() + { + return *this; + } +#endif +}; + +// ifm_base3_r - State managed by NPU_SET_IFM_BASE3 +struct ifm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_base3_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_base3_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_base3_r copy() + { + return *this; + } +#endif +}; + +// ifm_stride_x_r - State managed by NPU_SET_IFM_STRIDE_X +struct ifm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_stride_x_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_stride_x_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_x_r copy() + { + return *this; + } +#endif +}; + +// ifm_stride_y_r - State managed by NPU_SET_IFM_STRIDE_Y +struct ifm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_stride_y_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_stride_y_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_y_r copy() + { + return *this; + } +#endif +}; + +// ifm_stride_c_r - State managed by NPU_SET_IFM_STRIDE_C +struct ifm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_stride_c_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_stride_c_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_stride_c_r copy() + { + return *this; + } +#endif +}; + +// ofm_base0_r - State managed by NPU_SET_OFM_BASE0 +struct ofm_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base0_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base0_r copy() + { + return *this; + } +#endif +}; + +// ofm_base1_r - State managed by NPU_SET_OFM_BASE1 +struct ofm_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base1_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base1_r copy() + { + return *this; + } +#endif +}; + +// ofm_base2_r - State managed by NPU_SET_OFM_BASE2 +struct ofm_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base2_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base2_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base2_r copy() + { + return *this; + } +#endif +}; + +// ofm_base3_r - State managed by NPU_SET_OFM_BASE3 +struct ofm_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_base3_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_base3_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_base3_r copy() + { + return *this; + } +#endif +}; + +// ofm_stride_x_r - State managed by NPU_SET_OFM_STRIDE_X +struct ofm_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_stride_x_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_stride_x_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_x_r copy() + { + return *this; + } +#endif +}; + +// ofm_stride_y_r - State managed by NPU_SET_OFM_STRIDE_Y +struct ofm_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_stride_y_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_stride_y_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_y_r copy() + { + return *this; + } +#endif +}; + +// ofm_stride_c_r - State managed by NPU_SET_OFM_STRIDE_C +struct ofm_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_stride_c_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_stride_c_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_stride_c_r copy() + { + return *this; + } +#endif +}; + +// weight_base_r - State managed by NPU_SET_WEIGHT_BASE +struct weight_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight_base_r copy() + { + return *this; + } +#endif +}; + +// weight_length_r - State managed by NPU_SET_WEIGHT_LENGTH +struct weight_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight_length_r copy() + { + return *this; + } +#endif +}; + +// scale_base_r - State managed by NPU_SET_SCALE_BASE +struct scale_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR scale_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR scale_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + scale_base_r copy() + { + return *this; + } +#endif +}; + +// scale_length_r - State managed by NPU_SET_SCALE_LENGTH +struct scale_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR scale_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR scale_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + scale_length_r copy() + { + return *this; + } +#endif +}; + +// ofm_scale_r - State managed by NPU_SET_OFM_SCALE +struct ofm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ofm_scale_r() : + word0(0), + word1(0) + {} + CONSTEXPR ofm_scale_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ofm_scale_r copy() + { + return *this; + } +#endif +}; + +// ifm_scale_r - State managed by NPU_SET_IFM_SCALE +struct ifm_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm_scale_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm_scale_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm_scale_r copy() + { + return *this; + } +#endif +}; + +// ifm2_scale_r - State managed by NPU_SET_IFM2_SCALE +struct ifm2_scale_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_scale_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_scale_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_scale_r copy() + { + return *this; + } +#endif +}; + +// op_scalar_r - State managed by NPU_SET_OP_SCALAR +struct op_scalar_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR op_scalar_r() : + word0(0), + word1(0) + {} + CONSTEXPR op_scalar_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + op_scalar_r copy() + { + return *this; + } +#endif +}; + +// dma0_src_r - State managed by NPU_SET_DMA0_SRC +struct dma0_src_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_src_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_src_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_r copy() + { + return *this; + } +#endif +}; + +// dma0_dst_r - State managed by NPU_SET_DMA0_DST +struct dma0_dst_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_dst_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_dst_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_r copy() + { + return *this; + } +#endif +}; + +// dma0_len_r - State managed by NPU_SET_DMA0_LEN +struct dma0_len_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_len_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_len_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_len_r copy() + { + return *this; + } +#endif +}; + +// dma0_src_stride0_r - State managed by NPU_SET_DMA0_SRC_STRIDE0 +struct dma0_src_stride0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_src_stride0_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_src_stride0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_stride0_r copy() + { + return *this; + } +#endif +}; + +// dma0_src_stride1_r - State managed by NPU_SET_DMA0_SRC_STRIDE1 +struct dma0_src_stride1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_src_stride1_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_src_stride1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_src_stride1_r copy() + { + return *this; + } +#endif +}; + +// dma0_dst_stride0_r - State managed by NPU_SET_DMA0_DST_STRIDE0 +struct dma0_dst_stride0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_dst_stride0_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_dst_stride0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_stride0_r copy() + { + return *this; + } +#endif +}; + +// dma0_dst_stride1_r - State managed by NPU_SET_DMA0_DST_STRIDE1 +struct dma0_dst_stride1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_dst_stride1_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_dst_stride1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_dst_stride1_r copy() + { + return *this; + } +#endif +}; + +// dma0_idx_r - State managed by NPU_SET_DMA0_IDX +struct dma0_idx_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_idx_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_idx_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_idx_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base0_r - State managed by NPU_SET_IFM2_BASE0 +struct ifm2_base0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base0_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base0_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base0_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base1_r - State managed by NPU_SET_IFM2_BASE1 +struct ifm2_base1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base1_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base1_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base2_r - State managed by NPU_SET_IFM2_BASE2 +struct ifm2_base2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base2_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base2_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base2_r copy() + { + return *this; + } +#endif +}; + +// ifm2_base3_r - State managed by NPU_SET_IFM2_BASE3 +struct ifm2_base3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_base3_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_base3_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_base3_r copy() + { + return *this; + } +#endif +}; + +// ifm2_stride_x_r - State managed by NPU_SET_IFM2_STRIDE_X +struct ifm2_stride_x_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_stride_x_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_stride_x_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_x_r copy() + { + return *this; + } +#endif +}; + +// ifm2_stride_y_r - State managed by NPU_SET_IFM2_STRIDE_Y +struct ifm2_stride_y_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_stride_y_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_stride_y_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_y_r copy() + { + return *this; + } +#endif +}; + +// ifm2_stride_c_r - State managed by NPU_SET_IFM2_STRIDE_C +struct ifm2_stride_c_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR ifm2_stride_c_r() : + word0(0), + word1(0) + {} + CONSTEXPR ifm2_stride_c_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + ifm2_stride_c_r copy() + { + return *this; + } +#endif +}; + +// weight1_base_r - State managed by NPU_SET_WEIGHT1_BASE +struct weight1_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight1_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight1_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight1_base_r copy() + { + return *this; + } +#endif +}; + +// weight1_length_r - State managed by NPU_SET_WEIGHT1_LENGTH +struct weight1_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight1_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight1_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight1_length_r copy() + { + return *this; + } +#endif +}; + +// weight2_base_r - State managed by NPU_SET_WEIGHT2_BASE +struct weight2_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight2_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight2_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight2_base_r copy() + { + return *this; + } +#endif +}; + +// weight2_length_r - State managed by NPU_SET_WEIGHT2_LENGTH +struct weight2_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight2_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight2_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight2_length_r copy() + { + return *this; + } +#endif +}; + +// weight3_base_r - State managed by NPU_SET_WEIGHT3_BASE +struct weight3_base_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight3_base_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight3_base_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight3_base_r copy() + { + return *this; + } +#endif +}; + +// weight3_length_r - State managed by NPU_SET_WEIGHT3_LENGTH +struct weight3_length_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR weight3_length_r() : + word0(0), + word1(0) + {} + CONSTEXPR weight3_length_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + weight3_length_r copy() + { + return *this; + } +#endif +}; + +// resize_x_step_r - State managed by NPU_SET_RESIZE_X_STEP +struct resize_x_step_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR resize_x_step_r() : + word0(0), + word1(0) + {} + CONSTEXPR resize_x_step_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + resize_x_step_r copy() + { + return *this; + } +#endif +}; + +// resize_y_step_r - State managed by NPU_SET_RESIZE_Y_STEP +struct resize_y_step_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR resize_y_step_r() : + word0(0), + word1(0) + {} + CONSTEXPR resize_y_step_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + resize_y_step_r copy() + { + return *this; + } +#endif +}; + +// dma0_idx_max_r - State managed by NPU_SET_DMA0_IDX_MAX +struct dma0_idx_max_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_idx_max_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_idx_max_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_idx_max_r copy() + { + return *this; + } +#endif +}; + +// dma0_idx_skip1_r - State managed by NPU_SET_DMA0_IDX_SKIP1 +struct dma0_idx_skip1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value_LO : 32; // 64-bit register value - LSB + uint32_t value_HI : 32; // 64-bit register value - MSB + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR dma0_idx_skip1_r() : + word0(0), + word1(0) + {} + CONSTEXPR dma0_idx_skip1_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + dma0_idx_skip1_r copy() + { + return *this; + } +#endif +}; + +// revision_r - Internal FPGA build revision: first 32 bits of the Ultan git hash used for the build +struct revision_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t value : 32; // 32-bit register value + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR revision_r() : + word0(0) + {} + CONSTEXPR revision_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + revision_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_value() const + { + auto v = word0; + return v; + } + CONSTEXPR revision_r& set_value(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid4_r - Peripheral ID byte 4 (Arm=code 4) +struct pid4_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID4 : 32; // Byte 4 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid4_r() : + word0(4) + {} + CONSTEXPR pid4_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid4_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID4() const + { + auto v = word0; + return v; + } + CONSTEXPR pid4_r& set_PID4(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid5_r - Peripheral ID byte 5 (reserved) +struct pid5_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID5 : 32; // Byte 5 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid5_r() : + word0(0) + {} + CONSTEXPR pid5_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid5_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID5() const + { + auto v = word0; + return v; + } + CONSTEXPR pid5_r& set_PID5(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid6_r - Peripheral ID byte 6 (reserved) +struct pid6_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID6 : 32; // Byte 6 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid6_r() : + word0(0) + {} + CONSTEXPR pid6_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid6_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID6() const + { + auto v = word0; + return v; + } + CONSTEXPR pid6_r& set_PID6(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid7_r - Peripheral ID byte 7 (reserved) +struct pid7_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID7 : 32; // Byte 7 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid7_r() : + word0(0) + {} + CONSTEXPR pid7_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid7_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID7() const + { + auto v = word0; + return v; + } + CONSTEXPR pid7_r& set_PID7(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid0_r - Peripheral ID byte 0. This is bits[7:0] of the part number +struct pid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID0 : 32; // Byte 0 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid0_r() : + word0(130) + {} + CONSTEXPR pid0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID0() const + { + auto v = word0; + return v; + } + CONSTEXPR pid0_r& set_PID0(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid1_r - Peripheral ID byte 1. This is bits[11:8] of the part number in bits[3:0], and bits[3:0] of the Arm ID in bits[7:4] +struct pid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID1 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid1_r() : + word0(181) + {} + CONSTEXPR pid1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID1() const + { + auto v = word0; + return v; + } + CONSTEXPR pid1_r& set_PID1(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid2_r - Peripheral ID byte 2. This is bits[6:4] of the Arm ID in bits[2:0], and bit 3 indicates format B +struct pid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID2 : 32; // Byte 2 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid2_r() : + word0(11) + {} + CONSTEXPR pid2_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid2_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID2() const + { + auto v = word0; + return v; + } + CONSTEXPR pid2_r& set_PID2(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pid3_r - Peripheral ID byte 3 +struct pid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PID3 : 32; // Byte 1 of Peripheral ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pid3_r() : + word0(0) + {} + CONSTEXPR pid3_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pid3_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PID3() const + { + auto v = word0; + return v; + } + CONSTEXPR pid3_r& set_PID3(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid0_r - Component ID byte 0 +struct cid0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID0 : 32; // Byte 0 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid0_r() : + word0(13) + {} + CONSTEXPR cid0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID0() const + { + auto v = word0; + return v; + } + CONSTEXPR cid0_r& set_CID0(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid1_r - Component ID byte 1 +struct cid1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID1 : 32; // Byte 1 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid1_r() : + word0(240) + {} + CONSTEXPR cid1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID1() const + { + auto v = word0; + return v; + } + CONSTEXPR cid1_r& set_CID1(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid2_r - Component ID byte 2 +struct cid2_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID2 : 32; // Byte 2 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid2_r() : + word0(5) + {} + CONSTEXPR cid2_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid2_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID2() const + { + auto v = word0; + return v; + } + CONSTEXPR cid2_r& set_CID2(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// cid3_r - Component ID byte 3 +struct cid3_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CID3 : 32; // Byte 3 of Component ID (Lower 8 bits valid) + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR cid3_r() : + word0(177) + {} + CONSTEXPR cid3_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + cid3_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_CID3() const + { + auto v = word0; + return v; + } + CONSTEXPR cid3_r& set_CID3(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// wd_status_r - WD_STATUS +struct wd_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t ctrl_idle : 1; // All stripe jobs idle (all weights consumed) + uint32_t reserved0 : 1; + uint32_t active_core : 2; // WD active core + uint32_t sc0_idle : 1; // Standard core 0 idle + uint32_t sc1_idle : 1; // Standard core 1 idle + uint32_t sc2_idle : 1; // Standard core 2 idle + uint32_t sc3_idle : 1; // Standard core 3 idle + uint32_t fc_idle : 1; // Fast core idle + uint32_t tc_idle : 1; // Tensor core (IFM input) idle + uint32_t reserved1 : 6; + uint32_t wbuf0_valid : 1; // Weight buffer 0 full + uint32_t wbuf0_idle : 1; // Weight buffer 0 empty + uint32_t wbuf1_valid : 1; // Weight buffer 1 full + uint32_t wbuf1_idle : 1; // Weight buffer 1 empty + uint32_t wbuf2_valid : 1; // Weight buffer 2 full + uint32_t wbuf2_idle : 1; // Weight buffer 2 empty + uint32_t wbuf3_valid : 1; // Weight buffer 3 full + uint32_t wbuf3_idle : 1; // Weight buffer 3 empty + uint32_t stalled_by_ws_sc0 : 1; // WD stalled by lack of standard core 0 weight stream data + uint32_t stalled_by_ws_sc1 : 1; // WD stalled by lack of standard core 1 weight stream data + uint32_t stalled_by_ws_sc2 : 1; // WD stalled by lack of standard core 2 weight stream data + uint32_t stalled_by_ws_sc3 : 1; // WD stalled by lack of standard core 3 weight stream data + uint32_t stalled_by_ws_fc : 1; // WD stalled by lack of fast core weight stream data + uint32_t stalled_by_ws_tc : 1; // WD stalled by lack of tensor core IFM stream data + uint32_t stalled_by_wd_buf : 1; // WD stalled by lack of free WD buffer (blocked by MAC) + uint32_t reserved2 : 1; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR wd_status_r() : + word0(0) + {} + CONSTEXPR wd_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + wd_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_ctrl_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR wd_status_r& set_ctrl_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::wd_active_core get_active_core() const + { + auto v = ((1U << 2) - 1) & (word0 >> 2); + assert(v <= 3); + return static_cast(v); + } + CONSTEXPR wd_status_r& set_active_core(NPU_NAMESPACE::wd_active_core value) + { + word0 = (~(((1U << 2) - 1)<<2) & word0) | ((((1U << 2) - 1) & static_cast(value)) << 2); + return *this; + } + CONSTEXPR uint32_t get_sc0_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR wd_status_r& set_sc0_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_sc1_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR wd_status_r& set_sc1_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_sc2_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR wd_status_r& set_sc2_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_sc3_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR wd_status_r& set_sc3_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_fc_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR wd_status_r& set_fc_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_tc_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR wd_status_r& set_tc_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_wbuf0_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR wd_status_r& set_wbuf0_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_wbuf0_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 17); + return v; + } + CONSTEXPR wd_status_r& set_wbuf0_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_wbuf1_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 18); + return v; + } + CONSTEXPR wd_status_r& set_wbuf1_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_wbuf1_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 19); + return v; + } + CONSTEXPR wd_status_r& set_wbuf1_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wbuf2_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR wd_status_r& set_wbuf2_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wbuf2_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 21); + return v; + } + CONSTEXPR wd_status_r& set_wbuf2_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_wbuf3_valid() const + { + auto v = ((1U << 1) - 1) & (word0 >> 22); + return v; + } + CONSTEXPR wd_status_r& set_wbuf3_valid(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_wbuf3_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 23); + return v; + } + CONSTEXPR wd_status_r& set_wbuf3_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 24); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 25); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc1(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 26); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc2(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_sc3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 27); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_sc3(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_fc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_fc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_ws_tc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 29); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_ws_tc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } + CONSTEXPR uint32_t get_stalled_by_wd_buf() const + { + auto v = ((1U << 1) - 1) & (word0 >> 30); + return v; + } + CONSTEXPR wd_status_r& set_stalled_by_wd_buf(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<30) & word0) | ((((1U << 1) - 1) & value) << 30); + return *this; + } +#endif +}; + +// mac_status_r - MAC_STATUS +struct mac_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t mac_active : 1; // Valid block command and not stalled + uint32_t reserved0 : 2; + uint32_t mac_dpu_active : 1; // At least one DPU is active + uint32_t mac_stalled_by_w_or_acc : 1; // MAC stalled by WB or AB (not IB) + uint32_t mac_stalled_by_w : 1; // MAC stalled by WB (not IB) + uint32_t mac_stalled_by_acc : 1; // MAC stalled by AB (not IB) + uint32_t mac_stalled_by_ib : 1; // MAC stalled by IB + uint32_t reserved1 : 24; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR mac_status_r() : + word0(0) + {} + CONSTEXPR mac_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + mac_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_mac_active() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR mac_status_r& set_mac_active(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_mac_dpu_active() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR mac_status_r& set_mac_dpu_active(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_w_or_acc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_w_or_acc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_w() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_w(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_acc() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_acc(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_mac_stalled_by_ib() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR mac_status_r& set_mac_stalled_by_ib(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } +#endif +}; + +// ao_status_r - AO_STATUS +struct ao_status_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t ao_active : 1; // Valid block command and not stalled + uint32_t reserved0 : 2; + uint32_t ao_stalled_by_bs_or_ob : 1; // Stalled by bias scale data or output block + uint32_t ao_stalled_by_bs : 1; // Stalled by bias scale data + uint32_t ao_stalled_by_ob : 1; // Stalled by output block + uint32_t ao_stalled_by_ab_or_cb : 1; // Stalled by accumulator or chaining buffer + uint32_t ao_stalled_by_ab : 1; // Stalled by accumulator buffer + uint32_t ao_stalled_by_cb : 1; // Stalled by chaining buffer + uint32_t reserved1 : 23; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR ao_status_r() : + word0(0) + {} + CONSTEXPR ao_status_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + ao_status_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_ao_active() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR ao_status_r& set_ao_active(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_bs_or_ob() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_bs_or_ob(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_bs() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_bs(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_ob() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_ob(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_ab_or_cb() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_ab_or_cb(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_ab() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_ab(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_ao_stalled_by_cb() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR ao_status_r& set_ao_stalled_by_cb(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } +#endif +}; + +// dma_status0_r - DMA_STATUS0 +struct dma_status0_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cmd_ch_idle : 1; // When this bit is high means that the CMD channel is not busy in generating addresses for a CMD job + uint32_t ifm0_ch_idle : 1; // When this bit is high means that there are no ongoing IFM MAC jobs + uint32_t ifm1_ch_idle : 1; // When this bit is high means that there are no ongoing IFM STREAM jobs + uint32_t wgt_ch_idle : 1; // When this bit is high means that the WGT channel is not busy in generating addresses for a WGT job + uint32_t bas_ch_idle : 1; // When this bit is high means that the BAS channel is not busy in generating addresses for a BAS job + uint32_t m2m_ch_idle : 1; // When this bit is high means that there are no ongoing M2M jobs + uint32_t ofm_ch_idle : 1; // When this bit is high means that there are no ongoing OFM jobs + uint32_t axi_halt_req : 1; // CPM has requested to HALT AXI bus before soft reset + uint32_t axi_halt_ack : 1; // DMA is in condition to halt the AXI bus since there are no pending transactions + uint32_t axi_pause_req : 1; // CC has requested to pause the AXI + uint32_t axi_pause_ack : 1; // DMA is in condition to pause the AXI bus since there are no pending transactions + uint32_t cmd_abort_ack : 1; // CC has requested to abort a CMD channel job + uint32_t cmd_abort_req : 1; // DMA has acknowledged the request of aborting a CMD channel job + uint32_t ifm_mac_if_stall : 1; // Valid high and Ready low for IFM MAC interface + uint32_t ifm_tc_if_stall : 1; // Valid high and Ready low for IFM WD Tensor Core interface + uint32_t ifm_ao_if_stall : 1; // Valid high and Ready low for IFM AO interface + uint32_t ofm_if_stall : 1; // Valid high and Ready low for OFM interface between AO and DMA + uint32_t cmd_if_stall : 1; // Valid high and Ready low for CMD interface between DMA and CC + uint32_t wd_sc0_if_stall : 1; // Valid high and Ready low for SC0 bitstream interface toward WD + uint32_t wd_sc1_if_stall : 1; // Valid high and Ready low for SC1 bitstream interface toward WD + uint32_t wd_sc2_if_stall : 1; // Valid high and Ready low for SC2 bitstream interface toward WD + uint32_t wd_sc3_if_stall : 1; // Valid high and Ready low for SC2 bitstream interface toward WD + uint32_t wd_fc_if_stall : 1; // Valid high and Ready low for FC bitstream interface toward WD + uint32_t bs_if_stall : 1; // Valid high and Ready low for BAS interface between DMA and AO + uint32_t lutcfg_if_stall : 1; // Valid high and Ready low for LUTCFG interface between DMA and AO + uint32_t reserved0 : 7; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma_status0_r() : + word0(0) + {} + CONSTEXPR dma_status0_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma_status0_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_cmd_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_ifm0_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR dma_status0_r& set_ifm0_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_ifm1_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR dma_status0_r& set_ifm1_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_wgt_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR dma_status0_r& set_wgt_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_bas_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR dma_status0_r& set_bas_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_m2m_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR dma_status0_r& set_m2m_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_ofm_ch_idle() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR dma_status0_r& set_ofm_ch_idle(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_axi_halt_req() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR dma_status0_r& set_axi_halt_req(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_axi_halt_ack() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR dma_status0_r& set_axi_halt_ack(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_axi_pause_req() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR dma_status0_r& set_axi_pause_req(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_axi_pause_ack() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR dma_status0_r& set_axi_pause_ack(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_cmd_abort_ack() const + { + auto v = ((1U << 1) - 1) & (word0 >> 11); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_abort_ack(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_cmd_abort_req() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_abort_req(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_ifm_mac_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + return v; + } + CONSTEXPR dma_status0_r& set_ifm_mac_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_ifm_tc_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + return v; + } + CONSTEXPR dma_status0_r& set_ifm_tc_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_ifm_ao_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + return v; + } + CONSTEXPR dma_status0_r& set_ifm_ao_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_ofm_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR dma_status0_r& set_ofm_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_cmd_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 17); + return v; + } + CONSTEXPR dma_status0_r& set_cmd_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_wd_sc0_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 18); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc0_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_wd_sc1_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 19); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc1_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_wd_sc2_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc2_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_wd_sc3_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 21); + return v; + } + CONSTEXPR dma_status0_r& set_wd_sc3_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_wd_fc_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 22); + return v; + } + CONSTEXPR dma_status0_r& set_wd_fc_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_bs_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 23); + return v; + } + CONSTEXPR dma_status0_r& set_bs_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_lutcfg_if_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 24); + return v; + } + CONSTEXPR dma_status0_r& set_lutcfg_if_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } +#endif +}; + +// dma_status1_r - DMA_STATUS1 +struct dma_status1_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t axi_sram0_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM0 (due to memory system) + uint32_t axi_sram0_rd_limit_stall : 1; // Read stalled due to one AXI SRAM0 limit counter being reached + uint32_t axi_sram0_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM0 (due to memory system) + uint32_t axi_sram0_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM0 (due to memory system) + uint32_t axi_sram0_wr_limit_stall : 1; // Write stalled due to one AXI SRAM0 limit counter being reached + uint32_t axi_sram1_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM1 (due to memory system) + uint32_t axi_sram1_rd_limit_stall : 1; // Read stalled due to one AXI SRAM1 limit counter being reached + uint32_t axi_sram1_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM1 (due to memory system) + uint32_t axi_sram1_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM1 (due to memory system) + uint32_t axi_sram1_wr_limit_stall : 1; // Write stalled due to one AXI SRAM1 limit counter being reached + uint32_t axi_sram2_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM2 (due to memory system) + uint32_t axi_sram2_rd_limit_stall : 1; // Read stalled due to one AXI SRAM2 limit counter being reached + uint32_t axi_sram2_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM2 (due to memory system) + uint32_t axi_sram2_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM2 (due to memory system) + uint32_t axi_sram2_wr_limit_stall : 1; // Write stalled due to one AXI SRAM2 limit counter being reached + uint32_t axi_sram3_ar_stalled : 1; // Read transfer request stalled on arready low AXI SRAM3 (due to memory system) + uint32_t axi_sram3_rd_limit_stall : 1; // Read stalled due to one AXI SRAM3 limit counter being reached + uint32_t axi_sram3_aw_stalled : 1; // Write transfer request stalled on awready low AXI SRAM3 (due to memory system) + uint32_t axi_sram3_w_stalled : 1; // Write transfer stalled on awready low AXI SRAM3 (due to memory system) + uint32_t axi_sram3_wr_limit_stall : 1; // Write stalled due to one AXI SRAM3 limit counter being reached + uint32_t axi_ext0_ar_stalled : 1; // Read transfer request stalled on arready low AXI EXT0 (due to memory system) + uint32_t axi_ext0_rd_limit_stall : 1; // Read stalled due to one AXI EXT0 limit counter being reached + uint32_t axi_ext0_aw_stalled : 1; // Write transfer request stalled on awready low AXI EXT0 (due to memory system) + uint32_t axi_ext0_w_stalled : 1; // Write transfer stalled on awready low AXI EXT0 (due to memory system) + uint32_t axi_ext0_wr_limit_stall : 1; // Write stalled due to one AXI EXT0 limit counter being reached + uint32_t axi_ext1_ar_stalled : 1; // Read transfer request stalled on arready low AXI EXT1 (due to memory system) + uint32_t axi_ext1_rd_limit_stall : 1; // Read stalled due to one AXI EXT1 limit counter being reached + uint32_t axi_ext1_aw_stalled : 1; // Write transfer request stalled on awready low AXI EXT1 (due to memory system) + uint32_t axi_ext1_w_stalled : 1; // Write transfer stalled on awready low AXI EXT1 (due to memory system) + uint32_t axi_ext1_wr_limit_stall : 1; // Write stalled due to one AXI EXT1 limit counter being reached + uint32_t reserved0 : 2; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR dma_status1_r() : + word0(0) + {} + CONSTEXPR dma_status1_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + dma_status1_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_axi_sram0_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram0_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & value) << 8); + return *this; + } + CONSTEXPR uint32_t get_axi_sram1_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 9); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram1_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<9) & word0) | ((((1U << 1) - 1) & value) << 9); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 11); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<11) & word0) | ((((1U << 1) - 1) & value) << 11); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & value) << 12); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & value) << 13); + return *this; + } + CONSTEXPR uint32_t get_axi_sram2_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram2_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & value) << 14); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & value) << 15); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<16) & word0) | ((((1U << 1) - 1) & value) << 16); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 17); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<17) & word0) | ((((1U << 1) - 1) & value) << 17); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 18); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<18) & word0) | ((((1U << 1) - 1) & value) << 18); + return *this; + } + CONSTEXPR uint32_t get_axi_sram3_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 19); + return v; + } + CONSTEXPR dma_status1_r& set_axi_sram3_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<19) & word0) | ((((1U << 1) - 1) & value) << 19); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 20); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<20) & word0) | ((((1U << 1) - 1) & value) << 20); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 21); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<21) & word0) | ((((1U << 1) - 1) & value) << 21); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 22); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<22) & word0) | ((((1U << 1) - 1) & value) << 22); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 23); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<23) & word0) | ((((1U << 1) - 1) & value) << 23); + return *this; + } + CONSTEXPR uint32_t get_axi_ext0_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 24); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext0_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<24) & word0) | ((((1U << 1) - 1) & value) << 24); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_ar_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 25); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_ar_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<25) & word0) | ((((1U << 1) - 1) & value) << 25); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_rd_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 26); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_rd_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<26) & word0) | ((((1U << 1) - 1) & value) << 26); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_aw_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 27); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_aw_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<27) & word0) | ((((1U << 1) - 1) & value) << 27); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_w_stalled() const + { + auto v = ((1U << 1) - 1) & (word0 >> 28); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_w_stalled(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<28) & word0) | ((((1U << 1) - 1) & value) << 28); + return *this; + } + CONSTEXPR uint32_t get_axi_ext1_wr_limit_stall() const + { + auto v = ((1U << 1) - 1) & (word0 >> 29); + return v; + } + CONSTEXPR dma_status1_r& set_axi_ext1_wr_limit_stall(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<29) & word0) | ((((1U << 1) - 1) & value) << 29); + return *this; + } +#endif +}; + +// pmcr_r - PMU register control +struct pmcr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t cnt_en : 1; // Enable counter + uint32_t event_cnt_rst : 1; // Reset event counter + uint32_t cycle_cnt_rst : 1; // Reset cycle counter + uint32_t mask_en : 1; // PMU can be enabled/disabled by command stream operation NPU_OP_PMU_MASK + uint32_t reserved0 : 7; + uint32_t num_event_cnt : 5; // Number of event counters + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcr_r() : + word0(16384) + {} + CONSTEXPR pmcr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_cnt_en() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmcr_r& set_cnt_en(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_event_cnt_rst() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmcr_r& set_event_cnt_rst(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_cycle_cnt_rst() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmcr_r& set_cycle_cnt_rst(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_mask_en() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmcr_r& set_mask_en(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_num_event_cnt() const + { + auto v = ((1U << 5) - 1) & (word0 >> 11); + return v; + } + CONSTEXPR pmcr_r& set_num_event_cnt(uint32_t value) + { + word0 = (~(((1U << 5) - 1)<<11) & word0) | ((((1U << 5) - 1) & value) << 11); + return *this; + } +#endif +}; + +// pmcntenset_r - Count enable set register +struct pmcntenset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter enable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4 : 1; // Event counter enable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5 : 1; // Event counter enable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6 : 1; // Event counter enable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7 : 1; // Event counter enable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT : 1; // PMCCNTR enable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcntenset_r() : + word0(0) + {} + CONSTEXPR pmcntenset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcntenset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_1(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_2(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_3(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_4(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_5(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_6(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmcntenset_r& set_EVENT_CNT_7(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmcntenset_r& set_CYCLE_CNT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmcntenclr_r - Count enable clear register +struct pmcntenclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0 : 1; // Event counter disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1 : 1; // Event counter disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2 : 1; // Event counter disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3 : 1; // Event counter disable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4 : 1; // Event counter disable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5 : 1; // Event counter disable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6 : 1; // Event counter disable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7 : 1; // Event counter disable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT : 1; // PMCCNTR disable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcntenclr_r() : + word0(0) + {} + CONSTEXPR pmcntenclr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcntenclr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_1(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_2(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_3(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_4(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_5(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_6(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmcntenclr_r& set_EVENT_CNT_7(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmcntenclr_r& set_CYCLE_CNT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsset_r - Overflow flag status set register +struct pmovsset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow set bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow set bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow set bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow set bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_OVF : 1; // Event counter overflow set bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_OVF : 1; // Event counter overflow set bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_OVF : 1; // Event counter overflow set bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_OVF : 1; // Event counter overflow set bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow set bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmovsset_r() : + word0(0) + {} + CONSTEXPR pmovsset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmovsset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_4_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_5_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_6_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmovsset_r& set_EVENT_CNT_7_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmovsset_r& set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmovsclr_r - Overflow flag status clear register +struct pmovsclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_OVF : 1; // Event counter overflow clear bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_OVF : 1; // Event counter overflow clear bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_OVF : 1; // Event counter overflow clear bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_OVF : 1; // Event counter overflow clear bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_OVF : 1; // Event counter overflow clear bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_OVF : 1; // Event counter overflow clear bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_OVF : 1; // Event counter overflow clear bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_OVF : 1; // Event counter overflow clear bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_OVF : 1; // PMCCNTR overflow clear bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmovsclr_r() : + word0(0) + {} + CONSTEXPR pmovsclr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmovsclr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_0_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_1_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_2_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_3_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_4_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_5_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_6_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmovsclr_r& set_EVENT_CNT_7_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_OVF() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmovsclr_r& set_CYCLE_CNT_OVF(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintset_r - Interrupt enable set register +struct pmintset_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_INT : 1; // Event counter overflow interrupt request enable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request enable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmintset_r() : + word0(0) + {} + CONSTEXPR pmintset_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmintset_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_4_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_5_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_6_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmintset_r& set_EVENT_CNT_7_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmintset_r& set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmintclr_r - Interrupt enable clear register +struct pmintclr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EVENT_CNT_0_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR0 + uint32_t EVENT_CNT_1_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR1 + uint32_t EVENT_CNT_2_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR2 + uint32_t EVENT_CNT_3_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR3 + uint32_t EVENT_CNT_4_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR4 + uint32_t EVENT_CNT_5_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR5 + uint32_t EVENT_CNT_6_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR6 + uint32_t EVENT_CNT_7_INT : 1; // Event counter overflow interrupt request disable bit for PMEVCNTR7 + uint32_t reserved0 : 23; + uint32_t CYCLE_CNT_INT : 1; // PMCCNTR overflow interrupt request disable bit + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmintclr_r() : + word0(0) + {} + CONSTEXPR pmintclr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmintclr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_0_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_0_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_1_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 1); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_1_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<1) & word0) | ((((1U << 1) - 1) & value) << 1); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_2_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 2); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_2_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<2) & word0) | ((((1U << 1) - 1) & value) << 2); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_3_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 3); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_3_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<3) & word0) | ((((1U << 1) - 1) & value) << 3); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_4_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 4); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_4_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<4) & word0) | ((((1U << 1) - 1) & value) << 4); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_5_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 5); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_5_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<5) & word0) | ((((1U << 1) - 1) & value) << 5); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_6_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 6); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_6_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<6) & word0) | ((((1U << 1) - 1) & value) << 6); + return *this; + } + CONSTEXPR uint32_t get_EVENT_CNT_7_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 7); + return v; + } + CONSTEXPR pmintclr_r& set_EVENT_CNT_7_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<7) & word0) | ((((1U << 1) - 1) & value) << 7); + return *this; + } + CONSTEXPR uint32_t get_CYCLE_CNT_INT() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + return v; + } + CONSTEXPR pmintclr_r& set_CYCLE_CNT_INT(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & value) << 31); + return *this; + } +#endif +}; + +// pmccntr_r - Performance monitor cycle count register +struct pmccntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_LO : 32; // Cycle count - LSB + uint32_t CYCLE_CNT_HI : 16; // Cycle count - MSB + uint32_t reserved0 : 16; + }; + uint32_t word[2]; + }; +#else +private: + uint32_t word0; + uint32_t word1; +public: + CONSTEXPR pmccntr_r() : + word0(0), + word1(0) + {} + CONSTEXPR pmccntr_r(uint64_t init) : + word0(static_cast((init) & static_cast(std::numeric_limits::max()))), + word1(static_cast((init >> 32) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR void operator=(uint64_t value) + { + word0 = static_cast((value) & static_cast(std::numeric_limits::max())); word1 = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); + } + CONSTEXPR operator uint64_t() + { + return (static_cast(word1) << 32) | word0; + } + pmccntr_r copy() + { + return *this; + } +#endif +}; + +// pmccntr_cfg_r - Set start/stop event on the cycle counter +struct pmccntr_cfg_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CYCLE_CNT_CFG_START : 10; // Cycle counter start event + uint32_t reserved0 : 2; + uint32_t S0 : 1; // Start disabled for AXI port 0 + uint32_t S1 : 1; // Start disabled for AXI port 1 + uint32_t S2 : 1; // Start disabled for AXI port 2 + uint32_t S3 : 1; // Start disabled for AXI port 3 + uint32_t CYCLE_CNT_CFG_STOP : 10; // Cycle counter stop event + uint32_t reserved1 : 2; + uint32_t E0 : 1; // End disabled for AXI port 0 + uint32_t E1 : 1; // End disabled for AXI port 1 + uint32_t E2 : 1; // End disabled for AXI port 2 + uint32_t E3 : 1; // End disabled for AXI port 3 + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmccntr_cfg_r() : + word0(0) + {} + CONSTEXPR pmccntr_cfg_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmccntr_cfg_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_START() const + { + auto v = ((1U << 10) - 1) & (word0 >> 0); + assert(v <= 671); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_CYCLE_CNT_CFG_START(NPU_NAMESPACE::pmu_event value) + { + word0 = (~(((1U << 10) - 1)<<0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S0(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S1(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 13); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S2(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 14); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_S3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_S3(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 15); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_CYCLE_CNT_CFG_STOP() const + { + auto v = ((1U << 10) - 1) & (word0 >> 16); + assert(v <= 671); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_CYCLE_CNT_CFG_STOP(NPU_NAMESPACE::pmu_event value) + { + word0 = (~(((1U << 10) - 1)<<16) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 16); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 28); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E0(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<28) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 28); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 29); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E1(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<29) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 29); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 30); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E2(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<30) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 30); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_E3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 31); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmccntr_cfg_r& set_E3(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<31) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 31); + return *this; + } +#endif +}; + +// pmcaxi_chan_r - Set which AXI channel to monitor for latency measurements in PMU +struct pmcaxi_chan_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t CH_SEL : 4; // Channel select for latency measurements + uint32_t reserved0 : 4; + uint32_t AXI_SEL : 1; // AXI port select for latency measurements + uint32_t reserved1 : 1; + uint32_t BW_CH_SEL_EN : 1; // Bandwidth channel selector + uint32_t reserved2 : 21; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmcaxi_chan_r() : + word0(0) + {} + CONSTEXPR pmcaxi_chan_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmcaxi_chan_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_axi_channel get_CH_SEL() const + { + auto v = ((1U << 4) - 1) & (word0 >> 0); + assert(v <= 9); + return static_cast(v); + } + CONSTEXPR pmcaxi_chan_r& set_CH_SEL(NPU_NAMESPACE::pmu_axi_channel value) + { + word0 = (~(((1U << 4) - 1)<<0) & word0) | ((((1U << 4) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::axi_port get_AXI_SEL() const + { + auto v = ((1U << 1) - 1) & (word0 >> 8); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmcaxi_chan_r& set_AXI_SEL(NPU_NAMESPACE::axi_port value) + { + word0 = (~(((1U << 1) - 1)<<8) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 8); + return *this; + } + CONSTEXPR uint32_t get_BW_CH_SEL_EN() const + { + auto v = ((1U << 1) - 1) & (word0 >> 10); + return v; + } + CONSTEXPR pmcaxi_chan_r& set_BW_CH_SEL_EN(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<10) & word0) | ((((1U << 1) - 1) & value) << 10); + return *this; + } +#endif +}; + +// pmclut_r - Performance monitor control for lookup table +struct pmclut_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t PCM_LUT_EN_0 : 1; // PMU lookup table enable for event counter 0 + uint32_t reserved0 : 15; + uint32_t PMC_LUT_0 : 16; // PMU lookup table for event counter 0 + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmclut_r() : + word0(0) + {} + CONSTEXPR pmclut_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmclut_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_PCM_LUT_EN_0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 0); + return v; + } + CONSTEXPR pmclut_r& set_PCM_LUT_EN_0(uint32_t value) + { + word0 = (~(((1U << 1) - 1)<<0) & word0) | ((((1U << 1) - 1) & value) << 0); + return *this; + } + CONSTEXPR uint32_t get_PMC_LUT_0() const + { + auto v = ((1U << 16) - 1) & (word0 >> 16); + return v; + } + CONSTEXPR pmclut_r& set_PMC_LUT_0(uint32_t value) + { + word0 = (~(((1U << 16) - 1)<<16) & word0) | ((((1U << 16) - 1) & value) << 16); + return *this; + } +#endif +}; + +// pmevcntr_r - Performance monitor event 0 count register +struct pmevcntr_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t count : 32; // Count word + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmevcntr_r() : + word0(0) + {} + CONSTEXPR pmevcntr_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmevcntr_r copy() + { + return *this; + } + CONSTEXPR uint32_t get_count() const + { + auto v = word0; + return v; + } + CONSTEXPR pmevcntr_r& set_count(uint32_t value) + { + word0 = value; + return *this; + } +#endif +}; + +// pmevtyper_r - Performance monitor event type register 0 +struct pmevtyper_r +{ +#ifndef __cplusplus + union + { + struct + { + uint32_t EV_TYPE : 10; // Event Type + uint32_t reserved0 : 2; + uint32_t D0 : 1; // Counting disabled for AXI port 0 + uint32_t D1 : 1; // Counting disabled for AXI port 1 + uint32_t D2 : 1; // Counting disabled for AXI port 2 + uint32_t D3 : 1; // Counting disabled for AXI port 3 + uint32_t reserved1 : 16; + }; + uint32_t word; + }; +#else +private: + uint32_t word0; +public: + CONSTEXPR pmevtyper_r() : + word0(0) + {} + CONSTEXPR pmevtyper_r(uint32_t init) : + word0(init) + {} + CONSTEXPR void operator=(uint32_t value) + { + word0 = value; + } + CONSTEXPR operator uint32_t() + { + return word0; + } + pmevtyper_r copy() + { + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_event get_EV_TYPE() const + { + auto v = ((1U << 10) - 1) & (word0 >> 0); + assert(v <= 671); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_EV_TYPE(NPU_NAMESPACE::pmu_event value) + { + word0 = (~(((1U << 10) - 1)<<0) & word0) | ((((1U << 10) - 1) & static_cast(value)) << 0); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D0() const + { + auto v = ((1U << 1) - 1) & (word0 >> 12); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D0(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<12) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 12); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D1() const + { + auto v = ((1U << 1) - 1) & (word0 >> 13); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D1(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<13) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 13); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D2() const + { + auto v = ((1U << 1) - 1) & (word0 >> 14); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D2(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<14) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 14); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pmu_port_disable get_D3() const + { + auto v = ((1U << 1) - 1) & (word0 >> 15); + assert(v <= 1); + return static_cast(v); + } + CONSTEXPR pmevtyper_r& set_D3(NPU_NAMESPACE::pmu_port_disable value) + { + word0 = (~(((1U << 1) - 1)<<15) & word0) | ((((1U << 1) - 1) & static_cast(value)) << 15); + return *this; + } +#endif +}; + +struct NPU_REG +{ + STRUCT id_r ID; // 0x0000 + STRUCT status_r STATUS; // 0x0004 + STRUCT cmd_r CMD; // 0x0008 + STRUCT reset_r RESET; // 0x000C + STRUCT qbase_r QBASE; // 0x0010 + STRUCT qread_r QREAD; // 0x0018 + STRUCT qconfig_r QCONFIG; // 0x001C + STRUCT qsize_r QSIZE; // 0x0020 + STRUCT prot_r PROT; // 0x0024 + STRUCT config_r CONFIG; // 0x0028 + uint32_t unused0[1]; + STRUCT cond_status_r COND_STATUS; // 0x0030 + uint32_t unused1[1]; + STRUCT power_ctrl_r POWER_CTRL; // 0x0038 + STRUCT regioncfg_r REGIONCFG; // 0x003C + STRUCT mem_attr_r MEM_ATTR[4]; // 0x0040 + STRUCT axi_sram_r AXI_SRAM; // 0x0050 + STRUCT axi_ext_r AXI_EXT; // 0x0054 + uint32_t unused2[2]; + STRUCT cfg_sram_cap_r CFG_SRAM_CAP; // 0x0060 + STRUCT cfg_ext_cap_r CFG_EXT_CAP; // 0x0064 + STRUCT cfg_sram_hash0_r CFG_SRAM_HASH0; // 0x0068 + STRUCT cfg_sram_hash1_r CFG_SRAM_HASH1; // 0x0070 + STRUCT cfg_ext_hash0_r CFG_EXT_HASH0; // 0x0078 + STRUCT basep_r BASEP[8]; // 0x0080 + uint32_t unused3[32]; + STRUCT clkforce_r CLKFORCE; // 0x0140 + STRUCT debug_address_r DEBUG_ADDRESS; // 0x0144 + STRUCT debug_misc_r DEBUG_MISC; // 0x0148 + uint32_t unused4[2]; + STRUCT feature_disable_r FEATURE_DISABLE; // 0x0154 + uint32_t unused5[58]; + STRUCT dma_ifm_src_r DMA_IFM_SRC; // 0x0240 + uint32_t unused6[2]; + STRUCT dma_ofm_dst_r DMA_OFM_DST; // 0x0250 + STRUCT dma_weight_src_r DMA_WEIGHT_SRC; // 0x0258 + STRUCT dma_cmd_src_r DMA_CMD_SRC; // 0x0260 + STRUCT dma_cmd_size_r DMA_CMD_SIZE; // 0x0268 + STRUCT dma_m2m_src_r DMA_M2M_SRC; // 0x026C + STRUCT dma_m2m_dst_r DMA_M2M_DST; // 0x0274 + STRUCT current_qread_r CURRENT_QREAD; // 0x027C + STRUCT dma_scale_src_r DMA_SCALE_SRC; // 0x0280 + STRUCT dma_weight1_src_r DMA_WEIGHT1_SRC; // 0x0288 + STRUCT dma_weight2_src_r DMA_WEIGHT2_SRC; // 0x0290 + STRUCT dma_weight3_src_r DMA_WEIGHT3_SRC; // 0x0298 + uint32_t unused7[6]; + STRUCT current_op_r CURRENT_OP; // 0x02B8 + STRUCT current_cmd_r CURRENT_CMD; // 0x02BC + uint32_t unused8[80]; + STRUCT internal_memory_r INTERNAL_MEMORY[256]; // 0x0400 + STRUCT ifm_pad_top_r IFM_PAD_TOP; // 0x0800 + STRUCT ifm_pad_left_r IFM_PAD_LEFT; // 0x0804 + STRUCT ifm_pad_right_r IFM_PAD_RIGHT; // 0x0808 + STRUCT ifm_pad_bottom_r IFM_PAD_BOTTOM; // 0x080C + STRUCT ifm_depth_m1_r IFM_DEPTH_M1; // 0x0810 + STRUCT ifm_precision_r IFM_PRECISION; // 0x0814 + uint32_t unused9[1]; + STRUCT ifm_upscale_r IFM_UPSCALE; // 0x081C + STRUCT ifm_broadcast_r IFM_BROADCAST; // 0x0820 + STRUCT ifm_zero_point_r IFM_ZERO_POINT; // 0x0824 + STRUCT ifm_width0_m1_r IFM_WIDTH0_M1; // 0x0828 + STRUCT ifm_height0_m1_r IFM_HEIGHT0_M1; // 0x082C + STRUCT ifm_height1_m1_r IFM_HEIGHT1_M1; // 0x0830 + uint32_t unused10[2]; + STRUCT ifm_region_r IFM_REGION; // 0x083C + uint32_t unused11[1]; + STRUCT ofm_width_m1_r OFM_WIDTH_M1; // 0x0844 + STRUCT ofm_height_m1_r OFM_HEIGHT_M1; // 0x0848 + STRUCT ofm_depth_m1_r OFM_DEPTH_M1; // 0x084C + STRUCT ofm_precision_r OFM_PRECISION; // 0x0850 + STRUCT ofm_blk_width_m1_r OFM_BLK_WIDTH_M1; // 0x0854 + STRUCT ofm_blk_height_m1_r OFM_BLK_HEIGHT_M1; // 0x0858 + STRUCT ofm_blk_depth_m1_r OFM_BLK_DEPTH_M1; // 0x085C + STRUCT ofm_zero_point_r OFM_ZERO_POINT; // 0x0860 + uint32_t unused12[1]; + STRUCT ofm_width0_m1_r OFM_WIDTH0_M1; // 0x0868 + STRUCT ofm_height0_m1_r OFM_HEIGHT0_M1; // 0x086C + STRUCT ofm_height1_m1_r OFM_HEIGHT1_M1; // 0x0870 + uint32_t unused13[2]; + STRUCT ofm_region_r OFM_REGION; // 0x087C + STRUCT kernel_width_m1_r KERNEL_WIDTH_M1; // 0x0880 + STRUCT kernel_height_m1_r KERNEL_HEIGHT_M1; // 0x0884 + STRUCT kernel_stride_r KERNEL_STRIDE; // 0x0888 + uint32_t unused14[1]; + STRUCT acc_format_r ACC_FORMAT; // 0x0890 + STRUCT activation_r ACTIVATION; // 0x0894 + STRUCT activation_min_r ACTIVATION_MIN; // 0x0898 + STRUCT activation_max_r ACTIVATION_MAX; // 0x089C + STRUCT weight_region_r WEIGHT_REGION; // 0x08A0 + STRUCT scale_region_r SCALE_REGION; // 0x08A4 + STRUCT resize_x_scale_n_m1_r RESIZE_X_SCALE_N_M1; // 0x08A8 + STRUCT resize_y_scale_n_m1_r RESIZE_Y_SCALE_N_M1; // 0x08AC + STRUCT resize_x_offset_r RESIZE_X_OFFSET; // 0x08B0 + STRUCT resize_y_offset_r RESIZE_Y_OFFSET; // 0x08B4 + STRUCT weight_format_r WEIGHT_FORMAT; // 0x08B8 + STRUCT blockdep_r BLOCKDEP; // 0x08BC + STRUCT dma0_src_region_r DMA0_SRC_REGION; // 0x08C0 + STRUCT dma0_dst_region_r DMA0_DST_REGION; // 0x08C4 + STRUCT dma0_size0_r DMA0_SIZE0; // 0x08C8 + STRUCT dma0_size1_r DMA0_SIZE1; // 0x08CC + STRUCT dma0_idx_region_r DMA0_IDX_REGION; // 0x08D0 + uint32_t unused15[11]; + STRUCT ifm2_broadcast_r IFM2_BROADCAST; // 0x0900 + uint32_t unused16[4]; + STRUCT ifm2_precision_r IFM2_PRECISION; // 0x0914 + uint32_t unused17[3]; + STRUCT ifm2_zero_point_r IFM2_ZERO_POINT; // 0x0924 + STRUCT ifm2_width0_m1_r IFM2_WIDTH0_M1; // 0x0928 + STRUCT ifm2_height0_m1_r IFM2_HEIGHT0_M1; // 0x092C + STRUCT ifm2_height1_m1_r IFM2_HEIGHT1_M1; // 0x0930 + uint32_t unused18[2]; + STRUCT ifm2_region_r IFM2_REGION; // 0x093C + uint32_t unused19[48]; + STRUCT ifm_base0_r IFM_BASE0; // 0x0A00 + STRUCT ifm_base1_r IFM_BASE1; // 0x0A08 + STRUCT ifm_base2_r IFM_BASE2; // 0x0A10 + STRUCT ifm_base3_r IFM_BASE3; // 0x0A18 + STRUCT ifm_stride_x_r IFM_STRIDE_X; // 0x0A20 + STRUCT ifm_stride_y_r IFM_STRIDE_Y; // 0x0A28 + STRUCT ifm_stride_c_r IFM_STRIDE_C; // 0x0A30 + uint32_t unused20[2]; + STRUCT ofm_base0_r OFM_BASE0; // 0x0A40 + STRUCT ofm_base1_r OFM_BASE1; // 0x0A48 + STRUCT ofm_base2_r OFM_BASE2; // 0x0A50 + STRUCT ofm_base3_r OFM_BASE3; // 0x0A58 + STRUCT ofm_stride_x_r OFM_STRIDE_X; // 0x0A60 + STRUCT ofm_stride_y_r OFM_STRIDE_Y; // 0x0A68 + STRUCT ofm_stride_c_r OFM_STRIDE_C; // 0x0A70 + uint32_t unused21[2]; + STRUCT weight_base_r WEIGHT_BASE; // 0x0A80 + STRUCT weight_length_r WEIGHT_LENGTH; // 0x0A88 + STRUCT scale_base_r SCALE_BASE; // 0x0A90 + STRUCT scale_length_r SCALE_LENGTH; // 0x0A98 + STRUCT ofm_scale_r OFM_SCALE; // 0x0AA0 + STRUCT ifm_scale_r IFM_SCALE; // 0x0AA8 + STRUCT ifm2_scale_r IFM2_SCALE; // 0x0AB0 + STRUCT op_scalar_r OP_SCALAR; // 0x0AB8 + STRUCT dma0_src_r DMA0_SRC; // 0x0AC0 + STRUCT dma0_dst_r DMA0_DST; // 0x0AC8 + STRUCT dma0_len_r DMA0_LEN; // 0x0AD0 + STRUCT dma0_src_stride0_r DMA0_SRC_STRIDE0; // 0x0AD8 + STRUCT dma0_src_stride1_r DMA0_SRC_STRIDE1; // 0x0AE0 + STRUCT dma0_dst_stride0_r DMA0_DST_STRIDE0; // 0x0AE8 + STRUCT dma0_dst_stride1_r DMA0_DST_STRIDE1; // 0x0AF0 + STRUCT dma0_idx_r DMA0_IDX; // 0x0AF8 + STRUCT ifm2_base0_r IFM2_BASE0; // 0x0B00 + STRUCT ifm2_base1_r IFM2_BASE1; // 0x0B08 + STRUCT ifm2_base2_r IFM2_BASE2; // 0x0B10 + STRUCT ifm2_base3_r IFM2_BASE3; // 0x0B18 + STRUCT ifm2_stride_x_r IFM2_STRIDE_X; // 0x0B20 + STRUCT ifm2_stride_y_r IFM2_STRIDE_Y; // 0x0B28 + STRUCT ifm2_stride_c_r IFM2_STRIDE_C; // 0x0B30 + uint32_t unused22[2]; + STRUCT weight1_base_r WEIGHT1_BASE; // 0x0B40 + STRUCT weight1_length_r WEIGHT1_LENGTH; // 0x0B48 + STRUCT weight2_base_r WEIGHT2_BASE; // 0x0B50 + STRUCT weight2_length_r WEIGHT2_LENGTH; // 0x0B58 + STRUCT weight3_base_r WEIGHT3_BASE; // 0x0B60 + STRUCT weight3_length_r WEIGHT3_LENGTH; // 0x0B68 + STRUCT resize_x_step_r RESIZE_X_STEP; // 0x0B70 + STRUCT resize_y_step_r RESIZE_Y_STEP; // 0x0B78 + uint32_t unused23[16]; + STRUCT dma0_idx_max_r DMA0_IDX_MAX; // 0x0BC0 + STRUCT dma0_idx_skip1_r DMA0_IDX_SKIP1; // 0x0BC8 + uint32_t unused24[252]; + STRUCT revision_r REVISION; // 0x0FC0 + uint32_t unused25[3]; + STRUCT pid4_r PID4; // 0x0FD0 + STRUCT pid5_r PID5; // 0x0FD4 + STRUCT pid6_r PID6; // 0x0FD8 + STRUCT pid7_r PID7; // 0x0FDC + STRUCT pid0_r PID0; // 0x0FE0 + STRUCT pid1_r PID1; // 0x0FE4 + STRUCT pid2_r PID2; // 0x0FE8 + STRUCT pid3_r PID3; // 0x0FEC + STRUCT cid0_r CID0; // 0x0FF0 + STRUCT cid1_r CID1; // 0x0FF4 + STRUCT cid2_r CID2; // 0x0FF8 + STRUCT cid3_r CID3; // 0x0FFC + uint32_t unused26[64]; + STRUCT wd_status_r WD_STATUS; // 0x1100 + STRUCT mac_status_r MAC_STATUS; // 0x1104 + STRUCT ao_status_r AO_STATUS; // 0x1108 + uint32_t unused27[1]; + STRUCT dma_status0_r DMA_STATUS0; // 0x1110 + STRUCT dma_status1_r DMA_STATUS1; // 0x1114 + uint32_t unused28[26]; + STRUCT pmcr_r PMCR; // 0x1180 + STRUCT pmcntenset_r PMCNTENSET; // 0x1184 + STRUCT pmcntenclr_r PMCNTENCLR; // 0x1188 + STRUCT pmovsset_r PMOVSSET; // 0x118C + STRUCT pmovsclr_r PMOVSCLR; // 0x1190 + STRUCT pmintset_r PMINTSET; // 0x1194 + STRUCT pmintclr_r PMINTCLR; // 0x1198 + uint32_t unused29[1]; + STRUCT pmccntr_r PMCCNTR; // 0x11A0 + STRUCT pmccntr_cfg_r PMCCNTR_CFG; // 0x11A8 + STRUCT pmcaxi_chan_r PMCAXI_CHAN; // 0x11AC + STRUCT pmclut_r PMCLUT; // 0x11B0 + uint32_t unused30[83]; + STRUCT pmevcntr_r PMEVCNTR[8]; // 0x1300 + uint32_t unused31[24]; + STRUCT pmevtyper_r PMEVTYPER[8]; // 0x1380 + +#ifdef __cplusplus + enum class access_type_t : uint8_t { RW, RO, WO }; + NPU_REG() + { + reset(); + } + void reset() + { + ID = 536899585; + STATUS = 8; + CMD = 12; + RESET = 0; + QBASE = 0; + QREAD = 0; + QCONFIG = 0; + QSIZE = 0; + PROT = 0; + CONFIG = 536870928; + COND_STATUS = 0; + POWER_CTRL = 0; + REGIONCFG = 0; + for (size_t i = 0; i < (sizeof(MEM_ATTR) / sizeof(MEM_ATTR[0])); ++i) + MEM_ATTR[i] = 0; + AXI_SRAM = 0; + AXI_EXT = 0; + CFG_SRAM_CAP = 0; + CFG_EXT_CAP = 0; + CFG_SRAM_HASH0 = 0; + CFG_SRAM_HASH1 = 0; + CFG_EXT_HASH0 = 0; + for (size_t i = 0; i < (sizeof(BASEP) / sizeof(BASEP[0])); ++i) + BASEP[i] = 0; + CLKFORCE = 0; + DEBUG_ADDRESS = 0; + DEBUG_MISC = 0; + FEATURE_DISABLE = 0; + DMA_IFM_SRC = 0; + DMA_OFM_DST = 0; + DMA_WEIGHT_SRC = 0; + DMA_CMD_SRC = 0; + DMA_CMD_SIZE = 0; + DMA_M2M_SRC = 0; + DMA_M2M_DST = 0; + CURRENT_QREAD = 0; + DMA_SCALE_SRC = 0; + DMA_WEIGHT1_SRC = 0; + DMA_WEIGHT2_SRC = 0; + DMA_WEIGHT3_SRC = 0; + CURRENT_OP = 0; + CURRENT_CMD = 0; + for (size_t i = 0; i < (sizeof(INTERNAL_MEMORY) / sizeof(INTERNAL_MEMORY[0])); ++i) + INTERNAL_MEMORY[i] = 0; + IFM_PAD_TOP = 0; + IFM_PAD_LEFT = 0; + IFM_PAD_RIGHT = 0; + IFM_PAD_BOTTOM = 0; + IFM_DEPTH_M1 = 0; + IFM_PRECISION = 0; + IFM_UPSCALE = 0; + IFM_BROADCAST = 0; + IFM_ZERO_POINT = 0; + IFM_WIDTH0_M1 = 0; + IFM_HEIGHT0_M1 = 0; + IFM_HEIGHT1_M1 = 0; + IFM_REGION = 0; + OFM_WIDTH_M1 = 0; + OFM_HEIGHT_M1 = 0; + OFM_DEPTH_M1 = 0; + OFM_PRECISION = 0; + OFM_BLK_WIDTH_M1 = 0; + OFM_BLK_HEIGHT_M1 = 0; + OFM_BLK_DEPTH_M1 = 0; + OFM_ZERO_POINT = 0; + OFM_WIDTH0_M1 = 0; + OFM_HEIGHT0_M1 = 0; + OFM_HEIGHT1_M1 = 0; + OFM_REGION = 0; + KERNEL_WIDTH_M1 = 0; + KERNEL_HEIGHT_M1 = 0; + KERNEL_STRIDE = 0; + ACC_FORMAT = 0; + ACTIVATION = 0; + ACTIVATION_MIN = 0; + ACTIVATION_MAX = 0; + WEIGHT_REGION = 0; + SCALE_REGION = 0; + RESIZE_X_SCALE_N_M1 = 0; + RESIZE_Y_SCALE_N_M1 = 0; + RESIZE_X_OFFSET = 0; + RESIZE_Y_OFFSET = 0; + WEIGHT_FORMAT = 0; + BLOCKDEP = 0; + DMA0_SRC_REGION = 0; + DMA0_DST_REGION = 0; + DMA0_SIZE0 = 0; + DMA0_SIZE1 = 0; + DMA0_IDX_REGION = 0; + IFM2_BROADCAST = 0; + IFM2_PRECISION = 0; + IFM2_ZERO_POINT = 0; + IFM2_WIDTH0_M1 = 0; + IFM2_HEIGHT0_M1 = 0; + IFM2_HEIGHT1_M1 = 0; + IFM2_REGION = 0; + IFM_BASE0 = 0; + IFM_BASE1 = 0; + IFM_BASE2 = 0; + IFM_BASE3 = 0; + IFM_STRIDE_X = 0; + IFM_STRIDE_Y = 0; + IFM_STRIDE_C = 0; + OFM_BASE0 = 0; + OFM_BASE1 = 0; + OFM_BASE2 = 0; + OFM_BASE3 = 0; + OFM_STRIDE_X = 0; + OFM_STRIDE_Y = 0; + OFM_STRIDE_C = 0; + WEIGHT_BASE = 0; + WEIGHT_LENGTH = 0; + SCALE_BASE = 0; + SCALE_LENGTH = 0; + OFM_SCALE = 0; + IFM_SCALE = 0; + IFM2_SCALE = 0; + OP_SCALAR = 0; + DMA0_SRC = 0; + DMA0_DST = 0; + DMA0_LEN = 0; + DMA0_SRC_STRIDE0 = 0; + DMA0_SRC_STRIDE1 = 0; + DMA0_DST_STRIDE0 = 0; + DMA0_DST_STRIDE1 = 0; + DMA0_IDX = 0; + IFM2_BASE0 = 0; + IFM2_BASE1 = 0; + IFM2_BASE2 = 0; + IFM2_BASE3 = 0; + IFM2_STRIDE_X = 0; + IFM2_STRIDE_Y = 0; + IFM2_STRIDE_C = 0; + WEIGHT1_BASE = 0; + WEIGHT1_LENGTH = 0; + WEIGHT2_BASE = 0; + WEIGHT2_LENGTH = 0; + WEIGHT3_BASE = 0; + WEIGHT3_LENGTH = 0; + RESIZE_X_STEP = 0; + RESIZE_Y_STEP = 0; + DMA0_IDX_MAX = 0; + DMA0_IDX_SKIP1 = 0; + REVISION = 0; + PID4 = 4; + PID5 = 0; + PID6 = 0; + PID7 = 0; + PID0 = 130; + PID1 = 181; + PID2 = 11; + PID3 = 0; + CID0 = 13; + CID1 = 240; + CID2 = 5; + CID3 = 177; + WD_STATUS = 0; + MAC_STATUS = 0; + AO_STATUS = 0; + DMA_STATUS0 = 0; + DMA_STATUS1 = 0; + PMCR = 16384; + PMCNTENSET = 0; + PMCNTENCLR = 0; + PMOVSSET = 0; + PMOVSCLR = 0; + PMINTSET = 0; + PMINTCLR = 0; + PMCCNTR = 0; + PMCCNTR_CFG = 0; + PMCAXI_CHAN = 0; + PMCLUT = 0; + for (size_t i = 0; i < (sizeof(PMEVCNTR) / sizeof(PMEVCNTR[0])); ++i) + PMEVCNTR[i] = 0; + for (size_t i = 0; i < (sizeof(PMEVTYPER) / sizeof(PMEVTYPER[0])); ++i) + PMEVTYPER[i] = 0; + } + uint32_t& operator[](const int addr_offset) + { + return reinterpret_cast(this)[addr_offset / 4]; + } + access_type_t get_access_type(uint32_t offset) + { + switch (offset) + { + case 0: return access_type_t::RO; + case 4: return access_type_t::RO; + case 8: return access_type_t::RW; + case 12: return access_type_t::RW; + case 16: return access_type_t::RW; + case 24: return access_type_t::RO; + case 28: return access_type_t::RW; + case 32: return access_type_t::RW; + case 36: return access_type_t::RO; + case 40: return access_type_t::RO; + case 48: return access_type_t::RO; + case 56: return access_type_t::RW; + case 60: return access_type_t::RW; + case 64: return access_type_t::RW; + case 68: return access_type_t::RW; + case 72: return access_type_t::RW; + case 76: return access_type_t::RW; + case 80: return access_type_t::RW; + case 84: return access_type_t::RW; + case 96: return access_type_t::RO; + case 100: return access_type_t::RO; + case 104: return access_type_t::RO; + case 112: return access_type_t::RO; + case 120: return access_type_t::RO; + case 128: return access_type_t::RW; + case 136: return access_type_t::RW; + case 144: return access_type_t::RW; + case 152: return access_type_t::RW; + case 160: return access_type_t::RW; + case 168: return access_type_t::RW; + case 176: return access_type_t::RW; + case 184: return access_type_t::RW; + case 320: return access_type_t::RW; + case 324: return access_type_t::RW; + case 328: return access_type_t::RW; + case 340: return access_type_t::RW; + case 576: return access_type_t::RO; + case 592: return access_type_t::RO; + case 600: return access_type_t::RO; + case 608: return access_type_t::RO; + case 616: return access_type_t::RO; + case 620: return access_type_t::RO; + case 628: return access_type_t::RO; + case 636: return access_type_t::RO; + case 640: return access_type_t::RO; + case 648: return access_type_t::RO; + case 656: return access_type_t::RO; + case 664: return access_type_t::RO; + case 696: return access_type_t::RO; + case 700: return access_type_t::RO; + case 1024: return access_type_t::RW; + case 1028: return access_type_t::RW; + case 1032: return access_type_t::RW; + case 1036: return access_type_t::RW; + case 1040: return access_type_t::RW; + case 1044: return access_type_t::RW; + case 1048: return access_type_t::RW; + case 1052: return access_type_t::RW; + case 1056: return access_type_t::RW; + case 1060: return access_type_t::RW; + case 1064: return access_type_t::RW; + case 1068: return access_type_t::RW; + case 1072: return access_type_t::RW; + case 1076: return access_type_t::RW; + case 1080: return access_type_t::RW; + case 1084: return access_type_t::RW; + case 1088: return access_type_t::RW; + case 1092: return access_type_t::RW; + case 1096: return access_type_t::RW; + case 1100: return access_type_t::RW; + case 1104: return access_type_t::RW; + case 1108: return access_type_t::RW; + case 1112: return access_type_t::RW; + case 1116: return access_type_t::RW; + case 1120: return access_type_t::RW; + case 1124: return access_type_t::RW; + case 1128: return access_type_t::RW; + case 1132: return access_type_t::RW; + case 1136: return access_type_t::RW; + case 1140: return access_type_t::RW; + case 1144: return access_type_t::RW; + case 1148: return access_type_t::RW; + case 1152: return access_type_t::RW; + case 1156: return access_type_t::RW; + case 1160: return access_type_t::RW; + case 1164: return access_type_t::RW; + case 1168: return access_type_t::RW; + case 1172: return access_type_t::RW; + case 1176: return access_type_t::RW; + case 1180: return access_type_t::RW; + case 1184: return access_type_t::RW; + case 1188: return access_type_t::RW; + case 1192: return access_type_t::RW; + case 1196: return access_type_t::RW; + case 1200: return access_type_t::RW; + case 1204: return access_type_t::RW; + case 1208: return access_type_t::RW; + case 1212: return access_type_t::RW; + case 1216: return access_type_t::RW; + case 1220: return access_type_t::RW; + case 1224: return access_type_t::RW; + case 1228: return access_type_t::RW; + case 1232: return access_type_t::RW; + case 1236: return access_type_t::RW; + case 1240: return access_type_t::RW; + case 1244: return access_type_t::RW; + case 1248: return access_type_t::RW; + case 1252: return access_type_t::RW; + case 1256: return access_type_t::RW; + case 1260: return access_type_t::RW; + case 1264: return access_type_t::RW; + case 1268: return access_type_t::RW; + case 1272: return access_type_t::RW; + case 1276: return access_type_t::RW; + case 1280: return access_type_t::RW; + case 1284: return access_type_t::RW; + case 1288: return access_type_t::RW; + case 1292: return access_type_t::RW; + case 1296: return access_type_t::RW; + case 1300: return access_type_t::RW; + case 1304: return access_type_t::RW; + case 1308: return access_type_t::RW; + case 1312: return access_type_t::RW; + case 1316: return access_type_t::RW; + case 1320: return access_type_t::RW; + case 1324: return access_type_t::RW; + case 1328: return access_type_t::RW; + case 1332: return access_type_t::RW; + case 1336: return access_type_t::RW; + case 1340: return access_type_t::RW; + case 1344: return access_type_t::RW; + case 1348: return access_type_t::RW; + case 1352: return access_type_t::RW; + case 1356: return access_type_t::RW; + case 1360: return access_type_t::RW; + case 1364: return access_type_t::RW; + case 1368: return access_type_t::RW; + case 1372: return access_type_t::RW; + case 1376: return access_type_t::RW; + case 1380: return access_type_t::RW; + case 1384: return access_type_t::RW; + case 1388: return access_type_t::RW; + case 1392: return access_type_t::RW; + case 1396: return access_type_t::RW; + case 1400: return access_type_t::RW; + case 1404: return access_type_t::RW; + case 1408: return access_type_t::RW; + case 1412: return access_type_t::RW; + case 1416: return access_type_t::RW; + case 1420: return access_type_t::RW; + case 1424: return access_type_t::RW; + case 1428: return access_type_t::RW; + case 1432: return access_type_t::RW; + case 1436: return access_type_t::RW; + case 1440: return access_type_t::RW; + case 1444: return access_type_t::RW; + case 1448: return access_type_t::RW; + case 1452: return access_type_t::RW; + case 1456: return access_type_t::RW; + case 1460: return access_type_t::RW; + case 1464: return access_type_t::RW; + case 1468: return access_type_t::RW; + case 1472: return access_type_t::RW; + case 1476: return access_type_t::RW; + case 1480: return access_type_t::RW; + case 1484: return access_type_t::RW; + case 1488: return access_type_t::RW; + case 1492: return access_type_t::RW; + case 1496: return access_type_t::RW; + case 1500: return access_type_t::RW; + case 1504: return access_type_t::RW; + case 1508: return access_type_t::RW; + case 1512: return access_type_t::RW; + case 1516: return access_type_t::RW; + case 1520: return access_type_t::RW; + case 1524: return access_type_t::RW; + case 1528: return access_type_t::RW; + case 1532: return access_type_t::RW; + case 1536: return access_type_t::RW; + case 1540: return access_type_t::RW; + case 1544: return access_type_t::RW; + case 1548: return access_type_t::RW; + case 1552: return access_type_t::RW; + case 1556: return access_type_t::RW; + case 1560: return access_type_t::RW; + case 1564: return access_type_t::RW; + case 1568: return access_type_t::RW; + case 1572: return access_type_t::RW; + case 1576: return access_type_t::RW; + case 1580: return access_type_t::RW; + case 1584: return access_type_t::RW; + case 1588: return access_type_t::RW; + case 1592: return access_type_t::RW; + case 1596: return access_type_t::RW; + case 1600: return access_type_t::RW; + case 1604: return access_type_t::RW; + case 1608: return access_type_t::RW; + case 1612: return access_type_t::RW; + case 1616: return access_type_t::RW; + case 1620: return access_type_t::RW; + case 1624: return access_type_t::RW; + case 1628: return access_type_t::RW; + case 1632: return access_type_t::RW; + case 1636: return access_type_t::RW; + case 1640: return access_type_t::RW; + case 1644: return access_type_t::RW; + case 1648: return access_type_t::RW; + case 1652: return access_type_t::RW; + case 1656: return access_type_t::RW; + case 1660: return access_type_t::RW; + case 1664: return access_type_t::RW; + case 1668: return access_type_t::RW; + case 1672: return access_type_t::RW; + case 1676: return access_type_t::RW; + case 1680: return access_type_t::RW; + case 1684: return access_type_t::RW; + case 1688: return access_type_t::RW; + case 1692: return access_type_t::RW; + case 1696: return access_type_t::RW; + case 1700: return access_type_t::RW; + case 1704: return access_type_t::RW; + case 1708: return access_type_t::RW; + case 1712: return access_type_t::RW; + case 1716: return access_type_t::RW; + case 1720: return access_type_t::RW; + case 1724: return access_type_t::RW; + case 1728: return access_type_t::RW; + case 1732: return access_type_t::RW; + case 1736: return access_type_t::RW; + case 1740: return access_type_t::RW; + case 1744: return access_type_t::RW; + case 1748: return access_type_t::RW; + case 1752: return access_type_t::RW; + case 1756: return access_type_t::RW; + case 1760: return access_type_t::RW; + case 1764: return access_type_t::RW; + case 1768: return access_type_t::RW; + case 1772: return access_type_t::RW; + case 1776: return access_type_t::RW; + case 1780: return access_type_t::RW; + case 1784: return access_type_t::RW; + case 1788: return access_type_t::RW; + case 1792: return access_type_t::RW; + case 1796: return access_type_t::RW; + case 1800: return access_type_t::RW; + case 1804: return access_type_t::RW; + case 1808: return access_type_t::RW; + case 1812: return access_type_t::RW; + case 1816: return access_type_t::RW; + case 1820: return access_type_t::RW; + case 1824: return access_type_t::RW; + case 1828: return access_type_t::RW; + case 1832: return access_type_t::RW; + case 1836: return access_type_t::RW; + case 1840: return access_type_t::RW; + case 1844: return access_type_t::RW; + case 1848: return access_type_t::RW; + case 1852: return access_type_t::RW; + case 1856: return access_type_t::RW; + case 1860: return access_type_t::RW; + case 1864: return access_type_t::RW; + case 1868: return access_type_t::RW; + case 1872: return access_type_t::RW; + case 1876: return access_type_t::RW; + case 1880: return access_type_t::RW; + case 1884: return access_type_t::RW; + case 1888: return access_type_t::RW; + case 1892: return access_type_t::RW; + case 1896: return access_type_t::RW; + case 1900: return access_type_t::RW; + case 1904: return access_type_t::RW; + case 1908: return access_type_t::RW; + case 1912: return access_type_t::RW; + case 1916: return access_type_t::RW; + case 1920: return access_type_t::RW; + case 1924: return access_type_t::RW; + case 1928: return access_type_t::RW; + case 1932: return access_type_t::RW; + case 1936: return access_type_t::RW; + case 1940: return access_type_t::RW; + case 1944: return access_type_t::RW; + case 1948: return access_type_t::RW; + case 1952: return access_type_t::RW; + case 1956: return access_type_t::RW; + case 1960: return access_type_t::RW; + case 1964: return access_type_t::RW; + case 1968: return access_type_t::RW; + case 1972: return access_type_t::RW; + case 1976: return access_type_t::RW; + case 1980: return access_type_t::RW; + case 1984: return access_type_t::RW; + case 1988: return access_type_t::RW; + case 1992: return access_type_t::RW; + case 1996: return access_type_t::RW; + case 2000: return access_type_t::RW; + case 2004: return access_type_t::RW; + case 2008: return access_type_t::RW; + case 2012: return access_type_t::RW; + case 2016: return access_type_t::RW; + case 2020: return access_type_t::RW; + case 2024: return access_type_t::RW; + case 2028: return access_type_t::RW; + case 2032: return access_type_t::RW; + case 2036: return access_type_t::RW; + case 2040: return access_type_t::RW; + case 2044: return access_type_t::RW; + case 2048: return access_type_t::RW; + case 2052: return access_type_t::RW; + case 2056: return access_type_t::RW; + case 2060: return access_type_t::RW; + case 2064: return access_type_t::RW; + case 2068: return access_type_t::RW; + case 2076: return access_type_t::RW; + case 2080: return access_type_t::RW; + case 2084: return access_type_t::RW; + case 2088: return access_type_t::RW; + case 2092: return access_type_t::RW; + case 2096: return access_type_t::RW; + case 2108: return access_type_t::RW; + case 2116: return access_type_t::RW; + case 2120: return access_type_t::RW; + case 2124: return access_type_t::RW; + case 2128: return access_type_t::RW; + case 2132: return access_type_t::RW; + case 2136: return access_type_t::RW; + case 2140: return access_type_t::RW; + case 2144: return access_type_t::RW; + case 2152: return access_type_t::RW; + case 2156: return access_type_t::RW; + case 2160: return access_type_t::RW; + case 2172: return access_type_t::RW; + case 2176: return access_type_t::RW; + case 2180: return access_type_t::RW; + case 2184: return access_type_t::RW; + case 2192: return access_type_t::RW; + case 2196: return access_type_t::RW; + case 2200: return access_type_t::RW; + case 2204: return access_type_t::RW; + case 2208: return access_type_t::RW; + case 2212: return access_type_t::RW; + case 2216: return access_type_t::RW; + case 2220: return access_type_t::RW; + case 2224: return access_type_t::RW; + case 2228: return access_type_t::RW; + case 2232: return access_type_t::RW; + case 2236: return access_type_t::RW; + case 2240: return access_type_t::RW; + case 2244: return access_type_t::RW; + case 2248: return access_type_t::RW; + case 2252: return access_type_t::RW; + case 2256: return access_type_t::RW; + case 2304: return access_type_t::RW; + case 2324: return access_type_t::RW; + case 2340: return access_type_t::RW; + case 2344: return access_type_t::RW; + case 2348: return access_type_t::RW; + case 2352: return access_type_t::RW; + case 2364: return access_type_t::RW; + case 2560: return access_type_t::RW; + case 2568: return access_type_t::RW; + case 2576: return access_type_t::RW; + case 2584: return access_type_t::RW; + case 2592: return access_type_t::RW; + case 2600: return access_type_t::RW; + case 2608: return access_type_t::RW; + case 2624: return access_type_t::RW; + case 2632: return access_type_t::RW; + case 2640: return access_type_t::RW; + case 2648: return access_type_t::RW; + case 2656: return access_type_t::RW; + case 2664: return access_type_t::RW; + case 2672: return access_type_t::RW; + case 2688: return access_type_t::RW; + case 2696: return access_type_t::RW; + case 2704: return access_type_t::RW; + case 2712: return access_type_t::RW; + case 2720: return access_type_t::RW; + case 2728: return access_type_t::RW; + case 2736: return access_type_t::RW; + case 2744: return access_type_t::RW; + case 2752: return access_type_t::RW; + case 2760: return access_type_t::RW; + case 2768: return access_type_t::RW; + case 2776: return access_type_t::RW; + case 2784: return access_type_t::RW; + case 2792: return access_type_t::RW; + case 2800: return access_type_t::RW; + case 2808: return access_type_t::RW; + case 2816: return access_type_t::RW; + case 2824: return access_type_t::RW; + case 2832: return access_type_t::RW; + case 2840: return access_type_t::RW; + case 2848: return access_type_t::RW; + case 2856: return access_type_t::RW; + case 2864: return access_type_t::RW; + case 2880: return access_type_t::RW; + case 2888: return access_type_t::RW; + case 2896: return access_type_t::RW; + case 2904: return access_type_t::RW; + case 2912: return access_type_t::RW; + case 2920: return access_type_t::RW; + case 2928: return access_type_t::RW; + case 2936: return access_type_t::RW; + case 3008: return access_type_t::RW; + case 3016: return access_type_t::RW; + case 4032: return access_type_t::RO; + case 4048: return access_type_t::RO; + case 4052: return access_type_t::RO; + case 4056: return access_type_t::RO; + case 4060: return access_type_t::RO; + case 4064: return access_type_t::RO; + case 4068: return access_type_t::RO; + case 4072: return access_type_t::RO; + case 4076: return access_type_t::RO; + case 4080: return access_type_t::RO; + case 4084: return access_type_t::RO; + case 4088: return access_type_t::RO; + case 4092: return access_type_t::RO; + case 4352: return access_type_t::RO; + case 4356: return access_type_t::RO; + case 4360: return access_type_t::RO; + case 4368: return access_type_t::RO; + case 4372: return access_type_t::RO; + case 4480: return access_type_t::RW; + case 4484: return access_type_t::RW; + case 4488: return access_type_t::RW; + case 4492: return access_type_t::RW; + case 4496: return access_type_t::RW; + case 4500: return access_type_t::RW; + case 4504: return access_type_t::RW; + case 4512: return access_type_t::RW; + case 4520: return access_type_t::RW; + case 4524: return access_type_t::RW; + case 4528: return access_type_t::RW; + case 4864: return access_type_t::RW; + case 4868: return access_type_t::RW; + case 4872: return access_type_t::RW; + case 4876: return access_type_t::RW; + case 4880: return access_type_t::RW; + case 4884: return access_type_t::RW; + case 4888: return access_type_t::RW; + case 4892: return access_type_t::RW; + case 4992: return access_type_t::RW; + case 4996: return access_type_t::RW; + case 5000: return access_type_t::RW; + case 5004: return access_type_t::RW; + case 5008: return access_type_t::RW; + case 5012: return access_type_t::RW; + case 5016: return access_type_t::RW; + case 5020: return access_type_t::RW; + default: return access_type_t::RO; + } + } +#endif +}; + +#ifdef __cplusplus +struct isa +{ +#ifdef NPU_DISASSEMBLE +static int disassemble(const uint32_t* in, std::string& op, std::vector>& fields) +{ + switch (*in & 0xffff) + { + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP): + { + const npu_op_stop_t& v = *reinterpret_cast(in); + op = "NPU_OP_STOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ): + { + const npu_op_irq_t& v = *reinterpret_cast(in); + op = "NPU_OP_IRQ"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV): + { + const npu_op_conv_t& v = *reinterpret_cast(in); + op = "NPU_OP_CONV"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE): + { + const npu_op_depthwise_t& v = *reinterpret_cast(in); + op = "NPU_OP_DEPTHWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL): + { + const npu_op_pool_t& v = *reinterpret_cast(in); + op = "NPU_OP_POOL"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE): + { + const npu_op_elementwise_t& v = *reinterpret_cast(in); + op = "NPU_OP_ELEMENTWISE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE): + { + const npu_op_resize_t& v = *reinterpret_cast(in); + op = "NPU_OP_RESIZE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START): + { + const npu_op_dma_start_t& v = *reinterpret_cast(in); + op = "NPU_OP_DMA_START"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT): + { + const npu_op_dma_wait_t& v = *reinterpret_cast(in); + op = "NPU_OP_DMA_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT): + { + const npu_op_kernel_wait_t& v = *reinterpret_cast(in); + op = "NPU_OP_KERNEL_WAIT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK): + { + const npu_op_pmu_mask_t& v = *reinterpret_cast(in); + op = "NPU_OP_PMU_MASK"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP): + { + const npu_set_ifm_pad_top_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_TOP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT): + { + const npu_set_ifm_pad_left_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_LEFT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT): + { + const npu_set_ifm_pad_right_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_RIGHT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM): + { + const npu_set_ifm_pad_bottom_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PAD_BOTTOM"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1): + { + const npu_set_ifm_depth_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION): + { + const npu_set_ifm_precision_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE): + { + const npu_set_ifm_upscale_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_UPSCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT): + { + const npu_set_ifm_zero_point_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1): + { + const npu_set_ifm_width0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1): + { + const npu_set_ifm_height0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1): + { + const npu_set_ifm_height1_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION): + { + const npu_set_ifm_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST): + { + const npu_set_ifm_broadcast_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1): + { + const npu_set_ofm_width_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1): + { + const npu_set_ofm_height_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1): + { + const npu_set_ofm_depth_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION): + { + const npu_set_ofm_precision_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1): + { + const npu_set_ofm_blk_width_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1): + { + const npu_set_ofm_blk_height_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1): + { + const npu_set_ofm_blk_depth_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BLK_DEPTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT): + { + const npu_set_ofm_zero_point_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1): + { + const npu_set_ofm_width0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1): + { + const npu_set_ofm_height0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1): + { + const npu_set_ofm_height1_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION): + { + const npu_set_ofm_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1): + { + const npu_set_kernel_width_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_WIDTH_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1): + { + const npu_set_kernel_height_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_HEIGHT_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE): + { + const npu_set_kernel_stride_t& v = *reinterpret_cast(in); + op = "NPU_SET_KERNEL_STRIDE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT): + { + const npu_set_acc_format_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACC_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION): + { + const npu_set_activation_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN): + { + const npu_set_activation_min_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MIN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX): + { + const npu_set_activation_max_t& v = *reinterpret_cast(in); + op = "NPU_SET_ACTIVATION_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION): + { + const npu_set_weight_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION): + { + const npu_set_scale_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT): + { + const npu_set_weight_format_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_FORMAT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP): + { + const npu_set_blockdep_t& v = *reinterpret_cast(in); + op = "NPU_SET_BLOCKDEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1): + { + const npu_set_resize_x_scale_n_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_X_SCALE_N_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1): + { + const npu_set_resize_y_scale_n_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_Y_SCALE_N_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET): + { + const npu_set_resize_x_offset_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_X_OFFSET"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET): + { + const npu_set_resize_y_offset_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_Y_OFFSET"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION): + { + const npu_set_dma0_src_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION): + { + const npu_set_dma0_dst_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0): + { + const npu_set_dma0_size0_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1): + { + const npu_set_dma0_size1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SIZE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION): + { + const npu_set_dma0_idx_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST): + { + const npu_set_ifm2_broadcast_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BROADCAST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION): + { + const npu_set_ifm2_precision_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_PRECISION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT): + { + const npu_set_ifm2_zero_point_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_ZERO_POINT"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1): + { + const npu_set_ifm2_width0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_WIDTH0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1): + { + const npu_set_ifm2_height0_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT0_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1): + { + const npu_set_ifm2_height1_m1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_HEIGHT1_M1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION): + { + const npu_set_ifm2_region_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_REGION"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0): + { + const npu_set_ifm_base0_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1): + { + const npu_set_ifm_base1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2): + { + const npu_set_ifm_base2_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3): + { + const npu_set_ifm_base3_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X): + { + const npu_set_ifm_stride_x_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y): + { + const npu_set_ifm_stride_y_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C): + { + const npu_set_ifm_stride_c_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0): + { + const npu_set_ofm_base0_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1): + { + const npu_set_ofm_base1_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2): + { + const npu_set_ofm_base2_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3): + { + const npu_set_ofm_base3_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X): + { + const npu_set_ofm_stride_x_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y): + { + const npu_set_ofm_stride_y_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C): + { + const npu_set_ofm_stride_c_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE): + { + const npu_set_weight_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH): + { + const npu_set_weight_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE): + { + const npu_set_scale_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH): + { + const npu_set_scale_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_SCALE_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE): + { + const npu_set_ofm_scale_t& v = *reinterpret_cast(in); + op = "NPU_SET_OFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE): + { + const npu_set_ifm_scale_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE): + { + const npu_set_ifm2_scale_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_SCALE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR): + { + const npu_set_op_scalar_t& v = *reinterpret_cast(in); + op = "NPU_SET_OP_SCALAR"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC): + { + const npu_set_dma0_src_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST): + { + const npu_set_dma0_dst_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN): + { + const npu_set_dma0_len_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_LEN"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0): + { + const npu_set_dma0_src_stride0_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_STRIDE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1): + { + const npu_set_dma0_src_stride1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_SRC_STRIDE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0): + { + const npu_set_dma0_dst_stride0_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_STRIDE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1): + { + const npu_set_dma0_dst_stride1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_DST_STRIDE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX): + { + const npu_set_dma0_idx_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX): + { + const npu_set_dma0_idx_max_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX_MAX"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1): + { + const npu_set_dma0_idx_skip1_t& v = *reinterpret_cast(in); + op = "NPU_SET_DMA0_IDX_SKIP1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0): + { + const npu_set_ifm2_base0_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE0"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1): + { + const npu_set_ifm2_base1_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE1"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2): + { + const npu_set_ifm2_base2_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE2"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3): + { + const npu_set_ifm2_base3_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_BASE3"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X): + { + const npu_set_ifm2_stride_x_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_X"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y): + { + const npu_set_ifm2_stride_y_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_Y"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C): + { + const npu_set_ifm2_stride_c_t& v = *reinterpret_cast(in); + op = "NPU_SET_IFM2_STRIDE_C"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE): + { + const npu_set_weight1_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH): + { + const npu_set_weight1_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT1_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE): + { + const npu_set_weight2_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT2_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH): + { + const npu_set_weight2_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT2_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE): + { + const npu_set_weight3_base_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT3_BASE"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH): + { + const npu_set_weight3_length_t& v = *reinterpret_cast(in); + op = "NPU_SET_WEIGHT3_LENGTH"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X): + { + const npu_set_resize_x_step_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_X_STEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y): + { + const npu_set_resize_y_step_t& v = *reinterpret_cast(in); + op = "NPU_SET_RESIZE_Y_STEP"; + v.disassemble(fields); + break; + } + case (static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL) << 14) | static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH): + { + const npu_op_branch_t& v = *reinterpret_cast(in); + op = "NPU_OP_BRANCH"; + v.disassemble(fields); + break; + } + default: break; + } + return (*in & (3<<14)) != 0 ? 2 : 1; +} +#endif +#endif +// Signal the end of command stream +struct npu_op_stop_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t mask:16; // Encoding for 16-bit mask value +#ifdef __cplusplus +public: + npu_op_stop_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(_mask & ((1U << 16)-1)) + {} + CONSTEXPR npu_op_stop_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_STOP); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(mask) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_stop_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_stop_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_stop_t& set_mask(uint32_t value) + { + assert((value >> 16) == 0); + mask = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif +}; +// Raises an IRQ to the host +struct npu_op_irq_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t mask:16; // Encoding for 16-bit mask value +#ifdef __cplusplus +public: + npu_op_irq_t(uint32_t _mask) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(_mask & ((1U << 16)-1)) + {} + CONSTEXPR npu_op_irq_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mask(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_IRQ); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(mask) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_irq_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_irq_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_mask() const + { + return static_cast(mask); + } + CONSTEXPR npu_op_irq_t& set_mask(uint32_t value) + { + assert((value >> 16) == 0); + mask = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("mask", std::to_string(mask))); + } +#endif +#endif +}; +// 2D convolution +struct npu_op_conv_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t weights_ifm2:1; // Read weights from IFM2 rather than a static compressed stream + uint32_t reserved1:15; +#ifdef __cplusplus +public: + npu_op_conv_t(uint32_t _weights_ifm2) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weights_ifm2(_weights_ifm2 & ((1U << 1)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_conv_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weights_ifm2(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_CONV); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(weights_ifm2) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_conv_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_conv_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_weights_ifm2() const + { + return static_cast(weights_ifm2); + } + CONSTEXPR npu_op_conv_t& set_weights_ifm2(uint32_t value) + { + assert((value >> 1) == 0); + weights_ifm2 = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("weights_ifm2", std::to_string(weights_ifm2))); + } +#endif +#endif +}; +// Depth-wise 2D convolution +struct npu_op_depthwise_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; +#ifdef __cplusplus +public: + CONSTEXPR npu_op_depthwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DEPTHWISE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_depthwise_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_depthwise_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>&) const + { + } +#endif +#endif +}; +// Pooling +struct npu_op_pool_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pooling_mode:3; // Pooling mode + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_op_pool_t(NPU_NAMESPACE::pooling_mode _pooling_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(static_cast(_pooling_mode) & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_pool_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pooling_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_POOL); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pooling_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pool_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pool_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::pooling_mode get_pooling_mode() const + { + return static_cast(pooling_mode); + } + CONSTEXPR npu_op_pool_t& set_pooling_mode(NPU_NAMESPACE::pooling_mode value) + { + pooling_mode = static_cast(value) & ((1U << 3)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pooling_mode", (pooling_mode < (sizeof(pooling_mode_str)/sizeof(pooling_mode_str[0])) ? pooling_mode_str[pooling_mode] : "****"))); + } +#endif +#endif +}; +// Elementwise operation +struct npu_op_elementwise_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t elementwise_mode:6; // Elementwise mode + uint32_t reserved1:10; +#ifdef __cplusplus +public: + npu_op_elementwise_t(NPU_NAMESPACE::elementwise_mode _elementwise_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(static_cast(_elementwise_mode) & ((1U << 6)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_elementwise_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + elementwise_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_ELEMENTWISE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(elementwise_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_elementwise_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_elementwise_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::elementwise_mode get_elementwise_mode() const + { + return static_cast(elementwise_mode); + } + CONSTEXPR npu_op_elementwise_t& set_elementwise_mode(NPU_NAMESPACE::elementwise_mode value) + { + elementwise_mode = static_cast(value) & ((1U << 6)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("elementwise_mode", (elementwise_mode < (sizeof(elementwise_mode_str)/sizeof(elementwise_mode_str[0])) ? elementwise_mode_str[elementwise_mode] : "****"))); + } +#endif +#endif +}; +// Resize operation +struct npu_op_resize_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_mode:2; // Resize mode + uint32_t reserved1:14; +#ifdef __cplusplus +public: + npu_op_resize_t(NPU_NAMESPACE::resize_mode _resize_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_mode(static_cast(_resize_mode) & ((1U << 2)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_resize_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_RESIZE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_resize_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_resize_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::resize_mode get_resize_mode() const + { + return static_cast(resize_mode); + } + CONSTEXPR npu_op_resize_t& set_resize_mode(NPU_NAMESPACE::resize_mode value) + { + resize_mode = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_mode", (resize_mode < (sizeof(resize_mode_str)/sizeof(resize_mode_str[0])) ? resize_mode_str[resize_mode] : "****"))); + } +#endif +#endif +}; +// Queue new DMA for the given channel +struct npu_op_dma_start_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; +#ifdef __cplusplus +public: + CONSTEXPR npu_op_dma_start_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_START); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_start_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_start_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>&) const + { + } +#endif +#endif +}; +// Wait for the mem2mem DMA channel to have k or fewer active descriptors outstanding +struct npu_op_dma_wait_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t k:2; // Number of outstanding descriptors + uint32_t reserved1:14; +#ifdef __cplusplus +public: + npu_op_dma_wait_t(uint32_t _k) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + k(_k & ((1U << 2)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_dma_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + k(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_DMA_WAIT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(k) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_dma_wait_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_dma_wait_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_k() const + { + return static_cast(k); + } + CONSTEXPR npu_op_dma_wait_t& set_k(uint32_t value) + { + assert((value >> 2) == 0); + k = static_cast(value & ((1U << 2)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("k", std::to_string(k))); + } +#endif +#endif +}; +// Wait for kernel operations to complete +struct npu_op_kernel_wait_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t n:1; // Number of kernel operations + uint32_t reserved1:15; +#ifdef __cplusplus +public: + npu_op_kernel_wait_t(uint32_t _n) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + n(_n & ((1U << 1)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_kernel_wait_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + n(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_KERNEL_WAIT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(n) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_kernel_wait_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_kernel_wait_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_n() const + { + return static_cast(n); + } + CONSTEXPR npu_op_kernel_wait_t& set_n(uint32_t value) + { + assert((value >> 1) == 0); + n = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("n", std::to_string(n))); + } +#endif +#endif +}; +// Enable or disable PMU counting (debug feature only) +struct npu_op_pmu_mask_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t enable:1; // Enable or disable PMU mask + uint32_t reserved1:15; +#ifdef __cplusplus +public: + npu_op_pmu_mask_t(uint32_t _enable) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + enable(_enable & ((1U << 1)-1)), + reserved1(0) + {} + CONSTEXPR npu_op_pmu_mask_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + enable(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_OP_PMU_MASK); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(enable) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_pmu_mask_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_pmu_mask_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_enable() const + { + return static_cast(enable); + } + CONSTEXPR npu_op_pmu_mask_t& set_enable(uint32_t value) + { + assert((value >> 1) == 0); + enable = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("enable", std::to_string(enable))); + } +#endif +#endif +}; +// IFM top pad +struct npu_set_ifm_pad_top_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:7; // IFM top pad + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ifm_pad_top_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_top_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_TOP); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_top_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_top_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_top_t& set_pad(uint32_t value) + { + assert((value >> 7) == 0); + pad = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// IFM left pad +struct npu_set_ifm_pad_left_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:7; // IFM left pad + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ifm_pad_left_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_left_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_LEFT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_left_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_left_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_left_t& set_pad(uint32_t value) + { + assert((value >> 7) == 0); + pad = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// IFM right pad +struct npu_set_ifm_pad_right_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:8; // IFM right pad. Max value is 128 + uint32_t reserved1:8; +#ifdef __cplusplus +public: + npu_set_ifm_pad_right_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 8)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_right_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_RIGHT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_right_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_right_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_right_t& set_pad(uint32_t value) + { + assert((value >> 8) == 0); + pad = static_cast(value & ((1U << 8)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// IFM bottom pad +struct npu_set_ifm_pad_bottom_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t pad:8; // IFM bottom pad. Max value is 128 + uint32_t reserved1:8; +#ifdef __cplusplus +public: + npu_set_ifm_pad_bottom_t(uint32_t _pad) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(_pad & ((1U << 8)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_pad_bottom_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + pad(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PAD_BOTTOM); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(pad) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_pad_bottom_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_pad_bottom_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_pad() const + { + return static_cast(pad); + } + CONSTEXPR npu_set_ifm_pad_bottom_t& set_pad(uint32_t value) + { + assert((value >> 8) == 0); + pad = static_cast(value & ((1U << 8)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("pad", std::to_string(pad))); + } +#endif +#endif +}; +// Number of input channels for convolution +struct npu_set_ifm_depth_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t depth_m1:16; // Number of input channels for convolution +#ifdef __cplusplus +public: + npu_set_ifm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(_depth_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_DEPTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(depth_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_depth_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_depth_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ifm_depth_m1_t& set_depth_m1(uint32_t value) + { + assert((value >> 16) == 0); + depth_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif +}; +// IFM Precision +struct npu_set_ifm_precision_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_type:1; // IFM type + uint32_t reserved1:1; + uint32_t activation_precision:2; // IFM precision + uint32_t reserved2:2; + uint32_t activation_format:2; // IFM format + uint32_t reserved3:6; + uint32_t activation_storage:2; // IFM storage mode +#ifdef __cplusplus +public: + npu_set_ifm_precision_t(NPU_NAMESPACE::activation_type _activation_type, NPU_NAMESPACE::activation_precision _activation_precision, NPU_NAMESPACE::activation_format _activation_format, NPU_NAMESPACE::activation_storage _activation_storage) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1)-1)), + reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2)-1)), + reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2)-1)), + reserved3(0), + activation_storage(static_cast(_activation_storage) & ((1U << 2)-1)) + {} + CONSTEXPR npu_set_ifm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(0), + reserved1(0), + activation_precision(0), + reserved2(0), + activation_format(0), + reserved3(0), + activation_storage(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_PRECISION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_type) << 16; + word |= uint32_t(activation_precision) << 18; + word |= uint32_t(activation_format) << 22; + word |= uint32_t(activation_storage) << 30; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_precision_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_precision_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_storage get_activation_storage() const + { + return static_cast(activation_storage); + } + CONSTEXPR npu_set_ifm_precision_t& set_activation_storage(NPU_NAMESPACE::activation_storage value) + { + activation_storage = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_type", (activation_type < (sizeof(activation_type_str)/sizeof(activation_type_str[0])) ? activation_type_str[activation_type] : "****"))); + fields.push_back(std::make_pair("activation_precision", (activation_precision < (sizeof(activation_precision_str)/sizeof(activation_precision_str[0])) ? activation_precision_str[activation_precision] : "****"))); + fields.push_back(std::make_pair("activation_format", (activation_format < (sizeof(activation_format_str)/sizeof(activation_format_str[0])) ? activation_format_str[activation_format] : "****"))); + fields.push_back(std::make_pair("activation_storage", (activation_storage < (sizeof(activation_storage_str)/sizeof(activation_storage_str[0])) ? activation_storage_str[activation_storage] : "****"))); + } +#endif +#endif +}; +// IFM upscale mode +struct npu_set_ifm_upscale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t mode:2; // IFM upscale mode + uint32_t reserved1:14; +#ifdef __cplusplus +public: + npu_set_ifm_upscale_t(NPU_NAMESPACE::ifm_upscale_mode _mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(static_cast(_mode) & ((1U << 2)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_upscale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_UPSCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_upscale_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_upscale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ifm_upscale_mode get_mode() const + { + return static_cast(mode); + } + CONSTEXPR npu_set_ifm_upscale_t& set_mode(NPU_NAMESPACE::ifm_upscale_mode value) + { + mode = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("mode", (mode < (sizeof(ifm_upscale_mode_str)/sizeof(ifm_upscale_mode_str[0])) ? ifm_upscale_mode_str[mode] : "****"))); + } +#endif +#endif +}; +// IFM zero point +struct npu_set_ifm_zero_point_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t zero_point:16; // Zero point offset +#ifdef __cplusplus +public: + npu_set_ifm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_ZERO_POINT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(zero_point) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_zero_point_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_zero_point_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm_zero_point_t& set_zero_point(uint32_t value) + { + assert((value >> 16) == 0); + zero_point = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif +}; +// IFM Tile 0 and Tile 2 width +struct npu_set_ifm_width0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // IFM Tile 0 and tile 2 width +#ifdef __cplusplus +public: + npu_set_ifm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_WIDTH0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_width0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_width0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm_width0_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// IFM Tile 0 height +struct npu_set_ifm_height0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM Tile 0 height +#ifdef __cplusplus +public: + npu_set_ifm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height0_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// IFM Tile 1 height +struct npu_set_ifm_height1_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM Tile 1 height +#ifdef __cplusplus +public: + npu_set_ifm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_HEIGHT1_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_height1_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_height1_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm_height1_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Index n for IFM access +struct npu_set_ifm_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_ifm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// IFM broadcast configuration +struct npu_set_ifm_broadcast_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t broadcast_mode:4; // Broadcast mode for IFM + uint32_t reserved1:12; +#ifdef __cplusplus +public: + npu_set_ifm_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(static_cast(_broadcast_mode) & ((1U << 4)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM_BROADCAST); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(broadcast_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_broadcast_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_broadcast_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_mode() const + { + return static_cast(broadcast_mode); + } + CONSTEXPR npu_set_ifm_broadcast_t& set_broadcast_mode(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_mode = static_cast(value) & ((1U << 4)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("broadcast_mode", (broadcast_mode < (sizeof(broadcast_mode_str)/sizeof(broadcast_mode_str[0])) ? broadcast_mode_str[broadcast_mode] : "****"))); + } +#endif +#endif +}; +// Output feature map width +struct npu_set_ofm_width_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // Output feature map width +#ifdef __cplusplus +public: + npu_set_ofm_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// Output feature map height +struct npu_set_ofm_height_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // Output feature map height +#ifdef __cplusplus +public: + npu_set_ofm_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Output feature map depth +struct npu_set_ofm_depth_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t depth_m1:16; // Output feature map depth +#ifdef __cplusplus +public: + npu_set_ofm_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(_depth_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_DEPTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(depth_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_depth_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_depth_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_depth_m1_t& set_depth_m1(uint32_t value) + { + assert((value >> 16) == 0); + depth_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif +}; +// OFM Precision +struct npu_set_ofm_precision_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_type:1; // OFM type + uint32_t activation_precision:2; // OFM precision + uint32_t reserved1:3; + uint32_t activation_format:2; // OFM format + uint32_t scale_mode:1; // OFM scale mode + uint32_t activation_reverse:2; // OFM reverse + uint32_t activation_transpose:3; // OFM transpose + uint32_t activation_storage:2; // OFM storage mode +#ifdef __cplusplus +public: + npu_set_ofm_precision_t(NPU_NAMESPACE::activation_type _activation_type, NPU_NAMESPACE::activation_precision _activation_precision, NPU_NAMESPACE::activation_format _activation_format, NPU_NAMESPACE::ofm_scale_mode _scale_mode, NPU_NAMESPACE::activation_reverse _activation_reverse, NPU_NAMESPACE::activation_transpose _activation_transpose, NPU_NAMESPACE::activation_storage _activation_storage) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1)-1)), + activation_precision(static_cast(_activation_precision) & ((1U << 2)-1)), + reserved1(0), + activation_format(static_cast(_activation_format) & ((1U << 2)-1)), + scale_mode(static_cast(_scale_mode) & ((1U << 1)-1)), + activation_reverse(static_cast(_activation_reverse) & ((1U << 2)-1)), + activation_transpose(static_cast(_activation_transpose) & ((1U << 3)-1)), + activation_storage(static_cast(_activation_storage) & ((1U << 2)-1)) + {} + CONSTEXPR npu_set_ofm_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(0), + activation_precision(0), + reserved1(0), + activation_format(0), + scale_mode(0), + activation_reverse(0), + activation_transpose(0), + activation_storage(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_PRECISION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_type) << 16; + word |= uint32_t(activation_precision) << 17; + word |= uint32_t(activation_format) << 22; + word |= uint32_t(scale_mode) << 24; + word |= uint32_t(activation_reverse) << 25; + word |= uint32_t(activation_transpose) << 27; + word |= uint32_t(activation_storage) << 30; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_precision_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_precision_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::ofm_scale_mode get_scale_mode() const + { + return static_cast(scale_mode); + } + CONSTEXPR npu_set_ofm_precision_t& set_scale_mode(NPU_NAMESPACE::ofm_scale_mode value) + { + scale_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_reverse get_activation_reverse() const + { + return static_cast(activation_reverse); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_reverse(NPU_NAMESPACE::activation_reverse value) + { + activation_reverse = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_transpose get_activation_transpose() const + { + return static_cast(activation_transpose); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_transpose(NPU_NAMESPACE::activation_transpose value) + { + activation_transpose = static_cast(value) & ((1U << 3)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_storage get_activation_storage() const + { + return static_cast(activation_storage); + } + CONSTEXPR npu_set_ofm_precision_t& set_activation_storage(NPU_NAMESPACE::activation_storage value) + { + activation_storage = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_type", (activation_type < (sizeof(activation_type_str)/sizeof(activation_type_str[0])) ? activation_type_str[activation_type] : "****"))); + fields.push_back(std::make_pair("activation_precision", (activation_precision < (sizeof(activation_precision_str)/sizeof(activation_precision_str[0])) ? activation_precision_str[activation_precision] : "****"))); + fields.push_back(std::make_pair("activation_format", (activation_format < (sizeof(activation_format_str)/sizeof(activation_format_str[0])) ? activation_format_str[activation_format] : "****"))); + fields.push_back(std::make_pair("scale_mode", (scale_mode < (sizeof(ofm_scale_mode_str)/sizeof(ofm_scale_mode_str[0])) ? ofm_scale_mode_str[scale_mode] : "****"))); + fields.push_back(std::make_pair("activation_reverse", (activation_reverse < (sizeof(activation_reverse_str)/sizeof(activation_reverse_str[0])) ? activation_reverse_str[activation_reverse] : "****"))); + fields.push_back(std::make_pair("activation_transpose", (activation_transpose < (sizeof(activation_transpose_str)/sizeof(activation_transpose_str[0])) ? activation_transpose_str[activation_transpose] : "****"))); + fields.push_back(std::make_pair("activation_storage", (activation_storage < (sizeof(activation_storage_str)/sizeof(activation_storage_str[0])) ? activation_storage_str[activation_storage] : "****"))); + } +#endif +#endif +}; +// OFM block width +struct npu_set_ofm_blk_width_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:7; // OFM block width + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ofm_blk_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_blk_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_WIDTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_blk_width_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 7) == 0); + width_m1 = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// OFM block height +struct npu_set_ofm_blk_height_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:7; // OFM block height + uint32_t reserved1:9; +#ifdef __cplusplus +public: + npu_set_ofm_blk_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 7)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_blk_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_HEIGHT_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_blk_height_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 7) == 0); + height_m1 = static_cast(value & ((1U << 7)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// OFM block depth +struct npu_set_ofm_blk_depth_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t depth_m1:10; // OFM block depth + uint32_t reserved1:6; +#ifdef __cplusplus +public: + npu_set_ofm_blk_depth_m1_t(uint32_t _depth_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(_depth_m1 & ((1U << 10)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_blk_depth_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + depth_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_BLK_DEPTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(depth_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_depth_m1() const + { + return static_cast(depth_m1); + } + CONSTEXPR npu_set_ofm_blk_depth_m1_t& set_depth_m1(uint32_t value) + { + assert((value >> 10) == 0); + depth_m1 = static_cast(value & ((1U << 10)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("depth_m1", std::to_string(depth_m1))); + } +#endif +#endif +}; +// OFM zero point +struct npu_set_ofm_zero_point_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t zero_point:16; // Zero point offset +#ifdef __cplusplus +public: + npu_set_ofm_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_ZERO_POINT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(zero_point) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_zero_point_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_zero_point_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ofm_zero_point_t& set_zero_point(uint32_t value) + { + assert((value >> 16) == 0); + zero_point = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif +}; +// OFM Tile 0 and tile 2 width +struct npu_set_ofm_width0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // OFM Tile 0 and tile 2 width +#ifdef __cplusplus +public: + npu_set_ofm_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_WIDTH0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_width0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_width0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ofm_width0_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// OFM Tile 0 height +struct npu_set_ofm_height0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // OFM Tile 0 height +#ifdef __cplusplus +public: + npu_set_ofm_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height0_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// OFM Tile 1 height +struct npu_set_ofm_height1_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // OFM Tile 1 height +#ifdef __cplusplus +public: + npu_set_ofm_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ofm_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_HEIGHT1_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_height1_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_height1_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ofm_height1_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Index n for OFM access +struct npu_set_ofm_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_ofm_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ofm_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_OFM_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ofm_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// Kernel width +struct npu_set_kernel_width_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // Kernel width +#ifdef __cplusplus +public: + npu_set_kernel_width_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_kernel_width_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_WIDTH_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_width_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_width_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_kernel_width_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// Kernel height +struct npu_set_kernel_height_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // Kernel height +#ifdef __cplusplus +public: + npu_set_kernel_height_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_kernel_height_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_HEIGHT_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_height_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_height_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_kernel_height_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Kernel stride +struct npu_set_kernel_stride_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t stride_x_lsb:1; // Stride x LSB. (kernel_x_stride - 1)[0] + uint32_t stride_y_lsb:1; // Stride y LSB. (kernel_y_stride - 1)[0] + uint32_t weight_order:1; // Weight ordering mode + uint32_t dilation_x:1; // Kernel x dilation + uint32_t dilation_y:1; // Kernel y dilation + uint32_t decomposition:1; // Kernel decomposition + uint32_t stride_x_msb:1; // Stride x MSB. (kernel_x_stride - 1) >> 1 + uint32_t reserved1:2; + uint32_t stride_y_msb:1; // Stride y MSB. (kernel_y_stride - 1) >> 1 + uint32_t reserved2:6; +#ifdef __cplusplus +public: + npu_set_kernel_stride_t(uint32_t _stride_x_lsb, uint32_t _stride_y_lsb, NPU_NAMESPACE::weight_order _weight_order, NPU_NAMESPACE::kernel_dilation _dilation_x, NPU_NAMESPACE::kernel_dilation _dilation_y, NPU_NAMESPACE::kernel_decomposition _decomposition, uint32_t _stride_x_msb, uint32_t _stride_y_msb) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(_stride_x_lsb & ((1U << 1)-1)), + stride_y_lsb(_stride_y_lsb & ((1U << 1)-1)), + weight_order(static_cast(_weight_order) & ((1U << 1)-1)), + dilation_x(static_cast(_dilation_x) & ((1U << 1)-1)), + dilation_y(static_cast(_dilation_y) & ((1U << 1)-1)), + decomposition(static_cast(_decomposition) & ((1U << 1)-1)), + stride_x_msb(_stride_x_msb & ((1U << 1)-1)), + reserved1(0), + stride_y_msb(_stride_y_msb & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_kernel_stride_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + stride_x_lsb(0), + stride_y_lsb(0), + weight_order(0), + dilation_x(0), + dilation_y(0), + decomposition(0), + stride_x_msb(0), + reserved1(0), + stride_y_msb(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_KERNEL_STRIDE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(stride_x_lsb) << 16; + word |= uint32_t(stride_y_lsb) << 17; + word |= uint32_t(weight_order) << 18; + word |= uint32_t(dilation_x) << 19; + word |= uint32_t(dilation_y) << 20; + word |= uint32_t(decomposition) << 21; + word |= uint32_t(stride_x_msb) << 22; + word |= uint32_t(stride_y_msb) << 25; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_kernel_stride_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_kernel_stride_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_lsb() const + { + return static_cast(stride_x_lsb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_x_lsb(uint32_t value) + { + assert((value >> 1) == 0); + stride_x_lsb = static_cast(value & ((1U << 1)-1)); + return *this; + } + CONSTEXPR uint32_t get_stride_y_lsb() const + { + return static_cast(stride_y_lsb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_y_lsb(uint32_t value) + { + assert((value >> 1) == 0); + stride_y_lsb = static_cast(value & ((1U << 1)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_order get_weight_order() const + { + return static_cast(weight_order); + } + CONSTEXPR npu_set_kernel_stride_t& set_weight_order(NPU_NAMESPACE::weight_order value) + { + weight_order = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_x() const + { + return static_cast(dilation_x); + } + CONSTEXPR npu_set_kernel_stride_t& set_dilation_x(NPU_NAMESPACE::kernel_dilation value) + { + dilation_x = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_dilation get_dilation_y() const + { + return static_cast(dilation_y); + } + CONSTEXPR npu_set_kernel_stride_t& set_dilation_y(NPU_NAMESPACE::kernel_dilation value) + { + dilation_y = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::kernel_decomposition get_decomposition() const + { + return static_cast(decomposition); + } + CONSTEXPR npu_set_kernel_stride_t& set_decomposition(NPU_NAMESPACE::kernel_decomposition value) + { + decomposition = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_stride_x_msb() const + { + return static_cast(stride_x_msb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_x_msb(uint32_t value) + { + assert((value >> 1) == 0); + stride_x_msb = static_cast(value & ((1U << 1)-1)); + return *this; + } + CONSTEXPR uint32_t get_stride_y_msb() const + { + return static_cast(stride_y_msb); + } + CONSTEXPR npu_set_kernel_stride_t& set_stride_y_msb(uint32_t value) + { + assert((value >> 1) == 0); + stride_y_msb = static_cast(value & ((1U << 1)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("stride_x_lsb", std::to_string(stride_x_lsb))); + fields.push_back(std::make_pair("stride_y_lsb", std::to_string(stride_y_lsb))); + fields.push_back(std::make_pair("weight_order", (weight_order < (sizeof(weight_order_str)/sizeof(weight_order_str[0])) ? weight_order_str[weight_order] : "****"))); + fields.push_back(std::make_pair("dilation_x", (dilation_x < (sizeof(kernel_dilation_str)/sizeof(kernel_dilation_str[0])) ? kernel_dilation_str[dilation_x] : "****"))); + fields.push_back(std::make_pair("dilation_y", (dilation_y < (sizeof(kernel_dilation_str)/sizeof(kernel_dilation_str[0])) ? kernel_dilation_str[dilation_y] : "****"))); + fields.push_back(std::make_pair("decomposition", (decomposition < (sizeof(kernel_decomposition_str)/sizeof(kernel_decomposition_str[0])) ? kernel_decomposition_str[decomposition] : "****"))); + fields.push_back(std::make_pair("stride_x_msb", std::to_string(stride_x_msb))); + fields.push_back(std::make_pair("stride_y_msb", std::to_string(stride_y_msb))); + } +#endif +#endif +}; +// Accumulator format +struct npu_set_acc_format_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t acc_format:2; // Accumulator format + uint32_t reserved1:2; + uint32_t acc_input:2; // Accumulator input + uint32_t acc_output:1; // Accumulator output + uint32_t reserved2:1; + uint32_t microblock:3; // Accumulator microblock size + uint32_t reserved3:5; +#ifdef __cplusplus +public: + npu_set_acc_format_t(NPU_NAMESPACE::acc_format _acc_format, NPU_NAMESPACE::acc_input _acc_input, NPU_NAMESPACE::acc_output _acc_output, NPU_NAMESPACE::microblock _microblock) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(static_cast(_acc_format) & ((1U << 2)-1)), + reserved1(0), + acc_input(static_cast(_acc_input) & ((1U << 2)-1)), + acc_output(static_cast(_acc_output) & ((1U << 1)-1)), + reserved2(0), + microblock(static_cast(_microblock) & ((1U << 3)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_acc_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + acc_format(0), + reserved1(0), + acc_input(0), + acc_output(0), + reserved2(0), + microblock(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACC_FORMAT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(acc_format) << 16; + word |= uint32_t(acc_input) << 20; + word |= uint32_t(acc_output) << 22; + word |= uint32_t(microblock) << 24; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_acc_format_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_acc_format_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_format get_acc_format() const + { + return static_cast(acc_format); + } + CONSTEXPR npu_set_acc_format_t& set_acc_format(NPU_NAMESPACE::acc_format value) + { + acc_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_input get_acc_input() const + { + return static_cast(acc_input); + } + CONSTEXPR npu_set_acc_format_t& set_acc_input(NPU_NAMESPACE::acc_input value) + { + acc_input = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::acc_output get_acc_output() const + { + return static_cast(acc_output); + } + CONSTEXPR npu_set_acc_format_t& set_acc_output(NPU_NAMESPACE::acc_output value) + { + acc_output = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::microblock get_microblock() const + { + return static_cast(microblock); + } + CONSTEXPR npu_set_acc_format_t& set_microblock(NPU_NAMESPACE::microblock value) + { + microblock = static_cast(value) & ((1U << 3)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("acc_format", (acc_format < (sizeof(acc_format_str)/sizeof(acc_format_str[0])) ? acc_format_str[acc_format] : "****"))); + fields.push_back(std::make_pair("acc_input", (acc_input < (sizeof(acc_input_str)/sizeof(acc_input_str[0])) ? acc_input_str[acc_input] : "****"))); + fields.push_back(std::make_pair("acc_output", (acc_output < (sizeof(acc_output_str)/sizeof(acc_output_str[0])) ? acc_output_str[acc_output] : "****"))); + fields.push_back(std::make_pair("microblock", (microblock < (sizeof(microblock_str)/sizeof(microblock_str[0])) ? microblock_str[microblock] : "****"))); + } +#endif +#endif +}; +// Activation function and clip range +struct npu_set_activation_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_function:5; // Activation function to apply + uint32_t table:3; // Table number to use for LUT + uint32_t reserved1:4; + uint32_t activation_clip_range:1; // Activation clip to apply + uint32_t reserved2:3; +#ifdef __cplusplus +public: + npu_set_activation_t(NPU_NAMESPACE::activation_function _activation_function, uint32_t _table, NPU_NAMESPACE::activation_clip_range _activation_clip_range) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(static_cast(_activation_function) & ((1U << 5)-1)), + table(_table & ((1U << 3)-1)), + reserved1(0), + activation_clip_range(static_cast(_activation_clip_range) & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_activation_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_function(0), + table(0), + reserved1(0), + activation_clip_range(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_function) << 16; + word |= uint32_t(table) << 21; + word |= uint32_t(activation_clip_range) << 28; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_function get_activation_function() const + { + return static_cast(activation_function); + } + CONSTEXPR npu_set_activation_t& set_activation_function(NPU_NAMESPACE::activation_function value) + { + activation_function = static_cast(value) & ((1U << 5)-1); + return *this; + } + CONSTEXPR uint32_t get_table() const + { + return static_cast(table); + } + CONSTEXPR npu_set_activation_t& set_table(uint32_t value) + { + assert((value >> 3) == 0); + table = static_cast(value & ((1U << 3)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_clip_range get_activation_clip_range() const + { + return static_cast(activation_clip_range); + } + CONSTEXPR npu_set_activation_t& set_activation_clip_range(NPU_NAMESPACE::activation_clip_range value) + { + activation_clip_range = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_function", (activation_function < (sizeof(activation_function_str)/sizeof(activation_function_str[0])) ? activation_function_str[activation_function] : "****"))); + fields.push_back(std::make_pair("table", std::to_string(table))); + fields.push_back(std::make_pair("activation_clip_range", (activation_clip_range < (sizeof(activation_clip_range_str)/sizeof(activation_clip_range_str[0])) ? activation_clip_range_str[activation_clip_range] : "****"))); + } +#endif +#endif +}; +// Lower bound clip +struct npu_set_activation_min_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t clip_boundary:16; // Clip boundary for OFM activations +#ifdef __cplusplus +public: + npu_set_activation_min_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_activation_min_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MIN); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(clip_boundary) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_min_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_min_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_min_t& set_clip_boundary(uint32_t value) + { + assert((value >> 16) == 0); + clip_boundary = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif +}; +// Upper bound clip +struct npu_set_activation_max_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t clip_boundary:16; // Clip boundary for OFM activations +#ifdef __cplusplus +public: + npu_set_activation_max_t(uint32_t _clip_boundary) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(_clip_boundary & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_activation_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + clip_boundary(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_ACTIVATION_MAX); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(clip_boundary) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_activation_max_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_activation_max_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_clip_boundary() const + { + return static_cast(clip_boundary); + } + CONSTEXPR npu_set_activation_max_t& set_clip_boundary(uint32_t value) + { + assert((value >> 16) == 0); + clip_boundary = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("clip_boundary", std::to_string(clip_boundary))); + } +#endif +#endif +}; +// Index n for weight stream access +struct npu_set_weight_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Index n for weight stream access + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_weight_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_weight_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_weight_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// Index n for scale stream access +struct npu_set_scale_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Index n for scale stream access + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_scale_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_scale_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_SCALE_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_scale_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// Set weight stream format +struct npu_set_weight_format_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t weight_format:1; // Weight stream format + uint32_t reserved1:3; + uint32_t weight_sparsity:1; // Weight sparsity type + uint32_t reserved2:11; +#ifdef __cplusplus +public: + npu_set_weight_format_t(NPU_NAMESPACE::weight_format _weight_format, NPU_NAMESPACE::weight_sparsity _weight_sparsity) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weight_format(static_cast(_weight_format) & ((1U << 1)-1)), + reserved1(0), + weight_sparsity(static_cast(_weight_sparsity) & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_weight_format_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + weight_format(0), + reserved1(0), + weight_sparsity(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_WEIGHT_FORMAT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(weight_format) << 16; + word |= uint32_t(weight_sparsity) << 20; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_format_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_format_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_format get_weight_format() const + { + return static_cast(weight_format); + } + CONSTEXPR npu_set_weight_format_t& set_weight_format(NPU_NAMESPACE::weight_format value) + { + weight_format = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::weight_sparsity get_weight_sparsity() const + { + return static_cast(weight_sparsity); + } + CONSTEXPR npu_set_weight_format_t& set_weight_sparsity(NPU_NAMESPACE::weight_sparsity value) + { + weight_sparsity = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("weight_format", (weight_format < (sizeof(weight_format_str)/sizeof(weight_format_str[0])) ? weight_format_str[weight_format] : "****"))); + fields.push_back(std::make_pair("weight_sparsity", (weight_sparsity < (sizeof(weight_sparsity_str)/sizeof(weight_sparsity_str[0])) ? weight_sparsity_str[weight_sparsity] : "****"))); + } +#endif +#endif +}; +// Block number of blocks dependency +struct npu_set_blockdep_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t blockdep:3; // Block number of blocks dependency between kernel operations + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_blockdep_t(uint32_t _blockdep) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + blockdep(_blockdep & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_blockdep_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + blockdep(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_BLOCKDEP); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(blockdep) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_blockdep_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_blockdep_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_blockdep() const + { + return static_cast(blockdep); + } + CONSTEXPR npu_set_blockdep_t& set_blockdep(uint32_t value) + { + assert((value >> 3) == 0); + blockdep = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("blockdep", std::to_string(blockdep))); + } +#endif +#endif +}; +// Set resize scale X numerator +struct npu_set_resize_x_scale_n_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_x_scale_n_m1:11; // Resize X scale numerator + uint32_t reserved1:5; +#ifdef __cplusplus +public: + npu_set_resize_x_scale_n_m1_t(uint32_t _resize_x_scale_n_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_scale_n_m1(_resize_x_scale_n_m1 & ((1U << 11)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_x_scale_n_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_scale_n_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_SCALE_N_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_x_scale_n_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_x_scale_n_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_x_scale_n_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_x_scale_n_m1() const + { + return static_cast(resize_x_scale_n_m1); + } + CONSTEXPR npu_set_resize_x_scale_n_m1_t& set_resize_x_scale_n_m1(uint32_t value) + { + assert((value >> 11) == 0); + resize_x_scale_n_m1 = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_x_scale_n_m1", std::to_string(resize_x_scale_n_m1))); + } +#endif +#endif +}; +// Set resize scale Y numerator +struct npu_set_resize_y_scale_n_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_y_scale_n_m1:11; // Resize Y scale numerator + uint32_t reserved1:5; +#ifdef __cplusplus +public: + npu_set_resize_y_scale_n_m1_t(uint32_t _resize_y_scale_n_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_scale_n_m1(_resize_y_scale_n_m1 & ((1U << 11)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_y_scale_n_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_scale_n_m1(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_SCALE_N_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_y_scale_n_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_y_scale_n_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_y_scale_n_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_y_scale_n_m1() const + { + return static_cast(resize_y_scale_n_m1); + } + CONSTEXPR npu_set_resize_y_scale_n_m1_t& set_resize_y_scale_n_m1(uint32_t value) + { + assert((value >> 11) == 0); + resize_y_scale_n_m1 = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_y_scale_n_m1", std::to_string(resize_y_scale_n_m1))); + } +#endif +#endif +}; +// Set resize offset X +struct npu_set_resize_x_offset_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_x_offset:12; // Resize X offset + uint32_t reserved1:4; +#ifdef __cplusplus +public: + npu_set_resize_x_offset_t(uint32_t _resize_x_offset) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_offset(_resize_x_offset & ((1U << 12)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_x_offset_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_x_offset(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_X_OFFSET); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_x_offset) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_x_offset_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_x_offset_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_x_offset() const + { + return static_cast(resize_x_offset); + } + CONSTEXPR npu_set_resize_x_offset_t& set_resize_x_offset(uint32_t value) + { + assert((value >> 12) == 0); + resize_x_offset = static_cast(value & ((1U << 12)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_x_offset", std::to_string(((resize_x_offset <= std::numeric_limits::max() ? static_cast(resize_x_offset) : resize_x_offset - std::numeric_limits::min() + std::numeric_limits::max()) << 20) >> 20))); + } +#endif +#endif +}; +// Set resize offset Y +struct npu_set_resize_y_offset_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t resize_y_offset:12; // Resize Y offset + uint32_t reserved1:4; +#ifdef __cplusplus +public: + npu_set_resize_y_offset_t(uint32_t _resize_y_offset) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_offset(_resize_y_offset & ((1U << 12)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_resize_y_offset_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + resize_y_offset(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_RESIZE_Y_OFFSET); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(resize_y_offset) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_y_offset_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_y_offset_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_resize_y_offset() const + { + return static_cast(resize_y_offset); + } + CONSTEXPR npu_set_resize_y_offset_t& set_resize_y_offset(uint32_t value) + { + assert((value >> 12) == 0); + resize_y_offset = static_cast(value & ((1U << 12)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("resize_y_offset", std::to_string(((resize_y_offset <= std::numeric_limits::max() ? static_cast(resize_y_offset) : resize_y_offset - std::numeric_limits::min() + std::numeric_limits::max()) << 20) >> 20))); + } +#endif +#endif +}; +// DMA0 source region +struct npu_set_dma0_src_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:5; + uint32_t region_mode:1; // Region mode + uint32_t stride_mode:2; // Stride mode + uint32_t idx_mode:1; // Index mode for gather or scatter + uint32_t reserved2:4; +#ifdef __cplusplus +public: + npu_set_dma0_src_region_t(uint32_t _region, NPU_NAMESPACE::dma_region_mode _region_mode, NPU_NAMESPACE::dma_stride_mode _stride_mode, NPU_NAMESPACE::dma_idx_mode _idx_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1)-1)), + stride_mode(static_cast(_stride_mode) & ((1U << 2)-1)), + idx_mode(static_cast(_idx_mode) & ((1U << 1)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_dma0_src_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0), + region_mode(0), + stride_mode(0), + idx_mode(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SRC_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + word |= uint32_t(region_mode) << 24; + word |= uint32_t(stride_mode) << 25; + word |= uint32_t(idx_mode) << 27; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_src_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_src_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_stride_mode get_stride_mode() const + { + return static_cast(stride_mode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_stride_mode(NPU_NAMESPACE::dma_stride_mode value) + { + stride_mode = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_idx_mode get_idx_mode() const + { + return static_cast(idx_mode); + } + CONSTEXPR npu_set_dma0_src_region_t& set_idx_mode(NPU_NAMESPACE::dma_idx_mode value) + { + idx_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair("region_mode", (region_mode < (sizeof(dma_region_mode_str)/sizeof(dma_region_mode_str[0])) ? dma_region_mode_str[region_mode] : "****"))); + fields.push_back(std::make_pair("stride_mode", (stride_mode < (sizeof(dma_stride_mode_str)/sizeof(dma_stride_mode_str[0])) ? dma_stride_mode_str[stride_mode] : "****"))); + fields.push_back(std::make_pair("idx_mode", (idx_mode < (sizeof(dma_idx_mode_str)/sizeof(dma_idx_mode_str[0])) ? dma_idx_mode_str[idx_mode] : "****"))); + } +#endif +#endif +}; +// DMA0 destination region +struct npu_set_dma0_dst_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for memory accesses + uint32_t reserved1:5; + uint32_t region_mode:1; // Region mode + uint32_t reserved2:2; + uint32_t idx_mode:1; // Index mode for gather or scatter + uint32_t reserved3:4; +#ifdef __cplusplus +public: + npu_set_dma0_dst_region_t(uint32_t _region, NPU_NAMESPACE::dma_region_mode _region_mode, NPU_NAMESPACE::dma_idx_mode _idx_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0), + region_mode(static_cast(_region_mode) & ((1U << 1)-1)), + reserved2(0), + idx_mode(static_cast(_idx_mode) & ((1U << 1)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_dma0_dst_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0), + region_mode(0), + reserved2(0), + idx_mode(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_DST_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + word |= uint32_t(region_mode) << 24; + word |= uint32_t(idx_mode) << 27; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_region_mode get_region_mode() const + { + return static_cast(region_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_region_mode(NPU_NAMESPACE::dma_region_mode value) + { + region_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::dma_idx_mode get_idx_mode() const + { + return static_cast(idx_mode); + } + CONSTEXPR npu_set_dma0_dst_region_t& set_idx_mode(NPU_NAMESPACE::dma_idx_mode value) + { + idx_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + fields.push_back(std::make_pair("region_mode", (region_mode < (sizeof(dma_region_mode_str)/sizeof(dma_region_mode_str[0])) ? dma_region_mode_str[region_mode] : "****"))); + fields.push_back(std::make_pair("idx_mode", (idx_mode < (sizeof(dma_idx_mode_str)/sizeof(dma_idx_mode_str[0])) ? dma_idx_mode_str[idx_mode] : "****"))); + } +#endif +#endif +}; +// Size of second dimension for 2D/3D transfers +struct npu_set_dma0_size0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t size:16; // Size of second dimension for 2D/3D transfers +#ifdef __cplusplus +public: + npu_set_dma0_size0_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(_size & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_dma0_size0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(size) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size0_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size0_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size0_t& set_size(uint32_t value) + { + assert((value >> 16) == 0); + size = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif +}; +// Size of third dimension for 3D transfers +struct npu_set_dma0_size1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t size:16; // Size of third dimension for 3D transfers +#ifdef __cplusplus +public: + npu_set_dma0_size1_t(uint32_t _size) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(_size & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_dma0_size1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + size(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_SIZE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(size) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_size1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_size1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_size() const + { + return static_cast(size); + } + CONSTEXPR npu_set_dma0_size1_t& set_size(uint32_t value) + { + assert((value >> 16) == 0); + size = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("size", std::to_string(size))); + } +#endif +#endif +}; +// DMA0 index region +struct npu_set_dma0_idx_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_dma0_idx_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_dma0_idx_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_DMA0_IDX_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_idx_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_idx_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_dma0_idx_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// IFM2 broadcast configuration +struct npu_set_ifm2_broadcast_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t broadcast_mode:4; // Broadcast mode for IFM2 + uint32_t reserved1:12; +#ifdef __cplusplus +public: + npu_set_ifm2_broadcast_t(NPU_NAMESPACE::broadcast_mode _broadcast_mode) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(static_cast(_broadcast_mode) & ((1U << 4)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm2_broadcast_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + broadcast_mode(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_BROADCAST); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(broadcast_mode) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_broadcast_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_broadcast_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::broadcast_mode get_broadcast_mode() const + { + return static_cast(broadcast_mode); + } + CONSTEXPR npu_set_ifm2_broadcast_t& set_broadcast_mode(NPU_NAMESPACE::broadcast_mode value) + { + broadcast_mode = static_cast(value) & ((1U << 4)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("broadcast_mode", (broadcast_mode < (sizeof(broadcast_mode_str)/sizeof(broadcast_mode_str[0])) ? broadcast_mode_str[broadcast_mode] : "****"))); + } +#endif +#endif +}; +// IFM2 Precision +struct npu_set_ifm2_precision_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t activation_type:1; // IFM type + uint32_t reserved1:1; + uint32_t activation_precision:2; // IFM precision + uint32_t reserved2:2; + uint32_t activation_format:2; // IFM format + uint32_t reserved3:6; + uint32_t activation_storage:2; // IFM storage mode +#ifdef __cplusplus +public: + npu_set_ifm2_precision_t(NPU_NAMESPACE::activation_type _activation_type, NPU_NAMESPACE::activation_precision _activation_precision, NPU_NAMESPACE::activation_format _activation_format, NPU_NAMESPACE::activation_storage _activation_storage) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(static_cast(_activation_type) & ((1U << 1)-1)), + reserved1(0), + activation_precision(static_cast(_activation_precision) & ((1U << 2)-1)), + reserved2(0), + activation_format(static_cast(_activation_format) & ((1U << 2)-1)), + reserved3(0), + activation_storage(static_cast(_activation_storage) & ((1U << 2)-1)) + {} + CONSTEXPR npu_set_ifm2_precision_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + activation_type(0), + reserved1(0), + activation_precision(0), + reserved2(0), + activation_format(0), + reserved3(0), + activation_storage(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_PRECISION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(activation_type) << 16; + word |= uint32_t(activation_precision) << 18; + word |= uint32_t(activation_format) << 22; + word |= uint32_t(activation_storage) << 30; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_precision_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_precision_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_type get_activation_type() const + { + return static_cast(activation_type); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_type(NPU_NAMESPACE::activation_type value) + { + activation_type = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_precision get_activation_precision() const + { + return static_cast(activation_precision); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_precision(NPU_NAMESPACE::activation_precision value) + { + activation_precision = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_format get_activation_format() const + { + return static_cast(activation_format); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_format(NPU_NAMESPACE::activation_format value) + { + activation_format = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::activation_storage get_activation_storage() const + { + return static_cast(activation_storage); + } + CONSTEXPR npu_set_ifm2_precision_t& set_activation_storage(NPU_NAMESPACE::activation_storage value) + { + activation_storage = static_cast(value) & ((1U << 2)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("activation_type", (activation_type < (sizeof(activation_type_str)/sizeof(activation_type_str[0])) ? activation_type_str[activation_type] : "****"))); + fields.push_back(std::make_pair("activation_precision", (activation_precision < (sizeof(activation_precision_str)/sizeof(activation_precision_str[0])) ? activation_precision_str[activation_precision] : "****"))); + fields.push_back(std::make_pair("activation_format", (activation_format < (sizeof(activation_format_str)/sizeof(activation_format_str[0])) ? activation_format_str[activation_format] : "****"))); + fields.push_back(std::make_pair("activation_storage", (activation_storage < (sizeof(activation_storage_str)/sizeof(activation_storage_str[0])) ? activation_storage_str[activation_storage] : "****"))); + } +#endif +#endif +}; +// IFM2 zero point +struct npu_set_ifm2_zero_point_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t zero_point:16; // Zero point offset +#ifdef __cplusplus +public: + npu_set_ifm2_zero_point_t(uint32_t _zero_point) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(_zero_point & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_zero_point_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + zero_point(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_ZERO_POINT); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(zero_point) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_zero_point_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_zero_point_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_zero_point() const + { + return static_cast(zero_point); + } + CONSTEXPR npu_set_ifm2_zero_point_t& set_zero_point(uint32_t value) + { + assert((value >> 16) == 0); + zero_point = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("zero_point", std::to_string(zero_point))); + } +#endif +#endif +}; +// IFM2 Tile 0 and Tile 2 width +struct npu_set_ifm2_width0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t width_m1:16; // IFM2 Tile 0 and tile 2 width +#ifdef __cplusplus +public: + npu_set_ifm2_width0_m1_t(uint32_t _width_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(_width_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_width0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + width_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_WIDTH0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(width_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_width0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_width0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_width_m1() const + { + return static_cast(width_m1); + } + CONSTEXPR npu_set_ifm2_width0_m1_t& set_width_m1(uint32_t value) + { + assert((value >> 16) == 0); + width_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("width_m1", std::to_string(width_m1))); + } +#endif +#endif +}; +// IFM2 Tile 0 height +struct npu_set_ifm2_height0_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM2 Tile 0 height +#ifdef __cplusplus +public: + npu_set_ifm2_height0_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_height0_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT0_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height0_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height0_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height0_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// IFM2 Tile 1 height +struct npu_set_ifm2_height1_m1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t height_m1:16; // IFM2 Tile 1 height +#ifdef __cplusplus +public: + npu_set_ifm2_height1_m1_t(uint32_t _height_m1) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(_height_m1 & ((1U << 16)-1)) + {} + CONSTEXPR npu_set_ifm2_height1_m1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + height_m1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_HEIGHT1_M1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(height_m1) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_height1_m1_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_height1_m1_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_height_m1() const + { + return static_cast(height_m1); + } + CONSTEXPR npu_set_ifm2_height1_m1_t& set_height_m1(uint32_t value) + { + assert((value >> 16) == 0); + height_m1 = static_cast(value & ((1U << 16)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("height_m1", std::to_string(height_m1))); + } +#endif +#endif +}; +// Index n for IFM2 access +struct npu_set_ifm2_region_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t region:3; // Region number for external memory accesses + uint32_t reserved1:13; +#ifdef __cplusplus +public: + npu_set_ifm2_region_t(uint32_t _region) : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(_region & ((1U << 3)-1)), + reserved1(0) + {} + CONSTEXPR npu_set_ifm2_region_t() : + opcode(static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL)), + region(0), + reserved1(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION) && control == static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd0_opcode::NPU_SET_IFM2_REGION); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD0_CTRL); + } + operator uint32_t() + { + uint32_t word = 0; + word |= uint32_t(opcode) << 0; + word |= uint32_t(control) << 14; + word |= uint32_t(region) << 16; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd0_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_region_t& set_opcode(NPU_NAMESPACE::cmd0_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_region_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_region() const + { + return static_cast(region); + } + CONSTEXPR npu_set_ifm2_region_t& set_region(uint32_t value) + { + assert((value >> 3) == 0); + region = static_cast(value & ((1U << 3)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("region", std::to_string(region))); + } +#endif +#endif +}; +// IFM Tile 0 address +struct npu_set_ifm_base0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM Tile 1 address +struct npu_set_ifm_base1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM Tile 2 address +struct npu_set_ifm_base2_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE2); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base2_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM Tile 3 address +struct npu_set_ifm_base3_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_BASE3); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_base3_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM byte stride between horizontal values +struct npu_set_ifm_stride_x_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_x_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM byte stride between vertical values +struct npu_set_ifm_stride_y_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_y_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM byte stride between channel blocks +struct npu_set_ifm_stride_c_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_STRIDE_C); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm_stride_c_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 0 address +struct npu_set_ofm_base0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 1 address +struct npu_set_ofm_base1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 2 address +struct npu_set_ofm_base2_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE2); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base2_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM Tile 3 address +struct npu_set_ofm_base3_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_BASE3); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_base3_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM byte stride between horizontal values +struct npu_set_ofm_stride_x_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_x_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM byte stride between vertical values +struct npu_set_ofm_stride_y_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_y_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// OFM byte stride between channel blocks +struct npu_set_ofm_stride_c_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ofm_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ofm_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_STRIDE_C); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ofm_stride_c_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION +struct npu_set_weight_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length +struct npu_set_weight_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Scale and bias stream input byte offset from SCALE_REGION +struct npu_set_scale_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_scale_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_scale_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_scale_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Scale and bias stream input byte length +struct npu_set_scale_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:20; // Scale and bias stream byte length + uint32_t reserved2:12; +#ifdef __cplusplus +public: + npu_set_scale_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length & ((1U << 20)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_scale_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_SCALE_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_scale_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_scale_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_scale_length_t& set_length(uint32_t value) + { + assert((value >> 20) == 0); + length = value & ((1U << 20)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// OFM scale +struct npu_set_ofm_scale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t shift:6; // Right shift (0 to 63) + uint32_t dbl_rnd:5; // Double rounding shift (0 to 30) + uint32_t reserved1:2; + uint32_t round_mode:3; // Rounding mode + uint32_t scale:31; // Scale value (uint31 = non-negative int32) + uint32_t reserved2:1; +#ifdef __cplusplus +public: + npu_set_ofm_scale_t(uint32_t _shift, uint32_t _dbl_rnd, NPU_NAMESPACE::round_mode_ofm _round_mode, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(_shift & ((1U << 6)-1)), + dbl_rnd(_dbl_rnd & ((1U << 5)-1)), + reserved1(0), + round_mode(static_cast(_round_mode) & ((1U << 3)-1)), + scale(_scale & ((1U << 31)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_ofm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(0), + dbl_rnd(0), + reserved1(0), + round_mode(0), + scale(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OFM_SCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(shift) << 16; + word |= uint64_t(dbl_rnd) << 22; + word |= uint64_t(round_mode) << 29; + word |= uint64_t(scale) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ofm_scale_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ofm_scale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ofm_scale_t& set_shift(uint32_t value) + { + assert((value >> 6) == 0); + shift = static_cast(value & ((1U << 6)-1)); + return *this; + } + CONSTEXPR uint32_t get_dbl_rnd() const + { + return static_cast(dbl_rnd); + } + CONSTEXPR npu_set_ofm_scale_t& set_dbl_rnd(uint32_t value) + { + assert((value >> 5) == 0); + dbl_rnd = static_cast(value & ((1U << 5)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode_ofm get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ofm_scale_t& set_round_mode(NPU_NAMESPACE::round_mode_ofm value) + { + round_mode = static_cast(value) & ((1U << 3)-1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ofm_scale_t& set_scale(uint32_t value) + { + assert((value >> 31) == 0); + scale = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("dbl_rnd", std::to_string(dbl_rnd))); + fields.push_back(std::make_pair("round_mode", (round_mode < (sizeof(round_mode_ofm_str)/sizeof(round_mode_ofm_str[0])) ? round_mode_ofm_str[round_mode] : "****"))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif +}; +// IFM input scale +struct npu_set_ifm_scale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t shift:6; // Right shift (0 to 63) + uint32_t dbl_rnd:5; // Double rounding shift (0 to 30) + uint32_t reserved1:2; + uint32_t round_mode:1; // Rounding mode + uint32_t reserved2:2; + uint32_t scale:31; // Scale value (uint31 = non-negative int32) + uint32_t reserved3:1; +#ifdef __cplusplus +public: + npu_set_ifm_scale_t(uint32_t _shift, uint32_t _dbl_rnd, NPU_NAMESPACE::round_mode_ifm _round_mode, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(_shift & ((1U << 6)-1)), + dbl_rnd(_dbl_rnd & ((1U << 5)-1)), + reserved1(0), + round_mode(static_cast(_round_mode) & ((1U << 1)-1)), + reserved2(0), + scale(_scale & ((1U << 31)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_ifm_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(0), + dbl_rnd(0), + reserved1(0), + round_mode(0), + reserved2(0), + scale(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM_SCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(shift) << 16; + word |= uint64_t(dbl_rnd) << 22; + word |= uint64_t(round_mode) << 29; + word |= uint64_t(scale) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm_scale_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm_scale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ifm_scale_t& set_shift(uint32_t value) + { + assert((value >> 6) == 0); + shift = static_cast(value & ((1U << 6)-1)); + return *this; + } + CONSTEXPR uint32_t get_dbl_rnd() const + { + return static_cast(dbl_rnd); + } + CONSTEXPR npu_set_ifm_scale_t& set_dbl_rnd(uint32_t value) + { + assert((value >> 5) == 0); + dbl_rnd = static_cast(value & ((1U << 5)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode_ifm get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm_scale_t& set_round_mode(NPU_NAMESPACE::round_mode_ifm value) + { + round_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ifm_scale_t& set_scale(uint32_t value) + { + assert((value >> 31) == 0); + scale = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("dbl_rnd", std::to_string(dbl_rnd))); + fields.push_back(std::make_pair("round_mode", (round_mode < (sizeof(round_mode_ifm_str)/sizeof(round_mode_ifm_str[0])) ? round_mode_ifm_str[round_mode] : "****"))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif +}; +// IFM2 input scale +struct npu_set_ifm2_scale_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t shift:6; // Right shift (0 to 63) + uint32_t dbl_rnd:5; // Double rounding shift (0 to 30) + uint32_t reserved1:2; + uint32_t round_mode:1; // Rounding mode + uint32_t reserved2:2; + uint32_t scale:31; // Scale value (uint31 = non-negative int32) + uint32_t reserved3:1; +#ifdef __cplusplus +public: + npu_set_ifm2_scale_t(uint32_t _shift, uint32_t _dbl_rnd, NPU_NAMESPACE::round_mode_ifm _round_mode, uint32_t _scale) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(_shift & ((1U << 6)-1)), + dbl_rnd(_dbl_rnd & ((1U << 5)-1)), + reserved1(0), + round_mode(static_cast(_round_mode) & ((1U << 1)-1)), + reserved2(0), + scale(_scale & ((1U << 31)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_ifm2_scale_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + shift(0), + dbl_rnd(0), + reserved1(0), + round_mode(0), + reserved2(0), + scale(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_SCALE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(shift) << 16; + word |= uint64_t(dbl_rnd) << 22; + word |= uint64_t(round_mode) << 29; + word |= uint64_t(scale) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_ifm2_scale_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_ifm2_scale_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_shift() const + { + return static_cast(shift); + } + CONSTEXPR npu_set_ifm2_scale_t& set_shift(uint32_t value) + { + assert((value >> 6) == 0); + shift = static_cast(value & ((1U << 6)-1)); + return *this; + } + CONSTEXPR uint32_t get_dbl_rnd() const + { + return static_cast(dbl_rnd); + } + CONSTEXPR npu_set_ifm2_scale_t& set_dbl_rnd(uint32_t value) + { + assert((value >> 5) == 0); + dbl_rnd = static_cast(value & ((1U << 5)-1)); + return *this; + } + CONSTEXPR NPU_NAMESPACE::round_mode_ifm get_round_mode() const + { + return static_cast(round_mode); + } + CONSTEXPR npu_set_ifm2_scale_t& set_round_mode(NPU_NAMESPACE::round_mode_ifm value) + { + round_mode = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_scale() const + { + return static_cast(scale); + } + CONSTEXPR npu_set_ifm2_scale_t& set_scale(uint32_t value) + { + assert((value >> 31) == 0); + scale = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("shift", std::to_string(shift))); + fields.push_back(std::make_pair("dbl_rnd", std::to_string(dbl_rnd))); + fields.push_back(std::make_pair("round_mode", (round_mode < (sizeof(round_mode_ifm_str)/sizeof(round_mode_ifm_str[0])) ? round_mode_ifm_str[round_mode] : "****"))); + fields.push_back(std::make_pair("scale", std::to_string(scale))); + } +#endif +#endif +}; +// Operation scalar value +struct npu_set_op_scalar_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t scalar:32; // Scalar value (int32) +#ifdef __cplusplus +public: + npu_set_op_scalar_t(uint32_t _scalar) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + scalar(_scalar) + {} + CONSTEXPR npu_set_op_scalar_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + scalar(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_OP_SCALAR); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(scalar) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_op_scalar_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_op_scalar_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_scalar() const + { + return static_cast(scalar); + } + CONSTEXPR npu_set_op_scalar_t& set_scalar(uint32_t value) + { + scalar = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("scalar", std::to_string(((scalar <= std::numeric_limits::max() ? static_cast(scalar) : scalar - std::numeric_limits::min() + std::numeric_limits::max()) << 0) >> 0))); + } +#endif +#endif +}; +// DMA user channel 0 source byte offset from DMA0_SRC_REGION +struct npu_set_dma0_src_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_src_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_src_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA user channel 0 destination byte offset from DMA0_DST_REGION +struct npu_set_dma0_dst_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_dst_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_dst_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA user channel 0 transfer length in bytes for each 1D transfer +struct npu_set_dma0_len_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_len_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_len_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_LEN); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_len_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Source byte stride after each 1D transfer +struct npu_set_dma0_src_stride0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_src_stride0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_src_stride0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_stride0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Source byte stride after each 2D transfer +struct npu_set_dma0_src_stride1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_src_stride1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_src_stride1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_SRC_STRIDE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_src_stride1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Destination byte stride after each 1D transfer +struct npu_set_dma0_dst_stride0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_dst_stride0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_dst_stride0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_stride0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Destination byte stride after 2D transfer +struct npu_set_dma0_dst_stride1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_dst_stride1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_dst_stride1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_DST_STRIDE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_dst_stride1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA channel 0 index array address +struct npu_set_dma0_idx_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_idx_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_idx_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_idx_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// DMA channel 0 index maximum value +struct npu_set_dma0_idx_max_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t idx_max:31; // maximum permitted index + uint32_t reserved2:1; +#ifdef __cplusplus +public: + npu_set_dma0_idx_max_t(uint32_t _idx_max) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + idx_max(_idx_max & ((1U << 31)-1)), + reserved2(0) + {} + CONSTEXPR npu_set_dma0_idx_max_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + idx_max(0), + reserved2(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_MAX); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(idx_max) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_dma0_idx_max_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_dma0_idx_max_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_idx_max() const + { + return static_cast(idx_max); + } + CONSTEXPR npu_set_dma0_idx_max_t& set_idx_max(uint32_t value) + { + assert((value >> 31) == 0); + idx_max = value & ((1U << 31)-1); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("idx_max", std::to_string(idx_max))); + } +#endif +#endif +}; +// Index byte distance to skip in index after each 2D transfer +struct npu_set_dma0_idx_skip1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_dma0_idx_skip1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_dma0_idx_skip1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_DMA0_IDX_SKIP1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_dma0_idx_skip1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 0 address +struct npu_set_ifm2_base0_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base0_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base0_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE0); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base0_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 1 address +struct npu_set_ifm2_base1_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base1_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base1_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE1); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base1_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 2 address +struct npu_set_ifm2_base2_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base2_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base2_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE2); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base2_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 Tile 3 address +struct npu_set_ifm2_base3_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_base3_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_base3_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_BASE3); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_base3_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 byte stride between horizontal values +struct npu_set_ifm2_stride_x_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_stride_x_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_stride_x_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_x_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 byte stride between vertical values +struct npu_set_ifm2_stride_y_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_stride_y_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_stride_y_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_y_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// IFM2 byte stride between channel blocks +struct npu_set_ifm2_stride_c_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_ifm2_stride_c_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_ifm2_stride_c_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_IFM2_STRIDE_C); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_ifm2_stride_c_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION for weight decoder 1 +struct npu_set_weight1_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight1_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight1_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight1_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length for weight decoder 1 +struct npu_set_weight1_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight1_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight1_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT1_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight1_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight1_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight1_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION for weight decoder 2 +struct npu_set_weight2_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight2_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight2_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight2_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length for weight decoder 2 +struct npu_set_weight2_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight2_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight2_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT2_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight2_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight2_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight2_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Weight stream byte offset in WEIGHT_REGION for weight decoder 3 +struct npu_set_weight3_base_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t addr_hi:8; // address extension + uint32_t reserved1:8; + uint32_t addr_lo:32; // address offset +#ifdef __cplusplus +public: + npu_set_weight3_base_t(uint64_t _addr) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(static_cast((_addr >> 32) & static_cast(std::numeric_limits::max()))), + reserved1(0), + addr_lo(static_cast((_addr) & static_cast(std::numeric_limits::max()))) + {} + CONSTEXPR npu_set_weight3_base_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + addr_hi(0), + reserved1(0), + addr_lo(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_BASE); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(addr_hi) << 16; + word |= uint64_t(addr_lo) << 32; + return word; + } + CONSTEXPR uint64_t get_addr() const + { + return (static_cast(addr_hi) << 32) | addr_lo; + } + CONSTEXPR npu_set_weight3_base_t& set_addr(uint64_t value) + { + addr_lo = static_cast((value) & static_cast(std::numeric_limits::max())); addr_hi = static_cast((value >> 32) & static_cast(std::numeric_limits::max())); return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + std::stringstream saddr; saddr << std::hex << "0x" << get_addr(); + fields.push_back(std::make_pair("addr", saddr.str())); + } +#endif +#endif +}; +// Weight stream byte length for weight decoder 3 +struct npu_set_weight3_length_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t reserved1:16; + uint32_t length:32; // Weight stream byte length +#ifdef __cplusplus +public: + npu_set_weight3_length_t(uint32_t _length) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(_length) + {} + CONSTEXPR npu_set_weight3_length_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + reserved1(0), + length(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_WEIGHT3_LENGTH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(length) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_weight3_length_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_weight3_length_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_length() const + { + return static_cast(length); + } + CONSTEXPR npu_set_weight3_length_t& set_length(uint32_t value) + { + length = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("length", std::to_string(length))); + } +#endif +#endif +}; +// Resize X axis step parameters +struct npu_set_resize_x_step_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t one_step_int:4; // (1*scale_d) / scale_n + uint32_t blk_step_int:11; // ((ofm_block_size-1)*scale_d) / scale_n + uint32_t reserved1:1; + uint32_t one_step_mod:11; // (1*scale_d) % scale_n + uint32_t reserved2:5; + uint32_t blk_step_mod:11; // ((ofm_block_size-1)*scale_d) % scale_n + uint32_t reserved3:5; +#ifdef __cplusplus +public: + npu_set_resize_x_step_t(uint32_t _one_step_int, uint32_t _blk_step_int, uint32_t _one_step_mod, uint32_t _blk_step_mod) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(_one_step_int & ((1U << 4)-1)), + blk_step_int(_blk_step_int & ((1U << 11)-1)), + reserved1(0), + one_step_mod(_one_step_mod & ((1U << 11)-1)), + reserved2(0), + blk_step_mod(_blk_step_mod & ((1U << 11)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_resize_x_step_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(0), + blk_step_int(0), + reserved1(0), + one_step_mod(0), + reserved2(0), + blk_step_mod(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_X); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(one_step_int) << 16; + word |= uint64_t(blk_step_int) << 20; + word |= uint64_t(one_step_mod) << 32; + word |= uint64_t(blk_step_mod) << 48; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_x_step_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_x_step_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_one_step_int() const + { + return static_cast(one_step_int); + } + CONSTEXPR npu_set_resize_x_step_t& set_one_step_int(uint32_t value) + { + assert((value >> 4) == 0); + one_step_int = static_cast(value & ((1U << 4)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_int() const + { + return static_cast(blk_step_int); + } + CONSTEXPR npu_set_resize_x_step_t& set_blk_step_int(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_int = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_one_step_mod() const + { + return static_cast(one_step_mod); + } + CONSTEXPR npu_set_resize_x_step_t& set_one_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + one_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_mod() const + { + return static_cast(blk_step_mod); + } + CONSTEXPR npu_set_resize_x_step_t& set_blk_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("one_step_int", std::to_string(one_step_int))); + fields.push_back(std::make_pair("blk_step_int", std::to_string(blk_step_int))); + fields.push_back(std::make_pair("one_step_mod", std::to_string(one_step_mod))); + fields.push_back(std::make_pair("blk_step_mod", std::to_string(blk_step_mod))); + } +#endif +#endif +}; +// Resize Y axis step parameters +struct npu_set_resize_y_step_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t one_step_int:4; // (1*scale_d) / scale_n + uint32_t blk_step_int:11; // ((ofm_block_size-1)*scale_d) / scale_n + uint32_t reserved1:1; + uint32_t one_step_mod:11; // (1*scale_d) % scale_n + uint32_t reserved2:5; + uint32_t blk_step_mod:11; // ((ofm_block_size-1)*scale_d) % scale_n + uint32_t reserved3:5; +#ifdef __cplusplus +public: + npu_set_resize_y_step_t(uint32_t _one_step_int, uint32_t _blk_step_int, uint32_t _one_step_mod, uint32_t _blk_step_mod) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(_one_step_int & ((1U << 4)-1)), + blk_step_int(_blk_step_int & ((1U << 11)-1)), + reserved1(0), + one_step_mod(_one_step_mod & ((1U << 11)-1)), + reserved2(0), + blk_step_mod(_blk_step_mod & ((1U << 11)-1)), + reserved3(0) + {} + CONSTEXPR npu_set_resize_y_step_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + one_step_int(0), + blk_step_int(0), + reserved1(0), + one_step_mod(0), + reserved2(0), + blk_step_mod(0), + reserved3(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_SET_RESIZE_Y); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(one_step_int) << 16; + word |= uint64_t(blk_step_int) << 20; + word |= uint64_t(one_step_mod) << 32; + word |= uint64_t(blk_step_mod) << 48; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_set_resize_y_step_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_set_resize_y_step_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR uint32_t get_one_step_int() const + { + return static_cast(one_step_int); + } + CONSTEXPR npu_set_resize_y_step_t& set_one_step_int(uint32_t value) + { + assert((value >> 4) == 0); + one_step_int = static_cast(value & ((1U << 4)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_int() const + { + return static_cast(blk_step_int); + } + CONSTEXPR npu_set_resize_y_step_t& set_blk_step_int(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_int = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_one_step_mod() const + { + return static_cast(one_step_mod); + } + CONSTEXPR npu_set_resize_y_step_t& set_one_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + one_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } + CONSTEXPR uint32_t get_blk_step_mod() const + { + return static_cast(blk_step_mod); + } + CONSTEXPR npu_set_resize_y_step_t& set_blk_step_mod(uint32_t value) + { + assert((value >> 11) == 0); + blk_step_mod = static_cast(value & ((1U << 11)-1)); + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("one_step_int", std::to_string(one_step_int))); + fields.push_back(std::make_pair("blk_step_int", std::to_string(blk_step_int))); + fields.push_back(std::make_pair("one_step_mod", std::to_string(one_step_mod))); + fields.push_back(std::make_pair("blk_step_mod", std::to_string(blk_step_mod))); + } +#endif +#endif +}; +// Branch to new location +struct npu_op_branch_t +{ +#ifdef __cplusplus +private: +#endif + uint32_t opcode:10; // opcode + uint32_t reserved0:4; + uint32_t control:2; // control + uint32_t branch_cond:1; // Branch condition + uint32_t reserved1:15; + uint32_t branch_target:32; // Branch target in bytes +#ifdef __cplusplus +public: + npu_op_branch_t(NPU_NAMESPACE::branch_cond _branch_cond, uint32_t _branch_target) : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + branch_cond(static_cast(_branch_cond) & ((1U << 1)-1)), + reserved1(0), + branch_target(_branch_target) + {} + CONSTEXPR npu_op_branch_t() : + opcode(static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH)), + reserved0(0), + control(static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL)), + branch_cond(0), + reserved1(0), + branch_target(0) + {} + CONSTEXPR bool valid() const + { + return opcode == static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH) && control >= 1 && control <= 2; + } + CONSTEXPR void init() + { + opcode = static_cast(NPU_NAMESPACE::cmd1_opcode::NPU_OP_BRANCH); control = static_cast(NPU_NAMESPACE::cmd_ctrl::CMD1_CTRL); + } + operator uint64_t() + { + uint64_t word = 0; + word |= uint64_t(opcode) << 0; + word |= uint64_t(control) << 14; + word |= uint64_t(branch_cond) << 16; + word |= uint64_t(branch_target) << 32; + return word; + } + CONSTEXPR NPU_NAMESPACE::cmd1_opcode get_opcode() const + { + return static_cast(opcode); + } + CONSTEXPR npu_op_branch_t& set_opcode(NPU_NAMESPACE::cmd1_opcode value) + { + opcode = static_cast(value) & ((1U << 10)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::cmd_ctrl get_control() const + { + return static_cast(control); + } + CONSTEXPR npu_op_branch_t& set_control(NPU_NAMESPACE::cmd_ctrl value) + { + control = static_cast(value) & ((1U << 2)-1); + return *this; + } + CONSTEXPR NPU_NAMESPACE::branch_cond get_branch_cond() const + { + return static_cast(branch_cond); + } + CONSTEXPR npu_op_branch_t& set_branch_cond(NPU_NAMESPACE::branch_cond value) + { + branch_cond = static_cast(value) & ((1U << 1)-1); + return *this; + } + CONSTEXPR uint32_t get_branch_target() const + { + return static_cast(branch_target); + } + CONSTEXPR npu_op_branch_t& set_branch_target(uint32_t value) + { + branch_target = value; + return *this; + } +#ifdef NPU_DISASSEMBLE + void disassemble(std::vector>& fields) const + { + fields.push_back(std::make_pair("branch_cond", (branch_cond < (sizeof(branch_cond_str)/sizeof(branch_cond_str[0])) ? branch_cond_str[branch_cond] : "****"))); + fields.push_back(std::make_pair("branch_target", std::to_string(branch_target))); + } +#endif +#endif +}; +#ifdef __cplusplus +}; +#endif +#define NPU_OP_STRUCTS \ + NPU_OP_(stop) \ + NPU_OP_(irq) \ + NPU_OP_(conv) \ + NPU_OP_(depthwise) \ + NPU_OP_(pool) \ + NPU_OP_(elementwise) \ + NPU_OP_(resize) \ + NPU_OP_(dma_start) \ + NPU_OP_(dma_wait) \ + NPU_OP_(kernel_wait) \ + NPU_OP_(pmu_mask) \ + NPU_OP_(branch) + +#define NPU_SET_STRUCTS \ + NPU_SET_(ifm_pad_top) \ + NPU_SET_(ifm_pad_left) \ + NPU_SET_(ifm_pad_right) \ + NPU_SET_(ifm_pad_bottom) \ + NPU_SET_(ifm_depth_m1) \ + NPU_SET_(ifm_precision) \ + NPU_SET_(ifm_upscale) \ + NPU_SET_(ifm_zero_point) \ + NPU_SET_(ifm_width0_m1) \ + NPU_SET_(ifm_height0_m1) \ + NPU_SET_(ifm_height1_m1) \ + NPU_SET_(ifm_region) \ + NPU_SET_(ifm_broadcast) \ + NPU_SET_(ofm_width_m1) \ + NPU_SET_(ofm_height_m1) \ + NPU_SET_(ofm_depth_m1) \ + NPU_SET_(ofm_precision) \ + NPU_SET_(ofm_blk_width_m1) \ + NPU_SET_(ofm_blk_height_m1) \ + NPU_SET_(ofm_blk_depth_m1) \ + NPU_SET_(ofm_zero_point) \ + NPU_SET_(ofm_width0_m1) \ + NPU_SET_(ofm_height0_m1) \ + NPU_SET_(ofm_height1_m1) \ + NPU_SET_(ofm_region) \ + NPU_SET_(kernel_width_m1) \ + NPU_SET_(kernel_height_m1) \ + NPU_SET_(kernel_stride) \ + NPU_SET_(acc_format) \ + NPU_SET_(activation) \ + NPU_SET_(activation_min) \ + NPU_SET_(activation_max) \ + NPU_SET_(weight_region) \ + NPU_SET_(scale_region) \ + NPU_SET_(weight_format) \ + NPU_SET_(blockdep) \ + NPU_SET_(resize_x_scale_n_m1) \ + NPU_SET_(resize_y_scale_n_m1) \ + NPU_SET_(resize_x_offset) \ + NPU_SET_(resize_y_offset) \ + NPU_SET_(dma0_src_region) \ + NPU_SET_(dma0_dst_region) \ + NPU_SET_(dma0_size0) \ + NPU_SET_(dma0_size1) \ + NPU_SET_(dma0_idx_region) \ + NPU_SET_(ifm2_broadcast) \ + NPU_SET_(ifm2_precision) \ + NPU_SET_(ifm2_zero_point) \ + NPU_SET_(ifm2_width0_m1) \ + NPU_SET_(ifm2_height0_m1) \ + NPU_SET_(ifm2_height1_m1) \ + NPU_SET_(ifm2_region) \ + NPU_SET_(ifm_base0) \ + NPU_SET_(ifm_base1) \ + NPU_SET_(ifm_base2) \ + NPU_SET_(ifm_base3) \ + NPU_SET_(ifm_stride_x) \ + NPU_SET_(ifm_stride_y) \ + NPU_SET_(ifm_stride_c) \ + NPU_SET_(ofm_base0) \ + NPU_SET_(ofm_base1) \ + NPU_SET_(ofm_base2) \ + NPU_SET_(ofm_base3) \ + NPU_SET_(ofm_stride_x) \ + NPU_SET_(ofm_stride_y) \ + NPU_SET_(ofm_stride_c) \ + NPU_SET_(weight_base) \ + NPU_SET_(weight_length) \ + NPU_SET_(scale_base) \ + NPU_SET_(scale_length) \ + NPU_SET_(ofm_scale) \ + NPU_SET_(ifm_scale) \ + NPU_SET_(ifm2_scale) \ + NPU_SET_(op_scalar) \ + NPU_SET_(dma0_src) \ + NPU_SET_(dma0_dst) \ + NPU_SET_(dma0_len) \ + NPU_SET_(dma0_src_stride0) \ + NPU_SET_(dma0_src_stride1) \ + NPU_SET_(dma0_dst_stride0) \ + NPU_SET_(dma0_dst_stride1) \ + NPU_SET_(dma0_idx) \ + NPU_SET_(dma0_idx_max) \ + NPU_SET_(dma0_idx_skip1) \ + NPU_SET_(ifm2_base0) \ + NPU_SET_(ifm2_base1) \ + NPU_SET_(ifm2_base2) \ + NPU_SET_(ifm2_base3) \ + NPU_SET_(ifm2_stride_x) \ + NPU_SET_(ifm2_stride_y) \ + NPU_SET_(ifm2_stride_c) \ + NPU_SET_(weight1_base) \ + NPU_SET_(weight1_length) \ + NPU_SET_(weight2_base) \ + NPU_SET_(weight2_length) \ + NPU_SET_(weight3_base) \ + NPU_SET_(weight3_length) \ + NPU_SET_(resize_x_step) \ + NPU_SET_(resize_y_step) + +#define EXPAND_ACC_FORMAT(FUNC, SEP) \ + FUNC(acc_format, I32) SEP \ + FUNC(acc_format, I48) + +#define EXPAND_ACC_INPUT(FUNC, SEP) \ + FUNC(acc_input, RESET) SEP \ + FUNC(acc_input, KEEP) SEP \ + FUNC(acc_input, IFM2) + +#define EXPAND_ACC_OUTPUT(FUNC, SEP) \ + FUNC(acc_output, ENABLE) SEP \ + FUNC(acc_output, DISABLE) + +#define EXPAND_ACTIVATION_CLIP_RANGE(FUNC, SEP) \ + FUNC(activation_clip_range, B16) SEP \ + FUNC(activation_clip_range, NONE) + +#define EXPAND_ACTIVATION_FORMAT(FUNC, SEP) \ + FUNC(activation_format, NHWC) SEP \ + FUNC(activation_format, NHCWB16) + +#define EXPAND_ACTIVATION_FUNCTION(FUNC, SEP) \ + FUNC(activation_function, LUT_NONE) SEP \ + FUNC(activation_function, LUT_U8_U8) SEP \ + FUNC(activation_function, LUT_S8_S8) SEP \ + FUNC(activation_function, LUT_S8_S16) SEP \ + FUNC(activation_function, LUT_S8_S32) SEP \ + FUNC(activation_function, LUT_S16_S16) SEP \ + FUNC(activation_function, LUT_S16_S32) SEP \ + FUNC(activation_function, LUT_TANH) SEP \ + FUNC(activation_function, LUT_SIGMOID) + +#define EXPAND_ACTIVATION_PRECISION(FUNC, SEP) \ + FUNC(activation_precision, B8) SEP \ + FUNC(activation_precision, B16) SEP \ + FUNC(activation_precision, B32) SEP \ + FUNC(activation_precision, B64) + +#define EXPAND_ACTIVATION_REVERSE(FUNC, SEP) \ + FUNC(activation_reverse, NONE) SEP \ + FUNC(activation_reverse, H) SEP \ + FUNC(activation_reverse, W) SEP \ + FUNC(activation_reverse, C) + +#define EXPAND_ACTIVATION_STORAGE(FUNC, SEP) \ + FUNC(activation_storage, TILE2X2) SEP \ + FUNC(activation_storage, TILE3X1) SEP \ + FUNC(activation_storage, CHAINED) SEP \ + FUNC(activation_storage, NONE) + +#define EXPAND_ACTIVATION_TRANSPOSE(FUNC, SEP) \ + FUNC(activation_transpose, HWC) SEP \ + FUNC(activation_transpose, WHC) SEP \ + FUNC(activation_transpose, HCW) SEP \ + FUNC(activation_transpose, WCH) SEP \ + FUNC(activation_transpose, CHW) SEP \ + FUNC(activation_transpose, CWH) + +#define EXPAND_ACTIVATION_TYPE(FUNC, SEP) \ + FUNC(activation_type, UNSIGNED) SEP \ + FUNC(activation_type, SIGNED) + +#define EXPAND_AXI_MEM_DOMAIN(FUNC, SEP) \ + FUNC(axi_mem_domain, NON_SHARABLE) SEP \ + FUNC(axi_mem_domain, INNER_SHARABLE) SEP \ + FUNC(axi_mem_domain, OUTER_SHARABLE) SEP \ + FUNC(axi_mem_domain, SYSTEM) + +#define EXPAND_AXI_MEM_ENCODING(FUNC, SEP) \ + FUNC(axi_mem_encoding, DEVICE_NON_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, DEVICE_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_NON_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, NORMAL_NON_CACHEABLE_BUFFERABLE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_NO_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_READ_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_WRITE_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_THROUGH_READ_AND_WRITE_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_NO_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_READ_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_WRITE_ALLOCATE) SEP \ + FUNC(axi_mem_encoding, WRITE_BACK_READ_AND_WRITE_ALLOCATE) + +#define EXPAND_AXI_PORT(FUNC, SEP) \ + FUNC(axi_port, SRAM) SEP \ + FUNC(axi_port, EXT) + +#define EXPAND_BRANCH_COND(FUNC, SEP) \ + FUNC(branch_cond, ALWAYS) SEP \ + FUNC(branch_cond, RF_TRUE) + +#define EXPAND_BROADCAST_MODE(FUNC, SEP) \ + FUNC(broadcast_mode, NONE) SEP \ + FUNC(broadcast_mode, H) SEP \ + FUNC(broadcast_mode, W) SEP \ + FUNC(broadcast_mode, HW) SEP \ + FUNC(broadcast_mode, C) SEP \ + FUNC(broadcast_mode, CH) SEP \ + FUNC(broadcast_mode, CW) SEP \ + FUNC(broadcast_mode, CWH) SEP \ + FUNC(broadcast_mode, SCALAR) + +#define EXPAND_CMD0_OPCODE(FUNC, SEP) \ + FUNC(cmd0_opcode, NPU_OP_STOP) SEP \ + FUNC(cmd0_opcode, NPU_OP_IRQ) SEP \ + FUNC(cmd0_opcode, NPU_OP_CONV) SEP \ + FUNC(cmd0_opcode, NPU_OP_DEPTHWISE) SEP \ + FUNC(cmd0_opcode, NPU_OP_POOL) SEP \ + FUNC(cmd0_opcode, NPU_OP_ELEMENTWISE) SEP \ + FUNC(cmd0_opcode, NPU_OP_RESIZE) SEP \ + FUNC(cmd0_opcode, NPU_OP_DMA_START) SEP \ + FUNC(cmd0_opcode, NPU_OP_DMA_WAIT) SEP \ + FUNC(cmd0_opcode, NPU_OP_KERNEL_WAIT) SEP \ + FUNC(cmd0_opcode, NPU_OP_PMU_MASK) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_TOP) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_LEFT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_RIGHT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PAD_BOTTOM) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_DEPTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_UPSCALE) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_BROADCAST) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_HEIGHT1_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_DEPTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_BLK_WIDTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_BLK_HEIGHT_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_BLK_DEPTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_HEIGHT1_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_OFM_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_KERNEL_WIDTH_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_KERNEL_HEIGHT_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_KERNEL_STRIDE) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACC_FORMAT) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACTIVATION) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MIN) SEP \ + FUNC(cmd0_opcode, NPU_SET_ACTIVATION_MAX) SEP \ + FUNC(cmd0_opcode, NPU_SET_WEIGHT_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_SCALE_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_X_SCALE_N_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_Y_SCALE_N_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_X_OFFSET) SEP \ + FUNC(cmd0_opcode, NPU_SET_RESIZE_Y_OFFSET) SEP \ + FUNC(cmd0_opcode, NPU_SET_WEIGHT_FORMAT) SEP \ + FUNC(cmd0_opcode, NPU_SET_BLOCKDEP) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_SRC_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_DST_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE0) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_SIZE1) SEP \ + FUNC(cmd0_opcode, NPU_SET_DMA0_IDX_REGION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_BROADCAST) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_PRECISION) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_ZERO_POINT) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_WIDTH0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_HEIGHT0_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_HEIGHT1_M1) SEP \ + FUNC(cmd0_opcode, NPU_SET_IFM2_REGION) + +#define EXPAND_CMD1_OPCODE(FUNC, SEP) \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE2) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_BASE3) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_Y) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_STRIDE_C) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE2) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_BASE3) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_Y) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_STRIDE_C) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_SCALE_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_SCALE_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_OFM_SCALE) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM_SCALE) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_SCALE) SEP \ + FUNC(cmd1_opcode, NPU_SET_OP_SCALAR) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_SRC) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_DST) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_LEN) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_SRC_STRIDE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_SRC_STRIDE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_DST_STRIDE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_DST_STRIDE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_IDX) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_IDX_MAX) SEP \ + FUNC(cmd1_opcode, NPU_SET_DMA0_IDX_SKIP1) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE0) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE1) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE2) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_BASE3) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_Y) SEP \ + FUNC(cmd1_opcode, NPU_SET_IFM2_STRIDE_C) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT1_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT1_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT2_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT2_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT3_BASE) SEP \ + FUNC(cmd1_opcode, NPU_SET_WEIGHT3_LENGTH) SEP \ + FUNC(cmd1_opcode, NPU_SET_RESIZE_X) SEP \ + FUNC(cmd1_opcode, NPU_SET_RESIZE_Y) SEP \ + FUNC(cmd1_opcode, NPU_OP_BRANCH) + +#define EXPAND_CMD_CTRL(FUNC, SEP) \ + FUNC(cmd_ctrl, CMD0_CTRL) SEP \ + FUNC(cmd_ctrl, CMD1_CTRL) + +#define EXPAND_CUSTOM_DMA(FUNC, SEP) \ + FUNC(custom_dma, NOT_IMPLEMENTED) SEP \ + FUNC(custom_dma, IMPLEMENTED) + +#define EXPAND_DMA_FAULT_SRC(FUNC, SEP) \ + FUNC(dma_fault_src, SRAM) SEP \ + FUNC(dma_fault_src, EXT) + +#define EXPAND_DMA_IDX_MODE(FUNC, SEP) \ + FUNC(dma_idx_mode, DISABLED) SEP \ + FUNC(dma_idx_mode, ENABLED) + +#define EXPAND_DMA_REGION_MODE(FUNC, SEP) \ + FUNC(dma_region_mode, EXTERNAL) SEP \ + FUNC(dma_region_mode, INTERNAL) + +#define EXPAND_DMA_STRIDE_MODE(FUNC, SEP) \ + FUNC(dma_stride_mode, D1) SEP \ + FUNC(dma_stride_mode, D2) SEP \ + FUNC(dma_stride_mode, D3) + +#define EXPAND_ELEMENTWISE_MODE(FUNC, SEP) \ + FUNC(elementwise_mode, MUL) SEP \ + FUNC(elementwise_mode, ADD) SEP \ + FUNC(elementwise_mode, SUB) SEP \ + FUNC(elementwise_mode, MIN) SEP \ + FUNC(elementwise_mode, MAX) SEP \ + FUNC(elementwise_mode, LRELU) SEP \ + FUNC(elementwise_mode, ABS) SEP \ + FUNC(elementwise_mode, CLZ) SEP \ + FUNC(elementwise_mode, SHR) SEP \ + FUNC(elementwise_mode, SHL) SEP \ + FUNC(elementwise_mode, LSR) SEP \ + FUNC(elementwise_mode, DIV) SEP \ + FUNC(elementwise_mode, CMP_EQ) SEP \ + FUNC(elementwise_mode, CMP_NE) SEP \ + FUNC(elementwise_mode, CMP_GE) SEP \ + FUNC(elementwise_mode, CMP_GT) SEP \ + FUNC(elementwise_mode, AND) SEP \ + FUNC(elementwise_mode, OR) SEP \ + FUNC(elementwise_mode, XOR) SEP \ + FUNC(elementwise_mode, NOT) SEP \ + FUNC(elementwise_mode, AND_NOT) + +#define EXPAND_IFM_UPSCALE_MODE(FUNC, SEP) \ + FUNC(ifm_upscale_mode, NONE) SEP \ + FUNC(ifm_upscale_mode, NEAREST) SEP \ + FUNC(ifm_upscale_mode, ZEROS) + +#define EXPAND_KERNEL_DECOMPOSITION(FUNC, SEP) \ + FUNC(kernel_decomposition, D8X8) SEP \ + FUNC(kernel_decomposition, D4X4) + +#define EXPAND_KERNEL_DILATION(FUNC, SEP) \ + FUNC(kernel_dilation, NONE) SEP \ + FUNC(kernel_dilation, X2) + +#define EXPAND_MAX_BEATS(FUNC, SEP) \ + FUNC(max_beats, B64) SEP \ + FUNC(max_beats, B128) SEP \ + FUNC(max_beats, B256) + +#define EXPAND_MICROBLOCK(FUNC, SEP) \ + FUNC(microblock, U1X1) SEP \ + FUNC(microblock, U1X2) SEP \ + FUNC(microblock, U1X4) SEP \ + FUNC(microblock, U2X2) SEP \ + FUNC(microblock, U2X4) SEP \ + FUNC(microblock, U4X4) + +#define EXPAND_OFM_SCALE_MODE(FUNC, SEP) \ + FUNC(ofm_scale_mode, PER_CHANNEL) SEP \ + FUNC(ofm_scale_mode, GLOBAL) + +#define EXPAND_PMU_AXI_CHANNEL(FUNC, SEP) \ + FUNC(pmu_axi_channel, RD_CMD) SEP \ + FUNC(pmu_axi_channel, RD_IFM) SEP \ + FUNC(pmu_axi_channel, RD_WEIGHTS) SEP \ + FUNC(pmu_axi_channel, RD_SCALE_BIAS) SEP \ + FUNC(pmu_axi_channel, RD_MEM2MEM) SEP \ + FUNC(pmu_axi_channel, RD_IFM_STREAM) SEP \ + FUNC(pmu_axi_channel, RD_MEM2MEM_IDX) SEP \ + FUNC(pmu_axi_channel, WR_OFM) SEP \ + FUNC(pmu_axi_channel, WR_MEM2MEM) + +#define EXPAND_PMU_EVENT(FUNC, SEP) \ + FUNC(pmu_event, NO_EVENT) SEP \ + FUNC(pmu_event, CYCLE) SEP \ + FUNC(pmu_event, NPU_IDLE) SEP \ + FUNC(pmu_event, CC_STALLED_ON_BLOCKDEP) SEP \ + FUNC(pmu_event, NPU_ACTIVE) SEP \ + FUNC(pmu_event, MAC_ACTIVE) SEP \ + FUNC(pmu_event, MAC_DPU_ACTIVE) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_W_OR_ACC) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_W) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_ACC) SEP \ + FUNC(pmu_event, MAC_STALLED_BY_IB) SEP \ + FUNC(pmu_event, AO_ACTIVE) SEP \ + FUNC(pmu_event, AO_STALLED_BY_BS_OR_OB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_BS) SEP \ + FUNC(pmu_event, AO_STALLED_BY_OB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_AB_OR_CB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_AB) SEP \ + FUNC(pmu_event, AO_STALLED_BY_CB) SEP \ + FUNC(pmu_event, WD_ACTIVE) SEP \ + FUNC(pmu_event, WD_STALLED) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WD_BUF) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_FC) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_TC) SEP \ + FUNC(pmu_event, WD_TRANS_WBLK) SEP \ + FUNC(pmu_event, WD_TRANS_WS_FC) SEP \ + FUNC(pmu_event, WD_TRANS_WS_TC) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC0) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC1) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC2) SEP \ + FUNC(pmu_event, WD_STALLED_BY_WS_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_ACTIVE_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_IN_SC3) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC0) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC1) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC2) SEP \ + FUNC(pmu_event, WD_PARSE_STALL_OUT_SC3) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC0) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC1) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC2) SEP \ + FUNC(pmu_event, WD_TRANS_WS_SC3) SEP \ + FUNC(pmu_event, WD_TRANS_WB0) SEP \ + FUNC(pmu_event, WD_TRANS_WB1) SEP \ + FUNC(pmu_event, WD_TRANS_WB2) SEP \ + FUNC(pmu_event, WD_TRANS_WB3) SEP \ + FUNC(pmu_event, SRAM_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, AXI_LATENCY_ANY) SEP \ + FUNC(pmu_event, AXI_LATENCY_32) SEP \ + FUNC(pmu_event, AXI_LATENCY_64) SEP \ + FUNC(pmu_event, AXI_LATENCY_128) SEP \ + FUNC(pmu_event, AXI_LATENCY_256) SEP \ + FUNC(pmu_event, AXI_LATENCY_512) SEP \ + FUNC(pmu_event, AXI_LATENCY_1024) SEP \ + FUNC(pmu_event, ECC_DMA) SEP \ + FUNC(pmu_event, ECC_MAC_IB) SEP \ + FUNC(pmu_event, ECC_MAC_AB) SEP \ + FUNC(pmu_event, ECC_AO_CB) SEP \ + FUNC(pmu_event, ECC_AO_OB) SEP \ + FUNC(pmu_event, ECC_AO_LUT) SEP \ + FUNC(pmu_event, EXT_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, EXT_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, EXT_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, EXT_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, EXT_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, EXT_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, EXT_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, EXT_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM0_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM0_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM0_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM0_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM0_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM0_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM0_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM0_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM1_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM1_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM1_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM1_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM1_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM1_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM1_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM1_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM2_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM2_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM2_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM2_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM2_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM2_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM2_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM2_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM2_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM2_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM2_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM2_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM2_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM3_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM3_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, SRAM3_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, SRAM3_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM3_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, SRAM3_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, SRAM3_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, SRAM3_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, SRAM3_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, SRAM3_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, SRAM3_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, SRAM3_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, SRAM3_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT0_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT0_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, EXT0_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, EXT0_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT0_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT0_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, EXT0_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, EXT0_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, EXT0_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT0_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, EXT0_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, EXT0_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT0_WR_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT1_RD_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT1_RD_TRANS_COMPLETED) SEP \ + FUNC(pmu_event, EXT1_RD_DATA_BEAT_RECEIVED) SEP \ + FUNC(pmu_event, EXT1_RD_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT1_WR_TRANS_ACCEPTED) SEP \ + FUNC(pmu_event, EXT1_WR_TRANS_COMPLETED_M) SEP \ + FUNC(pmu_event, EXT1_WR_TRANS_COMPLETED_S) SEP \ + FUNC(pmu_event, EXT1_WR_DATA_BEAT_WRITTEN) SEP \ + FUNC(pmu_event, EXT1_WR_TRAN_REQ_STALLED) SEP \ + FUNC(pmu_event, EXT1_WR_DATA_BEAT_STALLED) SEP \ + FUNC(pmu_event, EXT1_ENABLED_CYCLES) SEP \ + FUNC(pmu_event, EXT1_RD_STALL_LIMIT) SEP \ + FUNC(pmu_event, EXT1_WR_STALL_LIMIT) + +#define EXPAND_PMU_PORT_DISABLE(FUNC, SEP) \ + FUNC(pmu_port_disable, ENABLE) SEP \ + FUNC(pmu_port_disable, DISABLE) + +#define EXPAND_POOLING_MODE(FUNC, SEP) \ + FUNC(pooling_mode, MAX) SEP \ + FUNC(pooling_mode, AVERAGE) SEP \ + FUNC(pooling_mode, REDUCE_SUM) SEP \ + FUNC(pooling_mode, SUM) SEP \ + FUNC(pooling_mode, NONE) SEP \ + FUNC(pooling_mode, MIN) SEP \ + FUNC(pooling_mode, ARGMAX_X) SEP \ + FUNC(pooling_mode, ARGMAX_Y) + +#define EXPAND_PRIVILEGE_LEVEL(FUNC, SEP) \ + FUNC(privilege_level, USER) SEP \ + FUNC(privilege_level, PRIVILEGED) + +#define EXPAND_RAM_ID(FUNC, SEP) \ + FUNC(ram_id, LUT) SEP \ + FUNC(ram_id, IB) SEP \ + FUNC(ram_id, AB) SEP \ + FUNC(ram_id, CB) SEP \ + FUNC(ram_id, OB) + +#define EXPAND_RESIZE_MODE(FUNC, SEP) \ + FUNC(resize_mode, BILINEAR) SEP \ + FUNC(resize_mode, REPLICATE) SEP \ + FUNC(resize_mode, NEAREST) + +#define EXPAND_ROUND_MODE_IFM(FUNC, SEP) \ + FUNC(round_mode_ifm, DOUBLE_SYMMETRIC) SEP \ + FUNC(round_mode_ifm, NATURAL) + +#define EXPAND_ROUND_MODE_OFM(FUNC, SEP) \ + FUNC(round_mode_ofm, DOUBLE_SYMMETRIC) SEP \ + FUNC(round_mode_ofm, NATURAL) SEP \ + FUNC(round_mode_ofm, DOUBLE_ASYMMETRIC) SEP \ + FUNC(round_mode_ofm, SYMMETRIC) SEP \ + FUNC(round_mode_ofm, TRUNCATE_TO_ZERO) SEP \ + FUNC(round_mode_ofm, TRUNCATE_TO_LOWER) + +#define EXPAND_SECURITY_LEVEL(FUNC, SEP) \ + FUNC(security_level, SECURE) SEP \ + FUNC(security_level, NON_SECURE) + +#define EXPAND_STATE(FUNC, SEP) \ + FUNC(state, STOPPED) SEP \ + FUNC(state, RUNNING) + +#define EXPAND_WD_ACTIVE_CORE(FUNC, SEP) \ + FUNC(wd_active_core, NONE) SEP \ + FUNC(wd_active_core, STANDARD) SEP \ + FUNC(wd_active_core, FAST) SEP \ + FUNC(wd_active_core, TENSOR) + +#define EXPAND_WEIGHT_FORMAT(FUNC, SEP) \ + FUNC(weight_format, SWD) SEP \ + FUNC(weight_format, FWD) + +#define EXPAND_WEIGHT_ORDER(FUNC, SEP) \ + FUNC(weight_order, DEPTH_FIRST) SEP \ + FUNC(weight_order, PART_KERNEL_FIRST) + +#define EXPAND_WEIGHT_SPARSITY(FUNC, SEP) \ + FUNC(weight_sparsity, NONE) SEP \ + FUNC(weight_sparsity, SPARSE_2_4) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h new file mode 100644 index 0000000..9330bb1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u55.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019-2020,2022 Arm Limited. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_CONFIG_H +#define ETHOSU_CONFIG_H + +/* Set default values if not manually overriden */ + +#ifndef NPU_QCONFIG +#define NPU_QCONFIG 2 +#endif + +#ifndef NPU_REGIONCFG_0 +#define NPU_REGIONCFG_0 3 +#endif + +#ifndef NPU_REGIONCFG_1 +#define NPU_REGIONCFG_1 0 +#endif + +#ifndef NPU_REGIONCFG_2 +#define NPU_REGIONCFG_2 1 +#endif + +#ifndef NPU_REGIONCFG_3 +#define NPU_REGIONCFG_3 1 +#endif + +#ifndef NPU_REGIONCFG_4 +#define NPU_REGIONCFG_4 1 +#endif + +#ifndef NPU_REGIONCFG_5 +#define NPU_REGIONCFG_5 1 +#endif + +#ifndef NPU_REGIONCFG_6 +#define NPU_REGIONCFG_6 1 +#endif + +#ifndef NPU_REGIONCFG_7 +#define NPU_REGIONCFG_7 1 +#endif + +#ifndef AXI_LIMIT0_MAX_BEATS_BYTES +#define AXI_LIMIT0_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT0_MEM_TYPE +#define AXI_LIMIT0_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_READS +#define AXI_LIMIT0_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT0_MAX_OUTSTANDING_WRITES 16 +#endif + +#ifndef AXI_LIMIT1_MAX_BEATS_BYTES +#define AXI_LIMIT1_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT1_MEM_TYPE +#define AXI_LIMIT1_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_READS +#define AXI_LIMIT1_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT1_MAX_OUTSTANDING_WRITES 16 +#endif + +#ifndef AXI_LIMIT2_MAX_BEATS_BYTES +#define AXI_LIMIT2_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT2_MEM_TYPE +#define AXI_LIMIT2_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_READS +#define AXI_LIMIT2_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT2_MAX_OUTSTANDING_WRITES 16 +#endif + +#ifndef AXI_LIMIT3_MAX_BEATS_BYTES +#define AXI_LIMIT3_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT3_MEM_TYPE +#define AXI_LIMIT3_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_READS +#define AXI_LIMIT3_MAX_OUTSTANDING_READS 32 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT3_MAX_OUTSTANDING_WRITES 16 +#endif + +#endif /* #ifndef ETHOSU_CONFIG_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h new file mode 100644 index 0000000..b115f43 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u65.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019-2020,2022 Arm Limited. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_CONFIG_H +#define ETHOSU_CONFIG_H + +/* Set default values if not manually overriden */ + +#ifndef NPU_QCONFIG +#define NPU_QCONFIG 2 +#endif + +#ifndef NPU_REGIONCFG_0 +#define NPU_REGIONCFG_0 3 +#endif + +#ifndef NPU_REGIONCFG_1 +#define NPU_REGIONCFG_1 2 +#endif + +#ifndef NPU_REGIONCFG_2 +#define NPU_REGIONCFG_2 1 +#endif + +#ifndef NPU_REGIONCFG_3 +#define NPU_REGIONCFG_3 1 +#endif + +#ifndef NPU_REGIONCFG_4 +#define NPU_REGIONCFG_4 1 +#endif + +#ifndef NPU_REGIONCFG_5 +#define NPU_REGIONCFG_5 1 +#endif + +#ifndef NPU_REGIONCFG_6 +#define NPU_REGIONCFG_6 1 +#endif + +#ifndef NPU_REGIONCFG_7 +#define NPU_REGIONCFG_7 1 +#endif + +#ifndef AXI_LIMIT0_MAX_BEATS_BYTES +#define AXI_LIMIT0_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT0_MEM_TYPE +#define AXI_LIMIT0_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_READS +#define AXI_LIMIT0_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT0_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT0_MAX_OUTSTANDING_WRITES 32 +#endif + +#ifndef AXI_LIMIT1_MAX_BEATS_BYTES +#define AXI_LIMIT1_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT1_MEM_TYPE +#define AXI_LIMIT1_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_READS +#define AXI_LIMIT1_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT1_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT1_MAX_OUTSTANDING_WRITES 32 +#endif + +#ifndef AXI_LIMIT2_MAX_BEATS_BYTES +#define AXI_LIMIT2_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT2_MEM_TYPE +#define AXI_LIMIT2_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_READS +#define AXI_LIMIT2_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT2_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT2_MAX_OUTSTANDING_WRITES 32 +#endif + +#ifndef AXI_LIMIT3_MAX_BEATS_BYTES +#define AXI_LIMIT3_MAX_BEATS_BYTES 0x0 +#endif + +#ifndef AXI_LIMIT3_MEM_TYPE +#define AXI_LIMIT3_MEM_TYPE 0x0 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_READS +#define AXI_LIMIT3_MAX_OUTSTANDING_READS 64 +#endif + +#ifndef AXI_LIMIT3_MAX_OUTSTANDING_WRITES +#define AXI_LIMIT3_MAX_OUTSTANDING_WRITES 32 +#endif + +#endif /* #ifndef ETHOSU_CONFIG_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h new file mode 100644 index 0000000..3cc1f97 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_config_u85.h @@ -0,0 +1,112 @@ +/* + * SPDX-FileCopyrightText: Copyright 2020, 2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_CONFIG_U85_H +#define ETHOSU_CONFIG_U85_H + +/* Set default values if not manually overriden */ + +/* MAC power ramping up/down control + * NOTE: Actual number of cycles is 4*NPU_MAC_PWR_RAMP_CYCLES + */ +#ifndef NPU_MAC_PWR_RAMP_CYCLES +#define NPU_MAC_PWR_RAMP_CYCLES 0 /* Valid range 0-63, where 0 disables power ramping */ +#endif + +/* Default MEM_ATTR entries */ +#ifndef NPU_MEM_ATTR_0 +#define NPU_MEM_ATTR_0 0 /* SRAM AXI port, non_sharable, device_non_bufferable */ +#endif + +#ifndef NPU_MEM_ATTR_1 +#define NPU_MEM_ATTR_1 0 /* SRAM AXI port, non_sharable, device_non_bufferable */ +#endif + +#ifndef NPU_MEM_ATTR_2 +#define NPU_MEM_ATTR_2 (1 << 2) /* EXT AXI port, non_sharable, device_non_bufferable */ +#endif + +#ifndef NPU_MEM_ATTR_3 +#define NPU_MEM_ATTR_3 (1 << 2) /* EXT AXI port, non_sharable, device_non_bufferable */ +#endif + +/* Default MEM_ATTR index to use for command stream */ +#ifndef NPU_QCONFIG +#define NPU_QCONFIG 2 +#endif + +/* Default MEM_ATTR index to use for regions 0-7 */ +#ifndef NPU_REGIONCFG_0 +#define NPU_REGIONCFG_0 3 +#endif + +#ifndef NPU_REGIONCFG_1 +#define NPU_REGIONCFG_1 0 +#endif + +#ifndef NPU_REGIONCFG_2 +#define NPU_REGIONCFG_2 1 +#endif + +#ifndef NPU_REGIONCFG_3 +#define NPU_REGIONCFG_3 1 +#endif + +#ifndef NPU_REGIONCFG_4 +#define NPU_REGIONCFG_4 1 +#endif + +#ifndef NPU_REGIONCFG_5 +#define NPU_REGIONCFG_5 1 +#endif + +#ifndef NPU_REGIONCFG_6 +#define NPU_REGIONCFG_6 1 +#endif + +#ifndef NPU_REGIONCFG_7 +#define NPU_REGIONCFG_7 1 +#endif + +/* AXI SRAM/EXT limits + * Set defaults to max. Hardware can be configured to cap at lower values. + */ +#ifndef AXI_LIMIT_SRAM_MAX_OUTSTANDING_READ_M1 +#define AXI_LIMIT_SRAM_MAX_OUTSTANDING_READ_M1 12 +#endif + +#ifndef AXI_LIMIT_SRAM_MAX_OUTSTANDING_WRITE_M1 +#define AXI_LIMIT_SRAM_MAX_OUTSTANDING_WRITE_M1 16 +#endif + +#ifndef AXI_LIMIT_SRAM_MAX_BEATS +#define AXI_LIMIT_SRAM_MAX_BEATS 2 /* 0=64B, 1=128B, 2=256B */ +#endif + +#ifndef AXI_LIMIT_EXT_MAX_OUTSTANDING_READ_M1 +#define AXI_LIMIT_EXT_MAX_OUTSTANDING_READ_M1 64 /* Hardware max might be less */ +#endif + +#ifndef AXI_LIMIT_EXT_MAX_OUTSTANDING_WRITE_M1 +#define AXI_LIMIT_EXT_MAX_OUTSTANDING_WRITE_M1 32 +#endif + +#ifndef AXI_LIMIT_EXT_MAX_BEATS +#define AXI_LIMIT_EXT_MAX_BEATS 2 /* 0=64B, 1=128B, 2=256B */ +#endif + +#endif /* #ifndef ETHOSU_CONFIG_U85_H */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h new file mode 100644 index 0000000..3567da4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device.h @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_DEVICE_H +#define ETHOSU_DEVICE_H + +/****************************************************************************** + * Includes + ******************************************************************************/ +#include "ethosu_types.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Prototypes + ******************************************************************************/ + +/** + * Initialize the device. + */ +bool ethosu_dev_init(struct ethosu_device *dev, void *base_address, uint32_t secure_enable, uint32_t privilege_enable); + +/** + * Initialize AXI settings for device. + */ +enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev); + +/** + * Execute a given command stream on NPU. + * \param[in] cmd_stream_ptr Pointer to the command stream + * \param[in] cms_length Command stream length + * \param[in] base_addr Pointer to array of base addresses + * - 0: weight tensor + * - 1: scratch tensor + * - All input tensors + * - All output tensors + * \param[in] num_base_addr Number of base addresses. + */ +void ethosu_dev_run_command_stream(struct ethosu_device *dev, + const uint8_t *cmd_stream_ptr, + uint32_t cms_length, + const uint64_t *base_addr, + int num_base_addr); + +/** + * Print information on NPU error status + */ +void ethosu_dev_print_err_status(struct ethosu_device *dev); + +/** + * Interrupt handler on device layer + * \return true if NPU status is OK, otherwise false + */ +bool ethosu_dev_handle_interrupt(struct ethosu_device *dev); + +/** + * Get hardware information from NPU + * \param[out] hwinfo Pointer to the hardware info struct to be filled in. + */ +void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo); + +/** + * Verify that requested security state and privilege mode are active + * \return 32 bit status value + */ +bool ethosu_dev_verify_access_state(struct ethosu_device *dev); + +/** + * Performs a NPU soft reset and waits for the NPU to become ready + * \return \ref ethosu_error_codes + */ +enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev); + +/** + * Enable/disable clock and power using clock/power q interface. + * \param[in] clock_q Clock q ENABLE/DISABLE \ref clock_q_request. + * \param[in] power_q Power q ENABLE/DISABLE \ref power_q_request. + * \return \ref ethosu_error_codes + */ +enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev, + enum ethosu_clock_q_request clock_q, + enum ethosu_power_q_request power_q); + +/** + * Verifies that optimizer parameters from model are compatible with the hardware + * \param[in] cfg Config data from optimizer. + * \param[in] id Id data from optimizer. + * \return true if parameters match with hardware, false otherwise. + */ +bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in); + +#ifdef __cplusplus +} +#endif + +#endif // ETHOSU_DEVICE_H diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c new file mode 100644 index 0000000..24e8949 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u55_u65.c @@ -0,0 +1,373 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "ethosu_interface.h" + +#include "ethosu_device.h" +#include "ethosu_log.h" + +#ifdef ETHOSU55 +#include "ethosu_config_u55.h" +#else +#include "ethosu_config_u65.h" +#endif + +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define ETHOSU_PRODUCT_U55 0 +#define ETHOSU_PRODUCT_U65 1 + +#define BASEP_OFFSET 4 + +#ifdef ETHOSU65 +#define ADDRESS_BITS 40 +#else +#define ADDRESS_BITS 32 +#endif + +#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1) + +#define NPU_CMD_PWR_CLK_MASK (0xC) + +/****************************************************************************** + * Functions + ******************************************************************************/ + +uint64_t __attribute__((weak)) ethosu_address_remap(uint64_t address, int index) +{ + (void)(index); + return address; +} + +bool ethosu_dev_init(struct ethosu_device *dev, void *base_address, uint32_t secure_enable, uint32_t privilege_enable) +{ + dev->reg = (volatile struct NPU_REG *)base_address; + dev->secure = secure_enable; + dev->privileged = privilege_enable; + +#ifdef ETHOSU55 + if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U55) +#else + if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U65) +#endif + { + LOG_ERR("Failed to initialize device. Driver has not been compiled for this product"); + return false; + } + + // Make sure the NPU is in a known state + if (ethosu_dev_soft_reset(dev) != ETHOSU_SUCCESS) + { + return false; + } + + return true; +} + +enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev) +{ + struct regioncfg_r rcfg = {0}; + struct axi_limit0_r l0 = {0}; + struct axi_limit1_r l1 = {0}; + struct axi_limit2_r l2 = {0}; + struct axi_limit3_r l3 = {0}; + + dev->reg->QCONFIG.word = NPU_QCONFIG; + + rcfg.region0 = NPU_REGIONCFG_0; + rcfg.region1 = NPU_REGIONCFG_1; + rcfg.region2 = NPU_REGIONCFG_2; + rcfg.region3 = NPU_REGIONCFG_3; + rcfg.region4 = NPU_REGIONCFG_4; + rcfg.region5 = NPU_REGIONCFG_5; + rcfg.region6 = NPU_REGIONCFG_6; + rcfg.region7 = NPU_REGIONCFG_7; + dev->reg->REGIONCFG.word = rcfg.word; + + l0.max_beats = AXI_LIMIT0_MAX_BEATS_BYTES; + l0.memtype = AXI_LIMIT0_MEM_TYPE; + l0.max_outstanding_read_m1 = AXI_LIMIT0_MAX_OUTSTANDING_READS - 1; + l0.max_outstanding_write_m1 = AXI_LIMIT0_MAX_OUTSTANDING_WRITES - 1; + + l1.max_beats = AXI_LIMIT1_MAX_BEATS_BYTES; + l1.memtype = AXI_LIMIT1_MEM_TYPE; + l1.max_outstanding_read_m1 = AXI_LIMIT1_MAX_OUTSTANDING_READS - 1; + l1.max_outstanding_write_m1 = AXI_LIMIT1_MAX_OUTSTANDING_WRITES - 1; + + l2.max_beats = AXI_LIMIT2_MAX_BEATS_BYTES; + l2.memtype = AXI_LIMIT2_MEM_TYPE; + l2.max_outstanding_read_m1 = AXI_LIMIT2_MAX_OUTSTANDING_READS - 1; + l2.max_outstanding_write_m1 = AXI_LIMIT2_MAX_OUTSTANDING_WRITES - 1; + + l3.max_beats = AXI_LIMIT3_MAX_BEATS_BYTES; + l3.memtype = AXI_LIMIT3_MEM_TYPE; + l3.max_outstanding_read_m1 = AXI_LIMIT3_MAX_OUTSTANDING_READS - 1; + l3.max_outstanding_write_m1 = AXI_LIMIT3_MAX_OUTSTANDING_WRITES - 1; + + dev->reg->AXI_LIMIT0.word = l0.word; + dev->reg->AXI_LIMIT1.word = l1.word; + dev->reg->AXI_LIMIT2.word = l2.word; + dev->reg->AXI_LIMIT3.word = l3.word; + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_run_command_stream(struct ethosu_device *dev, + const uint8_t *cmd_stream_ptr, + uint32_t cms_length, + const uint64_t *base_addr, + int num_base_addr) +{ + assert(num_base_addr <= NPU_REG_BASEP_ARRLEN); + + struct cmd_r cmd; + uint64_t qbase = ethosu_address_remap((uintptr_t)cmd_stream_ptr, -1); + assert(qbase <= ADDRESS_MASK); + LOG_DEBUG("QBASE=0x%016llx, QSIZE=%" PRIu32 ", cmd_stream_ptr=%p", qbase, cms_length, cmd_stream_ptr); + + dev->reg->QBASE.word[0] = qbase & 0xffffffff; +#ifdef ETHOSU65 + dev->reg->QBASE.word[1] = qbase >> 32; +#endif + dev->reg->QSIZE.word = cms_length; + + for (int i = 0; i < num_base_addr; i++) + { + uint64_t addr = ethosu_address_remap(base_addr[i], i); + assert(addr <= ADDRESS_MASK); + LOG_DEBUG("BASEP%d=0x%016llx", i, addr); + dev->reg->BASEP[i].word[0] = addr & 0xffffffff; +#ifdef ETHOSU65 + dev->reg->BASEP[i].word[1] = addr >> 32; +#endif + } + + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.transition_to_running_state = 1; + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); +} + +void ethosu_dev_print_err_status(struct ethosu_device *dev) +{ + LOG_ERR("NPU status=0x%08" PRIx32 ", qread=%" PRIu32 ", cmd_end_reached=%u", + dev->reg->STATUS.word, + dev->reg->QREAD.word, + dev->reg->STATUS.cmd_end_reached); +} + +bool ethosu_dev_handle_interrupt(struct ethosu_device *dev) +{ + struct cmd_r cmd; + + // Clear interrupt + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.clear_irq = 1; + dev->reg->CMD.word = cmd.word; + + // If a fault has occured, the NPU needs to be reset + if (dev->reg->STATUS.bus_status || dev->reg->STATUS.cmd_parse_error || dev->reg->STATUS.wd_fault || + dev->reg->STATUS.ecc_fault || !dev->reg->STATUS.cmd_end_reached) + { + return false; + } + + return true; +} + +bool ethosu_dev_verify_access_state(struct ethosu_device *dev) +{ + if (dev->reg->PROT.active_CSL != (dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE) || + dev->reg->PROT.active_CPL != (dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER)) + { + return false; + } + return true; +} + +enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev) +{ + // Note that after a soft-reset, the NPU is unconditionally + // powered until the next CMD gets written. + + struct reset_r reset; + + reset.word = 0; + reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER; + reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE; + + // Reset and set security level + LOG_INFO("Soft reset NPU"); + dev->reg->RESET.word = reset.word; + + // Wait until reset status indicates that reset has been completed + for (int i = 0; i < 100000 && dev->reg->STATUS.reset_status != 0; i++) + { + } + + if (dev->reg->STATUS.reset_status != 0) + { + LOG_ERR("Soft reset timed out"); + return ETHOSU_GENERIC_FAILURE; + } + + // Verify that NPU has switched security state and privilege level + if (ethosu_dev_verify_access_state(dev) != true) + { + LOG_ERR("Failed to switch security state and privilege level"); + return ETHOSU_GENERIC_FAILURE; + } + + // Reinitialize AXI settings + ethosu_dev_axi_init(dev); + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo) +{ + struct config_r cfg; + struct id_r id; + + cfg.word = dev->reg->CONFIG.word; + id.word = dev->reg->ID.word; + + hwinfo->cfg.cmd_stream_version = cfg.cmd_stream_version; + hwinfo->cfg.custom_dma = cfg.custom_dma; + hwinfo->cfg.macs_per_cc = cfg.macs_per_cc; + + hwinfo->version.arch_major_rev = id.arch_major_rev; + hwinfo->version.arch_minor_rev = id.arch_minor_rev; + hwinfo->version.arch_patch_rev = id.arch_patch_rev; + hwinfo->version.product_major = id.product_major; + hwinfo->version.version_major = id.version_major; + hwinfo->version.version_minor = id.version_minor; + hwinfo->version.version_status = id.version_status; +} + +enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev, + enum ethosu_clock_q_request clock_q, + enum ethosu_power_q_request power_q) +{ + struct cmd_r cmd = {0}; + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + + if (power_q != ETHOSU_POWER_Q_UNCHANGED) + { + cmd.power_q_enable = power_q == ETHOSU_POWER_Q_ENABLE ? 1 : 0; + } + if (clock_q != ETHOSU_CLOCK_Q_UNCHANGED) + { + cmd.clock_q_enable = clock_q == ETHOSU_CLOCK_Q_ENABLE ? 1 : 0; + } + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); + + return ETHOSU_SUCCESS; +} + +bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in) +{ + struct config_r *opt_cfg = (struct config_r *)&cfg_in; + struct config_r hw_cfg; + struct id_r *opt_id = (struct id_r *)&id_in; + struct id_r hw_id; + bool ret = true; + + hw_cfg.word = dev->reg->CONFIG.word; + hw_id.word = dev->reg->ID.word; + + LOG_INFO("Optimizer config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, shram_size=%u, custom_dma=%u", + opt_cfg->product, + opt_cfg->cmd_stream_version, + opt_cfg->macs_per_cc, + opt_cfg->shram_size, + opt_cfg->custom_dma); + LOG_INFO("Optimizer config. arch version: %u.%u.%u", + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + LOG_INFO("Ethos-U config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, shram_size=%u, custom_dma=%u", + hw_cfg.product, + hw_cfg.cmd_stream_version, + hw_cfg.macs_per_cc, + hw_cfg.shram_size, + hw_cfg.custom_dma); + LOG_INFO("Ethos-U. arch version=%u.%u.%u", hw_id.arch_major_rev, hw_id.arch_minor_rev, hw_id.arch_patch_rev); + + if (opt_cfg->word != hw_cfg.word) + { + if (hw_cfg.product != opt_cfg->product) + { + LOG_ERR("NPU config mismatch. npu.product=%u, optimizer.product=%u", hw_cfg.product, opt_cfg->product); + ret = false; + } + + if (hw_cfg.macs_per_cc != opt_cfg->macs_per_cc) + { + LOG_ERR("NPU config mismatch. npu.macs_per_cc=%u, optimizer.macs_per_cc=%u", + hw_cfg.macs_per_cc, + opt_cfg->macs_per_cc); + ret = false; + } + + if (hw_cfg.cmd_stream_version != opt_cfg->cmd_stream_version) + { + LOG_ERR("NPU config mismatch. npu.cmd_stream_version=%u, optimizer.cmd_stream_version=%u", + hw_cfg.cmd_stream_version, + opt_cfg->cmd_stream_version); + ret = false; + } + + if (!hw_cfg.custom_dma && opt_cfg->custom_dma) + { + LOG_ERR("NPU config mismatch. npu.custom_dma=%u, optimizer.custom_dma=%u", + hw_cfg.custom_dma, + opt_cfg->custom_dma); + ret = false; + } + } + + if ((hw_id.arch_major_rev != opt_id->arch_major_rev) || (hw_id.arch_minor_rev < opt_id->arch_minor_rev)) + { + LOG_ERR("NPU arch mismatch. npu.arch=%u.%u.%u, optimizer.arch=%u.%u.%u", + hw_id.arch_major_rev, + hw_id.arch_minor_rev, + hw_id.arch_patch_rev, + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + ret = false; + } + + return ret; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c new file mode 100644 index 0000000..098320c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_device_u85.c @@ -0,0 +1,373 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * Includes + ******************************************************************************/ +#include "ethosu85_interface.h" + +#include "ethosu_config_u85.h" +#include "ethosu_device.h" +#include "ethosu_log.h" + +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define ETHOSU_PRODUCT_U85 2 + +#define BASEP_OFFSET 4 + +#define ADDRESS_BITS 40 + +#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1) + +#define NPU_CMD_PWR_CLK_MASK (0xC) +#define NPU_MAC_PWR_RAMP_CYCLES_MASK (0x3F) + +/****************************************************************************** + * Functions + ******************************************************************************/ + +uint64_t __attribute__((weak)) ethosu_address_remap(uint64_t address, int index) +{ + (void)(index); + return address; +} + +bool ethosu_dev_init(struct ethosu_device *dev, void *base_address, uint32_t secure_enable, uint32_t privilege_enable) +{ + dev->reg = (volatile struct NPU_REG *)base_address; + dev->secure = secure_enable; + dev->privileged = privilege_enable; + + if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U85) + { + LOG_ERR("Failed to initialize device. Driver has not been compiled for this product"); + return false; + } + + // Make sure the NPU is in a known state + if (ethosu_dev_soft_reset(dev) != ETHOSU_SUCCESS) + { + return false; + } + + return true; +} + +enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev) +{ + struct regioncfg_r rcfg = {0}; + struct axi_sram_r axi_s = {0}; + struct axi_ext_r axi_e = {0}; + + // Configure MEM_ATTR array. These are user configurable, + // and each region will be set to use one of the entries + // as its config. + dev->reg->MEM_ATTR[0].word = NPU_MEM_ATTR_0; + dev->reg->MEM_ATTR[1].word = NPU_MEM_ATTR_1; + dev->reg->MEM_ATTR[2].word = NPU_MEM_ATTR_2; + dev->reg->MEM_ATTR[3].word = NPU_MEM_ATTR_3; + + // Set MEM_ATTR entry for command stream + dev->reg->QCONFIG.word = NPU_QCONFIG; + + // Set MEM_ATTR entries to use for regions 0-7 + rcfg.region0 = NPU_REGIONCFG_0; + rcfg.region1 = NPU_REGIONCFG_1; + rcfg.region2 = NPU_REGIONCFG_2; + rcfg.region3 = NPU_REGIONCFG_3; + rcfg.region4 = NPU_REGIONCFG_4; + rcfg.region5 = NPU_REGIONCFG_5; + rcfg.region6 = NPU_REGIONCFG_6; + rcfg.region7 = NPU_REGIONCFG_7; + dev->reg->REGIONCFG.word = rcfg.word; + + // Set AXI limits on SRAM AXI interfaces + axi_s.max_outstanding_read_m1 = AXI_LIMIT_SRAM_MAX_OUTSTANDING_READ_M1 - 1; + axi_s.max_outstanding_write_m1 = AXI_LIMIT_SRAM_MAX_OUTSTANDING_WRITE_M1 - 1; + axi_s.max_beats = AXI_LIMIT_SRAM_MAX_BEATS; + dev->reg->AXI_SRAM.word = axi_s.word; + + // Set AXI limits on EXT AXI interface(s) + axi_e.max_outstanding_read_m1 = AXI_LIMIT_EXT_MAX_OUTSTANDING_READ_M1 - 1; + axi_e.max_outstanding_write_m1 = AXI_LIMIT_EXT_MAX_OUTSTANDING_WRITE_M1 - 1; + axi_e.max_beats = AXI_LIMIT_EXT_MAX_BEATS; + dev->reg->AXI_EXT.word = axi_e.word; + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_run_command_stream(struct ethosu_device *dev, + const uint8_t *cmd_stream_ptr, + uint32_t cms_length, + const uint64_t *base_addr, + int num_base_addr) +{ + assert(num_base_addr <= NPU_REG_BASEP_ARRLEN); + + struct cmd_r cmd; + uint64_t qbase = ethosu_address_remap((uintptr_t)cmd_stream_ptr, -1); + assert(qbase <= ADDRESS_MASK); + LOG_DEBUG("QBASE=0x%016llx, QSIZE=%" PRIu32 ", cmd_stream_ptr=%p", qbase, cms_length, cmd_stream_ptr); + + dev->reg->QBASE.word[0] = qbase & 0xffffffff; + dev->reg->QBASE.word[1] = qbase >> 32; + dev->reg->QSIZE.word = cms_length; + + for (int i = 0; i < num_base_addr; i++) + { + uint64_t addr = ethosu_address_remap(base_addr[i], i); + assert(addr <= ADDRESS_MASK); + LOG_DEBUG("BASEP%d=0x%016llx", i, addr); + dev->reg->BASEP[i].word[0] = addr & 0xffffffff; + dev->reg->BASEP[i].word[1] = addr >> 32; + } + + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.transition_to_running_state = 1; + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); +} + +void ethosu_dev_print_err_status(struct ethosu_device *dev) +{ + LOG_ERR("NPU status=0x%08" PRIx32 ", qread=%" PRIu32 ", cmd_end_reached=%u", + dev->reg->STATUS.word, + dev->reg->QREAD.word, + dev->reg->STATUS.cmd_end_reached); +} + +bool ethosu_dev_handle_interrupt(struct ethosu_device *dev) +{ + struct cmd_r cmd; + + // Clear interrupt + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + cmd.clear_irq = 1; + dev->reg->CMD.word = cmd.word; + + // If a fault has occured, the NPU needs to be reset + if (dev->reg->STATUS.bus_status || dev->reg->STATUS.cmd_parse_error || dev->reg->STATUS.branch_fault || + dev->reg->STATUS.ecc_fault || !dev->reg->STATUS.cmd_end_reached) + { + return false; + } + + return true; +} + +bool ethosu_dev_verify_access_state(struct ethosu_device *dev) +{ + if (dev->reg->PROT.active_CSL != (dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE) || + dev->reg->PROT.active_CPL != (dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER)) + { + return false; + } + return true; +} + +enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev) +{ + struct reset_r reset; + + reset.word = 0; + reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER; + reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE; + + // Reset and set security level + LOG_INFO("Soft reset NPU"); + dev->reg->RESET.word = reset.word; + + // Wait until reset status indicates that reset has been completed + for (int i = 0; i < 100000 && dev->reg->STATUS.reset_status != 0; i++) + { + } + + if (dev->reg->STATUS.reset_status != 0) + { + LOG_ERR("Soft reset timed out"); + return ETHOSU_GENERIC_FAILURE; + } + + // Verify that NPU has switched security state and privilege level + if (ethosu_dev_verify_access_state(dev) != true) + { + LOG_ERR("Failed to switch security state and privilege level"); + return ETHOSU_GENERIC_FAILURE; + } + + // Reinitialize AXI settings + ethosu_dev_axi_init(dev); + + // MAC power ramping up/down control + dev->reg->POWER_CTRL.word = (NPU_MAC_PWR_RAMP_CYCLES & NPU_MAC_PWR_RAMP_CYCLES_MASK); + + return ETHOSU_SUCCESS; +} + +void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo) +{ + struct config_r cfg; + struct id_r id; + + cfg.word = dev->reg->CONFIG.word; + id.word = dev->reg->ID.word; + + hwinfo->cfg.cmd_stream_version = cfg.cmd_stream_version; + hwinfo->cfg.custom_dma = cfg.custom_dma; + hwinfo->cfg.macs_per_cc = cfg.macs_per_cc; + + hwinfo->version.arch_major_rev = id.arch_major_rev; + hwinfo->version.arch_minor_rev = id.arch_minor_rev; + hwinfo->version.arch_patch_rev = id.arch_patch_rev; + hwinfo->version.product_major = id.product_major; + hwinfo->version.version_major = id.version_major; + hwinfo->version.version_minor = id.version_minor; + hwinfo->version.version_status = id.version_status; +} + +enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev, + enum ethosu_clock_q_request clock_q, + enum ethosu_power_q_request power_q) +{ + struct cmd_r cmd = {0}; + cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK; + + if (power_q != ETHOSU_POWER_Q_UNCHANGED) + { + cmd.power_q_enable = power_q == ETHOSU_POWER_Q_ENABLE ? 1 : 0; + } + if (clock_q != ETHOSU_CLOCK_Q_UNCHANGED) + { + cmd.clock_q_enable = clock_q == ETHOSU_CLOCK_Q_ENABLE ? 1 : 0; + } + + dev->reg->CMD.word = cmd.word; + LOG_DEBUG("CMD=0x%08" PRIx32, cmd.word); + + return ETHOSU_SUCCESS; +} + +bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in) +{ + struct config_r *opt_cfg = (struct config_r *)&cfg_in; + struct config_r hw_cfg; + struct id_r *opt_id = (struct id_r *)&id_in; + struct id_r hw_id; + bool ret = true; + + hw_cfg.word = dev->reg->CONFIG.word; + hw_id.word = dev->reg->ID.word; + + LOG_INFO("Optimizer config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, num_axi_ext=%u, num_axi_sram=%u, " + "custom_dma=%u", + opt_cfg->product, + opt_cfg->cmd_stream_version, + opt_cfg->macs_per_cc, + 1U << opt_cfg->num_axi_ext, + 1U << opt_cfg->num_axi_sram, + opt_cfg->custom_dma); + + LOG_INFO("Optimizer config. arch version=%u.%u.%u", + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + + LOG_INFO("Ethos-U config. product=%u, cmd_stream_version=%u, macs_per_cc=%u, num_axi_ext=%u, num_axi_sram=%u, " + "custom_dma=%u", + hw_cfg.product, + hw_cfg.cmd_stream_version, + hw_cfg.macs_per_cc, + 1U << hw_cfg.num_axi_ext, + 1U << hw_cfg.num_axi_sram, + hw_cfg.custom_dma); + + LOG_INFO("Ethos-U. arch version=%u.%u.%u", hw_id.arch_major_rev, hw_id.arch_minor_rev, hw_id.arch_patch_rev); + + if (opt_cfg->word != hw_cfg.word) + { + if (hw_cfg.product != opt_cfg->product) + { + LOG_ERR("NPU config mismatch. npu.product=%u, optimizer.product=%u", hw_cfg.product, opt_cfg->product); + ret = false; + } + + if (hw_cfg.macs_per_cc != opt_cfg->macs_per_cc) + { + LOG_ERR("NPU config mismatch. npu.macs_per_cc=%u, optimizer.macs_per_cc=%u", + hw_cfg.macs_per_cc, + opt_cfg->macs_per_cc); + ret = false; + } + + if (hw_cfg.num_axi_ext != opt_cfg->num_axi_ext) + { + LOG_ERR("NPU config mismatch. npu.num_axi_ext=%u, optimizer.num_axi_ext=%u", + 1U << hw_cfg.num_axi_ext, + 1U << opt_cfg->num_axi_ext); + ret = false; + } + + if (hw_cfg.num_axi_sram != opt_cfg->num_axi_sram) + { + LOG_ERR("NPU config mismatch. npu.num_axi_sram=%u, optimizer.num_axi_sram=%u", + 1U << hw_cfg.num_axi_sram, + 1U << opt_cfg->num_axi_sram); + ret = false; + } + + if (hw_cfg.cmd_stream_version != opt_cfg->cmd_stream_version) + { + LOG_ERR("NPU config mismatch. npu.cmd_stream_version=%u, optimizer.cmd_stream_version=%u", + hw_cfg.cmd_stream_version, + opt_cfg->cmd_stream_version); + ret = false; + } + + if (!hw_cfg.custom_dma && opt_cfg->custom_dma) + { + LOG_ERR("NPU config mismatch. npu.custom_dma=%u, optimizer.custom_dma=%u", + hw_cfg.custom_dma, + opt_cfg->custom_dma); + ret = false; + } + } + + if ((hw_id.arch_major_rev != opt_id->arch_major_rev) || (hw_id.arch_minor_rev < opt_id->arch_minor_rev)) + { + LOG_ERR("NPU arch mismatch. npu.arch=%u.%u.%u, optimizer.arch=%u.%u.%u", + hw_id.arch_major_rev, + hw_id.arch_minor_rev, + hw_id.arch_patch_rev, + opt_id->arch_major_rev, + opt_id->arch_minor_rev, + opt_id->arch_patch_rev); + ret = false; + } + + return ret; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c new file mode 100644 index 0000000..3d0c95f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_driver.c @@ -0,0 +1,808 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "ethosu_driver.h" +#include "ethosu_device.h" +#include "ethosu_log.h" + +#if defined(ETHOSU55) +#include "ethosu_config_u55.h" +#elif defined(ETHOSU65) +#include "ethosu_config_u65.h" +#elif defined(ETHOSU85) +#include "ethosu_config_u85.h" +#else +#error Missing device type macro +#endif + +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +#define UNUSED(x) ((void)x) + +#define BYTES_IN_32_BITS 4 +#define MASK_16_BYTE_ALIGN (0xF) +#define OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD 2 +#define DRIVER_ACTION_LENGTH_32_BIT_WORD 1 +#define ETHOSU_FOURCC ('1' << 24 | 'P' << 16 | 'O' << 8 | 'C') // "Custom Operator Payload 1" + +#define SCRATCH_BASE_ADDR_INDEX 1 +#define FAST_MEMORY_BASE_ADDR_INDEX 2 + +/****************************************************************************** + * Types + ******************************************************************************/ + +// Driver actions +enum DRIVER_ACTION_e +{ + RESERVED = 0, + OPTIMIZER_CONFIG = 1, + COMMAND_STREAM = 2, + NOP = 5, +}; + +// Custom operator payload data struct +struct cop_data_s +{ + union + { + // Driver action data + struct + { + uint8_t driver_action_command; // (valid values in DRIVER_ACTION_e) + uint8_t reserved; + + // Driver action data + union + { + // DA_CMD_OPT_CFG + struct + { + uint16_t rel_nbr : 4; + uint16_t patch_nbr : 4; + uint16_t opt_cfg_reserved : 8; + }; + + // DA_CMD_CMSTRM + struct + { + uint16_t length; + }; + + uint16_t driver_action_data; + }; + }; + + uint32_t word; + }; +}; + +// optimizer config struct +struct opt_cfg_s +{ + struct cop_data_s da_data; + uint32_t cfg; + uint32_t id; +}; + +/****************************************************************************** + * Variables + ******************************************************************************/ + +// Registered drivers linked list HEAD +static struct ethosu_driver *registered_drivers = NULL; + +/****************************************************************************** + * Weak functions - Cache + * + * Default NOP operations. Override if available on the targeted device. + ******************************************************************************/ + +/* + * Flush/clean the data cache by address and size. Passing NULL as p argument + * expects the whole cache to be flushed. + */ +void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes) +{ + UNUSED(p); + UNUSED(bytes); +} + +/* + * Invalidate the data cache by address and size. Passing NULL as p argument + * expects the whole cache to be invalidated. + */ +void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes) +{ + UNUSED(p); + UNUSED(bytes); +} + +/****************************************************************************** + * Weak functions - Semaphore/Mutex for multi NPU + * + * Following section handles the minimal sempahore and mutex implementation in + * case of baremetal applications. Weak symbols will be overridden by RTOS + * definitions and implement true thread-safety (in application layer). + ******************************************************************************/ + +struct ethosu_semaphore_t +{ + uint8_t count; +}; + +static void *ethosu_mutex; +static void *ethosu_semaphore; + +void *__attribute__((weak)) ethosu_mutex_create(void) +{ + static uint8_t mutex_placeholder; + return &mutex_placeholder; +} + +void __attribute__((weak)) ethosu_mutex_destroy(void *mutex) +{ + UNUSED(mutex); +} + +int __attribute__((weak)) ethosu_mutex_lock(void *mutex) +{ + UNUSED(mutex); + return 0; +} + +int __attribute__((weak)) ethosu_mutex_unlock(void *mutex) +{ + UNUSED(mutex); + return 0; +} + +// Baremetal implementation of creating a semaphore +void *__attribute__((weak)) ethosu_semaphore_create(void) +{ + struct ethosu_semaphore_t *sem = malloc(sizeof(*sem)); + if (sem != NULL) + { + sem->count = 0; + } + return sem; +} + +void __attribute__((weak)) ethosu_semaphore_destroy(void *sem) +{ + free((struct ethosu_semaphore_t *)sem); +} + +// Baremetal simulation of waiting/sleeping for and then taking a semaphore using intrisics +int __attribute__((weak)) ethosu_semaphore_take(void *sem, uint64_t timeout) +{ + UNUSED(timeout); + // Baremetal pseudo-example on how to trigger a timeout: + // if (timeout != ETHOSU_SEMAPHORE_WAIT_FOREVER) { + // setup_a_timer_to_call_SEV_after_time(timeout); + // } + struct ethosu_semaphore_t *s = sem; + while (s->count == 0) + { + __WFE(); + // Baremetal pseudo-example check if timeout triggered: + // if (SEV_timer_triggered()) { + // return -1; + // } + } + s->count--; + return 0; +} + +// Baremetal simulation of giving a semaphore and waking up processes using intrinsics +int __attribute__((weak)) ethosu_semaphore_give(void *sem) +{ + struct ethosu_semaphore_t *s = sem; + s->count++; + __SEV(); + return 0; +} + +/****************************************************************************** + * Weak functions - Inference begin/end callbacks + ******************************************************************************/ + +void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg) +{ + UNUSED(user_arg); + UNUSED(drv); +} + +void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, void *user_arg) +{ + UNUSED(user_arg); + UNUSED(drv); +} + +/****************************************************************************** + * Static functions + ******************************************************************************/ +static void ethosu_register_driver(struct ethosu_driver *drv) +{ + ethosu_mutex_lock(ethosu_mutex); + drv->next = registered_drivers; + registered_drivers = drv; + ethosu_mutex_unlock(ethosu_mutex); + + ethosu_semaphore_give(ethosu_semaphore); + + LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%p)", drv, drv->dev.reg); +} + +static int ethosu_deregister_driver(struct ethosu_driver *drv) +{ + struct ethosu_driver *curr; + struct ethosu_driver **prev; + + ethosu_mutex_lock(ethosu_mutex); + curr = registered_drivers; + prev = ®istered_drivers; + + while (curr != NULL) + { + if (curr == drv) + { + *prev = curr->next; + LOG_INFO("NPU driver handle %p deregistered.", drv); + ethosu_semaphore_take(ethosu_semaphore, ETHOSU_SEMAPHORE_WAIT_FOREVER); + break; + } + + prev = &curr->next; + curr = curr->next; + } + + ethosu_mutex_unlock(ethosu_mutex); + + if (curr == NULL) + { + LOG_ERR("No NPU driver handle registered at address %p.", drv); + return -1; + } + + return 0; +} + +static void ethosu_reset_job(struct ethosu_driver *drv) +{ + memset(&drv->job, 0, sizeof(struct ethosu_job)); +} + +static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s const *opt_cfg_p) +{ + LOG_INFO("Optimizer release nbr: %u patch: %u", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr); + + if (ethosu_dev_verify_optimizer_config(&drv->dev, opt_cfg_p->cfg, opt_cfg_p->id) != true) + { + return -1; + } + + return 0; +} + +static int handle_command_stream(struct ethosu_driver *drv, const uint8_t *cmd_stream, const int cms_length) +{ + uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS; + + LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length); + + if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN)) + { + LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream); + return -1; + } + + // Verify minimum 16 byte alignment for base address' + for (int i = 0; i < drv->job.num_base_addr; i++) + { + if (0 != (drv->job.base_addr[i] & MASK_16_BYTE_ALIGN)) + { + LOG_ERR("Base addr %d: 0x%" PRIx64 "not aligned to 16 bytes", i, drv->job.base_addr[i]); + return -1; + } + } + + // DEPRECATION WARNING: + // It is advised against letting the driver handle flushing/cleaning of the cache, as this will + // be done for every invokation. It is up to the application code to ensure cache coherency + // before invoking an inference. + // + // The cache flush call below will flush/clean every base pointer marked in the flush mask. + // Typically only the scratch tensor contains RW data shared between the CPU and NPU, and needs + // to be flushed/cleaned before invoking an inference. + // + // It is recommended to not implement/override the default empty ethosu_flush_dcache() weak + // function. + // + // NOTE: It is required that any base pointer marked for cache flush/clean is aligned to the + // cache line size. + + // Flush/clean the cache for base pointers marked in the mask + for (int i = 0; i < drv->job.num_base_addr; i++) + { + if (drv->basep_flush_mask & (1 << i)) + { + ethosu_flush_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]); + } + } + + // Request power gating disabled during inference run + if (ethosu_request_power(drv)) + { + LOG_ERR("Failed to request power"); + return -1; + } + + drv->job.state = ETHOSU_JOB_RUNNING; + + // Inference begin callback + ethosu_inference_begin(drv, drv->job.user_arg); + + // Execute the command stream + ethosu_dev_run_command_stream(&drv->dev, cmd_stream, cms_bytes, drv->job.base_addr, drv->job.num_base_addr); + + return 0; +} + +/****************************************************************************** + * Weak functions - Interrupt handler + ******************************************************************************/ +void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv) +{ + // Prevent race condition where interrupt triggered after a timeout waiting + // for semaphore, but before NPU is reset. + if (drv->job.result == ETHOSU_JOB_RESULT_TIMEOUT) + { + return; + } + + drv->job.state = ETHOSU_JOB_DONE; + drv->job.result = ethosu_dev_handle_interrupt(&drv->dev) ? ETHOSU_JOB_RESULT_OK : ETHOSU_JOB_RESULT_ERROR; + ethosu_semaphore_give(drv->semaphore); +} + +/****************************************************************************** + * Functions API + ******************************************************************************/ + +void ethosu_set_basep_cache_mask(struct ethosu_driver *drv, uint8_t flush_mask, uint8_t invalidate_mask) +{ + drv->basep_flush_mask = flush_mask; + drv->basep_invalidate_mask = invalidate_mask; +} + +int ethosu_init(struct ethosu_driver *drv, + void *const base_address, + const void *fast_memory, + const size_t fast_memory_size, + uint32_t secure_enable, + uint32_t privilege_enable) +{ + LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32 + ", privileged=%" PRIu32, + base_address, + fast_memory, + fast_memory_size, + secure_enable, + privilege_enable); + + if (!ethosu_mutex) + { + ethosu_mutex = ethosu_mutex_create(); + if (!ethosu_mutex) + { + LOG_ERR("Failed to create global driver mutex"); + return -1; + } + } + + if (!ethosu_semaphore) + { + ethosu_semaphore = ethosu_semaphore_create(); + if (!ethosu_semaphore) + { + LOG_ERR("Failed to create global driver semaphore"); + return -1; + } + } + + drv->fast_memory = (uintptr_t)fast_memory; + drv->fast_memory_size = fast_memory_size; + drv->power_request_counter = 0; + + // Set default cache flush/clean and invalidate base pointer masks to invalidate the scratch + // base pointer where Vela for TFLM is placing the scratch buffer (tensor arena) + ethosu_set_basep_cache_mask(drv, (1 << SCRATCH_BASE_ADDR_INDEX), (1 << SCRATCH_BASE_ADDR_INDEX)); + + // Initialize the device and set requested security state and privilege mode + if (!ethosu_dev_init(&drv->dev, base_address, secure_enable, privilege_enable)) + { + LOG_ERR("Failed to initialize Ethos-U device"); + return -1; + } + + drv->semaphore = ethosu_semaphore_create(); + if (!drv->semaphore) + { + LOG_ERR("Failed to create driver semaphore"); + return -1; + } + + ethosu_reset_job(drv); + ethosu_register_driver(drv); + + return 0; +} + +void ethosu_deinit(struct ethosu_driver *drv) +{ + ethosu_deregister_driver(drv); + ethosu_semaphore_destroy(drv->semaphore); +} + +int ethosu_soft_reset(struct ethosu_driver *drv) +{ + // Soft reset the NPU + if (ethosu_dev_soft_reset(&drv->dev) != ETHOSU_SUCCESS) + { + LOG_ERR("Failed to soft-reset NPU"); + return -1; + } + + // Update power and clock gating after the soft reset + ethosu_dev_set_clock_and_power(&drv->dev, + drv->power_request_counter > 0 ? ETHOSU_CLOCK_Q_DISABLE : ETHOSU_CLOCK_Q_ENABLE, + drv->power_request_counter > 0 ? ETHOSU_POWER_Q_DISABLE : ETHOSU_POWER_Q_ENABLE); + + return 0; +} + +int ethosu_request_power(struct ethosu_driver *drv) +{ + // Check if this is the first power request, increase counter + if (drv->power_request_counter++ == 0) + { + // Always reset to a known state. Changes to requested + // security state/privilege mode if necessary. + if (ethosu_soft_reset(drv)) + { + LOG_ERR("Failed to request power for Ethos-U"); + drv->power_request_counter--; + return -1; + } + } + return 0; +} + +void ethosu_release_power(struct ethosu_driver *drv) +{ + if (drv->power_request_counter == 0) + { + LOG_WARN("No power request left to release, reference counter is 0"); + } + else + { + // Decrement ref counter and enable power gating if no requests remain + if (--drv->power_request_counter == 0) + { + ethosu_dev_set_clock_and_power(&drv->dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE); + } + } +} + +void ethosu_get_driver_version(struct ethosu_driver_version *ver) +{ + assert(ver != NULL); + ver->major = ETHOSU_DRIVER_VERSION_MAJOR; + ver->minor = ETHOSU_DRIVER_VERSION_MINOR; + ver->patch = ETHOSU_DRIVER_VERSION_PATCH; +} + +void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw) +{ + assert(hw != NULL); + ethosu_dev_get_hw_info(&drv->dev, hw); +} + +int ethosu_wait(struct ethosu_driver *drv, bool block) +{ + int ret = 0; + + switch (drv->job.state) + { + case ETHOSU_JOB_IDLE: + LOG_ERR("Inference job not running..."); + ret = -2; + break; + case ETHOSU_JOB_RUNNING: + if (!block) + { + // Inference still running, do not block + ret = 1; + break; + } + // fall through + case ETHOSU_JOB_DONE: + // Invalidate cache for base pointers marked to be invalidated, typically the + // scratch tensor base pointer containing the tensor arena. + // NOTE: Requires the base pointers to be cache line size aligned. + for (int i = 0; i < drv->job.num_base_addr; i++) + { + if (drv->basep_invalidate_mask & (1 << i)) + { + ethosu_invalidate_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]); + } + } + + // Wait for interrupt in blocking mode. In non-blocking mode + // the interrupt has already triggered + ret = ethosu_semaphore_take(drv->semaphore, ETHOSU_SEMAPHORE_WAIT_INFERENCE); + if (ret < 0) + { + drv->job.result = ETHOSU_JOB_RESULT_TIMEOUT; + + // There's a race where the NPU interrupt can have fired between semaphore + // timing out and setting the result above (checked in interrupt handler). + // By checking if the job state has been changed (only set to DONE by interrupt + // handler), we know if the interrupt handler has run, if so decrement the + // semaphore count by one (given in interrupt handler). + if (drv->job.state == ETHOSU_JOB_DONE) + { + drv->job.result = ETHOSU_JOB_RESULT_TIMEOUT; // Reset back to timeout + ethosu_semaphore_take(drv->semaphore, ETHOSU_SEMAPHORE_WAIT_INFERENCE); + } + } + + // Inference done callback - always called even in case of timeout + ethosu_inference_end(drv, drv->job.user_arg); + + // Release power gating disabled requirement + ethosu_release_power(drv); + + // Check NPU and interrupt status + if (drv->job.result) + { + if (drv->job.result == ETHOSU_JOB_RESULT_ERROR) + { + LOG_ERR("NPU error(s) occured during inference."); + ethosu_dev_print_err_status(&drv->dev); + } + else + { + LOG_ERR("NPU inference timed out."); + } + + // Reset the NPU + (void)ethosu_soft_reset(drv); + + ret = -1; + } + else + { + LOG_DEBUG("Inference finished successfully..."); + ret = 0; + } + + // Reset internal job (state resets to IDLE) + ethosu_reset_job(drv); + break; + + default: + LOG_ERR("Unexpected job state"); + ethosu_reset_job(drv); + ret = -1; + break; + } + + // Return inference job status + return ret; +} + +int ethosu_invoke_async(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg) +{ + assert(custom_data_ptr != NULL); + assert(base_addr != NULL); + assert(base_addr_size != NULL); + + const struct cop_data_s *data_ptr = custom_data_ptr; + const struct cop_data_s *data_end = (struct cop_data_s *)((ptrdiff_t)custom_data_ptr + custom_data_size); + + // Make sure an inference is not already running + if (drv->job.state != ETHOSU_JOB_IDLE) + { + LOG_ERR("Inference already running, or waiting to be cleared..."); + return -1; + } + + drv->job.state = ETHOSU_JOB_IDLE; + drv->job.custom_data_ptr = custom_data_ptr; + drv->job.custom_data_size = custom_data_size; + drv->job.base_addr = base_addr; + drv->job.base_addr_size = base_addr_size; + drv->job.num_base_addr = num_base_addr; + drv->job.user_arg = user_arg; + + // First word in custom_data_ptr should contain "Custom Operator Payload 1" + if (data_ptr->word != ETHOSU_FOURCC) + { + LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC); + goto err; + } + + // Custom data length must be a multiple of 32 bits + if ((custom_data_size % BYTES_IN_32_BITS) != 0) + { + LOG_ERR("custom_data_size=0x%x not a multiple of 4", (unsigned)custom_data_size); + goto err; + } + + data_ptr++; + + // Adjust base address to fast memory area + if (drv->fast_memory != 0 && num_base_addr > FAST_MEMORY_BASE_ADDR_INDEX) + { + if (base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size) + { + LOG_ERR("Fast memory area too small. fast_memory_size=%zu, base_addr_size=%zu", + drv->fast_memory_size, + base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]); + goto err; + } + + base_addr[FAST_MEMORY_BASE_ADDR_INDEX] = drv->fast_memory; + } + + // Parse Custom Operator Payload data + while (data_ptr < data_end) + { + switch (data_ptr->driver_action_command) + { + case OPTIMIZER_CONFIG: + LOG_DEBUG("OPTIMIZER_CONFIG"); + struct opt_cfg_s const *opt_cfg_p = (const struct opt_cfg_s *)data_ptr; + + if (handle_optimizer_config(drv, opt_cfg_p) < 0) + { + goto err; + } + data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD; + break; + case COMMAND_STREAM: + // Vela only supports putting one COMMAND_STREAM per op + LOG_DEBUG("COMMAND_STREAM"); + const uint8_t *command_stream = (const uint8_t *)(data_ptr + 1); + int cms_length = (data_ptr->reserved << 16) | data_ptr->length; + + if (handle_command_stream(drv, command_stream, cms_length) < 0) + { + goto err; + } + data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length; + break; + case NOP: + LOG_DEBUG("NOP"); + data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD; + break; + default: + LOG_ERR("UNSUPPORTED driver_action_command: %u", data_ptr->driver_action_command); + goto err; + break; + } + } + + return 0; +err: + LOG_ERR("Failed to invoke inference."); + ethosu_reset_job(drv); + return -1; +} + +int ethosu_invoke_v3(struct ethosu_driver *drv, + const void *custom_data_ptr, + const int custom_data_size, + uint64_t *const base_addr, + const size_t *base_addr_size, + const int num_base_addr, + void *user_arg) +{ + if (ethosu_invoke_async( + drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr, user_arg) < 0) + { + return -1; + } + + return ethosu_wait(drv, true); +} + +struct ethosu_driver *ethosu_reserve_driver(void) +{ + struct ethosu_driver *drv = NULL; + + LOG_INFO("Acquiring NPU driver handle"); + ethosu_semaphore_take(ethosu_semaphore, ETHOSU_SEMAPHORE_WAIT_FOREVER); // This is meant to block until available + + ethosu_mutex_lock(ethosu_mutex); + drv = registered_drivers; + + while (drv != NULL) + { + if (!drv->reserved) + { + drv->reserved = true; + LOG_DEBUG("NPU driver handle %p reserved", drv); + break; + } + drv = drv->next; + } + ethosu_mutex_unlock(ethosu_mutex); + + if (!drv) + { + LOG_ERR("No NPU driver handle available, but semaphore taken"); + } + + return drv; +} + +void ethosu_release_driver(struct ethosu_driver *drv) +{ + ethosu_mutex_lock(ethosu_mutex); + if (drv != NULL && drv->reserved) + { + if (drv->job.state == ETHOSU_JOB_RUNNING || drv->job.state == ETHOSU_JOB_DONE) + { + // Give the inference one shot to complete or force kill the job + if (ethosu_wait(drv, false) == 1) + { + // Still running, soft reset the NPU and reset driver + drv->power_request_counter = 0; + ethosu_soft_reset(drv); + ethosu_reset_job(drv); + } + } + + drv->reserved = false; + LOG_DEBUG("NPU driver handle %p released", drv); + ethosu_semaphore_give(ethosu_semaphore); + } + ethosu_mutex_unlock(ethosu_mutex); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h new file mode 100644 index 0000000..2409cb4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_interface.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2021 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// clang-format off +#ifndef ETHOSU_INTERFACE_WRAPPER_ +#define ETHOSU_INTERFACE_WRAPPER_ + +#define xstr(a) str(a) +#define str(a) #a + +#define catm(a, b) catm_(a, b) +#define catm_(a, b) a##b + +#define ETHOSU_INTERFACE_FILE xstr(catm(ethos, ETHOSU_ARCH)_interface.h) + +#include ETHOSU_INTERFACE_FILE + +#endif // ETHOSU_INTERFACE_WRAPPER_ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h new file mode 100644 index 0000000..13f7726 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_log.h @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: Copyright 2021-2023 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ETHOSU_LOG_H +#define ETHOSU_LOG_H + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include +#include + +/****************************************************************************** + * Defines + ******************************************************************************/ + +// Log severity levels +#define ETHOSU_LOG_ERR 0 +#define ETHOSU_LOG_WARN 1 +#define ETHOSU_LOG_INFO 2 +#define ETHOSU_LOG_DEBUG 3 + +// Define default log severity +#ifndef ETHOSU_LOG_SEVERITY +#define ETHOSU_LOG_SEVERITY ETHOSU_LOG_WARN +#endif + +// Logs enabled by default +#ifndef ETHOSU_LOG_ENABLE +#define ETHOSU_LOG_ENABLE 1 +#endif + +#if ETHOSU_LOG_ENABLE +#define LOG_COMMON(s, f, ...) (void)fprintf(s, f, ##__VA_ARGS__) +#else +#define LOG_COMMON(s, f, ...) +#endif + +// Log formatting +#define LOG(f, ...) LOG_COMMON(stdout, f, ##__VA__ARGS__) + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_ERR +#define LOG_ERR(f, ...) \ + LOG_COMMON(stderr, "E: " f " (%s:%d)\n", ##__VA_ARGS__, strrchr("/" __FILE__, '/') + 1, __LINE__) +#else +#define LOG_ERR(f, ...) +#endif + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_WARN +#define LOG_WARN(f, ...) LOG_COMMON(stdout, "W: " f "\n", ##__VA_ARGS__) +#else +#define LOG_WARN(f, ...) +#endif + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_INFO +#define LOG_INFO(f, ...) LOG_COMMON(stdout, "I: " f "\n", ##__VA_ARGS__) +#else +#define LOG_INFO(f, ...) +#endif + +#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_DEBUG +#define LOG_DEBUG(f, ...) LOG_COMMON(stdout, "D: %s(): " f "\n", __FUNCTION__, ##__VA_ARGS__) +#else +#define LOG_DEBUG(f, ...) +#endif + +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c new file mode 100644 index 0000000..2681c0e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/src/ethosu_pmu.c @@ -0,0 +1,316 @@ +/* + * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * Includes + *****************************************************************************/ + +#include "ethosu_device.h" +#include "ethosu_driver.h" +#include "ethosu_interface.h" +#include "ethosu_log.h" +#include "pmu_ethosu.h" + +#include +#include +#include + +/***************************************************************************** + * Defines + *****************************************************************************/ + +#define MASK_0_31_BITS (0xFFFFFFFF) +#define MASK_32_47_BITS (0xFFFF00000000) + +#define COMMA , +#define SEMICOLON ; + +#define EVTYPE(A, name) \ + case PMU_EVENT_##name: \ + return ETHOSU_PMU_##name + +#define EVID(A, name) (PMU_EVENT_##name) + +/***************************************************************************** + * Variables + *****************************************************************************/ + +static const enum pmu_event eventbyid[] = {EXPAND_PMU_EVENT(EVID, COMMA)}; + +/***************************************************************************** + * Static functions + *****************************************************************************/ + +static enum ethosu_pmu_event_type pmu_event_type(uint32_t id) +{ + switch (id) + { + EXPAND_PMU_EVENT(EVTYPE, SEMICOLON); + default: + LOG_ERR("Unknown PMU event id: 0x%" PRIx32, id); + } + + return ETHOSU_PMU_SENTINEL; +} + +static uint32_t pmu_event_value(enum ethosu_pmu_event_type event) +{ + int a = event; + if ((a < ETHOSU_PMU_SENTINEL) && (a >= ETHOSU_PMU_NO_EVENT)) + { + return eventbyid[event]; + } + + return UINT32_MAX; +} + +/***************************************************************************** + * Functions + *****************************************************************************/ + +void ETHOSU_PMU_Enable(struct ethosu_driver *drv) +{ + LOG_DEBUG("Enable PMU"); + struct pmcr_r pmcr = {0}; + pmcr.cnt_en = 1; + ethosu_request_power(drv); + drv->dev.reg->PMCR.word = pmcr.word; +} + +void ETHOSU_PMU_Disable(struct ethosu_driver *drv) +{ + LOG_DEBUG("Disable PMU"); + drv->dev.reg->PMCR.word = 0; + ethosu_release_power(drv); +} + +uint32_t ETHOSU_PMU_Get_NumEventCounters(void) +{ + return NPU_REG_PMEVCNTR_ARRLEN; +} + +void ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + uint32_t val = pmu_event_value(type); + if (val == UINT32_MAX) + { + LOG_ERR("Invalid ethosu_pmu_event_type: %d", type); + return; + } + + LOG_DEBUG("num=%" PRIu32 ", type=%d, val=%" PRIu32, num, type, val); + drv->dev.reg->PMEVTYPER[num].word = val; +} + +enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(struct ethosu_driver *drv, uint32_t num) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + uint32_t val = drv->dev.reg->PMEVTYPER[num].word; + enum ethosu_pmu_event_type type = pmu_event_type(val); + LOG_DEBUG("num=%" PRIu32 ", type=%d, val=%" PRIu32, num, type, val); + return type; +} + +void ETHOSU_PMU_CYCCNT_Reset(struct ethosu_driver *drv) +{ + LOG_DEBUG("Reset PMU cycle counter"); + struct pmcr_r pmcr; + pmcr.word = drv->dev.reg->PMCR.word; + pmcr.cycle_cnt_rst = 1; + drv->dev.reg->PMCR.word = pmcr.word; +} + +void ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver *drv) +{ + LOG_DEBUG("Reset all events"); + struct pmcr_r pmcr; + pmcr.word = drv->dev.reg->PMCR.word; + pmcr.event_cnt_rst = 1; + drv->dev.reg->PMCR.word = pmcr.word; +} + +void ETHOSU_PMU_CNTR_Enable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMCNTENSET.word = mask; +} + +void ETHOSU_PMU_CNTR_Disable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMCNTENCLR.word = mask; +} + +uint32_t ETHOSU_PMU_CNTR_Status(struct ethosu_driver *drv) +{ + uint32_t pmcntenset = drv->dev.reg->PMCNTENSET.word; + LOG_DEBUG("mask=0x%08" PRIx32, pmcntenset); + return pmcntenset; +} + +uint64_t ETHOSU_PMU_Get_CCNTR(struct ethosu_driver *drv) +{ + uint32_t val_lo = drv->dev.reg->PMCCNTR.CYCLE_CNT_LO; + uint32_t val_hi = drv->dev.reg->PMCCNTR.CYCLE_CNT_HI; + uint64_t val = ((uint64_t)val_hi << 32) | val_lo; + + LOG_DEBUG("val=%" PRIu64, val); + return val; +} + +void ETHOSU_PMU_Set_CCNTR(struct ethosu_driver *drv, uint64_t val) +{ + uint32_t active = ETHOSU_PMU_CNTR_Status(drv) & ETHOSU_PMU_CCNT_Msk; + + LOG_DEBUG("val=%llu", val); + + if (active) + { + ETHOSU_PMU_CNTR_Disable(drv, ETHOSU_PMU_CCNT_Msk); + } + + drv->dev.reg->PMCCNTR.CYCLE_CNT_LO = val & MASK_0_31_BITS; + drv->dev.reg->PMCCNTR.CYCLE_CNT_HI = (val & MASK_32_47_BITS) >> 32; + + if (active) + { + ETHOSU_PMU_CNTR_Enable(drv, ETHOSU_PMU_CCNT_Msk); + } +} + +uint32_t ETHOSU_PMU_Get_EVCNTR(struct ethosu_driver *drv, uint32_t num) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + uint32_t val = drv->dev.reg->PMEVCNTR[num].word; + LOG_DEBUG("num=%" PRIu32 ", val=%" PRIu32, num, val); + + return val; +} + +void ETHOSU_PMU_Set_EVCNTR(struct ethosu_driver *drv, uint32_t num, uint32_t val) +{ + assert(num < ETHOSU_PMU_NCOUNTERS); + LOG_DEBUG("num=%" PRIu32 ", val=%" PRIu32, num, val); + drv->dev.reg->PMEVCNTR[num].word = val; +} + +uint32_t ETHOSU_PMU_Get_CNTR_OVS(struct ethosu_driver *drv) +{ + LOG_DEBUG(""); + return drv->dev.reg->PMOVSSET.word; +} + +void ETHOSU_PMU_Set_CNTR_OVS(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG(""); + drv->dev.reg->PMOVSCLR.word = mask; +} + +void ETHOSU_PMU_Set_CNTR_IRQ_Enable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMINTSET.word = mask; +} + +void ETHOSU_PMU_Set_CNTR_IRQ_Disable(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG("mask=0x%08" PRIx32, mask); + drv->dev.reg->PMINTCLR.word = mask; +} + +uint32_t ETHOSU_PMU_Get_IRQ_Enable(struct ethosu_driver *drv) +{ + uint32_t pmint = drv->dev.reg->PMINTSET.word; + LOG_DEBUG("mask=0x%08" PRIx32, pmint); + return pmint; +} + +void ETHOSU_PMU_CNTR_Increment(struct ethosu_driver *drv, uint32_t mask) +{ + LOG_DEBUG(""); + uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status(drv); + + // Disable counters + ETHOSU_PMU_CNTR_Disable(drv, mask); + + // Increment cycle counter + if (mask & ETHOSU_PMU_CCNT_Msk) + { + uint64_t val = ETHOSU_PMU_Get_CCNTR(drv) + 1; + drv->dev.reg->PMCCNTR.CYCLE_CNT_LO = val & MASK_0_31_BITS; + drv->dev.reg->PMCCNTR.CYCLE_CNT_HI = (val & MASK_32_47_BITS) >> 32; + } + + for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) + { + if (mask & (1u << i)) + { + uint32_t val = ETHOSU_PMU_Get_EVCNTR(drv, i); + drv->dev.reg->PMEVCNTR[i].word = val + 1; + } + } + + // Reenable the active counters + ETHOSU_PMU_CNTR_Enable(drv, cntrs_active); +} + +void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type start_event) +{ + LOG_DEBUG("start_event=%u", start_event); + struct pmccntr_cfg_r cfg; + uint32_t val = pmu_event_value(start_event); + if (val == UINT32_MAX) + { + LOG_ERR("Invalid ethosu_pmu_event_type: %d", start_event); + return; + } + + cfg.word = drv->dev.reg->PMCCNTR_CFG.word; + cfg.CYCLE_CNT_CFG_START = val; + drv->dev.reg->PMCCNTR_CFG.word = cfg.word; +} + +void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type stop_event) +{ + LOG_DEBUG("stop_event=%u", stop_event); + struct pmccntr_cfg_r cfg; + uint32_t val = pmu_event_value(stop_event); + if (val == UINT32_MAX) + { + LOG_ERR("Invalid ethosu_pmu_event_type: %d", stop_event); + return; + } + + cfg.word = drv->dev.reg->PMCCNTR_CFG.word; + cfg.CYCLE_CNT_CFG_STOP = val; + drv->dev.reg->PMCCNTR_CFG.word = cfg.word; +} + +uint32_t ETHOSU_PMU_Get_QREAD(struct ethosu_driver *drv) +{ + uint32_t val = drv->dev.reg->QREAD.word; + LOG_DEBUG("qread=%" PRIu32, val); + return val; +} + +uint32_t ETHOSU_PMU_Get_STATUS(struct ethosu_driver *drv) +{ + uint32_t val = drv->dev.reg->STATUS.word; + LOG_DEBUG("status=0x%" PRIx32, val); + return val; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml new file mode 100644 index 0000000..08831dd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/third-party/ethos-u-core-driver/zephyr/module.yml @@ -0,0 +1,6 @@ +# Copyright (c) 2021-2022 Arm Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +name: hal_ethos_u +build: + cmake-ext: True + kconfig-ext: True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/TARGETS new file mode 100644 index 0000000..423970b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/TARGETS @@ -0,0 +1,80 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "schemas", + srcs = ["schemas/__init__.py"], + resources = [ + "schemas/tosa_1.0.fbs", + ], + visibility = ["PUBLIC"], +) + +runtime.python_library( + name = "mapping", + srcs = [ + "mapping.py", + ], + deps = [ + "fbsource//third-party/tosa_tools:serializer", + "//caffe2:torch", + ":specification", + ], +) +runtime.python_library( + name = "specification", + srcs = [ + "specification.py", + ], + deps = [ + "fbsource//third-party/pypi/packaging:packaging", + "//executorch/exir/backend:compile_spec_schema", + ], +) +runtime.python_library( + name = "utils", + srcs = [ + "utils.py", + ], + deps = [ + "//executorch/backends/arm/operators:node_visitor", + ], +) + +runtime.python_library( + name = "tosa", + srcs = [ + "__init__.py", + ], + deps = [ + ":specification", + ], +) + +runtime.python_library( + name = "compile_spec", + srcs = [ + "compile_spec.py", + ], + deps = [ + ":tosa", + ":specification", + "//executorch/backends/arm:arm_compile_spec", + ], +) + +runtime.python_library( + name = "partitioner", + srcs = [ + "backend.py", + "partitioner.py", + ], + deps = [ + ":compile_spec", + "//executorch/backends/arm:constants", + "//executorch/backends/arm:process_node", + "//executorch/backends/arm/debug:schema", + "//executorch/backends/arm/operator_support:operator_support", + "//executorch/backends/arm/_passes:passes", + "//executorch/exir:lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/__init__.py new file mode 100644 index 0000000..3086064 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/__init__.py @@ -0,0 +1,9 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +from .specification import TosaSpecification + +__all__ = ["TosaSpecification"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/backend.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/backend.py new file mode 100644 index 0000000..cb67d12 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/backend.py @@ -0,0 +1,443 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide TOSA backend entry points for the Arm ExecuTorch integration. + +Implement the Ahead-of-Time (AoT) preprocessing path that lowers an +``ExportedProgram`` to a TOSA flatbuffer using Arm's lowering pipeline. Use +this module either as a standalone backend that produces a TOSA artifact or as +part of a composed pipeline for hardware backends that consume TOSA as an +intermediate form. + +Use ``TOSABackend.preprocess`` to return the serialized TOSA flatbuffer that +subsequent stages (for example, JIT or hardware-specific compilers) consume. + +""" + +import logging +import tempfile +from itertools import count +from typing import cast, Dict, final, List + +import torch + +import tosa_serializer as ts +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.debug import debug_fail, debug_tosa_dump +from executorch.backends.arm.debug.schema import DebugHook +from executorch.backends.arm.process_node import ( + process_call_function, + process_output, + process_placeholder, +) +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.mapping import TOSA_TENSOR_NAME_META +from executorch.exir.backend.backend_details import BackendDetails, PreprocessResult +from executorch.exir.backend.compile_spec_schema import CompileSpec +from executorch.exir.dim_order_utils import get_memory_format +from executorch.exir.graph_module import get_cond_while_submodules +from torch.export.exported_program import ExportedProgram +from torch.fx import Graph, GraphModule, Node + +# TOSA backend debug functionality +logger = logging.getLogger(__name__) + + +def _annotate_external_ids(ep_graph: Graph) -> Dict[str, int]: + """Assign deterministic output IDs to leaf outputs. + + Flattens the output structure and assigns the external ID + based on the leaf position in the exported output tuple/list. + + Args: + ep_graph (Graph): FX graph produced by export preprocessing. + + Returns: + dict[str, int]: Mapping from *leaf output node name* to external output index. + """ + node2external_id = {} + + def _collect_leaves(arg, nodes): + # Collect only FX Nodes that are actual outputs + # (ignore ints/None/etc inside structured outputs). + if isinstance(arg, Node): + nodes.append(arg) + elif isinstance(arg, (list, tuple)): + for a in arg: + _collect_leaves(a, nodes) + + out = ep_graph.output_node() + out_leaves: list[Node] = [] + # First argument of output is the structured container (tuple/list) of outputs + _collect_leaves(out.args[0], out_leaves) + + # Map each output leaf's name to its position + node2external_id = {leaf.name: idx for idx, leaf in enumerate(out_leaves)} + + return node2external_id + + +def _sort_outputs(graph_module: GraphModule, node_to_id_map: dict[str, int]): + """Reorder graph outputs to match ascending external IDs. + + Args: + graph_module (GraphModule): Graph to reorder in place. + node_to_id_map (dict[str, int]): Mapping from node name to output index. + + Returns: + GraphModule: Updated graph module with deterministic output ordering. + + """ + + def _external_id(n: Node, node_2_id, fallback: int) -> int: + """Return the external ID for ``n`` or ``fallback`` when absent.""" + return node_2_id.get(n.name, fallback) + + out_node = graph_module.graph.output_node() + out_list = cast(tuple, out_node.args[0]) + _counter = count() + + # sort nodes by the key that is id + def _sort_key(t: Node) -> int: + """Key function that orders outputs by external ID or position.""" + return _external_id(t, node_to_id_map, next(_counter)) + + orig_ord = tuple(sorted(out_list, key=_sort_key)) + + current_order = tuple(out_list) + if orig_ord != current_order: + replacement = list(orig_ord) if isinstance(out_node.args[0], list) else orig_ord + out_node.args = (replacement,) + graph_module.graph.lint() + graph_module.recompile() + + return graph_module + + +def _get_matching_fake_tensor(node: Node): + """Return a fake tensor with the same properties as node, + but with .dim_order() == node.meta["tosa_dim_order"] + """ + fake_tensor = node.meta["val"] + desired_dim_order = node.meta["tosa_dim_order"] + return fake_tensor.to(memory_format=get_memory_format(list(desired_dim_order))) + + +def arm_get_first_delegation_tag(graph_module) -> str: + """Return the first delegation tag discovered in the FX graph. + + Args: + graph_module (GraphModule): Module produced by Arm partitioning. + + Returns: + str: First non-empty delegation tag or an empty string when no tag is + recorded. + + """ + for node in graph_module.graph.nodes: + tag = node.meta.get("delegation_tag") + if tag: + return tag + + logger.debug("No delegation tag found in partition.") + return "" + + +@final +class TOSABackend(BackendDetails): + """Provide a backend for lowering programs to TOSA. + + Use this class standalone to produce a TOSA representation, or as part of a + composed pipeline for hardware backends that consume TOSA. + + """ + + @staticmethod + def preprocess(edge_program: ExportedProgram, compile_specs: List[CompileSpec]): + """Convert an exported program using the provided compile specs. + + Args: + edge_program (ExportedProgram): Program generated by Torch export. + compile_specs (List[CompileSpec]): Raw compile specifications from + ``executorch.apply_backend``. + + Returns: + PreprocessResult: Result containing serialized TOSA bytes. + + """ + return TOSABackend._preprocess( + edge_program, TosaCompileSpec.from_list(compile_specs) + ) + + @staticmethod + def _preprocess( # noqa: C901 + edge_program: ExportedProgram, + compile_spec: TosaCompileSpec, + ) -> PreprocessResult: + """Lower an exported program to a TOSA flatbuffer. + + Apply Arm transformation passes to ``edge_program``, then walk the + transformed FX graph to emit a TOSA graph via the serializer. When + requested in ``compile_spec``, write additional debug artifacts. + + Args: + edge_program (ExportedProgram): Program to lower to TOSA. + compile_spec (TosaCompileSpec): Backend options. Recognized keys: + - output_format: Must be "tosa". + - tosa_spec: Target TOSA version/capabilities. + - debug_artifact_path: Directory for debug outputs. + - compile_flags: Optional backend flags. + - dump_debug_info: Enable extra debug JSON dump. + + Returns: + PreprocessResult: Result containing processed_bytes with the + serialized TOSA flatbuffer. + + Raises: + ValueError: If output_format is not "tosa" or the TOSA + specification is missing from compile_spec. + RuntimeError: If an unsupported FX node type is encountered. + + """ + # if a debug/test build capture output files from TOSA stage + artifact_path = compile_spec.get_intermediate_path() + tosa_spec = compile_spec.tosa_spec + dump_debug_info = compile_spec.tosa_debug_mode + debug_hook = None + if dump_debug_info is not None: + debug_hook = DebugHook(dump_debug_info) + + logger.info(f"Converting ExportedProgram to TOSA: {tosa_spec}") + + # Converted output for this subgraph, serializer needs path early as it emits + # const data directly. Path created and data written only in debug builds. + if not artifact_path: + artifact_path = "" + + version = tosa_spec.version + tosa_graph = ts.TosaSerializer( + artifact_path, + targetMajor=version.major, + targetMinor=version.minor, + targetPatch=version.micro, + targetDraft=False, + ) + + if not ( + tosa_spec.version.major == ts.TOSA_VERSION_MAJOR + and tosa_spec.version.minor <= ts.TOSA_VERSION_MINOR + ): + raise RuntimeError( + f"TOSA serializer version " + f"({ts.TOSA_VERSION_MAJOR}.{ts.TOSA_VERSION_MINOR}) " + f"doesn't match specification {tosa_spec}" + ) + + TOSABackend._preprocess_module( + edge_program.graph_module, + edge_program, + compile_spec, + tosa_graph, + debug_hook, + ) + # Serialize and return the TOSA flatbuffer. + binary = tosa_graph.serialize() + + if artifact_path: + tag = arm_get_first_delegation_tag(edge_program.graph_module) + + # Only dump TOSA if we are not saving to temporary folder. + if len( + tempdir := tempfile.gettempdir() + ) > 0 and not artifact_path.startswith(tempdir): + debug_tosa_dump( + binary, + artifact_path, + suffix="{}".format(f"_{tag}" if tag else "") + (f"_{tosa_spec}"), + ) + + if debug_hook is not None: + if debug_hook.mode == ArmCompileSpec.DebugMode.JSON: + json_output = debug_hook.serialize() + with open(f"{artifact_path}/debug.json", "w") as f: + f.write(json_output) + + return PreprocessResult(processed_bytes=binary) + + @staticmethod + def _regularize_submodule(submodule: GraphModule, submodule_node: Node): + """To make a submodule fit into the normal flow of a graph_module, we need to do some regularizations. + + - Buffers created before passes are treated as input to the submodule. Buffers created during passes + are treated as "normal" buffers, i.e. gathered from the state_dict. + To make it easy to tell them apart, mark all placeholders with "is_input = True" before running passes. + - Make sure output node args[0] is always iterable. + - Match the dim_order() of the input tensors with the dim orders of the submodule_node inputs. + - Match the dim_order() of the out tensors with the dim orders of the submodule_node outputs. + """ + submodule_inputs: list[Node] = [] + for node in submodule.graph.nodes: + if node.op == "placeholder": + node.meta["is_input"] = True + submodule_inputs.append(node) + match submodule_node.target: + case torch.ops.higher_order.cond: + args = cast(list[Node], submodule_node.args[-1]) + case torch.ops.higher_order.while_loop: + args = cast(list[Node], submodule_node.args[-2]) + cast( + list, submodule_node.args[-1] + ) + case _: + raise RuntimeError( + f"Unexpected control flow target: {submodule_node.target}" + ) + + for submodule_input, submodule_arg in zip(submodule_inputs, args, strict=True): + submodule_input.meta["val"] = _get_matching_fake_tensor(submodule_arg) + + output_node = submodule.graph.output_node() + if isinstance(output_node.args[0], Node): + output_node.update_arg(0, [output_node.args[0]]) + output_args = cast(list[Node], output_node.args[0]) + + # Not all outputs might be used, causing len(users) < len(outputs) + # Therefore, strict != True in the zip + for submodule_output, submodule_user in zip(output_args, submodule_node.users): + submodule_output.meta["val"] = _get_matching_fake_tensor(submodule_user) + + @staticmethod + def _preprocess_module( # noqa: C901 + graph_module: GraphModule, + edge_program: ExportedProgram, + compile_spec: TosaCompileSpec, + tosa_graph: ts.TosaSerializer, + debug_hook: DebugHook | None, + submodule_name: str | None = None, + containing_graph_module: GraphModule | None = None, + ): + """Convert an FX ``graph_module`` to TOSA serializer calls. + + Args: + graph_module (GraphModule): Module to lower recursively. + edge_program (ExportedProgram): Original exported program. + compile_spec (TosaCompileSpec): Backend options with TOSA settings. + tosa_graph (ts.TosaSerializer): Serializer receiving operators. + debug_hook (DebugHook | None): Optional debug instrumentation. + submodule_name (str | None): Name used when visiting nested blocks. + + Raises: + RuntimeError: If an FX node with an unsupported op kind is found. + + """ + tosa_spec = compile_spec.tosa_spec + node_to_id_map = _annotate_external_ids(graph_module.graph) + artifact_path = compile_spec.get_intermediate_path() + output_order_workaround = compile_spec.get_output_order_workaround() + + # TODO: Fix the need to lazily import this. + from executorch.backends.arm._passes import ArmPassManager + + graph_module = ArmPassManager(compile_spec).transform_to_backend_pipeline( # type: ignore + exported_program=edge_program, graph_module=graph_module + ) + + # TODO: Fix the need to lazily import this. + from executorch.backends.arm.operators.node_visitor import get_node_visitors + + node_visitors = get_node_visitors(edge_program, tosa_spec, debug_hook) + + if output_order_workaround: + logger.debug("Re-sorting outputs during TOSA lowering.") + graph_module = _sort_outputs(graph_module, node_to_id_map) + else: + logger.debug("No re-sorting outputs (workaround) during TOSA lowering.") + + if submodule_name is not None: + tosa_graph.startRegion(submodule_name) + tosa_graph.currRegion.addBasicBlock(submodule_name) + suffix = f"_{submodule_name}" + for loop_node in graph_module.graph.nodes: + loop_node.meta[TOSA_TENSOR_NAME_META] = suffix + + for node in graph_module.graph.nodes: + node = cast(Node, node) + try: + if node.op == "call_function": + process_call_function(node, tosa_graph, node_visitors, tosa_spec) + elif node.op == "placeholder": + if len(node.users) == 0 and submodule_name is None: + # In top level module, we don't need to handle unused placeholders. + # In submodules, we do need to handle them to preserve call signature. + continue + process_placeholder( + node, + tosa_graph, + edge_program, + containing_graph_module, + tosa_spec, + ) + elif node.op == "output": + process_output(node, tosa_graph, tosa_spec) + elif node.op == "get_attr": + attr = getattr(graph_module, str(node.target), None) + if attr is None: + raise RuntimeError( + "get_attr node is not targeting anything in graph module." + ) + if not isinstance(attr, GraphModule): + raise RuntimeError( + "get_attr node is not targeting a GraphModule." + ) + + # If the above conditions are ok, we don't need to handle this node here. + # Only the string value of node.target is important. + else: + # This will only happen if an unpartitioned graph is passed without + # any checking of compatibility. + raise RuntimeError(f"{node.name} is unsupported op {node.op}") + except Exception: + debug_fail(node, graph_module, tosa_graph, artifact_path) + raise + + # Recursively preprocess controlflow submodules. + for name, submodule, control_flow_node in get_cond_while_submodules( + graph_module + ): + TOSABackend._regularize_submodule(submodule, control_flow_node) + TOSABackend._preprocess_module( + submodule, + edge_program, + compile_spec, + tosa_graph, + debug_hook, + submodule_name=name, + containing_graph_module=graph_module, + ) + + @staticmethod + def filter_tosa_compile_specs( + compile_spec: ArmCompileSpec, + ) -> TosaCompileSpec: + """Extract the TOSA-specific settings from a composite compile spec. + + Args: + compile_spec (ArmCompileSpec): Compile specification that may + include both TOSA and hardware-specific options. + + Returns: + TosaCompileSpec: TOSA-only specification ready for + ``TOSABackend.preprocess``. + + """ + + pipeline_config = compile_spec.get_pass_pipeline_config() + tosa_compile_spec = TosaCompileSpec(compile_spec.tosa_spec) + tosa_compile_spec.set_pass_pipeline_config(pipeline_config) + return ( + tosa_compile_spec.dump_intermediate_artifacts_to( + compile_spec.get_intermediate_path() + ) + .dump_debug_info(compile_spec.tosa_debug_mode) + .set_output_order_workaround(compile_spec.output_order_workaround) + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/compile_spec.py new file mode 100644 index 0000000..5cd72ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/compile_spec.py @@ -0,0 +1,48 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( # noqa: unused + ArmPassPipelineConfig, +) +from executorch.backends.arm.tosa import TosaSpecification + + +class TosaCompileSpec(ArmCompileSpec): + """Arm-specific compile spec capturing TOSA serializer requirements.""" + + def __init__(self, tosa_spec: TosaSpecification | str): + """Normalize and store the provided TOSA specification. + + Args: + tosa_spec (TosaSpecification | str): Target spec object or version + string supported by :meth:`TosaSpecification.create_from_string`. + + """ + if isinstance(tosa_spec, str): + tosa_spec = TosaSpecification.create_from_string(tosa_spec) + self._set_compile_specs(tosa_spec, []) + self.validate() + + def validate(self): + """Ensure that no unsupported compiler flags were supplied.""" + if len(self.compiler_flags) != 0: + raise ValueError( + f"TosaCompileSpec can't have compiler flags, got {self.compiler_flags}" + ) + pass + + @classmethod + def get_output_format(cls) -> str: + """Return the artifact format emitted by this compile spec.""" + return "tosa" + + @classmethod + def from_list_hook(cls, compile_spec, specs: dict[str, str]): + super().from_list_hook(compile_spec, specs) + + def _create_default_pipeline_config(self): + config = super()._create_default_pipeline_config() + return config diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/TARGETS new file mode 100644 index 0000000..398d519 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/TARGETS @@ -0,0 +1,36 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +runtime.python_library( + name = "core", + srcs = [ + "lib.py", + "ops_registration.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/backends/arm/tosa:tosa", + "//executorch/exir/dialects:lib", + ], +) + +runtime.python_library( + name = "ops", + srcs = glob(["ops/*.py"]), + deps = [ + ":core", + "//caffe2:torch", + "//executorch/backends/arm/tosa:tosa", + ], +) + +runtime.python_library( + name = "lib", + srcs = ["__init__.py"], + deps = [ + ":core", + ":ops", + "//caffe2:torch", + "//executorch/backends/arm/tosa:tosa", + "//executorch/exir/dialects:lib", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/__init__.py new file mode 100644 index 0000000..152f99d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.tosa.dialect.ops import ( # noqa F401 + conv2d, + conv3d, + depthwise_conv2d, + matmul, + rescale, + resize, + table, + transpose, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/lib.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/lib.py new file mode 100644 index 0000000..ed26a21 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/lib.py @@ -0,0 +1,85 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable + +from executorch.exir.dialects._ops import _BACKEND_OP_LIB, ops as exir_ops +from torch.library import Library, register_fake +from torchgen.model import FunctionSchema + +# create a torch library for the TOSA dialect +# This defines a library to include Backend Dialect Operators in Executorch +tosa_lib = Library("tosa", "DEF") + + +def register_tosa_dialect_op(op_schema, func) -> Callable: + """Register a TOSA dialect operator with the backend op library. + + Args: + op_schema (str): Operator schema without namespace or overload name. + func (Callable): Fake implementation used for registration. + + Returns: + Callable: Backend dialect operator handle exposed via ``exir_ops`` and + marked ``not_callable`` for runtime use. + + """ + if tosa_lib.ns not in _BACKEND_OP_LIB: + _BACKEND_OP_LIB.append(tosa_lib.ns) + + if "::" in op_schema: + raise ValueError("The schema should not contain a namespace.") + + # Parse the op_schema into a FunctionSchema + func_schema = FunctionSchema.parse(op_schema) + overload_name = func_schema.name.overload_name + if overload_name: + raise ValueError( + "The TOSA dialect does not support overload names in the op schema." + ) + + opname = func_schema.name.name.base + tosa_lib.define(op_schema) + + overload_name = "default" + op_qualified_name = f"{tosa_lib.ns}::{opname}" + + register_fake(op_qualified_name, func, lib=tosa_lib) + + op = getattr(getattr(getattr(exir_ops.backend, tosa_lib.ns), opname), overload_name) + + # For now, since the TOSA operators are only used for lowering and serialization in the backend + # the op doesn't need to be callable. This can be changed in the future if needed to support + # execution of TOSA ops directly. + def not_callable(): + """Raise when the dialect op handle is invoked at runtime.""" + raise RuntimeError("TOSA dialect op is not callable") + + op.__equvalent_callable__ = not_callable + + return op + + +class TosaValueError(ValueError): + """Error type that annotates failures with the originating TOSA op.""" + + def __init__(self, message="A TOSA value error occurred", *args, op=None): + """Initialise the error with optional operator metadata. + + Args: + message (str): Human-readable error message. + *args: Additional arguments forwarded to ``ValueError``. + op: Optional operator identifier included in the string output. + + """ + super().__init__(message, *args) + self.op = op + + def __str__(self): + """Return the base message, appending the operator when provided.""" + base_message = super().__str__() + if self.op is not None: + return f"{base_message} (TOSA op: {self.op})" + return base_message diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv2d.py new file mode 100644 index 0000000..6d0fc22 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv2d.py @@ -0,0 +1,111 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Optional + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +def validate_conv2d_args_dtypes( + tosa_spec: TosaSpecification, + x: torch.Tensor, + weight: torch.Tensor, + bias: Optional[torch.Tensor] = None, + op: str = "CONV2D", +) -> torch.dtype: + output_dtype = None + supported_int_types = (torch.int8, torch.int16) + supported_float_types = ( + torch.float16, + torch.float32, + ) + if x.dtype in supported_int_types: + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support {x.dtype} but found input type {x.dtype}", + op=op, + ) + if weight.dtype not in (torch.int8,): + raise TosaValueError( + f"TOSA spec {tosa_spec} only supports {torch.int8} weights for {x.dtype} input but found {weight.dtype}", + op=op, + ) + if bias is not None and bias.dtype not in (torch.int32,): + raise TosaValueError( + f"TOSA spec {tosa_spec} only supports {torch.int32} bias for {x.dtype} input but found {bias.dtype}", + op=op, + ) + output_dtype = torch.int32 + + elif x.dtype in supported_float_types: + if not tosa_spec.support_float(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support {x.dtype} but found input type {x.dtype}", + op=op, + ) + if weight.dtype != x.dtype: + raise TosaValueError( + f"TOSA spec {tosa_spec} requires weights {weight.dtype} to be of the same type as input {x.dtype}", + op=op, + ) + if bias is not None and bias.dtype != x.dtype: + raise TosaValueError( + f"TOSA spec {tosa_spec} requires bias {bias.dtype} to be of the same type as input {x.dtype}", + op=op, + ) + output_dtype = x.dtype + else: + raise TosaValueError( + f"Unsupported input dtype {x.dtype}, supported types are {supported_int_types + supported_float_types} ", + op=op, + ) + return output_dtype + + +@register_fake_tosa_op( + "CONV2D(Tensor input, " + "Tensor weight, " + "Tensor bias, " + "int[2] stride, " + "int[4] pad, " + "int[2] dilation) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def CONV2D( + x: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor, + stride: list[int], + pad: list[int], + dilation: list[int], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + output_dtype = validate_conv2d_args_dtypes(tosa_spec, x, weight, bias, op="CONV2D") + + torch_pad = [pad[0], pad[2]] + N = x.shape[0] + C_out = weight.shape[0] + H_in, W_in = x.shape[2:] + H_out = math.floor( + (H_in + 2 * torch_pad[0] - dilation[0] * (weight.shape[2] - 1) - 1) / stride[0] + + 1 + ) + W_out = math.floor( + (W_in + 2 * torch_pad[1] - dilation[1] * (weight.shape[3] - 1) - 1) / stride[1] + + 1 + ) + output_shape = [N, C_out, H_out, W_out] + return torch.empty(size=output_shape, dtype=output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv3d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv3d.py new file mode 100644 index 0000000..9e01233 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/conv3d.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Optional + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops.conv2d import validate_conv2d_args_dtypes +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +def validate_conv3d_args_dtypes( + tosa_spec: TosaSpecification, + x: torch.Tensor, + weight: torch.Tensor, + bias: Optional[torch.Tensor] = None, +) -> torch.dtype: + if len(x.shape) != 5 or len(weight.shape) != 5: + raise TosaValueError( + f"Expected 5D input/weight tensors for CONV3D, got {x.shape} and {weight.shape}", + op="CONV3D", + ) + return validate_conv2d_args_dtypes(tosa_spec, x, weight, bias, op="CONV3D") + + +@register_fake_tosa_op( + "CONV3D(Tensor input, " + "Tensor weight, " + "Tensor bias, " + "int[3] stride, " + "int[6] pad, " + "int[3] dilation) -> Tensor", + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), +) +def CONV3D( + x: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor, + stride: list[int], + pad: list[int], + dilation: list[int], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + output_dtype = validate_conv3d_args_dtypes(tosa_spec, x, weight, bias) + + torch_pad = [pad[0], pad[2], pad[4]] + N = x.shape[0] + C_out = weight.shape[0] + D_in, H_in, W_in = x.shape[2:] + D_out = math.floor( + (D_in + 2 * torch_pad[0] - dilation[0] * (weight.shape[2] - 1) - 1) / stride[0] + + 1 + ) + H_out = math.floor( + (H_in + 2 * torch_pad[1] - dilation[1] * (weight.shape[3] - 1) - 1) / stride[1] + + 1 + ) + W_out = math.floor( + (W_in + 2 * torch_pad[2] - dilation[2] * (weight.shape[4] - 1) - 1) / stride[2] + + 1 + ) + output_shape = [N, C_out, D_out, H_out, W_out] + return torch.empty(size=output_shape, dtype=output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/depthwise_conv2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/depthwise_conv2d.py new file mode 100644 index 0000000..81d87d9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/depthwise_conv2d.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math + +import torch +from executorch.backends.arm.tosa.dialect.ops.conv2d import validate_conv2d_args_dtypes +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +@register_fake_tosa_op( + "DEPTHWISE_CONV2D(Tensor input, " + "Tensor weight, " + "Tensor bias, " + "int[2] stride, " + "int[4] pad, " + "int[2] dialation) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def DEPTHWISE_CONV2D( + x: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor, + stride: list[int], + pad: list[int], + dilation: list[int], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + output_dtype = validate_conv2d_args_dtypes( + tosa_spec, x, weight, bias, op="DEPTHWISE_CONV2D" + ) + + torch_pad = [pad[0], pad[2]] + kernel_h, kernel_w = weight.shape[0], weight.shape[2] + C_out = weight.shape[1] * x.shape[1] + N = x.shape[0] + H_in, W_in = x.shape[2:] + H_out = math.floor( + (H_in + 2 * torch_pad[0] - dilation[0] * (kernel_h - 1) - 1) / stride[0] + 1 + ) + W_out = math.floor( + (W_in + 2 * torch_pad[1] - dilation[1] * (kernel_w - 1) - 1) / stride[1] + 1 + ) + output_shape = [N, C_out, H_out, W_out] + return torch.empty(size=output_shape, dtype=output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/matmul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/matmul.py new file mode 100644 index 0000000..1ba3821 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/matmul.py @@ -0,0 +1,56 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops + + +@register_fake_tosa_op( + "MATMUL(Tensor input1, Tensor input2) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def MATMUL(x1: torch.Tensor, x2: torch.Tensor) -> torch.Tensor: + tosa_spec = get_context_spec() + """Performs matrix multiplication on two input tensors. + Additionally validates TOSA constraints of a MATMUL op. + """ + if x1.dtype != x2.dtype: + raise TosaValueError( + f"Input tensors must have the same dtype, got {x1.dtype} and {x2.dtype}", + op="MATMUL", + ) + if x1.dtype in (torch.int8, torch.int16): + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="MATMUL" + ) + else: + dtype = torch.int32 + elif x1.dtype in (torch.float16, torch.float32): + if not tosa_spec.support_float(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support float", op="MATMUL" + ) + else: + # float16 supports float16 accumulation as well + dtype = torch.float32 + else: + raise TosaValueError( + f"Input tensors must be of type int8, float16 or float32, got {x1.dtype}", + op="MATMUL", + ) + + aten_fake_tensor = exir_ops.edge.aten.bmm.default(x1, x2) + + return torch.empty_like(aten_fake_tensor, dtype=dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/rescale.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/rescale.py new file mode 100644 index 0000000..f622bbf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/rescale.py @@ -0,0 +1,53 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +@register_fake_tosa_op( + "RESCALE(Tensor input1, ScalarType dtype, float[] scale, int in_zp, int out_zp) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def RESCALE( + x: torch.Tensor, dtype: torch.dtype, scales: List[float], in_zp: int, out_zp: int +) -> torch.Tensor: + tosa_spec = get_context_spec() + """Casts the input tensor to dtype `dtype` to produce the correct tensor meta for a _rescale op. + Additionally validates TOSA constraints of a RESCALE op. + """ + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="RESCALE" + ) + + if dtype not in (torch.int32, torch.int8, torch.int16): + raise NotImplementedError( + f"tosa::rescale currently only supports int32, int16 and int8, not {dtype}" + ) + if dtype in (torch.int32, torch.int16) and out_zp != 0: + raise ValueError( + f"TOSA requires output_zp to be zero when the output dtype is {dtype}." + ) + if x.dtype in (torch.int32, torch.int16) and in_zp != 0: + raise ValueError( + f"TOSA requires input_zp to be zero when the input dtype is {dtype}" + ) + if x.dtype == torch.int8 and not -128 <= in_zp <= 127: + raise ValueError(f"{in_zp=} outside valid range (-128,127) for int8.") + if dtype == torch.int8 and not -128 <= out_zp <= 127: + raise ValueError(f"{out_zp=} outside valid range (-128,127) for int8.") + + return torch.empty_like(x, dtype=dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/resize.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/resize.py new file mode 100644 index 0000000..b40b1f7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/resize.py @@ -0,0 +1,66 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Literal, Optional + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) +from executorch.exir.dialects._ops import ops as exir_ops + + +# Add kwarg instead? +@register_fake_tosa_op( + "RESIZE(Tensor input, SymInt[]? output_size, bool align_corners, float[]? scale_factors, *, str resize_mode) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + TosaSpecification.create_from_string("TOSA-1.0+FP"), + ), # target TOSA specifications +) +def RESIZE( + x: torch.Tensor, + output_size: list[int] | None = None, + align_corners: Optional[bool] = False, + scale_factors: list[float] | None = None, + *, + resize_mode: Literal["nearest", "bilinear"], +) -> torch.Tensor: + tosa_spec = get_context_spec() + + if resize_mode not in ("nearest", "bilinear"): + raise TosaValueError(f"Unsupported resize mode {resize_mode} for TOSA RESIZE") + if x.dtype == torch.int8: + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="RESIZE" + ) + bilinear = resize_mode == "bilinear" + output_dtype = torch.int32 if bilinear else torch.int8 + elif x.dtype == torch.int16: + if not tosa_spec.support_integer(): + raise TosaValueError( + f"Context TOSA spec {tosa_spec} doesn't support int16", op="RESIZE" + ) + output_dtype = x.dtype + elif x.dtype in (torch.float16, torch.float32): + if not tosa_spec.support_float(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support float", op="RESIZE" + ) + output_dtype = x.dtype + else: + raise TosaValueError(f"Unsupported input dtype {x.dtype} for TOSA RESIZE") + + # Does it matter which one to use for fake tracing? + fake_aten_tensor = exir_ops.edge.aten.upsample_nearest2d.vec( + x, output_size, scale_factors + ) + + return fake_aten_tensor.to(output_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/table.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/table.py new file mode 100644 index 0000000..40f592e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/table.py @@ -0,0 +1,53 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + + +@register_fake_tosa_op( + "TABLE(Tensor input1, Tensor table) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def TABLE(a, table): + tosa_spec = get_context_spec() + # verifiy input types according to the spec + if not tosa_spec.support_integer(): + raise TosaValueError( + f"TOSA spec {tosa_spec} doesn't support integers", op="TABLE" + ) + + if a.dtype == torch.int8: + if table.shape != torch.Size((256,)): + raise TosaValueError( + f"Table of wrong size ({table.shape}!={torch.Size((256,))}", op="TABLE" + ) + if table.dtype != torch.int8: + raise TosaValueError(f"Table dtype {table.dtype} is not int8", op="TABLE") + return_dtype = torch.int8 + elif a.dtype == torch.int16: + if not tosa_spec.support_extension("int16"): + raise TosaValueError( + f"Context TOSA spec {tosa_spec} doesn't support int16", op="TABLE" + ) + if table.shape != torch.Size((513,)): + raise TosaValueError( + f"Table of wrong size ({table.shape}!={torch.Size((513,))})", op="TABLE" + ) + if table.dtype != torch.int16: + raise TosaValueError(f"Table dtype {table.dtype} is not int32", op="TABLE") + return_dtype = torch.int32 + else: + raise TosaValueError(f"Unsupported dtype {a.dtype} for {tosa_spec}", op="TABLE") + + return torch.empty_like(a, dtype=return_dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/transpose.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/transpose.py new file mode 100644 index 0000000..8d5bf8b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops/transpose.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.tosa.dialect.lib import TosaValueError +from executorch.backends.arm.tosa.dialect.ops_registration import register_fake_tosa_op + +from executorch.backends.arm.tosa.specification import TosaSpecification + + +@register_fake_tosa_op( + "TRANSPOSE(Tensor input, int[] perms) -> Tensor", # schema + ( + TosaSpecification.create_from_string("TOSA-1.0+FP"), + TosaSpecification.create_from_string("TOSA-1.0+INT"), + ), # target TOSA specifications +) +def TRANSPOSE(a, perms): + # The TOSA TRANSPOSE only do the transpose in the TOSA serialized world, + # so just return the same shape and type. + + # For certain operators we need the data in a specific data format. Changing tosa_dim_order + # is not sufficient as we also need transpose the data. + # By utilizing an edge IR passthrough operator we can keep the edge program in + # channels-first/contiguous and get the desired behavior in the TOSA lowering. + + if len(perms) not in (4, 5, 6): + raise TosaValueError( + f"Only 4D, 5D and 6D tensors are supported, got {len(perms)}: {perms}", + op="TRANSPOSE", + ) + + return torch.empty_like(a, dtype=a.dtype) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops_registration.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops_registration.py new file mode 100644 index 0000000..84aa5cb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/dialect/ops_registration.py @@ -0,0 +1,68 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Callable, Iterable, List, ParamSpec, TypeVar + +from executorch.backends.arm.tosa.dialect.lib import register_tosa_dialect_op + +from executorch.backends.arm.tosa.specification import ( + get_context_spec, + TosaSpecification, +) + +P = ParamSpec("P") +R = TypeVar("R") + +# The list of registered ops are not yet used, except for registration +_tosa_registered_ops: dict[TosaSpecification, list[Callable]] = { + TosaSpecification.create_from_string("TOSA-1.0+FP"): [], + TosaSpecification.create_from_string("TOSA-1.0+INT"): [], +} + +# Mapping to ensure we only register a given function once. +_registered_tosa_ops_by_func: dict[Callable, Callable] = {} + + +def register_fake_tosa_op( + op_schema: str, tosa_specs: Iterable[TosaSpecification] +) -> Callable[[Callable[P, R]], Callable[P, R]]: + """ + Decorator for registering a TOSA operation. + + Parameters: + op_schema : A string that defines the operation schema. + tosa_specs : Iterable of TOSA specification strings, + e.g. ("TOSA-1.0+INT", "TOSA-1.0+FP"). + + The decorated function is registered with the given op_schema by calling + register_tosa_dialect_op(op_schema, func) only once per function. The resulting + callable is then inserted into _tosa_registered_ops for each spec. + """ + + def decorator(func: Callable[P, R]) -> Callable[P, R]: + # Only call register_tosa_dialect_op if the function hasn't been registered yet. + if func not in _registered_tosa_ops_by_func: + op_callable = register_tosa_dialect_op(op_schema, func) + _registered_tosa_ops_by_func[func] = op_callable + else: + op_callable = _registered_tosa_ops_by_func[func] + + # For each TOSA spec, ensure the operation is added only once. + for spec in tosa_specs: + if spec not in _tosa_registered_ops: + raise ValueError(f"TOSA spec {spec} not listed for registrations") + if op_callable not in _tosa_registered_ops[spec]: + _tosa_registered_ops[spec].append(op_callable) + + # return the original function + return func + + return decorator + + +def get_registered_tosa_ops() -> List[Callable]: + tosa_spec = get_context_spec() + return _tosa_registered_ops[tosa_spec] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/mapping.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/mapping.py new file mode 100644 index 0000000..c11a046 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/mapping.py @@ -0,0 +1,309 @@ +# Copyright 2023-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide PyTorch-to-TOSA mapping helpers. + +Use these utilities to translate PyTorch dtypes and FX node metadata into the +TOSA serializer types and shapes used during initial compilation. + +""" + +import operator +from enum import Enum +from typing import Any, Optional, Sequence + +import torch +import tosa_serializer as ts +from executorch.backends.arm.tosa.specification import TosaSpecification + +TOSA_TENSOR_NAME_META = "tosa_tensor_name" + +UNSUPPORTED_DTYPES = ( + torch.float64, + torch.double, + torch.complex64, + torch.cfloat, + torch.complex128, + torch.cdouble, + torch.uint8, + torch.int64, + torch.long, +) + + +class TosaSpecialDtype(Enum): + """Special TOSA dtypes not natively expressed in PyTorch.""" + + INT48 = ts.DType.INT48 + INT4 = ts.DType.INT4 + + def get_tosa_dtype(self) -> ts.DType: + """Return the underlying ``ts.DType`` enumerant. + + Returns: + ts.DType: Serializer dtype associated with the enum entry. + + """ + return self.value + + @staticmethod + def meta_key() -> str: + """Return the FX ``meta`` key that stores special dtypes. + + Returns: + str: Metadata key used to encode :class:`TosaSpecialDtype`. + + """ + return "tosa_special_dtype" + + def max(self): + match self: + case self.INT4: + return 7 + case self.INT48: + return 2**47 - 1 + case _: + raise ValueError(f"Unrecognized TosaSpecialDtype {self}.") + + def min(self): + match self: + case self.INT4: + return -7 + case self.INT48: + return -(2**47) + case _: + raise ValueError(f"Unrecognized TosaSpecialDtype {self}.") + + +def map_dtype(data_type: torch.dtype, tosa_spec: TosaSpecification) -> Any: + """Map a ``torch.dtype`` to a ``ts.DType``. + + Args: + data_type (torch.dtype): PyTorch dtype to convert. + tosa_spec (TosaSpecification): Active spec (reserved for future checks). + + Returns: + ts.DType: Matching serializer dtype. + + Raises: + ValueError: If the dtype is unsupported or unknown. + + """ + if data_type in UNSUPPORTED_DTYPES: + raise ValueError(f"Unsupported type: {data_type}") + + dtype_map = { + torch.float32: ts.DType.FP32, + torch.float: ts.DType.FP32, + torch.float16: ts.DType.FP16, + torch.half: ts.DType.FP16, + torch.bfloat16: ts.DType.BF16, + torch.int8: ts.DType.INT8, + torch.int16: ts.DType.INT16, + torch.short: ts.DType.INT16, + torch.int32: ts.DType.INT32, + torch.int: ts.DType.INT32, + torch.bool: ts.DType.BOOL, + } + if data_type not in dtype_map: + raise ValueError(f"Unknown type: {data_type}") + return dtype_map[data_type] + + +# Returns the shape and type of a node +# TODO: other types, can be +# SymInt, FakeTensor, a List[Union[FakeTensor, SymInt]], or None +def extract_tensor_meta(meta, tosa_spec: TosaSpecification): + """Extract dtype, shape, and dimension order from FX metadata. + + Args: + meta (dict): FX node ``meta`` containing a ``val`` FakeTensor (or tuple). + tosa_spec (TosaSpecification): Active TOSA spec for dtype mapping. + + Returns: + tuple[ts.DType, tuple[int, ...], tuple[int, ...]]: Tuple containing + tensor dtype, shape, and dimension order. + + Raises: + ValueError: If ``meta['val']`` is not a ``FakeTensor``. + + """ + if meta.get("val") is None: + raise ValueError("Expected node.meta['val'] to be set to a FakeTensor") + val = meta["val"] + if type(val) is tuple: + # TODO: should use first concrete representation + val = val[0] + + if not isinstance(val, torch._subclasses.fake_tensor.FakeTensor): + raise ValueError( + f"Expected first value in node.meta['val'] to be FakeTensor, got {val.__class__}" + ) + dtype = map_dtype(val.dtype, tosa_spec) + shape = tuple(val.size()) + + if meta.get("tosa_dim_order") is not None: + dim_order = meta["tosa_dim_order"] + else: + dim_order = tuple(range(len(shape))) + return (dtype, shape, dim_order) + + +class TosaArg: + """Capture and normalize TOSA operator arguments. + + Use this to convert FX nodes, sequences, and numeric literals into a + consistent structure suitable for TOSA serialization. + + Attributes: + name (str): Node name when argument is a ``torch.fx.Node``; empty + otherwise. + dtype (ts.DType | None): Inferred dtype when available. + shape (tuple[int, ...] | None): Inferred shape when available. + dim_order (tuple[int, ...] | None): Dimension order, defaulting to + ``range(len(shape))``. + special (list | None): Captured list when the argument is a sequence. + number (float | int | None): Captured numeric value when provided. + tosa_spec (TosaSpecification): Active specification used for mapping. + multiple_output_name (list[str]): Output node names when node has multiple outputs; empty otherwise. + """ + + def __process_node(self, argument: torch.fx.Node): + """Parse a ``torch.fx.Node`` and populate tensor attributes. + + Args: + argument (torch.fx.Node): FX node to inspect. + + """ + suffix = argument.meta.get(TOSA_TENSOR_NAME_META, "") + self.name = argument.name + suffix + + if "val" in argument.meta: + output_dtype, self.shape, self.dim_order = extract_tensor_meta( + argument.meta, self.tosa_spec + ) + # Handle special case of types not representable in torch (i.e. i48_t) + if special_type := argument.meta.get(TosaSpecialDtype.meta_key(), None): + output_dtype = special_type.get_tosa_dtype() + + self.dtype = output_dtype + + # If all users of the node are getitems, node visitors should connect the output of this node directly to the getitem tensors. + # Add a new attribute 'multiple_output_names' instead of making 'name' a list to avoid ambiguity regarding the type of 'name'. + # Make name of the output is the first getitem since we in most cases only handle that output. + users = list(argument.users) + if len(users) > 0 and all(user.target == operator.getitem for user in users): + self.multiple_output_names: list = [user.name + suffix for user in users] + self.name = self.multiple_output_names[0] + else: + self.multiple_output_names = [] + + if not self.__validate(): + raise ValueError( + f"{self.tosa_spec} doesn't support tensor {self.__repr__()}" + ) + + def __process_list(self, argument): + """Capture a sequence argument as ``special``. + + Args: + argument (Sequence[Any]): Sequence to store. + + """ + self.special: list = list(argument) + + def __process_number(self, argument: float | int): + """Capture a numeric argument as ``number``. + + Args: + argument (float | int): Numeric value. + + """ + self.number: float | int = argument + + def __validate(self) -> bool: + match getattr(self, "dtype", None): + case ts.DType.FP32: + if not self.tosa_spec.support_float(): + return False + case ts.DType.INT4: + if not self.tosa_spec.support_extension("int4"): + return False + + return True + + def __init__( + self, argument: Any, tosa_spec: Optional[TosaSpecification] = None + ) -> None: + """Initialize the argument wrapper and populate fields. + + Args: + argument (Any): One of ``torch.fx.Node``, ``Sequence``, ``int``, + ``float``, ``torch.dtype``, or ``None``. + tosa_spec (Optional[TosaSpecification]): Active specification; + required for metadata extraction. + + Raises: + ValueError: If ``tosa_spec`` is missing or has the wrong type. + RuntimeError: If ``argument`` is of an unsupported type. + + """ + if tosa_spec is None: + raise ValueError("tosa_spec is None") + elif not isinstance(tosa_spec, TosaSpecification): + raise ValueError( + f"Expected tosa_spec to be a TosaSpecification, but got {tosa_spec}" + ) + self.tosa_spec = tosa_spec + + if isinstance(argument, torch.fx.Node): + self.__process_node(argument) + return + if isinstance(argument, Sequence): + self.__process_list(argument) + return + if isinstance(argument, (int, float)): + self.__process_number(argument) + return + if isinstance(argument, torch.dtype): + # Dtype is parsed from fake tensor + return + + if argument is None: + self.name = "" + self.dtype = None + self.shape = None + self.dim_order = None + return + + raise RuntimeError( + f"Unhandled node input argument: {argument}, of type {type(argument)}" + ) + + def __repr__(self): + """Return a compact representation of populated attributes. + + Returns: + str: Readable list of set attributes. + + """ + attrs = [] + if hasattr(self, "name"): + if self.name is not None: + attrs.append(f"name={self.name!r}") + if self.dtype is not None: + attrs.append(f"dtype={ts.DTypeNames[self.dtype]}") + if self.shape is not None: + attrs.append(f"shape={self.shape!r}") + if self.dim_order is not None: + attrs.append(f"dim_order={self.dim_order!r}") + if hasattr(self, "special") and self.special is not None: + attrs.append(f"special={self.special!r}") + if hasattr(self, "number") and self.number is not None: + attrs.append(f"number={self.number!r}") + if hasattr(self, "tosa_spec") and self.tosa_spec is not None: + attrs.append(f"tosa_spec={self.tosa_spec!r}") + if hasattr(self, "multiple_output_names"): + attrs.append(f"names={self.multiple_output_names!r}") + return f"{self.__class__.__name__}({', '.join(attrs)})" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/partitioner.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/partitioner.py new file mode 100644 index 0000000..24707f0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/partitioner.py @@ -0,0 +1,486 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Provide a partitioner for delegating subgraphs to the TOSA backend. + +Implement logic to identify and tag regions of an ``ExportedProgram`` that can +be delegated to the TOSA backend. Use this module to: + +- Partition graphs based on operator support and additional checks. +- Prune trivial no-op partitions that would lower to empty TOSA graphs. +- Tag constant data and report reasons for rejected nodes. + +""" + +import logging +from itertools import count +from typing import Callable, List, Optional, Sequence, Tuple + +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm._passes.convert_expand_copy_to_repeat import ( + calculate_multiples, +) + +from executorch.backends.arm.common.type import ensure_type +from executorch.backends.arm.constants import DQ_OPS, Q_OPS +from executorch.backends.arm.operator_support.tosa_supported_operators import ( + tosa_support_factory, +) +from executorch.backends.arm.tosa.backend import TOSABackend +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.exir.backend.partitioner import ( + DelegationSpec, + Partitioner, + PartitionResult, +) +from executorch.exir.backend.utils import tag_constant_data, WhyNoPartitionReporter +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.graph_module import get_cond_while_submodules +from torch.export.exported_program import ExportedProgram +from torch.fx import GraphModule +from torch.fx.passes.infra.partitioner import CapabilityBasedPartitioner, Partition +from torch.fx.passes.operator_support import OperatorSupportBase + +logger = logging.getLogger(__name__) + + +def is_noop_clone(node: torch.fx.node.Node) -> bool: + """Return True if the node is a no-op ``dim_order_ops._clone_dim_order``. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if the node targets ``dim_order_ops._clone_dim_order.default`` + in the Edge dialect; otherwise, False. + + """ + return node.target == exir_ops.edge.dim_order_ops._clone_dim_order.default + + +def is_noop_alias_copy(node: torch.fx.Node) -> bool: + """Return True if the node is a no-op ``aten.alias_copy``. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if the node targets ``aten.alias_copy.default``; otherwise, + False. + + """ + return node.target == exir_ops.edge.aten.alias_copy.default + + +def is_noop_to_dim_order_copy(node: torch.fx.node.Node) -> bool: + """Return True if node is a no-op ``dim_order_ops._to_dim_order_copy``. + + Consider the op a no-op when the output dtype equals the input's dtype. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if it targets ``_to_dim_order_copy.default`` and preserves + dtype; otherwise, False. + + """ + if node.target != exir_ops.edge.dim_order_ops._to_dim_order_copy.default: + return False + else: + input_node = ensure_type(torch.fx.Node, node.args[0]) + return node.meta.get("dtype") == get_first_fake_tensor(input_node).dtype + + +def is_noop_expand(node: torch.fx.node.Node) -> bool: + """Return True if the node is an ``expand_copy`` with all-ones multiples. + + This corresponds to a semantic no-op, since expanding by 1 along every + dimension leaves the tensor unchanged. + + Args: + node (torch.fx.Node): FX node to inspect. + + Returns: + bool: True if the node targets ``aten.expand_copy.default`` and all + computed multiples are 1; otherwise, False. + + """ + if node.target != exir_ops.edge.aten.expand_copy.default: + return False + else: + multiples, changes_rank = calculate_multiples(node.args) + return all(m == 1 for m in multiples) and not changes_rank + + +def is_partitioned( + node: torch.fx.Node, + tag: str, +) -> bool: + """Return True if the node currently belongs to the partition ``tag``. + + Args: + node (torch.fx.Node): FX node to check. + tag (str): Delegation tag identifying the partition. + + Returns: + bool: True if the node carries the matching delegation tag. + + """ + return "delegation_tag" in node.meta and node.meta["delegation_tag"] == tag + + +def reject_partition( + reason: str, partition: Partition, reporter: WhyNoPartitionReporter +) -> None: + """Remove a proposed partition and record the rejection reason. + + Args: + reason (str): Human-readable explanation for rejection. + partition (object): Proposed partition object from the + capability partitioner. + reporter (WhyNoPartitionReporter): used to report why nodes were rejected. + + """ + for node in partition.nodes: + if "delegation_tag" in node.meta: + del node.meta["delegation_tag"] + reporter.report_reject( + node, + reason, + ) + + +class TOSAPartitioner(Partitioner): + """Partition an exported program into TOSA-delegable subgraphs. + + Construct this partitioner for compile specs targeting TOSA. The partition + algorithm uses capability checks and optional additional operator-support + rules to tag nodes with a delegation tag per subgraph. + + """ + + def __init__( + self, + compile_spec: TosaCompileSpec, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + ) -> None: + """Initialize the TOSAPartitioner. + + Args: + compile_spec (TosaCompileSpec): Parsed compile specifications for + TOSA containing the TOSA spec and original list. + additional_checks (Optional[Sequence[OperatorSupportBase]]): Extra + operator-support checks to apply when partitioning. + + Raises: + RuntimeError: If the provided compile spec does not target TOSA. + + """ + self.delegation_spec = DelegationSpec( + TOSABackend.__name__, compile_spec.to_list() + ) + self.tosa_spec = compile_spec.tosa_spec + self.additional_checks = additional_checks + self.tosa_spec = compile_spec.tosa_spec + + def _detag_boundary_nodes( + self, module: GraphModule, tag: str, reporter: WhyNoPartitionReporter + ) -> None: + """De-tag nodes at the partition boundary. + + Remove delegation tags from quantize nodes with inputs outside the + partition and from dequantize nodes with outputs outside the partition. + + For non Q/DQ nodes, remove the tag from the first node in the partition + if any input has floating-point dtype. + + Args: + tag: The delegation tag assigned to the partition. + reporter: A reporter to log rejected nodes. + module: The GraphModule containing the partition. + + """ + + # De-tag outermost q-nodes upwards and dq-nodes downwards. + # De-tag if at least one input/output is not part of the partition. + for node in module.graph.nodes: + if not is_partitioned(node, tag): + continue + + is_q_node = node.target in Q_OPS + is_dq_node = node.target in DQ_OPS + is_boundary_q_node = is_q_node and not is_partitioned( + node.all_input_nodes[0], tag + ) + is_boundary_dq_node = is_dq_node and any( + not is_partitioned(user, tag) for user in node.users + ) + + if is_boundary_q_node or is_boundary_dq_node: + # Remove tag from quantize node with input outside partition, + # or dequantize node with any output outside partition + del node.meta["delegation_tag"] + elif not is_q_node and not is_dq_node: + # For non Q/DQ nodes, remove tag from first node in partition if any input has fp dtype + for input in node.all_input_nodes: + if is_partitioned(input, tag): + continue + if get_first_fake_tensor(input).dtype.is_floating_point: + reporter.report_reject( + node, + f"Was first node in partition and input {input.name} had fp dtype.", + ) + del node.meta["delegation_tag"] + break + + def _tag_module( # noqa + self, + module: GraphModule, + containing_program: ExportedProgram, + reporter: WhyNoPartitionReporter, + tag_iterator: count | None = None, + ) -> set[str]: + """Tag nodes in a module or submodule from the containing program. + + Args: + module: A GraphModule from `containing_program` to tag nodes in. + containing_program: The ExportedProgram that contains the module. + reporter: A reporter to report why nodes were rejected. + + Returns: + A set of strings with the partition tags. + + """ + tags: set[str] = set() + if tag_iterator is None: + tag_iterator = count(0) + for _, submodule, _ in get_cond_while_submodules(module): + submodule_tags = self._tag_module( + submodule, containing_program, reporter, tag_iterator + ) + if len(tags & submodule_tags) != 0: + raise RuntimeError( + "Got overlapping tags in two different modules, this shouldn't happen." + ) + tags = tags | submodule_tags + operator_support = tosa_support_factory( + self.tosa_spec, containing_program, reporter, self.additional_checks + ) + capability_partitioner = CapabilityBasedPartitioner( + module, + operator_support, + allows_single_node_partition=True, + ) + partition_list = capability_partitioner.propose_partitions() + + for partition in partition_list: + tag = f"tag{next(tag_iterator)}" + tags.add(tag) + + for node in partition.nodes: + node.meta["delegation_tag"] = tag + + if self.tosa_spec.support_integer() and not self.tosa_spec.support_float(): + # Detag boundary Q/DQ since we cannot handle them without float support + self._detag_boundary_nodes( + module, + tag, + reporter, + ) + + is_noop_partition = all( + is_noop_clone(node) + or is_noop_alias_copy(node) + or is_noop_expand(node) + or is_noop_to_dim_order_copy(node) + or node.target in Q_OPS + or node.target in DQ_OPS + for node in partition.nodes + ) + if is_noop_partition: + reject_partition( + "Partition contained only ops which are removed in the TOSA lowering, leading to an empty partition.", + partition, + reporter, + ) + tags.remove(tag) + return tags + + def partition(self, exported_program: ExportedProgram) -> PartitionResult: + """Partition the program and tag TOSA-compatible subgraphs. + + Run the FX capability-based partitioner to propose subgraphs, then + refine tags by removing boundary-only quantize/dequantize nodes and by + rejecting partitions that would lower to no-ops. Emit a detailed report + of rejected nodes and their reasons. + + Args: + exported_program (ExportedProgram): Program to analyze and + partition. + + Returns: + PartitionResult: The input program with nodes tagged for delegation + and a mapping of partition tags to delegation specs. + + """ + logger.info("TOSAPartitioner::partition") + logger.info( + f"Partitioning for {self.delegation_spec.backend_id}: {self.tosa_spec}" + ) + + reporter = WhyNoPartitionReporter() + tags = self._tag_module( + exported_program.graph_module, exported_program, reporter + ) + partition_tags = {tag: self.delegation_spec for tag in tags} + + tag_constant_data(exported_program) + logger.info(f"The following nodes were rejected for {self.tosa_spec}:") + logger.info("\n" + reporter.get_table_report()) + logger.info("(Placeholders and outputs are not included in this list)") + return PartitionResult( + tagged_exported_program=exported_program, partition_tags=partition_tags + ) + + def ops_to_not_decompose( # noqa: C901 + self, + ep: ExportedProgram, + ) -> Tuple[List[torch._ops.OpOverload], Optional[Callable[[torch.fx.Node], bool]]]: + """Return operators and a filter that should not be decomposed. + + Provide a base set of ops to preserve as-is and a predicate that keeps + certain activations whole when surrounded by quantize/dequantize ops in + a quantized graph. This helps downstream TOSA lowering and delegation. + + Args: + ep (ExportedProgram): Program used to infer target-specific policy. + + Returns: + Tuple[List[torch._ops.OpOverload], Optional[Callable[[torch.fx.Node], bool]]]: + A list of op overloads to keep intact, and an optional filter + function that returns True when an op should not be decomposed. + + """ + ops_to_not_decompose_if_quant_op = { + torch.ops.aten.eye.default, + torch.ops.aten.hardsigmoid.default, + torch.ops.aten.hardswish.default, + torch.ops.aten.linear.default, + torch.ops.aten.linspace.default, + } + ops_to_not_decompose_if_fp = { + torch.ops.aten.eye.default, + torch.ops.aten.logit.default, + torch.ops.aten.linear.default, + torch.ops.aten.linspace.default, + } + ops_to_not_decompose_always = { + torch.ops.aten.logit.default, + } + ops_to_not_decompose_if_integer = { + torch.ops.aten.eye.default, + torch.ops.aten.linspace.default, + } + + def filter_fn(node: torch.fx.Node) -> bool: + """Filter function applied to ops in 'ops_to_not_decompose'. + Returns True if the op should not be decomposed. + If this function returns True, the partitioner *must* accept the node, or the lowering fails. + + Args: + node (torch.fx.Node): FX node to evaluate. + + Returns: + bool: True to keep the op intact; otherwise, False. + + """ + if ( + self.tosa_spec.support_float() + and node.target in ops_to_not_decompose_if_fp + ): + return True + + dq = ( + torch.ops.quantized_decomposed.dequantize_per_tensor.default, + torch.ops.quantized_decomposed.dequantize_per_channel.default, + ) + q = ( + torch.ops.quantized_decomposed.quantize_per_tensor.default, + torch.ops.quantized_decomposed.quantize_per_channel.default, + ) + + if node.target in ops_to_not_decompose_if_quant_op: + # Assume we should not decompose the operator (it is quantized) + correct_output_quant = True + correct_input_quant = True + + input_nodes = node.all_input_nodes + output_nodes = node.users + + for inp in input_nodes: + if inp.target not in dq: + correct_input_quant = False + + for out in output_nodes: + if out.target not in q: + correct_output_quant = False + # In some cases, a linear is quantized together with its activation. + if ( + node.target == torch.ops.aten.linear.default + and len(output_nodes) == 1 + and list(output_nodes)[0].target + in (torch.ops.aten.relu.default, torch.ops.aten.hardtanh.default) + ): + correct_output_quant = True + + if correct_input_quant and correct_output_quant: + return True + + if node.target in ops_to_not_decompose_if_integer: + # We only want to tag nodes as do_not_decompose if we are sure that + # we can partition them. We partition them if one or more of the + # following is true: + # 1. The node outputs an integer type. + # 2. All users cast the output to an integer type. + + dtype = get_first_fake_tensor(node).dtype + if not dtype.is_floating_point and not dtype.is_complex: + return True + + output_nodes = node.users + for user in output_nodes: + if user.target != torch.ops.aten.to.dtype: + return False + else: + cast_dtype = get_first_fake_tensor(user).dtype + if cast_dtype.is_complex or cast_dtype.is_floating_point: + return False + return True + + if node.target in ops_to_not_decompose_if_fp: + if self.tosa_spec.support_float(): + return True + if node.target in ops_to_not_decompose_always: + return True + return False + + ops_to_not_decompose = list( + ops_to_not_decompose_always + | ops_to_not_decompose_if_quant_op + | ops_to_not_decompose_if_fp + | ops_to_not_decompose_if_integer + ) + + if not self.tosa_spec.is_U55_subset: + # Tosa operator "RESIZE" is not supported on U55. Since upsample_bilinear2d + # and upsample_nearest2d decompose into that it will not be possible to + # delegate those operators on U55. If we have said here to not decompose + # them there will be an error saying the operator was not decomposed. It + # will not be possible for it to end up on either CPU or NPU. + ops_to_not_decompose.append(torch.ops.aten.upsample_nearest2d.vec) + ops_to_not_decompose.append(torch.ops.aten.upsample_bilinear2d.vec) + + return (ops_to_not_decompose, filter_fn) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/README.md new file mode 100644 index 0000000..9ee41b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/README.md @@ -0,0 +1,5 @@ +# License + +The FlatBuffer schema (fbs) files originates from +https://git.mlplatform.org/tosa/reference_model.git/ and are relicensed under the BSD-style license +file found in the [LICENSE](../../../../LICENSE) file in the root directory of this source tree. \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/tosa_1.0.fbs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/tosa_1.0.fbs new file mode 100644 index 0000000..e58682d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/schemas/tosa_1.0.fbs @@ -0,0 +1,559 @@ +// Copyright 2025 Arm Limited and/or its affiliates. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +namespace tosa; + +// This corresponds to the version. +file_identifier "TOSA"; +// File extension of any written files. +file_extension "tosa"; + +// NOTE: New values added to the schema should be placed +// at the end of the list in order to keep schema stable. + +enum DType:uint32 { + UNKNOWN = 0, + BOOL, + INT4, + INT8, + INT16, + INT32, + INT48, + FP32, + FP16, + BF16, + SHAPE, + FP8E4M3, + FP8E5M2, +} + +enum ResizeMode:uint32 { + UNKNOWN = 0, + NEAREST, + BILINEAR, +} + +enum NanPropagationMode:uint32 { + UNKNOWN = 0, + PROPAGATE, + IGNORE, +} + +enum RoundingMode:uint32 { + UNKNOWN = 0, + SINGLE_ROUND, + INEXACT_ROUND, + DOUBLE_ROUND +} + +enum Op:uint32 { + UNKNOWN = 0, + ARGMAX, + AVG_POOL2D, + CONV2D, + CONV3D, + DEPTHWISE_CONV2D, + FFT2D, + MATMUL, + MAX_POOL2D, + RFFT2D, + TRANSPOSE_CONV2D, + CLAMP, + ERF, + SIGMOID, + TANH, + ADD, + ARITHMETIC_RIGHT_SHIFT, + BITWISE_AND, + BITWISE_OR, + BITWISE_XOR, + INTDIV, + LOGICAL_AND, + LOGICAL_LEFT_SHIFT, + LOGICAL_RIGHT_SHIFT, + LOGICAL_OR, + LOGICAL_XOR, + MAXIMUM, + MINIMUM, + MUL, + POW, + SUB, + TABLE, + ABS, + BITWISE_NOT, + CEIL, + CLZ, + COS, + EXP, + FLOOR, + LOG, + LOGICAL_NOT, + NEGATE, + RECIPROCAL, + RSQRT, + SIN, + SELECT, + EQUAL, + GREATER, + GREATER_EQUAL, + REDUCE_ALL, + REDUCE_ANY, + REDUCE_MAX, + REDUCE_MIN, + REDUCE_PRODUCT, + REDUCE_SUM, + CONCAT, + PAD, + RESHAPE, + REVERSE, + SLICE, + TILE, + TRANSPOSE, + GATHER, + SCATTER, + RESIZE, + CAST, + RESCALE, + CONST, + IDENTITY, + CUSTOM, + COND_IF, + WHILE_LOOP, + VARIABLE, + VARIABLE_WRITE, + VARIABLE_READ, + CONST_SHAPE, +} + +union Attribute { + ArgMaxAttribute, + AvgPool2dAttribute, + Conv2dAttribute, + Conv3dAttribute, + DepthwiseConv2dAttribute, + FFT2dAttribute, + MatMulAttribute, + MaxPool2dAttribute, + RFFT2dAttribute, + TransposeConv2dAttribute, + ClampAttribute, + ErfAttribute, + SigmoidAttribute, + TanhAttribute, + AddAttribute, + ArithmeticRightShiftAttribute, + BitwiseAndAttribute, + BitwiseOrAttribute, + BitwiseXorAttribute, + IntDivAttribute, + LogicalAndAttribute, + LogicalLeftShiftAttribute, + LogicalRightShiftAttribute, + LogicalOrAttribute, + LogicalXorAttribute, + MaximumAttribute, + MinimumAttribute, + MulAttribute, + PowAttribute, + SubAttribute, + TableAttribute, + AbsAttribute, + BitwiseNotAttribute, + CeilAttribute, + ClzAttribute, + CosAttribute, + ExpAttribute, + FloorAttribute, + LogAttribute, + LogicalNotAttribute, + NegateAttribute, + ReciprocalAttribute, + RsqrtAttribute, + SinAttribute, + SelectAttribute, + EqualAttribute, + GreaterAttribute, + GreaterEqualAttribute, + ReduceAllAttribute, + ReduceAnyAttribute, + ReduceMaxAttribute, + ReduceMinAttribute, + ReduceProductAttribute, + ReduceSumAttribute, + ConcatAttribute, + PadAttribute, + ReshapeAttribute, + ReverseAttribute, + SliceAttribute, + TileAttribute, + TransposeAttribute, + GatherAttribute, + ScatterAttribute, + ResizeAttribute, + CastAttribute, + RescaleAttribute, + ConstAttribute, + IdentityAttribute, + CustomAttribute, + CondIfAttribute, + WhileLoopAttribute, + VariableAttribute, + VariableWriteAttribute, + VariableReadAttribute, + ConstShapeAttribute, +} + +table ArgMaxAttribute { + axis: int32; + nan_mode: NanPropagationMode; +} + +table AvgPool2dAttribute { + kernel: [int32]; + stride: [int32]; + pad: [int32]; + acc_type: DType; +} + +table Conv2dAttribute { + pad: [int32]; + stride: [int32]; + dilation: [int32]; + local_bound: bool; + acc_type: DType; +} + +table Conv3dAttribute { + pad: [int32]; + stride: [int32]; + dilation: [int32]; + local_bound: bool; + acc_type: DType; +} + +table DepthwiseConv2dAttribute { + pad: [int32]; + stride: [int32]; + dilation: [int32]; + local_bound: bool; + acc_type: DType; +} + +table FFT2dAttribute { + inverse: bool; + local_bound: bool; +} + +table MatMulAttribute { +} + +table MaxPool2dAttribute { + kernel: [int32]; + stride: [int32]; + pad: [int32]; + nan_mode: NanPropagationMode; +} + +table RFFT2dAttribute { + local_bound: bool; +} + +table TransposeConv2dAttribute { + out_pad: [int32]; + stride: [int32]; + local_bound: bool; + acc_type: DType; +} + +table ClampAttribute { + min_val: [ubyte] (force_align: 8); + max_val: [ubyte] (force_align: 8); + nan_mode: NanPropagationMode; +} + +table ErfAttribute { +} + +table SigmoidAttribute { +} + +table TanhAttribute { +} + +table AddAttribute { +} + +table ArithmeticRightShiftAttribute { + round: bool; +} + +table BitwiseAndAttribute { +} + +table BitwiseOrAttribute { +} + +table BitwiseXorAttribute { +} + +table IntDivAttribute { +} + +table LogicalAndAttribute { +} + +table LogicalLeftShiftAttribute { +} + +table LogicalRightShiftAttribute { +} + +table LogicalOrAttribute { +} + +table LogicalXorAttribute { +} + +table MaximumAttribute { + nan_mode: NanPropagationMode; +} + +table MinimumAttribute { + nan_mode: NanPropagationMode; +} + +table MulAttribute { +} + +table PowAttribute { +} + +table SubAttribute { +} + +table TableAttribute { +} + +table AbsAttribute { +} + +table BitwiseNotAttribute { +} + +table CeilAttribute { +} + +table ClzAttribute { +} + +table CosAttribute { +} + +table ExpAttribute { +} + +table FloorAttribute { +} + +table LogAttribute { +} + +table LogicalNotAttribute { +} + +table NegateAttribute { +} + +table ReciprocalAttribute { +} + +table RsqrtAttribute { +} + +table SinAttribute { +} + +table SelectAttribute { +} + +table EqualAttribute { +} + +table GreaterAttribute { +} + +table GreaterEqualAttribute { +} + +table ReduceAllAttribute { + axis: int32; +} + +table ReduceAnyAttribute { + axis: int32; +} + +table ReduceMaxAttribute { + axis: int32; + nan_mode: NanPropagationMode; +} + +table ReduceMinAttribute { + axis: int32; + nan_mode: NanPropagationMode; +} + +table ReduceProductAttribute { + axis: int32; +} + +table ReduceSumAttribute { + axis: int32; +} + +table ConcatAttribute { + axis: int32; +} + +table PadAttribute { +} + +table ReshapeAttribute { +} + +table ReverseAttribute { + axis: int32; +} + +table SliceAttribute { +} + +table TileAttribute { +} + +table TransposeAttribute { + perms: [int32]; +} + +table GatherAttribute { +} + +table ScatterAttribute { +} + +table ResizeAttribute { + mode: ResizeMode; +} + +table CastAttribute { +} + +table RescaleAttribute { + scale32: bool; + rounding_mode: RoundingMode; + per_channel: bool; + input_unsigned: bool; + output_unsigned: bool; +} + +table ConstAttribute { + // value is stored in output TosaTensor +} + +table IdentityAttribute { +} + +table CustomAttribute { + operator_name:string; + domain_name:string; + implementation_attrs:[ubyte]; +} + +table CondIfAttribute { + then_graph: string; + else_graph: string; +} + +table WhileLoopAttribute { + cond_graph: string; + body_graph: string; +} + +table VariableAttribute { +} + +table VariableWriteAttribute { +} + +table VariableReadAttribute { +} + +table ConstShapeAttribute { + // value is stored in output TosaTensor +} + + +table Version { + _major: int32 = -1; + _minor: int32 = -1; + _patch: int32 = -1; + _draft: bool = true; +} + +table TosaTensor { + name:string; // name of the tensor, used for solving dependency + shape:[int32]; // shape of the tensor + type:DType; // data type of the tensor + data: [ubyte] (force_align: 8); // raw data array if it's a constant tensor. + variable: bool; // is this a variable tensor + is_unranked: bool; // whether this is an unranked tensor + variable_name:string; // name for variable attribute + + // In a model that is larger than 2GB, then tensors instead uses the following + // attributes to find stored data, which is outside of flatbuffers + // the offset is calculated relative to the beginning of the file and is only + // valid if > 1. + offset: ulong; + size: ulong; +} + +table TosaShape { + name: string; // name of the shape + rank: uint32; // rank of the shape + data: [ubyte] (force_align: 8); // raw data array if it's a constant shape +} + +table OpLocation { + text: string; // Opaque string, interpretted by user +} + +table TosaOperator { + op:Op; // operator enum + attribute:Attribute; // union structure. operator attribute + inputs:[string]; // list of input tensor or shape names + outputs:[string]; // list of output tensor or shape names + location: OpLocation; // location of this Op in mlir +} + +table TosaBasicBlock { + name:string; // basic block name + operators:[TosaOperator]; // operators array + tensors:[TosaTensor]; // tensors array + inputs:[string]; // name of graph inputs + outputs:[string]; // name of graph outputs + shapes:[TosaShape]; // shapes array +} + +table TosaRegion { + name:string; // name of region + blocks:[TosaBasicBlock]; // basic blocks array +} + +table TosaGraph { + version:Version (required); + regions:[TosaRegion]; // regions array +} + +root_type TosaGraph; \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/specification.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/specification.py new file mode 100644 index 0000000..b5b9613 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/specification.py @@ -0,0 +1,406 @@ +# Copyright 2024-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Provide TOSA specification parsing and context utilities. + +Use these helpers to parse and validate TOSA profile/extension strings and to +manage a lowering-time context for the active specification. + +""" + +import contextvars +import re +from typing import Dict, Generic, List, Set, TypeVar + +from packaging.version import Version + +T = TypeVar("T") + + +class TosaSpecMapping(Generic[T]): + def __init__(self): + self._mapping: Dict[TosaSpecification, List[T]] = {} + + def add(self, spec: "TosaSpecification", value: T) -> None: + """ + Adds a value to the mapping for the given TOSA specification. + The specification is normalized to its canonical form, which means that + only the version and profiles are considered, without extensions. + This allows for grouping of values under the same TOSA specification + regardless of the extensions they may have. + """ + + if spec.is_U55_subset or spec.extensions: + raise ValueError( + f"TosaSpecMapping does not support extensions, got: {spec}" + ) + + if isinstance(spec, Tosa_1_00) and len(spec.profiles) > 1: + raise ValueError( + f"TosaSpecMapping does not support multiple profiles, got: {spec}" + ) + + norm_spec = spec._canonical_key() + if norm_spec not in self._mapping: + self._mapping[norm_spec] = [] + self._mapping[norm_spec].append(value) + + @staticmethod + def _get_base_specs(spec: "TosaSpecification") -> List["TosaSpecification"]: + # Handles combined TOSA-1.0+FP+INT, etc. + if isinstance(spec, Tosa_1_00): + profiles: Set[str] = set(spec.profiles) + if profiles == {"FP", "INT"}: + version = spec.version + return [ + TosaSpecification.create_from_string(f"TOSA-{version}+FP"), + TosaSpecification.create_from_string(f"TOSA-{version}+INT"), + ] + return [spec] + + def get(self, spec: "TosaSpecification") -> List[T]: + """ + Returns a list of values associated with the given TOSA specification. + The specification is normalized to its canonical form, which means that + only the version and profiles are considered, without extensions. + """ + + base_specs = self._get_base_specs(spec) + result: List[T] = [] + for base in base_specs: + norm_base = base._canonical_key() + result.extend(self._mapping.get(norm_base, [])) + if len(result) == 0: + raise KeyError(f"No values found for TOSA specification: {spec}") + + return result # Do not deduplicate with set(), as values may be unhashable + + +class TosaSpecification: + """Represent a TOSA specification. + + A specification includes a semantic version, one or more profiles, and + optional extensions and levels (for example ``8k``). + The encoded form follows ``TOSA-..+[+][+...]``. + Profiles use uppercase (for example ``INT``, ``FP``); levels and extensions + use lowercase. + + Attributes: + version (Version): Parsed TOSA semantic version. + is_U55_subset (bool): True if the ``u55`` subset is requested. + + """ + + version: Version + is_U55_subset: bool + extensions: List[str] + + def support_integer(self) -> bool: + """Return True if integer operations are supported.""" + raise NotImplementedError + + def support_float(self) -> bool: + """Return True if floating-point operations are supported.""" + raise NotImplementedError + + def support_extension(self, extension: str) -> bool: + """Return True if an extension is supported and enabled. + + Args: + extension (str): Extension name (for example ``int4``, ``bf16``). + + Returns: + bool: True if the extension is valid for the active profiles and selected. + + """ + raise NotImplementedError + + def __init__(self, version: Version, extras: List[str]): + """Initialize the base specification. + + Args: + version (Version): Parsed TOSA semantic version. + extras (List[str]): Remaining tokens such as profiles, levels, and extensions. + + """ + self.version = version + self.extensions = [] + + self.is_U55_subset = "u55" in extras + if self.is_U55_subset: + extras.remove("u55") + + @staticmethod + def create_from_string(repr: str) -> "TosaSpecification": + """Create a specification from a standard string format. + + Example: ``TOSA-1.00.0+INT+FP+int4+cf``. + + Args: + repr (str): Standard representation string. + + Returns: + TosaSpecification: Parsed specification instance. + + Raises: + ValueError: If the representation is malformed or version is unsupported. + + """ + pattern = r"^(TOSA)-([\d.]+)\+(.+)$" + match = re.match(pattern, repr) + if match: + name = match.group(1) + version = Version(match.group(2)) + extras = match.group(3).split("+") + if name != "TOSA": + raise ValueError(f"Malformed TOSA specification representation: {repr}") + match version: + case _ if version.major == 1 and version.minor == 0: + return Tosa_1_00(version, extras) + case _: + raise ValueError(f"Wrong TOSA version: {version} from {repr}") + + raise ValueError(f"Failed to parse TOSA specification representation: {repr}") + + def _canonical_key(self) -> "TosaSpecification": + """ + Returns a new TosaSpecification instance with only version and profiles (no extensions). + """ + raise NotImplementedError + + +class Tosa_1_00(TosaSpecification): + """Provide TOSA 1.00 profile and extension semantics. + + This variant validates profiles (``INT``, ``FP``), the optional ``8k`` level, + and allowed extensions based on the selected profiles. + + Attributes: + profiles (List[str]): Selected profiles, e.g., ``["INT"]`` or ``["INT", "FP"]``. + level_8k (bool): True if the ``8k`` level is enabled. + extensions (List[str]): Enabled extensions valid for the chosen profiles. + + """ + + profiles: List[str] + level_8k: bool + extensions: List[str] + + available_profiles = ["INT", "FP"] + valid_extensions = { + "INT": ["int16", "int4", "var", "cf", "u55"], + "FP": ["bf16", "fp8e4m3", "fp8e5m2", "fft", "var", "cf"], + } + + def __init__(self, version: Version, extras: List[str]): + """Initialize the 1.00 specification and validate extras. + + Args: + version (Version): Semantic version (major=1, minor=0). + extras (List[str]): Tokens including profiles, level, and extensions. + + Raises: + ValueError: If no/too many profiles are provided or extensions are invalid. + + """ + super().__init__(version, extras) + + # Check that we have at least one profile in the extensions list + if [e in Tosa_1_00.available_profiles for e in extras].count(True) == 0: + raise ValueError( + f"No profile ({Tosa_1_00.available_profiles}) found in: {extras}." + ) + + # and not more than number of available profiles + if [e in Tosa_1_00.available_profiles for e in extras].count(True) > len( + Tosa_1_00.available_profiles + ): + raise ValueError( + f"Too many profiles ({Tosa_1_00.available_profiles}) found in: {extras}." + ) + + # The list contains one profile at least, so pick them + self.profiles = [e for e in extras if e in Tosa_1_00.available_profiles] + for p in self.profiles: + extras.remove(p) + + self.level_8k = "8k" in extras + if self.level_8k: + extras.remove("8k") + + combined_extensions = [] + for p in self.profiles: + combined_extensions += Tosa_1_00.valid_extensions[p] + + if not all(e in combined_extensions for e in extras): + raise ValueError( + f"Bad extensions for TOSA-{version}{self._get_profiles_string()}: {extras}" + ) + + # all the rest of the extras are handled extensions + self.extensions = extras + + def _get_profiles_string(self) -> str: + """Return the ``+``-joined profile segment (e.g., ``+INT+FP``).""" + return "".join(["+" + p for p in self.profiles]) + + def _get_extensions_string(self) -> str: + """Return the ``+``-joined extensions segment (e.g., ``+int4+cf``).""" + return "".join(["+" + e for e in self.extensions]) + + def __repr__(self): + """Return the standard specification string format. + + Returns: + str: Standard form like ``TOSA-1.00.0+INT+8k+int4``. + + """ + extensions = self._get_extensions_string() + if self.level_8k: + extensions += "+8k" + if self.is_U55_subset: + extensions += "+u55" + return f"TOSA-{self.version}{self._get_profiles_string()}{extensions}" + + def __hash__(self) -> int: + """Return a stable hash for use in sets and dict keys. + + Returns: + int: Hash value derived from version and profiles. + + """ + return hash(str(self.version) + self._get_profiles_string()) + + def __eq__(self, other: object) -> bool: + """Return True if another instance represents the same spec. + + Args: + other (object): Object to compare. + + Returns: + bool: True if versions and profiles match. + + """ + if isinstance(other, Tosa_1_00): + return (self.version == other.version) and ( + self._get_profiles_string() == other._get_profiles_string() + ) + return False + + def support_integer(self): + """Return True if the ``INT`` profile is present.""" + return "INT" in self.profiles + + def support_float(self): + """Return True if the ``FP`` profile is present.""" + return "FP" in self.profiles + + def support_extension(self, extension: str) -> bool: + """Return True if an extension is supported and enabled. + + Args: + extension (str): Extension name (for example ``int4``, ``bf16``). + + Returns: + bool: True if the extension is valid for the active profiles and selected. + + """ + for p in self.profiles: + if extension in self.valid_extensions[p] and extension in self.extensions: + return True + + return False + + def _canonical_key(self) -> "Tosa_1_00": + """ + Returns a new Tosa_1_00 instance with only major.minor version and profiles (no extensions). + Patch version is set to zero for normalization. + """ + from packaging.version import Version + + norm_version = Version(f"{self.version.major}.{self.version.minor}.0") + return Tosa_1_00(norm_version, self.profiles.copy()) + + +class TosaLoweringContext: + """Manage the TOSA specification context for lowering. + + For now, only the active ``TosaSpecification`` is tracked, but this can be + extended to carry additional lowering policies or configuration. + + Attributes: + tosa_spec_var (contextvars.ContextVar): Context variable storing the active spec. + spec (TosaSpecification): Specification passed to the context manager. + + """ + + # Define a context variable for the spec + tosa_spec_var: contextvars.ContextVar = contextvars.ContextVar("tosa_spec") + + def __init__(self, spec: TosaSpecification): + """Initialize the lowering context with a specification. + + Args: + spec (TosaSpecification): Active specification to put into context. + + """ + self.spec = spec + + def __enter__(self): + """Set the context variable and return self. + + Returns: + TosaLoweringContext: This context manager instance. + + """ + # Set the spec in the context variable and store the token for later reset + self.token = TosaLoweringContext.tosa_spec_var.set(self.spec) + return self + + def __exit__(self, exc_type, exc_value, traceback): + """Reset the context variable to its previous state. + + Args: + exc_type (type | None): Exception type, if any. + exc_value (BaseException | None): Exception instance, if any. + traceback (TracebackType | None): Traceback, if any. + + """ + # Reset the context variable to its previous state + TosaLoweringContext.tosa_spec_var.reset(self.token) + + +def get_context_spec() -> TosaSpecification: + """Get the current ``TosaSpecification`` from the lowering context. + + Returns: + TosaSpecification: Active specification retrieved from the context var. + + Raises: + RuntimeError: If called outside a ``TosaLoweringContext``. + + """ + try: + return TosaLoweringContext.tosa_spec_var.get() + except LookupError: + raise RuntimeError("Function must be executed within a TosaLoweringContext") + + +def tosa_spec_in_set(spec: TosaSpecification, specs: Set[TosaSpecification]) -> bool: + """Check if a specification matches any in a set, considering base specs. + + Args: + spec (TosaSpecification): Specification to check. + specs (Set[TosaSpecification]): Set of specifications to match against. + + Returns: + bool: True if a match is found, False otherwise. + + """ + base_specs = TosaSpecMapping._get_base_specs(spec) + for base in base_specs: + if base in specs: + return True + return False diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/utils.py new file mode 100644 index 0000000..df77153 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/tosa/utils.py @@ -0,0 +1,304 @@ +# Copyright 2023-2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +"""Utility helpers for building TOSA graphs in the Arm backend.""" + +import logging +from typing import Any + +import numpy as np + +import sympy # type: ignore + +import torch +import tosa_serializer as ts + +from executorch.backends.arm.tosa.mapping import extract_tensor_meta +from executorch.backends.arm.tosa.specification import TosaSpecification + +from torch._subclasses.fake_tensor import FakeTensor +from torch.fx import Node + +logger = logging.getLogger(__name__) + + +def are_fake_tensors_broadcastable( + fake_tensors: list[FakeTensor], +) -> tuple[bool, list[int]]: + """Determine whether the fake tensors share a broadcastable shape. + + Args: + fake_tensors (list[FakeTensor]): Fake tensors whose shapes should + be validated for broadcasting. + + Returns: + tuple[bool, list[int]]: Tuple where the first element indicates + whether broadcasting is possible and the second element contains + the broadcast shape. The shape list is empty when broadcasting + fails. + + Raises: + RuntimeError: Raised when fewer than two tensors are supplied. + + """ + if len(fake_tensors) < 1: + raise RuntimeError(f"Expected 2 or more tensors got {len(fake_tensors)}") + + reversed_shapes = [list(reversed(ft.shape)) for ft in fake_tensors] + sorted_shapes = sorted(reversed_shapes, key=len, reverse=True) + + broadcast_shape = [] + for dim in range(len(sorted_shapes[0])): + curr_dim = 1 + for shape in sorted_shapes: + if dim >= len(shape): + continue + if curr_dim == 1 and shape[dim] != 1: + curr_dim = shape[dim] + elif shape[dim] == 1: + continue + elif curr_dim != 1 and shape[dim] != curr_dim: + return (False, []) + broadcast_shape.append(curr_dim) + return (True, list(reversed(broadcast_shape))) + + +def broadcast_tensors( + tosa_fb, nodes: list[Node], tosa_spec: TosaSpecification +) -> list[Any]: + """Broadcast the FX nodes to a shared shape inside the TOSA graph. + + This mirrors ``reshape_for_broadcast`` but also emits the tile operators + needed to materialize the broadcast and supports any number of inputs. + + Args: + tosa_fb (Any): TOSA graph builder that receives the broadcast + operators. + nodes (list[Node]): FX nodes whose tensor metadata should be + broadcast. + tosa_spec (TosaSpecification): Active TOSA specification used to + decode tensor metadata. + + Returns: + list[Any]: Broadcast versions of the inputs. Each element is either + the original FX node or a TOSA serializer tensor, ordered to match + ``nodes``. + + Raises: + RuntimeError: If the supplied nodes are not broadcastable. + + """ + index_fake_tensors = [node.meta["val"] for node in nodes] + broadcastable, common_shape = are_fake_tensors_broadcastable(index_fake_tensors) + if not broadcastable: + raise RuntimeError("FakeTensors are not broadcastable") + + broadcast_tensors = [] + for node in nodes: + tens_dtype, tens_shape, _ = extract_tensor_meta(node.meta, tosa_spec) + list_tens_shape = list(tens_shape) + # Already in the right shape we can just add it to the list. + if list_tens_shape == common_shape: + broadcast_tensors.append(node) + continue + + rank_diff = len(common_shape) - len(tens_shape) + new_shape = [1] * rank_diff + list_tens_shape + reshaped = tosa_fb.addIntermediate( + new_shape, + tens_dtype, + ) + + build_reshape_tosa(tosa_fb, node.name, new_shape, reshaped.name) + + tiled = tosa_fb.addIntermediate(common_shape, tens_dtype) + multipliers = [ + comm if curr == 1 else 1 for comm, curr in zip(common_shape, new_shape) + ] + multiple_shapes = tosa_fb.addConst( + (len(multipliers),), + ts.DType.SHAPE, + multipliers, + name=f"{node.name}_multiples", + ) + + attr = ts.TosaSerializerAttribute() + attr.TileAttribute() + tosa_fb.addOperator( + ts.Op.TILE, + [reshaped.name, multiple_shapes.name], + [tiled.name], + attr, + ) + + broadcast_tensors.append(tiled) + + return broadcast_tensors + + +def build_reshape_tosa( + tosa_graph, input_name, new_shape, output_name, shape_name_override="" +): + """Insert a TOSA reshape operator using the v1.0 semantics. + + Args: + tosa_graph (Any): Graph builder used to emit TOSA operators. + input_name (str): Name of the tensor that should be reshaped. + new_shape (list[int]): Target tensor shape. + output_name (str): Name assigned to the reshaped tensor. + shape_name_override (str): Optional override for the shape constant + name. + + """ + shape = tosa_graph.addConst( + np.array(new_shape).shape, + ts.DType.SHAPE, + np.array(new_shape), + name=shape_name_override if shape_name_override else output_name + "_shape", + ) + + attr = ts.TosaSerializerAttribute() + attr.ReshapeAttribute() + tosa_graph.addOperator( + ts.Op.RESHAPE, + [input_name, shape.name], + [output_name], + attr, + ) + + +def tosa_shape(shape, dim_order): + """Reorder a shape tuple into TOSA layout while resolving symints. + + Args: + shape (Sequence[int | torch.SymInt]): Original tensor shape, + possibly containing ``torch.SymInt``. + dim_order (Sequence[int]): Desired dimension order for the output + shape. + + Returns: + list[int]: List containing the reordered dimensions where symbolic + values become ``-1``. + + """ + reordered = tuple([shape[dim] for dim in dim_order]) + # Dynamic shapes in executorch are represented with torch.SymInt objects in the shapes, + # in TOSA we do not have this concept and instead use -1. + removed_symints = tuple( + [-1 if isinstance(d, torch.SymInt) else d for d in reordered] + ) + return list(removed_symints) + + +def get_resize_parameters_1d( + input_size: int | torch.SymInt, + output_size: int | torch.SymInt, + resize_mode: int, + align_corners: bool, +): + """Compute resize coefficients for a single spatial dimension. + + Args: + input_size (int | torch.SymInt): Input size for the axis, possibly + symbolic. + output_size (int | torch.SymInt): Output size for the axis, possibly + symbolic. + resize_mode (int): Target resize mode defined by TOSA. + align_corners (bool): Whether the resize should align the corner + pixels. + + Returns: + tuple[int, int, int, int]: Numerator, denominator, offset, and border + terms encoded as integers. + + Raises: + RuntimeError: If symbolic shapes are used with ``align_corners`` or if + the computed ratio or border is not constant. + + """ + # We don't support align_corners for symbolic shapes, because handling the edge case where size == 1 is tricky. + if align_corners: + if (not isinstance(input_size, int)) or (not isinstance(output_size, int)): + raise RuntimeError( + "We do not support align_corners=True for symbolic shapes." + ) + + # SymInt seems to not actually work for symbolic expressions, so use the underlying sympy objects instead + input_size = ( + input_size.node._expr if isinstance(input_size, torch.SymInt) else input_size + ) + output_size = ( + output_size.node._expr if isinstance(output_size, torch.SymInt) else output_size + ) + if align_corners and input_size > 1 and output_size > 1: + scale_n = output_size - 1 + else: + scale_n = output_size + if align_corners and input_size > 1 and output_size > 1: + scale_d = input_size - 1 + else: + scale_d = input_size + ratio = scale_n / scale_d + if not sympy.sympify(ratio).is_constant(): + raise RuntimeError( + "Resize requires a constant ratio: " + str(ratio) + " is not constant!" + ) + gcd = sympy.gcd(scale_n, scale_d) + scale_n = 2 * scale_n // gcd + scale_d = 2 * scale_d // gcd + # These should always be whole integers, based on the above calculations + scale_n = int(scale_n.evalf()) + scale_d = int(scale_d.evalf()) + + if align_corners: + offset = 0 + else: + # Half pixel centers so input and output sampling positions are offset by 1/2 pixel. + offset = scale_d // 2 - scale_n // 2 + + # Calculate border to maintain the correct the output size. + # Note that this should always result in a constant value, as the ratio is constant. + border = scale_d * (output_size - 1) - scale_n * (input_size - 1) + offset + + if not sympy.sympify(border).is_constant(): + raise RuntimeError( + "Resize requires a constant border: " + str(border) + " is not constant!" + ) + + border = int(sympy.sympify(border).evalf()) + return scale_n, scale_d, offset, border + + +def get_resize_parameters( + input_size_xy: tuple[int | torch.SymInt, int | torch.SymInt], + output_size_xy: tuple[int | torch.SymInt, int | torch.SymInt], + resize_mode: int, + align_corners: bool, +) -> tuple[torch.IntTensor, ...]: + """Calculate 2D resize parameters for TOSA emission. + + Args: + input_size_xy (tuple[int | torch.SymInt, int | torch.SymInt]): Height + and width of the input tensor. + output_size_xy (tuple[int | torch.SymInt, int | torch.SymInt]): Height + and width of the output tensor. + resize_mode (int): TOSA resize mode used for coefficient generation. + align_corners (bool): Whether to align corner pixels between input and + output. + + Returns: + tuple[torch.IntTensor, ...]: Four-element tuple of tensors describing + the scale numerator, scale denominator, offset, and border for Y + and X dimensions. + + """ + # Get the parameters for each dimension independently + y_params = get_resize_parameters_1d( + input_size_xy[0], output_size_xy[0], resize_mode, align_corners + ) + x_params = get_resize_parameters_1d( + input_size_xy[1], output_size_xy[1], resize_mode, align_corners + ) + # Combine them together, so we return four 2-element tensors (scale_n, scale_d, offset, border) + return tuple(map(torch.IntTensor, zip(y_params, x_params))) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/_factory.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/_factory.py new file mode 100644 index 0000000..23d8215 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/_factory.py @@ -0,0 +1,59 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.ethosu import EthosUCompileSpec, EthosUPartitioner +from executorch.backends.arm.quantizer import ( + EthosUQuantizer, + TOSAQuantizer, + VgfQuantizer, +) +from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.vgf import VgfCompileSpec, VgfPartitioner +from executorch.exir.backend.compile_spec_schema import CompileSpec +from torch.fx.passes.operator_support import OperatorSupportBase + + +def parse_compile_spec(compile_specs: list[CompileSpec]) -> ArmCompileSpec: + output_format = None + for spec in compile_specs: + if spec.key == "output_format": + output_format = spec.value.decode() + break + else: + raise ValueError("Compile spec without output format.") + if output_format == TosaCompileSpec.get_output_format(): + return TosaCompileSpec.from_list(compile_specs) + if output_format == EthosUCompileSpec.get_output_format(): + return EthosUCompileSpec.from_list(compile_specs) + if output_format == VgfCompileSpec.get_output_format(): + return VgfCompileSpec.from_list(compile_specs) + raise ValueError(f"Unknown output format {output_format}") + + +def create_partitioner( + compile_spec: ArmCompileSpec, + additional_checks: list[OperatorSupportBase] | None = None, +): + if isinstance(compile_spec, TosaCompileSpec): + return TOSAPartitioner(compile_spec, additional_checks) + elif isinstance(compile_spec, EthosUCompileSpec): + return EthosUPartitioner(compile_spec, additional_checks) + elif isinstance(compile_spec, VgfCompileSpec): + return VgfPartitioner(compile_spec, additional_checks) + else: + raise ValueError("compile spec doesn't target any Arm Partitioner") + + +def create_quantizer(compile_spec: ArmCompileSpec): + if isinstance(compile_spec, TosaCompileSpec): + return TOSAQuantizer(compile_spec) + elif isinstance(compile_spec, EthosUCompileSpec): + return EthosUQuantizer(compile_spec) + elif isinstance(compile_spec, VgfCompileSpec): + return VgfQuantizer(compile_spec) + else: + raise ValueError("compile spec doesn't target any Arm Quantizer") diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/arm_model_evaluator.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/arm_model_evaluator.py new file mode 100644 index 0000000..3d41f71 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/util/arm_model_evaluator.py @@ -0,0 +1,388 @@ +# Copyright 2024-2026 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import json +import logging +import os +import random +import tempfile +import zipfile + +from collections import defaultdict +from pathlib import Path +from typing import Any, cast, Optional, Tuple + +import torch +from torch.nn.modules import Module +from torch.utils._pytree import tree_flatten +from torch.utils.data import DataLoader +from torchvision import datasets, transforms # type: ignore[import-untyped] + + +# Logger for outputting progress for longer running evaluation +logger = logging.getLogger(__name__) +# Explicitly set logging level: MLETORCH-893 +logger.setLevel(logging.INFO) + + +# ImageNet 224x224 transforms (Resize->CenterCrop->ToTensor->Normalize) +# If future models require different preprocessing, extend this helper accordingly. +def _get_imagenet_224_transforms(): + """Return standard ImageNet 224x224 preprocessing transforms.""" + return transforms.Compose( + [ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(mean=[0.484, 0.454, 0.403], std=[0.225, 0.220, 0.220]), + ] + ) + + +def _build_calibration_loader( + dataset: datasets.ImageFolder, max_items: int +) -> DataLoader: + """Return a DataLoader over a deterministic, shuffled subset of size <= max_items. + + Shuffles with seed: ARM_EVAL_CALIB_SEED (int) or default 1337; then selects first k and + sorts indices to keep enumeration order stable while content depends on seed. + """ + k = min(max_items, len(dataset)) + seed_env = os.getenv("ARM_EVAL_CALIB_SEED") + default_seed = 1337 + if seed_env is not None: + try: + seed = int(seed_env) + except ValueError: + logger.warning( + "ARM_EVAL_CALIB_SEED is not an int (%s); using default seed %d", + seed_env, + default_seed, + ) + seed = default_seed + else: + seed = default_seed + rng = random.Random( + seed + ) # nosec B311 - deterministic shuffling for evaluation only + indices = list(range(len(dataset))) + rng.shuffle(indices) + selected = sorted(indices[:k]) + return torch.utils.data.DataLoader( + torch.utils.data.Subset(dataset, selected), batch_size=1, shuffle=False + ) + + +def _load_imagenet_folder(directory: str) -> datasets.ImageFolder: + """Shared helper to load an ImageNet-layout folder. + + Raises FileNotFoundError for a missing directory early to aid debugging. + """ + directory_path = Path(directory) + if not directory_path.exists(): + raise FileNotFoundError(f"Directory: {directory} does not exist.") + transform = _get_imagenet_224_transforms() + return datasets.ImageFolder(directory_path, transform=transform) + + +class GenericModelEvaluator: + """Base evaluator computing quantization error metrics and optional compression ratio. + + Subclasses can extend: provide calibration (get_calibrator) and override evaluate() + to add domain specific metrics (e.g. top-1 / top-5 accuracy). + """ + + @staticmethod + def evaluate_topk( + model: Module, + dataset: datasets.ImageFolder, + batch_size: int, + topk: int = 5, + log_every: int = 50, + ) -> Tuple[float, float]: + """Evaluate model top-1 / top-k accuracy. + + Args: + model: Torch module (should be in eval() mode prior to call). + dataset: ImageFolder style dataset. + batch_size: Batch size for evaluation. + topk: Maximum k for accuracy (default 5). + log_every: Log running accuracy every N batches. + Returns: + (top1_accuracy, topk_accuracy) + """ + # Some exported / quantized models (torchao PT2E) disallow direct eval()/train(). + # Try to switch to eval mode, but degrade gracefully if unsupported. + try: + model.eval() + except NotImplementedError: + # Attempt to enable train/eval overrides if torchao helper is present. + try: + from torchao.quantization.pt2e.utils import ( # type: ignore + allow_exported_model_train_eval, + ) + + allow_exported_model_train_eval(model) + try: + model.eval() + except Exception: + logger.debug( + "Model eval still not supported after allow_exported_model_train_eval; proceeding without explicit eval()." + ) + except Exception: + logger.debug( + "Model eval() unsupported and torchao allow_exported_model_train_eval not available; proceeding." + ) + loaded_dataset = DataLoader(dataset, batch_size=batch_size, shuffle=False) + top1_correct = 0 + topk_correct = 0 + total = 0 + with torch.inference_mode(): # disable autograd + some backend optimizations + for i, (image, target) in enumerate(loaded_dataset): + prediction = model(image) + topk_indices = torch.topk(prediction, k=topk, dim=1).indices + # target reshaped for broadcasting + target_view = target.view(-1, 1) + top1_correct += (topk_indices[:, :1] == target_view).sum().item() + topk_correct += (topk_indices == target_view).sum().item() + batch_sz = image.size(0) + total += batch_sz + if (i + 1) % log_every == 0 or total == len(dataset): + logger.info( + "Eval progress: %d / %d top1=%.4f top%d=%.4f", + total, + len(dataset), + top1_correct / total, + topk, + topk_correct / total, + ) + top1_accuracy = top1_correct / len(dataset) + topk_accuracy = topk_correct / len(dataset) + return top1_accuracy, topk_accuracy + + REQUIRES_CONFIG = False + + def __init__( + self, + model_name: str, + fp32_model: torch.nn.Module, + quant_model: torch.nn.Module, + example_input: Tuple[torch.Tensor], + tosa_output_path: Optional[str], + ) -> None: + self.model_name = model_name + + self.fp32_model = fp32_model + self.quant_model = quant_model + self.example_input = example_input + + if tosa_output_path: + self.tosa_output_path = tosa_output_path + else: + self.tosa_output_path = "" + + def get_model_error(self) -> defaultdict: + """Return per-output quantization error statistics. + + Metrics (lists per output tensor): + max_error + max_absolute_error + max_percentage_error (safe-divided; zero fp32 elements -> 0%) + mean_absolute_error + """ + fp32_outputs, _ = tree_flatten(self.fp32_model(*self.example_input)) + quant_outputs, _ = tree_flatten(self.quant_model(*self.example_input)) + + model_error_dict = defaultdict(list) + + for fp32_output, quant_output in zip(fp32_outputs, quant_outputs): + difference = fp32_output - quant_output + # Avoid divide by zero: elements where fp32 == 0 produce 0% contribution + percentage_error = torch.where( + fp32_output != 0, + difference / fp32_output * 100, + torch.zeros_like(difference), + ) + model_error_dict["max_error"].append(torch.max(difference).item()) + model_error_dict["max_absolute_error"].append( + torch.max(torch.abs(difference)).item() + ) + model_error_dict["max_percentage_error"].append( + torch.max(percentage_error).item() + ) + model_error_dict["mean_absolute_error"].append( + torch.mean(torch.abs(difference).float()).item() + ) + + return model_error_dict + + def get_compression_ratio(self) -> float: + """Compute the compression ratio of the outputted TOSA flatbuffer.""" + with tempfile.NamedTemporaryFile(delete=True, suffix=".zip") as temp_zip: + with zipfile.ZipFile( + temp_zip.name, "w", compression=zipfile.ZIP_DEFLATED + ) as f: + f.write(self.tosa_output_path) + + compression_ratio = os.path.getsize( + self.tosa_output_path + ) / os.path.getsize(temp_zip.name) + + return compression_ratio + + def evaluate(self) -> dict[str, Any]: + model_error_dict = self.get_model_error() + + output_metrics = {"name": self.model_name, "metrics": dict(model_error_dict)} + + if self.tosa_output_path: + # We know output_metrics["metrics"] is list since we just defined it, safe to ignore. + output_metrics["metrics"][ # type: ignore[index] + "compression_ratio" + ] = self.get_compression_ratio() + + return output_metrics + + +class ImageNetEvaluator(GenericModelEvaluator): + """Shared evaluator behaviour for ImageNet-style classifiers. + + Provides dataset loading, calibration loader and a standard `evaluate` that + computes top-1/top-5 accuracy. + """ + + REQUIRES_CONFIG = True + + def __init__( + self, + model_name: str, + fp32_model: Module, + quant_model: Module, + example_input: Tuple[torch.Tensor], + tosa_output_path: str | None, + batch_size: int, + validation_dataset_path: str, + ) -> None: + super().__init__( + model_name, fp32_model, quant_model, example_input, tosa_output_path + ) + self._batch_size = batch_size + self._validation_set_path = validation_dataset_path + + @staticmethod + def _load_dataset(directory: str) -> datasets.ImageFolder: + return _load_imagenet_folder(directory) + + @staticmethod + def get_calibrator(training_dataset_path: str) -> DataLoader: + dataset = ImageNetEvaluator._load_dataset(training_dataset_path) + return _build_calibration_loader(dataset, 1000) + + @classmethod + def from_config( + cls, + model_name: str, + fp32_model: Module, + quant_model: Module, + example_input: Tuple[torch.Tensor], + tosa_output_path: str | None, + config: dict[str, Any], + ) -> "ImageNetEvaluator": + return cls( + model_name, + fp32_model, + quant_model, + example_input, + tosa_output_path, + batch_size=config["batch_size"], + validation_dataset_path=config["validation_dataset_path"], + ) + + def evaluate(self) -> dict[str, Any]: + dataset = self._load_dataset(self._validation_set_path) + top1, top5 = GenericModelEvaluator.evaluate_topk( + self.quant_model, dataset, self._batch_size, topk=5 + ) + output = super().evaluate() + output["metrics"]["accuracy"] = {"top-1": top1, "top-5": top5} + return output + + +evaluators: dict[str, type[GenericModelEvaluator]] = { + "generic": GenericModelEvaluator, + "mv2": ImageNetEvaluator, + "deit_tiny": ImageNetEvaluator, + "resnet18": ImageNetEvaluator, +} + + +def evaluator_calibration_data( + evaluator_name: str, + evaluator_config: str | None, +): + evaluator = evaluators[evaluator_name] + + if hasattr(evaluator, "get_calibrator"): + assert evaluator_config is not None + + config_path = Path(evaluator_config) + with config_path.open() as f: + config = json.load(f) + + # All current evaluators exposing calibration implement a uniform + # static method signature: get_calibrator(training_dataset_path: str) + # so we can call it generically without enumerating classes. + return evaluator.get_calibrator( + training_dataset_path=config["training_dataset_path"] + ) + + +def evaluate_model( + model_name: str, + intermediates: str, + target: str, + model_fp32: torch.nn.Module, + model_quant: torch.nn.Module, + example_inputs: Tuple[torch.Tensor], + evaluator_name: str, + evaluator_config: str | None, +) -> None: + evaluator = evaluators[evaluator_name] + + intermediates_path = Path(intermediates) + tosa_paths = list(intermediates_path.glob("*.tosa")) + + if evaluator.REQUIRES_CONFIG: + assert evaluator_config is not None + config_path = Path(evaluator_config) + with config_path.open() as f: + config = json.load(f) + + # Prefer a subclass provided from_config if available. + if hasattr(evaluator, "from_config"): + factory = cast(Any, evaluator.from_config) # type: ignore[attr-defined] + init_evaluator = factory( + model_name, + model_fp32, + model_quant, + example_inputs, + str(tosa_paths[0]), + config, + ) + else: + raise RuntimeError( + f"Evaluator {evaluator_name} requires config but does not implement from_config()" + ) + else: + init_evaluator = evaluator( + model_name, model_fp32, model_quant, example_inputs, str(tosa_paths[0]) + ) + + quant_metrics = init_evaluator.evaluate() + output_json_path = intermediates_path / f"{target}-quant_metrics.json" + + with output_json_path.open("w") as json_file: + json.dump(quant_metrics, json_file) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/__init__.py new file mode 100644 index 0000000..88be90e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/__init__.py @@ -0,0 +1,11 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +# + +from .backend import VgfBackend # noqa: F401 +from .compile_spec import VgfCompileSpec # noqa: F401 +from .partitioner import VgfPartitioner # noqa: F401 + +__all__ = ["VgfBackend", "VgfPartitioner", "VgfCompileSpec"] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/backend.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/backend.py new file mode 100644 index 0000000..0e931af --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/backend.py @@ -0,0 +1,172 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +# +# Main implementation of AoT flow to partition and preprocess for VGF target +# backends. This flow converts via TOSA, to an encoding of TOSA known as VGF +# this form is used where the final JIT compile is performed on target (in the +# runtime delegate executorch::runtime::BackendInterface::init +# +"""Ahead-of-time Arm VGF backend built on the shared TOSA pipeline.""" + +import logging +import os # nosec B404 - used alongside subprocess for tool invocation +import subprocess # nosec B404 - required to drive external converter CLI +import tempfile +from typing import final, List + +from executorch.backends.arm.tosa.backend import ( # type: ignore[import-not-found] + arm_get_first_delegation_tag, + TOSABackend, +) + +from executorch.backends.arm.vgf.compile_spec import ( # type: ignore[import-not-found] + VgfCompileSpec, +) +from executorch.backends.arm.vgf.model_converter import ( # type: ignore[import-not-found] + require_model_converter_binary, +) +from executorch.exir.backend.backend_details import ( # type: ignore[import-not-found] + BackendDetails, + PreprocessResult, +) +from executorch.exir.backend.compile_spec_schema import ( # type: ignore[import-not-found] + CompileSpec, +) +from torch.export.exported_program import ExportedProgram + +# debug functionality +logger = logging.getLogger(__name__) + + +@final +class VgfBackend(BackendDetails): + """BackendDetails subclass for delegation to VGF compatible devices. + + This enables encapsulated TOSA on target device and JIT compilation on + suitable platforms. + + """ + + @staticmethod + def _compile_tosa_flatbuffer( + tosa_flatbuffer: bytes, + compile_spec: VgfCompileSpec, + tag_name: str = "", + ) -> bytes: + """Compile a TOSA flatbuffer into a target-specific binary stream. + + Args: + tosa_flatbuffer (bytes): Serialized TOSA graph produced by + ``TOSABackend``. + compile_spec (VgfCompileSpec): Compile specification providing + converter flags and artifact paths. + tag_name (str): Optional suffix used when producing debug outputs. + + Returns: + bytes: Target-specific VGF binary stream. + + """ + compile_flags = compile_spec.compiler_flags + artifact_path = compile_spec.get_intermediate_path() + # Pass on the TOSA flatbuffer to the vgf compiler. + binary = vgf_compile(tosa_flatbuffer, compile_flags, artifact_path, tag_name) + return binary + + @staticmethod + def preprocess( + edge_program: ExportedProgram, + compile_specs: List[CompileSpec], + ) -> PreprocessResult: + """Lower the exported program and compile it for a VGF target. + + Args: + edge_program (ExportedProgram): Program to lower to VGF. + compile_specs (List[CompileSpec]): Serialized VGF compile specs + supplied by the frontend. + + Returns: + PreprocessResult: Result containing the compiled VGF binary. + + """ + logger.info(f"{VgfBackend.__name__} preprocess") + + compile_spec = VgfCompileSpec.from_list(compile_specs) + # deduce TOSA compile_spec from VGF compile spec. We get a new + # compile spec list, containing only elements relevant for the + # TOSABackend. + tosa_compile_spec = TOSABackend.filter_tosa_compile_specs(compile_spec) + + # Backends doesn't allow inheritance, as stated in comments in exir/backend/backend_api.py + # ('All backend implementation are final...'), so use composition instead. + # preprocess returns the serialized TOSA flatbuffer in .processed_bytes, + # which can be passed on to next compilation step. + tosa_preprocess = TOSABackend._preprocess(edge_program, tosa_compile_spec) + + tag_name = arm_get_first_delegation_tag(edge_program.graph_module) + + binary = VgfBackend._compile_tosa_flatbuffer( + tosa_preprocess.processed_bytes, compile_spec, tag_name + ) + + return PreprocessResult(processed_bytes=binary) + + +def vgf_compile( + tosa_flatbuffer: bytes, + compile_flags: List[str], + artifact_path: str | None = None, + tag_name: str = "", +): + """Invoke the VGF compiler to convert a TOSA flatbuffer. + + Args: + tosa_flatbuffer (bytes): Serialized TOSA graph produced by + ``TOSABackend``. + compile_flags (List[str]): Command-line flags forwarded to + ``model-converter``. + artifact_path (str | None): Directory where debug artifacts are saved. + tag_name (str): Optional suffix used when producing debug outputs. + + Returns: + bytes: Compiled VGF binary emitted by ``model-converter``. + + """ + with tempfile.TemporaryDirectory() as tmpdir: + + # We currently write out a flatbuffer as input to the converter + tosaname = f"output_{tag_name}.tosa" + tosa_path = os.path.join(tmpdir, tosaname) + with open(tosa_path, "wb") as f: + f.write(tosa_flatbuffer) + + additional_flags = " ".join(compile_flags) + converter_binary = require_model_converter_binary() + vgf_path = tosa_path + ".vgf" + conversion_command = ( + f"{converter_binary} {additional_flags} -i {tosa_path} -o {vgf_path}" + ) + try: + subprocess.run( # nosec B602 - shell invocation constrained to trusted converter binary + [conversion_command], shell=True, check=True, capture_output=True + ) + except subprocess.CalledProcessError as process_error: + raise RuntimeError( + f"Vgf compiler ('{conversion_command}') failed with error:\n \ + {process_error.stderr.decode()}\n \ + Stdout:\n{process_error.stdout.decode()}" + ) + + if artifact_path: + logger.info(f"Emitting debug output to: {vgf_path=}") + os.makedirs(artifact_path, exist_ok=True) + cp = f"cp {vgf_path} {artifact_path}" + subprocess.run( # nosec B602 - shell copy of trusted artifact for debugging + cp, shell=True, check=True, capture_output=False + ) + + vgf_bytes = open(vgf_path, "rb").read() + return vgf_bytes diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/compile_spec.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/compile_spec.py new file mode 100644 index 0000000..b5b13f5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/compile_spec.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec +from executorch.backends.arm.common.pipeline_config import ( # noqa: unused + ArmPassPipelineConfig, +) +from executorch.backends.arm.tosa import ( # type: ignore[import-not-found] + TosaSpecification, +) + +# debug functionality +logger = logging.getLogger(__name__) + + +class VgfCompileSpec(ArmCompileSpec): + """Compile specification for VGF-compatible targets.""" + + def __init__( + self, + tosa_spec: TosaSpecification | str | None = None, + compiler_flags: list[str] | None = None, + ): + """Normalise inputs and populate the underlying Arm compile spec. + + Args: + tosa_spec (TosaSpecification | str | None): TOSA specification to + target. Strings are parsed via + :meth:`TosaSpecification.create_from_string`. Defaults to + ``"TOSA-1.0+FP+INT"``. + compiler_flags (list[str] | None): Optional converter-backend flags. + """ + if tosa_spec is None: + tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+FP+INT") + elif isinstance(tosa_spec, str): + tosa_spec = TosaSpecification.create_from_string(tosa_spec) + + if compiler_flags is None: + compiler_flags = [] + self._set_compile_specs(tosa_spec, compiler_flags) + self.validate() + + def validate(self): + """Validate the configuration against VGF-supported TOSA profiles.""" + tosa_version = self.tosa_spec.version # type: ignore[attr-defined] + tosa_profiles = self.tosa_spec.profiles # type: ignore[attr-defined] + + if tosa_version.major != 1: + raise ValueError( + "Arm backend only supports converter-backend for TOSA version 1. " + f"Invalid TOSA version: {tosa_version}" + ) + + if "FP" not in tosa_profiles and "INT" not in tosa_profiles: + raise ValueError( + "Arm backend only supports converter-backend for FP and/or INT. " + f"Invalid TOSA profile: {tosa_profiles}" + ) + + @classmethod + def get_output_format(cls) -> str: + """Return the artifact format emitted by this compile spec.""" + return "vgf" + + def _create_default_pipeline_config(self) -> ArmPassPipelineConfig: + config = super()._create_default_pipeline_config() + # GRPHCOMP-3140 / MLETORCH-1529 + config.disable_fuse_duplicate_users() + return config diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/model_converter.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/model_converter.py new file mode 100644 index 0000000..dffbf76 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/model_converter.py @@ -0,0 +1,34 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from __future__ import annotations + +from shutil import which +from typing import Optional + +MODEL_CONVERTER_BINARY = "model-converter" +_MODEL_CONVERTER_FALLBACK_BINARY = "model_converter" + + +def find_model_converter_binary() -> Optional[str]: + """Return the name of the first model converter executable on PATH.""" + + for candidate in (MODEL_CONVERTER_BINARY, _MODEL_CONVERTER_FALLBACK_BINARY): + if which(candidate): + return candidate + return None + + +def require_model_converter_binary() -> str: + """Return a usable model converter executable or raise a helpful error.""" + + binary = find_model_converter_binary() + if binary is None: + tried = ", ".join((MODEL_CONVERTER_BINARY, _MODEL_CONVERTER_FALLBACK_BINARY)) + raise RuntimeError( + "Unable to locate a model converter executable. " + f"Tried: {tried}. Ensure the Model Converter is installed and on PATH." + ) + return binary diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/partitioner.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/partitioner.py new file mode 100644 index 0000000..96c4408 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/arm/vgf/partitioner.py @@ -0,0 +1,35 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import final, Optional, Sequence + +from executorch.backends.arm.tosa.partitioner import TOSAPartitioner +from executorch.backends.arm.vgf import VgfBackend, VgfCompileSpec +from executorch.exir.backend.partitioner import DelegationSpec +from torch.fx.passes.operator_support import OperatorSupportBase + + +@final +class VgfPartitioner(TOSAPartitioner): + """ + Partitions subgraphs supported by the Arm Vgf backend. + + Args: + compile_spec: The Vgf compilation specification. + additional_checks: Optional sequence of additional operator support checks. + """ + + def __init__( + self, + compile_spec: VgfCompileSpec, + additional_checks: Optional[Sequence[OperatorSupportBase]] = None, + ) -> None: + # Override the delegation spec for Vgf + self.delegation_spec = DelegationSpec( + VgfBackend.__name__, compile_spec.to_list() + ) + self.additional_checks = additional_checks + self.tosa_spec = compile_spec.tosa_spec diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/CMakeLists.txt new file mode 100644 index 0000000..7912d7f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/CMakeLists.txt @@ -0,0 +1,108 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# Source root directory for executorch +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Codegen.cmake) +include(FetchContent) + +# CMSIS-NN configuration with dynamic path detection +set(CMSIS_NN_VERSION + "v7.0.0" + CACHE STRING "CMSIS-NN version to download" +) +set(CMSIS_NN_LOCAL_PATH + "" + CACHE PATH "Path to existing local CMSIS-NN installation" +) + +# Try to find existing / local CMSIS-NN installation. This is useful for +# debugging and testing with local changes. This is not common, as the CMSIS-NN +# library is downloaded via FetchContent in the default/regular case. +if(CMSIS_NN_LOCAL_PATH AND EXISTS "${CMSIS_NN_LOCAL_PATH}") + message(STATUS "Using CMSIS-NN from specified path: ${CMSIS_NN_LOCAL_PATH}") + add_subdirectory(${CMSIS_NN_LOCAL_PATH} _deps/cmsis_nn-build) +else() + # Use FetchContent with automatic fallback + message(STATUS "Using CMSIS-NN via FetchContent") + + FetchContent_Declare( + cmsis_nn + GIT_REPOSITORY https://github.com/ARM-software/CMSIS-NN.git + GIT_TAG ${CMSIS_NN_VERSION} + GIT_SHALLOW TRUE + ) + + include(${CMAKE_SOURCE_DIR}/cmake/modules/PatchCmsisNN.cmake) + FetchContent_Populate(cmsis_nn) + patch_cmsis_nn_if_needed() + add_subdirectory(${cmsis_nn_SOURCE_DIR} ${cmsis_nn_BINARY_DIR}) +endif() + +# Cortex-M ops kernel sources +set(_cortex_m_kernels__srcs + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantize_per_tensor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_dequantize_per_tensor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_add.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_avg_pool2d.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_conv2d.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_depthwise_conv2d.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_linear.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_mul.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_minimum.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_maximum.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_softmax.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ops/op_transpose.cpp +) + +# Generate C++ bindings to register kernels into Executorch +set(_yaml_file ${CMAKE_CURRENT_LIST_DIR}/ops/operators.yaml) +gen_selected_ops(LIB_NAME "cortex_m_ops_lib" OPS_SCHEMA_YAML "${_yaml_file}") +generate_bindings_for_kernels( + LIB_NAME "cortex_m_ops_lib" CUSTOM_OPS_YAML "${_yaml_file}" +) + +# Build library for cortex_m_kernels +add_library(cortex_m_kernels ${_cortex_m_kernels__srcs}) + +# Use PRIVATE for implementation dependencies to avoid INTERFACE pollution +target_link_libraries( + cortex_m_kernels + PRIVATE cmsis-nn + PRIVATE executorch + PRIVATE kernels_util_all_deps +) + +# Include directories for cortex_m_kernels +target_include_directories( + cortex_m_kernels PRIVATE ${EXECUTORCH_ROOT}/.. + ${EXECUTORCH_ROOT}/runtime/core/portable_type/c10 +) + +# cortex_m_ops_lib: Register Cortex-M ops kernels into Executorch runtime +gen_operators_lib( + LIB_NAME "cortex_m_ops_lib" KERNEL_LIBS cortex_m_kernels DEPS executorch +) + +install( + TARGETS cortex_m_kernels cortex_m_ops_lib cmsis-nn + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/executorch/backends/cortex_m/ops/ +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/README.md new file mode 100644 index 0000000..898c815 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/README.md @@ -0,0 +1,3 @@ +# Cortex-M Backend + +WIP. This is a temporary/placeholder backend for Cortex-M CPUs. It is not intended to be used in production, but rather as a proof of concept. Things will change without notice. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/BUCK new file mode 100644 index 0000000..5630c92 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/BUCK @@ -0,0 +1,11 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/TARGETS new file mode 100644 index 0000000..18b387c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/TARGETS @@ -0,0 +1,24 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("targets.bzl", "define_common_targets") + +oncall("executorch") + +runtime.python_library( + name = "ops", + srcs = [ + "operators.py", + ], + deps = [ + "fbcode//caffe2:torch", + "//executorch/backends/cortex_m/passes:passes_utils", + "//executorch/backends/cortex_m/quantizer:quantization_configs", + ], +) + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/cmsis_scratch_buffer_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/cmsis_scratch_buffer_context.h similarity index 99% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/cmsis_scratch_buffer_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/cmsis_scratch_buffer_context.h index 4672f05..4b9fdae 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/cmsis_scratch_buffer_context.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/cmsis_scratch_buffer_context.h @@ -7,8 +7,10 @@ */ #pragma once -#include "arm_nnfunctions.h" #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} namespace cortex_m { namespace native { diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/cortex_m_ops_common.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/cortex_m_ops_common.h new file mode 100644 index 0000000..71cf718 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/cortex_m_ops_common.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * Copyright 2025 Arm Limited and/or its affiliates. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +extern "C" { +#include "arm_nn_types.h" +} + +using Tensor = torch::executor::Tensor; +using ScalarType = executorch::aten::ScalarType; +using Scalar = torch::executor::Scalar; +using Error = executorch::runtime::Error; +using IntArrayRef = executorch::aten::ArrayRef; +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +// From arm_nn_math_types.h +#define ARM_NN_Q31_MAX ((int32_t)(0x7FFFFFFFL)) +#define ARM_NN_Q31_MIN ((int32_t)(0x80000000L)) + +// Basic tensor type / layout validation and dimension order checking +inline void validate_cmsis_nn_tensor_requirements( + const Tensor& input1, + const Tensor& input2, + Tensor& output, + ScalarType expected_dtype = ScalarType::Char, + bool require_channels_last = false, + bool require_same_sizes = true) { + // Basic dtype validation + ET_CHECK_MSG( + input1.scalar_type() == expected_dtype, + "Input1 dtype must be %hhd, got %hhd", + expected_dtype, + input1.scalar_type()); + ET_CHECK_MSG( + input2.scalar_type() == expected_dtype, + "Input2 dtype must be %hhd, got %hhd", + expected_dtype, + input2.scalar_type()); + ET_CHECK_MSG( + output.scalar_type() == expected_dtype, + "Output dtype must be %hhd, got %hhd", + expected_dtype, + output.scalar_type()); + if (require_same_sizes) { + ET_CHECK_MSG( + input1.sizes() == input2.sizes(), + "Input1 and Input2 must have the same sizes"); + ET_CHECK_MSG( + output.sizes() == input1.sizes(), + "Output must have the same sizes as inputs"); + } + + // TBD (#16032): Validate dim_order + // TBD: Validate memory alignment (CMSIS-NN requirement) +} + +inline void validate_single_quant_params( + const Scalar& zero_point, + const Scalar& multiplier, + const Scalar& shift, + const char* param_name) { + int64_t zp_val = zero_point.to(); + int64_t mult_val = multiplier.to(); + int64_t shift_val = shift.to(); + + ET_CHECK_MSG( + mult_val >= std::numeric_limits::min() && + mult_val <= std::numeric_limits::max(), + "%s multiplier must be in int32 range [Value: %d]", + param_name, + mult_val); + + ET_CHECK_MSG( + shift_val >= -31 && shift_val <= 31, + "%s shift must be in range [-31, 31] [Value: %d]", + param_name, + shift_val); +} + +/** + * Validate quantization parameters for inputs and output. + * + * Checks that zero points fit in int8 range, multipliers fit in int32 range, + * and shifts are within a valid bit-shift range (0-31). + * + * Ensures parameters comply with Ahead-Of-Time (AOT) quantization requirements + * and CMSIS-NN kernel expectations. + * + * Raises errors via ET_KERNEL_CHECK if any check fails. + */ +inline void validate_quantization_params( + const Scalar& zero_point1, + const Scalar& multiplier1, + const Scalar& shift1, + const Scalar& zero_point2, + const Scalar& multiplier2, + const Scalar& shift2, + const Scalar& output_zero_point, + const Scalar& output_multiplier, + const Scalar& output_shift, + Tensor& output) { + validate_single_quant_params( + zero_point1, multiplier1, shift1, "Single quant Input1"); + validate_single_quant_params( + zero_point2, multiplier2, shift2, "Single quant Input2"); + validate_single_quant_params( + output_zero_point, + output_multiplier, + output_shift, + "Single quant Output"); +} + +inline bool is_channels_last_tensor(const Tensor& tensor) { + if (tensor.dim() != 4) { + return false; + } + + // When channels or spatial dims are 1 the layout information is ambiguous. + if (tensor.size(1) == 1 || (tensor.size(2) == 1 && tensor.size(3) == 1)) { + return true; + } + + constexpr executorch::aten::DimOrderType kChannelsLastDimOrder[] = { + 0, 2, 3, 1}; + executorch::aten::ArrayRef + channels_last_order(kChannelsLastDimOrder, 4); + + return tensor.dim_order() == channels_last_order; +} + +inline bool is_channel_broadcast(const Tensor& tensor1, const Tensor& tensor2) { + if (tensor1.dim() != tensor2.dim()) { + return false; + } + + if (tensor1.dim() != 4) { + return false; + } + + if (tensor1.size(1) != tensor2.size(1)) { + return false; + } + + const bool tensor1_channels_only = tensor1.numel() == tensor1.size(1); + const bool tensor2_channels_only = tensor2.numel() == tensor2.size(1); + + return tensor1_channels_only || tensor2_channels_only; +} + +// Refer to CMSIS-NN 'arm_nn_requantize' implementation for details: +// https://github.com/ARM-software/CMSIS-NN/blob/main/Include/arm_nnsupportfunctions.h#L1625 +// multiplier: Range {ARM_NN_Q31_MIN + 1, Q32_MAX} +// shift : Range {-31, 30} +inline bool validate_per_channel_quant_params( + const int32_t* multipliers, + const int32_t* shifts, + int num_channels) { + for (int i = 0; i < num_channels; ++i) { + // Multiplier: {ARM_NN_Q31_MIN + 1, ARM_NN_Q31_MAX} + if (multipliers[i] <= ARM_NN_Q31_MIN || multipliers[i] > ARM_NN_Q31_MAX) { + ET_LOG( + Error, + "weight_multiplier[%d] out of CMSIS-NN range: %d", + i, + multipliers[i]); + return false; + } + // Shift: {-31, 30} for arm_nn_requantize + if (shifts[i] < -31 || shifts[i] > 30) { + ET_LOG(Error, "weight_shift[%d] out of range: %d", i, shifts[i]); + return false; + } + } + return true; +} + +inline Error resize_to_broadcast_target_size( + const Tensor& input1, + const Tensor& input2, + Tensor& output) { + static constexpr int kTensorDimensionLimit = 5; + Tensor::SizesType expected_output_size[kTensorDimensionLimit]; + size_t expected_output_dim = 0; + auto err = torch::executor::get_broadcast_target_size( + input1, + input2, + expected_output_size, + kTensorDimensionLimit, + &expected_output_dim); + + if (err != Error::Ok) + return err; + + return executorch::runtime::resize_tensor( + output, {expected_output_size, expected_output_dim}); +} + +/** + * Convert Scalar to CMSIS-NN int32 format + * For multipliers, zero_points, etc. from quantize_multiplier_aot + */ +inline int32_t extractScalarToInt32(const Scalar& scalar_value) { + return static_cast(scalar_value.to()); +} + +/** + * Convert Scalar to CMSIS-NN int format + * For shift values from quantize_multiplier_aot + */ +inline int extractScalarToInt(const Scalar& scalar_value) { + return static_cast(scalar_value.to()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp new file mode 100644 index 0000000..d598ab2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +// Check for Helium/MVE support +#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) +#include +#define HAS_HELIUM_SIMD 1 +#endif + +namespace cortex_m { +namespace native { + +using Tensor = executorch::aten::Tensor; +using ScalarType = executorch::aten::ScalarType; +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +namespace { + +/** + * Asserts that the parameters are valid for float to int8 quantization. + */ +void check_dequantize_args( + const Tensor& input, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ensure input is char type + ET_CHECK_MSG( + input.scalar_type() == ScalarType::Char, + "input.scalar_type() %" PRId8 " is not char type", + static_cast(input.scalar_type())); + + // Check zp range + ET_CHECK_MSG( + zero_point >= quant_min, + "zero_point must be %" PRId64 " <= quant_min %" PRId64, + zero_point, + quant_min); + ET_CHECK_MSG( + zero_point <= quant_max, + "zero_point must be %" PRId64 " >= quant_max %" PRId64, + zero_point, + quant_max); + + // Check output dtype is float + ET_CHECK_MSG( + out.scalar_type() == ScalarType::Float, + "out.scalar_type() %" PRId8 " is not float", + static_cast(out.scalar_type())); + + // Check dtype is int8 (Char) + ET_CHECK_MSG( + dtype == ScalarType::Char, + "dtype %" PRId8 " is not int8 (Char)", + static_cast(dtype)); + + // Validate quant_min and quant_max for int8 + int32_t quant_min_lower_bound = std::numeric_limits::min(); + int32_t quant_max_upper_bound = std::numeric_limits::max(); + + ET_CHECK_MSG( + quant_min >= quant_min_lower_bound, + "quant_min out of bound for int8, expected quant_min_lower_bound: %" PRId32 + " actual quant_min: %" PRId64, + quant_min_lower_bound, + quant_min); + + ET_CHECK_MSG( + quant_max <= quant_max_upper_bound, + "quant_max out of bound for int8, expected quant_max_upper_bound: %" PRId32 + " actual quant_max: %" PRId64, + quant_max_upper_bound, + quant_max); +} + +/** + * Scalar implementation of quantization for a single value. + */ +template +F dequantize_val(float scale, int32_t zero_point, Q qvalue) { + return static_cast((static_cast(qvalue) - zero_point) * scale); +} +} // namespace + +Tensor& dequantize_per_tensor_out( + KernelRuntimeContext& context, + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ignore context for now + (void)context; + + // Resize output tensor to match input dimensions + torch::executor::Error err = resize_tensor(out, input.sizes()); + ET_CHECK_MSG( + err == torch::executor::Error::Ok, + "Failed to resize out Tensor in dequantize_per_tensor_out"); + + // Validate input parameters + check_dequantize_args(input, zero_point, quant_min, quant_max, dtype, out); + + int32_t zp = static_cast(zero_point); + + // Get pointers to input and output data + const int8_t* input_data = input.const_data_ptr(); + float* out_data = out.mutable_data_ptr(); + const size_t numel = input.numel(); + + size_t i = 0; +#if defined(HAS_HELIUM_SIMD) + // Helium MVE implementation for int8 to float quantization + static uint8x16_t voffset{ + 0x0, + 0x8, + 0x4, + 0xC, + 0x1, + 0x9, + 0x5, + 0xD, + 0x2, + 0xA, + 0x6, + 0xE, + 0x3, + 0xB, + 0x7, + 0xF}; + + int16x8_t vzp = vdupq_n_s16(static_cast(zp)); + float32x4_t vscale = vdupq_n_f32(static_cast(scale)); + + for (; i + 15 < numel; i += 16) { + int8x16_t in_084C195D2A6E3B7F = + vldrbq_gather_offset_s8(input_data, voffset); + + int16x8_t in_04152637 = vsubq_s16(vmovlbq_s8(in_084C195D2A6E3B7F), vzp); + int16x8_t in_8C9DAEBF = vsubq_s16(vmovltq_s8(in_084C195D2A6E3B7F), vzp); + + float32x4_t inf_0123 = vcvtq_f32_s32(vmovlbq_s16(in_04152637)); + float32x4_t inf_4567 = vcvtq_f32_s32(vmovltq_s16(in_04152637)); + float32x4_t inf_89AB = vcvtq_f32_s32(vmovlbq_s16(in_8C9DAEBF)); + float32x4_t inf_CDEF = vcvtq_f32_s32(vmovltq_s16(in_8C9DAEBF)); + + float32x4_t out_0123 = vmulq_f32(inf_0123, vscale); + float32x4_t out_4567 = vmulq_f32(inf_4567, vscale); + float32x4_t out_89AB = vmulq_f32(inf_89AB, vscale); + float32x4_t out_CDEF = vmulq_f32(inf_CDEF, vscale); + + vstrwq_f32(out_data + 0, out_0123); + vstrwq_f32(out_data + 4, out_4567); + vstrwq_f32(out_data + 8, out_89AB); + vstrwq_f32(out_data + 12, out_CDEF); + + input_data += 16; + out_data += 16; + } +#endif // defined(HAS_HELIUM_SIMD) + + for (; i < numel; i++) { + *out_data = dequantize_val(scale, zp, *input_data); + input_data++; + out_data++; + } + return out; +} + +Tensor& dequantize_per_tensor_out( + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + KernelRuntimeContext context; + return dequantize_per_tensor_out( + context, input, scale, zero_point, quant_min, quant_max, dtype, out); +} + +} // namespace native +} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_maximum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_maximum.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_maximum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_maximum.cpp index fc76f5c..71a907f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_maximum.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_maximum.cpp @@ -7,6 +7,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_minimum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_minimum.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_minimum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_minimum.cpp index 5a75cb8..f220aa2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_minimum.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_minimum.cpp @@ -9,6 +9,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp new file mode 100644 index 0000000..d92d266 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +// Check for Helium/MVE support +#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) +#include +#define HAS_HELIUM_SIMD 1 +#endif + +namespace cortex_m { +namespace native { + +using Tensor = executorch::aten::Tensor; +using ScalarType = executorch::aten::ScalarType; +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +namespace { + +/** + * Asserts that the parameters are valid for float to int8 quantization. + */ +void check_quantize_args( + const Tensor& input, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ensure input is float type + ET_CHECK_MSG( + input.scalar_type() == ScalarType::Float, + "input.scalar_type() %" PRId8 " is not float type", + static_cast(input.scalar_type())); + + // Check output dtype is int8 + ET_CHECK_MSG( + out.scalar_type() == ScalarType::Char, + "out.scalar_type() %" PRId8 " is not int8 (Char)", + static_cast(out.scalar_type())); + + // Check dtype is int8 + ET_CHECK_MSG( + dtype == ScalarType::Char, + "dtype %" PRId8 " is not int8 (Char)", + static_cast(dtype)); + + // Validate quant_min and quant_max for int8 + int32_t quant_min_lower_bound = std::numeric_limits::min(); + int32_t quant_max_upper_bound = std::numeric_limits::max(); + + ET_CHECK_MSG( + quant_min >= quant_min_lower_bound, + "quant_min out of bound for int8, expected quant_min_lower_bound: %" PRId32 + " actual quant_min: %" PRId64, + quant_min_lower_bound, + quant_min); + + ET_CHECK_MSG( + quant_max <= quant_max_upper_bound, + "quant_max out of bound for int8, expected quant_max_upper_bound: %" PRId32 + " actual quant_max: %" PRId64, + quant_max_upper_bound, + quant_max); +} + +/** + * Scalar implementation of quantization for a single value. + */ +template +Q quantize_val( + F inv_scale, + int32_t zero_point, + F value, + int64_t quant_min, + int64_t quant_max) { + int32_t qvalue = + zero_point + static_cast(std::nearbyint(inv_scale * value)); + qvalue = std::max(qvalue, static_cast(quant_min)); + qvalue = std::min(qvalue, static_cast(quant_max)); + return static_cast(qvalue); +} + +} // namespace + +Tensor& quantize_per_tensor_out( + KernelRuntimeContext& context, + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + // Ignore context for now + (void)context; + + // Resize output tensor to match input dimensions + torch::executor::Error err = resize_tensor(out, input.sizes()); + ET_CHECK_MSG( + err == torch::executor::Error::Ok, + "Failed to resize out Tensor in quantize_per_tensor_out"); + + // Validate input parameters + check_quantize_args(input, quant_min, quant_max, dtype, out); + + // Pre-compute inverse scale for better performance + float inv_scale = 1.0f / static_cast(scale); + int32_t zp = static_cast(zero_point); + int32_t qmin = static_cast(quant_min); + int32_t qmax = static_cast(quant_max); + + // Get pointers to input and output data + const float* input_data = input.const_data_ptr(); + int8_t* out_data = out.mutable_data_ptr(); + const size_t numel = input.numel(); + + size_t i = 0; + +#if defined(HAS_HELIUM_SIMD) + // Helium MVE implementation for float32 to int8 quantization + static uint8x16_t voffset{ + 0x0, + 0x8, + 0x4, + 0xC, + 0x1, + 0x9, + 0x5, + 0xD, + 0x2, + 0xA, + 0x6, + 0xE, + 0x3, + 0xB, + 0x7, + 0xF}; + + float32x4_t inv_scale_vec = vdupq_n_f32(inv_scale); + + // Magic number for float to int conversion, round to nearest even integer + // int magic_round(float f): interpret_as_int32(f + magic_float) - magic_int + // where, + // magic_float = 12582912.0f = (2 ** 23 + 2 ** 22) = (1.5 * 2 ** 23) + // magic_int = 1262485504 = 0x4B400000 = bit_pattern_as_int32(magic_float) + + float magic_float = 12582912.0f; + int32_t magic_int = 1262485504; + + float32x4_t vmagic_float = vdupq_n_f32(magic_float); + int32x4_t vmagic_int_less_zp = + vdupq_n_s32(magic_int - static_cast(zp)); + + int16x8_t vqmin = vdupq_n_s16(qmin); + int16x8_t vqmax = vdupq_n_s16(qmax); + + // TODO: Measure performnce, we are spilling + for (; i + 15 < numel; i += 16) { + float32x4_t in_0123 = vldrwq_f32(input_data + 0); + float32x4_t in_4567 = vldrwq_f32(input_data + 4); + float32x4_t in_89AB = vldrwq_f32(input_data + 8); + float32x4_t in_CDEF = vldrwq_f32(input_data + 12); + + float32x4_t outf_0123 = vfmaq_f32(vmagic_float, in_0123, inv_scale_vec); + float32x4_t outf_4567 = vfmaq_f32(vmagic_float, in_4567, inv_scale_vec); + float32x4_t outf_89AB = vfmaq_f32(vmagic_float, in_89AB, inv_scale_vec); + float32x4_t outf_CDEF = vfmaq_f32(vmagic_float, in_CDEF, inv_scale_vec); + + int32x4_t out_0123 = + vsubq_s32(vreinterpretq_s32_f32(outf_0123), vmagic_int_less_zp); + int32x4_t out_4567 = + vsubq_s32(vreinterpretq_s32_f32(outf_4567), vmagic_int_less_zp); + int32x4_t out_89AB = + vsubq_s32(vreinterpretq_s32_f32(outf_89AB), vmagic_int_less_zp); + int32x4_t out_CDEF = + vsubq_s32(vreinterpretq_s32_f32(outf_CDEF), vmagic_int_less_zp); + + int16x8_t out_04152637; + int16x8_t out_8C9DAEBF; + out_04152637 = vmovnbq_s32(out_04152637, out_0123); + out_04152637 = vmovntq_s32(out_04152637, out_4567); + out_8C9DAEBF = vmovnbq_s32(out_8C9DAEBF, out_89AB); + out_8C9DAEBF = vmovntq_s32(out_8C9DAEBF, out_CDEF); + + int16x8_t out_04152637_clamped = + vminq_s16(vmaxq_s16(out_04152637, vqmin), vqmax); + int16x8_t out_8C9DAEBF_clamped = + vminq_s16(vmaxq_s16(out_8C9DAEBF, vqmin), vqmax); + + int8x16_t out_084C195D2A6E3B7F; + out_084C195D2A6E3B7F = + vmovnbq_s16(out_084C195D2A6E3B7F, out_04152637_clamped); + out_084C195D2A6E3B7F = + vmovntq_s16(out_084C195D2A6E3B7F, out_8C9DAEBF_clamped); + + vstrbq_scatter_offset_s8(out_data, voffset, out_084C195D2A6E3B7F); + input_data += 16; + out_data += 16; + } +#endif // defined(HAS_HELIUM_SIMD) + + for (; i < numel; i++) { + *out_data = + quantize_val(inv_scale, zp, *input_data, qmin, qmax); + input_data++; + out_data++; + } + + return out; +} + +Tensor& quantize_per_tensor_out( + const Tensor& input, + double scale, + int64_t zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + KernelRuntimeContext context; + return quantize_per_tensor_out( + context, input, scale, zero_point, quant_min, quant_max, dtype, out); +} + +} // namespace native +} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_add.cpp similarity index 74% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_add.cpp index f607977..019ab4c 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_add.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_add.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -9,6 +9,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { using KernelRuntimeContext = torch::executor::KernelRuntimeContext; @@ -16,18 +21,16 @@ using KernelRuntimeContext = torch::executor::KernelRuntimeContext; Tensor& quantized_add_out( KernelRuntimeContext& context, const Tensor& input1_int8, - const int64_t input1_zero_point, - const int64_t input1_multiplier, - const int64_t input1_shift, + const Scalar& input1_zero_point, + const Scalar& input1_multiplier, + const Scalar& input1_shift, const Tensor& input2_int8, - const int64_t input2_zero_point, - const int64_t input2_multiplier, - const int64_t input2_shift, - const int64_t output_zero_point, - const int64_t output_multiplier, - const int64_t output_shift, - const int64_t activation_min, - const int64_t activation_max, + const Scalar& input2_zero_point, + const Scalar& input2_multiplier, + const Scalar& input2_shift, + const Scalar& output_zero_point, + const Scalar& output_multiplier, + const Scalar& output_shift, Tensor& out) { // Validate tensor types and dim order bool channel_broadcast = is_channel_broadcast(input1_int8, input2_int8); @@ -53,29 +56,29 @@ Tensor& quantized_add_out( out); ET_LOG( - Debug, + Info, "quantized_add_out: input1_int8.sizes() = %zu", input1_int8.sizes().size()); - int32_t zp1 = static_cast(input1_zero_point); - int32_t input1_mult = static_cast(input1_multiplier); - int input1_shift_val = static_cast(input1_shift); - int32_t zp2 = static_cast(input2_zero_point); - int32_t input2_mult = static_cast(input2_multiplier); - int input2_shift_val = static_cast(input2_shift); - int32_t out_zp = static_cast(output_zero_point); - int32_t output_mult = static_cast(output_multiplier); - int output_shift_val = static_cast(output_shift); + int32_t zp1 = extractScalarToInt32(input1_zero_point); + int32_t input1_mult = extractScalarToInt32(input1_multiplier); + int input1_shift_val = extractScalarToInt(input1_shift); + int32_t zp2 = extractScalarToInt32(input2_zero_point); + int32_t input2_mult = extractScalarToInt32(input2_multiplier); + int input2_shift_val = extractScalarToInt(input2_shift); + int32_t out_zp = extractScalarToInt32(output_zero_point); + int32_t output_mult = extractScalarToInt32(output_multiplier); + int output_shift_val = extractScalarToInt(output_shift); int8_t* input1_ptr = input1_int8.data_ptr(); int8_t* input2_ptr = input2_int8.data_ptr(); // Left shift to maximize precision const int32_t left_shift = 20; - const int32_t act_min = static_cast(activation_min); - const int32_t act_max = static_cast(activation_max); + const int32_t activation_min = std::numeric_limits::min(); + const int32_t activation_max = std::numeric_limits::max(); ET_LOG( - Debug, + Info, "Using AoT-computed parameters: input1[mult=%d, shift=%d], input2[mult=%d, shift=%d], output[mult=%d, shift=%d]", input1_mult, input1_shift_val, @@ -123,8 +126,8 @@ Tensor& quantized_add_out( static_cast(out_zp), output_mult, output_shift_val, - act_min, - act_max, + activation_min, + activation_max, adds_per_loop); if (status != ARM_CMSIS_NN_SUCCESS) { @@ -138,7 +141,7 @@ Tensor& quantized_add_out( } } ET_LOG( - Debug, + Info, "quantized_add_out: Successfully completed with AoT-computed parameters!"); return out; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp new file mode 100644 index 0000000..dfdedbd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2025 Arm Limited and/or its affiliates. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "cortex_m_ops_common.h" + +extern "C" { +#include "arm_nnfunctions.h" +} + +namespace cortex_m { +namespace native { + +using KernelRuntimeContext = torch::executor::KernelRuntimeContext; + +Tensor& quantized_avg_pool2d_out( + KernelRuntimeContext& context, + const Tensor& input, + const IntArrayRef kernel_size, + const IntArrayRef stride, + const IntArrayRef padding, + const Scalar& zero_point, + const Scalar& multiplier, + const Scalar& shift, + Tensor& out) { + if (input.dim() != 4 || out.dim() != 4) { + ET_LOG(Error, "quantized_avg_pool2d_out: tensors must be 4-D"); + context.fail(Error::InvalidArgument); + return out; + } + int32_t batch = static_cast(input.size(0)); + int32_t channels = static_cast(input.size(1)); + int32_t input_h = static_cast(input.size(2)); + int32_t input_w = static_cast(input.size(3)); + int32_t kernel_h = static_cast(kernel_size[0]); + int32_t kernel_w = static_cast(kernel_size[1]); + int32_t stride_h = static_cast(stride[0]); + int32_t stride_w = static_cast(stride[1]); + int32_t pad_h = static_cast(padding[0]); + int32_t pad_w = static_cast(padding[1]); + int32_t output_h = static_cast(out.size(2)); + int32_t output_w = static_cast(out.size(3)); + const int32_t activation_min = std::numeric_limits::min(); + const int32_t activation_max = std::numeric_limits::max(); + + const int8_t* input_data = input.const_data_ptr(); + int8_t* output_data = out.mutable_data_ptr(); + + cmsis_nn_context cmsis_ctx; + cmsis_ctx.buf = nullptr; + cmsis_ctx.size = 0; + cmsis_nn_pool_params pool_params; + pool_params.stride.h = stride_h; + pool_params.stride.w = stride_w; + pool_params.padding.h = pad_h; + pool_params.padding.w = pad_w; + pool_params.activation.min = activation_min; + pool_params.activation.max = activation_max; + + cmsis_nn_dims input_dims{batch, input_h, input_w, channels}; + cmsis_nn_dims filter_dims{1, kernel_h, kernel_w, 1}; + cmsis_nn_dims output_dims{batch, output_h, output_w, channels}; + + arm_cmsis_nn_status status = arm_avgpool_s8( + &cmsis_ctx, + &pool_params, + &input_dims, + input_data, + &filter_dims, + &output_dims, + output_data); + if (status != ARM_CMSIS_NN_SUCCESS) { + ET_LOG( + Error, + "quantized_avg_pool2d_out: arm_avgpool_s8 failed with status [%d]", + status); + context.fail(Error::Internal); + } + return out; +} + +} // namespace native +} // namespace cortex_m \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_conv2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_conv2d.cpp similarity index 84% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_conv2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_conv2d.cpp index 7d44336..ad14af9 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_conv2d.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_conv2d.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -7,6 +7,10 @@ #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -21,9 +25,9 @@ bool validate_conv2d_arguments( const Tensor& weight, const torch::executor::optional& bias, const Tensor& output, - const Int64ArrayRef& stride, - const Int64ArrayRef& padding, - const Int64ArrayRef& dilation, + const IntArrayRef& stride, + const IntArrayRef& padding, + const IntArrayRef& dilation, const Tensor& requantize_multipliers, const Tensor& requantize_shifts) { if (input.dim() != kConvDim || weight.dim() != kConvDim || @@ -40,7 +44,7 @@ bool validate_conv2d_arguments( executorch::aten::ArrayRef channels_last_order(kChannelsLastDimOrder, 4); - if (input.size(1) > 1 && !is_channels_last_tensor(input)) { + if (input.size(1) > 1 && input.dim_order() != channels_last_order) { ET_LOG( Error, "quantized_conv2d_out: input must have channels_last dim_order (NHWC)"); @@ -48,7 +52,7 @@ bool validate_conv2d_arguments( return false; } - if (output.size(1) > 1 && !is_channels_last_tensor(input)) { + if (output.size(1) > 1 && output.dim_order() != channels_last_order) { ET_LOG( Error, "quantized_conv2d_out: output must have channels_last dim_order (NHWC)"); @@ -103,9 +107,9 @@ Tensor& quantized_conv2d_out( const Tensor& input, const Tensor& weight, const torch::executor::optional& bias, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef dilation, + const IntArrayRef stride, + const IntArrayRef padding, + const IntArrayRef dilation, const int64_t input_offset, const int64_t output_offset, const Tensor& requantize_multipliers, @@ -184,28 +188,24 @@ Tensor& quantized_conv2d_out( cmsis_context.buf = nullptr; cmsis_context.size = 0; - const int32_t buffer_bytes = arm_convolve_wrapper_s8_get_buffer_size( - &conv_params, &input_dims, &filter_dims, &output_dims); - if (buffer_bytes < 0) { - ET_LOG( - Error, "quantized_conv2d_out: CMSIS-NN buffer size calculation failed"); - context.fail(Error::Internal); - return out; - } + const size_t buffer_bytes = static_cast( + arm_convolve_s8_get_buffer_size(&input_dims, &filter_dims)); if (buffer_bytes > 0) { auto buffer_or_error = - context.allocate_temp(buffer_bytes, kCortexMMveAlignment); + context.allocate_temp(buffer_bytes, alignof(int16_t)); if (!buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_conv2d_out: failed to allocate scratch buffer (%d bytes, error %d)", - static_cast(buffer_bytes), - static_cast(buffer_or_error.error())); - context.fail(buffer_or_error.error()); - return out; + if (buffer_or_error.error() != Error::NotFound) { + ET_LOG( + Error, + "quantized_conv2d_out: failed to allocate scratch buffer (%d)", + static_cast(buffer_or_error.error())); + context.fail(buffer_or_error.error()); + return out; + } + } else { + cmsis_context.buf = buffer_or_error.get(); + cmsis_context.size = buffer_bytes; } - cmsis_context.buf = buffer_or_error.get(); - cmsis_context.size = buffer_bytes; } const arm_cmsis_nn_status status = arm_convolve_wrapper_s8( @@ -224,7 +224,7 @@ Tensor& quantized_conv2d_out( if (status != ARM_CMSIS_NN_SUCCESS) { ET_LOG( Error, - "quantized_conv2d_out: arm_convolve_wrapper_s8 failed with status %d", + "quantized_conv2d_out: arm_convolve_s8 failed with status %d", status); context.fail(Error::Internal); } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp index 8dec61e..9cf0625 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_depthwise_conv2d.cpp @@ -1,5 +1,6 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -7,6 +8,10 @@ #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -21,9 +26,9 @@ bool validate_depthwise_conv2d_arguments( const Tensor& weight, const torch::executor::optional& bias, const Tensor& output, - const Int64ArrayRef& stride, - const Int64ArrayRef& padding, - const Int64ArrayRef& dilation, + const IntArrayRef& stride, + const IntArrayRef& padding, + const IntArrayRef& dilation, const int64_t depth_multiplier, const Tensor& requantize_multipliers, const Tensor& requantize_shifts) { @@ -140,9 +145,9 @@ Tensor& quantized_depthwise_conv2d_out( const Tensor& input, const Tensor& weight, const torch::executor::optional& bias, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef dilation, + const IntArrayRef stride, + const IntArrayRef padding, + const IntArrayRef dilation, const int64_t depth_multiplier, const int64_t input_offset, const int64_t output_offset, @@ -233,7 +238,7 @@ Tensor& quantized_depthwise_conv2d_out( } auto buffer_or_error = context.allocate_temp( - static_cast(buffer_bytes), kCortexMMveAlignment); + static_cast(buffer_bytes), alignof(int16_t)); if (!buffer_or_error.ok()) { ET_LOG( Error, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_linear.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_linear.cpp similarity index 80% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_linear.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_linear.cpp index 5d018cb..015fa80 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_linear.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_linear.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -9,6 +9,10 @@ #include "cortex_m_ops_common.h" +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { using KernelRuntimeContext = torch::executor::KernelRuntimeContext; @@ -19,15 +23,15 @@ Tensor& quantized_linear_out( const Tensor& weights, const torch::executor::optional& bias, const torch::executor::optional& kernel_sum, - const int64_t input_offset, - const int64_t filter_offset, - const int64_t output_offset, - const Int64ArrayRef requantize_multipliers, - const Int64ArrayRef requantize_shifts, - const int64_t activation_max, - const int64_t activation_min, + const Scalar& input_offset, + const Scalar& filter_offset, + const Scalar& output_offset, + const IntArrayRef requantize_multipliers, + const IntArrayRef requantize_shifts, + const Scalar& activation_max, + const Scalar& activation_min, Tensor& out) { - ET_LOG(Debug, "quantized_linear_out: called"); + ET_LOG(Info, "quantized_linear_out: called"); const int8_t* input_data = input.const_data_ptr(); const int8_t* weight_data = weights.const_data_ptr(); @@ -43,11 +47,11 @@ Tensor& quantized_linear_out( // Setup CMSIS-NN parameters cmsis_nn_fc_params fc_params; - fc_params.input_offset = static_cast(input_offset); - fc_params.filter_offset = static_cast(filter_offset); - fc_params.output_offset = static_cast(output_offset); - fc_params.activation.min = static_cast(activation_min); - fc_params.activation.max = static_cast(activation_max); + fc_params.input_offset = static_cast(input_offset.to()); + fc_params.filter_offset = static_cast(filter_offset.to()); + fc_params.output_offset = static_cast(output_offset.to()); + fc_params.activation.min = static_cast(activation_min.to()); + fc_params.activation.max = static_cast(activation_max.to()); cmsis_nn_per_tensor_quant_params per_tensor_quant_params; per_tensor_quant_params.multiplier = @@ -61,14 +65,14 @@ Tensor& quantized_linear_out( batches *= input.size(i); } ET_LOG( - Debug, + Info, "in features: %d, out_features: %d, batches: %d, kernel_sum_size: %d", in_feat, out_feat, batches, kernel_sum.has_value() ? kernel_sum.value().numel() : 0); ET_LOG( - Debug, + Info, "kernel_sum[0]: %d, kernel_sum[1]: %d", kernel_sum_data != nullptr ? kernel_sum_data[0] : -1, kernel_sum_data != nullptr ? kernel_sum_data[1] : -1); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_mul.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_mul.cpp similarity index 81% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_mul.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_mul.cpp index 524e74a..3d2d765 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_mul.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_quantized_mul.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -7,6 +7,11 @@ #include "cortex_m_ops_common.h" +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { namespace { @@ -21,12 +26,12 @@ using KernelRuntimeContext = torch::executor::KernelRuntimeContext; Tensor& quantized_mul_out( KernelRuntimeContext& context, const Tensor& input1_int8, - const int64_t input1_zero_point, + const Scalar& input1_zero_point, const Tensor& input2_int8, - const int64_t input2_zero_point, - const int64_t output_zero_point, - const int64_t output_multiplier, - const int64_t output_shift, + const Scalar& input2_zero_point, + const Scalar& output_zero_point, + const Scalar& output_multiplier, + const Scalar& output_shift, Tensor& out) { // Validate tensor types and quantization parameters @@ -39,8 +44,8 @@ Tensor& quantized_mul_out( /*require_channels_last=*/channel_broadcast, /*require_same_sizes=*/!channel_broadcast); - const int32_t kIdentityMultiplier(/*value=*/1); - const int32_t kZeroShift(/*value=*/0); + const Scalar kIdentityMultiplier(/*value=*/1); + const Scalar kZeroShift(/*value=*/0); validate_quantization_params( input1_zero_point, kIdentityMultiplier, @@ -56,11 +61,11 @@ Tensor& quantized_mul_out( // Extract quantization parameters int8_t* input1_ptr = input1_int8.data_ptr(); int8_t* input2_ptr = input2_int8.data_ptr(); - int32_t zp1 = static_cast(input1_zero_point); - int32_t zp2 = static_cast(input2_zero_point); - const int32_t out_zp = static_cast(output_zero_point); - const int32_t output_mult = static_cast(output_multiplier); - const int32_t output_shift_val = static_cast(output_shift); + int32_t zp1 = extractScalarToInt32(input1_zero_point); + int32_t zp2 = extractScalarToInt32(input2_zero_point); + const int32_t out_zp = extractScalarToInt32(output_zero_point); + const int32_t output_mult = extractScalarToInt32(output_multiplier); + const int32_t output_shift_val = extractScalarToInt32(output_shift); int32_t muls_per_loop = 0; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_softmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_softmax.cpp similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_softmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_softmax.cpp index c07a538..3e6f74e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_softmax.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_softmax.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -11,6 +11,11 @@ #include #include +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -72,9 +77,9 @@ Tensor& softmax_out( const int32_t diff_min_val = static_cast(diff_min); validate_single_quant_params( - static_cast(input_zero_point), - input_multiplier_val, - input_shift_val, + Scalar(static_cast(input_zero_point)), + Scalar(input_multiplier_val), + Scalar(input_shift_val), "softmax input"); const auto positive_dim = normalize_dim(input, dim); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_transpose.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_transpose.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_transpose.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_transpose.cpp index 7fcbc03..7befafc 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_transpose.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/op_transpose.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -11,6 +11,11 @@ #include #include +// Include CMSIS-NN headers with C linkage +extern "C" { +#include "arm_nnfunctions.h" +} + namespace cortex_m { namespace native { @@ -25,7 +30,7 @@ constexpr size_t kMaxSupportedDims = 4; Tensor& transpose_out( KernelRuntimeContext& context, const Tensor& input, - const Int64ArrayRef perm, + const IntArrayRef perm, Tensor& out) { if (input.scalar_type() != ScalarType::Char || out.scalar_type() != ScalarType::Char) { diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/operators.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/operators.py new file mode 100644 index 0000000..c62cac6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/operators.py @@ -0,0 +1,890 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from math import prod +from typing import Sequence + +import torch +import torch.nn.functional as F +from executorch.backends.cortex_m.passes.passes_utils import ( + dequantize_per_tensor_cmsis, + is_channel_broadcast, + quantize_per_tensor_cmsis, + requantize_cmsis, + SHIFT_INT8, +) +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + CMSIS_SOFTMAX_SCALE, + CMSIS_SOFTMAX_ZERO_POINT, +) +from executorch.exir.dialects._ops import ops as exir_ops + +# To provide the implementation of the operators +from torch.library import impl, Library, register_fake + + +# New operator library with a custom namespace to allow fusion etc. +lib = Library("cortex_m", "DEF") + +SOFTMAX_INPUT_INTEGER_BITS = 5 + +### +# dequantize_per_tensor +### + +lib.define( + "quantize_per_tensor(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype) -> (Tensor Z)" +) + +lib.define( + "quantize_per_tensor.out(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype, *, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantize_per_tensor") +def quantize_per_tensor_meta( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + return torch.empty_like(input, dtype=dtype) + + +@impl(lib, "quantize_per_tensor", "CompositeExplicitAutograd") +def quantize_per_tensor_impl( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + """ + The implementation of the quantize_per_tensor operator is the same as the + quantize_per_tensor operator in the edge dialect. + """ + return exir_ops.edge.quantized_decomposed.quantize_per_tensor.default( + input, scale, zero_point, quant_min, quant_max, dtype + ) + + +### +# dequantize_per_tensor +### + +lib.define( + "dequantize_per_tensor(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype) -> (Tensor Z)" +) +lib.define( + "dequantize_per_tensor.out(Tensor input, float scale, int zero_point, int quant_min, int quant_max, ScalarType dtype, *, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::dequantize_per_tensor") +def dequantize_per_tensor_meta( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + return torch.empty_like(input, dtype=torch.float) + + +@impl(lib, "dequantize_per_tensor", "CompositeExplicitAutograd") +def dequantize_per_tensor_impl( + input: torch.Tensor, + scale: float, + zero_point: int, + quant_min: int, + quant_max: int, + dtype: torch.dtype, +) -> torch.Tensor: + """ + The implementation of the dequantize_per_tensor operator is the same as the + dequantize_per_tensor operator in the edge dialect. + """ + return exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default( + input, scale, zero_point, quant_min, quant_max, dtype + ) + + +# Define the operator schema with multipliers and shifts (11 args) +lib.define( + "quantized_add(" + "Tensor self, Scalar self_zero_point, Scalar self_multiplier, Scalar self_shift, " + "Tensor other, Scalar other_zero_point, Scalar other_multiplier, Scalar other_shift, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift) -> Tensor" +) + +# Define the operator schema with multipliers and shifts (11 args + out tensor) +lib.define( + "quantized_add.out(" + "Tensor self, Scalar self_zero_point, Scalar self_multiplier, Scalar self_shift, " + "Tensor other, Scalar other_zero_point, Scalar other_multiplier, Scalar other_shift, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, " + "*, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_add") +def quantized_add_meta( + self: torch.Tensor, + self_zero_point: int, + self_multiplier: int, + self_shift: int, + other: torch.Tensor, + other_zero_point: int, + other_multiplier: int, + other_shift: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_add: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + if self.numel() > other.numel(): + output_tensor = self + else: + output_tensor = other + return torch.empty_like(output_tensor) + + +@impl(lib, "quantized_add", "CompositeExplicitAutograd") +def quantized_add_impl( + self: torch.Tensor, + self_zero_point: int, + self_multiplier: int, + self_shift: int, + other: torch.Tensor, + other_zero_point: int, + other_multiplier: int, + other_shift: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_add: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + self_shifted = (self.to(torch.int32) - self_zero_point) << SHIFT_INT8 + self_fp = requantize_cmsis(self_shifted, self_multiplier, self_shift) + + other_shifted = (other.to(torch.int32) - other_zero_point) << SHIFT_INT8 + other_fp = requantize_cmsis(other_shifted, other_multiplier, other_shift) + + result_fp = self_fp + other_fp + result_quantized = requantize_cmsis(result_fp, output_multiplier, output_shift) + result = torch.clamp(result_quantized + output_zero_point, -128, 127).to(torch.int8) + return result + + +# =================================================================== +# QUANTIZED MUL OPERATION DEFINITION +# =================================================================== +lib.define( + "quantized_mul(" + "Tensor self, Scalar self_zero_point, " + "Tensor other, Scalar other_zero_point, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift) -> Tensor" +) +lib.define( + "quantized_mul.out(" + "Tensor self, Scalar self_zero_point, " + "Tensor other, Scalar other_zero_point, " + "Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, " + "*, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_mul") +def quantized_mul_meta( + self: torch.Tensor, + self_zero_point: int, + other: torch.Tensor, + other_zero_point: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + # Broadcast to output shape + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_mul: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + if self.numel() > other.numel(): + output_tensor = self + else: + output_tensor = other + return torch.empty_like(output_tensor) + + +@impl(lib, "quantized_mul", "CompositeExplicitAutograd") +def quantized_mul_impl( + self: torch.Tensor, + self_zero_point: int, + other: torch.Tensor, + other_zero_point: int, + output_zero_point: int, + output_multiplier: int, + output_shift: int, +) -> torch.Tensor: + # CMSIS-NN kernel multiplies raw int8 tensors (after zero-point offset) and + # only uses the output multiplier/shift for rescaling. Mirror that here to + # keep the composite implementation numerically aligned with the backend. + assert self.shape == other.shape or is_channel_broadcast(self, other), ( + "Cortex-M quantized_mul: broadcasting is not yet supported except for channel dim — " + f"got self.shape={self.shape}, other.shape={other.shape}" + ) + self_int = self.to(torch.int32) - self_zero_point + other_int = other.to(torch.int32) - other_zero_point + result_fp = self_int * other_int + result_quantized = requantize_cmsis(result_fp, output_multiplier, output_shift) + result = torch.clamp(result_quantized + output_zero_point, -128, 127).to(torch.int8) + return result + + +# =================================================================== +# MINIMUM/MAXIMUM OPERATION DEFINITIONS +# =================================================================== +lib.define("minimum(Tensor self, Tensor other) -> Tensor") +lib.define("minimum.out(Tensor self, Tensor other, *, Tensor(a!) out) -> Tensor(a!)") + + +@register_fake("cortex_m::minimum") +def minimum_meta(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + assert self.dtype == other.dtype, ( + "Cortex-M minimum: dtype mismatch — " + f"got self.dtype={self.dtype}, other.dtype={other.dtype}" + ) + broadcasted_shape = torch.broadcast_shapes(self.shape, other.shape) + return torch.empty(broadcasted_shape, dtype=self.dtype, device=self.device) + + +@impl(lib, "minimum", "CompositeExplicitAutograd") +def minimum_impl(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + return torch.minimum(self, other) + + +lib.define("maximum(Tensor self, Tensor other) -> Tensor") +lib.define("maximum.out(Tensor self, Tensor other, *, Tensor(a!) out) -> Tensor(a!)") + + +@register_fake("cortex_m::maximum") +def maximum_meta(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + assert self.dtype == other.dtype, ( + "Cortex-M maximum: dtype mismatch — " + f"got self.dtype={self.dtype}, other.dtype={other.dtype}" + ) + broadcasted_shape = torch.broadcast_shapes(self.shape, other.shape) + return torch.empty(broadcasted_shape, dtype=self.dtype, device=self.device) + + +@impl(lib, "maximum", "CompositeExplicitAutograd") +def maximum_impl(self: torch.Tensor, other: torch.Tensor) -> torch.Tensor: + return torch.maximum(self, other) + + +# =================================================================== +# QUANTIZED LINEAR OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_linear.out(" + "Tensor input, " + "Tensor weights, " + "Tensor? bias, " + "Tensor? kernel_sum, " + "Scalar input_offset, " + "Scalar filter_offset, " + "Scalar output_offset, " + "int[] requantize_multipliers, " + "int[] requantize_shifts, " + "Scalar activation_max, " + "Scalar activation_min, " + "*, Tensor(a!) out" + ") -> Tensor(a!)" +) + +# Define functional variant (non-out version) +lib.define( + "quantized_linear(" + "Tensor input, " + "Tensor weights, " + "Tensor? bias, " + "Tensor? kernel_sum, " + "Scalar input_offset, " + "Scalar filter_offset, " + "Scalar output_offset, " + "int[] requantize_multipliers, " + "int[] requantize_shifts, " + "Scalar activation_max, " + "Scalar activation_min" + ") -> Tensor" +) + + +# Fake meta function for shape inference (functional variant) +@register_fake("cortex_m::quantized_linear") +def quantized_linear_meta( + input, + weights, + bias, + kernel_sum, + input_offset, + filter_offset, + output_offset, + requantize_multipliers, + requantize_shifts, + activation_max, + activation_min, +) -> torch.Tensor: + + shape = (*input.shape[:-1], weights.shape[0]) + return torch.empty(shape, dtype=input.dtype, device=input.device) + + +# Functional variant implementation +@impl(lib, "quantized_linear", "CompositeExplicitAutograd") +def quantized_linear_impl( + input: torch.Tensor, + weights: torch.Tensor, + bias: torch.Tensor, + kernel_sum: torch.Tensor, + input_offset: int, + filter_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_max: int, + activation_min: int, +) -> torch.Tensor: + """ + Functional variant - creates output tensor and calls out variant + """ + + # Leaving both implementations for debugging purposes. + compute_using_kernel_sum = True + + if compute_using_kernel_sum: + weights_int32 = weights.to(torch.int32) + + input_int32 = input.to(torch.int32) + new_shape = (prod(input.shape[:-1]), input.shape[-1]) + input_reshaped = input_int32.reshape(new_shape) + + lhs_sum = torch.sum(input_reshaped, dim=-1, keepdim=True) * filter_offset + output = torch.mm(input_reshaped, weights_int32.T) + lhs_sum + kernel_sum + output_shape = (*input.shape[:-1], output.shape[-1]) + output_reshaped = output.reshape(output_shape) + else: + weights_int32 = weights.to(torch.int32) + filter_offset + + input_int32 = input.to(torch.int32) + input_offset + new_shape = (prod(input.shape[:-1]), input.shape[-1]) + input_reshaped = input_int32.reshape(new_shape) + + output = torch.mm(input_reshaped, weights_int32.T) + if bias is not None: + output = output + bias + output_shape = (*input.shape[:-1], output.shape[-1]) + output_reshaped = output.reshape(output_shape) + + output = requantize_cmsis( + output_reshaped, requantize_multipliers[0], requantize_shifts[0] + ) + output += output_offset + output = torch.clamp(output, activation_min, activation_max).to(torch.int8) + return output + + +# =================================================================== +# SOFTMAX OPERATION DEFINITION +# =================================================================== + +lib.define( + "softmax(Tensor input, int dim, int input_zero_point, int output_zero_point, int input_multiplier, int input_shift, int diff_min) -> Tensor" +) +lib.define( + "softmax.out(Tensor input, int dim, int input_zero_point, int output_zero_point, int input_multiplier, int input_shift, int diff_min, *, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::softmax") +def softmax_meta( + input: torch.Tensor, + dim: int, + input_zero_point: int, + output_zero_point: int, + input_multiplier: int, + input_shift: int, + diff_min: int, +) -> torch.Tensor: + return torch.empty_like(input, dtype=torch.int8) + + +@impl(lib, "softmax", "CompositeExplicitAutograd") +def softmax_impl( + input: torch.Tensor, + dim: int, + input_zero_point: int, + output_zero_point: int, + input_multiplier: int, + input_shift: int, + diff_min: int, +) -> torch.Tensor: + del diff_min # not used in reference path + if input.dtype != torch.int8: + raise TypeError( + f"cortex_m.softmax: expected int8 input tensor, got {input.dtype}" + ) + if output_zero_point != CMSIS_SOFTMAX_ZERO_POINT: + raise ValueError( + f"cortex_m.softmax: expected output_zero_point {CMSIS_SOFTMAX_ZERO_POINT}, got {output_zero_point}" + ) + + real_multiplier = float(input_multiplier) / float(1 << 31) + real_multiplier = math.ldexp(real_multiplier, input_shift) + input_scale = real_multiplier / float(1 << (31 - SOFTMAX_INPUT_INTEGER_BITS)) + if input_scale <= 0: + raise ValueError( + f"cortex_m.softmax: derived non-positive input scale {input_scale}" + ) + + input_fp = (input.to(torch.int32) - int(input_zero_point)).float() * input_scale + probs = torch.softmax(input_fp, dim=dim) + quantized = torch.round(probs / CMSIS_SOFTMAX_SCALE) + int(output_zero_point) + return quantized.clamp(-128, 127).to(torch.int8) + + +# =================================================================== +# TRANSPOSE OPERATION DEFINITION +# =================================================================== +lib.define("transpose(Tensor input, int[] perm) -> Tensor") +lib.define("transpose.out(Tensor input, int[] perm, *, Tensor(a!) out) -> Tensor(a!)") + + +@register_fake("cortex_m::transpose") +def transpose_meta(input: torch.Tensor, perm) -> torch.Tensor: + output_shape = [input.shape[idx] for idx in perm] + return torch.empty(output_shape, dtype=input.dtype, device=input.device) + + +@impl(lib, "transpose", "CompositeExplicitAutograd") +def transpose_impl(input: torch.Tensor, perm) -> torch.Tensor: + return input.permute(tuple(perm)).contiguous() + + +# =================================================================== +# QUANTIZED CONV2D OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_conv2d(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max" + ") -> Tensor" +) + + +lib.define( + "quantized_conv2d.out(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max, " + "*, Tensor(a!) out" + ") -> Tensor(a!)" +) + + +def _compute_conv2d_output_shape( + input_shape: torch.Size, + weight_shape: torch.Size, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], +) -> torch.Size: + batch = input_shape[0] + in_height = input_shape[2] + in_width = input_shape[3] + # We store the weights in OHWI layout (out, kernel_h, kernel_w, in) + kernel_height = weight_shape[1] + kernel_width = weight_shape[2] + + stride_h, stride_w = stride + pad_h, pad_w = padding + dilation_h, dilation_w = dilation + + out_channels = weight_shape[0] + out_height = ( + in_height + 2 * pad_h - dilation_h * (kernel_height - 1) - 1 + ) // stride_h + 1 + out_width = ( + in_width + 2 * pad_w - dilation_w * (kernel_width - 1) - 1 + ) // stride_w + 1 + return torch.Size([batch, out_channels, out_height, out_width]) + + +def _compute_depthwise_conv2d_output_shape( + input_shape: torch.Size, + weight_shape: torch.Size, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], +) -> torch.Size: + batch = input_shape[0] + in_height = input_shape[2] + in_width = input_shape[3] + # For depthwise conv, we store the weights in IHWO layout (1, kernel_h, kernel_w, out) + # where dimension 3 contains the output channels + kernel_height = weight_shape[1] + kernel_width = weight_shape[2] + + stride_h, stride_w = stride + pad_h, pad_w = padding + dilation_h, dilation_w = dilation + + out_channels = weight_shape[3] # IHWO format: output channels at dimension 3 + out_height = ( + in_height + 2 * pad_h - dilation_h * (kernel_height - 1) - 1 + ) // stride_h + 1 + out_width = ( + in_width + 2 * pad_w - dilation_w * (kernel_width - 1) - 1 + ) // stride_w + 1 + return torch.Size([batch, out_channels, out_height, out_width]) + + +@register_fake("cortex_m::quantized_conv2d") +def quantized_conv2d_meta( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + stride_vals = list(stride) + padding_vals = list(padding) + dilation_vals = list(dilation) + output_shape = _compute_conv2d_output_shape( + input.shape, weight.shape, stride_vals, padding_vals, dilation_vals + ) + return torch.empty( + output_shape, + dtype=torch.int8, + device=input.device, + memory_format=torch.channels_last, + ) + + +@impl(lib, "quantized_conv2d", "CompositeExplicitAutograd") +def quantized_conv2d_impl( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + if input.dim() != 4 or weight.dim() != 4: + raise RuntimeError("quantized_conv2d expects 4D input and weight tensors") + # Convert to int32 for accumulation and apply offsets + input_int32 = input.to(torch.int32) + int(input_offset) + weight_int32 = weight.to(torch.int32) + + if bias is None: + bias_int32 = torch.zeros( + weight.shape[0], dtype=torch.int32, device=input.device + ) + else: + bias_int32 = bias.to(torch.int32) + + input_channels = input.shape[1] + kernel_input_channels = weight.shape[3] + groups = input_channels // kernel_input_channels + + # Convert weights back to OIHW layout expected by torch.nn.functional.conv2d + weight_oi_hw = weight_int32.permute(0, 3, 1, 2).contiguous() + + conv_acc = F.conv2d( + input_int32, + weight_oi_hw, + bias_int32, + stride=tuple(stride), + padding=tuple(padding), + dilation=tuple(dilation), + groups=groups, + ) + + result_channels = [] + for output_channel_i in range(conv_acc.shape[1]): + result_channel = requantize_cmsis( + conv_acc[:, output_channel_i, :, :], + int(requantize_multipliers[output_channel_i]), + int(requantize_shifts[output_channel_i]), + ) + result_channels.append(result_channel) + + result = torch.stack(result_channels, dim=1) + + result += output_offset + result = torch.clamp(result, activation_min, activation_max) + + return result.to(torch.int8) + + +# =================================================================== +# QUANTIZED DEPTHWISE CONV2D OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_depthwise_conv2d(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int depth_multiplier, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max" + ") -> Tensor" +) + + +lib.define( + "quantized_depthwise_conv2d.out(" + "Tensor input, " + "Tensor weight, " + "Tensor? bias, " + "int[] stride, " + "int[] padding, " + "int[] dilation, " + "int depth_multiplier, " + "int input_offset, " + "int output_offset, " + "Tensor requantize_multipliers, " + "Tensor requantize_shifts, " + "int activation_min, " + "int activation_max, " + "*, Tensor(a!) out" + ") -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_depthwise_conv2d") +def quantized_depthwise_conv2d_meta( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + depth_multiplier: int, + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + stride_vals = list(stride) + padding_vals = list(padding) + dilation_vals = list(dilation) + output_shape = _compute_depthwise_conv2d_output_shape( + input.shape, weight.shape, stride_vals, padding_vals, dilation_vals + ) + return torch.empty( + output_shape, + dtype=torch.int8, + device=input.device, + memory_format=torch.channels_last, + ) + + +@impl(lib, "quantized_depthwise_conv2d", "CompositeExplicitAutograd") +def quantized_depthwise_conv2d_impl( + input: torch.Tensor, + weight: torch.Tensor, + bias: torch.Tensor | None, + stride: Sequence[int], + padding: Sequence[int], + dilation: Sequence[int], + depth_multiplier: int, + input_offset: int, + output_offset: int, + requantize_multipliers: torch.Tensor, + requantize_shifts: torch.Tensor, + activation_min: int, + activation_max: int, +) -> torch.Tensor: + if input.dim() != 4 or weight.dim() != 4: + raise RuntimeError( + "quantized_depthwise_conv2d expects 4D input and weight tensors" + ) + + input_channels = input.shape[1] + groups = input_channels + + # Convert to int32 for accumulation and apply offsets + input_int32 = input.to(torch.int32) + int(input_offset) + weight_int32 = weight.to(torch.int32) + + if bias is None: + bias_int32 = torch.zeros( + weight.shape[3], + dtype=torch.int32, + device=input.device, # C_OUT is at dim 3 in IHWO + ) + else: + bias_int32 = bias.to(torch.int32) + + # Weight is in IHWO layout: [1, H, W, C_OUT] + # Convert to OIHW layout expected by torch.nn.functional.conv2d + # IHWO [1, H, W, C_OUT] -> OIHW [C_OUT, 1, H, W] + weight_oi_hw = weight_int32.permute(3, 0, 1, 2).contiguous() + + # Depthwise convolution has groups == input_channels + conv_acc = F.conv2d( + input_int32, + weight_oi_hw, + bias_int32, + stride=tuple(stride), + padding=tuple(padding), + dilation=tuple(dilation), + groups=groups, + ) + + result_channels = [] + for output_channel_i in range(conv_acc.shape[1]): + result_channel = requantize_cmsis( + conv_acc[:, output_channel_i, :, :], + int(requantize_multipliers[output_channel_i]), + int(requantize_shifts[output_channel_i]), + ) + result_channels.append(result_channel) + + result = torch.stack(result_channels, dim=1) + + result += output_offset + result = torch.clamp(result, activation_min, activation_max) + + return result.to(torch.int8) + + +# =================================================================== +# QUANTIZED AVG_POOL2D OPERATION DEFINITION +# =================================================================== + +lib.define( + "quantized_avg_pool2d(" + "Tensor input, " + "int[] kernel_size, " + "int[] stride, " + "int[] padding, " + "Scalar zero_point, " + "Scalar multiplier, " + "Scalar shift" + ") -> Tensor" +) +lib.define( + "quantized_avg_pool2d.out(" + "Tensor input, " + "int[] kernel_size, " + "int[] stride, " + "int[] padding, " + "Scalar zero_point, " + "Scalar multiplier, " + "Scalar shift, " + "*, Tensor(a!) out) -> Tensor(a!)" +) + + +@register_fake("cortex_m::quantized_avg_pool2d") +def quantized_avg_pool2d_meta( + input: torch.Tensor, + kernel_size: Sequence[int], + stride: Sequence[int], + padding: Sequence[int], + zero_point: int, + multiplier: int, + shift: int, +) -> torch.Tensor: + # Compute output shape as in PyTorch avg_pool2d + + output = F.avg_pool2d(input, kernel_size, stride, padding) + return torch.empty_like(output, dtype=torch.int8) + + +@impl(lib, "quantized_avg_pool2d", "CompositeExplicitAutograd") +def quantized_avg_pool2d_impl( + input: torch.Tensor, + kernel_size: Sequence[int], + stride: Sequence[int], + padding: Sequence[int], + zero_point: int, + multiplier: int, + shift: int, +) -> torch.Tensor: + + dequant_input = dequantize_per_tensor_cmsis(input, zero_point, multiplier, shift) + + # TODO: implement count_include_pad=True, ceil_mode=True. + result = F.avg_pool2d( + dequant_input, + kernel_size, + stride=stride, + padding=padding, + count_include_pad=False, + ceil_mode=False, + ) + result = quantize_per_tensor_cmsis(result, zero_point, multiplier, shift) + output = torch.clamp(result, -128, 127) + return output.to(torch.int8) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/operators.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/operators.yaml similarity index 56% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/operators.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/operators.yaml index e0ebbfa..d1222c3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/operators.yaml +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/operators.yaml @@ -1,6 +1,6 @@ # Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. -# Copyright 2025-2026 Arm Limited and/or its affiliates. +# Copyright 2025 Arm Limited and/or its affiliates. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. @@ -17,13 +17,13 @@ - arg_meta: null kernel_name: cortex_m::dequantize_per_tensor_out -- func: cortex_m::quantized_add.out(Tensor self, int self_zero_point, int self_multiplier, int self_shift, Tensor other, int other_zero_point, int other_multiplier, int other_shift, int output_zero_point, int output_multiplier, int output_shift, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_add.out(Tensor self, Scalar self_zero_point, Scalar self_multiplier, Scalar self_shift, Tensor other, Scalar other_zero_point, Scalar other_multiplier, Scalar other_shift, Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null kernel_name: cortex_m::quantized_add_out -- func: cortex_m::quantized_mul.out(Tensor self, int self_zero_point, Tensor other, int other_zero_point, int output_zero_point, int output_multiplier, int output_shift, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_mul.out(Tensor self, Scalar self_zero_point, Tensor other, Scalar other_zero_point, Scalar output_zero_point, Scalar output_multiplier, Scalar output_shift, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null @@ -41,7 +41,7 @@ - arg_meta: null kernel_name: cortex_m::maximum_out -- func: cortex_m::quantized_linear.out(Tensor input, Tensor weights, Tensor? bias, Tensor? kernel_sum, int input_offset, int filter_offset, int output_offset, int[] requantize_multipliers, int[] requantize_shifts, int activation_max, int activation_min, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_linear.out(Tensor input, Tensor weights, Tensor? bias, Tensor? kernel_sum, Scalar input_offset, Scalar filter_offset, Scalar output_offset, int[] requantize_multipliers, int[] requantize_shifts, Scalar activation_max, Scalar activation_min, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null @@ -59,12 +59,6 @@ - arg_meta: null kernel_name: cortex_m::transpose_out -- func: cortex_m::pad.out(Tensor input, int[] pre_pad, int[] post_pad, int pad_value, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::pad_out - - func: cortex_m::quantized_conv2d.out(Tensor input, Tensor weight, Tensor? bias, int[] stride, int[] padding, int[] dilation, int input_offset, int output_offset, Tensor requantize_multipliers, Tensor requantize_shifts, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: @@ -77,25 +71,8 @@ - arg_meta: null kernel_name: cortex_m::quantized_depthwise_conv2d_out -- func: cortex_m::quantized_transpose_conv2d.out(Tensor input, Tensor weight, Tensor? bias, int[] stride, int[] padding, int[] output_padding, int[] dilation, int input_offset, int output_offset, Tensor requantize_multipliers, Tensor requantize_shifts, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::quantized_transpose_conv2d_out - -- func: cortex_m::quantized_avg_pool2d.out(Tensor input, int[] kernel_size, int[] stride, int[] padding, int zero_point, int multiplier, int shift, *, Tensor(a!) out) -> Tensor(a!) +- func: cortex_m::quantized_avg_pool2d.out(Tensor input, int[] kernel_size, int[] stride, int[] padding, Scalar zero_point, Scalar multiplier, Scalar shift, *, Tensor(a!) out) -> Tensor(a!) variants: function kernels: - arg_meta: null kernel_name: cortex_m::quantized_avg_pool2d_out -- func: cortex_m::quantized_max_pool2d.out(Tensor input, int[] kernel_size, int[] stride, int[] padding, int[] dilation, bool ceil_mode, int input_zero_point, int output_zero_point, int activation_min, int activation_max, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::quantized_max_pool2d_out - -- func: cortex_m::quantized_batch_matmul.out(Tensor lhs, int lhs_zero_point, Tensor rhs_transposed, int rhs_zero_point, int output_zero_point, int output_multiplier, int output_shift, *, Tensor(a!) out) -> Tensor(a!) - variants: function - kernels: - - arg_meta: null - kernel_name: cortex_m::quantized_batch_matmul_out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/targets.bzl new file mode 100644 index 0000000..250fcf9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/ops/targets.bzl @@ -0,0 +1,80 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//tools/build_defs:platform_defs.bzl", "CXX") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") +load("@fbcode_macros//build_defs:export_files.bzl", "export_file") + +def define_operator_target(name: str): + runtime.cxx_library( + name = "op_{}".format(name), + srcs = [ + "op_{}.cpp".format(name), + ], + platforms = CXX, + deps = [ + "//executorch/runtime/kernel:kernel_includes" + ], + link_whole = True, + ) + +OPERATORS = [ + "quantize_per_tensor", + "dequantize_per_tensor", +] + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + for op in OPERATORS: + define_operator_target(op) + + all_op_targets = [":op_{}".format(op) for op in OPERATORS] + + runtime.cxx_library( + name = "cortex_m_operators", + srcs = [], + visibility = ["PUBLIC"], + platforms = CXX, + exported_deps = all_op_targets, + ) + + export_file(name = "operators.yaml") + + et_operator_library( + name = "ops_lib", + _is_external_target = True, + ops_schema_yaml_target = ":operators.yaml", + ) + + executorch_generated_lib( + name = "cortex_m_generated_lib", + deps = [ + ":ops_lib", + ":cortex_m_operators", + ], + functions_yaml_target = ":operators.yaml", + platforms = CXX, + visibility = ["PUBLIC"], + define_static_targets = True, + ) + + executorch_generated_lib( + name = "cortex_m_no_except_generated_lib", + deps = [ + ":ops_lib", + ":cortex_m_operators", + ], + functions_yaml_target = ":operators.yaml", + platforms = CXX, + visibility = ["PUBLIC"], + define_static_targets = True, + support_exceptions = False, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/TARGETS new file mode 100644 index 0000000..687aafe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/TARGETS @@ -0,0 +1,35 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +oncall("executorch") + +runtime.python_library( + name="replace_quant_nodes_pass", + srcs=[ + "replace_quant_nodes_pass.py", + "quantized_op_fusion_pass.py", + ], + deps=[ + "//caffe2:torch", + "//executorch/exir:lib", + "//executorch/exir:pass_base", + "//executorch/exir/dialects:lib", + "//executorch/backends/cortex_m/ops:ops", + "//executorch/backends/cortex_m/passes:passes_utils", + ], +) + +runtime.python_library( + name="passes_utils", + srcs=[ + "passes_utils.py", + ], + deps=[ + "fbcode//caffe2:torch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/__init__.py new file mode 100644 index 0000000..c8bb743 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/__init__.py @@ -0,0 +1,12 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from .activation_fusion_pass import ActivationFusionPass # noqa +from .clamp_hardswish_pass import ClampHardswishPass # noqa +from .convert_to_cortex_m_pass import ConvertToCortexMPass # noqa +from .decompose_hardswish_pass import DecomposeHardswishPass # noqa +from .quantized_op_fusion_pass import QuantizedOpFusionPass # noqa +from .replace_quant_nodes_pass import ReplaceQuantNodesPass # noqa +from .cortex_m_pass_manager import CortexMPassManager # noqa # usort: skip diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/activation_fusion_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/activation_fusion_pass.py new file mode 100644 index 0000000..864f9e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/activation_fusion_pass.py @@ -0,0 +1,181 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import executorch.backends.cortex_m.ops.operators # noqa: F401 +from executorch.backends.arm._passes.quant_args import QuantArgs +from executorch.backends.cortex_m.passes.passes_utils import quantize_val + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass + +from torch.fx import GraphModule, Node +from torch.fx.passes.infra.pass_manager import PassResult + +logger = logging.getLogger(__name__) + + +class ActivationFusionPass(ExportPass): + """Fuse activations into preceding Cortex-M quantized operators. + + Supported activation patterns: + q-> [conv2d, linear] -> [relu, hardtanh, hardsigmoid] -> dq + + Fusing works by clamping the quantized output range (and zero-point when + required) of the preceding Cortex-M operator, then removing the activation + node from the graph. + """ + + TARGETS = { + exir_ops.edge.aten.relu.default, + exir_ops.edge.aten.hardtanh.default, + exir_ops.edge.aten.hardsigmoid.default, + exir_ops.edge.aten.clamp.default, + } + + FUSE_OPS = { + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.convolution.default, + } + + def _get_validated_qparams(self, node, input_node): + + if "input_qparams" not in input_node.meta or "output_qparams" not in node.meta: + logger.warning( + f"Cannot fuse activation for {input_node.name}->{node.name} as the pattern wasn't quantized properly." + ) + return None + + qparams_dict = node.meta["output_qparams"][0]._asdict() + zp = qparams_dict["zp"] + scale = qparams_dict["scale"] + qmin = qparams_dict["qmin"] + qmax = qparams_dict["qmax"] + + if not isinstance(scale, float) or not isinstance(zp, int): + logger.warning( + f"Cannot fuse activation {node.name} as quantization parameters are not per tensor." + ) + return None + + match node.target: + case exir_ops.edge.aten.relu.default: + quantized_min_val = quantize_val(0, scale, zp, qmin, qmax) + quantized_max_val = qmax + case exir_ops.edge.aten.hardtanh.default: + quantized_min_val = quantize_val(node.args[1], scale, zp, qmin, qmax) + quantized_max_val = quantize_val(node.args[2], scale, zp, qmin, qmax) + case exir_ops.edge.aten.hardsigmoid.default: + quantized_min_val = quantize_val(0, scale, zp, qmin, qmax) + quantized_max_val = quantize_val(1, scale, zp, qmin, qmax) + case exir_ops.edge.aten.clamp.default: + quantized_min_val = ( + quantize_val(node.args[1], scale, zp, qmin, qmax) + if node.args[1] is not None + else qmin + ) + # Last arg is removed if none, so check length of args here + quantized_max_val = ( + quantize_val(node.args[2], scale, zp, qmin, qmax) + if len(node.args) == 3 + else qmax + ) + case _: + raise RuntimeError("Unexpected target {node.target}.") + + # If the minimal quantized value is larger than the qmin, it means that the quantized range contains + # invalid values [qmin, ..., quantized_min_val-1], indicating bad quantization parameters. + if qparams_dict["qmin"] != quantized_min_val: + logger.warning( + f"Cannot fuse activation {node.name} as qmin is out of range." + ) + return None + + # If the maximal quantized value is smaller than the qmax, it means that the quantized range contains + # invalid values [quantized_max_val + 1, ... , qmax], indicating bad quantization parameters. + if quantized_max_val != qparams_dict["qmax"]: + logger.warning( + f"Cannot fuse activation {node.name} as qmax is out of range." + ) + return None + + return qparams_dict + + def _update_qparams_hardsigmoid(self, quant_dict): + """ + Returns quant_dict with scale and zp updated to match hardsigmoid activation. + + The quantized output from the hard sigmoid is defined by + Q(y) = clamp(round(y/scale + zp), qmin, qmax) + y = clamp(x/6 + 1/2, 0, 1) + where x is the output of the fused activation op, conv or linear. + + Q(y) can be rewritten as a function of only x: + Q(y) = clamp(round(clamp(x/6 + 1/2, 0, 1)/scale + zp), qmin, qmax) + Q(y) = clamp(round(clamp((x/(6*scale) + 1/(2*scale) + zp, zp, 1/scale + zp)), qmin, qmax) + + From definition of the qparams mapping the output in the range [0,1] to quantized range + [qmin, qmax], we have: + zp = Q(0) <= qmin + 1/scale + zp = Q(1) >= qmax + which makes the inner clamp redundant. + + Therefore, hardsigmoid is equivalent to a quantization with modified parameters + new_scale := 6*scale + new_zp = zp + 1/(2*scale) ~= zp + round(1/(2*scale)) + """ + + new_scale = quant_dict["scale"] * 6 + + new_zp = quant_dict["zp"] + round(1 / (2 * quant_dict["scale"])) + clamped_new_zp = max(quant_dict["qmin"], min(quant_dict["qmax"], new_zp)) + + quant_dict["scale"] = new_scale + quant_dict["zp"] = clamped_new_zp + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + nodes_to_erase: list[Node] = [] + + for node in list(graph_module.graph.nodes): + if node.op != "call_function" or node.target not in self.TARGETS: + continue + + input_node = node.args[0] + if ( + input_node.op != "call_function" + or input_node.target not in self.FUSE_OPS + ): + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} is not a supported fused activation op." + ) + continue + if len(input_node.users.values()) > 1: + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} has multiple users." + ) + continue + + if (qparams_dict := self._get_validated_qparams(node, input_node)) is None: + continue + + if node.target == exir_ops.edge.aten.hardsigmoid.default: + self._update_qparams_hardsigmoid(qparams_dict) + + input_node.meta["output_qparams"][0] = QuantArgs(**qparams_dict) + + node.replace_all_uses_with(input_node) + nodes_to_erase.append(node) + modified = True + + for node in nodes_to_erase: + graph_module.graph.erase_node(node) + + if modified: + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/clamp_hardswish_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/clamp_hardswish_pass.py new file mode 100644 index 0000000..d257520 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/clamp_hardswish_pass.py @@ -0,0 +1,37 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict + +import torch + +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, NodeMetadata, ProxyValue +from torch.fx.node import Argument + + +class ClampHardswishPass(ExportPass): + """ + Adds a clamp operation before hardswish to ensure input is in the range [-3, inf). + + By doing this before quantization the output range of the preceeding op is minimized, + potentially improving accuracy. + """ + + def call_operator( + self, + op: EdgeOpOverload, + args: tuple[Argument, ...], + kwargs: Dict[str, Argument], + meta: NodeMetadata, + ) -> ProxyValue: + if op == torch.ops.aten.hardswish.default: + clamped_args = (args[0], -3) + clamped_input = super().call_operator( + torch.ops.aten.clamp.default, clamped_args, {}, meta + ) + args = (clamped_input,) + + return super().call_operator(op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/convert_to_cortex_m_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/convert_to_cortex_m_pass.py new file mode 100644 index 0000000..bed82c7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/convert_to_cortex_m_pass.py @@ -0,0 +1,318 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import executorch.backends.cortex_m.ops.operators # noqa + +import torch +import torch.fx +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.cortex_m.passes.passes_utils import quantize_multiplier_aot + +from executorch.backends.transforms.utils import ( + create_constant_placeholder, + get_param_tensor, +) + +from executorch.backends.xnnpack._passes.xnnpack_pass import XNNPACKPass +from executorch.exir.dialects._ops import ops as exir_ops +from torch.export.graph_signature import InputKind +from torch.fx.passes.infra.pass_manager import PassResult + + +class ConvertToCortexMPass(XNNPACKPass): + """ + Cortex-M backend pass for replacing supported quantized kernels with Cortex-M + accelerated kernels. + + Used for ops which require changes to input tensors which is not supported + by call_operator. + """ + + def _compute_kernel_sum(self, weights, bias, input_offset, weight_offset): + """ + Computes the precomputed kernel sum term (bias optional) + a * sum_j(wij + b) + ci + + for i = (1, ..., n), where j indexes the input activations. + """ + weights_transposed = weights.T + weights_int32 = weights_transposed.to(torch.int32) + offset_weights = weights_int32 + weight_offset + kernel_sum = torch.sum(offset_weights, dim=0, keepdim=True, dtype=torch.int32) + kernel_sum_offset = kernel_sum * input_offset + + if bias is not None: + kernel_sum_offset += bias + + return kernel_sum_offset + + def _get_batch_size_from_conv(self, conv_node: torch.fx.Node): + """ + Extract batch size from convolution node's output shape. + + Returns None if shape metadata is unavailable, which can occur when + processing nodes created earlier in the same pass iteration. + + For Conv2d operations, output_batch_size always equals input_batch_size. + Conv2d outputs are always 4D (N, C, H, W) in the edge dialect. + """ + try: + if "val" in conv_node.meta: + output_shape = conv_node.meta["val"].shape + return output_shape[0] + except (AttributeError, TypeError): + pass + return None + + def _get_linear_replacement(self, node): + """ + Let + - yi be the output activations (y1, ... yn) + - xj be the input activations (x1, ... xm) + - wij be the weights (w11, ... wnm) + - a be the input offset + - b be the weight offset + - ci be the bias + + Then the linear operation can be written as: + yi = sum_j((xj + a) * (wij + b)) + ci + = sum_j(xj*wij + xj*b + a*wij + a*b) + ci + = sum_j(xj*wij) + sum_j(xj)*b + (a * sum_j(wij + b) + ci) + = sum_j(xj*wij) + sum_j(xj)*b + kernel_sum + + where kernel_sum is precomputed aot. + """ + input_scale = node.meta["input_qparams"][0].scale + input_zp = node.meta["input_qparams"][0].zp + weight_scale = node.meta["input_qparams"][1].scale + weight_zp = node.meta["input_qparams"][1].zp + output_scale = node.meta["output_qparams"][0].scale + output_zp = node.meta["output_qparams"][0].zp + output_min = node.meta["output_qparams"][0].qmin + output_max = node.meta["output_qparams"][0].qmax + + quantized_multiplier, quantized_shift = quantize_multiplier_aot( + (input_scale * weight_scale) / output_scale + ) + + # TODO: Add support for configuring the backend to support other extensions. + # Kernel sum is only used in the CMSIS-NN implementation for the MVE extension, + # so this should be optional. + weights = node.args[1] + weights_tensor = get_param_tensor(self.exported_program, weights) + bias_tensor = ( + get_param_tensor(self.exported_program, node.args[2]) + if len(node.args) > 2 + else None + ) + kernel_sum_tensor = self._compute_kernel_sum( + weights_tensor, bias_tensor, -input_zp, -weight_zp + ) + with node.graph.inserting_after(weights): + kernel_sum = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_kernel_sum", + InputKind.PARAMETER, + kernel_sum_tensor, + ) + + args = ( + node.args[0], + weights, + None, + kernel_sum, + -input_zp, + -weight_zp, + output_zp, + [quantized_multiplier], + [quantized_shift], + output_max, + output_min, + ) + + return exir_ops.edge.cortex_m.quantized_linear.default, args + + def _get_convolution_replacement(self, node) -> int: + ( + x, + weight, + bias, + stride, + padding, + dilation, + transposed, + output_padding, + groups, + ) = node.args + + # Extract values + input_scale = node.meta["input_qparams"][0].scale + input_zero_point = node.meta["input_qparams"][0].zp + weight_scales = node.meta["input_qparams"][1].scale + if not isinstance(weight_scales, list): + weight_tensor = get_first_fake_tensor(weight) + weight_scales = [weight_scales] * weight_tensor.shape[0] + + output_qparams = node.meta["output_qparams"][0] + output_scale = output_qparams.scale + output_zero_point = output_qparams.zp + output_qmin = output_qparams.qmin + output_qmax = output_qparams.qmax + + quantized_multipliers = [] + quantized_shifts = [] + for weight_scale in weight_scales: + quantized_multiplier, quantized_shift = quantize_multiplier_aot( + input_scale * weight_scale / output_scale + ) + quantized_multipliers.append(quantized_multiplier) + quantized_shifts.append(quantized_shift) + + weight_tensor = get_param_tensor(self.exported_program, weight) + + # Detect depthwise convolution: + # Depthwise means groups == in_channels, out_channels == K * in_channels + # Weight shape is [out_ch, in_ch_per_group, H, W] + in_channels = weight_tensor.shape[1] * groups + out_channels = weight_tensor.shape[0] + is_depthwise = (in_channels == groups) and (out_channels % in_channels == 0) + + # Only use DW path if batch_size==1, as CMSIS-NN DW falls back to + # unoptimized implementation otherwise. + batch_size = self._get_batch_size_from_conv(node) + + # TODO(#16347): It is likely but not certain that the un-optimized + # CMSIS-NN DW conv or the one without any SIMD is less efficient that + # the corresponding CMSIS-NN conv. We should benchmark and update the + # constraints. + # optimal_dw_conv_constraints = (batch_size == 1) and ( + # (in_channels == out_channels and dilation == [1, 1]) or (in_channels == 1) + # ) + use_depthwise_conv = is_depthwise and (batch_size == 1) + + if use_depthwise_conv: + # For depthwise: OIHW -> IHWO which gives [1, H, W, C_OUT] for CMSIS-NN + # PyTorch depthwise weight is [out_ch, 1, H, W], permute to [1, H, W, out_ch] + weight_permuted = weight_tensor.permute(1, 2, 3, 0).contiguous( + memory_format=torch.channels_last + ) + else: + # For regular conv: OIHW -> OHWI + weight_permuted = weight_tensor.permute(0, 2, 3, 1).contiguous( + memory_format=torch.channels_last + ) + + with node.graph.inserting_after(weight): + weight_nhwc = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_weight_nhwc", + InputKind.PARAMETER, + weight_permuted, + ) + + quantized_multiplier_tensor = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_quantized_multiplier", + InputKind.PARAMETER, + torch.tensor(quantized_multipliers, dtype=torch.int32), + ) + + quantized_shift_tensor = create_constant_placeholder( + self.exported_program, + node.graph, + node.name + "_quantized_shift", + InputKind.PARAMETER, + torch.tensor(quantized_shifts, dtype=torch.int32), + ) + + if use_depthwise_conv: + # Compute depth_multiplier for depthwise convolution + # For depthwise: output_channels = input_channels * depth_multiplier + + if out_channels % in_channels != 0: + raise ValueError( + f"Depthwise conv: output_channels ({out_channels}) must be " + f"divisible by input_channels ({in_channels})" + ) + depth_multiplier = out_channels // in_channels + + new_args = ( + x, + weight_nhwc, + bias, + stride, + padding, + dilation, + depth_multiplier, + -input_zero_point, + output_zero_point, + quantized_multiplier_tensor, + quantized_shift_tensor, + output_qmin, + output_qmax, + ) + return exir_ops.edge.cortex_m.quantized_depthwise_conv2d.default, new_args + else: + # Use regular convolution operator + new_args = ( + x, + weight_nhwc, + bias, + stride, + padding, + dilation, + -input_zero_point, + output_zero_point, + quantized_multiplier_tensor, + quantized_shift_tensor, + output_qmin, + output_qmax, + ) + return exir_ops.edge.cortex_m.quantized_conv2d.default, new_args + + def call(self, graph_module: torch.fx.GraphModule) -> PassResult: + modified = False + for node in graph_module.graph.nodes: + if node.op != "call_function": + continue + if ( + node.meta.get("input_qparams", {}) == {} + or node.meta.get("output_qparams", {}) == {} + ): + continue + + match node.target: + case exir_ops.edge.aten.linear.default: + op, args = self._get_linear_replacement(node) + case exir_ops.edge.aten.convolution.default: + op, args = self._get_convolution_replacement(node) + case _: + continue + + with graph_module.graph.inserting_before(node): + cortex_m_op = graph_module.graph.create_node( + "call_function", + target=op, + args=args, + kwargs={}, + ) + + node.replace_all_uses_with(cortex_m_op) + graph_module.graph.erase_node(node) + + modified = True + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + graph_module = super().call(graph_module).graph_module + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/cortex_m_pass_manager.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/cortex_m_pass_manager.py new file mode 100644 index 0000000..c47bcc3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/cortex_m_pass_manager.py @@ -0,0 +1,73 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import inspect + +from executorch.backends.arm._passes import ( + FoldAndAnnotateQParamsPass, + ScalarsToAttributePass, +) +from executorch.backends.transforms.replace_scalar_with_tensor import ( + ReplaceScalarWithTensorArgPass, +) +from executorch.exir.pass_base import ExportPass +from executorch.exir.pass_manager import PassManager +from executorch.exir.program._program import _transform +from torch.export import ExportedProgram + +from .activation_fusion_pass import ActivationFusionPass +from .clamp_hardswish_pass import ClampHardswishPass +from .convert_to_cortex_m_pass import ConvertToCortexMPass +from .decompose_hardswish_pass import DecomposeHardswishPass +from .quantized_op_fusion_pass import QuantizedOpFusionPass +from .replace_quant_nodes_pass import ReplaceQuantNodesPass + + +class CortexMPassManager(PassManager): + + pass_list: list[ExportPass] = [ + FoldAndAnnotateQParamsPass, + ReplaceScalarWithTensorArgPass, + ReplaceQuantNodesPass, + ActivationFusionPass, + DecomposeHardswishPass, + QuantizedOpFusionPass, + ConvertToCortexMPass, + ] + + pass_list_transform_for_annotation: list[ExportPass] = [ + ScalarsToAttributePass, + ReplaceScalarWithTensorArgPass, + ClampHardswishPass, + ] + + def __init__(self, exported_program, passes=None): + self.exported_program = exported_program + if passes is not None: + self.passes = passes + else: + self.passes = self.pass_list + + def transform_for_annotation(self, model): + passes = self.pass_list_transform_for_annotation + for p in passes: + model = p().call(model).graph_module + return model + + def transform(self) -> ExportedProgram: + ep = self.exported_program + for pass_ in self.passes: + signature = inspect.signature(pass_.__init__) + if "exported_program" in signature.parameters: + transform_pass = pass_(ep) + elif issubclass(pass_, ExportPass): + transform_pass = pass_() + else: + raise RuntimeError( + f"Expecting ExportPass or ExportPass(), but got pass: {pass_} with type: {type(pass_)}" + ) + ep = _transform(ep, transform_pass) + return ep diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/decompose_hardswish_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/decompose_hardswish_pass.py new file mode 100644 index 0000000..36ca6bd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/decompose_hardswish_pass.py @@ -0,0 +1,127 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import executorch.backends.cortex_m.ops.operators # noqa: F401 + +import torch +from executorch.backends.arm._passes.quant_args import QuantArgs + +from executorch.backends.cortex_m.passes.passes_utils import quantize_val + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass +from torch.fx import GraphModule, Node +from torch.fx.passes.infra.pass_manager import PassResult + +logger = logging.getLogger(__name__) + + +class DecomposeHardswishPass(ExportPass): + """ + Decomposes hardswish like + + hardswish(x) = x * (clamp(x, -3, 3) + 3)/6 + + where the add and division is implemented by modifying the quantization parameters similar + to hardsigmoid in the activation_fusion_pass. Note that this pass assumes + that the output range of the preceding op is already clamped to [-3, inf] during + quantization by the clamp_hardswish_pass, removing the need for the negative clamp. + """ + + TARGETS = { + exir_ops.edge.aten.hardswish.default, + } + + FUSE_OPS = { + exir_ops.edge.aten.linear.default, + exir_ops.edge.aten.convolution.default, + } + + def call(self, graph_module: GraphModule) -> PassResult: + modified = False + nodes_to_erase: list[Node] = [] + + for node in list(graph_module.graph.nodes): + if node.op != "call_function" or node.target not in self.TARGETS: + continue + + input_node = node.args[0] + if ( + input_node.op != "call_function" + or input_node.target not in self.FUSE_OPS + ): + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} is not a supported fused activation op." + ) + continue + if len(input_node.users.values()) > 1: + logger.warning( + f"Cannot fuse activation {node.name} as input node {input_node.name} has multiple users." + ) + continue + + input_quant_dict = input_node.meta.get("output_qparams", [None])[ + 0 + ]._asdict() + scale = input_quant_dict["scale"] + zero_point = input_quant_dict["zp"] + qmin = input_quant_dict["qmin"] + qmax = input_quant_dict["qmax"] + + # Create min node + with graph_module.graph.inserting_after(input_node): + clamp_node = graph_module.graph.create_node( + "call_function", + target=exir_ops.edge.aten.minimum.default, + args=( + input_node, + torch.tensor( + quantize_val(3, scale, zero_point, qmin, qmax), + dtype=torch.int8, + ), + ), + kwargs={}, + ) + clamp_node.meta = input_node.meta.copy() + + # Create mul node + with graph_module.graph.inserting_after(clamp_node): + mul_node = graph_module.graph.create_node( + "call_function", + target=exir_ops.edge.aten.mul.Tensor, + args=(input_node, clamp_node), + kwargs={}, + ) + mul_node.meta = node.meta.copy() + + mul_quant_dict = node.meta["input_qparams"][0]._asdict() + + mul_quant_dict_shifted = mul_quant_dict.copy() + mul_quant_dict_shifted["zp"] = mul_quant_dict_shifted["zp"] - round( + 3 / (mul_quant_dict_shifted["scale"]) + ) + + output_quant_dict = node.meta["output_qparams"][0]._asdict() + output_quant_dict["scale"] = output_quant_dict["scale"] * 6 + + node.meta["input_qparams"][0] = QuantArgs(**mul_quant_dict) + mul_node.meta["input_qparams"][1] = QuantArgs(**mul_quant_dict_shifted) + mul_node.meta["output_qparams"][0] = QuantArgs(**output_quant_dict) + + node.replace_all_uses_with(mul_node) + nodes_to_erase.append(node) + modified = True + + for node in nodes_to_erase: + graph_module.graph.erase_node(node) + + if modified: + graph_module.graph.eliminate_dead_code() + graph_module.recompile() + + return PassResult(graph_module, modified) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/passes_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/passes_utils.py new file mode 100644 index 0000000..131541f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/passes_utils.py @@ -0,0 +1,226 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math + +import torch + +from executorch.exir.dialects._ops import ops as exir_ops + +from torch.fx import Node + +# L-shift value used in CMSIS-NN for int8 operations +SHIFT_INT8 = 20 + + +def quantize_val(val, scale, zp, qmin, qmax): + return min(max(round(val / scale + zp), qmin), qmax) + + +def dequantize_per_tensor_cmsis( + qtensor: torch.Tensor, zero_point: int, multiplier: int, shift: int +) -> torch.Tensor: + """ + Simulate CMSIS-NN fixed-point dequantization: + result = (qtensor - zero_point) * multiplier * 2^shift / 2^31 + """ + scale = multiplier * (2**shift) / (1 << 31) + return (qtensor.float() - zero_point) * scale + + +def quantize_per_tensor_cmsis( + tensor: torch.Tensor, + zero_point: int, + multiplier: int, + shift: int, + qmin=-128, + qmax=127, +) -> torch.Tensor: + """ + Simulate CMSIS-NN fixed-point quantization: + result = round(tensor / scale) + zero_point, clamped to [qmin, qmax] + """ + scale = multiplier * (2**shift) / (1 << 31) + quantized = torch.round(tensor / scale) + zero_point + return quantized.clamp(qmin, qmax).to(torch.int8) + + +def requantize_cmsis( + tensor: torch.Tensor, + multiplier: int, + shift: int, +) -> torch.Tensor: + """Simulate CMSIS-NN's arm_nn_requantize helper.""" + + tensor_64 = tensor.to(torch.int64) + left_shift = max(shift, 0) + right_shift = max(-shift, 0) + + # Equivalent to val * (1 << LEFT_SHIFT(shift)) + value = tensor_64 << left_shift + + # arm_nn_doubling_high_mult_no_sat(value, multiplier) + product = value * int(multiplier) + product = product + (1 << 30) + result = product >> 31 + + if right_shift: + remainder_mask = (1 << right_shift) - 1 + remainder = torch.bitwise_and(result, remainder_mask) + result = result >> right_shift + threshold = remainder_mask >> 1 + threshold_tensor = torch.full_like(result, threshold, dtype=torch.int64) + threshold_tensor = torch.where( + result < 0, threshold_tensor + 1, threshold_tensor + ) + result = result + torch.where(remainder > threshold_tensor, 1, 0) + + return result.to(torch.int32) + + +def extract_scalar_value(node_arg) -> float: + """ + Extract scalar value from various PyTorch scalar representations. + """ + if hasattr(node_arg, "op") and node_arg.op == "get_attr": + # Handle case where scalar is a graph attribute + return float(node_arg.target) + elif isinstance(node_arg, (int, float)): + return float(node_arg) + elif hasattr(node_arg, "item"): + return float(node_arg.item()) + else: + # Try to extract from meta if available + if hasattr(node_arg, "meta") and "val" in node_arg.meta: + val = node_arg.meta["val"] + if hasattr(val, "item"): + return float(val.item()) + return float(val) + raise ValueError( + f"Cannot extract scalar value from {type(node_arg)}: {node_arg}" + ) + + +def is_qualified_int8_node(args) -> bool: + try: + if len(args) < 6: + return False + qmin = int(args[3]) + qmax = int(args[4]) + dtype_str = str(args[5]) + is_int8_range = ( + qmin >= torch.iinfo(torch.int8).min and qmax <= torch.iinfo(torch.int8).max + ) + is_int8_dtype = "int8" in dtype_str.lower() + return is_int8_range and is_int8_dtype + except (IndexError, ValueError, TypeError): + return False + + +def quantize_multiplier_aot(scale: float) -> tuple[int, int]: + if scale == 0.0: + return 0, 0 + mantissa, shift = math.frexp(scale) + q_fixed = int(round(mantissa * (1 << 31))) + if q_fixed == (1 << 31): + q_fixed //= 2 + shift += 1 + multiplier = max( + torch.iinfo(torch.int32).min, min(torch.iinfo(torch.int32).max, q_fixed) + ) + return multiplier, shift + + +def cleanup_erased_nodes(graph_module: torch.fx.GraphModule): + # Placeholder for any additional cleanup if needed + pass + + +def transfer_metadata( + new_node: Node, source_node: Node, pass_name: str = "QuantizedPass" +) -> None: + """Transfer metadata with proper provenance tracking.""" + if hasattr(source_node, "meta") and source_node.meta: + new_node.meta = source_node.meta.copy() + if "from_node" in new_node.meta: + from_node_list = new_node.meta.get("from_node", []).copy() + from_node_list.append( + {"source": source_node.name, "pass": pass_name, "op": "fuse"} + ) + new_node.meta["from_node"] = from_node_list + for field in ["tensor_meta", "stack_trace"]: + if field in source_node.meta: + new_node.meta[field] = source_node.meta[field] + + +def is_dequant_node(node: Node) -> bool: + """Check if node is a dequantize operation.""" + dequant_targets = { + exir_ops.edge.cortex_m.dequantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.dequantize_per_channel.default, + } + return node.op == "call_function" and node.target in dequant_targets + + +def is_quant_node(node: Node) -> bool: + """Check if node is a quantize operation.""" + quant_targets = { + exir_ops.edge.cortex_m.quantize_per_tensor.default, + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + } + return node.op == "call_function" and node.target in quant_targets + + +def cleanup_nodes(nodes_to_erase, graph): + """Clean up marked nodes from graph.""" + failed_nodes = [] + + for node in reversed(nodes_to_erase): + if node in graph.nodes and len(node.users) == 0: + try: + graph.erase_node(node) + except Exception as e: + print(f"Warning: Failed to erase node {node}: {e}") + failed_nodes.append(node) + continue + + if failed_nodes: + print(f"Warning: {len(failed_nodes)} nodes could not be erased") + + return failed_nodes + + +def is_channels_last(tensor: torch.Tensor) -> bool: + """Check if a 4D tensor is in channels last format.""" + if tensor.ndim != 4: + return False + + if tensor.shape[1] == 1 or tensor.shape[2] == tensor.shape[3] == 1: + return True + + dim_order = list(tensor.dim_order()) + return dim_order[0:2] == [0, 2] + + +def is_channel_broadcast(tensor1: torch.Tensor, tensor2: torch.Tensor) -> bool: + """ + Check if tensor1 is broadcasted to tensor2 along channel dimension. + Assumes tensor2 has shape [N, C, ...] and tensor1 has shape [N, 1, ...] or [1, C, ...]. + """ + if tensor1.dim() != tensor2.dim(): + return False + if not is_channels_last(tensor1): + return False + if not is_channels_last(tensor2): + return False + + channel_match = tensor1.size(1) == tensor2.size(1) + tensor1_channels_only = tensor1.numel() == tensor1.size(1) + tensor2_channels_only = tensor2.numel() == tensor2.size(1) + + return channel_match and (tensor1_channels_only or tensor2_channels_only) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/quantized_op_fusion_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/quantized_op_fusion_pass.py new file mode 100644 index 0000000..b21cd50 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/quantized_op_fusion_pass.py @@ -0,0 +1,255 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Dict + +import torch + +from executorch.backends.cortex_m.passes.passes_utils import ( + quantize_multiplier_aot, + SHIFT_INT8, +) +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + CMSIS_SOFTMAX_SCALE, + CMSIS_SOFTMAX_ZERO_POINT, +) + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.dialects.edge._ops import EdgeOpOverload +from executorch.exir.pass_base import ExportPass, NodeMetadata, ProxyValue +from torch.fx.node import Argument + + +class QuantizedOpFusionPass(ExportPass): + """ + Generic ExportPass that: + 1. Replaces certain ops with cortex_m variants based on qualifiers. + 2. Fuses patterns: dequantize_per_tensor -> [binary_op] -> quantize_per_tensor + into cortex_m.quantized_[op].default with AoT computed multipliers/shifts. + + + Supports multiple binary operations with backward compatibility for add. + """ + + _SOFTMAX_INPUT_INTEGER_BITS = 5 + + def _get_add_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten.add.Tensor, args + + # Extract values + scale1 = meta["input_qparams"][0].scale + zero_point1 = meta["input_qparams"][0].zp + scale2 = meta["input_qparams"][1].scale + zero_point2 = meta["input_qparams"][1].zp + output_scale = meta["output_qparams"][0].scale + output_zero_point = meta["output_qparams"][0].zp + + # AoT COMPUTATION: Calculate multipliers and shifts + max_scale_2x = 2 * max(scale1, scale2) + + input1_mult, input1_shift = quantize_multiplier_aot(scale1 / max_scale_2x) + input2_mult, input2_shift = quantize_multiplier_aot(scale2 / max_scale_2x) + output_mult, output_shift = quantize_multiplier_aot( + max_scale_2x / (output_scale * (1 << SHIFT_INT8)) + ) + + args = ( + args[0], + zero_point1, + input1_mult, + input1_shift, + args[1], + zero_point2, + input2_mult, + input2_shift, + output_zero_point, + output_mult, + output_shift, + ) + + return exir_ops.edge.cortex_m.quantized_add.default, args + + def _get_mul_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten.mul.Tensor, args + + # Extract values + scale1 = meta["input_qparams"][0].scale + zero_point1 = meta["input_qparams"][0].zp + scale2 = meta["input_qparams"][1].scale + zero_point2 = meta["input_qparams"][1].zp + output_scale = meta["output_qparams"][0].scale + output_zero_point = meta["output_qparams"][0].zp + + scale_factor = (scale1 * scale2) / output_scale + output_mult, output_shift = quantize_multiplier_aot(scale_factor) + + args = ( + args[0], + zero_point1, + args[1], + zero_point2, + output_zero_point, + output_mult, + output_shift, + ) + + return exir_ops.edge.cortex_m.quantized_mul.default, args + + def _compute_softmax_params(self, input_scale: float) -> tuple[int, int, int]: + """ + Convert the incoming per-tensor input scale into the CMSIS fixed-point + parameters expected by `arm_softmax_s8`. + + 1. Clamp the real multiplier to the Q31 range using the fixed number of + input integer bits mandated by CMSIS. + 2. Feed that multiplier through `quantize_multiplier_aot` to get the + (multiplier, shift) pair arm_softmax_s8 expects. + 3. Derive `diff_min`, the CMSIS threshold for early bailout when + differences saturate, using the same multiplier/shift values. + """ + real_multiplier = min( + input_scale * (1 << (31 - self._SOFTMAX_INPUT_INTEGER_BITS)), + float((1 << 31) - 1), + ) + input_multiplier, input_shift = quantize_multiplier_aot(real_multiplier) + diff_min_term = ( + ((1 << self._SOFTMAX_INPUT_INTEGER_BITS) - 1) + * math.ldexp(1.0, 31 - self._SOFTMAX_INPUT_INTEGER_BITS) + / math.ldexp(1.0, input_shift) + ) + diff_min = -int(math.floor(diff_min_term)) + return int(input_multiplier), int(input_shift), diff_min + + def _get_softmax_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten._softmax.default, args + + input_qparams = meta["input_qparams"][0] + output_qparams = meta["output_qparams"][0] + + half_to_float = args[2] if len(args) > 2 else False + if half_to_float: + return exir_ops.edge.aten._softmax.default, args + + input_multiplier, input_shift, diff_min = self._compute_softmax_params( + float(input_qparams.scale) + ) + + output_scale_attr = getattr(output_qparams, "scale", None) + output_zp_attr = getattr(output_qparams, "zp", None) + if output_scale_attr is None or output_zp_attr is None: + raise AssertionError("Softmax requires output quantization parameters.") + + output_scale_val = float(output_scale_attr) + output_zp_val = int(output_zp_attr) + if not math.isclose( + output_scale_val, CMSIS_SOFTMAX_SCALE, rel_tol=0.0, abs_tol=1e-12 + ): + raise AssertionError( + "Softmax output scale must match CMSIS (1/256). " + f"Got {output_scale_val}." + ) + if output_zp_val != CMSIS_SOFTMAX_ZERO_POINT: + raise AssertionError( + "Softmax output zero-point must match CMSIS (-128). " + f"Got {output_zp_val}." + ) + + new_args = ( + args[0], + args[1], + int(input_qparams.zp), + output_zp_val, + input_multiplier, + input_shift, + diff_min, + ) + + return exir_ops.edge.cortex_m.softmax.default, new_args + + def _get_minimum_replacement(self, args, meta): + if args[0].data.dtype != torch.int8: + return exir_ops.edge.aten.minimum.default, args + + return exir_ops.edge.cortex_m.minimum.default, args + + def _get_maximum_replacement(self, args, meta): + if args[0].data.dtype != torch.int8: + return exir_ops.edge.aten.maximum.default, args + + return exir_ops.edge.cortex_m.maximum.default, args + + def _get_permute_replacement(self, args, meta): + if args[0].data.dtype != torch.int8: + return exir_ops.edge.aten.permute_copy.default, args + + rank = len(args[0].data.shape) + perms = [p % rank for p in args[1]] + args = (args[0], perms) + return exir_ops.edge.cortex_m.transpose.default, args + + def _get_avg_pool2d_replacement(self, args, meta): + if ( + meta.data.get("input_qparams", {}) == {} + or meta.data.get("output_qparams", {}) == {} + ): + return exir_ops.edge.aten.avg_pool2d.default, args + + # Extract values + scale = meta["input_qparams"][0].scale + zero_point = meta["input_qparams"][0].zp + + output_mult, output_shift = quantize_multiplier_aot(scale) + args = ( + *args[0:-2], + zero_point, + output_mult, + output_shift, + ) + + return exir_ops.edge.cortex_m.quantized_avg_pool2d.default, args + + def call_operator( + self, + op: EdgeOpOverload, + args: tuple[Argument, ...], + kwargs: Dict[str, Argument], + meta: NodeMetadata, + ) -> ProxyValue: + + match op: + case exir_ops.edge.aten.add.Tensor: + op, args = self._get_add_replacement(args, meta) + case exir_ops.edge.aten.mul.Tensor: + op, args = self._get_mul_replacement(args, meta) + case exir_ops.edge.aten._softmax.default: + op, args = self._get_softmax_replacement(args, meta) + case exir_ops.edge.aten.minimum.default: + op, args = self._get_minimum_replacement(args, meta) + case exir_ops.edge.aten.maximum.default: + op, args = self._get_maximum_replacement(args, meta) + case exir_ops.edge.aten.permute_copy.default: + op, args = self._get_permute_replacement(args, meta) + case exir_ops.edge.aten.avg_pool2d.default: + op, args = self._get_avg_pool2d_replacement(args, meta) + case _: + pass + + result = super().call_operator(op, args, {}, meta) + return result diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/replace_quant_nodes_pass.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/replace_quant_nodes_pass.py new file mode 100644 index 0000000..a815313 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/passes/replace_quant_nodes_pass.py @@ -0,0 +1,67 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Dict, Tuple + +import executorch.backends.cortex_m.ops.operators # noqa +import torch + +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.pass_base import ExportPass, NodeMetadata, ProxyValue + + +class ReplaceQuantNodesPass(ExportPass): + """ + Replace quantize and dequantize nodes with the corresponding + cortex_m.quantize_per_tensor and cortex_m.dequantize_per_tensor nodes. + """ + + @staticmethod + def _is_qualified_int8_node(args) -> bool: + return ( + args[3] >= torch.iinfo(torch.int8).min # qmin + and args[4] <= torch.iinfo(torch.int8).max # qmax + and args[5] == torch.int8 # dtype + ) + + def __init__(self): + super().__init__() + self.op_replacements = { + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default: { + "new_target": exir_ops.edge.cortex_m.quantize_per_tensor.default, + "qualifier": self._is_qualified_int8_node, + }, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default: { + "new_target": exir_ops.edge.cortex_m.dequantize_per_tensor.default, + "qualifier": self._is_qualified_int8_node, + }, + } + self.disallowed_targets = { + torch.ops.quantized_decomposed.dequantize_per_tensor.default, + torch.ops.quantized_decomposed.quantize_per_tensor.default, + } + + def call_operator( + self, + op: Callable[..., object], + args: Tuple[object, ...], + kwargs: Dict[str, object], + meta: NodeMetadata, + ) -> ProxyValue: + if op in self.disallowed_targets: + raise RuntimeError( + f"Found unexpected aten op '{op}'. Make sure you run this pass after lowering to edge." + ) + + if op in self.op_replacements and self.op_replacements[op]["qualifier"](args): + return super().call_operator( + self.op_replacements[op]["new_target"], + args, + kwargs, + meta, + ) + return super().call_operator(op, args, kwargs, meta) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/TARGETS new file mode 100644 index 0000000..0af105e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/TARGETS @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbcode_macros//build_defs:python_library.bzl", "python_library") + +oncall("executorch") + +python_library( + name = "quantizer", + srcs = [ + "__init__.py", + "operator_configs.py", + "quantization_configs.py", + "quantizer.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/backends/arm/quantizer:quantization_config", + "//pytorch/ao:torchao", + ], +) + +python_library( + name = "quantization_configs", + srcs = [ + "quantization_configs.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/backends/arm/quantizer:quantization_config", + "//pytorch/ao:torchao", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/__init__.py new file mode 100644 index 0000000..c55f200 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/__init__.py @@ -0,0 +1,18 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from .quantization_configs import ( # noqa + CMSIS_SOFTMAX_SCALE, + CMSIS_SOFTMAX_ZERO_POINT, + INT8_ACTIVATION_PER_CHANNEL_QSPEC, + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_PER_CHANNEL_CONFIG, + INT8_PER_TENSOR_CONFIG, + INT8_WEIGHT_PER_CHANNEL_QSPEC, + INT8_WEIGHT_PER_TENSOR_QSPEC, + SOFTMAX_OUTPUT_FIXED_QSPEC, + SOFTMAX_PER_TENSOR_CONFIG, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/operator_configs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/operator_configs.py new file mode 100644 index 0000000..5458eef --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/operator_configs.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +""" +Operator configs maps a list of operators/operator patterns to a quantization configuration. +These can be used with the OperatorConfigQuantizer to quantize models based on operator patterns. +""" + +import torch + +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + INT8_PER_CHANNEL_CONFIG, + INT8_PER_TENSOR_CONFIG, + SOFTMAX_PER_TENSOR_CONFIG, +) +from torchao.quantization.pt2e.quantizer import OperatorConfig + +# ----------------- OPERATOR PATTERN PRESETS ----------------- +BINARY_OP_PATTERNS = [ + [torch.ops.aten.add.Tensor], + [torch.ops.aten.mul.Tensor], + [torch.ops.aten.hardswish.default], + [torch.ops.aten.hardswish_.default], +] + +LINEAR_OP_PATTERNS = [ + [torch.ops.aten.linear.default], + [torch.ops.aten.linear.default, torch.ops.aten.relu.default], + [torch.ops.aten.linear.default, torch.ops.aten.relu_.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardtanh.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardtanh_.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardsigmoid.default], + [torch.ops.aten.linear.default, torch.ops.aten.hardsigmoid_.default], + [torch.ops.aten.linear.default, torch.ops.aten.clamp.default], + [torch.ops.aten.linear.default, torch.ops.aten.clamp_.default], +] + +CONV_OP_PATTERNS = [ + [torch.ops.aten.conv2d.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.relu.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.relu_.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardtanh.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardtanh_.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardsigmoid.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.hardsigmoid_.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.clamp.default], + [torch.ops.aten.conv2d.default, torch.ops.aten.clamp_.default], +] + +SOFTMAX_OP_PATTERNS = [ + [torch.ops.aten._softmax.default], + [torch.ops.aten.softmax.int], +] + +# ----------------- OPERATOR CONFIG PRESETS ----------------- +INT8_BINARY_OPS_OPERATOR_CONFIG = OperatorConfig( + INT8_PER_TENSOR_CONFIG, BINARY_OP_PATTERNS +) + +INT8_LINEAR_OPERATOR_CONFIG = OperatorConfig( + INT8_PER_TENSOR_CONFIG, + LINEAR_OP_PATTERNS, +) + +INT8_CONV_OPERATOR_CONFIG = OperatorConfig( + INT8_PER_CHANNEL_CONFIG, + CONV_OP_PATTERNS, +) + +INT8_SOFTMAX_OPERATOR_CONFIG = OperatorConfig( + SOFTMAX_PER_TENSOR_CONFIG, + SOFTMAX_OP_PATTERNS, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantization_configs.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantization_configs.py new file mode 100644 index 0000000..7ec84c6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantization_configs.py @@ -0,0 +1,121 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from torchao.quantization.pt2e import ( + HistogramObserver, + MinMaxObserver, + PerChannelMinMaxObserver, +) +from torchao.quantization.pt2e.quantizer import ( + DerivedQuantizationSpec, + FixedQParamsQuantizationSpec, + QuantizationSpec, +) + +# ----------------- QUANTIZATION SPEC PRESETS ----------------- +INT8_WEIGHT_PER_TENSOR_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=MinMaxObserver, + qscheme=torch.per_tensor_symmetric, +) + +INT8_WEIGHT_PER_CHANNEL_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=PerChannelMinMaxObserver, + qscheme=torch.per_channel_symmetric, + ch_axis=0, +) + +INT8_ACTIVATION_PER_TENSOR_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=HistogramObserver, + qscheme=torch.per_tensor_affine, +) + +INT8_ACTIVATION_PER_CHANNEL_QSPEC = QuantizationSpec( + dtype=torch.int8, + observer_or_fake_quant_ctr=PerChannelMinMaxObserver, + qscheme=torch.per_channel_affine, + ch_axis=0, +) + +# Constants shared by Cortex-M quantized operators. +CMSIS_SOFTMAX_SCALE: float = 1.0 / 256.0 +CMSIS_SOFTMAX_ZERO_POINT: int = -128 + +SOFTMAX_OUTPUT_FIXED_QSPEC = FixedQParamsQuantizationSpec( + dtype=torch.int8, + scale=CMSIS_SOFTMAX_SCALE, + zero_point=CMSIS_SOFTMAX_ZERO_POINT, + quant_min=-128, + quant_max=127, + qscheme=torch.per_tensor_affine, +) + + +def _derive_bias_qparams_fn( + obs_or_fqs, +) -> tuple[torch.Tensor, torch.Tensor]: + if len(obs_or_fqs) != 2: + raise ValueError( + f"Expecting two obs/fqs, one for activation and one for weight, got: {len(obs_or_fqs)}" + ) + act_obs_or_fq = obs_or_fqs[0] + weight_obs_or_fq = obs_or_fqs[1] + act_scale, _ = act_obs_or_fq.calculate_qparams() + weight_scale, _ = weight_obs_or_fq.calculate_qparams() + return act_scale * weight_scale, torch.full_like( + weight_scale, fill_value=0, dtype=torch.int32 + ) + + +def _get_int32_bias_qspec(node): + return DerivedQuantizationSpec( + derived_from=[(node.args[0], node), (node.args[1], node)], # type: ignore[list-item] + derive_qparams_fn=_derive_bias_qparams_fn, + dtype=torch.int32, + quant_min=torch.iinfo(torch.int32).min, + quant_max=torch.iinfo(torch.int32).max - 1, + ) + + +def _get_int32_per_channel_bias_qspec(node): + return DerivedQuantizationSpec( + derived_from=[(node.args[0], node), (node.args[1], node)], # type: ignore[list-item] + derive_qparams_fn=_derive_bias_qparams_fn, + dtype=torch.int32, + quant_min=torch.iinfo(torch.int32).min, + quant_max=torch.iinfo(torch.int32).max - 1, + qscheme=torch.per_channel_symmetric, + ch_axis=0, + ) + + +# ----------------- QUANTIZATION CONFIG PRESETS ----------------- +INT8_PER_TENSOR_CONFIG = QuantizationConfig( + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_WEIGHT_PER_TENSOR_QSPEC, + _get_int32_bias_qspec, +) + + +INT8_PER_CHANNEL_CONFIG = QuantizationConfig( + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_ACTIVATION_PER_TENSOR_QSPEC, + INT8_WEIGHT_PER_CHANNEL_QSPEC, + _get_int32_per_channel_bias_qspec, +) + + +SOFTMAX_PER_TENSOR_CONFIG = QuantizationConfig( + INT8_ACTIVATION_PER_TENSOR_QSPEC, + SOFTMAX_OUTPUT_FIXED_QSPEC, + None, + None, +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantizer.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantizer.py new file mode 100644 index 0000000..aceced0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/quantizer/quantizer.py @@ -0,0 +1,500 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import Any, Callable, cast, List, Optional + +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.common.annotation_meta import ArmAnnotationInfo +from executorch.backends.arm.quantizer.quantization_config import QuantizationConfig +from executorch.backends.cortex_m.passes.cortex_m_pass_manager import CortexMPassManager +from executorch.backends.cortex_m.passes.passes_utils import ( + is_channel_broadcast, + is_channels_last, +) +from executorch.backends.cortex_m.quantizer.operator_configs import ( + BINARY_OP_PATTERNS, + CONV_OP_PATTERNS, + INT8_BINARY_OPS_OPERATOR_CONFIG, + INT8_CONV_OPERATOR_CONFIG, + INT8_LINEAR_OPERATOR_CONFIG, + INT8_SOFTMAX_OPERATOR_CONFIG, + SOFTMAX_OP_PATTERNS, +) +from executorch.backends.cortex_m.quantizer.quantization_configs import ( + INT8_PER_TENSOR_CONFIG, + QuantizationSpec, +) +from torch._ops import OpOverload +from torch.fx import GraphModule, Node +from torchao.quantization.pt2e.quantizer import ( + ComposableQuantizer, + QuantizationAnnotation, + Quantizer, + SharedQuantizationSpec, +) +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + + +def mark_node_as_annotated( + node: Node, + input_qspec_map: dict[Node, Optional[QuantizationSpec]], + output_qspec: Optional[QuantizationSpec], +) -> None: + node.meta[Q_ANNOTATION_KEY] = QuantizationAnnotation(input_qspec_map, output_qspec) + annotation_info = ArmAnnotationInfo( + quantized=True, + ) + meta_custom = node.meta.get("custom", {}) + meta_custom[ArmAnnotationInfo.CUSTOM_META_KEY] = dict(annotation_info) + node.meta["custom"] = meta_custom + + +class CortexMQuantizer(ComposableQuantizer): + + def broadcasting_filter(self, node: Optional[Node]) -> bool: + """ + Filter function to exclude nodes that perform broadcasting. + """ + if node is None: + return False + if [node.target] not in BINARY_OP_PATTERNS: + return False + + if len(node.all_input_nodes) == 2: + t1 = get_first_fake_tensor(node.all_input_nodes[0]) + t2 = get_first_fake_tensor(node.all_input_nodes[1]) + return t1.shape != t2.shape and not ( + is_channel_broadcast(t1, t2) and is_channels_last(t1) + ) + + return False + + def nchw_filter(self, node: Optional[Node]) -> bool: + """ + Filter function to exclude nodes that use NCHW memory format. + """ + if node is None: + return False + if [node.target] not in CONV_OP_PATTERNS: + return False + + tensor = get_first_fake_tensor(node) + if tensor is None: + return False + + return not is_channels_last(tensor) + + @staticmethod + def _resolve_int(value: Any) -> Optional[int]: + """Best-effort conversion of FX node arguments to ints.""" + if isinstance(value, int): + return value + if hasattr(value, "item"): + try: + return int(value.item()) # type: ignore[arg-type] + except Exception: + return None + if hasattr(value, "meta"): + meta_val = value.meta.get("val") + return CortexMQuantizer._resolve_int(meta_val) + return None + + def _extract_dim(self, node: Node) -> Optional[int]: + """Return the dim argument from a softmax node when statically known.""" + dim_arg = None + if len(node.args) > 1: + dim_arg = node.args[1] + elif "dim" in node.kwargs: + dim_arg = node.kwargs["dim"] + + if dim_arg is None: + return -1 + + return self._resolve_int(dim_arg) + + def softmax_memory_format_filter(self, node: Optional[Node]) -> bool: + """ + Return true given the tensor must either + - be contiguous (default layout) with softmax dim == last logical dim, or + - be channels_last with softmax dim == channel dim. + Any other combination is skipped so the op stays in ATen form. + """ + if node is None: + return False + if [node.target] not in SOFTMAX_OP_PATTERNS: + return False + + tensor = get_first_fake_tensor(node) + if tensor is None: + return True + + dim = self._extract_dim(node) + if dim is None: + return True + + rank = tensor.dim() + if rank == 0: + return True + + positive_dim = dim if dim >= 0 else dim + rank + if positive_dim < 0 or positive_dim >= rank: + return True + + is_channels_last = False + if rank == 4: + is_channels_last = tensor.is_contiguous(memory_format=torch.channels_last) + + if is_channels_last: + channel_dim = 1 if rank >= 2 else rank - 1 + if positive_dim != channel_dim: + return True + else: + if positive_dim != rank - 1: + return True + + return False + + def __init__(self) -> None: + quantizers: List[Quantizer] = [ + OperatorConfigQuantizer( + INT8_BINARY_OPS_OPERATOR_CONFIG, filter_fn=self.broadcasting_filter + ), + OperatorConfigQuantizer(INT8_LINEAR_OPERATOR_CONFIG), + OperatorConfigQuantizer( + INT8_CONV_OPERATOR_CONFIG, filter_fn=self.nchw_filter + ), + OperatorConfigQuantizer( + INT8_SOFTMAX_OPERATOR_CONFIG, + filter_fn=self.softmax_memory_format_filter, + ), + InputQuantizer(INT8_PER_TENSOR_CONFIG), + OutputQuantizer(INT8_PER_TENSOR_CONFIG), + SharedQspecQuantizer(), + ] + super().__init__(quantizers) + + def validate(self, model: GraphModule) -> bool: + return True + + def transform_for_annotation(self, model: GraphModule) -> GraphModule: + pass_manager = CortexMPassManager(None) + return pass_manager.transform_for_annotation(model) + + +class OperatorConfigQuantizer(Quantizer): + """ + Quantizes a graph according to an OperatorConfig. + + Args: + operator_config (OperatorConfig): The operator config to use for quantization. + filter_fn (Callable): Negative filter function. If it returns True on any node in the pattern, the pattern is + skipped. Used to match for example particular targets or modules. + """ + + def __init__( + self, + operator_config: QuantizationConfig, + filter_fn: Callable[[Node], bool] = lambda node: False, + ) -> None: + self.operator_config = operator_config + self.filter_fn = filter_fn + + def check_node(self, node: Optional[Node], target: str) -> bool: + """ + Return true if the node is a valid match for the given target. + """ + if node is None: + return False + if not node.target == target: + return False + if node.meta.get("quantizer_matched", False): + return False + if self.filter_fn(node): + return False + + return True + + def check_pattern( + self, node: Optional[Node], pattern: List[OpOverload] + ) -> Optional[List[Node]]: + """ + Returns the matched nodes if the given node matches the given pattern, otherwise None. + """ + match: List[Node] = [] + + for pattern_target in pattern: + if self.check_node(node, pattern_target): + match.append(node) + node = list(node.users)[0] if len(node.users) > 0 else None + else: + return None + + return match + + def match_patterns( + self, model: GraphModule, patterns: List[List[str]] + ) -> List[List[Node]]: + """ + Match all given patterns in the graph and return list of matches. + Each node can only be part of one match, larger patterns are prioritized. + Currently only linear patterns (single chain) are supported. + """ + patterns.sort(key=len, reverse=True) + matches: List[List[Node]] = [] + for pattern in patterns: + for node in model.graph.nodes: + potential_match = self.check_pattern(node, pattern) + if potential_match: + matches.append(potential_match) + for node in potential_match: + node.meta["quantizer_matched"] = True + + return matches + + def is_parameter(self, node: Node, model: GraphModule) -> bool: + """Returns True if the given node is a parameter of the model.""" + try: + _ = model.get_parameter(node.target) + return True + except Exception: + return False + + def is_weight(self, node: Node, params: List[Node], model: GraphModule) -> bool: + """Returns True if node is the first parameter of the given parameters""" + return len(params) > 0 and node == params[0] + + def is_bias(self, node: Node, params: List[Node], model: GraphModule) -> bool: + """Returns True if node is the second parameter of the given parameters""" + return len(params) == 2 and node == params[1] + + def annotate_match( + self, match: List[Node], config: QuantizationConfig, model: GraphModule + ) -> None: + """ + Annotates a matched pattern according to the given quantization config. The + following assumptions are made: + + - All operators have either no parameters, only weights, or weights and biases + - Tensors which are the first parameter of an operator are annotated as weights + - Tensors which are the second parameter of an operator are annotated as biases + - All other tensors going into the matched pattern are annotated as input activations. + - All other outputs coming out of the matched pattern are annotated as output activations. + + """ + for node in match: + input_qspec_map = {} + output_qspec = None + + params = [n for n in node.all_input_nodes if self.is_parameter(n, model)] + # Check that the assumptions on number of parameters hold to avoid silent errors + assert ( + 0 <= len(params) <= 2 + ), f"{self.__class__.__name__} expected 0 params, 1 params (weight) or 2 params (weight, bias), but got {len(params)} for node {node}." + + for input_node in node.all_input_nodes: + if self.is_weight(input_node, params, model): + input_qspec_map[input_node] = config.weight if config else None + elif self.is_bias(input_node, params, model): + # Bias qspec is derived from input + weight qspecs + input_qspec_map[input_node] = config.bias(node) if config else None + elif input_node not in match: + input_qspec_map[input_node] = ( + config.input_activation if config else None + ) + + if all(node not in match for node in node.users) and output_qspec is None: + output_qspec = config.output_activation if config else None + + mark_node_as_annotated(node, input_qspec_map, output_qspec) + + def annotate(self, model: GraphModule) -> None: + matches = self.match_patterns(model, self.operator_config.operators) + for match in matches: + self.annotate_match(match, self.operator_config.config, model) + + def validate(self, model: GraphModule) -> bool: + return True + + +class InputQuantizer(Quantizer): + """ + Quantizes only the input activations of the graph. + """ + + def __init__( + self, + quantization_config: QuantizationConfig, + filter_fn: Callable[[Node], bool] = lambda node: False, + ) -> None: + self.quantization_config = quantization_config + self.filter_fn = filter_fn + + def annotate(self, model: GraphModule) -> None: + for node in model.graph.nodes: + is_placeholder = node.op == "placeholder" + is_filtered = self.filter_fn(node) + if is_placeholder and not is_filtered: + mark_node_as_annotated( + node, {}, self.quantization_config.output_activation + ) + + def validate(self, model: GraphModule) -> bool: + return True + + +class OutputQuantizer(Quantizer): + """ + Quantizes only the output activations of the graph. + """ + + def __init__( + self, + quantization_config: QuantizationConfig, + filter_fn: Callable[[Node], bool] = lambda node: False, + ) -> None: + self.quantization_config = quantization_config + self.filter_fn = filter_fn + + def annotate(self, model: GraphModule) -> None: + output_node = model.graph.output_node() + input_qspec_map = { + n: self.quantization_config.input_activation + for n in output_node.all_input_nodes + if not self.filter_fn(n) + } + output_qspec = self.quantization_config.output_activation + mark_node_as_annotated(output_node, input_qspec_map, output_qspec) + + def validate(self, model: GraphModule) -> bool: + return True + + +class SharedQspecQuantizer(Quantizer): + """ + Special quantizer for assuring that given ops share the same quantization parameters on all input and outputs, + i.e. ops which does not change the scale such as clone, min/max, transposes and so on. + + Args: + targets (Optional[List[OpOverload]]): List of operator overloads to apply shared quantization spec to. + If None, a default list of supported ops is used. + """ + + SHARED_QSPEC_OPS_DEFAULT: List[OpOverload] = [ + # Clone + torch.ops.aten.clone.default, + torch.ops.aten.lift_fresh_copy.default, + torch.ops.aten.detach_.default, + # Min/Max/Mean + torch.ops.aten.minimum.default, + torch.ops.aten.maximum.default, + torch.ops.aten.avg_pool2d.default, + # Data shuffling + torch.ops.aten.permute.default, + torch.ops.aten.permute_copy.default, + torch.ops.aten.transpose.Dimname, + torch.ops.aten.transpose.int, + torch.ops.aten.transpose_copy.int, + torch.ops.aten.t_copy.default, + torch.ops.aten.t.default, + # Change shape + torch.ops.aten.squeeze.default, + torch.ops.aten.squeeze_copy.default, + torch.ops.aten.squeeze_copy.dim, + torch.ops.aten.squeeze.dim, + torch.ops.aten.squeeze.dims, + torch.ops.aten.unsqueeze.default, + torch.ops.aten.unsqueeze_copy.default, + torch.ops.aten.reshape.default, + torch.ops.aten.view.default, + torch.ops.aten.view_as.default, + torch.ops.aten.view_copy.default, + torch.ops.aten._unsafe_view.default, + torch.ops.aten.unflatten.int, + torch.ops.aten.flatten.using_ints, + ] + + def __init__(self, targets: Optional[List[OpOverload]] = None) -> None: + super().__init__() + if targets is None: + self.targets = self.SHARED_QSPEC_OPS_DEFAULT + else: + self.targets = targets + + def _is_annotated(self, node: Node) -> bool: + return Q_ANNOTATION_KEY in node.meta + + def _annotate_shared_cluster(self, root_node: Node) -> None: + """ + Finds a cluster of unannotated nodes starting in root_node and annotates them with a common + SharedQuantizationSpec. + """ + + shared_nodes = set() + leaf_nodes = set() + bfs_queue = [root_node] + + while bfs_queue: + node = bfs_queue.pop(0) + + if self._is_annotated(node): + leaf_nodes.add(node) + continue + if node.op == "get_attr": + continue + + if node.target not in self.targets: + raise NotImplementedError( + ( + f"{SharedQspecQuantizer.__name__} found unannoted node '{node.name}' in neighbour_nodes " + "which is not in the supported target list. This might be the case either because:\n" + "1) The op should have shared qspec but is not in the target list. " + "In this case, try modifying the list using the targets field in the initializer.\n" + "2) The op should not be quantized, which is not currently supported by the SharedQspecQuantizer." + ) + ) + + shared_nodes.add(node) + neighbour_nodes = list(node.all_input_nodes) + list(node.users) + for n in neighbour_nodes: + if n not in shared_nodes: + bfs_queue.append(n) + + # The selection of root node for the shared_qspec is important for + # torchao.quantization.pt2e.prepare._create_obs_or_fq_from_qspec: + # 1. For regular QuantizationSpecs, it creates a new observer + # 2. For SharedQuantizationSpecs, it returns the observer created for it's root node + # 3. It handles nodes in the order they appear in graph.nodes + # This means that the root node of the shared group needs to be the first annotated node that appears in graph.nodes. + shared_root_node = next(n for n in root_node.graph.nodes if n in leaf_nodes) + shared_qspec = SharedQuantizationSpec(shared_root_node) + + for node in shared_nodes: + input_qspec_map: dict[Node, Optional[QuantizationSpec]] = { + n: shared_qspec for n in node.all_input_nodes + } + mark_node_as_annotated(node, input_qspec_map, shared_qspec) + + def annotate(self, model: GraphModule) -> None: + """ + Annotate shared quantization spec for supported ops, but skip avg_pool2d + when both ceil_mode and count_include_pad are True. + """ + for node in model.graph.nodes: + # TODO Skip avg_pool2d when ceil_mode=True or count_include_pad=True + # CMSIS-NN doesn't directly support this. But, it should be done. + if node.target is torch.ops.aten.avg_pool2d.default: + ceil_mode = cast(bool, node.args[4]) if len(node.args) > 4 else False + count_include_pad = ( + cast(bool, node.args[5]) if len(node.args) > 5 else True + ) + if ceil_mode or count_include_pad: + continue + if node.target in self.targets and not self._is_annotated(node): + self._annotate_shared_cluster(node) + + def validate(self, model: GraphModule) -> bool: + return True diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/BUCK new file mode 100644 index 0000000..5630c92 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/BUCK @@ -0,0 +1,11 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/TARGETS new file mode 100644 index 0000000..292a087 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/TARGETS @@ -0,0 +1,25 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") +load("targets.bzl", "define_common_targets") + +oncall("executorch") +python_unittest( + name="test_replace_quant_nodes", + srcs=[ + "test_helpers_passes_utils.py", + "test_replace_quant_nodes.py", + ], + deps=[ + "//pytorch/ao:torchao", # @manual + "//caffe2:torch", + "//executorch/backends/cortex_m/passes:replace_quant_nodes_pass", + "//executorch/backends/cortex_m/ops:ops", + ], +) + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/build_test_runner.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/build_test_runner.sh new file mode 100755 index 0000000..bf29b21 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/build_test_runner.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# TODO: More separation from the regular arm executor runner and testing. + +set -eu + +# Always rebuild executorch in case the cortex-m kernels has been updated. +script_dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +et_root_dir=$(realpath "${script_dir}/../../..") +build_executorch="${et_root_dir}/backends/arm/scripts/build_executorch.sh" +${build_executorch} + +# Build executor runner with selected aten ops and semi hosting +build_dir="${et_root_dir}/arm_test" +build_executor_runner="${et_root_dir}/backends/arm/scripts/build_executor_runner.sh" +build_root_test_dir="${et_root_dir}/arm_test/arm_semihosting_executor_runner_corstone-300" + +select_ops_list="\ +aten::add.out,\ +aten::clamp.out,\ +aten::convolution.out,\ +aten::div.out,\ +aten::mean.out,\ +aten::mul.out,\ +aten::relu.out,\ +aten::view_copy.out,\ +dim_order_ops::_to_dim_order_copy.out" + +${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --output="${build_root_test_dir}" --select_ops_list="${select_ops_list}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/misc/test_quantization.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/misc/test_quantization.py new file mode 100644 index 0000000..d4f84e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/misc/test_quantization.py @@ -0,0 +1,359 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm._passes.arm_pass_utils import get_first_fake_tensor +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) +from executorch.exir.dialects._ops import ops as exir_ops + + +class SharedQspecMulipleClusters(torch.nn.Module): + """Three linear shared qspec clusters.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 8, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 8, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 4, + } + + def forward(self, x): + x1 = torch.clone(x) + x2 = x1 + x1 + x3 = torch.clone(x2) + x3 = torch.clone(x3) + x3 = torch.clone(x3) + x4 = x3 + x3 + x5 = torch.transpose(x4, 2, 1) + return x5 + + +class SharedQspecInputForkNonShared(torch.nn.Module): + """Shared qspec cluster with an input fork with both inputs as non-shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + } + + def forward(self, x, y): + z = torch.maximum(x, y) + return torch.flatten(z) + + +class SharedQspecInputForkShared(torch.nn.Module): + """Shared qspec cluster with an input fork with both inputs as shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 5, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 5, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x, y): + x = torch.clone(x) + y = torch.permute(y, (0, 1, 3, 2)) + z = torch.minimum(x, y) + return z + + +class SharedQspecInputForkXShared(torch.nn.Module): + """Shared qspec cluster with an input fork with left input as shared qspec.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x, y): + x = torch.t_copy(x) + z = torch.maximum(x, y) + return z + + +class SharedQspecInputForkYShared(torch.nn.Module): + """Shared qspec cluster with an input fork with right input as shared qspec.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 5, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 5, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x, y): + y = torch.clone(y) + z = torch.minimum(x, y) + return torch.squeeze(z) + + +class SharedQspecInputForkXConstant(torch.nn.Module): + """Shared qspec cluster with an input fork with left input as global constant.""" + + ops_before_transforms = {} + ops_after_transforms = {} + constant = torch.tensor(5.0) + + def forward(self, x): + return torch.minimum(self.constant, x) + + +class SharedQspecInputForkYConstant(torch.nn.Module): + """Shared qspec cluster with an input fork with left input as local constant.""" + + ops_before_transforms = {} + ops_after_transforms = {} + + def forward(self, x): + return torch.maximum(x, torch.tensor(5.0)) + + +class SharedQspecOutputForkNonShared(torch.nn.Module): + """Shared qspec cluster with an output fork with both outputs as non-shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + } + + def forward(self, x): + x = torch.unsqueeze(x, 0) + y = x + x + return x, y + + +class SharedQspecOutputForkShared(torch.nn.Module): + """Shared qspec cluster with an output fork with both outputs as shared qspecs.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 6, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x): + x = torch.unsqueeze(x, 0) + y = torch.clone(x) + z = torch.permute_copy(x, (0, 2, 1, 3)) + return y, z, x + + +class SharedQspecManyForks(torch.nn.Module): + """Shared qspec cluster with a number of forks to testmore complex structures.""" + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 2, + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 9, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 6, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x): + x1 = torch.clone(x) + x2 = torch.maximum(x, x1) + x3 = torch.maximum(x, torch.t(x2)) + x4 = torch.minimum(x2, x3) + + return x4 + + +class SharedQspecSurroundedQuantizedOp(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 5, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + } + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__clone_dim_order_default": 1, + } + + def forward(self, x): + x1 = torch.clone(x) + x2 = torch.add(x1, x1) + x3 = torch.maximum(x1, x2) + return x3 + + +class SharedQspecSurroundedQuantizedOpConstant(torch.nn.Module): + ops_before_transforms = {} + ops_after_transforms = {} + + def forward(self, x): + x1 = torch.clone(x) + x2 = torch.add(x1, torch.ones(2, 2)) + x3 = torch.maximum(x1, x2) + return x3 + + +class SharedQspecSub(torch.nn.Module): + ops_before_transforms = {} + ops_after_transforms = {} + + def forward(self, x, y): + return torch.clone(x - y) + + +test_cases = { + "multiple_clusters": McuTestCase( + SharedQspecMulipleClusters(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "input_fork_non_shared": McuTestCase( + SharedQspecInputForkNonShared(), + (ramp_tensor(-2, 2, (2, 3, 4)), ramp_tensor(-1, 3, (2, 3, 4))), + ), + "input_fork_shared": McuTestCase( + SharedQspecInputForkShared(), + (ramp_tensor(-2, 2, (2, 3, 4, 5)), ramp_tensor(-1, 3, (2, 3, 5, 4))), + ), + "input_fork_x_shared": McuTestCase( + SharedQspecInputForkXShared(), + (ramp_tensor(-2, 2, (3, 4)), ramp_tensor(-1, 3, (4, 3))), + ), + "input_fork_y_shared": McuTestCase( + SharedQspecInputForkYShared(), + (ramp_tensor(-2, 2, (2, 3, 4)), ramp_tensor(-1, 3, (2, 3, 4))), + ), + "input_fork_x_constant": McuTestCase( + SharedQspecInputForkXConstant(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "input_fork_y_constant": McuTestCase( + SharedQspecInputForkYConstant(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "surrounded_quantized_op": McuTestCase( + SharedQspecSurroundedQuantizedOp(), + (ramp_tensor(-128, 2, (2, 3, 4)),), + ), + "surrounded_quantized_op_constant": McuTestCase( + SharedQspecSurroundedQuantizedOpConstant(), + (ramp_tensor(-2, 2, (2, 2)),), + ), + "output_fork_non_shared": McuTestCase( + SharedQspecOutputForkNonShared(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "output_fork_shared": McuTestCase( + SharedQspecOutputForkShared(), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "many_forks": McuTestCase( + SharedQspecManyForks(), + (ramp_tensor(-20, 2, (4, 4)),), + ), + "non-quantized_op": McuTestCase( + SharedQspecSub(), + (ramp_tensor(0, 10, (5, 5)), ramp_tensor(0, 1, (5, 5))), + ), +} + +xfails = { + "surrounded_quantized_op_constant": "Numerical error since the add is forced to have non-correct qparams.", + "non-quantized_op": "Non-quantized ops are not currently supported in SharedQspecQuantizer.", +} + + +@parametrize("test_case", test_cases, xfails=xfails) +def test_shared_qspec_quantizer(test_case): + """ + Test that ops which does not change dynamic range are able to use int8 portable kernels. + """ + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + # Check that all nodes in the graph are in int8 + artifact = tester.get_artifact() + for node in artifact.exported_program().module().graph.nodes: + if node.op != "call_function": + continue + if node.target == exir_ops.edge.cortex_m.dequantize_per_tensor.default: + continue + + assert get_first_fake_tensor(node).dtype == torch.int8, f"{node.name}" diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/test_mobilenet_v3.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/test_mobilenet_v3.py new file mode 100644 index 0000000..598d71e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/models/test_mobilenet_v3.py @@ -0,0 +1,74 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import pytest +import torch + +from executorch.backends.cortex_m.test.tester import CortexMTester, McuTestCase +from torchvision import models + + +# TODO: Update as more ops are converted by CMSIS-NN ops. +ops_before_transforms: dict[str, int] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 34, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 2, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 56, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 52, + "executorch_exir_dialects_edge__ops_aten_div_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 10, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_relu_default": 14, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 56, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 178, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 109, +} +ops_after_transforms: dict[str, int] = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 28, # Not lowered due to broadcasting + "executorch_exir_dialects_edge__ops_aten_addmm_default": 0, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 6, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 2, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 56, + "executorch_exir_dialects_edge__ops_aten_convolution_default": 52, + "executorch_exir_dialects_edge__ops_aten_div_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_mean_dim": 10, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 28, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 0, + "executorch_exir_dialects_edge__ops_aten_relu_default": 14, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_dim_order_ops__to_dim_order_copy_default": 56, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 0, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 0, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 162, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 101, +} + +model = models.mobilenet_v3_small(weights=None) +example_input = torch.randn(1, 3, 224, 224) + + +test_cases = { + "mobilenet_v3_small": McuTestCase( + model=models.mobilenet_v3_small(weights=None), + example_inputs=(example_input,), + ), +} + + +@pytest.mark.skip("Skip until add + linear fix are upstreamed.") +def test_dialect_mv3(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + ops_before_transforms, + ops_after_transforms, + qtol=1, + ) + + +@pytest.mark.skip("Skip until add + linear fix are upstreamed.") +def test_implementation_mv3(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp new file mode 100644 index 0000000..a4cf9d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_dequantize_per_tensor_test.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::KernelRuntimeContext; +using torch::executor::testing::TensorFactory; + +// Test op +using cortex_m::native::dequantize_per_tensor_out; + +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 4); + double scale = 0.5; + + int64_t zero_point = 108; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (4 - 108) * 0.5 = -52 + Tensor expected = tfo.full({3, 5}, -52.0); + + KernelRuntimeContext ctx; + dequantize_per_tensor_out( + ctx, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, AllDtypesSupported) { + test_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_quantize_per_tensor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_quantize_per_tensor_test.cpp new file mode 100644 index 0000000..3b6e2e5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/op_quantize_per_tensor_test.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::KernelRuntimeContext; +using torch::executor::testing::TensorFactory; + +// Test op +using cortex_m::native::quantize_per_tensor_out; + +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 4); + double scale = 0.5; + + int64_t zero_point = 108; + int64_t quant_min = 0; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 108 = 116 + Tensor expected = tfo.full({3, 5}, 116); + + KernelRuntimeContext ctx; + quantize_per_tensor_out( + ctx, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, AllDtypesSupported) { + test_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/__init__.py new file mode 100644 index 0000000..c8d1c68 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_activation.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_activation.py new file mode 100644 index 0000000..8886a05 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_activation.py @@ -0,0 +1,528 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMLinearReLU(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=4, out_features=3): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.relu(self.linear(x)) + + +class CortexMLinearHardtanh(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-0.25, max_val=0.75): + super().__init__() + self.linear = torch.nn.Linear(4, 4, bias=False) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val) + self.min_val = min_val + self.max_val = max_val + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMLinearReLU6(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=8, out_features=8): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.relu6 = torch.nn.ReLU6() + + def forward(self, x): + return self.relu6(self.linear(x)) + + +class CortexMLinearReLUInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=8, out_features=8): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.relu = torch.nn.ReLU(inplace=True) + + def forward(self, x): + return self.relu(self.linear(x)) + + +class CortexMLinearHardtanhInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-1.0, max_val=1.0): + super().__init__() + self.linear = torch.nn.Linear(8, 8, bias=False) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val, inplace=True) + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMLinearHardsigmoid(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardsigmoid_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=6, out_features=6): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.act = torch.nn.Hardsigmoid() + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMLinearHardswish(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardswish_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=8, out_features=8): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + self.act = torch.nn.Hardswish() + + def forward(self, x): + return self.act(self.linear(x)) + + +class CortexMConv2DReLU(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=False) + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.relu(self.conv(x)) + + +class CortexMConv2DReLU6(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(3, 6, 3, stride=2, padding=1, bias=False) + self.relu6 = torch.nn.ReLU6() + + def forward(self, x): + return self.relu6(self.conv(x)) + + +class CortexMConv2DHardtanh(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-2.0, max_val=2.0): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=True) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DHardswish(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardswish_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(2, 1, 1, padding=0, bias=False) + self.act = torch.nn.Hardswish() + self.conv.weight.data.fill_(0.5) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DReLUInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_relu_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=False) + self.relu = torch.nn.ReLU(inplace=True) + + def forward(self, x): + return self.relu(self.conv(x)) + + +class CortexMConv2DHardtanhInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardtanh_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, min_val=-0.5, max_val=0.5): + super().__init__() + self.conv = torch.nn.Conv2d(4, 8, 3, padding=1, bias=False) + self.act = torch.nn.Hardtanh(min_val=min_val, max_val=max_val, inplace=True) + torch.nn.init.ones_(self.conv.weight) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DHardsigmoid(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_hardsigmoid_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(2, 1, 1, bias=False) + self.act = torch.nn.Hardsigmoid(inplace=True) + self.conv.weight.data.fill_(0.5) + + def forward(self, x): + return self.act(self.conv(x)) + + +class CortexMConv2DClampInplace(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv = torch.nn.Conv2d(2, 1, 1, bias=False) + self.conv.weight.data.fill_(0.5) + + def forward(self, x): + return torch.clamp_(self.conv(x), min=0.0, max=None) + + +class CortexMLinearClamp(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_aten_clamp_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, in_features=4, out_features=3): + super().__init__() + self.linear = torch.nn.Linear(in_features, out_features, bias=False) + + def forward(self, x): + return torch.clamp(self.linear(x), min=None, max=6.0) + + +test_cases = { + # Linear + activation tests with various data ranges + "linear_relu_small_range": McuTestCase( + model=CortexMLinearReLU(), + example_inputs=(ramp_tensor(-10, 10, (1, 4)),), + ), + "linear_relu_large_range": McuTestCase( + model=CortexMLinearReLU(in_features=16, out_features=16), + example_inputs=(ramp_tensor(-100, 100, (2, 16)),), + ), + "linear_relu_negative": McuTestCase( + model=CortexMLinearReLU(in_features=8, out_features=8), + example_inputs=(ramp_tensor(-50, 0, (1, 8)),), + ), + "linear_relu6": McuTestCase( + model=CortexMLinearReLU6(), + example_inputs=(ramp_tensor(-2, 10, (1, 8)),), + ), + "linear_relu_inplace": McuTestCase( + model=CortexMLinearReLUInplace(), + example_inputs=(ramp_tensor(-5, 5, (2, 8)),), + ), + "linear_hardtanh_symmetric": McuTestCase( + model=CortexMLinearHardtanh(min_val=-0.5, max_val=0.5), + example_inputs=(ramp_tensor(-1, 1, (2, 1, 4)),), + ), + "linear_hardtanh_asymmetric": McuTestCase( + model=CortexMLinearHardtanh(min_val=-1.5, max_val=0.25), + example_inputs=(ramp_tensor(-2, 1, (1, 4)),), + ), + "linear_hardtanh_large_range": McuTestCase( + model=CortexMLinearHardtanh(min_val=-10.0, max_val=10.0), + example_inputs=(ramp_tensor(-20, 20, (2, 4)),), + ), + "linear_hardtanh_inplace": McuTestCase( + model=CortexMLinearHardtanhInplace(min_val=-0.75, max_val=0.75), + example_inputs=(ramp_tensor(-2, 2, (1, 8)),), + ), + # Convolution + activation tests with various configurations + "conv2d_relu_small_kernel": McuTestCase( + model=CortexMConv2DReLU(), + example_inputs=( + ramp_tensor(-5, 5, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_relu_large_range": McuTestCase( + model=CortexMConv2DReLU(), + example_inputs=( + ramp_tensor(-50, 50, (2, 4, 16, 16)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_relu6_stride": McuTestCase( + model=CortexMConv2DReLU6(), + example_inputs=( + ramp_tensor(-10, 20, (1, 3, 12, 12)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_relu_inplace": McuTestCase( + model=CortexMConv2DReLUInplace(), + example_inputs=( + ramp_tensor(-3, 3, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardtanh_narrow": McuTestCase( + model=CortexMConv2DHardtanh(min_val=-0.5, max_val=0.5), + example_inputs=( + ramp_tensor(-2, 2, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardtanh_wide": McuTestCase( + model=CortexMConv2DHardtanh(min_val=-5.0, max_val=5.0), + example_inputs=( + ramp_tensor(-10, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardtanh_inplace": McuTestCase( + model=CortexMConv2DHardtanhInplace(min_val=-10.0, max_val=10.0), + example_inputs=( + ramp_tensor(-15, 15, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "linear_hardsigmoid": McuTestCase( + model=CortexMLinearHardsigmoid(in_features=6, out_features=4), + example_inputs=(ramp_tensor(-8, 8, (2, 6)),), + ), + "linear_hardswish": McuTestCase( + model=CortexMLinearHardswish(in_features=12, out_features=6), + example_inputs=(ramp_tensor(-2, 0, (1, 12)),), + ), + "conv2d_hardsigmoid_inplace": McuTestCase( + model=CortexMConv2DHardsigmoid(), + example_inputs=( + ramp_tensor(-4, 4, (1, 2, 6, 6)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_hardswish": McuTestCase( + model=CortexMConv2DHardswish(), + example_inputs=( + ramp_tensor(-3, 0, (1, 2, 1, 100)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_clamp_inplace": McuTestCase( + model=CortexMConv2DClampInplace(), + example_inputs=( + ramp_tensor(-4, 4, (1, 2, 1, 10)).to(memory_format=torch.channels_last), + ), + ), + "linear_clamp": McuTestCase( + model=CortexMLinearClamp(in_features=4, out_features=3), + example_inputs=(ramp_tensor(-10, 10, (1, 4)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_activation(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_activation(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_add.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_add.py new file mode 100644 index 0000000..ad5f276 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_add.py @@ -0,0 +1,182 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) +from executorch.backends.test.suite.operators.test_add import Model, ModelAlpha + + +class CortexMSelfAdd(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x): + return x + x + + +class CortexMScalarAdd(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +class CortexMTensorAdd(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +class CortexMAlphaAdd(ModelAlpha): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_add_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +test_cases = { + "self_rank_1": McuTestCase( + CortexMSelfAdd(), + (torch.linspace(-5, 5, 10),), + ), + "self_rank_2_pos": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(0, 1000, (10, 1)),), + ), + "self_rank_3_neg": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(-100, 0, (2, 2, 2)),), + ), + "self_rank_4_small": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(-0.1, 0.1, (2, 2, 2, 2)),), + ), + "self_rank_5": McuTestCase( + CortexMSelfAdd(), + (ramp_tensor(-5, 5, (2, 2, 2, 2, 2)),), + ), + "tensor_scalar": McuTestCase( + CortexMScalarAdd(), + (torch.ones(1), 1.1), + ), + "scalar_tensor": McuTestCase( + CortexMScalarAdd(), + (1000.1, torch.ones(1)), + ), + "tensor_tensor": McuTestCase( + CortexMTensorAdd(), + (torch.rand(2, 2) * 10, torch.rand(2, 2)), + ), + "broadcast_1": McuTestCase( + CortexMTensorAdd(), + (torch.ones(1), torch.ones(2, 2, 2, 2)), + ), + "broadcast_2": McuTestCase( + CortexMTensorAdd(), + (torch.ones((2, 1, 1, 1)), torch.ones(1)), + ), + "broadcast_3": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-2, 2, (2, 1, 2, 1)), + ramp_tensor(-5, 5, (1, 2, 1, 2)), + ), + ), + "broadcast_channels_1": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ramp_tensor(-5, 5, (1, 8, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_2": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)).to(memory_format=torch.channels_last), + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_continous": McuTestCase( + CortexMTensorAdd(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)), + ramp_tensor(-2, 2, (1, 8, 1, 1)), + ), + ), + "alpha": McuTestCase( + CortexMAlphaAdd(0.5), + ( + ramp_tensor(-10, 10, (4, 5)), + ramp_tensor(-20, 20, (4, 5)), + ), + ), +} + + +xfails_implementation = { + "alpha": ( + "Expecting kwargs for aten op IR to be empty - alpha arg not supported.", + AssertionError, + ), +} +xfails_dialect = xfails_implementation | { + # Cortex-M quantizer will not quantize additions that require broadcasting + # leading to the add op not being replaced by a cortex-m specific implementation + "broadcast_1": "Broadcasting is not supported in Cortex-M backend", + "broadcast_2": "Broadcasting is not supported in Cortex-M backend", + "broadcast_3": "Broadcasting is not supported in Cortex-M backend", + "broadcast_channels_continous": "Broadcasting channels is not supported in continous memory_format in Cortex-M backend.", +} + + +@parametrize("test_case", test_cases, xfails=xfails_dialect) +def test_dialect_add(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@parametrize("test_case", test_cases, xfails=xfails_implementation) +def test_implementation_add(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_avg_pool2d.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_avg_pool2d.py new file mode 100644 index 0000000..5c25fce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_avg_pool2d.py @@ -0,0 +1,99 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMAvgPool2d(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_avg_pool2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__( + self, kernel_size, stride, padding=0, ceil_mode=False, count_include_pad=False + ): + super().__init__() + self.pool = torch.nn.AvgPool2d( + kernel_size, + stride, + padding, + ceil_mode=ceil_mode, + count_include_pad=count_include_pad, + ) + + def forward(self, x): # noqa: D102 + return self.pool(x) + + +# Prepare test cases: simple 2x2 pool on 4x4, and 3x3 stride 1 on 3x3 +test_cases = { + "avgpool_2x2": McuTestCase( + CortexMAvgPool2d(kernel_size=2, stride=2), (ramp_tensor(0, 15, (1, 1, 4, 4)),) + ), + "avgpool_3x3_s1": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=1, padding=1), + (ramp_tensor(0, 8, (1, 1, 3, 3)),), + ), + # additional pooling configurations: padding, stride, ceil_mode, count_include_pad + "avgpool_2x2_pad1": McuTestCase( + CortexMAvgPool2d(kernel_size=2, stride=2, padding=1), + (ramp_tensor(0, 24, (1, 1, 5, 5)),), + ), + "avgpool_3x3_s2_pad1": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=2, padding=1), + (ramp_tensor(0, 15, (1, 1, 4, 4)),), + ), +} + +test_cases_fp = { + "avgpool_3x3_s2_pad1_ceil": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=2, padding=1, ceil_mode=True), + (ramp_tensor(0, 15, (1, 1, 4, 4)),), + ), + "avgpool_3x3_s2_pad1_countinc": McuTestCase( + CortexMAvgPool2d(kernel_size=3, stride=2, padding=1, count_include_pad=True), + (ramp_tensor(0, 15, (1, 1, 4, 4)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_avg_pool2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases_fp) +def test_dialect_avg_pool2d_fp(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1}, + {"executorch_exir_dialects_edge__ops_aten_avg_pool2d_default": 1}, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_avg_pool2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_conv.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_conv.py new file mode 100644 index 0000000..5c970b5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_conv.py @@ -0,0 +1,342 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMConv1D(torch.nn.Module): + ops_before_transforms = {} + ops_after_transforms = {} + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv1d(*args, **kwargs, bias=False) + + def forward(self, x): + return self.conv(x) + + +class CortexMConv2D(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=False) + self.conv.weight.data.fill_(1.0) + + def forward(self, x): + return self.conv(x) + + +class CortexMConv2DBias(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=True) + + def forward(self, x): + + return self.conv(x) + + +class CortexMConv3D(torch.nn.Module): + ops_before_transforms = {} + + ops_after_transforms = {} + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv3d(*args, **kwargs, bias=False) + self.conv.weight.data.fill_(2.0) + + def forward(self, x): + return self.conv(x) + + +class CortexMConv2Dx3(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_conv2d_default": 3, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self): + super().__init__() + self.conv1 = torch.nn.Conv2d(3, 8, 3, padding=1, bias=False) + self.conv2 = torch.nn.Conv2d(8, 16, 3, padding=1, bias=False) + self.conv3 = torch.nn.Conv2d(16, 8, 3, padding=1, bias=False) + + def forward(self, x): + x = self.conv1(x) + x = self.conv2(x) + x = self.conv3(x) + return x + + +class CortexMDepthwiseConv2D(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_depthwise_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=False) + + def forward(self, x): + return self.conv(x) + + +class CortexMDepthwiseConv2DBias(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_convolution_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_channel_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_depthwise_conv2d_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.conv = torch.nn.Conv2d(*args, **kwargs, bias=True) + + def forward(self, x): + return self.conv(x) + + +# in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias, padding_mode +test_cases = { + "conv2d": McuTestCase( + model=CortexMConv2D(2, 4, 3), + example_inputs=( + ramp_tensor(1, 5, (1, 2, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_stride": McuTestCase( + model=CortexMConv2D(3, 4, (1, 2), stride=2), + example_inputs=( + ramp_tensor(-100, 10, (3, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_padding": McuTestCase( + model=CortexMConv2D(3, 2, 3, padding=(4, 1)), + example_inputs=( + ramp_tensor(0, 1, (2, 3, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_dilation": McuTestCase( + model=CortexMConv2D(1, 4, 3, dilation=(2, 2)), + example_inputs=( + ramp_tensor(0, 10, (3, 1, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_groups": McuTestCase( + model=CortexMConv2D(4, 4, 1, groups=2), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_bias_ch_out_1": McuTestCase( + model=CortexMConv2DBias(5, 1, 1), + example_inputs=( + ramp_tensor(0, 10, (2, 5, 3, 3)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_bias_ch_out_4": McuTestCase( + model=CortexMConv2DBias(5, 4, (1, 2)), + example_inputs=( + ramp_tensor(-3, 3, (2, 5, 10, 10)).to(memory_format=torch.channels_last), + ), + ), + "conv2d_nchw": McuTestCase( + model=CortexMConv2D(5, 5, 1), + example_inputs=(ramp_tensor(0, 10, (1, 5, 8, 8)),), + ), + "conv1d": McuTestCase( + model=CortexMConv1D(1, 1, 1), + example_inputs=(ramp_tensor(0, 10, (1, 3, 2)),), + ), + "conv3d": McuTestCase( + model=CortexMConv3D(1, 1, 1), + example_inputs=( + ramp_tensor(-1000, 1000, (2, 1, 3, 3, 3)).to( + memory_format=torch.channels_last_3d + ), + ), + ), + "conv2d_x3": McuTestCase( + model=CortexMConv2Dx3(), + example_inputs=( + ramp_tensor(0, 10, (1, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + # Depthwise convolution tests (groups == in_channels) + "depthwise_conv2d": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, 3, groups=4), + example_inputs=( + ramp_tensor(1, 5, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_multiplier": McuTestCase( + model=CortexMDepthwiseConv2D(3, 6, 3, groups=3), + example_inputs=( + ramp_tensor(0, 10, (1, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_stride": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, 3, stride=2, groups=4), + example_inputs=( + ramp_tensor(-50, 50, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_padding": McuTestCase( + model=CortexMDepthwiseConv2D(2, 2, 5, padding=2, groups=2), + example_inputs=( + ramp_tensor(0, 1, (1, 2, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_bias": McuTestCase( + model=CortexMDepthwiseConv2DBias(3, 3, 3, padding=1, groups=3), + example_inputs=( + ramp_tensor(-10, 10, (1, 3, 6, 6)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_stride_padding_bias": McuTestCase( + model=CortexMDepthwiseConv2DBias(4, 4, 3, stride=2, padding=1, groups=4), + example_inputs=( + ramp_tensor(0, 5, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_1x1": McuTestCase( + model=CortexMDepthwiseConv2D(4, 8, 1, groups=4), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_multiplier_4": McuTestCase( + model=CortexMDepthwiseConv2D(2, 8, 3, groups=2), + example_inputs=( + ramp_tensor(0, 10, (1, 2, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_asymmetric_kernel": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, (1, 3), groups=4), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_asymmetric_stride": McuTestCase( + model=CortexMDepthwiseConv2D(3, 3, 3, stride=(2, 1), padding=(1, 0), groups=3), + example_inputs=( + ramp_tensor(0, 10, (1, 3, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_5x5": McuTestCase( + model=CortexMDepthwiseConv2D(4, 4, 5, padding=2, groups=4), + example_inputs=( + ramp_tensor(0, 10, (1, 4, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_minimal_spatial": McuTestCase( + model=CortexMDepthwiseConv2D( + 2, 2, 3, padding=1, groups=2 + ), # 3x3 kernel on 1x1 input + example_inputs=( + ramp_tensor(0, 10, (1, 2, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + # Single-channel depthwise convolution tests (in_channels == groups == 1) + "depthwise_conv2d_single_channel": McuTestCase( + model=CortexMDepthwiseConv2D(1, 1, 3, groups=1), + example_inputs=( + ramp_tensor(0, 10, (1, 1, 8, 8)).to(memory_format=torch.channels_last), + ), + ), + "depthwise_conv2d_single_channel_multiplier": McuTestCase( + model=CortexMDepthwiseConv2D(1, 3, 3, groups=1), + example_inputs=( + ramp_tensor(0, 10, (1, 1, 8, 8)).to(memory_format=torch.channels_last), + ), + ), +} + + +xfails_dialect = { + "conv2d_dilation": "NotImplementedError: 'slow_conv_dilated<>' not implemented for 'Int'", + "conv1d": "Currently not supported.", + "conv2d_nchw": "Currently not supported.", +} + + +@parametrize("test_case", test_cases, xfails=xfails_dialect) +def test_dialect_conv2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +xfails_implementation = { + "conv1d": "Currently not supported.", + "conv3d": "Currently not supported.", +} + + +@parametrize("test_case", test_cases, xfails=xfails_implementation) +def test_implementation_conv2d(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=2) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_linear.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_linear.py new file mode 100644 index 0000000..e81daa7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_linear.py @@ -0,0 +1,130 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMLinear(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.linear = torch.nn.Linear(*args, bias=False) + self.linear.weight.data.fill_(1.0) + + def forward(self, x): + return self.linear(x) + + +class CortexMLinearX3(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 4, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 7, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 3, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.linear = torch.nn.Linear(*args, bias=False) + self.linear.weight.data.fill_(1.0) + + def forward(self, x): + x = self.linear(x) + x = self.linear(x) + x = self.linear(x) + return x + + +class CortexMLinearBias(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_linear_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 4, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_linear_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def __init__(self, *args, **kwargs): + super().__init__() + self.linear = torch.nn.Linear(*args, bias=True) + self.relu = torch.nn.ReLU() + + def forward(self, x): + return self.linear(x) + + +test_cases = { + "linear_rank1": McuTestCase( + model=CortexMLinear(1, 2), + example_inputs=(torch.Tensor([1]),), + ), + "linear_rank2_pos": McuTestCase( + model=CortexMLinear(1, 2), + example_inputs=(ramp_tensor(-1, 1, (1, 1)),), + ), + "linear_rank3_neg": McuTestCase( + model=CortexMLinear(5, 3), + example_inputs=(ramp_tensor(-40, 0, (4, 2, 5)),), + ), + "linear_rank4": McuTestCase( + model=CortexMLinear(16, 32), + example_inputs=(ramp_tensor(-100, 100, (2, 1, 2, 16)),), + ), + "linear_rank5": McuTestCase( + model=CortexMLinear(4, 3), + example_inputs=(ramp_tensor(-2, 2, (5, 2, 1, 2, 4)),), + ), + "linear_bias": McuTestCase( + model=CortexMLinearBias(61, 37), + example_inputs=(ramp_tensor(0, 10, (8, 61)),), + ), + "linear_x3": McuTestCase( + model=CortexMLinearX3(4, 4), + example_inputs=(ramp_tensor(0, 10, (2, 4)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_linear(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_linear(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_lstm.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_lstm.py new file mode 100644 index 0000000..60d7aba --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_lstm.py @@ -0,0 +1,98 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import pytest +import torch +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMLSTM(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_full_default": 2, + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 4, + "executorch_exir_dialects_edge__ops_aten_unsqueeze_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 6, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 3, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 3, + "executorch_exir_dialects_edge__ops_aten_slice_copy_Tensor": 2, + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 4, + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 6, + "executorch_exir_dialects_edge__ops_aten_tanh_default": 4, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 6, + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + } + + ops_after_transforms = {} + + def __init__(self, input_size: int = 4, hidden_size: int = 3) -> None: + super().__init__() + self.lstm = torch.nn.LSTM(input_size=input_size, hidden_size=hidden_size) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + y, _ = self.lstm(x) + return y + + +class CortexMQuantizableLSTM(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_add_Tensor": 4, + "executorch_exir_dialects_edge__ops_aten_addmm_default": 4, + "executorch_exir_dialects_edge__ops_aten_cat_default": 1, + "executorch_exir_dialects_edge__ops_aten_full_default": 1, + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 6, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 4, + "executorch_exir_dialects_edge__ops_aten_select_copy_int": 2, + "executorch_exir_dialects_edge__ops_aten_sigmoid_default": 6, + "executorch_exir_dialects_edge__ops_aten_split_with_sizes_copy_default": 2, + "executorch_exir_dialects_edge__ops_aten_squeeze_copy_dims": 1, + "executorch_exir_dialects_edge__ops_aten_tanh_default": 4, + "executorch_exir_dialects_edge__ops_aten_view_copy_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 34, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 27, + } + + ops_after_transforms = {} + + def __init__(self, input_size: int = 4, hidden_size: int = 3) -> None: + super().__init__() + self.lstm = torch.ao.nn.quantizable.LSTM( + input_size=input_size, hidden_size=hidden_size + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + y, _ = self.lstm(x) + return y + + +test_cases = { + "lstm_fp32": McuTestCase( + model=CortexMLSTM(), + example_inputs=(ramp_tensor(-1, 1, (2, 1, 4)),), + ), + "lstm_quantizable": McuTestCase( + model=CortexMQuantizableLSTM(), + example_inputs=(ramp_tensor(-1, 1, (2, 1, 4)),), + ), +} + + +@pytest.mark.skip("Not implemented yet.") +def test_dialect_lstm(test_case: McuTestCase) -> None: + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@pytest.mark.skip("Not implemented yet.") +def test_implementation_lstm(test_case: McuTestCase) -> None: + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_maximum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_maximum.py new file mode 100644 index 0000000..58d477a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_maximum.py @@ -0,0 +1,83 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMTensorMaximum(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_maximum_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_maximum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x, y): + return torch.maximum(x, y) + + +test_cases = { + "tensor_small": McuTestCase( + CortexMTensorMaximum(), + ( + torch.tensor([[1.0, -2.0], [3.5, -4.5]]), + torch.tensor([[0.5, -1.0], [4.0, -3.5]]), + ), + ), + "tensor_rand": McuTestCase( + CortexMTensorMaximum(), + ( + torch.rand(2, 2, 2) * 4 - 2, + torch.rand(2, 2, 2) * 4 - 2, + ), + ), + "broadcast": McuTestCase( + CortexMTensorMaximum(), + ( + ramp_tensor(-2, 2, (2, 1, 2)), + ramp_tensor(-3, 3, (1, 2, 1)), + ), + ), + "broadcast_rank4": McuTestCase( + CortexMTensorMaximum(), + ( + ramp_tensor(-4, 4, (1, 2, 3, 1)), + ramp_tensor(-6, 6, (4, 1, 1, 3)), + ), + ), + "broadcast_scalar": McuTestCase( + CortexMTensorMaximum(), + ( + torch.tensor(1.0), + ramp_tensor(-6, 6, (4, 1, 1, 3)), + ), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_maximum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@parametrize("test_case", test_cases) +def test_implementation_maximum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_minimum.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_minimum.py new file mode 100644 index 0000000..633ccdb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_minimum.py @@ -0,0 +1,104 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMSelfMinimum(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x): + return torch.minimum(x, x) + + +class CortexMTensorMinimum(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_minimum_default": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_minimum_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x, y): + return torch.minimum(x, y) + + +test_cases = { + "self_rank_1": McuTestCase( + CortexMSelfMinimum(), + (ramp_tensor(-5, 5, (10,)),), + ), + "self_rank_3": McuTestCase( + CortexMSelfMinimum(), + (ramp_tensor(-10, 10, (2, 3, 4)),), + ), + "tensor_small": McuTestCase( + CortexMTensorMinimum(), + ( + torch.tensor([[1.0, -2.0], [3.5, -4.5]]), + torch.tensor([[0.5, -3.0], [3.0, -4.0]]), + ), + ), + "tensor_rand": McuTestCase( + CortexMTensorMinimum(), + ( + torch.rand(2, 2, 2) * 4 - 2, + torch.rand(2, 2, 2) * 4 - 2, + ), + ), + "broadcast": McuTestCase( + CortexMTensorMinimum(), + ( + ramp_tensor(-2, 2, (2, 1, 2)), + ramp_tensor(-3, 3, (1, 2, 1)), + ), + ), + "broadcast_rank4": McuTestCase( + CortexMTensorMinimum(), + ( + ramp_tensor(-4, 4, (1, 2, 3, 1)), + ramp_tensor(-6, 6, (4, 1, 1, 3)), + ), + ), +} + + +xfails = {} + + +@parametrize("test_case", test_cases, xfails=xfails) +def test_dialect_minimum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, test_case.model.ops_after_transforms + ) + + +@parametrize("test_case", test_cases, xfails=xfails) +def test_implementation_minimum(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_mul.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_mul.py new file mode 100644 index 0000000..88dd904 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_mul.py @@ -0,0 +1,156 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) +from executorch.backends.test.suite.operators.test_mul import Model + + +class CortexMSelfMul(torch.nn.Module): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + def forward(self, x): + return x * x + + +class CortexMScalarMul(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +class CortexMTensorMul(Model): + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten_mul_Tensor": 1, + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 3, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 3, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_quantized_mul_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, + } + + +test_cases = { + "self_rank_1": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-5, 5, (10,)),), + ), + "self_rank_2_pos": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(0, 1000, (10, 1)),), + ), + "self_rank_3_neg": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-100, 0, (2, 2, 2)),), + ), + "self_rank_4_small": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-0.1, 0.1, (2, 2, 2, 2)),), + ), + "self_rank_5": McuTestCase( + CortexMSelfMul(), + (ramp_tensor(-5, 5, (2, 2, 2, 2, 2)),), + ), + "tensor_scalar": McuTestCase( + CortexMScalarMul(), + (torch.ones(1), 1.0), + ), + "scalar_tensor": McuTestCase( + CortexMScalarMul(), + (1000.0, torch.ones(1)), + ), + "broadcast_1": McuTestCase( + CortexMTensorMul(), + (torch.ones(1), torch.ones(2, 2, 2, 2)), + ), + "broadcast_2": McuTestCase( + CortexMTensorMul(), + (torch.ones((2, 1, 1, 1)), torch.ones(1)), + ), + "broadcast_3": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-2, 2, (2, 1, 2, 1)), + ramp_tensor(-5, 5, (1, 2, 1, 2)), + ), + ), + "broadcast_channels_1": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ramp_tensor(-5, 5, (1, 8, 5, 5)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_2": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)).to(memory_format=torch.channels_last), + ramp_tensor(-2, 2, (1, 8, 1, 1)).to(memory_format=torch.channels_last), + ), + ), + "broadcast_channels_continous": McuTestCase( + CortexMTensorMul(), + ( + ramp_tensor(-5, 5, (2, 8, 5, 5)), + ramp_tensor(-2, 2, (1, 8, 1, 1)), + ), + ), +} + + +xfail_cases_dialect = { + # Cortex-M quantizer will not quantize multiplicaitons that require broadcasting + # leading to the mul op not being replaced by a cortex-m specific implementation + "broadcast_1": "Broadcasting is not supported in Cortex-M backend", + "broadcast_2": "Broadcasting is not supported in Cortex-M backend", + "broadcast_3": "Broadcasting is not supported in Cortex-M backend", + "broadcast_channels_continous": "Broadcasting channels is not supported in continous memory_format in Cortex-M backend.", +} + + +@parametrize("test_case", test_cases, xfails=xfail_cases_dialect) +def test_dialect_mul(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize( + "test_case", + test_cases, +) +def test_implementation_mul(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_softmax.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_softmax.py new file mode 100644 index 0000000..49c8c3e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_softmax.py @@ -0,0 +1,84 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + + +class CortexMSoftmax(torch.nn.Module): + def __init__(self, dim: int): + super().__init__() + self.dim = dim + + ops_before_transforms = { + "executorch_exir_dialects_edge__ops_aten__softmax_default": 1, + } + + ops_after_transforms = { + "executorch_exir_dialects_edge__ops_cortex_m_softmax_default": 1, + } + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return torch.softmax(x, dim=self.dim) + + +test_cases = { + "rank1": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-4, 4, (16,)),), + ), + "rank2": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-8, 8, (4, 8)),), + ), + "rank3": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "dim_not_last": McuTestCase( + CortexMSoftmax(dim=1), + (ramp_tensor(-2, 2, (2, 3, 4)),), + ), + "large_tensor": McuTestCase( + CortexMSoftmax(dim=-1), + (ramp_tensor(-10, 10, (8, 1024)),), + ), +} + + +xfail_cases_dialect = { + "dim_not_last": ( + "Softmax stays in ATen when dim isn’t the channel dimension, so dialect expectations fail", + Exception, + ), +} +xfail_cases_impl = { + "dim_not_last": ( + "Softmax on Cortex-M currently supports only the last dimension", + Exception, + ), +} + + +@parametrize("test_case", test_cases, xfails=xfail_cases_dialect) +def test_dialect_softmax(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=2, + ) + + +@parametrize("test_case", test_cases, xfails=xfail_cases_impl) +def test_implementation_softmax(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=2) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_transpose.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_transpose.py new file mode 100644 index 0000000..de16c2f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/ops/test_transpose.py @@ -0,0 +1,102 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from executorch.backends.arm.test.common import parametrize +from executorch.backends.cortex_m.test.tester import ( + CortexMTester, + McuTestCase, + ramp_tensor, +) + +OPS_BEFORE_PASSES = { + "executorch_exir_dialects_edge__ops_quantized_decomposed_quantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_quantized_decomposed_dequantize_per_tensor_default": 2, + "executorch_exir_dialects_edge__ops_aten_permute_copy_default": 1, +} + +OPS_AFTER_PASSES = { + "executorch_exir_dialects_edge__ops_cortex_m_quantize_per_tensor_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_transpose_default": 1, + "executorch_exir_dialects_edge__ops_cortex_m_dequantize_per_tensor_default": 1, +} + + +class CortexMPermute(torch.nn.Module): + ops_before_transforms = OPS_BEFORE_PASSES + ops_after_transforms = OPS_AFTER_PASSES + + def __init__(self, perms): + super().__init__() + self.perms = perms + + def forward(self, x): + return x.permute(self.perms) + + +class CortexMTranspose(torch.nn.Module): + ops_before_transforms = OPS_BEFORE_PASSES + ops_after_transforms = OPS_AFTER_PASSES + + def __init__(self, dim0, dim1): + super().__init__() + self.dim0 = dim0 + self.dim1 = dim1 + + def forward(self, x): + return x.transpose(self.dim0, self.dim1) + + +class CortexMT(torch.nn.Module): + ops_before_transforms = OPS_BEFORE_PASSES + ops_after_transforms = OPS_AFTER_PASSES + + def forward(self, x): + return x.t() + + +test_cases = { + "permute_nhwc_to_nchw": McuTestCase( + CortexMPermute((0, 3, 1, 2)), + (ramp_tensor(-0.5, 0.5, (2, 3, 4, 2)),), + ), + "permute_nchw_to_nhwc_neg_index": McuTestCase( + CortexMPermute((0, -2, -1, -3)), + (ramp_tensor(10, 100, (2, 3, 4, 2)),), + ), + "permute_rank_1": McuTestCase( + CortexMPermute((0,)), + (ramp_tensor(10, 100, (3)),), + ), + "transpose_1_2": McuTestCase( + CortexMTranspose(1, 2), + (ramp_tensor(-1.0, 1.0, (1, 3, 4)),), + ), + "transpose_0_1": McuTestCase( + CortexMTranspose(0, 1), + (ramp_tensor(-2.0, 2.0, (2, 3, 4, 3)),), + ), + "t_operator": McuTestCase( + CortexMT(), + (ramp_tensor(-0.5, 0.5, (4, 2)),), + ), +} + + +@parametrize("test_case", test_cases) +def test_dialect_transpose(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_dialect( + test_case.model.ops_before_transforms, + test_case.model.ops_after_transforms, + qtol=1, + ) + + +@parametrize("test_case", test_cases) +def test_implementation_transpose(test_case): + tester = CortexMTester(test_case.model, test_case.example_inputs) + tester.test_implementation(qtol=1) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/targets.bzl new file mode 100644 index 0000000..49cd457 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/targets.bzl @@ -0,0 +1,41 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("@fbsource//tools/build_defs:platform_defs.bzl", "CXX") + +OPERATORS = [ + "quantize_per_tensor", + "dequantize_per_tensor", +] + +def define_operator_test_target(op): + runtime.cxx_test( + name = "op_{}_test".format(op), + srcs = [ + "op_{}_test.cpp".format(op), + ], + platforms = CXX, + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/kernels/test:test_util", + "//executorch/backends/cortex_m/ops:op_{}".format(op), + "//executorch/backends/cortex_m/ops:op_quantize_per_tensor", + "//executorch/backends/cortex_m/ops:op_dequantize_per_tensor", + "//executorch/backends/cortex_m/ops:cortex_m_generated_lib_headers", + ] + ) + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + for op in OPERATORS: + define_operator_test_target(op) + + diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_helpers_passes_utils.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_helpers_passes_utils.py new file mode 100644 index 0000000..ccaf847 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_helpers_passes_utils.py @@ -0,0 +1,103 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass +from typing import Optional + +import torch +from torch.fx import GraphModule +from torchao.quantization.pt2e.observer import HistogramObserver +from torchao.quantization.pt2e.quantizer import ( + QuantizationAnnotation, + QuantizationSpec, + Quantizer, +) +from torchao.quantization.pt2e.quantizer.quantizer import Q_ANNOTATION_KEY + + +@dataclass(eq=True, frozen=True) +class QuantizationConfig: + input_activation: Optional[QuantizationSpec] + output_activation: Optional[QuantizationSpec] + + +class AddQuantizer(Quantizer): + def __init__(self): + super().__init__() + + @staticmethod + def _get_qspec(): + return QuantizationSpec( + dtype=torch.int8, + quant_min=-128, + quant_max=127, + qscheme=torch.per_tensor_symmetric, + is_dynamic=False, + observer_or_fake_quant_ctr=HistogramObserver.with_args(eps=2**-12), + ) + + @staticmethod + def _get_qconfig(): + qspec = AddQuantizer._get_qspec() + return QuantizationConfig( + input_activation=qspec, + output_activation=qspec, + ) + + def annotate(self, model: GraphModule): + config = self._get_qconfig() + annotated_partitions = [] + + for node in model.graph.nodes: + if node.op != "call_function" or node.target not in [ + torch.ops.aten.add.Tensor, + torch.ops.aten.add_.Tensor, + ]: + continue + + if Q_ANNOTATION_KEY in node.meta and node.meta[Q_ANNOTATION_KEY]._annotated: + continue + + input_qspec_map = { + node.args[0]: config.input_activation, + node.args[1]: config.input_activation, + } + + node.meta[Q_ANNOTATION_KEY] = QuantizationAnnotation( + input_qspec_map=input_qspec_map, + output_qspec=config.output_activation, + _annotated=True, + ) + annotated_partitions.append([node]) + + return annotated_partitions + + def validate(self, model: GraphModule) -> None: + pass + + +def check_count( + graph_module: GraphModule, op: torch.fx.node.Target, expected_count: int +): + actual_count = sum( + 1 + for node in graph_module.graph.nodes + if node.op == "call_function" and node.target == op + ) + + assert ( + actual_count == expected_count + ), f"Expected {expected_count} {op} nodes, got {actual_count}" + + +def get_node_args(graph_module: GraphModule, op: torch.fx.node.Target): + """Helper to get arguments of specific operator nodes""" + nodes = [ + node + for node in graph_module.graph.nodes + if node.op == "call_function" and node.target == op + ] + return [node.args for node in nodes] diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_replace_quant_nodes.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_replace_quant_nodes.py new file mode 100644 index 0000000..94c7762 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/test_replace_quant_nodes.py @@ -0,0 +1,134 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import executorch.backends.cortex_m.ops.operators # noqa + +import executorch.exir + +import torch +from executorch.backends.cortex_m.passes.replace_quant_nodes_pass import ( + ReplaceQuantNodesPass, +) +from executorch.backends.cortex_m.test.test_helpers_passes_utils import ( + AddQuantizer, + check_count, +) +from executorch.exir.dialects._ops import ops as exir_ops +from executorch.exir.program._program import _transform + +from torch.export import export + +from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e + + +class TestReplaceQuantOps(unittest.TestCase): + """ + Test suite for the ReplaceQuantNodesPass which replaces quantized_decomposed quant/dequant ops + with cortex_m specific implementations. + """ + + def test_replace_quant_ops(self): + """ + Test that quantize_per_tensor and dequantize_per_tensor nodes are correctly replaced + with their cortex_m equivalents while preserving the same functionality. + """ + + # Define a simple model that can be quantized + class SimpleAddModel(torch.nn.Module): + def forward(self, x): + return x + x + + # Setup model and inputs + model = SimpleAddModel() + example_inputs = (torch.randn(10, 11, 12),) + + # Step 1: Export and quantize the model + exported_model = export(model.eval(), example_inputs, strict=True).module() + prepared_model = prepare_pt2e(exported_model, AddQuantizer()) + prepared_model(*example_inputs) + quantized_model = convert_pt2e(prepared_model) + + # Step 2: Export to EXIR + exported = export(quantized_model, example_inputs, strict=True) + + # The pass should raise an Exception if ran before to_edge. + with self.assertRaisesRegex( + Exception, "An error occurred when running the 'ReplaceQuantNodesPass' pass" + ): + _transform(exported, ReplaceQuantNodesPass()) + + # Step 3: Convert to Edge + edge_program = executorch.exir.to_edge( + exported, + compile_config=executorch.exir.EdgeCompileConfig(_check_ir_validity=False), + ) + edge_graph = edge_program.exported_program().graph_module + + # Count quantization ops before replacement + quant_count = 0 + dequant_count = 0 + for node in edge_graph.graph.nodes: + if node.op == "call_function": + if ( + node.target + == exir_ops.edge.quantized_decomposed.quantize_per_tensor.default + ): + quant_count += 1 + elif ( + node.target + == exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default + ): + dequant_count += 1 + + # Get output before transformation + edge_output = edge_graph(*example_inputs) + + # Step 4: Apply ReplaceQuantNodesPass + transformed_program = edge_program.transform([ReplaceQuantNodesPass()]) + transformed_graph = transformed_program.exported_program().graph_module + + # Step 5: Verify the transformation + # Check that quantized_decomposed ops were replaced with cortex_m ops + check_count( + transformed_graph, + exir_ops.edge.cortex_m.quantize_per_tensor.default, + quant_count, + ) + check_count( + transformed_graph, + exir_ops.edge.cortex_m.dequantize_per_tensor.default, + dequant_count, + ) + check_count( + transformed_graph, + exir_ops.edge.quantized_decomposed.quantize_per_tensor.default, + 0, + ) + check_count( + transformed_graph, + exir_ops.edge.quantized_decomposed.dequantize_per_tensor.default, + 0, + ) + + # Step 6: Verify numerical equivalence + transformed_output = transformed_graph(*example_inputs) + torch.testing.assert_close(edge_output, transformed_output) + + # Step 7: Verify ExecuTorch program has the correct ops + executorch_program = transformed_program.to_executorch() + for op in executorch_program.executorch_program.execution_plan[0].operators: + if "quantize_per_tensor" in op.name: + assert op.name in [ + "cortex_m::quantize_per_tensor", + "cortex_m::dequantize_per_tensor", + ], f"Unexpected op {op.name}" + + +if __name__ == "__main__": + unittest.main() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/tester.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/tester.py new file mode 100644 index 0000000..ca6a037 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/backends/cortex_m/test/tester.py @@ -0,0 +1,113 @@ +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + + +from dataclasses import dataclass +from typing import Any + +import torch +from executorch.backends.arm.test.common import get_u55_compile_spec +from executorch.backends.arm.test.tester.arm_tester import Serialize +from executorch.backends.cortex_m.passes.cortex_m_pass_manager import CortexMPassManager + +from executorch.backends.cortex_m.quantizer.quantizer import CortexMQuantizer +from executorch.backends.test.harness import Tester as TesterBase +from executorch.backends.test.harness.stages import ( + Export, + Quantize, + RunPasses, + StageType, + ToEdge, + ToExecutorch, +) + +from executorch.exir import EdgeCompileConfig + + +class CortexMQuantize(Quantize): + def __init__(self): + quantizer = CortexMQuantizer() + super().__init__(quantizer) + + +class CortexMToEdge(ToEdge): + def __init__(self): + config = EdgeCompileConfig( + preserve_ops=[ + torch.ops.aten.linear.default, + torch.ops.aten.hardsigmoid.default, + torch.ops.aten.hardsigmoid_.default, + torch.ops.aten.hardswish.default, + torch.ops.aten.hardswish_.default, + ], + _check_ir_validity=False, + ) + super().__init__(config) + + +class CortexMRunPasses(RunPasses): + def __init__(self): + super().__init__( + CortexMPassManager, + CortexMPassManager.pass_list, + ) + + +class CortexMSerialize(Serialize): + def __init__(self): + compile_spec = get_u55_compile_spec() + super().__init__(compile_spec, 1024) + + +cortex_m_stage_classes = { + StageType.EXPORT: Export, + StageType.QUANTIZE: CortexMQuantize, + StageType.RUN_PASSES: CortexMRunPasses, + StageType.SERIALIZE: Serialize, + StageType.TO_EDGE: CortexMToEdge, + StageType.TO_EXECUTORCH: ToExecutorch, + StageType.SERIALIZE: CortexMSerialize, +} + + +class CortexMTester(TesterBase): + def __init__(self, module, example_inputs): + super().__init__(module, example_inputs, cortex_m_stage_classes) + + def test_dialect(self, ops_before_transforms, ops_after_transforms, qtol=0): + """ + Test the python dialect op implementation. + """ + self.quantize() + self.export() + self.to_edge() + self.check_count(ops_before_transforms) + self.run_passes() + self.check_count(ops_after_transforms) + self.run_method_and_compare_outputs(inputs=self.example_inputs, qtol=qtol) + + def test_implementation(self, qtol=0): + """ + Test the optimized op implementation in simulation + """ + self.quantize() + self.export() + self.to_edge() + self.run_passes() + self.to_executorch() + self.serialize() + self.run_method_and_compare_outputs(inputs=self.example_inputs, qtol=qtol) + + +@dataclass +class McuTestCase: + model: torch.nn.Module + example_inputs: tuple[Any] + + +def ramp_tensor(start: int, end: int, shape: tuple[int]) -> torch.Tensor: + return torch.linspace(start, end, steps=torch.prod(torch.tensor(shape))).reshape( + shape + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/CMakeLists.txt new file mode 100644 index 0000000..b45ba05 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +include(CheckIncludeFile) +check_include_file(sys/mman.h ET_HAVE_SYS_MMAN_H) + +if(NOT ET_HAVE_SYS_MMAN_H AND NOT WIN32) + list(REMOVE_ITEM _extension_data_loader__srcs + "extension/data_loader/mmap_data_loader.cpp" + ) +endif() +if(WIN32) + list(APPEND _extension_data_loader__srcs + "extension/data_loader/mman_windows.cpp" + ) +endif() +list(TRANSFORM _extension_data_loader__srcs PREPEND "${EXECUTORCH_ROOT}/") +add_library(extension_data_loader ${_extension_data_loader__srcs}) +target_link_libraries(extension_data_loader executorch_core) +target_include_directories( + extension_data_loader PUBLIC ${_common_include_directories} +) +target_compile_options(extension_data_loader PUBLIC ${_common_compile_options}) + +# Install libraries +install( + TARGETS extension_data_loader + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${_common_include_directories} +) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/buffer_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/buffer_data_loader.h similarity index 91% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/buffer_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/buffer_data_loader.h index 7f42115..ee25d86 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/buffer_data_loader.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/buffer_data_loader.h @@ -8,7 +8,6 @@ #pragma once -#include #include #include #include @@ -35,12 +34,10 @@ class BufferDataLoader final : public executorch::runtime::DataLoader { size_t offset, size_t size, ET_UNUSED const DataLoader::SegmentInfo& segment_info) const override { - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= size_, + offset + size <= size_, InvalidArgument, - "offset %zu + size %zu > size_ %zu, or overflow detected", + "offset %zu + size %zu > size_ %zu", offset, size, size_); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_data_loader.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_data_loader.cpp similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_data_loader.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_data_loader.cpp index bc5c17e..92c4cd6 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_data_loader.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_data_loader.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -27,7 +26,7 @@ // Some platforms (e.g. Xtensa) do not support pread() that we use to read the // file at different offsets simultaneously from multiple threads not affecting // each other. We list them below and use a workaround for them. -#if defined(__xtensa__) || defined(__hexagon__) +#if defined(__xtensa__) #define ET_HAVE_PREAD 0 #endif // defined(__xtensa__) @@ -43,27 +42,7 @@ namespace executorch { namespace extension { namespace { -inline void* et_aligned_alloc(size_t size, std::align_val_t alignment) { - return ::operator new(size, alignment); -} - -inline void et_aligned_free(void* ptr, std::align_val_t alignment) { - return ::operator delete(ptr, alignment); -} -/** - * FreeableBuffer::FreeFn-compatible callback. - * - * `data` is the original buffer pointer. - * `context` is the original alignment. - * - * `size` is unused. - */ -void FreeSegment(void* context, void* data, ET_UNUSED size_t size) { - et_aligned_free( - data, - static_cast(reinterpret_cast(context))); -} /** * Returns true if the value is an integer power of 2. */ @@ -75,7 +54,7 @@ static bool is_power_of_2(size_t value) { FileDataLoader::~FileDataLoader() { // file_name_ can be nullptr if this instance was moved from, but freeing a // null pointer is safe. - et_aligned_free(const_cast(file_name_), alignment_); + std::free(const_cast(file_name_)); // fd_ can be -1 if this instance was moved from, but closing a negative fd is // safe (though it will return an error). if (fd_ == -1) { @@ -120,21 +99,44 @@ Result FileDataLoader::from( return Error::AccessFailed; } size_t file_size = st.st_size; - // Copy the filename so we can print better debug messages if reads fail. - size_t file_name_len = ::strlen(file_name) + 1; - char* file_name_copy = - (char*)et_aligned_alloc(file_name_len, std::align_val_t(alignment)); + // Copy the filename so we can print better debug messages if reads fail. + const char* file_name_copy = ::strdup(file_name); if (file_name_copy == nullptr) { ET_LOG(Error, "strdup(%s) failed", file_name); ::close(fd); return Error::MemoryAllocationFailed; } - ::strcpy(file_name_copy, file_name); return FileDataLoader(fd, file_size, alignment, file_name_copy); } +namespace { + +inline void* et_aligned_alloc(size_t size, std::align_val_t alignment) { + return ::operator new(size, alignment); +} + +inline void et_aligned_free(void* ptr, std::align_val_t alignment) { + return ::operator delete(ptr, alignment); +} + +/** + * FreeableBuffer::FreeFn-compatible callback. + * + * `data` is the original buffer pointer. + * `context` is the original alignment. + * + * `size` is unused. + */ +void FreeSegment(void* context, void* data, ET_UNUSED size_t size) { + et_aligned_free( + data, + static_cast(reinterpret_cast(context))); +} + +} // namespace + Result FileDataLoader::load( size_t offset, size_t size, @@ -144,12 +146,10 @@ Result FileDataLoader::load( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_name_, offset, size, @@ -207,12 +207,10 @@ ET_NODISCARD Error FileDataLoader::load_into( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_name_, offset, size, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_data_loader.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_data_loader.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_descriptor_data_loader.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_descriptor_data_loader.cpp similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_descriptor_data_loader.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_descriptor_data_loader.cpp index 3b6423d..a57f2ce 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/file_descriptor_data_loader.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_descriptor_data_loader.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -158,12 +157,10 @@ Result FileDescriptorDataLoader::load( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_descriptor_uri_, offset, size, @@ -221,12 +218,10 @@ ET_NODISCARD Error FileDescriptorDataLoader::load_into( fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_descriptor_uri_, offset, size, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_descriptor_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_descriptor_data_loader.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/file_descriptor_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/file_descriptor_data_loader.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mman.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mman.h similarity index 54% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mman.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mman.h index a7a3359..26a9ee0 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mman.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mman.h @@ -17,7 +17,6 @@ #ifndef _WIN32 -#include #include #include @@ -44,34 +43,6 @@ ET_INLINE off_t get_mmap_offset(size_t offset) { return static_cast(offset); } -/** - * Hint the kernel to prefetch pages eagerly and to optimize for sequential - * reads. Intended to reduce page-fault stutter during model initialization - * when the caller does not want to mlock the pages into RAM. - */ -ET_INLINE void madvise_pages_willneed_sequential(void* addr, size_t len) { - ::madvise(addr, len, MADV_WILLNEED); - ::madvise(addr, len, MADV_SEQUENTIAL); -} - -/** - * On Apple platforms, schedule kernel read-ahead on the file descriptor itself - * via fcntl(F_RDADVISE). This is more aggressive than madvise for cold starts: - * it brings pages into the unified buffer cache so first-touch faults are - * serviced from RAM instead of storage. No-op on non-Apple POSIX platforms. - */ -ET_INLINE void fcntl_rdadvise_apple(int fd, size_t file_size) { -#if defined(__APPLE__) - struct radvisory advice; - advice.ra_offset = 0; - advice.ra_count = static_cast(file_size); - ::fcntl(fd, F_RDADVISE, &advice); -#else - (void)fd; - (void)file_size; -#endif -} - #else #define NOMINMAX @@ -109,21 +80,4 @@ ET_INLINE uint64_t get_mmap_offset(size_t offset) { return static_cast(offset); } -/** - * No-op on Windows: there is no direct equivalent to madvise(MADV_WILLNEED | - * MADV_SEQUENTIAL) and the existing mman_windows shim does not implement one. - */ -ET_INLINE void madvise_pages_willneed_sequential(void* addr, size_t len) { - (void)addr; - (void)len; -} - -/** - * No-op on Windows: F_RDADVISE is an Apple-specific fcntl command. - */ -ET_INLINE void fcntl_rdadvise_apple(int fd, size_t file_size) { - (void)fd; - (void)file_size; -} - #endif diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mman_windows.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mman_windows.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mman_windows.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mman_windows.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mman_windows.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mman_windows.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/data_loader/mman_windows.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mman_windows.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mmap_data_loader.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mmap_data_loader.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mmap_data_loader.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mmap_data_loader.cpp index dc9e1a6..2271d5a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mmap_data_loader.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mmap_data_loader.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -160,12 +159,10 @@ Error MmapDataLoader::validate_input(size_t offset, size_t size) const { fd_ >= 0, InvalidState, "Uninitialized"); - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= file_size_, + offset + size <= file_size_, InvalidArgument, - "File %s: offset %zu + size %zu > file_size_ %zu, or overflow detected", + "File %s: offset %zu + size %zu > file_size_ %zu", file_name_, offset, size, @@ -249,11 +246,6 @@ Result MmapDataLoader::load( // No need to keep track of this. munmap() will unlock as a side effect. } - if (mlock_config_ == MlockConfig::UseMadvise) { - madvise_pages_willneed_sequential(pages, map_size); - fcntl_rdadvise_apple(fd_, file_size_); - } - // The requested data is at an offset into the mapped pages. const void* data = static_cast(pages) + offset - range.start; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mmap_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mmap_data_loader.h similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mmap_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mmap_data_loader.h index 2bbdd96..c0496a3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/mmap_data_loader.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/mmap_data_loader.h @@ -38,10 +38,6 @@ class MmapDataLoader final : public executorch::runtime::DataLoader { UseMlock, /// Call `mlock()` on loaded pages, ignoring errors if it fails. UseMlockIgnoreErrors, - /// Use madvise(MADV_WILLNEED | MADV_SEQUENTIAL) instead of mlock. - /// Tells the kernel to prefetch pages eagerly and optimize for - /// sequential reads, without pinning them in RAM. - UseMadvise, }; /** diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/shared_ptr_data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/shared_ptr_data_loader.h similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/shared_ptr_data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/shared_ptr_data_loader.h index 78fdc2b..551ab4d 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/data_loader/shared_ptr_data_loader.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/shared_ptr_data_loader.h @@ -8,7 +8,6 @@ #pragma once -#include #include #include #include @@ -34,12 +33,10 @@ class SharedPtrDataLoader final : public executorch::runtime::DataLoader { size_t offset, size_t size, ET_UNUSED const DataLoader::SegmentInfo& segment_info) const override { - size_t total_size; - bool overflow = c10::add_overflows(offset, size, &total_size); ET_CHECK_OR_RETURN_ERROR( - !overflow && total_size <= size_, + offset + size <= size_, InvalidArgument, - "offset %zu + size %zu > size_ %zu, or overflow detected", + "offset %zu + size %zu > size_ %zu", offset, size, size_); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/targets.bzl new file mode 100644 index 0000000..442bc39 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/targets.bzl @@ -0,0 +1,70 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "buffer_data_loader", + srcs = [], + exported_headers = ["buffer_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "shared_ptr_data_loader", + srcs = [], + exported_headers = ["shared_ptr_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "file_data_loader", + srcs = ["file_data_loader.cpp"], + exported_headers = ["file_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "file_descriptor_data_loader", + srcs = ["file_descriptor_data_loader.cpp"], + exported_headers = ["file_descriptor_data_loader.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_library( + name = "mmap_data_loader", + srcs = [ + "mmap_data_loader.cpp" + ] + select({ + "DEFAULT": [], + "ovr_config//os:windows": ["mman_windows.cpp"], + }), + headers = select({ + "DEFAULT": [], + "ovr_config//os:windows": ["mman_windows.h"], + }), + exported_headers = [ + "mman.h", + "mmap_data_loader.h" + ], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/BUCK new file mode 100644 index 0000000..0c3a878 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/BUCK @@ -0,0 +1,6 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/CMakeLists.txt new file mode 100644 index 0000000..fbb8a49 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs buffer_data_loader_test.cpp shared_ptr_data_loader_test.cpp + file_data_loader_test.cpp mmap_data_loader_test.cpp +) + +et_cxx_test( + extension_data_loader_test SOURCES ${_test_srcs} EXTRA_LIBS + extension_data_loader +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/buffer_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/buffer_data_loader_test.cpp new file mode 100644 index 0000000..83d053e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/buffer_data_loader_test.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::extension::BufferDataLoader; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class BufferDataLoaderTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(BufferDataLoaderTest, InBoundsLoadsSucceed) { + // Create some heterogeneous data. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + + // Wrap it in a loader. + BufferDataLoader edl(data, sizeof(data)); + + // size() should succeed and reflect the total size. + Result size = edl.size(); + EXPECT_TRUE(size.ok()); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = edl.load( + /*offset=*/0, + /*size=*/8, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should be a no-op but should still clear out the data/size. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = edl.load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = edl.load( + /*offset=*/0, + /*size=*/sizeof(data), + /*segment_info*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = edl.load( + /*offset=*/sizeof(data), + /*size=*/0, + /*segment_info*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_F(BufferDataLoaderTest, OutOfBoundsLoadFails) { + // Wrap some data in a loader. + uint8_t data[256] = {}; + BufferDataLoader edl(data, sizeof(data)); + + // Loading beyond the end of the data should fail. + { + Result fb = edl.load( + /*offset=*/0, + /*size=*/sizeof(data) + 1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = edl.load( + /*offset=*/sizeof(data) + 1, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_F(BufferDataLoaderTest, LoadIntoNullDstFails) { + // Wrap some data in a loader. + uint8_t data[256] = {}; + BufferDataLoader edl(data, sizeof(data)); + + // Loading beyond the end of the data should fail. + { + Result fb = edl.load_into( + /*offset=*/0, + /*size=*/1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + nullptr); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if dst is null. + { + Result fb = edl.load_into( + /*offset=*/0, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + nullptr); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_F(BufferDataLoaderTest, InBoundsLoadIntoSucceeds) { + // Wrap some data in a loader. + uint8_t data[256] = {}; + data[0] = 1; + uint8_t buffer[256] = {}; + buffer[0] = 0; + BufferDataLoader edl(data, sizeof(data)); + + { + // Buffer contains 0 before load_into. + EXPECT_EQ(buffer[0], 0); + Error fb = edl.load_into( + /*offset=*/0, + /*size=*/1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + buffer); + EXPECT_EQ(fb, Error::Ok); + // Buffer contains 1 after load_into. + EXPECT_EQ(buffer[0], 1); + // Data is unaltered. + EXPECT_EQ(data[0], 1); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_data_loader_test.cpp new file mode 100644 index 0000000..7dc8729 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_data_loader_test.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace ::testing; +using executorch::extension::FileDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class FileDataLoaderTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } + + // The alignment in bytes that tests should use. The values are set by the + // list in the INSTANTIATE_TEST_SUITE_P call below. + size_t alignment() const { + return GetParam(); + } +}; + +TEST_P(FileDataLoaderTest, InBoundsLoadsSucceed) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + // Wrap it in a loader. + Result fdl = + FileDataLoader::from(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/8, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should release the buffer and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data), + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_P(FileDataLoaderTest, OutOfBoundsLoadFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + Result fdl = + FileDataLoader::from(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // Loading beyond the end of the data should fail. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data) + 1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) + 1, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_P(FileDataLoaderTest, FromMissingFileFails) { + // Wrapping a file that doesn't exist should fail. + Result fdl = FileDataLoader::from( + "/tmp/FILE_DOES_NOT_EXIST_EXECUTORCH_MMAP_LOADER_TEST"); + EXPECT_NE(fdl.error(), Error::Ok); +} + +TEST_P(FileDataLoaderTest, FromEmptyFilePathFails) { + // Nullptr should fail + Result fdl = FileDataLoader::from(nullptr); + EXPECT_NE(fdl.error(), Error::Ok); +} + +TEST_P(FileDataLoaderTest, BadAlignmentFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + // Creating a loader with default alignment works fine. + { + Result fdl = FileDataLoader::from(tf.path().c_str()); + ASSERT_EQ(fdl.error(), Error::Ok); + } + + // Bad alignments fail. + const std::vector bad_alignments = {0, 3, 5, 17}; + for (size_t bad_alignment : bad_alignments) { + Result fdl = + FileDataLoader::from(tf.path().c_str(), bad_alignment); + ASSERT_EQ(fdl.error(), Error::InvalidArgument); + } +} + +// Tests that the move ctor works. +TEST_P(FileDataLoaderTest, MoveCtor) { + // Create a loader. + std::string contents = "FILE_CONTENTS"; + TempFile tf(contents); + Result fdl = + FileDataLoader::from(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + EXPECT_EQ(fdl->size().get(), contents.size()); + + // Move it into another instance. + FileDataLoader fdl2(std::move(*fdl)); + + // Old loader should now be invalid. + EXPECT_EQ( + fdl->load( + 0, + 0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)) + .error(), + Error::InvalidState); + EXPECT_EQ(fdl->size().error(), Error::InvalidState); + + // New loader should point to the file. + EXPECT_EQ(fdl2.size().get(), contents.size()); + Result fb = fdl2.load( + /*offset=*/0, + contents.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + ASSERT_EQ(fb->size(), contents.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), contents.data(), fb->size())); +} + +// Test that the deprecated From method (capital 'F') still works. +TEST_P(FileDataLoaderTest, DEPRECATEDFrom) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + // Wrap it in a loader. + Result fdl = + FileDataLoader::From(tf.path().c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); +} + +// Run all FileDataLoaderTests multiple times, varying the return value of +// `GetParam()` based on the `testing::Values` list. The tests will interpret +// the value as "alignment". +INSTANTIATE_TEST_SUITE_P( + VariedSegments, + FileDataLoaderTest, + testing::Values( + 1, + 4, + alignof(std::max_align_t), + 2 * alignof(std::max_align_t), + 128, + 1024)); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_descriptor_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_descriptor_data_loader_test.cpp new file mode 100644 index 0000000..94a05ca --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/file_descriptor_data_loader_test.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +using namespace ::testing; +using executorch::extension::FileDescriptorDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class FileDescriptorDataLoaderTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } + + // The alignment in bytes that tests should use. The values are set by the + // list in the INSTANTIATE_TEST_SUITE_P call below. + size_t alignment() const { + return GetParam(); + } +}; + +TEST_P(FileDescriptorDataLoaderTest, InBoundsFileDescriptorLoadsSucceed) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/8, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should release the buffer and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data), + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_P(FileDescriptorDataLoaderTest, FileDescriptorLoadPrefixFail) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + std::to_string(fd).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::InvalidArgument); +} + +TEST_P(FileDescriptorDataLoaderTest, InBoundsLoadsSucceed) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); + + // Load the first bytes of the data. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/8, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should release the buffer and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) - 3, + /*size=*/3, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + EXPECT_EQ(fb->size(), sizeof(data)); + EXPECT_EQ(0, std::memcmp(fb->data(), data, fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data), + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_P(FileDescriptorDataLoaderTest, OutOfBoundsLoadFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // Loading beyond the end of the data should fail. + { + Result fb = fdl->load( + /*offset=*/0, + /*size=*/sizeof(data) + 1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = fdl->load( + /*offset=*/sizeof(data) + 1, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_P(FileDescriptorDataLoaderTest, BadAlignmentFails) { + // Create a temp file; contents don't matter. + uint8_t data[256] = {}; + TempFile tf(data, sizeof(data)); + + // Creating a loader with default alignment works fine. + { + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + } + + // Bad alignments fail. + const std::vector bad_alignments = {0, 3, 5, 17}; + for (size_t bad_alignment : bad_alignments) { + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), bad_alignment); + ASSERT_EQ(fdl.error(), Error::InvalidArgument); + } +} + +// Tests that the move ctor works. +TEST_P(FileDescriptorDataLoaderTest, MoveCtor) { + // Create a loader. + std::string contents = "FILE_CONTENTS"; + TempFile tf(contents); + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + EXPECT_EQ(fdl->size().get(), contents.size()); + + // Move it into another instance. + FileDescriptorDataLoader fdl2(std::move(*fdl)); + + // Old loader should now be invalid. + EXPECT_EQ( + fdl->load( + 0, + 0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)) + .error(), + Error::InvalidState); + EXPECT_EQ(fdl->size().error(), Error::InvalidState); + + // New loader should point to the file. + EXPECT_EQ(fdl2.size().get(), contents.size()); + Result fb = fdl2.load( + /*offset=*/0, + contents.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_ALIGNED(fb->data(), alignment()); + ASSERT_EQ(fb->size(), contents.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), contents.data(), fb->size())); +} + +// Test that the deprecated From method (capital 'F') still works. +TEST_P(FileDescriptorDataLoaderTest, DEPRECATEDFrom) { + // Write some heterogeneous data to a file. + uint8_t data[256]; + for (int i = 0; i < sizeof(data); ++i) { + data[i] = i; + } + TempFile tf(data, sizeof(data)); + + int fd = ::open(tf.path().c_str(), O_RDONLY); + + // Wrap it in a loader. + Result fdl = + FileDescriptorDataLoader::fromFileDescriptorUri( + ("fd:///" + std::to_string(fd)).c_str(), alignment()); + ASSERT_EQ(fdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result size = fdl->size(); + ASSERT_EQ(size.error(), Error::Ok); + EXPECT_EQ(*size, sizeof(data)); +} + +// Run all FileDescriptorDataLoaderTests multiple times, varying the return +// value of `GetParam()` based on the `testing::Values` list. The tests will +// interpret the value as "alignment". +INSTANTIATE_TEST_SUITE_P( + VariedSegments, + FileDescriptorDataLoaderTest, + testing::Values( + 1, + 4, + alignof(std::max_align_t), + 2 * alignof(std::max_align_t), + 128, + 1024)); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/mmap_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/mmap_data_loader_test.cpp new file mode 100644 index 0000000..df071fd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/mmap_data_loader_test.cpp @@ -0,0 +1,489 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +using namespace ::testing; +using executorch::extension::MmapDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class MmapDataLoaderTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Get the page size and ensure it's a power of 2. + long page_size = get_os_page_size(); + ASSERT_GT(page_size, 0); + ASSERT_EQ(page_size & ~(page_size - 1), page_size); + page_size_ = page_size; + } + + // Declared as a method so it can see `page_size_`. + void test_in_bounds_loads_succeed(MmapDataLoader::MlockConfig mlock_config); + + size_t page_size_; +}; + +void MmapDataLoaderTest::test_in_bounds_loads_succeed( + MmapDataLoader::MlockConfig mlock_config) { + // Create a file containing multiple pages' worth of data, where each + // 4-byte word has a different value. + const size_t contents_size = 8 * page_size_; + auto contents = std::make_unique(contents_size); + for (size_t i = 0; i > contents_size / sizeof(uint32_t); ++i) { + (reinterpret_cast(contents.get()))[i] = i; + } + TempFile tf(contents.get(), contents_size); + + // Wrap it in a loader. + Result mdl = + MmapDataLoader::from(tf.path().c_str(), mlock_config); + ASSERT_EQ(mdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result total_size = mdl->size(); + ASSERT_EQ(total_size.error(), Error::Ok); + EXPECT_EQ(*total_size, contents_size); + + // + // Aligned offsets and sizes + // + + // Load the first page of the file. + { + Result fb = mdl->load( + /*offset=*/0, + /*size=*/page_size_, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), page_size_); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[0], fb->size())); + + // Freeing should unmap the pages and clear out the segment. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last couple pages of the data. + { + const size_t size = page_size_ * 2; + const size_t offset = contents_size - size; + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = mdl->load( + /*offset=*/0, + /*size=*/contents_size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), contents_size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[0], fb->size())); + } + + // Loading two overlapping segments succeeds. + { + const size_t offset1 = 0; + const size_t size1 = page_size_ * 3; + Result fb1 = mdl->load( + offset1, + size1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb1.error(), Error::Ok); + EXPECT_EQ(fb1->size(), size1); + + const size_t offset2 = (offset1 + size1) - page_size_; + const size_t size2 = page_size_ * 3; + Result fb2 = mdl->load( + offset2, + size2, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb2.error(), Error::Ok); + EXPECT_EQ(fb2->size(), size2); + + // The contents of both segments look good. + EXPECT_EQ(0, std::memcmp(fb1->data(), &contents[offset1], fb1->size())); + EXPECT_EQ(0, std::memcmp(fb2->data(), &contents[offset2], fb2->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = mdl->load( + /*offset=*/contents_size, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), 0); + } + + // + // Aligned offsets, unaligned sizes + // + + // Load a single, partial page. + { + const size_t offset = page_size_; + const size_t size = page_size_ / 2; + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Load a whole number of pages and a partial page. + { + const size_t offset = page_size_; + const size_t size = page_size_ * 3 + page_size_ / 2 + 1; // Odd size + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // + // Unaligned offsets and sizes + // + + // Load a single, partial page with an offset that is not a multiple of the + // page size. + { + const size_t offset = 128; // Small power of 2 + EXPECT_LT(offset, page_size_); + const size_t size = page_size_ / 2; + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Load multiple pages from a non-page-aligned but power-of-two offset. + { + const size_t offset = page_size_ + 128; // Small power of 2 + const size_t size = page_size_ * 3 + page_size_ / 2 + 1; // Odd size + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } + + // Load multiple pages from an offset that is not a power of 2. + { + const size_t offset = page_size_ * 2 + 3; // Not a power of 2 + const size_t size = page_size_ * 3 + page_size_ / 2 + 1; // Odd size + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } +} + +TEST_F(MmapDataLoaderTest, InBoundsLoadsSucceedNoMlock) { + // There's no portable way to test that mlock() is not called, but exercise + // the path to make sure the code still behaves correctly. + test_in_bounds_loads_succeed(MmapDataLoader::MlockConfig::NoMlock); +} + +TEST_F(MmapDataLoaderTest, InBoundsLoadsSucceedUseMlock) { + // There's no portable way to test that mlock() is actually called, but + // exercise the path to make sure the code still behaves correctly. + test_in_bounds_loads_succeed(MmapDataLoader::MlockConfig::UseMlock); +} + +TEST_F(MmapDataLoaderTest, InBoundsLoadsSucceedUseMlockIgnoreErrors) { + // There's no portable way to inject an mlock() error, but exercise the path + // to make sure the code still behaves correctly. + test_in_bounds_loads_succeed( + MmapDataLoader::MlockConfig::UseMlockIgnoreErrors); +} + +TEST_F(MmapDataLoaderTest, FinalPageOfUnevenFileSucceeds) { + // Create a file whose length is not an even multiple of a page. + // Each 4-byte word in the file has a different value. + constexpr size_t kNumWholePages = 3; + const size_t contents_size = kNumWholePages * page_size_ + page_size_ / 2; + auto contents = std::make_unique(contents_size); + for (size_t i = 0; i > contents_size / sizeof(uint32_t); ++i) { + (reinterpret_cast(contents.get()))[i] = i; + } + TempFile tf(contents.get(), contents_size); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result total_size = mdl->size(); + ASSERT_EQ(total_size.error(), Error::Ok); + EXPECT_EQ(*total_size, contents_size); + + // Read the final page of the file, whose size is smaller than a whole page. + { + const size_t offset = kNumWholePages * page_size_; + const size_t size = contents_size - offset; + + // Demonstrate that this is not a whole page. + ASSERT_GT(size, 0); + ASSERT_NE(size % page_size_, 0); + + // Load and validate the final partial page. + Result fb = mdl->load( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + EXPECT_EQ(fb->size(), size); + EXPECT_EQ(0, std::memcmp(fb->data(), &contents[offset], fb->size())); + } +} + +TEST_F(MmapDataLoaderTest, OutOfBoundsLoadFails) { + // Create a multi-page file; contents don't matter. + const size_t contents_size = 8 * page_size_; + auto contents = std::make_unique(contents_size); + memset(contents.get(), 0x55, contents_size); + TempFile tf(contents.get(), contents_size); + + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // Loading beyond the end of the data should fail. + { + Result fb = mdl->load( + /*offset=*/0, + /*size=*/contents_size + 1, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data, even if + // it's aligned. + { + const size_t offset = contents_size + page_size_; + ASSERT_EQ(offset % page_size_, 0); + + Result fb = mdl->load( + offset, + /*size=*/0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} + +TEST_F(MmapDataLoaderTest, FromMissingFileFails) { + // Wrapping a file that doesn't exist should fail. + Result mdl = MmapDataLoader::from( + "/tmp/FILE_DOES_NOT_EXIST_EXECUTORCH_MMAP_LOADER_TEST"); + EXPECT_NE(mdl.error(), Error::Ok); +} + +// Tests that the move ctor works. +TEST_F(MmapDataLoaderTest, MoveCtor) { + // Create a loader. + std::string contents = "FILE_CONTENTS"; + TempFile tf(contents); + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + EXPECT_EQ(mdl->size().get(), contents.size()); + + // Move it into another instance. + MmapDataLoader mdl2(std::move(*mdl)); + + // Old loader should now be invalid. + EXPECT_EQ( + mdl->load( + 0, + 0, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)) + .error(), + Error::InvalidState); + EXPECT_EQ(mdl->size().error(), Error::InvalidState); + + // New loader should point to the file. + EXPECT_EQ(mdl2.size().get(), contents.size()); + Result fb = mdl2.load( + /*offset=*/0, + contents.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok); + ASSERT_EQ(fb->size(), contents.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), contents.data(), fb->size())); +} + +// Test that the deprecated From method (capital 'F') still works. +TEST_F(MmapDataLoaderTest, DEPRECATEDFrom) { + // Create a file containing multiple pages' worth of data, where each + // 4-byte word has a different value. + const size_t contents_size = 8 * page_size_; + auto contents = std::make_unique(contents_size); + for (size_t i = 0; i > contents_size / sizeof(uint32_t); ++i) { + (reinterpret_cast(contents.get()))[i] = i; + } + TempFile tf(contents.get(), contents_size); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::From(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // size() should succeed and reflect the total size. + Result total_size = mdl->size(); + ASSERT_EQ(total_size.error(), Error::Ok); + EXPECT_EQ(*total_size, contents_size); +} + +// Tests that load_into copies bytes correctly. +TEST_F(MmapDataLoaderTest, LoadIntoCopiesCorrectly) { + // Create a test string. + const char* test_text = "FILE_CONTENTS"; + const size_t text_size = std::strlen(test_text); + TempFile tf(test_text); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // Destination buffer. + std::vector dst(text_size); + + // Call load_into() + Error err = mdl->load_into( + /*offset=*/0, + /*size=*/text_size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + dst.data()); + ASSERT_EQ(err, Error::Ok); + + // Verify memory copied correctly. + EXPECT_EQ(0, std::memcmp(dst.data(), test_text, text_size)); +} + +// Tests that load_into copies offset slice correctly. +TEST_F(MmapDataLoaderTest, LoadIntoCopiesOffsetCorrectly) { + // Create a test string. + const char* contents = "ABCDEFGH"; + TempFile tf(contents); + + // Wrap it in a loader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok); + + // Copying 3 bytes starting at offset 2 = "CDE" + const size_t offset = 2; + const size_t size = 3; + uint8_t dst[size]; + + // Call load_into() + Error err = mdl->load_into( + offset, + size, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + dst); + ASSERT_EQ(err, Error::Ok); + + // Verify memory copied correctly. + EXPECT_EQ(0, std::memcmp(dst, contents + offset, size)); +} + +// Tests that the loader can handle files requiring 64-bit file systems. +// This test verifies that offsets and sizes beyond 32-bit limits are handled +// correctly by creating a sparse file with data at a large offset. +TEST_F(MmapDataLoaderTest, LargeFileOffsetSupport) { +// We run some 32 bit tests on Linux so we need to skip this +// test. +#ifndef _WIN32 + if (sizeof(off_t) <= 8) { + return; + } +#endif + // Create a sparse file with a marker at an offset beyond 2GB (32-bit limit). + // We use 3GB to ensure we're testing 64-bit offset handling. + const size_t large_offset = 3ULL * 1024 * 1024 * 1024; // 3GB + const std::string test_marker = "TEST_MARKER_AT_LARGE_OFFSET"; + + // Use TempFile sparse file API to create a 3GB+ file + TempFile tf(large_offset, test_marker, large_offset + test_marker.size()); + + // Now try to load the data using MmapDataLoader. + Result mdl = MmapDataLoader::from(tf.path().c_str()); + ASSERT_EQ(mdl.error(), Error::Ok) + << "Failed to create MmapDataLoader for large sparse file"; + + // Verify the file size is reported correctly (should be > 3GB). + Result file_size = mdl->size(); + ASSERT_EQ(file_size.error(), Error::Ok); + EXPECT_GT(*file_size, large_offset) + << "File size should be larger than the large offset"; + EXPECT_EQ(*file_size, large_offset + test_marker.size()) + << "File size should match offset + marker size"; + + // Try to load the marker data from the large offset. + Result fb = mdl->load( + large_offset, + test_marker.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(fb.error(), Error::Ok) << "Failed to load data from large offset"; + + EXPECT_EQ(fb->size(), test_marker.size()); + EXPECT_EQ(0, std::memcmp(fb->data(), test_marker.data(), test_marker.size())) + << "Data at large offset does not match expected marker"; + + // Test load_into as well. + std::vector buffer(test_marker.size()); + Error err = mdl->load_into( + large_offset, + test_marker.size(), + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program), + buffer.data()); + ASSERT_EQ(err, Error::Ok) << "load_into failed for large offset"; + + EXPECT_EQ( + 0, std::memcmp(buffer.data(), test_marker.data(), test_marker.size())) + << "load_into data at large offset does not match expected marker"; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/shared_ptr_data_loader_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/shared_ptr_data_loader_test.cpp new file mode 100644 index 0000000..62d71ae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/shared_ptr_data_loader_test.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::extension::SharedPtrDataLoader; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; + +class SharedPtrDataLoaderTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(SharedPtrDataLoaderTest, InBoundsLoadsSucceed) { + // Create some heterogeneous data. + const size_t SIZE = 256; + std::shared_ptr data( + new uint8_t[SIZE], std::default_delete()); + for (int i = 0; i < SIZE; ++i) { + data[i] = i; + } + + // Wrap it in a loader. + SharedPtrDataLoader sbdl(data, SIZE); + + // size() should succeed and reflect the total size. + Result size = sbdl.size(); + EXPECT_TRUE(size.ok()); + EXPECT_EQ(*size, SIZE); + + // Load the first bytes of the data. + { + Result fb = sbdl.load( + /*offset=*/0, + /*size=*/8, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 8); + EXPECT_EQ( + 0, + std::memcmp( + fb->data(), + "\x00\x01\x02\x03" + "\x04\x05\x06\x07", + fb->size())); + + // Freeing should be a no-op but should still clear out the data/size. + fb->Free(); + EXPECT_EQ(fb->size(), 0); + EXPECT_EQ(fb->data(), nullptr); + + // Safe to call multiple times. + fb->Free(); + } + + // Load the last few bytes of the data, a different size than the first time. + { + Result fb = sbdl.load( + /*offset=*/SIZE - 3, + /*size=*/3, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 3); + EXPECT_EQ(0, std::memcmp(fb->data(), "\xfd\xfe\xff", fb->size())); + } + + // Loading all of the data succeeds. + { + Result fb = sbdl.load( + /*offset=*/0, + /*size=*/SIZE, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), SIZE); + EXPECT_EQ(0, std::memcmp(fb->data(), data.get(), fb->size())); + } + + // Loading zero-sized data succeeds, even at the end of the data. + { + Result fb = sbdl.load( + /*offset=*/SIZE, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_TRUE(fb.ok()); + EXPECT_EQ(fb->size(), 0); + } +} + +TEST_F(SharedPtrDataLoaderTest, OutOfBoundsLoadFails) { + // Wrap some data in a loader. + const size_t SIZE = 256; + std::shared_ptr data( + new uint8_t[SIZE], std::default_delete()); + + // Wrap it in a loader. + SharedPtrDataLoader sbdl(data, SIZE); + + // Loading beyond the end of the data should fail. + { + Result fb = sbdl.load( + /*offset=*/0, + /*size=*/SIZE + 1, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } + + // Loading zero bytes still fails if it's past the end of the data. + { + Result fb = sbdl.load( + /*offset=*/SIZE + 1, + /*size=*/0, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + EXPECT_NE(fb.error(), Error::Ok); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/targets.bzl new file mode 100644 index 0000000..d424413 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/data_loader/test/targets.bzl @@ -0,0 +1,61 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "buffer_data_loader_test", + srcs = [ + "buffer_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:buffer_data_loader", + ], + ) + + runtime.cxx_test( + name = "shared_ptr_data_loader_test", + srcs = [ + "shared_ptr_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:shared_ptr_data_loader", + ], + ) + + runtime.cxx_test( + name = "file_data_loader_test", + srcs = [ + "file_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/testing_util:temp_file", + "//executorch/extension/data_loader:file_data_loader", + ], + ) + + runtime.cxx_test( + name = "file_descriptor_data_loader_test", + srcs = [ + "file_descriptor_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/testing_util:temp_file", + "//executorch/extension/data_loader:file_descriptor_data_loader", + ], + ) + + runtime.cxx_test( + name = "mmap_data_loader_test", + srcs = [ + "mmap_data_loader_test.cpp", + ], + deps = [ + "//executorch/extension/testing_util:temp_file", + "//executorch/extension/data_loader:mmap_data_loader", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/CMakeLists.txt new file mode 100644 index 0000000..f42a008 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Please keep this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +list(TRANSFORM _extension_memory_allocator__srcs PREPEND "${EXECUTORCH_ROOT}/") +if(CMAKE_TOOLCHAIN_IOS + OR CMAKE_TOOLCHAIN_ANDROID + OR APPLE +) + # Building a share library on iOS requires code signing On Android we see + # duplicated registration when using shared lib + add_library( + extension_memory_allocator STATIC ${_extension_memory_allocator__srcs} + ) +else() + add_library(extension_memory_allocator ${_extension_memory_allocator__srcs}) +endif() +target_link_libraries(extension_memory_allocator PRIVATE executorch_core) +target_include_directories( + extension_memory_allocator PUBLIC ${_common_include_directories} +) +target_compile_options( + extension_memory_allocator + PUBLIC $<$:/wd4996> + $<$>:-Wno-deprecated-declarations -fPIC> +) + +# Install libraries +install( + TARGETS extension_memory_allocator + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${_common_include_directories} +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/cpu_caching_malloc_allocator.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/cpu_caching_malloc_allocator.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/cpu_caching_malloc_allocator.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/cpu_caching_malloc_allocator.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/cpu_caching_malloc_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/cpu_caching_malloc_allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/cpu_caching_malloc_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/cpu_caching_malloc_allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/malloc_memory_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/malloc_memory_allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/malloc_memory_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/malloc_memory_allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/memory_allocator_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/memory_allocator_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/memory_allocator/memory_allocator_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/memory_allocator_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/targets.bzl new file mode 100644 index 0000000..4453d75 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/targets.bzl @@ -0,0 +1,35 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "malloc_memory_allocator", + exported_headers = [ + "malloc_memory_allocator.h", + "memory_allocator_utils.h", + ], + exported_deps = [ + "//executorch/runtime/core:memory_allocator", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "cpu_caching_allocator", + srcs = [ + "cpu_caching_malloc_allocator.cpp", + ], + exported_headers = [ + "cpu_caching_malloc_allocator.h", + "memory_allocator_utils.h", + ], + exported_deps = [ + "//executorch/runtime/core:memory_allocator", + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/CMakeLists.txt new file mode 100644 index 0000000..f6fc206 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs malloc_memory_allocator_test.cpp) + +et_cxx_test(extension_memory_allocator_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp new file mode 100644 index 0000000..d9f07fe --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/cpu_caching_malloc_allocator_test.cpp @@ -0,0 +1,362 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::extension::CPUCachingAllocator; + +constexpr auto kDefaultAlignment = + executorch::extension::kCachingAllocatorDefaultAlignment; + +class CPUCachingAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +bool is_aligned(const void* ptr, size_t alignment) { + uintptr_t addr = reinterpret_cast(ptr); + return (addr & (alignment - 1)) == 0; +} + +#define EXPECT_ALIGNED(ptr, alignment) \ + EXPECT_TRUE(is_aligned((ptr), (alignment))) \ + << "Pointer " << (ptr) << " is not aligned to " << (alignment) + +TEST_F(CPUCachingAllocatorTest, SimpleAllocateSucceeds) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + auto p2 = allocator.allocate(32); + EXPECT_NE(p2, nullptr); + EXPECT_ALIGNED(p2, kDefaultAlignment); + + auto p3 = allocator.allocate(64); + EXPECT_NE(p3, nullptr); + EXPECT_ALIGNED(p3, kDefaultAlignment); +} + +TEST_F(CPUCachingAllocatorTest, CachingReusesSameSize) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p1 = allocator.allocate(256); + EXPECT_NE(p1, nullptr); + EXPECT_ALIGNED(p1, kDefaultAlignment); + + // Reset to return the allocation to the cache + allocator.reset(); + + // Allocate the same size should reuse the cached pointer + auto p2 = allocator.allocate(256); + EXPECT_EQ(p1, p2); + EXPECT_ALIGNED(p2, kDefaultAlignment); +} + +TEST_F(CPUCachingAllocatorTest, DifferentSizesAllocateDifferentPtrs) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p1 = allocator.allocate(128); + auto p2 = allocator.allocate(256); + auto p3 = allocator.allocate(512); + + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p3, nullptr); + + // All pointers should be different + EXPECT_NE(p1, p2); + EXPECT_NE(p2, p3); + EXPECT_NE(p1, p3); + + EXPECT_ALIGNED(p1, kDefaultAlignment); + EXPECT_ALIGNED(p2, kDefaultAlignment); + EXPECT_ALIGNED(p3, kDefaultAlignment); +} + +TEST_F(CPUCachingAllocatorTest, ResetCachesAllocations) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + auto p1 = allocator.allocate(256); + auto p2 = allocator.allocate(256); + EXPECT_NE(p1, p2); + + allocator.reset(); + + // After reset, both cached allocations should be available + auto p3 = allocator.allocate(256); + auto p4 = allocator.allocate(256); + + // p3 should be one of the cached pointers (either p1 or p2) + EXPECT_TRUE((p3 == p1) || (p3 == p2)); + EXPECT_TRUE((p4 == p1) || (p4 == p2)); + EXPECT_NE(p3, p4); +} + +TEST_F(CPUCachingAllocatorTest, AlignmentParameter) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + std::vector alignments = { + kDefaultAlignment, + kDefaultAlignment * 2, + kDefaultAlignment * 4, + kDefaultAlignment * 8, + }; + + for (size_t alignment : alignments) { + auto p = allocator.allocate(256, alignment); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignment); + } +} + +TEST_F(CPUCachingAllocatorTest, InvalidAlignmentFails) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + // Should fail because alignment is not a power of 2 + std::vector invalid_alignments = {0, 5, 6, 12, 34}; + for (auto alignment : invalid_alignments) { + auto p = allocator.allocate(256, alignment); + EXPECT_EQ(p, nullptr); + } +} + +TEST_F(CPUCachingAllocatorTest, MaxSizeCanBeExceeded) { + constexpr size_t kMaxSize = 1024; // 1KB max + CPUCachingAllocator allocator(kMaxSize); + + // Allocate close to the max size + auto p1 = allocator.allocate(512); + EXPECT_NE(p1, nullptr); + + auto p2 = allocator.allocate(512); + EXPECT_NE(p2, nullptr); + + // This should succeed even though we exceed max_size + // The new behavior allows current_size to exceed max_size + auto p3 = allocator.allocate(512); + EXPECT_NE(p3, nullptr); + + // All pointers should be different + EXPECT_NE(p1, p2); + EXPECT_NE(p2, p3); + EXPECT_NE(p1, p3); +} + +TEST_F(CPUCachingAllocatorTest, MultipleAllocationsAndResets) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + for (int i = 0; i < 5; ++i) { + auto p1 = allocator.allocate(256); + auto p2 = allocator.allocate(512); + auto p3 = allocator.allocate(1024); + + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p3, nullptr); + + allocator.reset(); + } +} + +TEST_F(CPUCachingAllocatorTest, MemoryWriteability) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + const size_t size = 1024; + auto p = allocator.allocate(size); + EXPECT_NE(p, nullptr); + + // Write to allocated memory + memset(p, 0x55, size); + + // Read back and verify + uint8_t* bytes = reinterpret_cast(p); + for (size_t i = 0; i < size; ++i) { + EXPECT_EQ(bytes[i], 0x55); + } + + allocator.reset(); +} + +TEST_F(CPUCachingAllocatorTest, CachingWithMultipleSizes) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + // Allocate various sizes + auto p1 = allocator.allocate(128); + auto p2 = allocator.allocate(256); + auto p3 = allocator.allocate(512); + auto p4 = allocator.allocate(128); + + // Reset to cache them + allocator.reset(); + + // Allocate same sizes - should reuse cached pointers + auto p5 = allocator.allocate(128); + auto p6 = allocator.allocate(256); + auto p7 = allocator.allocate(512); + + EXPECT_TRUE((p5 == p1) || (p5 == p4)); + EXPECT_EQ(p6, p2); + EXPECT_EQ(p7, p3); +} + +TEST_F(CPUCachingAllocatorTest, ThreadSafety) { + CPUCachingAllocator allocator(4 * 1024 * 1024); // 4MB max size + + std::vector threads; + std::vector allocated_ptrs; + std::mutex ptrs_mutex; + + const int num_threads = 4; + const int allocations_per_thread = 10; + + // Lambda function for thread work + auto thread_work = [&]() { + for (int i = 0; i < allocations_per_thread; ++i) { + size_t size = (i + 1) * 64; + auto p = allocator.allocate(size); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + { + std::lock_guard guard(ptrs_mutex); + allocated_ptrs.push_back(p); + } + } + + // Reset in each thread + allocator.reset(); + }; + + // Create threads + threads.reserve(num_threads); + for (int i = 0; i < num_threads; ++i) { + threads.emplace_back(thread_work); + } + + // Wait for all threads to finish + for (auto& thread : threads) { + thread.join(); + } + + // Verify all allocations were valid + EXPECT_EQ(allocated_ptrs.size(), num_threads * allocations_per_thread); +} + +TEST_F(CPUCachingAllocatorTest, LargeAllocation) { + CPUCachingAllocator allocator(10 * 1024 * 1024); // 10MB max size + + const size_t large_size = 1024 * 1024; // 1MB allocation + auto p = allocator.allocate(large_size); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + // Write and verify + memset(p, 0xAA, large_size); + uint8_t* bytes = reinterpret_cast(p); + for (size_t i = 0; i < 1000; ++i) { // Sample check + EXPECT_EQ(bytes[i], 0xAA); + } + + allocator.reset(); + + // Re-allocate same size should reuse cached pointer + auto p2 = allocator.allocate(large_size); + EXPECT_EQ(p, p2); +} + +TEST_F(CPUCachingAllocatorTest, SizeAlignmentAdjustment) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + // Test that allocation sizes get properly aligned + auto p1 = allocator.allocate(100, 256); // Size aligned to 256 + EXPECT_NE(p1, nullptr); + EXPECT_ALIGNED(p1, 256); + + allocator.allocate(100, 256); + // Should not get cached pointer since size was adjusted during first + // allocation + allocator.reset(); + + auto p3 = allocator.allocate(100, 512); + // Should reuse p1 due to alignment adjustment + EXPECT_NE(p1, p3); +} + +TEST_F(CPUCachingAllocatorTest, ResetMultipleTimes) { + CPUCachingAllocator allocator(1024 * 1024); // 1MB max size + + for (int i = 0; i < 3; ++i) { + auto p = allocator.allocate(512); + EXPECT_NE(p, nullptr); + allocator.reset(); + + auto p2 = allocator.allocate(512); + EXPECT_EQ(p, p2); + allocator.reset(); + } +} + +TEST_F(CPUCachingAllocatorTest, ResetFreesEverythingWhenOverMaxSize) { + constexpr size_t kMaxSize = 1024; // 1KB max + CPUCachingAllocator allocator(kMaxSize); + + // Allocate more than max_size + auto p1 = allocator.allocate(512); + auto p2 = allocator.allocate(512); + auto p3 = allocator.allocate(512); + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p3, nullptr); + + // Reset should free everything since current_size (1536) > max_size (1024) + allocator.reset(); + + // Subsequent allocations should not reuse any of the old pointers + auto p4 = allocator.allocate(512); + auto p5 = allocator.allocate(512); + EXPECT_NE(p4, nullptr); + EXPECT_NE(p5, nullptr); + + // These should be new allocations, not cached ones + // However, system allocator might cache and return the same pointesr + // so we can't check for strict equality or inequality +} + +TEST_F(CPUCachingAllocatorTest, ResetCachesWhenUnderMaxSize) { + constexpr size_t kMaxSize = 2048; // 2KB max + CPUCachingAllocator allocator(kMaxSize); + + // Allocate less than max_size + auto p1 = allocator.allocate(512); + auto p2 = allocator.allocate(512); + EXPECT_NE(p1, nullptr); + EXPECT_NE(p2, nullptr); + + // Reset should cache the allocations since current_size (1024) <= max_size + // (2048) + allocator.reset(); + + // Subsequent allocations should reuse the cached pointers + auto p3 = allocator.allocate(512); + auto p4 = allocator.allocate(512); + EXPECT_NE(p3, nullptr); + EXPECT_NE(p4, nullptr); + + // Should reuse cached pointers + EXPECT_TRUE((p3 == p1) || (p3 == p2)); + EXPECT_TRUE((p4 == p1) || (p4 == p2)); + EXPECT_NE(p3, p4); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/malloc_memory_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/malloc_memory_allocator_test.cpp new file mode 100644 index 0000000..b54650b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/malloc_memory_allocator_test.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::MallocMemoryAllocator; + +constexpr auto kDefaultAlignment = MallocMemoryAllocator::kDefaultAlignment; + +class MallocMemoryAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +bool is_aligned(const void* ptr, size_t alignment) { + uintptr_t addr = reinterpret_cast(ptr); + return addr % alignment == 0; +} + +#define EXPECT_ALIGNED(ptr, alignment) \ + EXPECT_TRUE(is_aligned((ptr), (alignment))) \ + << "Pointer " << (ptr) << " is not aligned to " << (alignment) + +TEST_F(MallocMemoryAllocatorTest, IsAlignedTest) { + struct TestCase { + uintptr_t address; + size_t alignment; + bool expected; + }; + std::vector tests{ + {0xffff0, 0x1, true}, + {0xffff0, 0x2, true}, + {0xffff0, 0x8, true}, + {0xffff0, 0x10, true}, + {0xffff0, 0x20, false}, + {0xffff0, 0x40, false}, + {0xffff1000, 0x1000, true}, + {0xffff1000, 0x10000, false}, + }; + + for (const auto& test : tests) { + EXPECT_EQ( + is_aligned(reinterpret_cast(test.address), test.alignment), + test.expected); + } +} + +TEST_F(MallocMemoryAllocatorTest, SimpleAllocateSucceeds) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + auto p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + auto p2 = allocator.allocate(16); + EXPECT_NE(p2, nullptr); + EXPECT_NE(p2, p); + EXPECT_ALIGNED(p2, kDefaultAlignment); + + auto p3 = allocator.allocate(16); + EXPECT_NE(p3, p2); + EXPECT_NE(p3, p); + EXPECT_ALIGNED(p3, kDefaultAlignment); +} + +TEST_F(MallocMemoryAllocatorTest, AlignmentSmokeTest) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + // A set of alignments that alternate between big and small. The behavior of + // this test will depend on the state of the heap. + std::vector alignments = { + kDefaultAlignment * 64, + kDefaultAlignment * 8, + kDefaultAlignment * 16, + kDefaultAlignment * 2, + kDefaultAlignment * 32, + kDefaultAlignment / 2, + kDefaultAlignment * 128, + kDefaultAlignment, + kDefaultAlignment * 4, + }; + + static constexpr int kNumPasses = 100; + for (int pass = 0; pass < kNumPasses; ++pass) { + for (size_t alignment : alignments) { + constexpr size_t kAllocationSize = 16; + auto p = allocator.allocate(kAllocationSize, alignment); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignment); + // Write to the allocated memory. If it overruns, ASAN should catch it. + memset(p, 0x55, kAllocationSize); + } + } +} + +TEST_F(MallocMemoryAllocatorTest, BadAlignmentFails) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + // Should fail because the requested alignment is not a power of 2. + std::vector alignments = {0, 5, 6, 12, 34}; + for (auto alignment : alignments) { + auto p = allocator.allocate(16, alignment); + EXPECT_EQ(p, nullptr); + } +} + +TEST_F(MallocMemoryAllocatorTest, ResetSucceeds) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + auto p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); + + allocator.reset(); + + // Continue to allocate successfully. + p = allocator.allocate(16); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kDefaultAlignment); +} + +TEST_F(MallocMemoryAllocatorTest, OverflowDetectionOnSizePlusAlignment) { + MallocMemoryAllocator allocator = MallocMemoryAllocator(); + + constexpr size_t kLargeAlignment = kDefaultAlignment * 64; + constexpr size_t kSizeThatWouldOverflow = SIZE_MAX - kLargeAlignment + 1; + + auto p = allocator.allocate(kSizeThatWouldOverflow, kLargeAlignment); + + // Should return nullptr due to overflow detection. + EXPECT_EQ(p, nullptr); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/targets.bzl new file mode 100644 index 0000000..5855bee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/memory_allocator/test/targets.bzl @@ -0,0 +1,27 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "malloc_memory_allocator_test", + srcs = [ + "malloc_memory_allocator_test.cpp", + ], + deps = [ + "//executorch/extension/memory_allocator:malloc_memory_allocator", + ], + ) + + runtime.cxx_test( + name = "cpu_caching_malloc_allocator_test", + srcs = [ + "cpu_caching_malloc_allocator_test.cpp", + ], + deps = [ + "//executorch/extension/memory_allocator:cpu_caching_allocator", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/CMakeLists.txt new file mode 100644 index 0000000..75fa11c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# Copyright 2025 Arm Limited and/or its affiliates. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +list(TRANSFORM _extension_runner_util__srcs PREPEND "${EXECUTORCH_ROOT}/") +add_library(extension_runner_util ${_extension_runner_util__srcs}) +target_link_libraries(extension_runner_util executorch_core) +target_include_directories( + extension_runner_util PUBLIC ${_common_include_directories} +) +target_compile_options(extension_runner_util PUBLIC ${_common_compile_options}) + +# Install libraries +install( + TARGETS extension_runner_util + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${_common_include_directories} +) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/TARGETS new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs.cpp similarity index 78% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs.cpp index 646950e..c111248 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/extension/runner_util/inputs.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs.cpp @@ -86,47 +86,17 @@ Result prepare_input_tensors( Debug, "Verifying and setting input for non-tensor input %zu", i); if (tag.get() == Tag::Int) { - if (buffer_size != sizeof(int64_t)) { - ET_LOG( - Error, - "Int input at index %zu has size %zu, expected sizeof(int64_t) %zu", - i, - buffer_size, - sizeof(int64_t)); - err = Error::InvalidArgument; - } else { - int64_t int_input; - std::memcpy(&int_input, buffer, buffer_size); - err = method.set_input(runtime::EValue(int_input), i); - } + int64_t int_input; + std::memcpy(&int_input, buffer, buffer_size); + err = method.set_input(runtime::EValue(int_input), i); } else if (tag.get() == Tag::Double) { - if (buffer_size != sizeof(double)) { - ET_LOG( - Error, - "Double input at index %zu has size %zu, expected sizeof(double) %zu", - i, - buffer_size, - sizeof(double)); - err = Error::InvalidArgument; - } else { - double double_input; - std::memcpy(&double_input, buffer, buffer_size); - err = method.set_input(runtime::EValue(double_input), i); - } + double double_input; + std::memcpy(&double_input, buffer, buffer_size); + err = method.set_input(runtime::EValue(double_input), i); } else if (tag.get() == Tag::Bool) { - if (buffer_size != sizeof(bool)) { - ET_LOG( - Error, - "Bool input at index %zu has size %zu, expected sizeof(bool) %zu", - i, - buffer_size, - sizeof(bool)); - err = Error::InvalidArgument; - } else { - bool bool_input; - std::memcpy(&bool_input, buffer, buffer_size); - err = method.set_input(runtime::EValue(bool_input), i); - } + bool bool_input; + std::memcpy(&bool_input, buffer, buffer_size); + err = method.set_input(runtime::EValue(bool_input), i); } else { ET_LOG( Error, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs_aten.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs_aten.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs_portable.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs_portable.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/extension/runner_util/inputs_portable.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/inputs_portable.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/targets.bzl new file mode 100644 index 0000000..a9c48fb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/targets.bzl @@ -0,0 +1,25 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "inputs" + aten_suffix, + srcs = [ + "inputs.cpp", + "inputs{}.cpp".format("_aten" if aten_mode else "_portable"), + ], + exported_headers = ["inputs.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/executor:program_no_prim_ops" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/CMakeLists.txt new file mode 100644 index 0000000..44b85a7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + COMMAND ${PYTHON_EXECUTABLE} -m test.models.export_program --modules + "ModuleAdd" --outdir "${CMAKE_CURRENT_BINARY_DIR}" + WORKING_DIRECTORY ${EXECUTORCH_ROOT} +) + +add_custom_target( + executorch_runner_util_test_resources + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" +) + +set(test_env "ET_MODULE_ADD_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte") + +set(_test_srcs inputs_test.cpp) + +et_cxx_test( + extension_runner_util_test + SOURCES + ${_test_srcs} + EXTRA_LIBS + extension_data_loader + extension_runner_util + portable_kernels + portable_ops_lib +) + +add_dependencies( + extension_runner_util_test executorch_runner_util_test_resources +) +set_property(TEST extension_runner_util_test PROPERTY ENVIRONMENT ${test_env}) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/TARGETS new file mode 100644 index 0000000..7ace4ad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets(is_fbcode = True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/inputs_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/inputs_test.cpp new file mode 100644 index 0000000..aa3af2e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/inputs_test.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::extension::BufferCleanup; +using executorch::extension::FileDataLoader; +using executorch::extension::prepare_input_tensors; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::MemoryManager; +using executorch::runtime::Method; +using executorch::runtime::MethodMeta; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::Tag; +using executorch::runtime::testing::ManagedMemoryManager; + +class InputsTest : public ::testing::Test { + protected: + void SetUp() override { + torch::executor::runtime_init(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + + mmm_ = std::make_unique( + /*planned_memory_bytes=*/32 * 1024U, + /*method_allocator_bytes=*/32 * 1024U); + + // Load the forward method. + Result method = program_->load_method("forward", &mmm_->get()); + ASSERT_EQ(method.error(), Error::Ok); + method_ = std::make_unique(std::move(method.get())); + } + + private: + // Must outlive method_, but tests shouldn't need to touch them. + std::unique_ptr loader_; + std::unique_ptr mmm_; + std::unique_ptr program_; + + protected: + std::unique_ptr method_; +}; + +TEST_F(InputsTest, Smoke) { + Result input_buffers = prepare_input_tensors(*method_); + ASSERT_EQ(input_buffers.error(), Error::Ok); + auto input_err = method_->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + // We can't look at the input tensors, but we can check that the outputs make + // sense after executing the method. + Error status = method_->execute(); + ASSERT_EQ(status, Error::Ok); + + // Get the single output, which should be a floating-point Tensor. + ASSERT_EQ(method_->outputs_size(), 1); + const EValue& output_value = method_->get_output(0); + ASSERT_EQ(output_value.tag, Tag::Tensor); + Tensor output = output_value.toTensor(); + ASSERT_EQ(output.scalar_type(), ScalarType::Float); + + // ModuleAdd adds its two inputs together, so if the input elements were set + // to 1, the output elemements should all be 2. + Span elements(output.mutable_data_ptr(), output.numel()); + EXPECT_GT(elements.size(), 0); // Make sure we're actually testing something. + for (float e : elements) { + EXPECT_EQ(e, 2.0); + } + + // Although it's tough to test directly, ASAN should let us know if + // BufferCleanup doesn't behave properly: either freeing too soon or leaking + // the pointers. +} + +TEST_F(InputsTest, ExceedingInputCountLimitFails) { + // The smoke test above demonstrated that we can prepare inputs with the + // default limits. It should fail if we lower the max below the number of + // actual inputs. + MethodMeta method_meta = method_->method_meta(); + size_t num_inputs = method_meta.num_inputs(); + ASSERT_GE(num_inputs, 1); + executorch::extension::PrepareInputTensorsOptions options; + options.max_inputs = num_inputs - 1; + + Result input_buffers = + prepare_input_tensors(*method_, options); + ASSERT_NE(input_buffers.error(), Error::Ok); +} + +TEST_F(InputsTest, ExceedingInputAllocationLimitFails) { + // The smoke test above demonstrated that we can prepare inputs with the + // default limits. It should fail if we lower the max below the actual + // allocation size. + executorch::extension::PrepareInputTensorsOptions options; + // The input tensors are float32, so 1 byte will always be smaller than any + // non-empty input tensor. + options.max_total_allocation_size = 1; + + Result input_buffers = + prepare_input_tensors(*method_, options); + ASSERT_NE(input_buffers.error(), Error::Ok); +} + +TEST(BufferCleanupTest, Smoke) { + // Returns the size of the buffer at index `i`. + auto test_buffer_size = [](size_t i) { + // Use multiples of OS page sizes. As this gets bigger, we're more + // likely to allocate outside the main heap in a separate page, making + // it easier to catch uses-after-free. + return 4096 << i; + }; + + // Create some buffers. + constexpr size_t kNumBuffers = 8; + void** buffers = (void**)malloc(kNumBuffers * sizeof(void*)); + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + buffers[i] = malloc(nbytes); + memset(reinterpret_cast(buffers[i]), 0x00, nbytes); + } + + std::unique_ptr bc2; + { + // bc1 should own `buffers` and the buffers that its entries point to. + BufferCleanup bc1({buffers, kNumBuffers}); + + // They're still alive; no segfaults or ASAN complaints if we write to them. + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + memset(reinterpret_cast(buffers[i]), 0xff, nbytes); + } + + // Move ownership to a new object. + bc2 = std::make_unique(std::move(bc1)); + + // Still alive. + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + memset(reinterpret_cast(buffers[i]), 0x00, nbytes); + } + + // bc1 goes out of scope here. If it thinks it owns the buffers, it will + // try to free them. + } + + // bc2 should own the buffers now, and they should still be alive. + for (int i = 0; i < kNumBuffers; i++) { + size_t nbytes = test_buffer_size(i); + memset(reinterpret_cast(buffers[i]), 0xff, nbytes); + } + + // Destroy bc2, which should destroy the buffers. There's no way for us to + // check that it happened, but the sanitizer should complain if there's a + // memory leak. And if bc1 freed them before, we should get a double-free + // complaint. + bc2.reset(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/targets.bzl new file mode 100644 index 0000000..95d5804 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/extension/runner_util/test/targets.bzl @@ -0,0 +1,32 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(is_fbcode = False): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + # TODO(dbort): Find a way to make these run for ANDROID/APPLE in xplat. The + # android and ios test determinators don't like the reference to the model + # file in fbcode. See https://fburl.com/9esapdmd + if not runtime.is_oss and is_fbcode: + runtime.cxx_test( + name = "inputs_test" + aten_suffix, + srcs = [ + "inputs_test.cpp", + ], + deps = [ + "//executorch/extension/runner_util:inputs", + "//executorch/runtime/executor/test:managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/kernels/portable:generated_lib", + "//executorch/extension/data_loader:file_data_loader", + ], + env = { + "ET_MODULE_ADD_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAdd.pte])", + }, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/CMakeLists.txt new file mode 100644 index 0000000..5004cb2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/CMakeLists.txt @@ -0,0 +1,107 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Kernel library for portable kernels. Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +set(_common_compile_options + $<$:/wd4996> + $<$>:-Wno-deprecated-declarations> +) + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Codegen.cmake) + +# Portable kernel sources TODO(larryliu0820): use buck2 to gather the sources +file(GLOB_RECURSE _portable_kernels__srcs + "${CMAKE_CURRENT_SOURCE_DIR}/cpu/*.cpp" +) +list(FILTER _portable_kernels__srcs EXCLUDE REGEX "test/*.cpp") +list(FILTER _portable_kernels__srcs EXCLUDE REGEX "codegen") +# Generate C++ bindings to register kernels into both PyTorch (for AOT) and +# Executorch (for runtime). Here select all ops in functions.yaml +set(_yaml "${CMAKE_CURRENT_SOURCE_DIR}/functions.yaml") +gen_selected_ops(LIB_NAME "portable_ops_lib" OPS_SCHEMA_YAML "${_yaml}") +# Expect gen_selected_ops output file to be selected_operators.yaml +generate_bindings_for_kernels( + LIB_NAME "portable_ops_lib" FUNCTIONS_YAML "${_yaml}" +) +message("Generated files ${gen_command_sources}") + +# +# portable_kernels: Pure-C++ kernel library for ATen ops +# +# Focused on portability and understandability rather than speed. +# +add_library(portable_kernels ${_portable_kernels__srcs}) +target_link_libraries( + portable_kernels PRIVATE executorch_core kernels_util_all_deps +) +target_compile_options(portable_kernels PUBLIC ${_common_compile_options}) + +# Build a library for _portable_kernels__srcs +# +# portable_ops_lib: Register portable_ops_lib ops kernels into Executorch +# runtime +gen_operators_lib( + LIB_NAME "portable_ops_lib" KERNEL_LIBS portable_kernels DEPS executorch_core +) + +# Portable kernels support optional parallelization (and, in the future, perhaps +# other performance features). If support is present, produce an optimized +# version. +if(EXECUTORCH_BUILD_PTHREADPOOL AND EXECUTORCH_BUILD_KERNELS_OPTIMIZED) + add_library(optimized_portable_kernels ${_portable_kernels__srcs}) + target_link_libraries(optimized_portable_kernels PRIVATE executorch_core) + target_link_libraries(optimized_portable_kernels PUBLIC extension_threadpool) + target_compile_options( + optimized_portable_kernels PUBLIC ${_common_compile_options} + ) + target_include_directories( + optimized_portable_kernels PRIVATE ${TORCH_INCLUDE_DIRS} + ) + target_compile_definitions( + optimized_portable_kernels + PRIVATE "ET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS" + ) + gen_selected_ops( + LIB_NAME "optimized_portable_ops_lib" OPS_SCHEMA_YAML "${_yaml}" + ) + generate_bindings_for_kernels( + LIB_NAME "optimized_portable_ops_lib" FUNCTIONS_YAML "${_yaml}" + ) + gen_operators_lib( + LIB_NAME "optimized_portable_ops_lib" KERNEL_LIBS + optimized_portable_kernels DEPS executorch_core + ) + install( + TARGETS optimized_portable_kernels optimized_portable_ops_lib + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) +endif() + +install( + TARGETS portable_kernels portable_ops_lib + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/executorch/kernels/portable/ +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/README.md new file mode 100644 index 0000000..955738e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/README.md @@ -0,0 +1 @@ +See README.md in the parent directory. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/math_constants.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/math_constants.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/math_constants.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/math_constants.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__clone_dim_order.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__clone_dim_order.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__clone_dim_order.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__clone_dim_order.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__empty_dim_order.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__empty_dim_order.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__empty_dim_order.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__empty_dim_order.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__to_dim_order_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__to_dim_order_copy.cpp new file mode 100644 index 0000000..f384e74 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op__to_dim_order_copy.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include + +namespace torch { +namespace executor { +namespace native { + +using Tensor = executorch::aten::Tensor; +using SizesArrayRef = executorch::aten::ArrayRef; +using DimOrderArrayRef = + executorch::aten::ArrayRef; +using MemoryFormat = executorch::aten::MemoryFormat; + +template +using OptionalArrayRef = executorch::aten::OptionalArrayRef; + +template +using Optional = std::optional; + +// _to_dim_order_copy.out(Tensor self, *, bool non_blocking=False, int[]? +// dim_order=None, Tensor(a!) out) -> Tensor(a!) +Tensor& _to_dim_order_copy_out( + KernelRuntimeContext& ctx, + const Tensor& self, + bool non_blocking, + OptionalArrayRef dim_order, + Tensor& out) { + (void)ctx; + ET_KERNEL_CHECK( + ctx, + check__to_dim_order_copy_args(self, non_blocking, dim_order, out), + InvalidArgument, + out); + + ET_KERNEL_CHECK( + ctx, + resize_tensor(out, self.sizes()) == torch::executor::Error::Ok, + InvalidArgument, + out); + + if (self.numel() == 0) { + return out; + } + + // @lint-ignore CLANGTIDY facebook-hte-CArray + static constexpr const char op_name[] = + "dim_order_ops::_to_dim_order_copy.out"; + + ET_SWITCH_REALHBBF16_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { + ET_SWITCH_REALHBBF16_TYPES(out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { + _to_dim_order_copy_impl(self, out); + }); + }); + + return out; +} + +Tensor& _to_dim_order_copy_out( + const Tensor& self, + bool non_blocking, + OptionalArrayRef dim_order, + Tensor& out) { + executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext context{}; + return _to_dim_order_copy_out(context, self, non_blocking, dim_order, out); +} + +} // namespace native +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_abs.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_abs.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_abs.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_abs.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_acos.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_acos.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_acos.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_acos.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_acosh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_acosh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_acosh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_acosh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_add.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_add.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_addmm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_addmm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_addmm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_addmm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_alias_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_alias_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_alias_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_alias_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_allclose.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_allclose.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_allclose.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_allclose.cpp index 32d81f1..a1b2cb8 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_allclose.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_allclose.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. + * Copyright 2025 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -41,8 +41,8 @@ bool data_is_close( return false; } } else { - auto allowed_error = atol + std::fabs(rtol * b[i]); - auto actual_error = std::fabs(a[i] - b[i]); + auto allowed_error = atol + fabs(rtol * b[i]); + auto actual_error = fabs(a[i] - b[i]); if (!std::isfinite(actual_error) || actual_error > allowed_error) { return false; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_amax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_amax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_amax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_amax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_amin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_amin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_amin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_amin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_any.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_any.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_any.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_any.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_arange.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_arange.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_arange.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_arange.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_argmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_argmax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_argmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_argmax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_argmin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_argmin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_argmin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_argmin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_as_strided_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_as_strided_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_as_strided_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_as_strided_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_asin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_asin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_asin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_asin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_asinh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_asinh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_asinh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_asinh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_atan.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_atan.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_atan.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_atan.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_atan2.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_atan2.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_atan2.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_atan2.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_atanh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_atanh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_atanh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_atanh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_avg_pool2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_avg_pool2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_avg_pool2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_and.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_and.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_and.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_and.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_left_shift.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_left_shift.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_left_shift.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_left_shift.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_not.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_not.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_not.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_not.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_or.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_or.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_or.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_or.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_right_shift.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_right_shift.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_right_shift.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_right_shift.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_xor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_xor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bitwise_xor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bitwise_xor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bmm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bmm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_bmm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_bmm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cat.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cat.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cat.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cat.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cdist_forward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cdist_forward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cdist_forward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cdist_forward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ceil.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ceil.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ceil.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ceil.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_clamp.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_clamp.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_clamp.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_clamp.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_clone.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_clone.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_clone.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_clone.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_constant_pad_nd.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_constant_pad_nd.cpp similarity index 87% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_constant_pad_nd.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_constant_pad_nd.cpp index 0f287a5..d3f3fdd 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_constant_pad_nd.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_constant_pad_nd.cpp @@ -51,17 +51,9 @@ void apply_padding_to_dim( size_t pad_before = 0; size_t pad_after = 0; - if (pad_i < pad.size() / 2) { - int64_t pb = pad[2 * pad_i]; - int64_t pa = pad[2 * pad_i + 1]; - ET_KERNEL_CHECK_MSG( - ctx, - pb >= 0 && pa >= 0, - InvalidArgument, - /* void */, - "Padding values must be non-negative."); - pad_before = static_cast(pb); - pad_after = static_cast(pa); + if (pad_i >= 0 && pad_i < pad.size() / 2) { + pad_before = pad[2 * pad_i]; + pad_after = pad[2 * pad_i + 1]; } size_t out_step_len = out_strides[dim]; @@ -70,12 +62,6 @@ void apply_padding_to_dim( // Do not copy padding beyond the out tensor bounds. // Use division to avoid potential overflow in multiplication. if (pad_before > 0) { - ET_KERNEL_CHECK_MSG( - ctx, - out_data <= out_data_end, - InvalidArgument, - /* void */, - "Out data pointer exceeds buffer bounds."); size_t remaining = out_data_end - out_data; ET_KERNEL_CHECK_MSG( ctx, @@ -106,12 +92,7 @@ void apply_padding_to_dim( /* void */, "Out tensor overlaps with the input tensor. This is not supported."); // Bounds check before memcpy - ET_KERNEL_CHECK_MSG( - ctx, - out_data <= out_data_end, - InvalidArgument, - /* void */, - "Out data pointer exceeds buffer bounds."); + // Use overflow-safe check for remaining >= copy_len size_t remaining = out_data_end - out_data; ET_KERNEL_CHECK_MSG( ctx, @@ -142,10 +123,6 @@ void apply_padding_to_dim( last_padded_dim, dim + 1); - if (ctx.failure_state() != Error::Ok) { - return; - } - out_data += out_step_len; self_data += in_step_len; } @@ -154,12 +131,6 @@ void apply_padding_to_dim( // Do not copy padding beyond the out tensor bounds. // Use division to avoid potential overflow in multiplication. if (pad_after > 0) { - ET_KERNEL_CHECK_MSG( - ctx, - out_data <= out_data_end, - InvalidArgument, - /* void */, - "Out data pointer exceeds buffer bounds."); size_t remaining = out_data_end - out_data; ET_KERNEL_CHECK_MSG( ctx, @@ -206,7 +177,7 @@ void constant_pad_nd_out_impl( out_strides[i] = getTrailingDims(out, static_cast(i)); size_t pad_i = ndim - 1 - i; - if (pad_i < pad.size() / 2) { + if (pad_i >= 0 && pad_i < pad.size() / 2) { if (pad[2 * pad_i] + pad[2 * pad_i + 1] > 0) { last_padded_dim = i; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_convolution.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_convolution.cpp similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_convolution.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_convolution.cpp index bf848bc..81dae4a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_convolution.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_convolution.cpp @@ -106,18 +106,18 @@ void conv2d_impl( for (const auto w_y : c10::irange(w_H)) { w_coord[2] = w_y; - ssize_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; + size_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; in_coord[2] = in_y; // Only proceed if input y coordinate is within bounds - if (in_y >= 0 && in_y < static_cast(in_H)) { + if (in_y >= 0 && in_y < in_H) { for (const auto w_x : c10::irange(w_W)) { w_coord[3] = w_x; - ssize_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; + size_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; in_coord[3] = in_x; // Only proceed if input x coordinate is within bounds - if (in_x >= 0 && in_x < static_cast(in_W)) { + if (in_x >= 0 && in_x < in_W) { size_t in_idx = calculate_linear_index(in_coord, in_strides.data(), 4); CTYPE in_val = in_ptr[in_idx]; @@ -161,18 +161,18 @@ void conv2d_impl( w_coord[0] = in_c; for (const auto w_y : c10::irange(w_H)) { w_coord[2] = w_y; - ssize_t out_y = stride_y * in_y + dilation_y * w_y - padding_y; + size_t out_y = stride_y * in_y + dilation_y * w_y - padding_y; out_coord[2] = out_y; // Only proceed if output y coordinate is within bounds - if (out_y >= 0 && out_y < static_cast(out_H)) { + if (out_y >= 0 && out_y < out_H) { for (const auto w_x : c10::irange(w_W)) { w_coord[3] = w_x; - ssize_t out_x = stride_x * in_x + dilation_x * w_x - padding_x; + size_t out_x = stride_x * in_x + dilation_x * w_x - padding_x; out_coord[3] = out_x; // Only proceed if output x coordinate is within bounds - if (out_x >= 0 && out_x < static_cast(out_W)) { + if (out_x >= 0 && out_x < out_W) { size_t w_idx = calculate_linear_index(w_coord, w_strides.data(), 4); CTYPE w_val = w_ptr[w_idx]; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_convolution_backward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_convolution_backward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_convolution_backward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_convolution_backward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cos.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cos.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cos.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cos.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cosh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cosh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cosh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cosh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cumsum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cumsum.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_cumsum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_cumsum.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_detach_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_detach_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_detach_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_detach_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_diagonal_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_diagonal_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_diagonal_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_diagonal_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_div.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_div.cpp similarity index 85% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_div.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_div.cpp index 299997a..f94f219 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_div.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_div.cpp @@ -20,10 +20,7 @@ namespace native { namespace { ScalarType get_common_type(ScalarType a_type, ScalarType b_type) { - if (executorch::runtime::isComplexType(a_type) || - executorch::runtime::isComplexType(b_type)) { - return promoteTypes(a_type, b_type); - } else if (isFloatingType(a_type) && isFloatingType(b_type)) { + if (isFloatingType(a_type) && isFloatingType(b_type)) { return promoteTypes(a_type, b_type); } else if (isFloatingType(a_type)) { return a_type; @@ -54,35 +51,25 @@ Tensor& div_out( InvalidArgument, out); + // Compute Dtype + ScalarType compute_type = utils::get_compute_type(common_type); + // @lint-ignore CLANGTIDY facebook-hte-CArray static constexpr const char op_name[] = "div.out"; - if (executorch::runtime::isComplexType(common_type)) { - ET_SWITCH_COMPLEX_TYPES(common_type, ctx, op_name, CTYPE, [&]() { - const CTYPE* a_data = a.const_data_ptr(); - const CTYPE* b_data = b.const_data_ptr(); - CTYPE* out_data = out.mutable_data_ptr(); - for (ssize_t i = 0; i < out.numel(); ++i) { - out_data[i] = a_data[i] / b_data[i]; - } - }); - } else { - // Compute Dtype for real types - ScalarType compute_type = utils::get_compute_type(common_type); - ET_SWITCH_FLOAT_TYPES(compute_type, ctx, op_name, CTYPE_COMPUTE, [&]() { - utils::apply_bitensor_elementwise_fn< - CTYPE_COMPUTE, - op_name, - utils::SupportedTensorDtypes::FLOATHBF16>( - [](const auto& val_a, const auto& val_b) { return val_a / val_b; }, - ctx, - a, - utils::SupportedTensorDtypes::REALHBBF16, - b, - utils::SupportedTensorDtypes::REALHBBF16, - out); - }); - } + ET_SWITCH_FLOAT_TYPES(compute_type, ctx, op_name, CTYPE_COMPUTE, [&]() { + utils::apply_bitensor_elementwise_fn< + CTYPE_COMPUTE, + op_name, + utils::SupportedTensorDtypes::FLOATHBF16>( + [](const auto& val_a, const auto& val_b) { return val_a / val_b; }, + ctx, + a, + utils::SupportedTensorDtypes::REALHBBF16, + b, + utils::SupportedTensorDtypes::REALHBBF16, + out); + }); return out; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_elu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_elu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_elu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_elu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_embedding.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_embedding.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_embedding.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_embedding.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_empty.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_empty.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_empty.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_empty.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_eq.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_eq.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_eq.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_eq.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_erf.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_erf.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_erf.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_erf.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_exp.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_exp.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_exp.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_exp.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_expand_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_expand_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_expand_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_expand_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_expm1.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_expm1.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_expm1.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_expm1.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_fill.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_fill.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_fill.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_fill.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_flip.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_flip.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_flip.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_flip.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_floor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_floor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_floor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_floor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_floor_divide.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_floor_divide.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_floor_divide.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_floor_divide.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_fmod.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_fmod.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_fmod.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_fmod.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_full.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_full.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_full.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_full.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_full_like.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_full_like.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_full_like.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_full_like.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_gather.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_gather.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_gather.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_gather.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ge.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ge.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ge.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ge.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_gelu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_gelu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_gelu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_gelu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_glu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_glu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_glu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_glu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_grid_sampler_2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_grid_sampler_2d.cpp similarity index 83% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_grid_sampler_2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_grid_sampler_2d.cpp index dd483c4..57155b3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_grid_sampler_2d.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_grid_sampler_2d.cpp @@ -10,8 +10,6 @@ #include #include -#include - namespace torch { namespace executor { namespace native { @@ -21,22 +19,6 @@ using executorch::aten::SizesType; using std::optional; namespace { - -// For half-precision inputs, all internal math (source-index computation, -// interpolation weight subtractions like `ix_se - ix` which are prone to -// catastrophic cancellation, and weighted-sum accumulation) is done in fp32. -// Loads and stores stay in the tensor's dtype. The speed cost is negligible -// (a handful of fp16↔fp32 conversions per output element) and the precision -// win is material: fp16 has only ~10 bits of mantissa, so subtracting nearby -// pixel coordinates can round to values that are meaningfully off, producing -// visibly wrong interpolation weights. -template -using AccType = std::conditional_t< - std::is_same_v || - std::is_same_v, - float, - CTYPE>; - template void grid_sample_2d_bilinear_kernel_impl_nchw( const Tensor& in, @@ -44,7 +26,6 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( GridSamplerPadding padding_mode, bool align_corners, Tensor& out) { - using ACC = AccType; const auto in_data = in.const_data_ptr(); auto out_data = out.mutable_data_ptr(); @@ -78,14 +59,13 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( // grid[n, h, w] contains (x, y) const int64_t grid_idx = grid_offset + h * grid.strides()[1] + w * grid.strides()[2]; - const ACC x = static_cast(grid_data[grid_idx]); - const ACC y = - static_cast(grid_data[grid_idx + grid.strides()[3]]); + const CTYPE x = grid_data[grid_idx]; + const CTYPE y = grid_data[grid_idx + grid.strides()[3]]; - // Compute source coordinates in pixel space (in ACC precision). - const ACC ix = grid_sampler_compute_source_index( + // Compute source coordinates in pixel space + const CTYPE ix = grid_sampler_compute_source_index( x, inp_W, padding_mode, align_corners); - const ACC iy = grid_sampler_compute_source_index( + const CTYPE iy = grid_sampler_compute_source_index( y, inp_H, padding_mode, align_corners); // Get corner pixel coordinates @@ -98,46 +78,40 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( const int64_t ix_se = ix_nw + 1; const int64_t iy_se = iy_nw + 1; - // Interpolation weights. For half inputs these are computed in - // fp32 — the subtractions `ix_se - ix` otherwise suffer - // catastrophic cancellation in fp16 for interior pixels. - const ACC nw_weight = (ix_se - ix) * (iy_se - iy); - const ACC ne_weight = (ix - ix_sw) * (iy_sw - iy); - const ACC sw_weight = (ix_ne - ix) * (iy - iy_ne); - const ACC se_weight = (ix - ix_nw) * (iy - iy_nw); + // Get interpolation weights + const CTYPE nw_weight = (ix_se - ix) * (iy_se - iy); + const CTYPE ne_weight = (ix - ix_sw) * (iy_sw - iy); + const CTYPE sw_weight = (ix_ne - ix) * (iy - iy_ne); + const CTYPE se_weight = (ix - ix_nw) * (iy - iy_nw); - // Accumulate the weighted sum in ACC precision. - ACC out_val = 0; + // Compute output value for this channel + CTYPE out_val = 0; // Add contribution from each corner if within bounds if (padding_mode == GridSamplerPadding::Zeros) { // For zeros padding, only sample if within bounds if (within_bounds_2d(iy_nw, ix_nw, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_nw * in.strides()[2] + - ix_nw * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_nw * in.strides()[2] + + ix_nw * in.strides()[3]] * nw_weight; } if (within_bounds_2d(iy_ne, ix_ne, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_ne * in.strides()[2] + - ix_ne * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_ne * in.strides()[2] + + ix_ne * in.strides()[3]] * ne_weight; } if (within_bounds_2d(iy_sw, ix_sw, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_sw * in.strides()[2] + - ix_sw * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_sw * in.strides()[2] + + ix_sw * in.strides()[3]] * sw_weight; } if (within_bounds_2d(iy_se, ix_se, inp_H, inp_W)) { - out_val += static_cast( - in_data - [in_channel_offset + iy_se * in.strides()[2] + - ix_se * in.strides()[3]]) * + out_val += in_data + [in_channel_offset + iy_se * in.strides()[2] + + ix_se * in.strides()[3]] * se_weight; } } else { @@ -152,33 +126,28 @@ void grid_sample_2d_bilinear_kernel_impl_nchw( const int64_t iy_sw_safe = clip_coordinates(iy_sw, inp_H); const int64_t ix_se_safe = clip_coordinates(ix_se, inp_W); const int64_t iy_se_safe = clip_coordinates(iy_se, inp_H); - out_val = - static_cast( - in_data - [in_channel_offset + iy_nw_safe * in.strides()[2] + - ix_nw_safe * in.strides()[3]]) * + out_val = in_data + [in_channel_offset + iy_nw_safe * in.strides()[2] + + ix_nw_safe * in.strides()[3]] * nw_weight + - static_cast( - in_data + in_data [in_channel_offset + iy_ne_safe * in.strides()[2] + - ix_ne_safe * in.strides()[3]]) * + ix_ne_safe * in.strides()[3]] * ne_weight + - static_cast( - in_data + in_data [in_channel_offset + iy_sw_safe * in.strides()[2] + - ix_sw_safe * in.strides()[3]]) * + ix_sw_safe * in.strides()[3]] * sw_weight + - static_cast( - in_data + in_data [in_channel_offset + iy_se_safe * in.strides()[2] + - ix_se_safe * in.strides()[3]]) * + ix_se_safe * in.strides()[3]] * se_weight; } // Write output in NCHW order const int64_t out_idx = out_channel_offset + h * out.strides()[2] + w * out.strides()[3]; - out_data[out_idx] = static_cast(out_val); + out_data[out_idx] = out_val; } } } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_gt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_gt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_gt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_gt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_hardtanh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_hardtanh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_hardtanh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_hardtanh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_index.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_index.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_index.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_index.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_index_put.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_index_put.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_index_put.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_index_put.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_index_select.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_index_select.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_index_select.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_index_select.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_isinf.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_isinf.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_isinf.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_isinf.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_isnan.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_isnan.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_isnan.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_isnan.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_le.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_le.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_le.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_le.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_leaky_relu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_leaky_relu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_leaky_relu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_leaky_relu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_lift_fresh_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_lift_fresh_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_lift_fresh_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_lift_fresh_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log10.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log10.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log10.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log10.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log1p.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log1p.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log1p.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log1p.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log2.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log2.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log2.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log2.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log_softmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log_softmax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_log_softmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_log_softmax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_and.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_and.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_and.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_and.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_not.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_not.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_not.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_not.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_or.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_or.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_or.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_or.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_xor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_xor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logical_xor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logical_xor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logit.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logit.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_logit.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_logit.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_lt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_lt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_lt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_lt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_masked_fill.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_masked_fill.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_masked_fill.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_masked_fill.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_masked_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_masked_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_masked_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_masked_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_masked_select.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_masked_select.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_masked_select.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_masked_select.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_max.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_max.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_max.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_max.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_max_pool2d_with_indices.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_max_pool2d_with_indices.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_max_pool2d_with_indices.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_max_pool2d_with_indices.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_max_pool2d_with_indices_backward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_maximum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_maximum.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_maximum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_maximum.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_mean.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_mean.cpp similarity index 67% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_mean.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_mean.cpp index 78ae41b..63c7896 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_mean.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_mean.cpp @@ -45,36 +45,6 @@ Tensor& mean_dim_out( InvalidArgument, out); - // Fast path: contiguous tensor, single innermost dim reduction, same dtype. - // Bypasses generic MapReduceOverDimListPlan to use a tight vectorizable loop. - if (in.numel() > 0 && dim_list.has_value() && dim_list.value().size() == 1 && - in.scalar_type() == out.scalar_type()) { - const int64_t d = dim_list.value()[0] < 0 ? dim_list.value()[0] + in.dim() - : dim_list.value()[0]; - if (d >= 0 && d < in.dim() && d == in.dim() - 1 && - tensor_is_contiguous(in)) { - const int64_t reduce_size = in.size(d); - const int64_t outer_size = in.numel() / reduce_size; - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "mean.out"; - ET_SWITCH_FLOATHBF16_TYPES(in.scalar_type(), ctx, op_name, CTYPE, [&] { - const CTYPE* in_data = in.const_data_ptr(); - CTYPE* out_data = out.mutable_data_ptr(); - const CTYPE denom = static_cast(reduce_size); - for (int64_t i = 0; i < outer_size; i++) { - const CTYPE* row = in_data + i * reduce_size; - CTYPE acc = 0; - for (int64_t j = 0; j < reduce_size; j++) { - acc += row[j]; - } - out_data[i] = acc / denom; - } - }); - return out; - } - } - std::optional plan; if (in.numel() > 0) { plan.emplace(in, dim_list); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_min.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_min.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_min.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_min.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_minimum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_minimum.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_minimum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_minimum.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_mm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_mm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_mm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_mm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_mul.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_mul.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_mul.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_mul.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_narrow_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_narrow_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_narrow_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_narrow_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_batch_norm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_batch_norm.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_batch_norm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_batch_norm.cpp index 3a76d35..b8905e0 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_batch_norm.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_batch_norm.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include @@ -268,10 +267,6 @@ std::tuple _native_batch_norm_legit_no_stats_out( CTYPE* mean_data = mean_out.mutable_data_ptr(); CTYPE* invstd_data = invstd_out.mutable_data_ptr(); - // Initialize accumulators to zero before accumulating - std::memset(mean_data, 0, C * sizeof(CTYPE)); - std::memset(invstd_data, 0, C * sizeof(CTYPE)); - // Compute sum and sum of squares for each channel for (size_t b = 0; b < N; ++b) { const CTYPE* b_in_data = in_data + b * C * inner; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_dropout.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_dropout.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_dropout.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_dropout.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_group_norm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_group_norm.cpp similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_group_norm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_group_norm.cpp index 7a2b40c..9e300dc 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_native_group_norm.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_group_norm.cpp @@ -77,8 +77,8 @@ void group_norm( const CTYPE* x = input_data + i * inner_size; // compute E[X] and Var[x] = E[x^2] - E[x]^2 - float sum = reduce_add(x, inner_size); - float sq_sum = vec_powerf(x, inner_size); + CTYPE sum = reduce_add(x, static_cast(inner_size)); + CTYPE sq_sum = vec_powerf(x, static_cast(inner_size)); double mean_value = static_cast(sum) / static_cast(inner_size); double variance = diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_layer_norm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_layer_norm.cpp similarity index 77% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_layer_norm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_layer_norm.cpp index b35796f..12a03a1 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_native_layer_norm.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_native_layer_norm.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -53,21 +54,41 @@ void layer_norm( } const CTYPE* input_data = input.const_data_ptr(); - const CTYPE* weight_data = - weight.has_value() ? weight.value().const_data_ptr() : nullptr; - const CTYPE* bias_data = - bias.has_value() ? bias.value().const_data_ptr() : nullptr; - - layer_norm_scalar( - input_data, - weight_data, - bias_data, - out_data, - mean_data, - rstd_data, - leading, - normalized, - eps); + const CTYPE* weight_data; + if (weight.has_value()) { + weight_data = weight.value().const_data_ptr(); + } else { + weight_data = nullptr; + } + const CTYPE* bias_data; + if (bias.has_value()) { + bias_data = bias.value().const_data_ptr(); + } else { + bias_data = nullptr; + } + + const CTYPE ct_normalized = static_cast(normalized); + for (const auto i : c10::irange(leading)) { + const CTYPE* x = input_data + i * normalized; + CTYPE* y = out_data + i * normalized; + + // compute E[X] and Var[x] = E[x^2] - E[x]^2 + CTYPE sum = reduce_add(x, ct_normalized); + CTYPE sq_sum = vec_powerf(x, ct_normalized); + CTYPE mean_value = sum / ct_normalized; + CTYPE variance = sq_sum / ct_normalized - mean_value * mean_value; + CTYPE std = std::sqrt(variance + eps); + + // Calculate the elements of output + for (const auto j : c10::irange(normalized)) { + CTYPE w = weight_data ? weight_data[j] : static_cast(1); + CTYPE b = bias_data ? bias_data[j] : static_cast(0); + y[j] = (x[j] - mean_value) / std * w + b; + } + + mean_data[i] = mean_value; + rstd_data[i] = 1.0 / std; + } } } // namespace diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ne.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ne.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ne.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ne.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_neg.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_neg.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_neg.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_neg.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_nonzero.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_nonzero.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_nonzero.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_nonzero.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ones.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ones.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_ones.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_ones.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pdist_forward.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pdist_forward.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pdist_forward.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pdist_forward.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_permute_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_permute_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_permute_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_permute_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pixel_shuffle.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pixel_shuffle.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pixel_shuffle.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pixel_shuffle.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pixel_unshuffle.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pixel_unshuffle.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pixel_unshuffle.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pixel_unshuffle.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pow.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pow.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_pow.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_pow.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_prod.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_prod.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_prod.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_prod.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_rand.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_rand.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_rand.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_rand.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_randn.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_randn.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_randn.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_randn.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reciprocal.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reciprocal.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reciprocal.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reciprocal.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reflection_pad1d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reflection_pad1d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reflection_pad1d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reflection_pad1d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reflection_pad2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reflection_pad2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reflection_pad2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reflection_pad2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reflection_pad3d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reflection_pad3d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_reflection_pad3d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_reflection_pad3d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_relu.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_relu.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_relu.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_relu.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_remainder.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_remainder.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_remainder.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_remainder.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_repeat.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_repeat.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_repeat.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_repeat.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_repeat_interleave.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_repeat_interleave.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_repeat_interleave.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_repeat_interleave.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_replication_pad1d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_replication_pad1d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_replication_pad1d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_replication_pad1d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_replication_pad2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_replication_pad2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_replication_pad2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_replication_pad2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_replication_pad3d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_replication_pad3d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_replication_pad3d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_replication_pad3d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_roll.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_roll.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_roll.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_roll.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_round.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_round.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_round.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_round.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_rsqrt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_rsqrt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_rsqrt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_rsqrt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_rsub.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_rsub.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_rsub.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_rsub.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_scalar_tensor.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_scalar_tensor.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_scalar_tensor.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_scalar_tensor.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_scatter_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_scatter_add.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_scatter_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_scatter_add.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_select_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_select_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_select_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_select_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_select_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_select_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_select_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_select_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sigmoid.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sigmoid.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sigmoid.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sigmoid.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sign.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sign.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sign.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sign.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sin.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sin.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sin.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sin.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sinh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sinh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sinh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sinh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_slice_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_slice_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_slice_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_slice_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_slice_scatter.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_slice_scatter.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_slice_scatter.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_slice_scatter.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_softmax.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_softmax.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_softmax.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_softmax.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_split_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_split_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_split_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_split_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_split_with_sizes_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_split_with_sizes_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_split_with_sizes_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_split_with_sizes_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sqrt.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sqrt.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sqrt.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sqrt.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_squeeze_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_squeeze_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_squeeze_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_squeeze_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_stack.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_stack.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_stack.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_stack.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sub.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sub.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_sub.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sub.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sum.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sum.cpp similarity index 73% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sum.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sum.cpp index f2d750d..dcd8179 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_sum.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_sum.cpp @@ -46,36 +46,6 @@ Tensor& sum_dim_out( ET_KERNEL_CHECK(ctx, tensor_is_default_dim_order(in), InvalidArgument, out); - // Fast path: contiguous tensor, single innermost dim reduction, same dtype. - // Bypasses generic MapReduceOverDimListPlan to use a tight vectorizable loop. - if (in.numel() > 0 && dim_list.has_value() && dim_list.value().size() == 1 && - !executorch::runtime::isComplexType(in.scalar_type()) && - in.scalar_type() == out.scalar_type()) { - const int64_t d = dim_list.value()[0] < 0 ? dim_list.value()[0] + in.dim() - : dim_list.value()[0]; - if (d >= 0 && d < in.dim() && d == in.dim() - 1 && - tensor_is_contiguous(in)) { - const int64_t reduce_size = in.size(d); - const int64_t outer_size = in.numel() / reduce_size; - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "sum.IntList_out"; - ET_SWITCH_REALHBBF16_TYPES(in.scalar_type(), ctx, op_name, CTYPE, [&] { - const CTYPE* in_data = in.const_data_ptr(); - CTYPE* out_data = out.mutable_data_ptr(); - for (int64_t i = 0; i < outer_size; i++) { - const CTYPE* row = in_data + i * reduce_size; - CTYPE acc = 0; - for (int64_t j = 0; j < reduce_size; j++) { - acc += row[j]; - } - out_data[i] = acc; - } - }); - return out; - } - } - std::optional plan; if (in.numel() > 0) { plan.emplace(in, dim_list); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_t_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_t_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_t_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_t_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_tan.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_tan.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_tan.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_tan.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_tanh.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_tanh.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_tanh.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_tanh.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_to_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_to_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_to_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_to_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_topk.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_topk.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_topk.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_topk.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_transpose_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_transpose_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_transpose_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_transpose_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_tril.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_tril.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_tril.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_tril.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_trunc.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_trunc.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_trunc.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_trunc.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_unbind_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_unbind_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_unbind_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_unbind_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_unfold_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_unfold_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_unfold_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_unfold_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_unsqueeze_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_unsqueeze_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_unsqueeze_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_unsqueeze_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_upsample_bilinear2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_upsample_bilinear2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_upsample_bilinear2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_upsample_bilinear2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_upsample_bilinear2d_aa.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_upsample_nearest2d.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_upsample_nearest2d.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_upsample_nearest2d.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_upsample_nearest2d.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_var.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_var.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_var.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_var.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_view_as_real_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_view_as_real_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_view_as_real_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_view_as_real_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_view_copy.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_view_copy.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_view_copy.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_view_copy.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_where.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_where.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_where.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_where.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_zeros.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_zeros.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_zeros.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/op_zeros.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/bitwise_op.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/bitwise_op.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/bitwise_op.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/bitwise_op.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/comparison_op.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/comparison_op.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/comparison_op.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/comparison_op.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/logical_op.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/logical_op.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/logical_op.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/logical_op.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/pattern.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/pattern.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/pattern.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/pattern.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/targets.bzl new file mode 100644 index 0000000..5df8fde --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/targets.bzl @@ -0,0 +1,64 @@ +load("@fbsource//xplat/executorch/build:build_variables.bzl", "PATTERN_SRCS") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Note: add all portable_op dependencies to all_deps. This is used for dtype selective + # build, where the portable ops are built from source and linked with :all_deps + runtime.cxx_library( + name = "all_deps", + exported_deps = [ + "//executorch/kernels/portable/cpu/pattern:pattern", + "//executorch/kernels/portable/cpu/pattern:bitwise_op", + "//executorch/kernels/portable/cpu/pattern:comparison_op", + "//executorch/kernels/portable/cpu/pattern:logical_op" + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "bitwise_op", + exported_headers = [ + "bitwise_op.h", + ], + compiler_flags = [], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/...", "//executorch/backends/cadence/..."], + ) + + runtime.cxx_library( + name = "comparison_op", + exported_headers = [ + "comparison_op.h", + ], + compiler_flags = [], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/...", "//executorch/backends/cadence/..."], + ) + + runtime.cxx_library( + name = "logical_op", + exported_headers = [ + "logical_op.h", + ], + compiler_flags = [], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "pattern", + srcs = PATTERN_SRCS, + exported_headers = [ + "pattern.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + exported_deps = [ + "//executorch/kernels/portable/cpu/util:broadcast_util", + "//executorch/kernels/portable/cpu/util:functional_util", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_bool.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/unary_ufunc_realhbbf16_to_floathbf16.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/pattern/unary_ufunc_realhbf16.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/scalar_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/scalar_utils.h similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/scalar_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/scalar_utils.h index 18cc1f4..312a663 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/scalar_utils.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/scalar_utils.h @@ -221,8 +221,8 @@ bool extract_scalar(Scalar scalar, FLOAT_T* out_val) { // be represented when FLOAT_T == float. float can, however, represent // infinite and NaN values. if (std::isfinite(val) && - (val < static_cast(std::numeric_limits::lowest()) || - val > static_cast(std::numeric_limits::max()))) { + (val < std::numeric_limits::lowest() || + val > std::numeric_limits::max())) { // PyTorch's implementation of clamp() raises an exception if the min/max // values cannot be represented as the dtype, so we should fail too. return false; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/selective_build.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/selective_build.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/selective_build.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/selective_build.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/targets.bzl new file mode 100644 index 0000000..7df7757 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/targets.bzl @@ -0,0 +1,89 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/kernels/portable:op_registration_util.bzl", "ATEN_OPS", "CUSTOM_OPS", "define_op_target") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Define build targets for all operators registered in the tables above. + for op in ATEN_OPS: + define_op_target(is_aten_op = True, **op) + for op in CUSTOM_OPS: + define_op_target(is_aten_op = False, **op) + + custom_op_targets = [":{}".format(op["name"]) for op in CUSTOM_OPS] + + aten_op_targets = [":{}".format(op["name"]) for op in ATEN_OPS] + all_op_targets = custom_op_targets + aten_op_targets + + runtime.cxx_library( + name = "cpu", + srcs = [], + visibility = [ + "//executorch/kernels/portable/...", + "//executorch/kernels/test/...", + ], + exported_deps = all_op_targets, + ) + + if True in get_aten_mode_options(): + runtime.cxx_library( + name = "cpu_aten", + srcs = [], + visibility = ["//executorch/kernels/portable/..."], + exported_deps = [t + "_aten" for t in custom_op_targets], + ) + + # Only for use by op targets under //executorch. This API needs to be + # reevaluated before becoming a public API. + runtime.cxx_library( + name = "vec_ops", + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + "//executorch/runtime/platform:compiler", + ], + srcs = [], + exported_headers = ["vec_ops.h"], + visibility = ["PUBLIC"], + ) + + # Only for use by targets in this directory. Defines constants like M_PI + # if they arent already defined by the toolchains cmath + runtime.cxx_library( + name = "math_constants", + srcs = [], + exported_headers = [ + "math_constants.h", + ], + visibility = ["PUBLIC"], + ) + + # Only for use by targets in this directory. + runtime.cxx_library( + name = "scalar_utils", + srcs = [], + exported_headers = ["scalar_utils.h", "selective_build.h"], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + ], + exported_deps = [ + "//executorch/runtime/core/exec_aten:lib", + ], + ) + + # Used for dtype selective build. Collect source and header files. + runtime.filegroup( + name = "portable_source_files", + srcs = native.glob(["*.cpp"]), + visibility = ["PUBLIC"], + ) + + runtime.filegroup( + name = "portable_header_files", + srcs = native.glob(["*.h"]), + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/scalar_utils_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/scalar_utils_test.cpp new file mode 100644 index 0000000..f1e7af6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/scalar_utils_test.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +template +struct promote_type_with_scalar_type_is_valid + : std::integral_constant< + bool, + (std::is_same::value || + std::is_same::value || + std::is_same::value) && + !std::is_same::value && + !torch::executor::is_qint_type::value && + !torch::executor::is_bits_type::value && + !executorch::runtime::is_bits_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_barebones_unsigned_type::value && + !executorch::runtime::is_barebones_unsigned_type::value> {}; + +template +struct CompileTimePromoteTypeWithScalarTypeTestCase { + static void testAll() { +#define CALL_TEST_ONE(cpp_type, scalar_type) \ + testOne< \ + cpp_type, \ + promote_type_with_scalar_type_is_valid::value>(); + ET_FORALL_SCALAR_TYPES(CALL_TEST_ONE) +#undef CALL_TEST_ONE + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + auto actual = torch::executor::CppTypeToScalarType< + typename torch::executor::native::utils:: + promote_type_with_scalar_type::type>::value; + const auto scalarType1 = torch::executor::CppTypeToScalarType::value; + const auto scalarType2 = torch::executor::CppTypeToScalarType::value; + T2 scalar_value = 0; + auto expected = torch::executor::native::utils::promote_type_with_scalar( + scalarType1, scalar_value, half_to_float); + EXPECT_EQ(actual, expected) + << "promoting " << (int)scalarType1 << " with " << (int)scalarType2 + << " given half_to_float = " << half_to_float << " expected " + << (int)expected << " but got " << (int)actual; + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + // Skip invalid case + } +}; + +TEST(ScalarTypeUtilTest, compileTypePromoteTypesTest) { +#define INSTANTIATE_TYPE_TEST(cpp_type, scalar_type) \ + CompileTimePromoteTypeWithScalarTypeTestCase::testAll(); \ + CompileTimePromoteTypeWithScalarTypeTestCase::testAll(); + + ET_FORALL_SCALAR_TYPES(INSTANTIATE_TYPE_TEST); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/targets.bzl new file mode 100644 index 0000000..a40f6da --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/targets.bzl @@ -0,0 +1,29 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # + # NOTE: tests for operators should live in kernels/portable/test, so that + # they can be run against all implementations of a given operator. This + # directory is only for testing cpu-specific helper libraries. + # + + runtime.cxx_test( + name = "scalar_utils_test", + srcs = ["scalar_utils_test.cpp"], + deps = [ + "//executorch/kernels/portable/cpu:scalar_utils", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + ) + + runtime.cxx_test( + name = "vec_ops_test", + srcs = ["vec_ops_test.cpp"], + deps = ["//executorch/kernels/portable/cpu:vec_ops"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/vec_ops_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/vec_ops_test.cpp new file mode 100644 index 0000000..9611acd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/test/vec_ops_test.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include + +using namespace ::testing; + +TEST(VecMinfTest, Smoke) { + // No need to be super thorough since we know this is implemented with + // std::min_element(). Just show that it's hooked up correctly. + + constexpr size_t kNumVals = 5; + float x[kNumVals] = {1.1, -2.2, 0, -1234.5, 10.0}; + EXPECT_EQ(torch::executor::vec_minf(x, kNumVals), -1234.5); +} + +TEST(VecMaxfTest, Smoke) { + // No need to be super thorough since we know this is implemented with + // std::max_element(). Just show that it's hooked up correctly. + + constexpr size_t kNumVals = 5; + float x[kNumVals] = {1.1, -2.2, 0, -1234.5, 10.0}; + EXPECT_EQ(torch::executor::vec_maxf(x, kNumVals), 10.0); +} + +TEST(VecAddfTest, Smoke) { + constexpr size_t kNumVals = 5; + float in1[kNumVals] = {1, 2, 3, 4, 5}; + float in2[kNumVals] = {10, 20, 30, 40, 50}; + float out[kNumVals] = {}; + + torch::executor::vec_addf(out, in1, in2, kNumVals); + + // Each element of `out` should be the sum of the corresponding elements + // of `in1` and `in2`. + EXPECT_EQ(out[0], 11); + EXPECT_EQ(out[1], 22); + EXPECT_EQ(out[2], 33); + EXPECT_EQ(out[3], 44); + EXPECT_EQ(out[4], 55); +} + +TEST(VecScalefTest, Smoke) { + constexpr size_t kNumVals = 5; + float in[kNumVals] = {4, 8, 16, 32, 64}; + float out[kNumVals] = {0, 0, 0, 0, 0}; + + torch::executor::vec_scalef(out, in, 0.5, kNumVals); + + // Each element of `out` should be the product of 0.5 and the corresponding + // element of `in`. + EXPECT_EQ(out[0], 2); + EXPECT_EQ(out[1], 4); + EXPECT_EQ(out[2], 8); + EXPECT_EQ(out[3], 16); + EXPECT_EQ(out[4], 32); +} + +TEST(VecPowerfTest, Smoke) { + constexpr size_t kNumVals = 5; + float in[kNumVals] = {-2, -1, 0, 1, 2}; + + // Should return the sum of the squares of all input elements. + EXPECT_EQ( + torch::executor::vec_powerf(in, kNumVals), + (-2 * -2) + (-1 * -1) + (0 * 0) + (1 * 1) + (2 * 2)); +} + +TEST(VecMatMulTest, Smoke) { + // x sizes: (3, 2) + constexpr size_t kXNumVals = 6; + // y sizes: (2, 4) + constexpr size_t kYNumVals = 8; + // z sizes: (3, 4) + constexpr size_t kZNumVals = 12; + + // clang-format off + int64_t X[kXNumVals] = { + 1, 2, + 2, 1, + 3, 0, + }; + int64_t Y[kYNumVals] = { + 1, 2, 3, 4, + 5, 6, 7, 8, + }; + // clang-format on + + int64_t out[kZNumVals] = {}; + + torch::executor::vec_matmul(out, X, Y, 3, 2, 4); + + // clang-format off + std::vector expected({ + 11, 14, 17, 20, + 7, 10, 13, 16, + 3, 6, 9, 12, + }); + // clang-format on + EXPECT_EQ(std::vector(out, out + kZNumVals), expected); +} + +TEST(VecAddmmTest, Smoke) { + // x sizes: (3, 2) + constexpr size_t kXNumVals = 6; + // y sizes: (2, 4) + constexpr size_t kYNumVals = 8; + // z sizes: (3, 4) + constexpr size_t kZNumVals = 12; + + // clang-format off + int64_t self[kZNumVals] = { + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + }; + + int64_t X[kXNumVals] = { + 1, 2, + 2, 1, + 3, 0, + }; + int64_t Y[kYNumVals] = { + 1, 2, 3, 4, + 5, 6, 7, 8, + }; + // clang-format on + + int64_t out[kZNumVals] = {}; + + torch::executor::vec_addmm(out, self, X, Y, 3, 2, 4, 2.0, 3.0); + + // clang-format off + std::vector expected({ + 35, 44, 53, 62, + 25, 34, 43, 52, + 15, 24, 33, 42, + }); + // clang-format on + EXPECT_EQ(std::vector(out, out + kZNumVals), expected); +} + +TEST(VecSoftMaxTest, Smoke) { + // x sizes: (1, 3) + constexpr size_t kXNumVals = 3; + + // clang-format off + float X[kXNumVals] = { + 1, 2, 3, + }; + // clang-format on + float out[kXNumVals] = {}; + + torch::executor::vec_softmax(out, X, 3); + + // clang-format off + std::vector expected({ + 0.0900306, 0.244728, 0.665241, + }); + // clang-format on + for (auto i = 0; i < 3; ++i) { + EXPECT_NEAR(out[i], expected[i], 10e-6); + } +} + +class QuantizeI8F32Test : public ::testing::Test { + protected: + void SetUp() override { + constexpr float kInfinity = std::numeric_limits::infinity(); + // A spread of inputs for various scales and zero points. + inputs_ = { + -kInfinity, -512, -256, -128, -64, 0, 64, 128, 256, 512, kInfinity}; + outputs_.resize(inputs_.size()); + } + + std::vector inputs_; + std::vector outputs_; +}; + +TEST_F(QuantizeI8F32Test, Identity) { + const float kScale = 1.0; // No scaling. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + // Most values will be clamped to min/max uint8_t, but the unclamped values + // should be the same as the inputs. + EXPECT_EQ( + outputs_, + std::vector( + {-128, -128, -128, -128, -64, 0, 64, 127, 127, 127, 127})); +} + +TEST_F(QuantizeI8F32Test, Rounding) { + // Demonstrate that quantization uses roundf() semantics, not + // ceilf()/floorf(). + std::vector in = {-1.9, -1.1, 1.1, 1.9}; + std::vector out; + out.resize(in.size()); + + torch::executor::quantize_i8_f32( + out.data(), in.data(), /*scale=*/1.0, /*zero_point=*/0, in.size()); + + EXPECT_EQ(out, std::vector({-2, -1, 1, 2})); +} + +TEST_F(QuantizeI8F32Test, ScaledDown) { + const float kScale = 0.5; // Scaled down. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector({ + -128, // Clamped + -128, // Clamped + -128, // Clamped + -64, // -128 * 0.5 + -32, // -64 * 0.5 + 0, // 0 * 0.5 + 32, // 64 * 0.5 + 64, // 128 * 0.5 + 127, // Clamped + 127, // Clamped + 127, // Clamped + })); +} + +TEST_F(QuantizeI8F32Test, ShiftedZeroPoint) { + const float kScale = 1.0; // No scaling. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector({ + -128, // Clamped + -128, // Clamped + -128, // Clamped + -96, // -128 + 32 + -32, // -64 + 32 + 32, // 0 + 32 + 96, // 64 + 32 + 127, // Clamped + 127, // Clamped + 127, // Clamped + 127, // Clamped + })); +} + +TEST_F(QuantizeI8F32Test, ScaledDownWithShiftedZeroPoint) { + const float kScale = 0.5; // Scaled down. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::quantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + // Demonstrate that the zero point adjustment happens after scaling. + EXPECT_EQ( + outputs_, + std::vector({ + -128, // Clamped + -128, // Clamped + -96, // (-256 * 0.5) + 32 + -32, // (-128 * 0.5) + 32 + 0, // (-64 * 0.5) + 32 + 32, // (0 * 0.5) + 32 + 64, // (64 * 0.5) + 32 + 96, // (128 * 0.5) + 32 + 127, // Clamped + 127, // Clamped + 127, // Clamped + })); +} + +class DequantizeI8F32Test : public ::testing::Test { + protected: + void SetUp() override { + // A spread of inputs for various scales and zero points. + inputs_ = {-128, -64, -32, 0, 32, 64, 127}; + outputs_.resize(inputs_.size()); + } + + std::vector inputs_; + std::vector outputs_; +}; + +TEST_F(DequantizeI8F32Test, Identity) { + const float kScale = 1.0; // No scaling. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ(outputs_, std::vector({-128, -64, -32, 0, 32, 64, 127})); +} + +TEST_F(DequantizeI8F32Test, ScaledUp) { + const float kScale = 2.0; // Scaled up. + const int32_t kZeroPoint = 0; // Not shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector( + {-128 * kScale, + -64 * kScale, + -32 * kScale, + 0 * kScale, + 32 * kScale, + 64 * kScale, + 127 * kScale})); +} + +TEST_F(DequantizeI8F32Test, ShiftedZeroPoint) { + const float kScale = 1.0; // Not scaled. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + EXPECT_EQ( + outputs_, + std::vector( + {-128 - kZeroPoint, + -64 - kZeroPoint, + -32 - kZeroPoint, + 0 - kZeroPoint, + 32 - kZeroPoint, + 64 - kZeroPoint, + 127 - kZeroPoint})); +} + +TEST_F(DequantizeI8F32Test, ScaledUpWithShiftedZeroPoint) { + const float kScale = 2.0; // Scaled up. + const int32_t kZeroPoint = 32; // Shifted. + torch::executor::dequantize_i8_f32( + outputs_.data(), inputs_.data(), kScale, kZeroPoint, inputs_.size()); + + // Demonstrate that the zero point adjustment happens before scaling. + EXPECT_EQ( + outputs_, + std::vector({ + (-128 - kZeroPoint) * kScale, + (-64 - kZeroPoint) * kScale, + (-32 - kZeroPoint) * kScale, + (0 - kZeroPoint) * kScale, + (32 - kZeroPoint) * kScale, + (64 - kZeroPoint) * kScale, + (127 - kZeroPoint) * kScale, + })); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/CMakeLists.txt new file mode 100644 index 0000000..eabf3ad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Kernel library for portable kernels. Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ + +cmake_minimum_required(VERSION 3.19) + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) +endif() + +list(TRANSFORM _kernels_util_all_deps__srcs PREPEND "${EXECUTORCH_ROOT}/") + +set(_common_compile_options + $<$:/wd4996> + $<$>:-Wno-deprecated-declarations> +) + +add_library(kernels_util_all_deps ${_kernels_util_all_deps__srcs}) +target_link_libraries(kernels_util_all_deps PRIVATE executorch_core) +target_include_directories( + kernels_util_all_deps PUBLIC ${_common_include_directories} +) +target_compile_definitions( + kernels_util_all_deps PUBLIC C10_USING_CUSTOM_GENERATED_MACROS +) +target_compile_options(kernels_util_all_deps PUBLIC ${_common_compile_options}) + +install( + TARGETS kernels_util_all_deps + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/activation_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/activation_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/activation_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/activation_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/activation_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/activation_ops_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/activation_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/activation_ops_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/advanced_index_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/advanced_index_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/advanced_index_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/advanced_index_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/advanced_index_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/advanced_index_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/advanced_index_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/advanced_index_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/arange_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/arange_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/arange_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/arange_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/arange_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/arange_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/arange_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/arange_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/broadcast_indexes_range.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/broadcast_indexes_range.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/broadcast_indexes_range.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/broadcast_indexes_range.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/broadcast_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/broadcast_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/broadcast_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/broadcast_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/broadcast_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/broadcast_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/broadcast_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/broadcast_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/copy_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/copy_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/copy_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/copy_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/copy_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/copy_ops_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/copy_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/copy_ops_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/delinearize_index.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/delinearize_index.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/delinearize_index.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/delinearize_index.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/delinearize_index.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/delinearize_index.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/delinearize_index.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/delinearize_index.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/distance_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/distance_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/distance_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/distance_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/distance_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/distance_util.h similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/distance_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/distance_util.h index a54e02d..05406e3 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/distance_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/distance_util.h @@ -116,7 +116,7 @@ void pdist(const Tensor& in, Tensor& out, double p) { pdist>(in, out, p); } else if (p == 2.0) { pdist>(in, out, p); - } else if (p == static_cast(INFINITY)) { + } else if (p == INFINITY) { pdist>(in, out, p); } else { pdist>(in, out, p); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/dtype_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/dtype_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/dtype_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/dtype_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/dtype_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/dtype_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/dtype_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/dtype_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/elementwise_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/elementwise_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/elementwise_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/elementwise_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/functional_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/functional_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/functional_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/functional_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/grid_sampler_2d_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/grid_sampler_2d_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/grid_sampler_2d_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/grid_sampler_2d_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/grid_sampler_2d_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/grid_sampler_2d_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/grid_sampler_2d_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/grid_sampler_2d_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/index_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/index_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/index_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/index_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/index_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/index_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/index_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/index_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/kernel_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/kernel_ops_util.cpp similarity index 91% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/kernel_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/kernel_ops_util.cpp index 2e0ceee..daa85f6 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/kernel_ops_util.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/kernel_ops_util.cpp @@ -262,53 +262,6 @@ bool check_arange_args(double start, double end, double step, Tensor& out) { return true; } -bool check_adaptive_avg_pool2d_args( - const Tensor& in, - const IntArrayRef output_size, - const Tensor& out) { - ET_LOG_AND_RETURN_IF_FALSE(tensors_have_same_dtype(in, out)); - - ET_LOG_AND_RETURN_IF_FALSE(tensor_is_default_or_channels_last_dim_order(in)); - ET_LOG_AND_RETURN_IF_FALSE(tensor_is_default_or_channels_last_dim_order(out)); - - ET_CHECK_OR_RETURN_FALSE( - (in.dim() == 3 && in.size(0) > 0 && in.size(1) > 0 && in.size(2) > 0) || - (in.dim() == 4 && in.size(1) > 0 && in.size(2) > 0 && in.size(3) > 0), - "Expected 3D or 4D (batch mode) tensor with optional 0 dim batch size for input; in.dim() = %" ET_PRI_TENSOR_DIM, - in.dim()); - - ET_CHECK_OR_RETURN_FALSE( - output_size.size() == 2, - "output_size must have exactly 2 elements, but got %zu", - output_size.size()); - - ET_CHECK_OR_RETURN_FALSE( - output_size[0] > 0 && output_size[1] > 0, - "output_size must be positive, but got (%" PRId64 ", %" PRId64 ")", - output_size[0], - output_size[1]); - - return true; -} - -void get_adaptive_avg_pool2d_out_target_size( - const Tensor& in, - const IntArrayRef output_size, - executorch::aten::SizesType* const out_sizes, - size_t* const out_ndim) { - *out_ndim = in.dim(); - - if (in.dim() == 4) { - out_sizes[0] = in.size(0); - out_sizes[1] = in.size(1); - } else { - out_sizes[0] = in.size(0); - } - - out_sizes[*out_ndim - 2] = output_size[0]; - out_sizes[*out_ndim - 1] = output_size[1]; -} - bool check_avg_pool2d_args( const Tensor& in, const IntArrayRef kernel_size, @@ -611,14 +564,6 @@ bool check_constant_pad_args( pad.size() / 2, in.dim()); - for (size_t i = 0; i < pad.size(); ++i) { - ET_CHECK_OR_RETURN_FALSE( - pad[i] >= 0, - "Padding values must be non-negative, but got pad[%zu] = %" PRId64, - i, - pad[i]); - } - return true; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/kernel_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/kernel_ops_util.h similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/kernel_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/kernel_ops_util.h index db6ce07..e3eaf4d 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/kernel_ops_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/kernel_ops_util.h @@ -218,7 +218,7 @@ void kernel_reduction_then_map_2d( int64_t padding_y = p_H; int64_t dilation_y = d_H; - ssize_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; + size_t in_y = stride_y * out_y + dilation_y * w_y - padding_y; in_coord[in_dim - 2] = in_y; for (const auto w_x : c10::irange(k_W)) { @@ -226,13 +226,11 @@ void kernel_reduction_then_map_2d( int64_t padding_x = p_W; int64_t dilation_x = d_W; - ssize_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; + size_t in_x = stride_x * out_x + dilation_x * w_x - padding_x; in_coord[in_dim - 1] = in_x; - const bool x_in_bound = - (in_x >= 0 && in_x < static_cast(in_W)); - const bool y_in_bound = - (in_y >= 0 && in_y < static_cast(in_H)); + const bool x_in_bound = (in_x >= 0 && in_x < in_W); + const bool y_in_bound = (in_y >= 0 && in_y < in_H); const bool xy_in_bound = (x_in_bound && y_in_bound); CTYPE in_val = 0; @@ -386,17 +384,6 @@ void apply_kernel_2d_reduce_then_map_fn( // Operator specific utility functions // -bool check_adaptive_avg_pool2d_args( - const Tensor& in, - const IntArrayRef output_size, - const Tensor& out); - -void get_adaptive_avg_pool2d_out_target_size( - const Tensor& in, - const IntArrayRef output_size, - executorch::aten::SizesType* const out_sizes, - size_t* const out_ndim); - bool check_arange_args(double start, double end, double step, Tensor& out); bool check_avg_pool2d_args( diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/math_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/math_util.h similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/math_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/math_util.h index 434c51d..a3a6499 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/math_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/math_util.h @@ -47,8 +47,7 @@ template < type = true> FLOAT_T floor_divide(FLOAT_T a, FLOAT_T b) { if (b == 0) { - return std::signbit(a) ? static_cast(-INFINITY) - : static_cast(INFINITY); + return std::signbit(a) ? -INFINITY : INFINITY; } const auto mod = std::fmod(a, b); auto div = (a - mod) / b; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/matmul_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/matmul_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/matmul_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/matmul_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/matmul_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/matmul_ops_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/matmul_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/matmul_ops_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/normalization_ops_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/normalization_ops_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/normalization_ops_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/normalization_ops_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/normalization_ops_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/normalization_ops_util.h similarity index 50% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/normalization_ops_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/normalization_ops_util.h index d5b5f97..f7bcfa0 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/normalization_ops_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/normalization_ops_util.h @@ -9,54 +9,10 @@ #pragma once #include -#include -#include namespace torch { namespace executor { -/** - * Scalar layer_norm computation over M rows of N elements each. - * Computes mean/variance in float, normalizes with (x - mean) / std * gamma + - * beta. Caller must handle M==0 and N==0 edge cases before calling. - */ -template -inline void layer_norm_scalar( - const CTYPE* input_data, - const CTYPE* weight_data, // nullable - const CTYPE* bias_data, // nullable - CTYPE* out_data, - CTYPE* mean_data, - CTYPE* rstd_data, - size_t M, - size_t N, - float eps) { - for (size_t i = 0; i < M; ++i) { - const CTYPE* x = input_data + i * N; - CTYPE* y = out_data + i * N; - - // compute E[X] and Var[x] = E[x^2] - E[x]^2 - float sum = std::accumulate(x, x + N, 0.0f); - float sq_sum = 0; - for (size_t j = 0; j < N; ++j) { - sq_sum += static_cast(x[j]) * x[j]; - } - float mean_value = sum / N; - float variance = sq_sum / N - mean_value * mean_value; - float std = std::sqrt(variance + eps); - - // Calculate the elements of output - for (size_t j = 0; j < N; ++j) { - CTYPE w = weight_data ? weight_data[j] : static_cast(1); - CTYPE b = bias_data ? bias_data[j] : static_cast(0); - y[j] = (x[j] - mean_value) / std * w + b; - } - - mean_data[i] = mean_value; - rstd_data[i] = 1.0 / std; - } -} - bool check_batch_norm_args( const Tensor& in, const std::optional& weight, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/padding_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/padding_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/padding_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/padding_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/padding_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/padding_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/padding_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/padding_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/reduce_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/reduce_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/reduce_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/reduce_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/reduce_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/reduce_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/reduce_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/reduce_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/repeat_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/repeat_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/repeat_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/repeat_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/repeat_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/repeat_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/repeat_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/repeat_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/select_copy_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/select_copy_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/select_copy_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/select_copy_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/select_copy_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/select_copy_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/select_copy_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/select_copy_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/slice_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/slice_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/slice_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/slice_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/slice_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/slice_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/slice_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/slice_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/stack_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/stack_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/stack_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/stack_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/stack_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/stack_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/stack_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/stack_util.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/targets.bzl new file mode 100644 index 0000000..1fd1e61 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/targets.bzl @@ -0,0 +1,383 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Note: add all portable_op dependencies to all_deps. This is used for dtype selective + # build, where the portable ops are built from source and linked with :all_deps + runtime.cxx_library( + name = "all_deps", + exported_deps = [ + "//executorch/extension/threadpool:threadpool", + "//executorch/kernels/portable/cpu/util:arange_util", + "//executorch/kernels/portable/cpu/util:functional_util", + "//executorch/kernels/portable/cpu/util:broadcast_util", + "//executorch/kernels/portable/cpu/util:kernel_ops_util", + "//executorch/kernels/portable/cpu:vec_ops", + "//executorch/kernels/portable/cpu/util:matmul_ops_util", + "//executorch/kernels/portable/cpu/util:copy_ops_util", + "//executorch/kernels/portable/cpu/util:transpose_util", + "//executorch/kernels/portable/cpu/util:index_util", + "//executorch/kernels/portable/cpu/util:math_util", + "//executorch/kernels/portable/cpu/util:padding_util", + "//executorch/kernels/portable/cpu/util:repeat_util", + "//executorch/kernels/portable/cpu/util:activation_ops_util", + "//executorch/kernels/portable/cpu/util:reduce_util", + "//executorch/kernels/portable/cpu/util:normalization_ops_util", + "//executorch/kernels/portable/cpu/util:distance_util", + "//executorch/kernels/portable/cpu/util:select_copy_util", + "//executorch/kernels/portable/cpu/util:advanced_index_util", + "//executorch/kernels/portable/cpu/util:slice_util", + "//executorch/kernels/portable/cpu/util:stack_util", + "//executorch/kernels/portable/cpu/util:elementwise_util", + "//executorch/kernels/portable/cpu/util:upsample_util", + "//executorch/kernels/portable/cpu/util:vectorized_math", + "//executorch/kernels/portable/cpu/util:grid_sampler_2d_util", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "activation_ops_util", + srcs = ["activation_ops_util.cpp"], + exported_headers = [ + "activation_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "repeat_util", + srcs = [ + "repeat_util.cpp", + ], + exported_headers = ["repeat_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "broadcast_util", + srcs = [ + "broadcast_util.cpp", + "delinearize_index.cpp", + ], + exported_headers = [ + "broadcast_util.h", + "delinearize_index.h", + ], + exported_deps = [ + ":broadcast_indexes_range", + ], + deps = [ + ":repeat_util", + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "dtype_util", + srcs = ["dtype_util.cpp"], + exported_headers = [ + "dtype_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "elementwise_util", + exported_headers = [ + "elementwise_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + exported_deps = [ + ":broadcast_indexes_range", + ":broadcast_util", + ":dtype_util", + ":vectorized_math", + "//executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch", + "//executorch/runtime/kernel:kernel_runtime_context", + "//executorch/kernels/portable/cpu:scalar_utils", + "//executorch/extension/threadpool:threadpool", + "//executorch/kernels/portable/cpu:scalar_utils", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "advanced_index_util", + srcs = ["advanced_index_util.cpp"], + exported_headers = [ + "advanced_index_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + ":broadcast_util", + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "copy_ops_util", + srcs = ["copy_ops_util.cpp"], + exported_headers = [ + "copy_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + exported_deps = [ + ":broadcast_util", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "distance_util", + srcs = ["distance_util.cpp"], + exported_headers = [ + "distance_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "kernel_ops_util", + srcs = ["kernel_ops_util.cpp"], + exported_headers = [ + "kernel_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "matmul_ops_util", + srcs = ["matmul_ops_util.cpp"], + exported_headers = [ + "matmul_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + ":broadcast_util", + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "padding_util", + srcs = ["padding_util.cpp"], + exported_headers = [ + "padding_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "normalization_ops_util", + srcs = ["normalization_ops_util.cpp"], + exported_headers = [ + "normalization_ops_util.h", + ], + compiler_flags = ["-Wno-missing-prototypes"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/optimized/cpu/..."], + ) + + runtime.cxx_library( + name = "transpose_util", + exported_headers = [ + "transpose_util.h", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + # Utility functions that can be used by operators that perform indexing + runtime.cxx_library( + name = "index_util", + srcs = ["index_util.cpp"], + exported_headers = ["index_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/quantized/..."], + ) + + # Utility functions that can be used by operators that repeat the same computation for each element in the tensor + # Note that because this is a header only library, targets must also depend on broadcast_util. + runtime.cxx_library( + name = "functional_util", + srcs = [], + exported_headers = ["functional_util.h"], + exported_deps = [ + "//executorch/extension/threadpool:threadpool", + ], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ":broadcast_util", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "math_util", + srcs = [], + exported_headers = ["math_util.h"], + visibility = ["//executorch/kernels/portable/cpu/...", "//executorch/kernels/quantized/..."], + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch", + ], + ) + + runtime.cxx_library( + name = "select_copy_util", + srcs = ["select_copy_util.cpp"], + exported_headers = ["select_copy_util.h"], + deps = [ + ":copy_ops_util", + "//executorch/runtime/kernel:kernel_includes", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "slice_util", + srcs = ["slice_util.cpp"], + exported_headers = ["slice_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + "//executorch/extension/threadpool:threadpool", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "stack_util", + srcs = ["stack_util.cpp"], + exported_headers = ["stack_util.h"], + deps = [ + "//executorch/kernels/portable/cpu/util:copy_ops_util", + ], + exported_deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "upsample_util", + srcs = ["upsample_util.cpp"], + exported_headers = ["upsample_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + runtime.cxx_library( + name = "broadcast_indexes_range", + exported_headers = ["broadcast_indexes_range.h"], + deps = [ + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit", + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "vectorized_math", + exported_headers = ["vectorized_math.h"], + visibility = ["//executorch/..."], + exported_deps = [ + "//executorch/runtime/core/portable_type:portable_type", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + ], + ) + + runtime.cxx_library( + name = "grid_sampler_2d_util", + srcs = ["grid_sampler_2d_util.cpp"], + exported_headers = ["grid_sampler_2d_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes", + ], + visibility = ["//executorch/kernels/portable/cpu/..."], + ) + + # Utility functions that can be used by operators that perform reduction + for aten_mode in get_aten_mode_options(): + suffix = "_aten" if aten_mode else "" + runtime.cxx_library( + name = "reduce_util{}".format(suffix), + srcs = ["reduce_util.cpp"], + exported_headers = ["reduce_util.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes{}".format(suffix), + "//executorch/runtime/core/exec_aten/util:tensor_util{}".format(suffix), + ], + exported_deps = [ + "//executorch/extension/threadpool:threadpool", + ], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "arange_util{}".format(suffix), + srcs = ["arange_util.cpp"], + exported_headers = ["arange_util.h"], + exported_deps = [ + "//executorch/runtime/kernel:kernel_includes{}".format(suffix), + ], + visibility = [ + "//executorch/kernels/portable/cpu/...", + "//executorch/extension/llm/...", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/CMakeLists.txt new file mode 100644 index 0000000..33ca3db --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) + +set(_test_srcs broadcast_indexes_range_test.cpp broadcast_test.cpp + reduce_test.cpp vectorized_math_test.cpp +) + +et_cxx_test( + kernels_portable_cpu_util_test SOURCES ${_test_srcs} EXTRA_LIBS + portable_kernels portable_ops_lib +) + +find_package_torch_headers() +target_include_directories( + kernels_portable_cpu_util_test PRIVATE ${TORCH_INCLUDE_DIRS} +) +target_compile_definitions( + kernels_portable_cpu_util_test PRIVATE ET_USE_PYTORCH_HEADERS +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp new file mode 100644 index 0000000..42fd248 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_indexes_range_test.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include + +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::testing::TensorFactory; +using torch::executor::BroadcastIndexesRange; +using torch::executor::delinearize_index; +using torch::executor::linearize_access_indexes; + +namespace { +template +auto range_to_vec(const Range& rng) { + return std::vector( + rng.begin(), rng.end()); +} +} // namespace +TEST(BroadcastIndexesRangeTest, Empty) { + TensorFactory tf; + + Tensor a = tf.make({0}, {}); + ASSERT_EQ(a.numel(), 0); + bool loop_entered = false; + for (auto _ : BroadcastIndexesRange<1>(a, a)) { + loop_entered = true; + } + EXPECT_FALSE(loop_entered); +} + +// [W] -> [W] +TEST(BroadcastIndexesRangeTest, OneDNotBroadcasted) { + TensorFactory tf; + + Tensor out = tf.zeros({5}); + int idx = 0; + const auto range = BroadcastIndexesRange<1>(out, out); + for (const auto& elem : range_to_vec(range)) { + EXPECT_EQ(*(range.begin() + idx), elem); + EXPECT_EQ(elem[0], idx++); + EXPECT_EQ(elem[0], elem[1]); + } +} + +template +void test_operator_plus(const Range& range) { + size_t idx = 0; + for (const auto& indexes : range) { + EXPECT_EQ(*(range.begin() + idx), indexes); + idx++; + } +} + +// [1] -> [H, W] +// [W] -> [H, W] +// [1, 1] -> [H, W] +// [1, W] -> [H, W] +// [H, 1] -> [H, W] +// [H, W] -> [H, W] +// Cover all these at the same time to also exercise multiple input tensors. +TEST(BroadcastIndexesRangeTest, OneAndTwoDExhaustive) { + TensorFactory tf; + Tensor out = tf.zeros({3, 4}); + Tensor in_0d_scalar = tf.zeros({}); + Tensor in_1d_scalar = tf.zeros({1}); + Tensor in_2d_scalar = tf.zeros({1, 1}); + + Tensor in_row = tf.zeros({4}); + Tensor in_col = tf.zeros({3, 1}); + + Tensor in_not_broadcast = tf.zeros({3, 4}); + + const auto range = BroadcastIndexesRange<6>( + out, + in_0d_scalar, + in_1d_scalar, + in_2d_scalar, + in_row, + in_col, + in_not_broadcast); + auto actual = range_to_vec(range); + decltype(actual) expected = { + {0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 1, 0, 1}, + {2, 0, 0, 0, 2, 0, 2}, + {3, 0, 0, 0, 3, 0, 3}, + {4, 0, 0, 0, 0, 1, 4}, + {5, 0, 0, 0, 1, 1, 5}, + {6, 0, 0, 0, 2, 1, 6}, + {7, 0, 0, 0, 3, 1, 7}, + {8, 0, 0, 0, 0, 2, 8}, + {9, 0, 0, 0, 1, 2, 9}, + {10, 0, 0, 0, 2, 2, 10}, + {11, 0, 0, 0, 3, 2, 11}, + }; + EXPECT_EQ(expected, actual); + + test_operator_plus(range); +} + +// Make sure nothing is thrown off by a size-1 dim in the output: +// [] -> [1, W] +// [] -> [H, 1] +// [1] -> [1, W] +// [1] -> [H, 1] +// [W] -> [1, W] +// [1, 1] -> [1, W] +// [1, 1] -> [H, 1] +// [1, W] -> [1, W] +// [H, 1] -> [H, 1] +TEST(BroadcastIndexesRangeTest, OneAndTwoDWith1InOutputShapeExhaustive) { + TensorFactory tf; + constexpr auto H = 2; + constexpr auto W = 3; + Tensor out_row = tf.zeros({1, W}); + Tensor out_col = tf.zeros({H, 1}); + Tensor in_0d_scalar = tf.zeros({}); + Tensor in_1d_scalar = tf.zeros({1}); + Tensor in_2d_scalar = tf.zeros({1, 1}); + + Tensor in_row = tf.zeros({W}); + Tensor in_leading_one_row = tf.zeros({1, W}); + + Tensor in_col = tf.zeros({H, 1}); + + size_t idx = 0; + const auto range_row = BroadcastIndexesRange<5>( + out_row, + in_0d_scalar, + in_1d_scalar, + in_2d_scalar, + in_row, + in_leading_one_row); + for (const auto + [out_idx, + in_0d_idx, + in_1d_idx, + in_2d_idx, + in_row_idx, + in_leading_one_row_idx] : range_row) { + EXPECT_EQ(out_idx, idx++); + EXPECT_EQ(in_0d_idx, 0); + EXPECT_EQ(in_1d_idx, 0); + EXPECT_EQ(in_2d_idx, 0); + EXPECT_EQ(in_row_idx, out_idx); + EXPECT_EQ(in_leading_one_row_idx, out_idx); + } + + test_operator_plus(range_row); + + idx = 0; + const auto range_col = BroadcastIndexesRange<4>( + out_col, in_0d_scalar, in_1d_scalar, in_2d_scalar, in_col); + for (const auto [out_idx, in_0d_idx, in_1d_idx, in_2d_idx, in_col_idx] : + range_col) { + EXPECT_EQ(out_idx, idx++); + EXPECT_EQ(in_0d_idx, 0); + EXPECT_EQ(in_1d_idx, 0); + EXPECT_EQ(in_2d_idx, 0); + EXPECT_EQ(in_col_idx, out_idx); + } + + test_operator_plus(range_col); +} + +// [1, 1, 1] -> [C, H, W] +// [C, H, 1] -> [C, H, W] +// [C, 1, W] -> [C, H, W] +// [1, H, W] -> [C, H, W] +// [C, 1, 1] -> [C, H, W] +// [1, H, 1] -> [C, H, W] +// [1, 1, W] -> [C, H, W] +// [C, H, W] -> [C, H, W] +TEST(BroadcastIndexesRangeTest, ThreeDBroadcasting) { + TensorFactory tf; + Tensor out = tf.zeros({2, 3, 4}); + std::array input_tensors = { + tf.zeros({2, 3, 1}), + tf.zeros({2, 1, 4}), + tf.zeros({1, 3, 4}), + tf.zeros({2, 1, 1}), + tf.zeros({1, 3, 1}), + tf.zeros({1, 1, 4}), + tf.zeros({1, 1, 1}), + tf.zeros({2, 3, 4}), + }; + // Writing out all the indexes would be too cumbersome, so here we + // take the opportunity to mutation test against delinearize_index + // and linearize_access_indexes. + int idx = 0; + const auto range = BroadcastIndexesRange<8>( + out, + input_tensors[0], + input_tensors[1], + input_tensors[2], + input_tensors[3], + input_tensors[4], + input_tensors[5], + input_tensors[6], + input_tensors[7]); + for (const auto indexes : range) { + const auto out_idx = indexes[0]; + EXPECT_EQ(out_idx, idx++); + size_t out_indexes[executorch::runtime::kTensorDimensionLimit]; + delinearize_index( + out_idx, out, out_indexes, executorch::runtime::kTensorDimensionLimit); + for (const auto tensor_idx : c10::irange(0, input_tensors.size())) { + EXPECT_EQ( + indexes[tensor_idx + 1], + linearize_access_indexes( + out_indexes, out.dim(), input_tensors[tensor_idx])); + } + } + test_operator_plus(range); +} + +// 4-D should generalize, but we will go ahead and test: +// [N, 1, H, 1] -> [N, C, H, W] +// [1, C, 1, W] -> [N, C, H, W] +template +void four_d_broadcasting_test() { + TensorFactory tf; + Tensor out = tf.zeros({N, C, H, W}); + Tensor in_broadcast_cw = tf.zeros({N, 1, H, 1}); + Tensor in_broadcast_nh = tf.zeros({1, C, 1, W}); + + // Writing out all the indexes would be too cumbersome, so here we + // take the opportunity to mutation test against delinearize_index + // and linearize_access_indexes. + int idx = 0; + const auto range = + BroadcastIndexesRange<2>(out, in_broadcast_cw, in_broadcast_nh); + for (const auto [out_idx, in_cw_idx, in_nh_idx] : range) { + EXPECT_EQ(out_idx, idx++); + size_t out_indexes[executorch::runtime::kTensorDimensionLimit]; + delinearize_index( + out_idx, out, out_indexes, executorch::runtime::kTensorDimensionLimit); + EXPECT_EQ( + in_cw_idx, + linearize_access_indexes(out_indexes, out.dim(), in_broadcast_cw)); + EXPECT_EQ( + in_nh_idx, + linearize_access_indexes(out_indexes, out.dim(), in_broadcast_nh)); + } + + test_operator_plus(range); +} + +TEST(BroadcastIndexesRangeTest, FourDBroadcasting) { + four_d_broadcasting_test<2, 3, 4, 5>(); +} + +TEST(BroadcastIndexesRangeTest, FourDBroadcastingWithOneDimsInOutput) { + four_d_broadcasting_test<2, 3, 1, 5>(); + four_d_broadcasting_test<2, 1, 3, 1>(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_test.cpp new file mode 100644 index 0000000..7ffd95b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/broadcast_test.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::ArrayRef; +using executorch::runtime::testing::TensorFactory; +using torch::executor::broadcast_tensor; +using torch::executor::delinearize_index; +using torch::executor::get_broadcast_target_size; +using torch::executor::linearize_access_indexes; +using torch::executor::tensor_is_broadcastable_to; +using torch::executor::tensors_are_broadcastable_between; + +TEST(BroadcastUtilTest, BroadcastTensor) { + TensorFactory tf; + + Tensor a = tf.make({1}, {2}); + Tensor b = tf.make({2, 2}, {2, 2, 2, 2}); + Tensor c = tf.zeros({2, 2}); + + Tensor d = torch::executor::broadcast_tensor(a, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); + + d = torch::executor::broadcast_tensor(b, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); +} + +TEST(BroadcastUtilTest, BroadcastableBetween) { + TensorFactory tf; + + std::vector tensor_list = { + tf.zeros({1, 2}), tf.zeros({2, 1}), tf.zeros({1}), tf.zeros({2, 2})}; + + for (int i = 0; i < 4; i++) { + for (int j = i + 1; j < 4; j++) { + EXPECT_TRUE( + tensors_are_broadcastable_between(tensor_list[i], tensor_list[j])); + } + } +} + +TEST(BroadcastUtilTest, BroadcastableToFrom) { + TensorFactory tf; + + Tensor a = tf.make({1, 2}, {2, 2}); + Tensor b = tf.make({2, 1}, {2, 2}); + Tensor c = tf.zeros({2, 2}); + + ASSERT_TRUE(tensor_is_broadcastable_to(a, c)); + Tensor d = torch::executor::broadcast_tensor(a, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); + + ASSERT_TRUE(tensor_is_broadcastable_to(b, c)); + d = torch::executor::broadcast_tensor(b, c); + EXPECT_TENSOR_DATA_EQ(d, tf.make({2, 2}, {2, 2, 2, 2})); + torch::executor::free_broadcast_tensor(d); +} + +TEST(BroadcastUtilTest, NotBroadcastableTo) { + TensorFactory tf; + + // Tensor a is broadcastable to tensor b means when tracing their sizes from + // back to front, each pair of corresponding dimensions should meet one of the + // following conditions: + // 1. the two dimensions are equal; + // 2. a's dimension is 1; + // 3. one of the dimensions does not exist. + Tensor a = tf.make({3}, {2, 2, 2}); + Tensor b = tf.zeros({2, 1}); + Tensor c = tf.zeros({1, 2}); + + ASSERT_FALSE(tensor_is_broadcastable_to(a, b)); + ET_EXPECT_DEATH(broadcast_tensor(a, b), ""); + + // Can not broadcast from b to c, though they are broadcastable. + // When broadcasting, b and c should be broadcasted to a new size (2, 2). + // Neither of them can be broadcasted to each other's size. + ASSERT_FALSE(tensor_is_broadcastable_to(b, c)); + ET_EXPECT_DEATH(broadcast_tensor(b, c), ""); +} + +TEST(BroadcastUtilTest, NotBroadcastableBetween) { + TensorFactory tf; + + Tensor a = tf.make({3}, {2, 2, 2}); + Tensor b = tf.zeros({2, 1}); + + EXPECT_FALSE(tensor_is_broadcastable_to(a, b)); +} + +TEST(BroadcastUtilTest, GetBroadcastTargetSize) { + TensorFactory tf; + Tensor::SizesType + expected_output_size[torch::executor::kTensorDimensionLimit] = {}; + size_t expected_output_dim = 0; + + Tensor a = tf.zeros({2, 1}); + Tensor b = tf.zeros({5, 1, 2}); + + executorch::runtime::Error err = get_broadcast_target_size( + a, + b, + expected_output_size, + torch::executor::kTensorDimensionLimit, + &expected_output_dim); + EXPECT_EQ(err, torch::executor::Error::Ok); + + EXPECT_TRUE( + ArrayRef(expected_output_size, expected_output_dim) + .equals(ArrayRef({5, 2, 2}))); + + Tensor c = tf.zeros({4, 5}); + et_pal_init(); + err = get_broadcast_target_size( + a, + c, + expected_output_size, + torch::executor::kTensorDimensionLimit, + &expected_output_dim); + EXPECT_EQ(err, torch::executor::Error::InvalidArgument); +} + +size_t linearize_indexes(size_t* indexes, size_t indexes_len, const Tensor& t) { + size_t linear_index = 0; + size_t acc_loop_counts = 1; + for (ssize_t i = indexes_len - 1; i >= 0; --i) { + linear_index += indexes[i] * acc_loop_counts; + acc_loop_counts *= (size_t)t.sizes()[i]; + } + return linear_index; +} + +TEST(BroadcastUtilTest, DelinearizeIndex) { + TensorFactory tf; + + const size_t DIMS = 3; + Tensor t = tf.zeros({4, 3, 5}); + auto sizes = t.sizes(); + + for (size_t i0 = 0; i0 < (size_t)sizes[0]; ++i0) { + for (size_t i1 = 0; i1 < (size_t)sizes[1]; ++i1) { + for (size_t i2 = 0; i2 < (size_t)sizes[2]; ++i2) { + size_t indexes[DIMS] = {i0, i1, i2}; + auto linear_index = linearize_indexes(indexes, DIMS, t); + + size_t out_indexes[DIMS]; + delinearize_index(linear_index, t, out_indexes, DIMS); + + EXPECT_EQ(linear_index, linearize_indexes(out_indexes, DIMS, t)); + } + } + } +} + +TEST(BroadcastUtilTest, LinearizeIndex) { + TensorFactory tf; + + Tensor broadcast_from = tf.zeros({2, 1, 3, 1}); + Tensor broadcast_to = tf.zeros({2, 2, 3, 4}); + + // The linear index for brodcast_from should be the same in + // the brocasted dimension. + for (size_t i = 0; i < 3; ++i) { + size_t test_indexes[] = {0, 0, 0, i}; + ArrayRef broadcast_to_indexes(test_indexes); + size_t linear_index = linearize_access_indexes( + broadcast_to_indexes, broadcast_to.dim(), broadcast_from); + EXPECT_EQ(linear_index, 0); + } + + // The linear index for brodcast_from should be the same. + // the brocasted dimension. + for (size_t i = 0; i <= 2; ++i) { + size_t test_indexes[] = {0, i, 2, 3}; + ArrayRef broadcast_to_indexes(test_indexes); + size_t linear_index = linearize_access_indexes( + broadcast_to_indexes, broadcast_to.dim(), broadcast_from); + EXPECT_EQ(linear_index, 2); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/reduce_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/reduce_test.cpp new file mode 100644 index 0000000..69e1093 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/reduce_test.cpp @@ -0,0 +1,583 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::testing::TensorFactory; +using std::optional; +using torch::executor::apply_over_dim; +using torch::executor::apply_over_dim_list; +using torch::executor::get_out_numel; + +void _apply_over_dim(const Tensor& in, const optional& dim) { + int64_t* in_data = in.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim); ++out_ix) { + apply_over_dim( + [in_data, out_ix](size_t in_ix, size_t _) { in_data[in_ix] = out_ix; }, + in, + dim, + out_ix); + } +} + +void _apply_over_dim_list( + const Tensor& in, + const optional>& dim_list) { + int64_t* in_data = in.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim_list); ++out_ix) { + apply_over_dim_list( + [in_data, out_ix](size_t in_ix) { in_data[in_ix] = out_ix; }, + in, + dim_list, + out_ix); + } +} + +TEST(ReduceUtilTest, ApplyOverDim) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + _apply_over_dim(in, 0); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + _apply_over_dim(in, 1); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_2[1] = {2}; + dim_list = optional>(ArrayRef{dim_array_2, 1}); + _apply_over_dim(in, 2); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + + 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, + 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, + 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, + 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_3[1] = {3}; + dim_list = optional>(ArrayRef{dim_array_3, 1}); + _apply_over_dim(in, 3); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + + 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, + 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, + 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListNull) { + TensorFactory tf; + optional> null_dim_list; + + Tensor in = tf.ones({2, 4, 5, 3}); + _apply_over_dim_list(in, null_dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({2, 4, 5, 3})); +} + +TEST(ReduceUtilTest, ApplyOverZeroDimListEmpty) { + TensorFactory tf; + optional> null_dim_list; + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, null_dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({})); +} + +TEST(ReduceUtilTest, ApplyOverZeroDim) { + TensorFactory tf; + optional> dim_list; + int64_t dim_array_0[1] = {0}; + dim_list = optional>(ArrayRef{dim_array_0, 1}); + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({})); +} + +TEST(ReduceUtilTest, ApplyOverDimListEmpty) { + TensorFactory tf; + optional> empty_dim_list{ArrayRef{}}; + + Tensor in = tf.ones({2, 4, 5, 3}); + _apply_over_dim_list(in, empty_dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({2, 4, 5, 3})); +} + +TEST(ReduceUtilTest, ApplyOverDimListLength1) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_0[1] = {0}; + dim_list = optional>(ArrayRef{dim_array_0, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_1[1] = {1}; + dim_list = optional>(ArrayRef{dim_array_1, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_2[1] = {2}; + dim_list = optional>(ArrayRef{dim_array_2, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + + 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, 12, 13, 14, + 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, 15, 16, 17, + 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, 18, 19, 20, + 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, 21, 22, 23, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_3[1] = {3}; + dim_list = optional>(ArrayRef{dim_array_3, 1}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + + 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, + 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, + 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListLength2) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_01[2] = {0, 1}; + dim_list = optional>(ArrayRef{dim_array_01, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_02[2] = {0, 2}; + dim_list = optional>(ArrayRef{dim_array_02, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8, + 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, 9, 10, 11, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_03[2] = {0, 3}; + dim_list = optional>(ArrayRef{dim_array_03, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_12[2] = {1, 2}; + dim_list = optional>(ArrayRef{dim_array_12, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_13[2] = {1, 3}; + dim_list = optional>(ArrayRef{dim_array_13, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_23[2] = {2, 3}; + dim_list = optional>(ArrayRef{dim_array_23, 2}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListLength3) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_012[3] = {0, 1, 2}; + dim_list = optional>(ArrayRef{dim_array_012, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_013[3] = {0, 1, 3}; + dim_list = optional>(ArrayRef{dim_array_013, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_023[3] = {0, 2, 3}; + dim_list = optional>(ArrayRef{dim_array_023, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + })); + // clang-format on + + in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_123[3] = {1, 2, 3}; + dim_list = optional>(ArrayRef{dim_array_123, 3}); + _apply_over_dim_list(in, dim_list); + // clang-format off + EXPECT_TENSOR_EQ(in, tf.make({2, 4, 5, 3}, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + })); + // clang-format on +} + +TEST(ReduceUtilTest, ApplyOverDimListLength4) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.ones({2, 4, 5, 3}); + int64_t dim_array_0123[4] = {0, 1, 2, 3}; + dim_list = optional>(ArrayRef{dim_array_0123, 4}); + _apply_over_dim_list(in, dim_list); + EXPECT_TENSOR_EQ(in, tf.zeros({2, 4, 5, 3})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDim) { + TensorFactory tf; + + Tensor in = tf.ones({}); + _apply_over_dim(in, 0); + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDimListNull) { + TensorFactory tf; + optional> null_dim_list; + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, null_dim_list); + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDimListEmpty) { + TensorFactory tf; + optional> empty_dim_list{ArrayRef{}}; + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, empty_dim_list); + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnZeroDimTensorOverDimListNonEmpty) { + TensorFactory tf; + int64_t dim_array_0[1] = {0}; + optional> dim_list = + optional>(ArrayRef{dim_array_0, 1}); + + Tensor in = tf.ones({}); + _apply_over_dim_list(in, dim_list), ""; + EXPECT_TENSOR_EQ(in, tf.make({}, {0})); +} + +TEST(ReduceUtilTest, ApplyOnEmptyTensorOverDim) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 0, 5, 3}); + Tensor out = tf.zeros({2, 5, 3}); + + // dim = 1 + int64_t dim = 1; + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(out.numel() == 30 && out.numel() == get_out_numel(in, dim)); + + int64_t* in_data = in.mutable_data_ptr(); + int64_t* out_data = out.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim); ++out_ix) { + out_data[out_ix] = 1; + apply_over_dim( + [in_data, out_data, out_ix](size_t in_ix, size_t _) { + in_data[in_ix] = out_ix; // Should be ignored. + out_data[out_ix] = 2; // Should be ignored. + }, + in, + dim, + out_ix); + } + EXPECT_TENSOR_EQ(out, tf.ones({2, 5, 3})); + + // dim = 0 + dim = 0; + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(get_out_numel(in, dim) == 0); + // Should die if called on empty tensor with dim that also produces + // empty tensor, because out_ix will be out of bounds + ET_EXPECT_DEATH( + apply_over_dim([](size_t in_ix, size_t _) { return; }, in, dim, 0), ""); +} + +TEST(ReduceUtilTest, ApplyOnEmptyTensorOverDimList) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 0, 5, 3}); + Tensor out = tf.zeros({5, 3}); + + // dim list = {0, 1} + int64_t dim_array_01[2] = {0, 1}; + dim_list = optional>(ArrayRef{dim_array_01, 2}); + + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(out.numel() == 15 && out.numel() == get_out_numel(in, dim_list)); + + int64_t* in_data = in.mutable_data_ptr(); + int64_t* out_data = out.mutable_data_ptr(); + for (size_t out_ix = 0; out_ix < get_out_numel(in, dim_list); ++out_ix) { + out_data[out_ix] = 1; + apply_over_dim_list( + [in_data, out_data, out_ix](size_t in_ix) { + in_data[in_ix] = out_ix; // Should be ignored. + out_data[out_ix] = 2; // Should be ignored. + }, + in, + dim_list, + out_ix); + } + EXPECT_TENSOR_EQ(out, tf.ones({5, 3})); + + // dim list = {0, 2} + int64_t dim_array_02[2] = {0, 2}; + dim_list = optional>(ArrayRef{dim_array_02, 2}); + + EXPECT_TRUE(in.numel() == 0); + EXPECT_TRUE(get_out_numel(in, dim_list) == 0); + // Should die if called on empty tensor with dim list that also produces + // empty tensor, because out_ix will be out of bounds + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); +} + +TEST(ReduceUtilTest, ApplyOverDimListInvalid) { + TensorFactory tf; + optional> dim_list; + + Tensor in = tf.zeros({2, 4, 5, 3}); + int64_t dim_array_09[2] = {0, 9}; + dim_list = optional>(ArrayRef{dim_array_09, 2}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); + + int64_t dim_array_neg[3] = {0, -5, 3}; + dim_list = optional>(ArrayRef{dim_array_neg, 3}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); + + int64_t dim_array_011[3] = {0, 1, 1}; + dim_list = optional>(ArrayRef{dim_array_011, 3}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); + + int64_t dim_array_1_3[2] = {1, -3}; + dim_list = optional>(ArrayRef{dim_array_1_3, 2}); + + ET_EXPECT_DEATH( + apply_over_dim_list([](size_t in_ix) { return; }, in, dim_list, 0), ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/targets.bzl new file mode 100644 index 0000000..69ca7d0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/targets.bzl @@ -0,0 +1,45 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + runtime.cxx_test( + name = "broadcast_test", + srcs = ["broadcast_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core:evalue", + "//executorch/kernels/portable/cpu/util:broadcast_util", + ], + ) + + runtime.cxx_test( + name = "broadcast_indexes_range_test", + srcs = ["broadcast_indexes_range_test.cpp"], + deps = [ + "//executorch/kernels/portable/cpu/util:broadcast_util", + "//executorch/kernels/portable/cpu/util:broadcast_indexes_range", + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ], + ) + + runtime.cxx_test( + name = "reduce_test", + srcs = ["reduce_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/kernels/portable/cpu/util:reduce_util", + ], + ) + + # this test requires ET_USE_PYTORCH_HEADERS, which doesn't work in OSS Buck. + if not runtime.is_oss: + runtime.cxx_test( + name = "vectorized_math_test", + srcs = ["vectorized_math_test.cpp"], + deps = [ + "//executorch/kernels/portable/cpu/util:vectorized_math", + "//executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/vectorized_math_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/vectorized_math_test.cpp new file mode 100644 index 0000000..6911598 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/test/vectorized_math_test.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +#include + +#ifndef ET_USE_PYTORCH_HEADERS +#error "This test requires ET_USE_PYTORCH_HEADERS!" +#endif // ET_USE_PYTORCH_HEADERS + +TEST(VectorizedMathTest, BasicUnary) { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto result_vec = executorch::math::exp(x_vec); + result_vec.store(result_floats); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_FLOAT_EQ(result_floats[ii], std::exp(ii)); + } +} + +namespace { +template +void test_unary_t_to_float() { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto result_vec = executorch::math::exp(x_vec); + static_assert(decltype(result_vec)::size() >= at::vec::Vectorized::size()); + result_vec.store(result_floats, at::vec::Vectorized::size()); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_FLOAT_EQ(result_floats[ii], std::exp((float)ii)) << ii; + } +} + +} // namespace + +TEST(VectorizedMathTest, UnaryInt16ToFloat) { + test_unary_t_to_float(); +} + +TEST(VectorizedMathTest, UnaryInt32ToFloat) { + test_unary_t_to_float(); +} + +TEST(VectorizedMathTest, UnaryInt64ToFloat) { + test_unary_t_to_float(); +} + +TEST(VectorizedMathTest, BasicBinary) { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto y_vec = at::vec::Vectorized(2); + const auto result_vec = executorch::math::pow(x_vec, y_vec); + result_vec.store(result_floats); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_FLOAT_EQ(result_floats[ii], std::pow((float)ii, 2.0f)); + } +} + +namespace { +template +void test_binary_t_to_float() { + __at_align__ float result_floats[at::vec::Vectorized::size()] = {0}; + const auto x_vec = at::vec::Vectorized::arange(0, 1); + const auto y_vec = at::vec::Vectorized(2); + const auto result_vec = executorch::math::pow(x_vec, y_vec); + static_assert(decltype(result_vec)::size() >= at::vec::Vectorized::size()); + result_vec.store(result_floats, at::vec::Vectorized::size()); + for (const auto ii : c10::irange(at::vec::Vectorized::size())) { + EXPECT_EQ(result_floats[ii], std::pow((float)ii, 2.0f)) << ii; + } +} + +TEST(VectorizedMathTest, BinaryInt16ToFloat) { + test_binary_t_to_float(); +} + +TEST(VectorizedMathTest, BinaryInt32ToFloat) { + test_binary_t_to_float(); +} + +TEST(VectorizedMathTest, BinaryInt64ToFloat) { + test_binary_t_to_float(); +} + +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/transpose_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/transpose_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/transpose_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/transpose_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/upsample_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/upsample_util.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/upsample_util.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/upsample_util.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/upsample_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/upsample_util.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/upsample_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/upsample_util.h index 6940c63..7ac1fec 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/util/upsample_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/upsample_util.h @@ -1,7 +1,6 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2026 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -9,8 +8,6 @@ #pragma once -#include - #include #include #include @@ -101,8 +98,8 @@ inline void guard_index_and_lambda( const int64_t& input_size, int64_t& input_index, scalar_t& lambda) { - input_index = std::min( - static_cast(std::floor(real_input_index)), input_size - 1); + input_index = + std::min(static_cast(floorf(real_input_index)), input_size - 1); lambda = std::min( std::max(real_input_index - input_index, static_cast(0)), static_cast(1)); @@ -143,8 +140,8 @@ inline int64_t nearest_neighbor_compute_source_index( int64_t input_size) { // Index computation matching OpenCV INTER_NEAREST // which is buggy and kept for BC - const int64_t src_index = std::min( - static_cast(std::floor(dst_index * scale)), input_size - 1); + const int64_t src_index = + std::min(static_cast(floorf(dst_index * scale)), input_size - 1); return src_index; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/vectorized_math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/vectorized_math.h similarity index 99% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/vectorized_math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/vectorized_math.h index f81236b..e67e862 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/util/vectorized_math.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/util/vectorized_math.h @@ -1,7 +1,6 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2026 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -15,6 +14,7 @@ #include #endif // ET_USE_PYTORCH_HEADERS +#include #include #if defined(ET_USE_PYTORCH_HEADERS) && ET_USE_PYTORCH_HEADERS diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/vec_ops.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/vec_ops.h similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/vec_ops.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/vec_ops.h index 16a9e93..87dd05a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/vec_ops.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/cpu/vec_ops.h @@ -1,7 +1,7 @@ /* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. - * Copyright 2024,2026 Arm Limited and/or its affiliates. + * Copyright 2024 Arm Limited and/or its affiliates. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include /** * @file @@ -177,7 +179,7 @@ template inline float vec_powerf(const T* x, size_t size) { float sum = 0; for (const auto i : c10::irange(size)) { - sum += static_cast(x[i]) * x[i]; + sum += x[i] * x[i]; } return sum; } @@ -199,7 +201,7 @@ inline void vec_softmax(T* ET_RESTRICT y, const U* ET_RESTRICT x, int n) { T sum = 0; for (const auto i : c10::irange(n)) { - y[i] = std::exp(x[i] - max_x); + y[i] = expf(x[i] - max_x); sum += y[i]; } @@ -228,7 +230,7 @@ inline void quantize_i8_f32( int32_t zero_point, size_t size) { for (const auto i : c10::irange(size)) { - float tmp = std::round(x[i] * scale + zero_point); + float tmp = roundf(x[i] * scale + zero_point); y[i] = internal::clamp(tmp, -128.f, 127.f); } } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/custom_ops.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/custom_ops.yaml similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/custom_ops.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/custom_ops.yaml diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/find_op_header.sh b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/find_op_header.sh new file mode 100755 index 0000000..9a38433 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/find_op_header.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -o errexit +set -o nounset +set -o pipefail + +# The directory containing this shell script, regardless of the CWD when it +# was invoked. +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" +readonly SCRIPT_DIR + +# The fbsource root that contains this script, even if it was run from xplat. +FBSOURCE_DIR="$(cd -- "${SCRIPT_DIR}" && hg root)" +readonly FBSOURCE_DIR + +# The buck target that generates the header file. +readonly GENRULE_TARGET='fbcode//executorch/kernels/portable:generated_lib_combined' + +# Prints the path to the generated NativeFunctions.h to stdout. +print_header_path() { + # buck2 will produce a line like + # fbcode//executorch/kernels/portable:generated_lib_combined[NativeFunctions.h] buck-out/v2/gen/fbcode/d839c731f5505c62/executorch/codegen/__generated_lib_combined__/out/NativeFunctions.h + # The sed command chops off everything before the space character. + # The relative path is relative to fbsource, so we print that first. + echo -n "${FBSOURCE_DIR}/" + ( + cd "${FBSOURCE_DIR}/fbcode" + buck2 build --show-output \ + "${GENRULE_TARGET}[NativeFunctions.h]" 2>&1 \ + | grep '/NativeFunctions.h' \ + | head -1 \ + | sed -e 's/.* //' + ) +} + +main() { + echo "===== Generating header files =====" + ( + cd "${FBSOURCE_DIR}/fbcode" + buck2 build "${GENRULE_TARGET}" + ) + echo "" + echo "Header file: $(print_header_path)" +} + +main "$@" diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/functions.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/functions.yaml similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/functions.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/functions.yaml index 620d97d..14dd949 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/functions.yaml +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/functions.yaml @@ -17,21 +17,11 @@ # See the README.md file in this directory for a description of the syntax used # by this file. -- op: _adaptive_avg_pool2d.out - kernels: - - arg_meta: null - kernel_name: torch::executor::_adaptive_avg_pool2d_out - - op: _cdist_forward.out kernels: - arg_meta: null kernel_name: torch::executor::_cdist_forward_out -- op: _conj_physical.out - kernels: - - arg_meta: null - kernel_name: torch::executor::_conj_physical_out - - op: _log_softmax.out kernels: - arg_meta: null @@ -1015,11 +1005,6 @@ - arg_meta: null kernel_name: torch::executor::var_correction_out -- op: var_mean.correction_out - kernels: - - arg_meta: null - kernel_name: torch::executor::var_mean_correction_out - - op: var.out kernels: - arg_meta: null @@ -1058,4 +1043,4 @@ - func: dim_order_ops::_clone_dim_order.out(Tensor self, *, bool non_blocking=False, int[]? dim_order=None, Tensor(a!) out) -> Tensor(a!) kernels: - arg_meta: null - kernel_name: torch::executor::_clone_dim_order_out + kernel_name: torch::executor::_clone_dim_order_out \ No newline at end of file diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/targets.bzl new file mode 100644 index 0000000..2c6e0b5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/targets.bzl @@ -0,0 +1,94 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "operators", + srcs = [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/kernels/portable/cpu:cpu", + ], + ) + + if True in get_aten_mode_options(): + runtime.cxx_library( + name = "operators_aten", + srcs = [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/kernels/portable/cpu:cpu_aten", + ], + ) + + runtime.export_file( + name = "functions.yaml", + visibility = ["PUBLIC"], + ) + + runtime.export_file( + name = "custom_ops.yaml", + visibility = ["PUBLIC"], + ) + + et_operator_library( + name = "executorch_all_ops", + include_all_operators = True, + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + et_operator_library( + name = "executorch_aten_ops", + ops_schema_yaml_target = "//executorch/kernels/portable:functions.yaml", + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + et_operator_library( + name = "executorch_custom_ops", + ops_schema_yaml_target = "//executorch/kernels/portable:custom_ops.yaml", + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + generated_lib_common_args = { + "custom_ops_yaml_target": "//executorch/kernels/portable:custom_ops.yaml", + # size_test expects _static targets to be available for these libraries. + "define_static_targets": True, + "functions_yaml_target": "//executorch/kernels/portable:functions.yaml", + "visibility": ["PUBLIC"], + } + + executorch_generated_lib( + name = "generated_lib", + deps = [ + ":executorch_aten_ops", + ":executorch_custom_ops", + ], + kernel_deps = ["//executorch/kernels/portable:operators"], + **generated_lib_common_args + ) + + if True in get_aten_mode_options(): + executorch_generated_lib( + name = "generated_lib_aten", + deps = [ + ":executorch_aten_ops", + ":executorch_custom_ops", + "//executorch/kernels/portable:operators_aten", + ], + custom_ops_aten_kernel_deps = [ + "//executorch/kernels/portable:operators_aten", + ], + custom_ops_yaml_target = "//executorch/kernels/portable:custom_ops.yaml", + aten_mode = True, + visibility = ["PUBLIC"], + define_static_targets = True, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/TARGETS new file mode 100644 index 0000000..44c5697 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/TARGETS @@ -0,0 +1,28 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +oncall("executorch") + +define_common_targets() + +runtime.cxx_library( + name = "aot_ops_test_lib", + srcs = [ + "register_ops_aot_for_test.cpp", + ], + visibility = ["PUBLIC"], + deps = [ + "//executorch/extension/aten_util:aten_bridge", + "//executorch/kernels/portable/cpu:op_grid_sampler_2d", + "//executorch/kernels/portable/cpu:op_upsample_bilinear2d", + "//executorch/kernels/portable/cpu:op_upsample_bilinear2d_aa", + "//executorch/kernels/portable/cpu:op_upsample_nearest2d", + "//executorch/runtime/core/exec_aten:lib", + ], + external_deps = [ + "libtorch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/dtype_selective_build_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/dtype_selective_build_test.cpp new file mode 100644 index 0000000..d536d90 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/dtype_selective_build_test.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using torch::executor::ScalarTypeToCppType; + +TEST(DtypeSelectiveBuildTest, UnknownOp) { + // Create a minimal context for error handling in ET_SWITCH + struct { + [[noreturn]] void fail(torch::executor::Error /* error */) { + ET_CHECK_MSG(false, "Unsupported dtype"); + } + } ctx; + ET_EXPECT_DEATH( + ET_SWITCH_TWO_TYPES( + Float, + Int, + executorch::aten::ScalarType::Float, + ctx, + "unknown.out", + // @lint-ignore CLANGTIDY clang-diagnostic-unused-local-typedef + CTYPE_OUT, + [&] { return true; }), + ""); +} + +TEST(DtypeSelectiveBuildTest, OpWithoutDtype) { + // Create a minimal context for error handling in ET_SWITCH + struct { + [[noreturn]] void fail(torch::executor::Error /* error */) { + ET_CHECK_MSG(false, "Unsupported dtype"); + } + } ctx; + ET_EXPECT_DEATH( + ET_SWITCH_TWO_TYPES( + Float, + Int, + executorch::aten::ScalarType::Int, + ctx, + "add.out", + // @lint-ignore CLANGTIDY clang-diagnostic-unused-local-typedef + CTYPE_OUT, + [&] { return true; }), + ""); +} + +TEST(DtypeSelectiveBuildTest, OpWithDtype) { + // Create a minimal context for error handling in ET_SWITCH + struct { + [[noreturn]] void fail(torch::executor::Error /* error */) { + ET_CHECK_MSG(false, "Unsupported dtype"); + } + } ctx; + ASSERT_EQ( + ET_SWITCH_TWO_TYPES( + Float, + Int, + executorch::aten::ScalarType::Float, + ctx, + "add.out", + // @lint-ignore CLANGTIDY clang-diagnostic-unused-local-typedef + CTYPE_OUT, + [&] { return true; }), + true); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_allclose_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_allclose_test.cpp new file mode 100644 index 0000000..99c08c3 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_allclose_test.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using torch::executor::native::allclose_out; +using torch::executor::testing::TensorFactory; + +const double default_atol{1e-08}; +const double default_rtol{1e-05}; + +class OpAllCloseTest : public OperatorTest { + protected: + template + void test_tensors_vary_tolerance( + double rtol, + double rdiff, + double atol, + double adiff, + bool should_match) { + TensorFactory tf; + Tensor a = tf.ones(/*sizes=*/{2, 2}); + Tensor b = tf.ones(/*sizes=*/{2, 2}); + + auto a_data = a.data_ptr(); + auto b_data = b.data_ptr(); + b_data[0] = a_data[0] + adiff + a_data[0] * rdiff; + + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + rtol, + atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], should_match) + << a_data[0] << " doesn't match " << b_data[0] << "; dtype " << DTYPE; + } +}; + +TEST_F(OpAllCloseTest, IdenticalFloatTensors) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + Tensor b = tf_float.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, IdenticalDoubleTensors) { + TensorFactory tf_double; + Tensor a = tf_double.ones(/*sizes=*/{2, 2}); + Tensor b = tf_double.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, NonEqualFloatTensors) { + TensorFactory tf_float; + Tensor a = tf_float.make(/*sizes=*/{2, 2}, /*data=*/{1., 2., 3., 4.}); + Tensor b = tf_float.make(/*sizes=*/{2, 2}, /*data=*/{5., 6., 7., 8.}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, NonEqualDoubleTensors) { + TensorFactory tf_double; + Tensor a = tf_double.make(/*sizes=*/{2, 2}, /*data=*/{1., 2., 3., 4.}); + Tensor b = tf_double.make(/*sizes=*/{2, 2}, /*data=*/{5., 6., 7., 8.}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, IdenticalIntTensors) { + TensorFactory tf_int; + Tensor a = tf_int.ones(/*sizes=*/{2, 2}); + Tensor b = tf_int.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, NonEqualIntTensors) { + TensorFactory tf_int; + Tensor a = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}); + Tensor b = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{5, 6, 7, 8}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, IdenticalBoolTensors) { + TensorFactory tf_bool; + Tensor a = tf_bool.ones(/*sizes=*/{2, 2}); + Tensor b = tf_bool.ones(/*sizes=*/{2, 2}); + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], true); +} + +TEST_F(OpAllCloseTest, NonEqualBoolTensors) { + TensorFactory tf_bool; + Tensor a = tf_bool.ones(/*sizes=*/{2, 2}); + Tensor b = tf_bool.ones(/*sizes=*/{2, 2}); + auto b_data = b.data_ptr(); + b_data[0] = false; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out); + auto out_data = out.data_ptr(); + EXPECT_EQ(out_data[0], false); +} + +TEST_F(OpAllCloseTest, MismatchedInputShapesDeath) { + TensorFactory tf_int; + Tensor a = tf_int.ones(/*sizes=*/{2, 1}); + Tensor b = tf_int.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, MismatchedInputDtypesDeath) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + + TensorFactory tf_int; + Tensor b = tf_int.ones(/*sizes=*/{2, 2}); + + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{1}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, IncorrectOutputDtypeDeath) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + Tensor b = tf_float.ones(/*sizes=*/{2, 2}); + Tensor out = tf_float.zeros(/*sizes=*/{1}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, IncorrectOutputShapeDeath) { + TensorFactory tf_float; + Tensor a = tf_float.ones(/*sizes=*/{2, 2}); + Tensor b = tf_float.ones(/*sizes=*/{2, 2}); + TensorFactory tf_bool; + Tensor out = tf_bool.zeros(/*sizes=*/{2, 2}); + + ET_EXPECT_DEATH( + allclose_out( + a, + b, + default_rtol, + default_atol, + /*equal_nan=*/false, + /*dummy_param=*/false, + out), + ""); +} + +TEST_F(OpAllCloseTest, TensorsVaryWithinRelativeTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance( \ + 1e-01, 1e-02, 0, 0, true); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryOutsideRelativeTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance(1e-01, 1, 0, 0, false); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryWithinAbsoluteTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance( \ + 0, 0, 1e-01, 1e-02, true); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryOutsideAbsoluteTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance(0, 0, 1e-01, 1, false); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST_F(OpAllCloseTest, TensorsVaryWithZeroTolerance) { +#define TEST_ENTRY(ctype, dtype) \ + test_tensors_vary_tolerance(0, 0, 0, 1e-01, false); + ET_FORALL_FLOATHBF16_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_div_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_div_test.cpp new file mode 100644 index 0000000..dec78af --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_div_test.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::StridesType; +using executorch::aten::Tensor; +using torch::executor::testing::TensorFactory; + +// Note: This file is used for testing op_div for *portable kernel specific*. +// If your test case is generic and should be tested on all kernels, add it to +// executorch/kernels/test/op_div_test.cpp instead. + +class OpDivScalarOutKernelTest : public OperatorTest { + protected: + Tensor& op_div_out_mode( + const Tensor& a, + const Tensor& b, + std::optional mode, + Tensor& out) { + return torch::executor::aten::div_outf(context_, a, b, mode, out); + } +}; + +class OpDivScalarModeOutKernelTest : public OperatorTest { + protected: + Tensor& op_div_scalar_mode_out( + const Tensor& a, + const Scalar& b, + std::optional mode, + Tensor& out) { + return torch::executor::aten::div_outf(context_, a, b, mode, out); + } +}; + +TEST_F(OpDivScalarOutKernelTest, SanityCheckModeTrunc) { + TensorFactory tf_a; + TensorFactory tf_out; + + const std::vector sizes = {2, 2}; + + Tensor out = tf_out.zeros(sizes); + + op_div_out_mode( + tf_a.make(sizes, {1, 2, 4, -9}), + tf_a.make(sizes, {2, 2, 2, 2}), + std::optional("trunc"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf_out.make(sizes, {0.0, 1.0, 2.0, -4.0})); +} + +TEST_F(OpDivScalarOutKernelTest, SanityCheckModeFloor) { + TensorFactory tf_a; + TensorFactory tf_out; + + const std::vector sizes = {2, 2}; + + Tensor out = tf_out.zeros(sizes); + + op_div_out_mode( + tf_a.make(sizes, {1, 2, 4, -9}), + tf_a.make(sizes, {2, 2, 2, 2}), + std::optional("floor"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf_out.make(sizes, {0.0, 1.0, 2.0, -5.0})); +} + +TEST_F(OpDivScalarModeOutKernelTest, SanityCheckModeTrunc) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + Tensor out = tf.zeros(sizes); + + op_div_scalar_mode_out( + tf.make(sizes, {1, 2, 4, -9}), + 2, + std::optional("trunc"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf.make(sizes, {0, 1, 2, -4})); +} + +TEST_F(OpDivScalarModeOutKernelTest, SanityCheckModeFloor) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + Tensor out = tf.zeros(sizes); + + op_div_scalar_mode_out( + tf.make(sizes, {1, 2, 4, -9}), + 2, + std::optional("floor"), + out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf.make(sizes, {0, 1, 2, -5})); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_gelu_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_gelu_test.cpp new file mode 100644 index 0000000..fa663f8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_gelu_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using std::string_view; +using torch::executor::testing::TensorFactory; + +// Note: This file is used for testing op_gelu for *portable kernel specific*. +// If your test case is generic and should be tested on all kernels, add it to +// executorch/kernels/test/op_gelu_test.cpp instead. + +Tensor& +op_gelu_out(const Tensor& self, std::string_view approximate, Tensor& out) { + executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext context{}; + return torch::executor::native::gelu_out(context, self, approximate, out); +} + +TEST(OpGeluKernelTest, HandleInfAndNanInput) { + TensorFactory tf; + + const std::vector sizes = {3, 2}; + + Tensor in = tf.make( + sizes, + /*data=*/ + {-0.4775, + -std::numeric_limits::infinity(), + -0.3984, + NAN, + std::numeric_limits::infinity(), + -0.4848}); + + // Destination for the gelu. + Tensor out = tf.zeros(sizes); + + // Run full gelu. + op_gelu_out(in, "none", out); + + // Check that it matches the expected output. + EXPECT_TENSOR_CLOSE( + out, + tf.make( + sizes, + /*data=*/ + {-0.15113, 0.0, -0.137515, NAN, INFINITY, -0.152183})); + + // Run tanh gelu appx. + op_gelu_out(in, "tanh", out); + + // Check that it matches the expected output. + EXPECT_TENSOR_CLOSE( + out, + tf.make( + sizes, + /*data=*/ + {-0.151145, 0.0, -0.137522, NAN, INFINITY, -0.152199})); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_grid_sampler_2d_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_grid_sampler_2d_test.py new file mode 100644 index 0000000..4791da5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_grid_sampler_2d_test.py @@ -0,0 +1,234 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import itertools +import unittest + +import torch + + +class GridSampler2dTest(unittest.TestCase): + def run_grid_sampler_test( + self, + inp: torch.Tensor, + grid: torch.Tensor, + mode: str = "bilinear", + padding_mode: str = "zeros", + align_corners: bool = False, + atol: float = 1e-5, + ) -> None: + """Test grid_sampler_2d against PyTorch's reference implementation.""" + # PyTorch reference + aten_result = torch.nn.functional.grid_sample( + inp, + grid, + mode=mode, + padding_mode=padding_mode, + align_corners=align_corners, + ) + + # Convert mode strings to integers for et_test + mode_map = {"bilinear": 0, "nearest": 1, "bicubic": 2} + padding_map = {"zeros": 0, "border": 1, "reflection": 2} + + # ExecuTorch implementation + et_result = torch.zeros_like(aten_result) + et_result = torch.ops.et_test.grid_sampler_2d( + inp, + grid, + interpolation_mode=mode_map[mode], + padding_mode=padding_map[padding_mode], + align_corners=align_corners, + out=et_result, + ) + + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol, rtol=1e-5), + msg=f"Mode: {mode}, Padding: {padding_mode}, Align: {align_corners}\n" + f"ET: {et_result}\n" + f"ATen: {aten_result}\n" + f"Error: {(et_result.to(torch.float) - aten_result.to(torch.float)).abs().max()}", + ) + + def test_grid_sampler_2d_all_modes_f32(self): + """Test all combinations of interpolation, padding, and align_corners.""" + N = [1, 2] + C = [1, 3] + H_IN = [4, 8] + W_IN = [4, 8] + H_OUT = [3, 6] + W_OUT = [3, 6] + MODES = ["bilinear", "nearest", "bicubic"] + PADDING_MODES = ["zeros", "border", "reflection"] + ALIGN_CORNERS = [True, False] + + for ( + n, + c, + h_in, + w_in, + h_out, + w_out, + mode, + padding_mode, + align_corners, + ) in itertools.product( + N, C, H_IN, W_IN, H_OUT, W_OUT, MODES, PADDING_MODES, ALIGN_CORNERS + ): + # Create input tensor + input_tensor = torch.randn(n, c, h_in, w_in, dtype=torch.float32) + + # Create grid with coordinates in [-1, 1] + grid = torch.randn(n, h_out, w_out, 2, dtype=torch.float32) + # Normalize grid to [-1, 1] range + grid = torch.clamp(grid, -2, 2) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode=mode, + padding_mode=padding_mode, + align_corners=align_corners, + atol=1e-4, # Slightly relaxed tolerance for bicubic + ) + + def test_grid_sampler_2d_bilinear_specific_cases(self): + """Test bilinear mode with specific edge cases.""" + # Test with identity grid (should return same as input) + input_tensor = torch.randn(1, 3, 4, 4) + y = torch.linspace(-1, 1, 4) + x = torch.linspace(-1, 1, 4) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bilinear", + padding_mode="zeros", + align_corners=True, + ) + + def test_grid_sampler_2d_nearest_specific_cases(self): + """Test nearest mode with specific patterns.""" + # Create a checkerboard pattern + input_tensor = torch.zeros(1, 1, 4, 4) + input_tensor[0, 0, ::2, ::2] = 1.0 + input_tensor[0, 0, 1::2, 1::2] = 1.0 + + # Sample at grid points + y = torch.linspace(-1, 1, 6) + x = torch.linspace(-1, 1, 6) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="nearest", + padding_mode="zeros", + align_corners=False, + ) + + def test_grid_sampler_2d_padding_modes(self): + """Test different padding modes with out-of-bounds coordinates.""" + input_tensor = torch.randn(1, 2, 5, 5) + + # Create grid with some out-of-bounds coordinates + grid = torch.tensor( + [ + [ + [[-1.5, -1.5], [-0.5, -0.5], [0.5, 0.5], [1.5, 1.5]], + [[-1.0, 1.5], [0.0, 0.0], [1.0, -1.5], [2.0, 2.0]], + ] + ], + dtype=torch.float32, + ) + + for padding_mode in ["zeros", "border", "reflection"]: + for align_corners in [True, False]: + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bilinear", + padding_mode=padding_mode, + align_corners=align_corners, + ) + + def test_grid_sampler_2d_bicubic_smoothness(self): + """Test bicubic interpolation for smooth gradients.""" + # Create a smooth gradient + input_tensor = torch.arange(16, dtype=torch.float32).reshape(1, 1, 4, 4) + + # Create a fine grid for upsampling + y = torch.linspace(-1, 1, 7) + x = torch.linspace(-1, 1, 7) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bicubic", + padding_mode="zeros", + align_corners=True, + atol=1e-4, + ) + + def test_grid_sampler_2d_align_corners_comparison(self): + """Compare align_corners=True vs False.""" + input_tensor = torch.randn(1, 1, 8, 8) + + # Create grid at corner positions + grid = torch.tensor( + [ + [ + [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0]], + ] + ], + dtype=torch.float32, + ) + + for mode in ["bilinear", "nearest", "bicubic"]: + # Test with align_corners=True + self.run_grid_sampler_test( + input_tensor, + grid, + mode=mode, + padding_mode="zeros", + align_corners=True, + ) + + # Test with align_corners=False + self.run_grid_sampler_test( + input_tensor, + grid, + mode=mode, + padding_mode="zeros", + align_corners=False, + ) + + def test_grid_sampler_2d_batch_processing(self): + """Test with multiple batches.""" + batch_sizes = [1, 2, 4] + for batch_size in batch_sizes: + input_tensor = torch.randn(batch_size, 3, 6, 6) + grid = torch.randn(batch_size, 4, 4, 2) + grid = torch.clamp(grid, -1.5, 1.5) + + self.run_grid_sampler_test( + input_tensor, + grid, + mode="bilinear", + padding_mode="border", + align_corners=False, + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_mul_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_mul_test.cpp new file mode 100644 index 0000000..0827f8d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_mul_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::StridesType; +using executorch::aten::Tensor; +using torch::executor::testing::TensorFactory; + +// Note: This file is used for testing op_mul for *portable kernel specific*. +// If your test case is generic and should be tested on all kernels, add it to +// executorch/kernels/test/op_mul_test.cpp instead. + +class OpMulOutKernelTest : public OperatorTest { + protected: + Tensor& mul_out(const Tensor& self, const Tensor& other, Tensor& out) { + return torch::executor::native::mul_out(context_, self, other, out); + } +}; + +TEST_F(OpMulOutKernelTest, UnhandledDtypeDies) { + // mul_out() doesn't handle QInt8. + // TensorFactory cannot be used with ScalarType::QInt8 since + // executorch::aten::qint8 does not have a default constructor. It must be + // initialized with an explicit value. So, we need to manually create the + // underlying data without default construction and then the tensors from that + // data via TensorImpl. + + std::vector sizes = {2, 2}; + + std::vector a_data{}; + std::generate_n(std::back_inserter(a_data), 4, []() { + return executorch::aten::qint8{0}; + }); + std::vector b_data(a_data); + std::vector out_data(a_data); + + std::vector dim_order = {0, 1}; + + auto a_impl = torch::executor::TensorImpl( + ScalarType::QInt8, 2, sizes.data(), a_data.data(), dim_order.data()); + auto b_impl = torch::executor::TensorImpl( + ScalarType::QInt8, 2, sizes.data(), b_data.data(), dim_order.data()); + auto out_impl = torch::executor::TensorImpl( + ScalarType::QInt8, 2, sizes.data(), out_data.data(), dim_order.data()); + + // Two input tensors. + Tensor a(&a_impl); + Tensor b(&b_impl); + + // Output tensor. + Tensor out(&out_impl); + + // Multiplying the two QInt8 tensors should cause an assertion and + // kill the test process. + ET_EXPECT_KERNEL_FAILURE(context_, mul_out(a, b, out)); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_aa_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_aa_test.py new file mode 100644 index 0000000..f86aa35 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_aa_test.py @@ -0,0 +1,346 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +# NOTE: This test file follows the structure of op_upsample_bilinear2d_test.py +# but requires et_test namespace setup to run the actual ExecuTorch implementation. +# The comprehensive C++ test suite in op_upsample_bilinear2d_aa_test.cpp provides +# complete validation of the anti-aliased bilinear upsampling implementation. + +import unittest + +from typing import Optional, Sequence + +import torch + + +class UpsampleBilinear2dAATest(unittest.TestCase): + def run_upsample_aa_test( + self, + inp: torch.Tensor, + output_size: Optional[Sequence[int]] = None, + align_corners: bool = False, + scale_factors: Optional[Sequence[float]] = None, + atol=1e-4, + ) -> None: + """Test our ExecuTorch anti-aliased bilinear upsampling against PyTorch reference.""" + # PyTorch reference with anti-aliasing + aten_result = torch.nn.functional.interpolate( + inp, + size=output_size, + mode="bilinear", + scale_factor=scale_factors, + align_corners=align_corners, + antialias=True, + ) + + # Our ExecuTorch implementation via et_test namespace + # NOTE: Requires proper et_test namespace setup + et_result = torch.zeros_like(aten_result) + + # Compute output_size from scale_factors if needed + actual_output_size = output_size + scale_h = None + scale_w = None + + if output_size is None and scale_factors is not None: + # Compute output size from input size and scale factors + input_h, input_w = inp.shape[-2:] + output_h = int(input_h * scale_factors[0]) + output_w = int(input_w * scale_factors[1]) + actual_output_size = [output_h, output_w] + scale_h = scale_factors[0] + scale_w = scale_factors[1] + + # Ensure actual_output_size is never None + if actual_output_size is None: + raise ValueError("Either output_size or scale_factors must be provided") + + # Ensure actual_output_size is a list of integers + actual_output_size = [int(x) for x in actual_output_size] + + et_result = torch.ops.et_test._upsample_bilinear2d_aa( + inp, + actual_output_size, + align_corners, + scale_h, + scale_w, + out=et_result, + ) + + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol), + msg=f"ET: {et_result} \n ATen: {aten_result} \n Error: {et_result.to(torch.float) - aten_result.to(torch.float)}", + ) + + def test_upsample_bilinear2d_aa_basic_functionality(self): + """Test basic functionality - function calls work and produce reasonable outputs.""" + # Simple 2x2 -> 4x4 upsampling test to verify function signature fix + input_tensor = torch.randn(1, 1, 2, 2) + + # Test with output_size - this should work if function signature is fixed + try: + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), + align_corners=False, + atol=1e-3, # Relaxed tolerance for basic functionality test + ) + print("✓ Function call with output_size works") + except RuntimeError as e: + if "missing value for argument" in str(e): + self.fail(f"Function signature issue not fixed: {e}") + else: + raise + + # Test with scale_factors - this should also work + try: + self.run_upsample_aa_test( + input_tensor, + scale_factors=(2.0, 2.0), + align_corners=False, + atol=1e-3, # Relaxed tolerance for basic functionality test + ) + print("✓ Function call with scale_factors works") + except RuntimeError as e: + if "missing value for argument" in str(e): + self.fail(f"Function signature issue not fixed: {e}") + else: + raise + + def test_upsample_bilinear2d_aa_aten_parity_f32(self): + """Test float32 parity with PyTorch's anti-aliased implementation.""" + # Simplified test with just one case for debugging + input_tensor = torch.randn(1, 1, 2, 2) + self.run_upsample_aa_test(input_tensor, output_size=(4, 4), align_corners=False) + + def test_upsample_bilinear2d_aa_aten_parity_u8(self): + """Test uint8 parity with PyTorch's anti-aliased implementation.""" + # Simplified test with just one case for debugging + input_tensor = torch.randint(0, 255, (1, 1, 2, 2), dtype=torch.uint8) + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), + align_corners=False, + atol=3.5, # Relaxed tolerance for uint8 due to implementation differences in anti-aliasing + ) + + def test_upsample_bilinear2d_aa_downsampling(self): + """Test downsampling with anti-aliasing - key differentiator from regular bilinear.""" + # 8x8 -> 4x4 downsampling where anti-aliasing should have significant effect + input_tensor = torch.randn(1, 2, 8, 8) + self.run_upsample_aa_test( + input_tensor, output_size=(4, 4), align_corners=False, atol=1e-3 + ) + + def test_upsample_bilinear2d_aa_aggressive_downsampling(self): + """Test aggressive downsampling (8x8 -> 2x2) where anti-aliasing is most important.""" + input_tensor = torch.randn(1, 1, 8, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(2, 2), + align_corners=False, + atol=0.4, # Relaxed tolerance due to implementation differences in separable vs direct interpolation + ) + + def test_upsample_bilinear2d_aa_asymmetric_downsampling(self): + """Test asymmetric downsampling (different scale factors for H and W).""" + input_tensor = torch.randn(1, 2, 12, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), # 3x downsample in H, 2x in W + align_corners=False, + atol=0.25, # Relaxed tolerance due to implementation differences in separable vs direct interpolation + ) + + def test_upsample_bilinear2d_aa_align_corners_upsampling(self): + """Test align_corners=True with upsampling.""" + input_tensor = torch.randn(1, 1, 3, 3) + self.run_upsample_aa_test( + input_tensor, + output_size=(6, 6), + align_corners=True, + atol=1e-3, # Keep tight tolerance for upsampling which works well + ) + + def test_upsample_bilinear2d_aa_align_corners_downsampling(self): + """Test align_corners=True with downsampling.""" + input_tensor = torch.randn(1, 1, 8, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(4, 4), + align_corners=True, + atol=0.25, # Relaxed tolerance due to implementation differences in separable vs direct interpolation + ) + + def test_upsample_bilinear2d_aa_batched(self): + """Test batched inputs.""" + input_tensor = torch.randn(3, 4, 6, 6) + self.run_upsample_aa_test( + input_tensor, + output_size=(3, 3), # Downsampling + align_corners=False, + atol=1e-3, + ) + + def test_upsample_bilinear2d_aa_identity_transform(self): + """Test that same input/output size preserves values (identity transform).""" + input_tensor = torch.randn(1, 2, 4, 4) + self.run_upsample_aa_test( + input_tensor, output_size=(4, 4), align_corners=False, atol=1e-3 + ) + + def test_upsample_bilinear2d_aa_edge_case_1x1(self): + """Test edge case with 1x1 input.""" + input_tensor = torch.randn(1, 3, 1, 1) + self.run_upsample_aa_test( + input_tensor, output_size=(4, 4), align_corners=False, atol=1e-3 + ) + + def test_upsample_bilinear2d_aa_edge_case_to_1x1(self): + """Test edge case downsampling to 1x1.""" + input_tensor = torch.randn(1, 2, 8, 8) + self.run_upsample_aa_test( + input_tensor, + output_size=(1, 1), + align_corners=False, + atol=0.6, # Higher tolerance for 1x1 edge case due to significant implementation differences + ) + + def test_upsample_bilinear2d_aa_fractional_scaling(self): + """Test non-integer scale factors.""" + input_tensor = torch.randn(1, 1, 5, 7) + self.run_upsample_aa_test( + input_tensor, + output_size=(8, 10), # Non-integer scaling + align_corners=False, + atol=1e-3, + ) + + def test_upsample_bilinear2d_aa_known_values_correctness(self): + """Test against known correct output values to catch regressions.""" + # This test case is adapted from ATen's test suite + input_tensor = torch.arange(3 * 8 * 8, dtype=torch.float).reshape(1, 3, 8, 8) + + # Test with a known downsampling case + try: + self.run_upsample_aa_test( + input_tensor, + output_size=(2, 2), + align_corners=False, + atol=1e-2, # Slightly relaxed for implementation differences + ) + # The test should pass if our implementation is close to ATen + except AssertionError as e: + # Log the difference for debugging but don't fail the test during development + print(f"Known values test difference (expected during development): {e}") + + def test_upsample_bilinear2d_aa_various_dtypes(self): + """Test with various data types.""" + test_cases = [ + (torch.float32, 1e-3), + (torch.float64, 1e-6), + ] + + for dtype, atol in test_cases: + with self.subTest(dtype=dtype): + input_tensor = torch.randn(1, 2, 6, 6, dtype=dtype) + self.run_upsample_aa_test( + input_tensor, output_size=(3, 3), align_corners=False, atol=atol + ) + + def test_upsample_bilinear2d_aa_scale_factors_vs_output_size(self): + """Test that scale_factors and equivalent output_size give same results.""" + input_tensor = torch.randn(1, 2, 4, 6) + + # Test with scale factors + try: + result1 = torch.zeros(1, 2, 8, 12) + result1 = torch.ops.et_test._upsample_bilinear2d_aa( + input_tensor, + [8, 12], # output_size equivalent to 2x scale + False, # align_corners + 2.0, # scale_h + 2.0, # scale_w + out=result1, + ) + + # Test with output_size + result2 = torch.zeros(1, 2, 8, 12) + result2 = torch.ops.et_test._upsample_bilinear2d_aa( + input_tensor, + [8, 12], # output_size + False, # align_corners + None, # scale_h + None, # scale_w + out=result2, + ) + + # Results should be identical + self.assertTrue( + torch.allclose(result1, result2, atol=1e-5), + "Scale factors and output_size should give identical results", + ) + except RuntimeError as e: + # Skip this test if et_test namespace setup issues persist + print(f"Skipping scale factors test due to: {e}") + + def test_upsample_bilinear2d_aa_extreme_scale_factors(self): + """Test the specific case that exposed the segfault bug with extreme scale factors.""" + # Create input tensor with same data as C++ test to ensure consistency + input_tensor = torch.zeros(8, 2, 7, 1, dtype=torch.float32) + for i in range(8 * 2 * 7 * 1): + input_tensor.view(-1)[i] = i * 0.1 + + # Test the specific case that caused segfault before the fix + self.run_upsample_aa_test( + input_tensor, + output_size=[7, 2], + align_corners=False, + scale_factors=None, # Use explicit scale factors via direct call + atol=1e-2, # Relaxed tolerance for extreme scale factors + ) + + # Also test with direct ExecuTorch call using the extreme scale factors + try: + et_result = torch.zeros(8, 2, 7, 2, dtype=torch.float32) + et_result = torch.ops.et_test._upsample_bilinear2d_aa( + input_tensor, + [7, 2], # output_size + False, # align_corners + 0.010000000000000002, # scales_h (very small) + 10.0, # scales_w (very large) + out=et_result, + ) + + # Verify no NaN or Inf values (the bug would cause these) + self.assertFalse( + torch.isnan(et_result).any().item(), + "Output should not contain NaN values after bug fix", + ) + self.assertFalse( + torch.isinf(et_result).any().item(), + "Output should not contain Inf values after bug fix", + ) + + # Verify reasonable output values + self.assertTrue( + et_result.min().item() >= -100.0, + "Output values should be reasonable (not extremely negative)", + ) + self.assertTrue( + et_result.max().item() <= 100.0, + "Output values should be reasonable (not extremely positive)", + ) + + except RuntimeError as e: + # Skip the direct test if et_test namespace setup issues persist + print(f"Skipping direct extreme scale factors test due to: {e}") + + +if __name__ == "__main__": + unittest.main() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_test.py new file mode 100644 index 0000000..6760920 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_bilinear2d_test.py @@ -0,0 +1,87 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import itertools +import unittest + +from typing import Optional, Sequence + +import torch + + +class UpsampleBilinear2dTest(unittest.TestCase): + def run_upsample_test( + self, + inp: torch.Tensor, + output_size: Optional[Sequence[int]] = None, + align_corners: bool = False, + scale_factors: Optional[Sequence[float]] = None, + atol=2e-7, + ) -> None: + aten_result = torch.nn.functional.interpolate( + inp, + size=output_size, + mode="bilinear", + scale_factor=scale_factors, + align_corners=align_corners, + ) + et_result = torch.zeros_like(aten_result) + et_result = torch.ops.et_test.upsample_bilinear2d( + inp, + output_size=output_size, + scale_factors=scale_factors, + align_corners=align_corners, + out=et_result, + ) + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol), + msg=f"ET: {et_result} \n ATen: {aten_result} \n Error: {et_result.to(torch.float) - aten_result.to(torch.float)}", + ) + + def test_upsample_bilinear2d_aten_parity_f32(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + ALIGN_CORNERS = [True, False] + + for n, c, h, w, out_h, out_w, align_corners in itertools.product( + N, C, H, W, OUT_H, OUT_W, ALIGN_CORNERS + ): + input = torch.randn(n, c, h, w) + self.run_upsample_test( + input, output_size=(out_h, out_w), align_corners=align_corners + ) + self.run_upsample_test( + input, scale_factors=(out_h / h, out_w / w), align_corners=align_corners + ) + + def test_upsample_bilinear2d_aten_parity_u8(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + ALIGN_CORNERS = [True, False] + + for n, c, h, w, out_h, out_w, align_corners in itertools.product( + N, C, H, W, OUT_H, OUT_W, ALIGN_CORNERS + ): + input = torch.randint(0, 255, (n, c, h, w), dtype=torch.uint8) + self.run_upsample_test( + input, output_size=(out_h, out_w), align_corners=align_corners, atol=2 + ) + self.run_upsample_test( + input, + scale_factors=(out_h / h, out_w / w), + align_corners=align_corners, + atol=2, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_nearest2d_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_nearest2d_test.py new file mode 100644 index 0000000..23a6bb5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/op_upsample_nearest2d_test.py @@ -0,0 +1,71 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import itertools +import unittest + +from typing import Optional, Sequence + +import torch + + +class UpsampleNearest2dTest(unittest.TestCase): + def run_upsample_test( + self, + inp: torch.Tensor, + output_size: Optional[Sequence[int]] = None, + scale_factors: Optional[Sequence[float]] = None, + atol=1e-7, + ) -> None: + aten_result = torch.nn.functional.interpolate( + inp, + size=output_size, + mode="nearest", + scale_factor=scale_factors, + ) + et_result = torch.zeros_like(aten_result) + et_result = torch.ops.et_test.upsample_nearest2d( + inp, + output_size=output_size, + scale_factors=scale_factors, + out=et_result, + ) + self.assertTrue( + torch.allclose(et_result, aten_result, atol=atol), + msg=f"ET: {et_result} \n ATen: {aten_result} \n Error: {et_result.to(torch.float) - aten_result.to(torch.float)}", + ) + + def test_upsample_nearest2d_aten_parity_f32(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + + for n, c, h, w, out_h, out_w in itertools.product(N, C, H, W, OUT_H, OUT_W): + input = torch.randn(n, c, h, w) + self.run_upsample_test(input, output_size=(out_h, out_w)) + self.run_upsample_test(input, scale_factors=(out_h / h, out_w / w)) + + def test_upsample_nearest2d_aten_parity_u8(self): + N = [1, 2] + C = [1, 3] + H = [1, 3, 50, 1001] + W = [1, 2, 62, 1237] + OUT_H = [5, 21] + OUT_W = [7, 31] + + for n, c, h, w, out_h, out_w in itertools.product(N, C, H, W, OUT_H, OUT_W): + input = torch.randint(0, 255, (n, c, h, w), dtype=torch.uint8) + self.run_upsample_test(input, output_size=(out_h, out_w), atol=1) + self.run_upsample_test( + input, + scale_factors=(out_h / h, out_w / w), + atol=2, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/register_ops_aot_for_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/register_ops_aot_for_test.cpp new file mode 100644 index 0000000..cee7a56 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/register_ops_aot_for_test.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +namespace torch { +namespace executor { + +namespace native { + +// Signatures are auto-generated, so disable pass-by-value lint. +// NOLINTBEGIN(facebook-hte-ConstantArgumentPassByValue, +// facebook-hte-ParameterMightThrowOnCopy) +Tensor& upsample_bilinear2d_vec_out( + KernelRuntimeContext& ctx, + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + bool align_corners, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out); + +Tensor& upsample_bilinear2d_vec_out_no_context( + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + bool align_corners, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = upsample_bilinear2d_vec_out( + ctx, in, output_size, align_corners, scale_factors, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} + +Tensor& upsample_nearest2d_vec_out( + KernelRuntimeContext& ctx, + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out); + +Tensor& upsample_nearest2d_vec_out_no_context( + const Tensor& in, + const executorch::aten::OptionalArrayRef output_size, + const executorch::aten::OptionalArrayRef scale_factors, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = + upsample_nearest2d_vec_out(ctx, in, output_size, scale_factors, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} + +Tensor& _upsample_bilinear2d_aa_out( + KernelRuntimeContext& ctx, + const Tensor& in, + const executorch::aten::ArrayRef output_size, + bool align_corners, + const std::optional scale_h, + const std::optional scale_w, + Tensor& out); + +Tensor& _upsample_bilinear2d_aa_out_no_context( + const Tensor& in, + const executorch::aten::ArrayRef output_size, + bool align_corners, + const std::optional scale_h, + const std::optional scale_w, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = _upsample_bilinear2d_aa_out( + ctx, in, output_size, align_corners, scale_h, scale_w, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} + +Tensor& grid_sampler_2d_out( + KernelRuntimeContext& ctx, + const Tensor& input, + const Tensor& grid, + int64_t interpolation_mode, + int64_t padding_mode, + bool align_corners, + Tensor& out); + +Tensor& grid_sampler_2d_out_no_context( + const Tensor& input, + const Tensor& grid, + int64_t interpolation_mode, + int64_t padding_mode, + bool align_corners, + Tensor& out) { + KernelRuntimeContext ctx; + auto& ret = grid_sampler_2d_out( + ctx, input, grid, interpolation_mode, padding_mode, align_corners, out); + + if (ctx.failure_state() != Error::Ok) { + throw std::runtime_error( + std::string("Kernel failed with error: ") + + std::to_string((int)ctx.failure_state())); + } + + return ret; +} +// NOLINTEND(facebook-hte-ConstantArgumentPassByValue, +// facebook-hte-ParameterMightThrowOnCopy) + +TORCH_LIBRARY(et_test, m) { + m.def( + "upsample_bilinear2d.vec_out(Tensor input, SymInt[]? output_size, bool align_corners, float[]? scale_factors, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(upsample_bilinear2d_vec_out_no_context, 4)); + m.def( + "upsample_nearest2d.vec_out(Tensor input, SymInt[]? output_size, float[]? scale_factors, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(upsample_nearest2d_vec_out_no_context, 3)); + m.def( + "_upsample_bilinear2d_aa.out(Tensor input, SymInt[] output_size, bool align_corners, float? scale_h, float? scale_w, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(_upsample_bilinear2d_aa_out_no_context, 5)); + m.def( + "grid_sampler_2d.out(Tensor input, Tensor grid, int interpolation_mode, int padding_mode, bool align_corners, *, Tensor(a!) out) -> Tensor(a!)", + WRAP_TO_ATEN(grid_sampler_2d_out_no_context, 5)); +} + +} // namespace native +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/supported_features_def.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/supported_features_def.yaml new file mode 100644 index 0000000..c97183a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/supported_features_def.yaml @@ -0,0 +1 @@ +# no override diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/targets.bzl new file mode 100644 index 0000000..c52b59b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/targets.bzl @@ -0,0 +1,101 @@ +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "is_xplat", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") +load("@fbsource//xplat/executorch/kernels/test:util.bzl", "define_supported_features_lib", "op_test") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + if not runtime.is_oss: + define_supported_features_lib() + + if not is_xplat(): + python_unittest( + name = "op_upsample_bilinear2d_test", + srcs = [ + "op_upsample_bilinear2d_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + python_unittest( + name = "op_upsample_bilinear2d_aa_test", + srcs = [ + "op_upsample_bilinear2d_aa_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + python_unittest( + name = "op_upsample_nearest2d_test", + srcs = [ + "op_upsample_nearest2d_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + python_unittest( + name = "op_grid_sampler_2d_test", + srcs = [ + "op_grid_sampler_2d_test.py", + ], + preload_deps = [ + ":aot_ops_test_lib", + ], + deps = [ + "//caffe2:torch", + ], + ) + + op_test(name = "op_allclose_test") + op_test(name = "op_div_test") + op_test(name = "op_gelu_test") + op_test(name = "op_mul_test") + + if is_xplat(): + et_operator_library( + name = "add_float", + ops_dict = { + "aten::add.out": ["v1/6;0,1"], # float + }, + ) + + executorch_generated_lib( + name = "add_float_lib", + functions_yaml_target = "//executorch/kernels/portable:functions.yaml", + kernel_deps = [ + "//executorch/kernels/portable:operators", + ], + visibility = ["//executorch/..."], + deps = [ + ":add_float", + ], + dtype_selective_build = True, + ) + + runtime.cxx_test( + name = "dtype_selective_build_test", + srcs = ["dtype_selective_build_test.cpp"], + deps = [ + ":add_float_lib", + "//executorch/kernels/portable/cpu:scalar_utils", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/test_grid_sampler_2d_executorch.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/test_grid_sampler_2d_executorch.py new file mode 100644 index 0000000..4b635e1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/portable/test/test_grid_sampler_2d_executorch.py @@ -0,0 +1,458 @@ +#!/usr/bin/env python3 +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +""" +Test grid_sampler_2d by exporting to ExecuTorch and comparing with PyTorch. +""" + +import itertools +import sys +import unittest + +import torch +import torch.nn as nn +from executorch.exir import to_edge +from executorch.runtime import Runtime +from torch.export import export + + +class GridSampleModule(nn.Module): + """Wrapper module for grid_sample operation.""" + + def __init__( + self, + mode: str = "bilinear", + padding_mode: str = "zeros", + align_corners: bool = False, + ): + super().__init__() + self.mode = mode + self.padding_mode = padding_mode + self.align_corners = align_corners + + def forward(self, input: torch.Tensor, grid: torch.Tensor) -> torch.Tensor: + return torch.nn.functional.grid_sample( + input, + grid, + mode=self.mode, + padding_mode=self.padding_mode, + align_corners=self.align_corners, + ) + + +class GridSampler2DExecutorchTest(unittest.TestCase): + """Test ExecuTorch grid_sampler_2d implementation.""" + + def run_executorch_test( + self, + input_tensor: torch.Tensor, + grid: torch.Tensor, + mode: str = "bilinear", + padding_mode: str = "zeros", + align_corners: bool = False, + atol: float = 1e-5, + rtol: float = 1e-5, + ) -> None: + """Export to ExecuTorch and compare with PyTorch reference.""" + + # Create module + model = GridSampleModule(mode, padding_mode, align_corners) + model.eval() + + # PyTorch reference + with torch.no_grad(): + pytorch_output = model(input_tensor, grid) + + try: + # Export to ExecuTorch + example_inputs = (input_tensor, grid) + + # Export the model + exported_program = export(model, example_inputs) + + # Convert to edge IR + edge_program = to_edge(exported_program) + + # Get ExecuTorch program + executorch_program = edge_program.to_executorch() + + # Run through ExecuTorch + runtime = Runtime.get() + fwd_method = runtime.load_program(executorch_program.buffer).load_method( + "forward" + ) + if fwd_method is None: + self.fail("Failed to load forward method") + executorch_output = fwd_method.execute((input_tensor, grid))[0] + + # Compare results + self.assertTrue( + executorch_output.shape == pytorch_output.shape, + msg=f"Shape mismatch: ET={executorch_output.shape} vs PT={pytorch_output.shape}", + ) + + if not torch.allclose( + executorch_output, pytorch_output, atol=atol, rtol=rtol + ): + max_diff = (executorch_output - pytorch_output).abs().max().item() + mean_diff = (executorch_output - pytorch_output).abs().mean().item() + self.fail( + f"\nMode: {mode}, Padding: {padding_mode}, Align: {align_corners}\n" + f"Max difference: {max_diff:.6e}\n" + f"Mean difference: {mean_diff:.6e}\n" + f"Tolerance (atol): {atol:.6e}\n" + f"ExecuTorch output:\n{executorch_output}\n" + f"PyTorch output:\n{pytorch_output}\n" + ) + + except Exception as e: + self.fail( + f"Failed to export or run model:\n" + f"Mode: {mode}, Padding: {padding_mode}, Align: {align_corners}\n" + f"Error: {str(e)}" + ) + + def test_all_mode_combinations(self): + """Test all combinations of interpolation modes, padding modes, and align_corners.""" + print("\n" + "=" * 70) + print("Testing all mode combinations") + print("=" * 70) + + modes = ["bilinear", "nearest", "bicubic"] + padding_modes = ["zeros", "border", "reflection"] + align_corners_options = [True, False] + + # Test parameters + batch_size = 2 + channels = 3 + height_in = 5 + width_in = 5 + height_out = 4 + width_out = 4 + + test_count = 0 + for mode, padding, align in itertools.product( + modes, padding_modes, align_corners_options + ): + with self.subTest(mode=mode, padding=padding, align=align): + # Create random input + input_tensor = torch.randn( + batch_size, channels, height_in, width_in, dtype=torch.float32 + ) + + # Create grid with some values in [-1, 1] range + grid = torch.randn( + batch_size, height_out, width_out, 2, dtype=torch.float32 + ) + grid = torch.clamp(grid, -1.2, 1.2) # Include some out-of-bounds + + # Bicubic may have slightly larger numerical errors + atol = 1e-4 if mode == "bicubic" else 1e-5 + + self.run_executorch_test( + input_tensor, grid, mode, padding, align, atol=atol + ) + test_count += 1 + print(f" ✓ {mode}/{padding}/align={align}") + + print(f"✓ Passed {test_count} mode combination tests") + + def test_batch_sizes(self): + """Test various batch sizes.""" + print("\n" + "=" * 70) + print("Testing various batch sizes") + print("=" * 70) + + batch_sizes = [1, 2, 4] + + for batch_size in batch_sizes: + with self.subTest(batch_size=batch_size): + input_tensor = torch.randn(batch_size, 3, 6, 6, dtype=torch.float32) + grid = torch.randn(batch_size, 4, 4, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ batch_size={batch_size}") + + print(f"✓ Passed {len(batch_sizes)} batch size tests") + + def test_input_sizes(self): + """Test various input and output sizes.""" + print("\n" + "=" * 70) + print("Testing various input/output sizes") + print("=" * 70) + + test_cases = [ + # (H_in, W_in, H_out, W_out) + (4, 4, 4, 4), # Same size + (8, 8, 4, 4), # Downsampling + (4, 4, 8, 8), # Upsampling + (10, 5, 7, 3), # Non-square, different aspect ratios + ] + + for h_in, w_in, h_out, w_out in test_cases: + with self.subTest(h_in=h_in, w_in=w_in, h_out=h_out, w_out=w_out): + input_tensor = torch.randn(1, 2, h_in, w_in, dtype=torch.float32) + grid = torch.randn(1, h_out, w_out, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ {h_in}x{w_in} -> {h_out}x{w_out}") + + print(f"✓ Passed {len(test_cases)} size variation tests") + + def test_identity_grid(self): + """Test with identity grid (should return approximately same as input).""" + print("\n" + "=" * 70) + print("Testing identity grid") + print("=" * 70) + + input_tensor = torch.randn(1, 3, 4, 4, dtype=torch.float32) + + # Create identity grid + y = torch.linspace(-1, 1, 4) + x = torch.linspace(-1, 1, 4) + grid_y, grid_x = torch.meshgrid(y, x, indexing="ij") + grid = torch.stack([grid_x, grid_y], dim=-1).unsqueeze(0) + + for mode in ["bilinear", "nearest", "bicubic"]: + with self.subTest(mode=mode): + atol = 1e-4 if mode == "bicubic" else 1e-5 + self.run_executorch_test( + input_tensor, grid, mode, "zeros", True, atol=atol + ) + print(f" ✓ {mode}") + + print("✓ Passed identity grid tests") + + def test_corner_coordinates(self): + """Test sampling at corner coordinates with different align_corners settings.""" + print("\n" + "=" * 70) + print("Testing corner coordinates") + print("=" * 70) + + input_tensor = torch.randn(1, 1, 8, 8, dtype=torch.float32) + + # Grid sampling at corners + grid = torch.tensor( + [ + [ + [[-1.0, -1.0], [-1.0, 1.0]], + [[1.0, -1.0], [1.0, 1.0]], + ] + ], + dtype=torch.float32, + ) + + for align_corners in [True, False]: + for mode in ["bilinear", "nearest"]: + with self.subTest(align_corners=align_corners, mode=mode): + self.run_executorch_test( + input_tensor, grid, mode, "zeros", align_corners + ) + print(f" ✓ {mode}/align={align_corners}") + + print("✓ Passed corner coordinate tests") + + def test_out_of_bounds(self): + """Test behavior with out-of-bounds coordinates for different padding modes.""" + print("\n" + "=" * 70) + print("Testing out-of-bounds coordinates") + print("=" * 70) + + input_tensor = torch.randn(1, 2, 5, 5, dtype=torch.float32) + + # Grid with out-of-bounds coordinates + grid = torch.tensor( + [ + [ + [[-1.5, -1.5], [-0.5, -0.5], [0.5, 0.5], [1.5, 1.5]], + [[-1.0, 1.5], [0.0, 0.0], [1.0, -1.5], [2.0, 2.0]], + ] + ], + dtype=torch.float32, + ) + + for padding_mode in ["zeros", "border", "reflection"]: + for mode in ["bilinear", "nearest"]: + with self.subTest(padding_mode=padding_mode, mode=mode): + self.run_executorch_test( + input_tensor, grid, mode, padding_mode, False + ) + print(f" ✓ {mode}/{padding_mode}") + + print("✓ Passed out-of-bounds tests") + + def test_single_channel(self): + """Test with single channel input.""" + print("\n" + "=" * 70) + print("Testing single channel input") + print("=" * 70) + + input_tensor = torch.randn(1, 1, 6, 6, dtype=torch.float32) + grid = torch.randn(1, 4, 4, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + for mode in ["bilinear", "nearest", "bicubic"]: + with self.subTest(mode=mode): + atol = 1e-4 if mode == "bicubic" else 1e-5 + self.run_executorch_test( + input_tensor, grid, mode, "zeros", False, atol=atol + ) + print(f" ✓ {mode}") + + print("✓ Passed single channel tests") + + def test_different_dtypes(self): + """Test with different data types (float16, bfloat16).""" + print("\n" + "=" * 70) + print("Testing different dtypes") + print("=" * 70) + + dtypes = [torch.float16, torch.bfloat16] + + for dtype in dtypes: + with self.subTest(dtype=dtype): + input_tensor = torch.randn(1, 2, 4, 4, dtype=dtype) + grid = torch.randn(1, 3, 3, 2, dtype=dtype) + grid = torch.clamp(grid, -1, 1) + + # Use larger tolerance for float16/bfloat16 + atol = 1e-2 if dtype == torch.bfloat16 else 5e-3 + + self.run_executorch_test( + input_tensor, grid, "bilinear", "zeros", False, atol=atol + ) + print(f" ✓ {dtype}") + + print("✓ Passed dtype tests") + + def test_very_small_inputs(self): + """Test with very small input sizes.""" + print("\n" + "=" * 70) + print("Testing very small inputs") + print("=" * 70) + + test_cases = [ + # (H_in, W_in, H_out, W_out, description) + (1, 1, 1, 1, "1x1 input, 1x1 output"), + (1, 1, 2, 2, "1x1 input, 2x2 output"), + (2, 2, 1, 1, "2x2 input, 1x1 output"), + (2, 2, 2, 2, "2x2 input, 2x2 output"), + (2, 2, 3, 3, "2x2 input, 3x3 output"), + (3, 3, 1, 1, "3x3 input, single pixel output"), + ] + + for h_in, w_in, h_out, w_out, desc in test_cases: + with self.subTest(desc=desc): + input_tensor = torch.randn(1, 2, h_in, w_in, dtype=torch.float32) + grid = torch.randn(1, h_out, w_out, 2, dtype=torch.float32) + grid = torch.clamp(grid, -1, 1) + + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ {desc}") + + print("✓ Passed very small input tests") + + def test_exact_boundary_coordinates(self): + """Test with grid coordinates exactly at boundaries.""" + print("\n" + "=" * 70) + print("Testing exact boundary coordinates") + print("=" * 70) + + input_tensor = torch.randn(1, 2, 5, 5, dtype=torch.float32) + + # Test grid with exact boundary values + grids = [ + # All corners + torch.tensor( + [[[[-1.0, -1.0], [-1.0, 1.0]], [[1.0, -1.0], [1.0, 1.0]]]], + dtype=torch.float32, + ), + # Center + torch.tensor([[[[0.0, 0.0]]]], dtype=torch.float32), + # Edges + torch.tensor( + [[[[-1.0, 0.0], [1.0, 0.0], [0.0, -1.0], [0.0, 1.0]]]], + dtype=torch.float32, + ), + ] + + for i, grid in enumerate(grids): + for mode in ["bilinear", "nearest", "bicubic"]: + for align_corners in [True, False]: + with self.subTest(grid=i, mode=mode, align_corners=align_corners): + atol = 1e-4 if mode == "bicubic" else 1e-5 + self.run_executorch_test( + input_tensor, grid, mode, "zeros", align_corners, atol=atol + ) + print(f" ✓ grid {i}/{mode}/align={align_corners}") + + print("✓ Passed exact boundary coordinate tests") + + def test_out_of_bounds_values_in_grid(self): + """Test with out of bounds values in grid.""" + print("\n" + "=" * 70) + print("Testing special values in grid") + print("=" * 70) + + input_tensor = torch.randn(1, 2, 4, 4, dtype=torch.float32) + + test_cases = [ + # (grid, description) + ( + torch.tensor([[[[10.0, 10.0], [-10.0, -10.0]]]], dtype=torch.float32), + "Very large coordinates (far out of bounds)", + ), + ( + torch.tensor( + [[[[2.0, 0.0], [0.0, 2.0], [-2.0, 0.0], [0.0, -2.0]]]], + dtype=torch.float32, + ), + "Moderately out of bounds coordinates", + ), + ] + + for grid, desc in test_cases: + with self.subTest(desc=desc): + # Test with zeros padding (most common for out-of-bounds) + self.run_executorch_test(input_tensor, grid, "bilinear", "zeros", False) + print(f" ✓ {desc}") + + print("✓ Passed special value tests") + + +def main(): + """Run the tests.""" + print("\n" + "=" * 70) + print("ExecuTorch grid_sampler_2d Test Suite") + print("Testing via model export and ExecuTorch runtime") + print("=" * 70) + + # Run tests with verbose output + suite = unittest.TestLoader().loadTestsFromTestCase(GridSampler2DExecutorchTest) + runner = unittest.TextTestRunner(verbosity=2) + result = runner.run(suite) + + # Print summary + print("\n" + "=" * 70) + print("Test Summary") + print("=" * 70) + print(f"Tests run: {result.testsRun}") + print(f"Failures: {len(result.failures)}") + print(f"Errors: {len(result.errors)}") + + if result.wasSuccessful(): + print("\n✓ All tests passed!") + return 0 + else: + print("\n✗ Some tests failed") + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/TARGETS new file mode 100644 index 0000000..77b3834 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/TARGETS @@ -0,0 +1,7 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_copy_index.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_copy_index.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_copy_index.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_copy_index.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_copy_index.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_copy_index.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_copy_index.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_copy_index.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_view.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_view.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_view.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_view.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_view.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_view.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/et_view.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/et_view.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/register_prim_ops.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/register_prim_ops.cpp similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/register_prim_ops.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/register_prim_ops.cpp index 62eb089..7ff2f1f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/register_prim_ops.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/register_prim_ops.cpp @@ -654,13 +654,21 @@ static Kernel prim_ops[] = { #if !defined(EXECUTORCH_ENABLE_PRIM_OPS_SELECTIVE_BUILD) || \ defined(INCLUDE_EXECUTORCH_PRIM_ET_COPY_INDEX_TENSOR) // executorch_prim::et_copy_index.tensor(tensor, tensor) -> tensor - Kernel("executorch_prim::et_copy_index.tensor", et_copy_index), + Kernel( + "executorch_prim::et_copy_index.tensor", + [](KernelRuntimeContext& context, Span stack) { + et_copy_index(context, stack); + }), #endif #if !defined(EXECUTORCH_ENABLE_PRIM_OPS_SELECTIVE_BUILD) || \ defined(INCLUDE_EXECUTORCH_PRIM_ET_VIEW_DEFAULT) // executorch_prim::et_view.default(Tensor, int[]) -> Tensor - Kernel("executorch_prim::et_view.default", et_view), + Kernel( + "executorch_prim::et_view.default", + [](KernelRuntimeContext& context, Span stack) { + et_view(context, stack); + }), #endif }; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/selective_build_prim_ops.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/selective_build_prim_ops.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/prim_ops/selective_build_prim_ops.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/selective_build_prim_ops.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/targets.bzl new file mode 100644 index 0000000..1750eb5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/targets.bzl @@ -0,0 +1,78 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Define the filegroup once outside the loop since it doesn't vary by aten mode + runtime.filegroup( + name = "prim_ops_sources", + srcs = ["register_prim_ops.cpp"], + visibility = ["PUBLIC"], + ) + + runtime.filegroup( + name = "selective_build_prim_ops.h", + srcs = ["selective_build_prim_ops.h"], + visibility = ["PUBLIC"], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "et_copy_index" + aten_suffix, + srcs = ["et_copy_index.cpp"], + # To allow for selective prim ops to depend on this library. + # Used by selective_build.bzl + visibility = ["PUBLIC"], + exported_headers = ["et_copy_index.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes" + aten_suffix, + "//executorch/runtime/core:core", + ], + exported_deps = [ + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "et_view" + aten_suffix, + srcs = ["et_view.cpp"], + # To allow for selective prim ops to depend on this library. + # Used by selective_build.bzl + visibility = ["PUBLIC"], + exported_headers = ["et_view.h"], + deps = [ + "//executorch/runtime/kernel:kernel_includes" + aten_suffix, + "//executorch/runtime/core:core", + ], + exported_deps = [ + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "prim_ops_registry" + aten_suffix, + srcs = ["register_prim_ops.cpp"], + visibility = ["PUBLIC"], + # @lint-ignore BUCKLINT link_whole, need this to register prim ops. + link_whole = True, + # prim ops are registered through a global table so the ctor needs to be allowed + compiler_flags = select({ + "DEFAULT": ["-Wno-global-constructors"], + "ovr_config//os:windows": [], + }), + deps = [ + ":et_copy_index" + aten_suffix, + ":et_view" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:operator_registry" + aten_suffix, + "//executorch/runtime/kernel:kernel_includes" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/BUCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/CMakeLists.txt new file mode 100644 index 0000000..c92daad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs prim_ops_test.cpp) + +et_cxx_test(kernels_prim_ops_test SOURCES ${_test_srcs} EXTRA_LIBS executorch) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/TARGETS new file mode 100644 index 0000000..d910e24 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/TARGETS @@ -0,0 +1,37 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") + +oncall("executorch") + +python_unittest( + name = "prim_ops_test_py", + srcs = [ + "prim_ops_test.py", + ], + deps = [ + "//caffe2:torch", + "//executorch/exir/passes:prim_ops_py_registry", + ], +) + +runtime.cxx_test( + name = "prim_ops_test_cpp", + srcs = [ + "prim_ops_test.cpp", + ], + deps = [ + "//executorch/kernels/prim_ops:prim_ops_registry", # @manual + "//executorch/kernels/test:test_util", # @manual + "//executorch/runtime/core:evalue", # @manual + "//executorch/runtime/core/exec_aten:lib", # @manual + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", # @manual + "//executorch/runtime/core/exec_aten/util:tensor_util", # @manual + "//executorch/runtime/kernel:kernel_runtime_context", # @manual + "//executorch/runtime/kernel:operator_registry", + "//executorch/runtime/platform:platform", + "//executorch/test/utils:utils", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.cpp new file mode 100644 index 0000000..37a4e8b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.cpp @@ -0,0 +1,932 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using executorch::aten::SizesType; +using torch::executor::Error; +using torch::executor::resize_tensor; +using torch::executor::Span; + +namespace torch { +namespace executor { + +class RegisterPrimOpsTest : public OperatorTest { + protected: + void SetUp() override { + context_ = KernelRuntimeContext(); + } +}; + +TEST_F(RegisterPrimOpsTest, OpRegistered) { + EXPECT_TRUE(hasOpsFn("aten::sym_size.int")); + EXPECT_TRUE(hasOpsFn("aten::sym_numel")); + EXPECT_TRUE(hasOpsFn("executorch_prim::sym_max.Scalar")); + EXPECT_TRUE(hasOpsFn("executorch_prim::sym_min.Scalar")); +} + +TEST_F(RegisterPrimOpsTest, SymSizeReturnsCorrectValue) { + testing::TensorFactory tf; + + Tensor self_tensor = tf.ones({3, 5}); + EValue values[3]; + int64_t dim = 1; + int64_t out = 0; + values[0] = EValue(self_tensor); + values[1] = EValue(dim); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("aten::sym_size.int")(context_, Span(stack)); + + int64_t expected = 5; + EXPECT_EQ(stack[2]->toInt(), expected); +} + +TEST_F(RegisterPrimOpsTest, SymNumelReturnsCorrectValue) { + testing::TensorFactory tf; + + Tensor self_tensor = tf.ones({3, 5}); + EValue values[2]; + int64_t out = 0; + values[0] = EValue(self_tensor); + values[1] = EValue(out); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + getOpsFn("aten::sym_numel")(context_, Span(stack)); + + int64_t expected = 15; + EXPECT_EQ(stack[1]->toInt(), expected); +} + +TEST_F(RegisterPrimOpsTest, SymMaxReturnsCorrectValue) { + EValue values[3]; + int64_t a = 5; + int64_t b = 3; + int64_t out = 0; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with swapped values + values[0] = EValue(b); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with equal values + values[0] = EValue(a); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with negative values + a = -2; + b = -5; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_max.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), -2); +} + +TEST_F(RegisterPrimOpsTest, SymMinReturnsCorrectValue) { + EValue values[3]; + int64_t a = 5; + int64_t b = 3; + int64_t out = 0; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + // Test with swapped values + values[0] = EValue(b); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + // Test with equal values + values[0] = EValue(a); + values[1] = EValue(a); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 5); + + // Test with negative values + a = -2; + b = -5; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + getOpsFn("executorch_prim::sym_min.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), -5); +} + +TEST_F(RegisterPrimOpsTest, TestAlgebraOps) { + EValue values[3]; + int64_t a = 3; + int64_t b = 4; + int64_t out = 0; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + EValue* stack2[2] = {&values[0], &values[1]}; + + getOpsFn("executorch_prim::add.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 7); + + getOpsFn("executorch_prim::sub.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), -1); + + getOpsFn("executorch_prim::mul.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 12); + + getOpsFn("executorch_prim::floordiv.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 0); + + getOpsFn("executorch_prim::truediv.Scalar")(context_, Span(stack)); + EXPECT_FLOAT_EQ(stack[2]->toDouble(), 0.75); + + getOpsFn("executorch_prim::mod.int")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + getOpsFn("executorch_prim::mod.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toInt(), 3); + + getOpsFn("executorch_prim::sym_float.Scalar")( + context_, Span(stack2)); + EXPECT_FLOAT_EQ(stack[1]->toDouble(), 3.0); +} + +TEST_F(RegisterPrimOpsTest, TestETCopyIndex) { + EXPECT_TRUE(hasOpsFn("executorch_prim::et_copy_index.tensor")); + + int64_t index = 0; + testing::TensorFactory tf; + +#ifdef USE_ATEN_LIB + // ATen mode tensors don't need dynamism specification. + Tensor copy_to = tf.make({2, 2}, {0, 0, 0, 0}); +#else + std::vector buf(4); + SizesType expected_output_size[2] = {0, 2}; + Tensor copy_to = + tf.make({2, 2}, {0, 0, 0, 0}, {}, TensorShapeDynamism::DYNAMIC_BOUND); + // Resize the tensor to 0 size for the tests. + Error err = resize_tensor(copy_to, {expected_output_size, 2}); + EXPECT_EQ(err, Error::Ok); +#endif + + Tensor to_copy = tf.make({2}, {3, 4}); + + EValue values[3]; + EValue* stack[3]; + + values[0] = EValue(copy_to); + values[1] = EValue(to_copy); + values[2] = EValue(index); + + stack[0] = &values[0]; + stack[1] = &values[1]; + stack[2] = &values[2]; + + // Simple test to copy to index 0. + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack)); + + EXPECT_EQ(copy_to.sizes()[0], 1); + EXPECT_EQ(copy_to.sizes()[1], 2); + EXPECT_TENSOR_EQ(copy_to, tf.make({1, 2}, {3, 4})); + + values[1] = tf.make({2}, {5, 6}); + values[2] = EValue((int64_t)1); + // Copy to the next index, 1. + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack)); + + EXPECT_EQ(copy_to.sizes()[0], 2); + EXPECT_EQ(copy_to.sizes()[1], 2); + EXPECT_TENSOR_EQ(copy_to, tf.make({2, 2}, {3, 4, 5, 6})); +} + +TEST_F(RegisterPrimOpsTest, TestETCopyIndexMismatchShape) { + int64_t index = 1; + testing::TensorFactory tf; + + EValue values[3]; + EValue* stack[3]; + + auto copy_to = tf.make({2, 3}, {1, 2, 3, 4, 5, 6}); + auto to_copy = tf.make({2}, {1, 2}); + + values[0] = EValue(copy_to); + values[1] = EValue(to_copy); + values[2] = EValue(index); + + stack[0] = &values[0]; + stack[1] = &values[1]; + stack[2] = &values[2]; + + // Try to copy and replace at index 1. This will fail because + // copy_to.sizes[1:] and to_copy.sizes[:] don't match each other + // which is a pre-requisite for this operator. + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack))); +} + +TEST_F(RegisterPrimOpsTest, TestBooleanOps) { + EValue values[3]; + double a = 3; + double b = 4; + bool out = false; + values[0] = EValue(a); + values[1] = EValue(b); + values[2] = EValue(out); + + EValue* stack[3]; + for (size_t i = 0; i < 3; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::ge.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), false); + + getOpsFn("executorch_prim::gt.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), false); + + getOpsFn("executorch_prim::le.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), true); + + getOpsFn("executorch_prim::lt.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), true); + + getOpsFn("executorch_prim::eq.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[2]->toBool(), false); +} + +TEST_F(RegisterPrimOpsTest, LocalScalarDenseReturnsCorrectValue) { + testing::TensorFactory tf; + + Tensor self_tensor = tf.ones({1}); + const int64_t num_vals = 2; + EValue values[num_vals]; + int64_t out = 0; + values[0] = EValue(self_tensor); + values[1] = EValue(out); + + EValue* stack[num_vals]; + for (size_t i = 0; i < num_vals; i++) { + stack[i] = &values[i]; + } + + getOpsFn("aten::_local_scalar_dense")(context_, Span(stack)); + + int64_t expected = 1; + EXPECT_EQ(stack[1]->toInt(), expected); +} + +TEST_F(RegisterPrimOpsTest, NegScalarReturnsCorrectValue) { + EValue values[2]; + + // Test with float + values[0] = EValue(5.0f); + values[1] = EValue(0.0f); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + getOpsFn("executorch_prim::neg.Scalar")(context_, Span(stack)); + + EXPECT_EQ(stack[1]->toDouble(), -5.0f); + + // Test with int + int64_t a = 5; + int64_t b = 0; + values[0] = EValue(a); + values[1] = EValue(b); + + getOpsFn("executorch_prim::neg.Scalar")(context_, Span(stack)); + + EXPECT_EQ(stack[1]->toInt(), -5l); +} + +TEST_F(RegisterPrimOpsTest, TestNegScalarWithTensorFails) { + testing::TensorFactory tf; + + EValue values[2]; + + auto tensor = tf.make({2, 3}, {1, 2, 3, 4, 5, 6}); + + int64_t zero = 0; + values[0] = EValue(tensor); + values[1] = EValue(zero); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + // Try to negate a tensor, which should cause a runtime error. + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::neg.Scalar")(context_, Span(stack))); +} + +TEST_F(RegisterPrimOpsTest, TestETView) { + EXPECT_TRUE(hasOpsFn("executorch_prim::et_view.default")); + + testing::TensorFactory tf; + + // *************************************************************************** + // Make self for tests + // *************************************************************************** + auto self = tf.make({3, 2}, {1, 2, 3, 4, 5, 6}); + auto self_evalue = EValue(self); + + // *************************************************************************** + // Make size for tests + // *************************************************************************** + int64_t size[3] = {1, 3, -1}; + EValue size_as_evals[3] = {EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list); + + int64_t bad_size1[3] = {-1, 3, -1}; // two inferred dimensions + EValue bad_size_as_evals1[3] = { + EValue(bad_size1[0]), EValue(bad_size1[1]), EValue(bad_size1[2])}; + EValue* bad_size_wrapped_vals1[3] = { + &bad_size_as_evals1[0], &bad_size_as_evals1[1], &bad_size_as_evals1[2]}; + int64_t bad_size_unwrapped_vals1[3] = {0, 0, 0}; + BoxedEvalueList bad_size_boxed_list1( + bad_size_wrapped_vals1, bad_size_unwrapped_vals1, 3); + EValue bad_size_int_list_evalue1 = EValue(&bad_size_boxed_list1); + + int64_t bad_size2[3] = {-2, -3, 1}; // negative size not supported + EValue bad_size_as_evals2[3] = { + EValue(bad_size2[0]), EValue(bad_size2[1]), EValue(bad_size2[2])}; + EValue* bad_size_wrapped_vals2[3] = { + &bad_size_as_evals2[0], &bad_size_as_evals2[1], &bad_size_as_evals2[2]}; + int64_t bad_size_unwrapped_vals2[3] = {0, 0, 0}; + BoxedEvalueList bad_size_boxed_list2( + bad_size_wrapped_vals2, bad_size_unwrapped_vals2, 3); + EValue bad_size_int_list_evalue2 = EValue(&bad_size_boxed_list2); + + // *************************************************************************** + // Make outs for tests + // *************************************************************************** + constexpr int N_GOOD_OUTS = 2; + Tensor good_outs[N_GOOD_OUTS] = { + tf.ones({1, 3, 2}), // correct size with nullptr + tf.ones({1, 3, 2}), // correct size with self data_ptr + }; + internal::reset_data_ptr(good_outs[0]); + ET_CHECK( + internal::set_tensor_data( + good_outs[1], self.mutable_data_ptr(), good_outs[1].nbytes()) == + Error::Ok); + EValue good_out_evalues[N_GOOD_OUTS] = { + EValue(good_outs[0]), EValue(good_outs[1])}; + + // bad outs expect death + constexpr int N_BAD_OUTS = 2; + Tensor bad_outs[N_BAD_OUTS] = { + tf.ones({1, 3, 2, 1}), // wrong rank + tf.ones({1, 3, 3}) // wrong size + }; + EValue bad_out_evalues[N_BAD_OUTS] = { + EValue(bad_outs[0]), EValue(bad_outs[1])}; + + // *************************************************************************** + // Run tests + // *************************************************************************** + + constexpr int N_BAD_STACKS = N_BAD_OUTS + 2; + EValue* bad_stacks[N_BAD_STACKS][3] = { + // Bad out stacks + {&self_evalue, &size_int_list_evalue, &bad_out_evalues[0]}, + {&self_evalue, &size_int_list_evalue, &bad_out_evalues[1]}, + // Bad size stacks + {&self_evalue, &bad_size_int_list_evalue1, &good_out_evalues[0]}, + {&self_evalue, &bad_size_int_list_evalue2, &good_out_evalues[0]}}; + + // Bad stacks expect death + for (int i = 0; i < N_BAD_STACKS; i++) { + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_view.default")( + context_, Span(bad_stacks[i]))); + } + + constexpr int N_GOOD_STACKS = N_GOOD_OUTS; + EValue* good_out_stacks[N_GOOD_STACKS][3] = { + {&self_evalue, &size_int_list_evalue, &good_out_evalues[0]}, + {&self_evalue, &size_int_list_evalue, &good_out_evalues[1]}}; + + // Good outs expect no death and correct output + for (int i = 0; i < N_GOOD_STACKS; i++) { + getOpsFn("executorch_prim::et_view.default")( + context_, Span(good_out_stacks[i])); + EXPECT_TENSOR_EQ(good_outs[i], tf.make({1, 3, 2}, {1, 2, 3, 4, 5, 6})); + EXPECT_EQ(good_outs[i].const_data_ptr(), self.const_data_ptr()); + } +} + +TEST_F(RegisterPrimOpsTest, TestETViewDynamic) { + testing::TensorFactory tf; + + auto self = tf.make({3, 1}, {1, 2, 3}); + auto self_evalue = EValue(self); + + int64_t size[3] = {1, 3, -1}; // inferred size should be {1, 3, 1} + // Construct the size as an EValue int_list + EValue size_as_evals[3] = {EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list_2( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_2); + +#ifdef USE_ATEN_LIB + // ATen mode tensors don't need dynamism specification. + auto out = tf.make({3, 2, 1}, {0, 0, 0, 0, 0, 0}); +#else + auto out = tf.make( + {3, 2, 1}, {0, 0, 0, 0, 0, 0}, {}, TensorShapeDynamism::DYNAMIC_BOUND); +#endif + + internal::reset_data_ptr(out); + EValue out_evalue = EValue(out); + + EValue* stack[3] = {&self_evalue, &size_int_list_evalue, &out_evalue}; + + getOpsFn("executorch_prim::et_view.default")(context_, Span(stack)); + + EXPECT_TENSOR_EQ(out, tf.make({1, 3, 1}, {1, 2, 3})); + EXPECT_EQ(out.const_data_ptr(), self.const_data_ptr()); +} + +TEST_F(RegisterPrimOpsTest, TestETViewEmpty) { + testing::TensorFactory tf; + + auto self = tf.make({3, 1, 0}, {}); + auto self_evalue = EValue(self); + EXPECT_EQ(self.const_data_ptr(), nullptr); // empty tensor has null data + + // Construct the sizes + int64_t size[3] = {3, 1, -1}; + EValue size_as_evals[3] = {EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list_3( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_3); + + int64_t bad_size[3] = {0, 1, -1}; // bad size: cannot infer with 0 + EValue bad_size_as_evals[3] = { + EValue(bad_size[0]), EValue(bad_size[1]), EValue(bad_size[2])}; + EValue* bad_size_wrapped_vals[3] = { + &bad_size_as_evals[0], &bad_size_as_evals[1], &bad_size_as_evals[2]}; + int64_t bad_size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList bad_size_boxed_list( + bad_size_wrapped_vals, bad_size_unwrapped_vals, 3); + EValue bad_size_int_list_evalue = EValue(&bad_size_boxed_list); + + auto out = tf.make({3, 1, 0}, {}, {}); + EValue out_evalue = EValue(out); + EXPECT_EQ(out.const_data_ptr(), nullptr); + + // good size test + EValue* stack[3] = {&self_evalue, &size_int_list_evalue, &out_evalue}; + getOpsFn("executorch_prim::et_view.default")(context_, Span(stack)); + EXPECT_TENSOR_EQ(out, tf.make({3, 1, 0}, {})); + EXPECT_EQ(out.const_data_ptr(), self.const_data_ptr()); + + // bad size test + EValue* bad_stack[3] = {&self_evalue, &bad_size_int_list_evalue, &out_evalue}; + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_view.default")( + context_, Span(bad_stack))); +} + +TEST_F(RegisterPrimOpsTest, TestCeil) { + std::array inputs = { + 0.0, 0.25, 0.5, 0.75, 1.0, 1.75, -0.5, -1.0, -1.5, 9.999999}; + std::array expected = {0, 1, 1, 1, 1, 2, 0, -1, -1, 10}; + + for (auto i = 0; i < inputs.size(); i++) { + EValue values[2]; + values[0] = EValue(inputs[i]); + values[1] = EValue(0.0); + + EValue* stack[2]; + for (size_t j = 0; j < 2; j++) { + stack[j] = &values[j]; + } + + getOpsFn("executorch_prim::ceil.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[1]->toInt(), expected[i]); + } +} + +TEST_F(RegisterPrimOpsTest, TestRound) { + // Note that Python uses round-to-even for halfway values. + std::array inputs = { + 0.0, 0.25, 0.5, 0.75, 1.0, 1.5, -0.5, -1.0, -1.5, 9.999999}; + std::array expected = {0, 0, 0, 1, 1, 2, 0, -1, -2, 10}; + + for (auto i = 0; i < inputs.size(); i++) { + EValue values[2]; + values[0] = EValue(inputs[i]); + values[1] = EValue(0.0); + + EValue* stack[2]; + for (size_t j = 0; j < 2; j++) { + stack[j] = &values[j]; + } + + getOpsFn("executorch_prim::round.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[1]->toInt(), expected[i]); + } +} + +TEST_F(RegisterPrimOpsTest, TestTrunc) { + std::array inputs = { + 0.0, 0.25, 0.5, 0.75, 1.0, 1.75, -0.5, -1.0, -1.5, 9.999999}; + std::array expected = {0, 0, 0, 0, 1, 1, 0, -1, -1, 9}; + + for (auto i = 0; i < inputs.size(); i++) { + EValue values[2]; + values[0] = EValue(inputs[i]); + values[1] = EValue(0.0); + + EValue* stack[2]; + for (size_t j = 0; j < 2; j++) { + stack[j] = &values[j]; + } + + getOpsFn("executorch_prim::trunc.Scalar")(context_, Span(stack)); + EXPECT_EQ(stack[1]->toInt(), expected[i]); + } +} + +// Test that each prim op returns InvalidProgram error when given a stack that's +// one element shorter than expected +TEST_F(RegisterPrimOpsTest, TestInvalidProgramErrorOnShortStack) { + // Test aten::sym_size.int with a stack of size 2 (missing output) + { + testing::TensorFactory tf; + Tensor self_tensor = tf.ones({3, 5}); + EValue values[2]; + int64_t dim = 1; + values[0] = EValue(self_tensor); + values[1] = EValue(dim); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("aten::sym_size.int")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), torch::executor::Error::InvalidProgram); + } + + // Test aten::sym_numel with a stack of size 1 (missing output) + { + testing::TensorFactory tf; + Tensor self_tensor = tf.ones({3, 5}); + EValue values[1]; + values[0] = EValue(self_tensor); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, getOpsFn("aten::sym_numel")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), torch::executor::Error::InvalidProgram); + } + + // Test executorch_prim::sym_max.Scalar with a stack of size 2 (missing + // output) + { + EValue values[2]; + int64_t a = 5; + int64_t b = 3; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sym_max.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::sym_min.Scalar with a stack of size 2 (missing + // output) + { + EValue values[2]; + int64_t a = 5; + int64_t b = 3; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sym_min.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test algebra ops with a stack of size 2 (missing output) + { + EValue values[2]; + int64_t a = 3; + int64_t b = 4; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::add.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sub.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::mul.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::floordiv.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::truediv.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::mod.int")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::mod.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::sym_float.Scalar with a stack of size 1 (missing + // output) + { + EValue values[1]; + int64_t a = 3; + values[0] = EValue(a); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::sym_float.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test boolean ops with a stack of size 2 (missing output) + { + EValue values[2]; + double a = 3; + double b = 4; + values[0] = EValue(a); + values[1] = EValue(b); + + EValue* stack[2]; + for (size_t i = 0; i < 2; i++) { + stack[i] = &values[i]; + } + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::ge.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::gt.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::le.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::lt.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::eq.Scalar")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test aten::_local_scalar_dense with a stack of size 1 (missing output) + { + testing::TensorFactory tf; + Tensor self_tensor = tf.ones({1}); + EValue values[1]; + values[0] = EValue(self_tensor); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("aten::_local_scalar_dense")(context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::neg.Scalar with a stack of size 1 (missing output) + { + EValue values[1]; + values[0] = EValue(5.0f); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::neg.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::et_copy_index.tensor with a stack of size 2 (missing + // index) + { + testing::TensorFactory tf; + auto copy_to = tf.make({2, 2}, {0, 0, 0, 0}); + auto to_copy = tf.make({2}, {3, 4}); + + EValue values[2]; + values[0] = EValue(copy_to); + values[1] = EValue(to_copy); + + EValue* stack[2]; + stack[0] = &values[0]; + stack[1] = &values[1]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_copy_index.tensor")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test executorch_prim::et_view.default with a stack of size 2 (missing + // output) + { + testing::TensorFactory tf; + auto self = tf.make({3, 2}, {1, 2, 3, 4, 5, 6}); + auto self_evalue = EValue(self); + + int64_t size[3] = {1, 3, -1}; + EValue size_as_evals[3] = { + EValue(size[0]), EValue(size[1]), EValue(size[2])}; + EValue* size_wrapped_vals[3] = { + &size_as_evals[0], &size_as_evals[1], &size_as_evals[2]}; + int64_t size_unwrapped_vals[3] = {0, 0, 0}; + BoxedEvalueList size_boxed_list_4( + size_wrapped_vals, size_unwrapped_vals, 3); + EValue size_int_list_evalue = EValue(&size_boxed_list_4); + + EValue* stack[2] = {&self_evalue, &size_int_list_evalue}; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::et_view.default")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } + + // Test ceil, round, trunc with a stack of size 1 (missing output) + { + EValue values[1]; + values[0] = EValue(5.5); + + EValue* stack[1]; + stack[0] = &values[0]; + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::ceil.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::round.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + + ET_EXPECT_KERNEL_FAILURE( + context_, + getOpsFn("executorch_prim::trunc.Scalar")( + context_, Span(stack))); + EXPECT_EQ(context_.failure_state(), Error::InvalidProgram); + } +} + +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.py new file mode 100644 index 0000000..62e7a2c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/prim_ops/test/prim_ops_test.py @@ -0,0 +1,23 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +# necessary to ensure the ops are registered +import executorch.exir.passes.executorch_prim_ops_registry # noqa: F401 + +import torch + + +# This class tests whether we can generate correct code to register the prim ops into PyTorch runtime. +class TestCustomOps(unittest.TestCase): + def setUp(self) -> None: + self.x = 1 + self.y = 2 + + def test_add_registered(self) -> None: + out_1 = torch.ops.executorch_prim.add.Scalar(self.x, self.y) + self.assertEqual(out_1, 3) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/CMakeLists.txt new file mode 100644 index 0000000..d4fc52a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/CMakeLists.txt @@ -0,0 +1,158 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Kernel library for quantized operators. Please this file formatted by running: +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..) +endif() + +set(_common_compile_options -Wno-deprecated-declarations) + +include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake) +include(${EXECUTORCH_ROOT}/tools/cmake/Codegen.cmake) + +# Quantized ops kernel sources TODO(larryliu0820): use buck2 to gather the +# sources +list(TRANSFORM _quantized_kernels__srcs PREPEND "${EXECUTORCH_ROOT}/") +# Generate C++ bindings to register kernels into both PyTorch (for AOT) and +# Executorch (for runtime). Here select all ops in quantized.yaml +set(_yaml_file ${CMAKE_CURRENT_LIST_DIR}/quantized.yaml) +gen_selected_ops(LIB_NAME "quantized_ops_lib" OPS_SCHEMA_YAML "${_yaml_file}") + +# Expect gen_selected_ops output file to be selected_operators.yaml +generate_bindings_for_kernels( + LIB_NAME "quantized_ops_lib" CUSTOM_OPS_YAML "${_yaml_file}" +) +message("Generated files ${gen_command_sources}") + +# Not targeting Xcode, because the custom command generating +# kernels/quantized/selected_operators.yaml is attached to multiple targets: +# quantized_ops_aot_lib quantized_ops_lib but none of these is a common +# dependency of the other(s). This is not allowed by the Xcode "new build +# system". +if(NOT CMAKE_GENERATOR STREQUAL "Xcode" + AND EXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT +) + # Not targeting ARM_BAREMETAL as aot_lib depends on incompatible libraries + if(NOT EXECUTORCH_BUILD_ARM_BAREMETAL) + set(_quantized_aot_ops + "quantized_decomposed::add.out" + "quantized_decomposed::choose_qparams.Tensor_out" + "quantized_decomposed::choose_qparams_per_token_asymmetric.out" + "quantized_decomposed::dequantize_per_channel.out" + "quantized_decomposed::dequantize_per_tensor.out" + "quantized_decomposed::dequantize_per_tensor.Tensor_out" + "quantized_decomposed::dequantize_per_token.out" + "quantized_decomposed::mixed_linear.out" + "quantized_decomposed::mixed_mm.out" + "quantized_decomposed::quantize_per_channel.out" + "quantized_decomposed::quantize_per_tensor.out" + "quantized_decomposed::quantize_per_tensor.Tensor_out" + "quantized_decomposed::quantize_per_token.out" + ) + gen_selected_ops( + LIB_NAME "quantized_ops_aot_lib" ROOT_OPS ${_quantized_aot_ops} + ) + # Expect gen_selected_ops output file to be + # quantized_ops_aot_lib/selected_operators.yaml + generate_bindings_for_kernels( + LIB_NAME "quantized_ops_aot_lib" CUSTOM_OPS_YAML "${_yaml_file}" + ) + # Build a AOT library to register quantized ops into PyTorch. This is a + # hack. + set(_quantized_sources + ${_quantized_kernels__srcs} + ${EXECUTORCH_ROOT}/kernels/portable/cpu/util/reduce_util.cpp + ${EXECUTORCH_ROOT}/runtime/core/exec_aten/util/tensor_util_aten.cpp + ) + gen_custom_ops_aot_lib( + LIB_NAME "quantized_ops_aot_lib" KERNEL_SOURCES "${_quantized_sources}" + ) + + # Register quantized ops to portable_lib, so that they're available via + # pybindings. + if(TARGET portable_lib) + add_library(quantized_pybind_kernels_lib ${_quantized_kernels__srcs}) + target_link_libraries( + quantized_pybind_kernels_lib PRIVATE portable_lib executorch_core + kernels_util_all_deps + ) + target_compile_options( + quantized_pybind_kernels_lib PUBLIC ${_common_compile_options} + ) + target_include_directories( + quantized_pybind_kernels_lib PUBLIC "${_common_include_directories}" + ) + gen_selected_ops( + LIB_NAME "quantized_ops_pybind_lib" OPS_SCHEMA_YAML "${_yaml_file}" + ) + generate_bindings_for_kernels( + LIB_NAME "quantized_ops_pybind_lib" CUSTOM_OPS_YAML "${_yaml_file}" + ) + # Build a library for pybind usage. quantized_ops_pybind_lib: Register + # quantized ops kernels into Executorch runtime for pybind. + gen_operators_lib( + LIB_NAME "quantized_ops_pybind_lib" KERNEL_LIBS + quantized_pybind_kernels_lib DEPS portable_lib + ) + target_link_libraries( + quantized_ops_aot_lib PUBLIC quantized_ops_pybind_lib + ) + + # pip wheels will need to be able to find the dependent libraries. On + # Linux, the .so has non-absolute dependencies on libs like + # "_portable_lib.so" without paths; as long as we `import torch` first, + # those dependencies will work. But Apple dylibs do not support + # non-absolute dependencies, so we need to tell the loader where to look + # for its libraries. The LC_LOAD_DYLIB entries for the portable_lib + # libraries will look like "@rpath/_portable_lib.cpython-310-darwin.so", + # so we can add an LC_RPATH entry to look in a directory relative to the + # installed location of our _portable_lib.so file. To see these LC_* + # values, run `otool -l libquantized_ops_lib.dylib`. + if(APPLE) + set(RPATH "@loader_path/../../extensions/pybindings") + else() + set(RPATH "$ORIGIN/../../extensions/pybindings") + endif() + set_target_properties( + quantized_ops_aot_lib PROPERTIES BUILD_RPATH ${RPATH} INSTALL_RPATH + ${RPATH} + ) + endif() + endif() +endif() + +add_library(quantized_kernels ${_quantized_kernels__srcs}) +target_link_libraries( + quantized_kernels PRIVATE executorch_core kernels_util_all_deps +) +target_compile_options(quantized_kernels PUBLIC ${_common_compile_options}) +# Build a library for _quantized_kernels_srcs +# +# quantized_ops_lib: Register quantized ops kernels into Executorch runtime +gen_operators_lib( + LIB_NAME "quantized_ops_lib" KERNEL_LIBS quantized_kernels DEPS + executorch_core +) + +install( + TARGETS quantized_kernels quantized_ops_lib + EXPORT ExecuTorchTargets + DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/executorch/kernels/quantized/ +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/README.md new file mode 100644 index 0000000..f193130 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/README.md @@ -0,0 +1,12 @@ +# Quantized Ops + +This folder contains kernels for quantization related ops, similar to `//executorch/kernels/portable/`. + +## How to add quantized ops + +1. Add a new operator definition in `quantized.yaml` + +2. Implement the kernel for this operator. +3. Add unit test in `/test` directory. +4. Start to use `//executorch/kernels/quantized:generated_lib` in ExecuTorch or + create your own generated lib if you only need a subset of the ops. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/TARGETS new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/TARGETS @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/__init__.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/__init__.py new file mode 100644 index 0000000..3883630 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/__init__.py @@ -0,0 +1,21 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +try: + from pathlib import Path + + libs = list(Path(__file__).parent.resolve().glob("**/*quantized_ops_aot_lib.*")) + del Path + assert len(libs) == 1, f"Expected 1 library but got {len(libs)}" + import torch as _torch + + _torch.ops.load_library(libs[0]) + del _torch +except: + import logging + + logging.info("libquantized_ops_aot_lib is not loaded") + del logging diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/TARGETS new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/TARGETS @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/embeddingxb.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/embeddingxb.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/embeddingxb.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/embeddingxb.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/embeddingxb.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/embeddingxb.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/embeddingxb.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/embeddingxb.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_add.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_add.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_add.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_add.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_choose_qparams.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_choose_qparams.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_choose_qparams.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_choose_qparams.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_dequantize.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_dequantize.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_dequantize.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_dequantize.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_embedding.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_embedding.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_embedding.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_embedding.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_embedding2b.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_embedding2b.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_embedding2b.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_embedding2b.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_embedding4b.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_embedding4b.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_embedding4b.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_embedding4b.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_mixed_linear.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_mixed_linear.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_mixed_linear.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_mixed_linear.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_mixed_mm.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_mixed_mm.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_mixed_mm.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_mixed_mm.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_quantize.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_quantize.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/cpu/op_quantize.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/op_quantize.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/targets.bzl new file mode 100644 index 0000000..88a3823 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/cpu/targets.bzl @@ -0,0 +1,102 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load("@fbsource//xplat/executorch/kernels/portable:op_registration_util.bzl", "define_op_target", "op_target") + +_QUANT_OPS = ( + op_target( + name = "op_add", + ), + op_target( + name = "op_choose_qparams", + deps = [ + "//executorch/kernels/portable/cpu:vec_ops", + "//executorch/extension/threadpool:threadpool", + ], + ), + op_target( + name = "op_dequantize", + deps = [ + "//executorch/kernels/portable/cpu/util:reduce_util", + ], + _aten_mode_deps = [ + "//executorch/kernels/portable/cpu/util:reduce_util_aten", + ], + ), + op_target( + name = "op_embedding", + ), + op_target( + name = "op_embedding2b", + deps = ["//executorch/kernels/quantized/cpu:embeddingxb"], + _aten_mode_deps = [ + "//executorch/kernels/quantized/cpu:embeddingxb_aten", + ], + ), + op_target( + name = "op_embedding4b", + deps = ["//executorch/kernels/quantized/cpu:embeddingxb"], + _aten_mode_deps = [ + "//executorch/kernels/quantized/cpu:embeddingxb_aten", + ], + ), + op_target( + name = "op_mixed_mm", + deps = [ + "//executorch/kernels/portable/cpu:vec_ops", + ], + ), + op_target( + name = "op_mixed_linear", + deps = [ + "//executorch/kernels/portable/cpu:vec_ops", + ], + ), + op_target( + name = "op_quantize", + deps = [ + "//executorch/extension/threadpool:threadpool", + ], + ), +) + +def define_common_targets(): + for op in _QUANT_OPS: + define_op_target(is_aten_op = False, **op) + + quant_op_targets = [":{}".format(op["name"]) for op in _QUANT_OPS] + + runtime.cxx_library( + name = "quantized_cpu", + srcs = [], + visibility = [ + "//executorch/kernels/quantized/...", + "//executorch/extension/pybindings/test/...", + ], + exported_deps = quant_op_targets, + ) + + runtime.cxx_library( + name = "embeddingxb", + srcs = ["embeddingxb.cpp"], + exported_headers = ["embeddingxb.h"], + visibility = [ + "//executorch/kernels/quantized/...", + ], + deps = ["//executorch/runtime/kernel:kernel_includes"], + ) + + runtime.cxx_library( + name = "embeddingxb_aten", + srcs = ["embeddingxb.cpp"], + exported_headers = ["embeddingxb.h"], + visibility = [ + "//executorch/kernels/quantized/...", + ], + deps = ["//executorch/runtime/kernel:kernel_includes_aten"], + ) + + runtime.cxx_library( + name = "quantized_cpu_aten", + srcs = [], + visibility = ["//executorch/kernels/quantized/..."], + exported_deps = [t + "_aten" for t in quant_op_targets], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/quantized.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/quantized.yaml similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/quantized/quantized.yaml rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/quantized.yaml diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/targets.bzl new file mode 100644 index 0000000..86fe81e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/targets.bzl @@ -0,0 +1,130 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib", "exir_custom_ops_aot_lib") + +def define_common_targets(): + runtime.export_file( + name = "quantized.yaml", + visibility = ["PUBLIC"], + ) + + # Excluding embedding_byte ops because we choose to define them + # in python separately, mostly to be easy to share with oss. + et_operator_library( + name = "quantized_ops_need_aot_registration", + ops = [ + "quantized_decomposed::add.out", + "quantized_decomposed::choose_qparams.Tensor_out", + "quantized_decomposed::choose_qparams_per_token_asymmetric.out", + "quantized_decomposed::dequantize_per_channel.out", + "quantized_decomposed::dequantize_per_tensor.out", + "quantized_decomposed::dequantize_per_tensor.Tensor_out", + "quantized_decomposed::dequantize_per_token.out", + "quantized_decomposed::mixed_linear.out", + "quantized_decomposed::mixed_mm.out", + "quantized_decomposed::quantize_per_channel.out", + "quantized_decomposed::quantize_per_tensor.out", + "quantized_decomposed::quantize_per_tensor.Tensor_out", + "quantized_decomposed::quantize_per_token.out", + ], + define_static_targets = True, + ) + + # lib used to register quantized ops into EXIR + exir_custom_ops_aot_lib( + name = "custom_ops_generated_lib", + yaml_target = ":quantized.yaml", + visibility = ["PUBLIC"], + kernels = [":quantized_operators_aten"], + deps = [ + ":quantized_ops_need_aot_registration", + ], + ) + + # lib used to register quantized ops into EXIR + # TODO: merge this with custom_ops_generated_lib + exir_custom_ops_aot_lib( + name = "aot_lib", + yaml_target = ":quantized.yaml", + visibility = ["PUBLIC"], + kernels = [":quantized_operators_aten"], + deps = [ + ":quantized_ops_need_aot_registration", + ], + ) + + et_operator_library( + name = "all_quantized_ops", + ops_schema_yaml_target = ":quantized.yaml", + define_static_targets = True, + visibility = ["PUBLIC"], + ) + + # On Windows we can only compile these two ops currently, so adding a + # separate target for this. + et_operator_library( + name = "q_dq_ops", + ops = [ + "quantized_decomposed::dequantize_per_tensor.out", + "quantized_decomposed::dequantize_per_tensor.Tensor_out", + "quantized_decomposed::quantize_per_tensor.out", + "quantized_decomposed::quantize_per_tensor.Tensor_out", + "quantized_decomposed::dequantize_per_channel.out", + "quantized_decomposed::quantize_per_channel.out", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_library( + name = "quantized_operators" + aten_suffix, + srcs = [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/kernels/quantized/cpu:quantized_cpu" + aten_suffix, + ], + ) + + for support_exceptions in [True, False]: + exception_suffix = "_no_exceptions" if not support_exceptions else "" + + executorch_generated_lib( + name = "generated_lib" + aten_suffix + exception_suffix, + deps = [ + ":quantized_operators" + aten_suffix, + ":all_quantized_ops", + ], + custom_ops_yaml_target = ":quantized.yaml", + custom_ops_aten_kernel_deps = [":quantized_operators_aten"] if aten_mode else [], + custom_ops_requires_aot_registration = False, + aten_mode = aten_mode, + support_exceptions = support_exceptions, + visibility = ["PUBLIC"], + define_static_targets = True, + ) + + # On Windows we can only compile these two ops currently, so adding a + # separate target for this. + executorch_generated_lib( + name = "q_dq_ops_generated_lib" + aten_suffix + exception_suffix, + custom_ops_yaml_target = ":quantized.yaml", + kernel_deps = [ + "//executorch/kernels/quantized/cpu:op_quantize" + aten_suffix, + "//executorch/kernels/quantized/cpu:op_dequantize" + aten_suffix, + ], + aten_mode = aten_mode, + deps = [ + ":q_dq_ops", + ], + support_exceptions = support_exceptions, + visibility = ["PUBLIC"], + ) + + runtime.python_library( + name = "quantized_ops_lib", + srcs = ["__init__.py"], + deps = [ + "//caffe2:torch", + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/TARGETS new file mode 100644 index 0000000..16cf19a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/TARGETS @@ -0,0 +1,51 @@ +load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() + +python_unittest( + name = "test_out_variants", + srcs = ["test_out_variants.py"], + preload_deps = [ + "//executorch/kernels/quantized:custom_ops_generated_lib", + ], + deps = [ + "//caffe2:torch", + "//executorch/exir/dialects:lib", + "//executorch/exir/passes:quant_fusion_pass", + "//executorch/kernels/quantized:quantized_ops_lib", + ], +) + +runtime.cxx_library( + name = "quantized_ops_for_test_lib", + srcs = [ + "quantized_ops_aot_register.cpp", + ], + visibility = ["PUBLIC"], + deps = [ + "//executorch/extension/aten_util:aten_bridge", + "//executorch/kernels/quantized/cpu:op_dequantize", + "//executorch/kernels/quantized/cpu:op_quantize", + "//executorch/runtime/core/exec_aten:lib", + ], + external_deps = [ + "libtorch", + ], +) + +python_unittest( + name = "test_quant_dequant_per_token", + srcs = [ + "test_quant_dequant_per_token.py", + ], + preload_deps = [ + ":quantized_ops_for_test_lib", + ], + deps = [ + "//caffe2:torch", + ], +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_add_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_add_test.cpp new file mode 100644 index 0000000..fdf38cc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_add_test.cpp @@ -0,0 +1,413 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::add_out; +using torch::executor::native::dequantize_per_tensor_out; +using torch::executor::native::quantize_per_tensor_out; +using torch::executor::native::quantized_add_out; + +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + double scale = 0.5; + + int64_t zero_point = 1; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + quantize_per_tensor_out( + input2, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + scale, + zero_point, + quant_min, + quant_max, + qinput2, + scale, + zero_point, + quant_min, + quant_max, + scale, + zero_point, + quant_min, + quant_max, + qoutput); + + // can lossessly dq here so retrive the full 3.5 in operation + // (3.5 + 3.5) / 0.5 + 1 = 15 + Tensor expected = tfo.full({3, 5}, 15.0); + + EXPECT_TENSOR_EQ(qoutput, expected); +} + +TEST(OpQuantizeAddTest, AllDtypesSupported) { + test_dtype(); +} + +TEST(OpQuantizeAddTest, DifferentQParams) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + double a_scale = 0.5; + int64_t a_zero_point = 1; + + double b_scale = 0.25; + int64_t b_zero_point = 2; + + double out_scale = 0.1; + int64_t out_zero_point = 5; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + out_scale, + out_zero_point, + quant_min, + quant_max, + qoutput); + + // can lossessly dq here so retrive the full 3.5 in operation + // (3.5 + 3.5) / 0.1 + 5 = 75 + Tensor expected = tfo.full({3, 5}, 75.0); + + EXPECT_TENSOR_EQ(qoutput, expected); +} + +// Q -> DQ -> FP ADD -> Q -> DQ should be == to Q -> QADD -> DQ +TEST(OpQuantizeAddTest, ConsitencyWithReferencePattern) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + Tensor dq_input1 = tf.zeros({3, 5}); + Tensor dq_input2 = tf.zeros({3, 5}); + Tensor reference_op_output = tf.zeros({3, 5}); + Tensor reference_pattern_output = tf.zeros({3, 5}); + Tensor fp_output = tf.zeros({3, 5}); + + double a_scale = 0.5; + int64_t a_zero_point = 1; + + double b_scale = 0.25; + int64_t b_zero_point = 2; + + double out_scale = 0.1; + int64_t out_zero_point = 5; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + + optional out_dtype = optional(); + + KernelRuntimeContext context{}; + // q -> qadd -> dq + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + out_scale, + out_zero_point, + quant_min, + quant_max, + qoutput); + dequantize_per_tensor_out( + qoutput, + out_scale, + out_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + reference_op_output); + + // now get results for q -> dq -> fp add -> q -> dq + dequantize_per_tensor_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + dq_input1); + + dequantize_per_tensor_out( + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + dq_input2); + + add_out(context, dq_input1, dq_input2, 1.0, fp_output); + // reuse 'qoutput' tensor as an intermediate + quantize_per_tensor_out( + fp_output, + out_scale, + out_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qoutput); + + dequantize_per_tensor_out( + qoutput, + out_scale, + out_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out_dtype, + reference_pattern_output); + + Tensor expected = tf.full({3, 5}, 7.0); + + // Pattern and op results should both be equal to expected and each other, + // check all cases explicitly instead of relying on transitivity + EXPECT_TENSOR_EQ(reference_op_output, expected); + EXPECT_TENSOR_EQ(reference_pattern_output, expected); + EXPECT_TENSOR_EQ(reference_op_output, reference_pattern_output); +} + +TEST(OpQuantizeAddTest, InvalidMinMaxDies) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 3.5); + Tensor input2 = tf.full({3, 5}, 3.5); + double scale = 0.5; + int64_t zero_point = 1; + + int64_t quant_min = 0; + int64_t quant_max = 255; + int64_t out_quant_min = -1; + int64_t out_quant_max = 256; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + // 3.5 / 0.5 + 1 = 8 + quantize_per_tensor_out( + input1, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + ET_EXPECT_DEATH( + quantized_add_out( + qinput1, + scale, + zero_point, + quant_min, + quant_max, + qinput2, + scale, + zero_point, + quant_min, + quant_max, + scale, + zero_point, + out_quant_min, + out_quant_max, + qoutput), + ""); +} + +TEST(OpQuantizeAddTest, TopOfRangeTest) { + TensorFactory tf; + + Tensor input1 = tf.full({3, 5}, 255); + Tensor input2 = tf.full({3, 5}, 255); + double a_scale = 1; + int64_t a_zero_point = 0; + + double b_scale = 1; + int64_t b_zero_point = 0; + + double out_scale = 1; + int64_t out_zero_point = 0; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor qinput1 = tfo.zeros({3, 5}); + Tensor qinput2 = tfo.zeros({3, 5}); + Tensor qoutput = tfo.zeros({3, 5}); + + quantize_per_tensor_out( + input1, + a_scale, + a_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput1); + + // 3.5 / 0.25 + 2 = 16 + quantize_per_tensor_out( + input2, + b_scale, + b_zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qinput2); + + quantized_add_out( + qinput1, + a_scale, + a_zero_point, + quant_min, + quant_max, + qinput2, + b_scale, + b_zero_point, + quant_min, + quant_max, + out_scale, + out_zero_point, + quant_min, + quant_max, + qoutput); + + Tensor expected = tfo.full({3, 5}, 255); + + EXPECT_TENSOR_EQ(qoutput, expected); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_choose_qparams_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_choose_qparams_test.cpp new file mode 100644 index 0000000..dc92df8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_choose_qparams_test.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using torch::executor::native::choose_qparams_per_token_asymmetric_out; +using torch::executor::native::choose_qparams_tensor_out; +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({2, 2}, {1.0, 2.5, 3.2, 15.4}); + Tensor scale_out = tf_double.zeros({1}); + Tensor zero_point_out = tf_long.zeros({1}); + Tensor expected_scale = tf_double.make({1}, {0.0603922}); + Tensor expected_zero_point = tf_long.make({1}, {0}); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + choose_qparams_tensor_out( + input, quant_min, quant_max, 0.0, DTYPE, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE(scale_out, expected_scale); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, Float) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1}); + Tensor scale_out = tf_double.zeros({2, 1}); + Tensor zero_point_out = tf_long.zeros({2, 1}); + Tensor expected_scale = tf_double.make({2, 1}, {0.00666667, 0.0113725485}); + Tensor expected_zero_point = tf_long.make({2, 1}, {-53, -58}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, ExtraDimFloat) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({1, 2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1}); + Tensor scale_out = tf_double.zeros({1, 2, 1}); + Tensor zero_point_out = tf_long.zeros({1, 2, 1}); + Tensor expected_scale = tf_double.make({1, 2, 1}, {0.00666667, 0.0113725485}); + Tensor expected_zero_point = tf_long.make({1, 2, 1}, {-53, -58}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, LargeArray) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make( + {5, 17}, + {0.41654, 0.26599, 0.4141, 0.83809, 0.02938, 0.12199, 0.53667, + 0.799, 0.6606, 0.46657, 0.66142, 0.71787, 0.56098, 0.30202, + 0.059377, 0.85473, 0.8017, 0.2703, 0.44299, 0.49045, 0.75581, + 0.24429, 0.43906, 0.78652, 0.83885, 0.31034, 0.76534, 0.74422, + 0.62549, 0.80006, 0.38144, 0.70652, 0.33553, 0.89136, 0.49126, + 0.072916, 0.75654, 0.82057, 0.083848, 0.29753, 0.62718, 0.95579, + 0.83097, 0.47293, 0.15666, 0.6248, 0.21672, 0.14626, 0.71834, + 0.93664, 0.23382, 0.68931, 0.70866, 0.60545, 0.98648, 0.30335, + 0.62439, 0.19195, 0.1923, 0.75638, 0.81114, 0.34778, 0.0070671, + 0.50918, 0.19698, 0.19969, 0.57687, 0.062786, 0.18447, 0.22961, + 0.29656, 0.25486, 0.75965, 0.11328, 0.86468, 0.21264, 0.99591, + 0.75231, 0.97834, 0.042441, 0.39978, 0.9633, 0.9297, 0.12188, + 0.73564}); + Tensor scale_out = tf_double.zeros({5, 1}); + Tensor zero_point_out = tf_long.zeros({5, 1}); + Tensor expected_scale = tf_double.make( + {5, 1}, {0.0033519, 0.0034955, 0.0037482, 0.0038685, 0.0039055}); + Tensor expected_zero_point = + tf_long.make({5, 1}, {-128, -128, -128, -128, -128}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-5, 1e-5); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); +} + +TEST(OpChooseQparamsPerTokenAsymmetricTensorOutTest, DynamicShapeFloat) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.make({1, 2, 3}, {-0.5, 0.3, 1.2, 0.1, -0.8, 2.1}); + Tensor scale_out = tf_double.zeros( + {1, 5, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); + Tensor zero_point_out = tf_long.zeros( + {1, 5, 1}, torch::executor::TensorShapeDynamism::DYNAMIC_BOUND); + Tensor expected_scale = tf_double.make({1, 2, 1}, {0.00666667, 0.0113725485}); + Tensor expected_zero_point = tf_long.make({1, 2, 1}, {-53, -58}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, expected_zero_point); + + Tensor new_input = tf_float.make( + {1, 5, 8}, + {5.2254, 5.6041, 5.7653, -1.0126, -0.86126, -0.1606, -0.99196, + -1.067, 5.5913, 5.7713, 5.4901, -0.43128, -1.1759, -0.60466, + -0.82913, -0.73623, 5.4588, 5.4066, 5.2644, -0.89692, -0.16866, + -0.63169, -0.42352, -0.48866, 5.594, 5.5223, 5.5277, -0.17658, + -0.30669, -1.1777, -0.65389, -0.36422, 5.6375, 5.1857, 5.0743, + -0.46654, -0.43817, -0.41506, -0.94515, -0.60247}); + Tensor new_expected_scale = tf_double.make( + {1, 5, 1}, {0.026793, 0.027244, 0.024924, 0.026556, 0.025814}); + Tensor new_expected_zero_point = + tf_long.make({1, 5, 1}, {-88, -85, -92, -84, -91}); + + choose_qparams_per_token_asymmetric_out( + new_input, ScalarType::Float, scale_out, zero_point_out); + + EXPECT_TENSOR_CLOSE_WITH_TOL(scale_out, new_expected_scale, 1e-4, 1e-4); + EXPECT_TENSOR_EQ(zero_point_out, new_expected_zero_point); +} + +TEST( + OpChooseQparamsPerTokenAsymmetricTensorOutTest, + LargeInputParallelization) { + et_pal_init(); + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Create input with 8 tokens x 128 elements per token = 1024 total elements + // This exceeds the MIN_ELEMENTS_FOR_PARALLEL threshold of 512 + const int num_tokens = 8; + const int token_size = 128; + std::vector input_data(num_tokens * token_size); + + // Generate test data with known min/max per token for easier verification + std::vector expected_min(num_tokens); + std::vector expected_max(num_tokens); + + for (int i = 0; i < num_tokens; i++) { + float token_min = -1.0f * (i + 1); + float token_max = 2.0f * (i + 1); + expected_min[i] = token_min; + expected_max[i] = token_max; + + for (int j = 0; j < token_size; j++) { + // Linearly interpolate between min and max + float t = j / static_cast(token_size - 1); + input_data[i * token_size + j] = token_min + t * (token_max - token_min); + } + } + + Tensor input = tf_float.make({num_tokens, token_size}, input_data); + Tensor scale_out = tf_double.zeros({num_tokens, 1}); + Tensor zero_point_out = tf_long.zeros({num_tokens, 1}); + + choose_qparams_per_token_asymmetric_out( + input, ScalarType::Float, scale_out, zero_point_out); + + // Manually calculate expected scale and zero_point using the same algorithm + // as calculate_scale_and_zero_point function + const int32_t qmin = -128; + const int32_t qmax = 127; + const float SMALL_SCALE_THRESHOLD = 6.1e-5f; + + for (int i = 0; i < num_tokens; i++) { + float min = std::min(expected_min[i], 0.0f); + float max = std::max(expected_max[i], 0.0f); + + // Calculate scale + double scale = (static_cast(max) - min) / (qmax - qmin); + if (float(scale) == 0.0f || std::isinf(1.0f / float(scale))) { + scale = 0.1; + } + + // Cut off small scale + if (scale < SMALL_SCALE_THRESHOLD) { + scale = SMALL_SCALE_THRESHOLD; + if (min == 0.0f) { + max = SMALL_SCALE_THRESHOLD * (qmax - qmin); + } else if (max == 0.0f) { + min = -SMALL_SCALE_THRESHOLD * (qmax - qmin); + } else { + float amplifier = SMALL_SCALE_THRESHOLD / scale; + min *= amplifier; + max *= amplifier; + } + } + + // Calculate zero_point + double zero_point_from_min = qmin - min / scale; + double zero_point_from_max = qmax - max / scale; + double zero_point_from_min_error = std::abs(qmin) - std::abs(min / scale); + double zero_point_from_max_error = std::abs(qmax) - std::abs(max / scale); + double initial_zero_point = + zero_point_from_min_error < zero_point_from_max_error + ? zero_point_from_min + : zero_point_from_max; + + int32_t nudged_zero_point = 0; + if (initial_zero_point < qmin) { + nudged_zero_point = qmin; + } else if (initial_zero_point > qmax) { + nudged_zero_point = qmax; + } else { + nudged_zero_point = + std::nearbyint(static_cast(initial_zero_point)); + } + + // Verify computed values match expected + EXPECT_NEAR(scale_out.const_data_ptr()[i], scale, 1e-6); + EXPECT_EQ(zero_point_out.const_data_ptr()[i], nudged_zero_point); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_dequantize_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_dequantize_test.cpp new file mode 100644 index 0000000..4a0c195 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_dequantize_test.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using std::optional; +using torch::executor::native::dequantize_per_channel_out; +using torch::executor::native::dequantize_per_tensor_out; +using torch::executor::native::dequantize_per_tensor_tensor_args_out; +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 100); + double scale = 0.5; + int64_t zero_point = 30; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 + Tensor expected = tfo.full({3, 5}, 35); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, AllDtypesSupported) { + et_pal_init(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); +} + +/// Test all supported output dtypes for dequantization +template +void test_output_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 100); + double scale = 0.5; + int64_t zero_point = 30; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 = 35 + Tensor expected = tfo.full({3, 5}, 35); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(OUT_DTYPE), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, AllOutputDtypesSupported) { + et_pal_init(); + test_output_dtype(); + test_output_dtype(); + test_output_dtype(); +} + +TEST(OpDequantizeOutTest, HalfOutput) { + et_pal_init(); + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 10); + double scale = 0.5; + int64_t zero_point = 100000; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (10 - 100000) * 0.5 = -49995 + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(ScalarType::Half), + out); + + // The expected result should be (10 - 100000) * 0.5 = -49995 + Tensor expected = tfo.full({3, 5}, -49995); + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, DoubleOutput) { + et_pal_init(); + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 10); + double scale = 0.5; + int64_t zero_point = 100000; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(ScalarType::Double), + out); + + // The expected result should be (10 - 100000) * 0.5 = -49995 + Tensor expected = tfo.full({3, 5}, -49995); + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, NonWholeNumbers) { + et_pal_init(); + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 100); + double scale = 0.45; + int64_t zero_point = 30; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 + Tensor expected = tfo.full({3, 5}, 31.5); + dequantize_per_tensor_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, TensorArgOverload) { + et_pal_init(); + TensorFactory tf_byte; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_byte.full({3, 5}, 100); + Tensor scale = tf_double.make({1}, {0.45}); + Tensor zero_point = tf_long.make({1}, {30}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // (100 - 30) * 0.5 + Tensor expected = tfo.full({3, 5}, 31.5); + dequantize_per_tensor_tensor_args_out( + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +template +void test_per_channel_dtype() { + TensorFactory tf; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf.full({3, 2}, 100); + Tensor scale = tf_double.make({2}, {0.5, 1}); + Tensor zero_point = tf_long.make({2}, {30, 60}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 2}); + // (100 - 30) * 0.5 + // (100 - 60) * 1 + Tensor expected = tfo.make({3, 2}, {35, 40, 35, 40, 35, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/1, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Test with a different axis + out = tfo.zeros({3, 2}); + scale = tf_double.make({3}, {0.5, 0.75, 1}); + zero_point = tf_long.make({3}, {30, 50, 60}); + // (100 - 30) * 0.5 + // (100 - 50) * 0.75 + // (100 - 60) * 1 + expected = tfo.make({3, 2}, {35, 35, 37.5, 37.5, 40, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/0, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Test with a different axis + out = tfo.zeros({3}); + input = tf.make({3}, {100, 100, 100}); + scale = tf_double.make({3}, {0.5, 0.75, 1}); + zero_point = tf_long.make({3}, {30, 50, 60}); + // (100 - 30) * 0.5 + // (100 - 50) * 0.75 + // (100 - 60) * 1 + expected = tfo.make({3}, {35, 37.5, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/0, + quant_min, + quant_max, + DTYPE, + optional(), + out); + EXPECT_TENSOR_EQ(out, expected); + + // Test with a different axis + input = tf.full({3, 19}, 100); + out = tfo.zeros({3, 19}); + scale = tf_double.make({3}, {0.5, 0.75, 1}); + zero_point = tf_long.make({3}, {30, 50, 60}); + // (100 - 30) * 0.5 + // (100 - 50) * 0.75 + // (100 - 60) * 1 + expected = tfo.make( + {3, 19}, + {35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 37.5, 37.5, 37.5, 37.5, 37.5, + 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, 37.5, + 37.5, 37.5, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40}); + dequantize_per_channel_out( + input, + scale, + zero_point, + /*axis=*/0, + quant_min, + quant_max, + DTYPE, + optional(), + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpDequantizeOutTest, DequantizePerChannel) { + et_pal_init(); + test_per_channel_dtype(); + test_per_channel_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding2b_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding2b_test.cpp new file mode 100644 index 0000000..597492e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding2b_test.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_embedding_2bit_out; + +using torch::executor::testing::TensorFactory; + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbedding) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -2, 0}); + + // -2, 1, 0, 1, -> 0, 3, 2, 3 -> (reverse) 11 10 11 00 -> 236 + // 0, -1, -2, 0, -> 2, 1, 0, 2 -> (reverse) 10 00 01 10 -> 134 + // -2, -1, 0, 1, -> 0, 1, 2, 3 -> (reverse) 11 10 01 00 -> 228 + + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-1.5, 0.0, -0.5, 0.0, -3.0, -1.5, 0.0, 1.5, 2.0, 1.0, 0.0, 2.0}); + + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_2bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Groupwise quantization. groupsize = 2 + + weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.0, 2.5, 3.0}); + weight_zero_points = tf.make({3, 2}, {1, -2, 0, 1, -2, -1}); + + // -2, 1, 0, 1, -> 0, 3, 2, 3 -> (reverse) 11 10 11 00 -> 236 + // 0, -1, -2, 0, -> 2, 1, 0, 2 -> (reverse) 10 00 01 10 -> 134 + // -2, -1, 0, 1, -> 0, 1, 2, 3 -> (reverse) 11 10 01 00 -> 228 + + qweight = tfb.make({3, 1}, {236, 134, 228}); + + indices = tfl.make({3}, {0, 2, 1}); + + out = tf.zeros({3, 4}); + expected = tf.make( + {3, 4}, {-1.5, 0.0, 2.0, 3.0, 0.0, 2.5, 3.0, 6.0, 0.0, -1.5, -6.0, -2.0}); + + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingInt32Indices) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfi; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -2, 0}); + + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + + Tensor indices = tfi.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-1.5, 0.0, -0.5, 0.0, -3.0, -1.5, 0.0, 1.5, 2.0, 1.0, 0.0, 2.0}); + + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_2bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingDeath1) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({4}, {0.5, 1.0, 1.5, 3.3}); + Tensor weight_zero_points = tf.make({4}, {1, -2, 1, 0}); + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + Tensor out = tf.zeros({3, 4}); + + // qvals are incompatible shape with scales/zeros + ET_EXPECT_DEATH( + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingDeath2) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({2}, {0.5, 1.0}); + Tensor weight_zero_points = tf.make({2}, {1, -2}); + Tensor qweight = tfb.make({3, 1}, {236, 134, 228}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + Tensor out = tf.zeros({3, 4}); + + // qvals are incompatible shape with scales/zeros + ET_EXPECT_DEATH( + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbedding2bTest, TestGroupWiseQuantizedEmbeddingDeath3) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -2; + int64_t quant_max = 1; + + Tensor weight_scales = tf.make({2, 3}, {1.0, 1.0, 1.0, 1.0, 1.0, 1.0}); + Tensor weight_zero_points = tf.make({2, 3}, {0, 0, 0, 0, 0, 0}); + Tensor qweight = tfb.make({2, 1}, {236, 134}); + Tensor indices = tfl.make({2}, {0, 2}); + Tensor out = tf.zeros({2, 8}); + + // scales/zeros imply 3 groups, which does not divide embed dimension from + // qvals (8) + ET_EXPECT_DEATH( + quantized_embedding_2bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding4b_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding4b_test.cpp new file mode 100644 index 0000000..4646f18 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding4b_test.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_embedding_4bit_out; + +using torch::executor::testing::TensorFactory; + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbedding) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -5, 0}); + + // -3, 1, 6, 7, + // 2, -5, -4, 0, + // -8, 3, -1, 6, + + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-2.0, 0.0, 2.5, 3.0, -12.0, 4.5, -1.5, 9.0, 7.0, 0.0, 1.0, 5.0}); + + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_4bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Groupwise quantization. groupsize = 2 + weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.0, 2.5, 3.0}); + weight_zero_points = tf.make({3, 2}, {1, -5, 0, 2, -3, -1}); + /* + fp_weight = [-2.0, 0.0, 11.0, 12.0, + 3.0, -7.5, -12.0, -4.0, + -12.5, 15.0, 0.0, 21.0] + */ + + out = tf.zeros({3, 4}); + expected = tf.make( + {3, 4}, + {-2.0, 0.0, 11.0, 12.0, -12.5, 15.0, 0.0, 21.0, 3.0, -7.5, -12.0, -4.0}); + + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbeddingInt32Indices) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfi; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, -5, 0}); + + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + + Tensor indices = tfi.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {-2.0, 0.0, 2.5, 3.0, -12.0, 4.5, -1.5, 9.0, 7.0, 0.0, 1.0, 5.0}); + + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + out = tf.zeros({3, 4}); + auto context = KernelRuntimeContext(); + torch::executor::native::quantized_embedding_4bit_out( + context, + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbeddingDeath1) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({4}, {0.5, 1.0, 1.5, 3.3}); + Tensor weight_zero_points = tf.make({4}, {1, 5, 7, 5}); + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbedding4bTest, TestGroupWiseQuantizedEmbeddingDeath2) { + et_pal_init(); + TensorFactory tfb; + TensorFactory tf; + TensorFactory tfl; + + int64_t quant_min = -8; + int64_t quant_max = 7; + + Tensor weight_scales = tf.make({2}, {0.5, 1.0}); + Tensor weight_zero_points = tf.make({2}, {1, 5}); + Tensor qweight = tfb.make({3, 2}, {89, 239, 163, 72, 11, 126}); + Tensor indices = tfl.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_4bit_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding_test.cpp new file mode 100644 index 0000000..5d5ad45 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_embedding_test.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::dequantize_per_tensor_out; +using torch::executor::native::embedding_out; +using torch::executor::native::quantize_per_tensor_out; +using torch::executor::native::quantized_embedding_byte_out; + +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + TensorFactory tf_l; + + float scale = 0.5; + float zero_point = 1; + int64_t quant_min = 0; + int64_t quant_max = 255; + + // clang-format off + Tensor weight = tf.make({3, 2}, {3.5, 2.0, + 4, 1, + 5.5, 13.2}); + // clang-format on + // TODO make these different per dimension once per channel quant ops + // available + Tensor weight_scales = tf.full({3}, scale); + Tensor weight_zero_points = tf.full({3}, zero_point); + + Tensor indices = tf_l.make({2}, {0, 2}); + + Tensor out = tf.zeros({2, 2}); + + TensorFactory tfo; + Tensor qweight = tfo.zeros({3, 2}); + + // 3.5 / 0.5 + 1 = 8 + // 2 / 0.5 + 1 = 5 + // 4 / 0.5 + 1 = 9 + // 1 / 0.5 + 1 = 3 + // 5.5 / 0.5 + 1 = 12 + // 13.2 / 0.5 + 1 = 27 + quantize_per_tensor_out( + weight, scale, (float)zero_point, quant_min, quant_max, DTYPE, qweight); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + // (8 - 1) * 0.5 = 3.5 + // (5 - 1) * 0.5 = 2.0 + // (12 - 1) * 0.5 = 5.5 + // (27 - 1) * 0.5 = 13 + // clang-format off + Tensor expected = tf.make({2, 2}, {3.5, 2, + 5.5, 13}); + // clang-format on + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbeddingTest, AllDtypesSupported) { + test_dtype(); +} + +// Q -> DQ -> FP Embedding should be == to Q -> QEmbedding Bytes +TEST(OpQuantizedEmbeddingTest, ConsitencyWithReferencePattern) { + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + float scale = 0.5; + float zero_point = 1; + int64_t quant_min = 0; + int64_t quant_max = 255; + + // Do Q -> QEmbedding Bytes + Tensor weight = tf.make({3, 1}, {3.5, 5.5, 1.0}); + // TODO make these different per dimension once per channel quant ops + // available + Tensor weight_scales = tf.full({3}, scale); + Tensor weight_zero_points = tf.full({3}, zero_point); + + Tensor indices = tf_l.make({2}, {0, 2}); + + Tensor out = tf.zeros({2, 1}); + Tensor fp_out = tf.zeros({2, 1}); + + TensorFactory tfo; + Tensor qweight = tfo.zeros({3, 1}); + KernelRuntimeContext context{}; + // 3.5 / 0.5 + 1 = 8 + // 5.5 / 0.5 + 1 = 12 + // 1 / 0.5 + 1 = 3 + quantize_per_tensor_out( + weight, + scale, + (int64_t)zero_point, + quant_min, + quant_max, + ScalarType::Byte, + qweight); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + // Do Q DQ embedding + dequantize_per_tensor_out( + qweight, + scale, + (int64_t)zero_point, + quant_min, + quant_max, + ScalarType::Byte, + optional(), + weight); + + embedding_out( + context, + weight, + indices, + /*padding_idx=*/0, + /*scale_grad_by_freq=*/false, + /*sparse=*/false, + fp_out); + + // can lossessly dq here so retrive the full information + // (8 - 1) * 0.5 = 3.5 + // (3 - 1) * 0.5 = 1 + Tensor expected = tf.make({2, 1}, {3.5, 1}); + EXPECT_TENSOR_EQ(out, fp_out); + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbedding) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3}, {1, 5, 7}); + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + Tensor expected = tf.make( + {3, 4}, {3.5, 4.5, 5.5, 6.5, 1.5, 3.0, 4.5, 7.5, 5.0, 7.0, 7.0, 9.0}); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); + + // Groupwise quantization. groupsize = 2 + weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.0, 2.5, 3.0}); + weight_zero_points = tf.make({3, 2}, {1, 5, 7, 9, 11, 13}); + /* + fp_weight = [3.5, 4.5, 7, 9, + 4.5, 7.5, 6, 10, + -7.5, -5.0, -9.0, -3.0] + */ + + out = tf.zeros({3, 4}); + expected = tf.make( + {3, 4}, {3.5, 4.5, 7, 9, -7.5, -5.0, -9.0, -3.0, 4.5, 7.5, 6, 10}); + + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath1) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({4}, {0.5, 1.0, 1.5, 3.3}); + Tensor weight_zero_points = tf.make({4}, {1, 5, 7, 5}); + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath2) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({2}, {0.5, 1.0}); + Tensor weight_zero_points = tf.make({2}, {1, 5}); + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 4}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath3) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.5, 3.5, 3.5}); + Tensor weight_zero_points = tf.make({3, 2}, {1, 5, 7, 9, 11, 13}); + TensorFactory tfo; + Tensor qweight = tfo.make({3, 3}, {8, 10, 12, 14, 10, 12, 12, 14, 8}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 3}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath4) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.5, 3.5, 3.5}); + Tensor weight_zero_points = tf.make({3}, {1, 5, 7}); + TensorFactory tfo; + Tensor qweight = tfo.make({3, 3}, {8, 10, 12, 14, 10, 12, 12, 14, 8}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 3}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestGroupWiseQuantizedEmbeddingDeath5) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_i; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + Tensor weight_scales = tf.make({3, 2}, {0.5, 1.0, 1.5, 2.5, 3.5, 3.5}); + Tensor weight_zero_points = tf.make({3, 3}, {1, 5, 7, 1, 5, 7, 1, 5, 7}); + TensorFactory tfo; + Tensor qweight = tfo.make({3, 3}, {8, 10, 12, 14, 10, 12, 12, 14, 8}); + + Tensor indices = tf_l.make({3}, {0, 2, 1}); + + Tensor out = tf.zeros({3, 3}); + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} + +TEST(OpQuantizedEmbeddingTest, TestOutOfBoundsIndex) { + et_pal_init(); + TensorFactory tf; + TensorFactory tf_l; + + int64_t quant_min = 0; + int64_t quant_max = 255; + + // Create a weight tensor with 3 rows + TensorFactory tfo; + Tensor qweight = + tfo.make({3, 4}, {8, 10, 12, 14, 10, 12, 12, 14, 8, 9, 10, 12}); + + // Create weight_scales with the same number of rows + Tensor weight_scales = tf.make({3, 1}, {0.5, 1.0, 1.5}); + Tensor weight_zero_points = tf.make({3, 1}, {1, 5, 7}); + + // Create indices with an out-of-bounds index (3, which is >= weight.size(0)) + Tensor indices = tf_l.make({2}, {1, 3}); + + Tensor out = tf.zeros({2, 4}); + + // Expect death when accessing an out-of-bounds index + ET_EXPECT_DEATH( + quantized_embedding_byte_out( + qweight, + weight_scales, + weight_zero_points, + quant_min, + quant_max, + indices, + out), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_linear_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_linear_test.cpp new file mode 100644 index 0000000..e659b41 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_linear_test.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_mixed_linear_out; +using torch::executor::testing::TensorFactory; + +class OpQuantizedMixedDtypeLinearTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + torch::executor::runtime_init(); + } +}; + +template +void test_dtype() { + TensorFactory tf; + TensorFactory tf_char; + TensorFactory tf_out; + + Tensor input = tf.make( + /*sizes=*/{1, 3}, + /*data=*/{1.0, 1.5, 2.0}); + Tensor weight = tf_char.make( + /*sizes=*/{2, 3}, + /*data=*/{5, 3, 1, 4, 2, 1}); + Tensor weight_scales = tf.make( + /*sizes=*/{2}, + /*data=*/{0.2, 0.4}); + const optional opt_weight_zp{}; + const optional opt_dtype_out{}; + + Tensor out = tf_out.zeros({1, 2}); + + Tensor expected = tf_out.make( + /*sizes=*/{1, 2}, + /*data=*/{2.3, 3.6}); + + KernelRuntimeContext ctx{}; + + quantized_mixed_linear_out( + ctx, input, weight, weight_scales, opt_weight_zp, opt_dtype_out, out); + + EXPECT_TENSOR_CLOSE(out, expected); +} + +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputFloatOutput) { + test_dtype(); +} + +#if 0 +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputHalfOutput) { + test_dtype(); +} + +// need to relax tolerance +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputFloatOutput) { + test_dtype(); +} + +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputHalfOutput) { + test_dtype(); +} +#endif + +template +void test_dtype_partials() { + TensorFactory tf; + TensorFactory tf_char; + TensorFactory tf_out; + + Tensor input = tf.make( + /*sizes=*/{1, 3}, + /*data=*/{1.0, 1.5, 2.0}); + Tensor weight = tf_char.make( + /*sizes=*/{2, 3}, + /*data=*/{5, 3, 1, 4, 2, 1}); + Tensor weight_scales = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{0.2, 1, 0.4, 0.5}); + const optional opt_weight_zp{}; + const optional opt_dtype_out{}; + + Tensor out = tf_out.zeros({1, 2}); + + Tensor expected = tf_out.make( + /*sizes=*/{1, 2}, + /*data=*/ + {(1.0 * 5 + 1.5 * 3) * 0.2 + 2.0 * 1 * 1, + (1.0 * 4 + 1.5 * 2) * 0.4 + 2.0 * 1 * 0.5}); + + KernelRuntimeContext ctx{}; + + quantized_mixed_linear_out( + ctx, input, weight, weight_scales, opt_weight_zp, opt_dtype_out, out); + + EXPECT_TENSOR_CLOSE(out, expected); +} + +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputFloatOutput_Partials) { + test_dtype_partials(); +} + +#if 0 +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, FloatInputHalfOutput_Partials) { + test_dtype_partials(); +} + +// need to relax tolerance +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputFloatOutput_Partials) { + test_dtype_partials(); +} + +// need << +TEST_F(OpQuantizedMixedDtypeLinearTest, HalfInputHalfOutput_Partials) { + test_dtype_partials(); +} +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_mm_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_mm_test.cpp new file mode 100644 index 0000000..8051f29 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_mixed_mm_test.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the aten operator +#include // Declares the quantized operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using std::optional; +using torch::executor::native::quantized_mixed_mm_out; +using torch::executor::testing::TensorFactory; + +class OpQuantizedMixedMMTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + torch::executor::runtime_init(); + } +}; + +template +void test_dtype() { + TensorFactory tf; + TensorFactory tf_char; + + Tensor input = tf.make( + /*sizes=*/{1, 3}, + /*data=*/{1.0, 1.5, 2.0}); + Tensor weight = tf_char.make( + /*sizes=*/{3, 2}, + /*data=*/{5, 4, 3, 2, 1, 1}); + Tensor weight_scales = tf.make( + /*sizes=*/{3}, + /*data=*/{0.2, 0.4, 0.5}); + const optional opt_weight_zp{}; + + Tensor out = tf.zeros({1, 2}); + + Tensor expected = tf.make( + /*sizes=*/{1, 2}, + /*data=*/{3.8, 3.0}); + + KernelRuntimeContext ctx{}; + + quantized_mixed_mm_out(ctx, input, weight, weight_scales, opt_weight_zp, out); + + EXPECT_TENSOR_CLOSE(out, expected); +} + +TEST_F(OpQuantizedMixedMMTest, FloatInput) { + test_dtype(); +} + +TEST_F(OpQuantizedMixedMMTest, HalfInput) { + test_dtype(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_quantize_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_quantize_test.cpp new file mode 100644 index 0000000..b450ec0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/op_quantize_test.cpp @@ -0,0 +1,983 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include // Declares the operator +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using torch::executor::native::quantize_per_channel_out; +using torch::executor::native::quantize_per_tensor_out; +using torch::executor::native::quantize_per_tensor_tensor_args_out; +using torch::executor::testing::TensorFactory; + +/// A generic smoke test that works for any dtype that supports ones() and +/// zeros(). +template +void test_dtype() { + TensorFactory tf; + + Tensor input = tf.full({3, 5}, 4); + double scale = 0.5; + + int64_t zero_point = 108; + int64_t quant_min = 0; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 127 + Tensor expected = tfo.full({3, 5}, 116); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, DTYPE, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +template +void test_input_dtype() { + TensorFactory tf_input; + + Tensor input = tf_input.full({3, 5}, 4); + double scale = 0.5; + int64_t zero_point = 108; + int64_t quant_min = 0; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 108 = 116 + Tensor expected = tfo.full({3, 5}, 116); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, AllInputDtypesSupported) { + test_input_dtype(); + test_input_dtype(); + test_input_dtype(); +} + +TEST(OpQuantizeOutTest, AllDtypesSupported) { + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); + test_dtype(); +} + +TEST(OpQuantizeOutTest, DoubleInputTest) { + TensorFactory tf_double; + + // Test with a more complex value that might have precision differences + Tensor input = tf_double.full({2, 3}, 3.14159265359); + double scale = 0.01; + int64_t zero_point = -100; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // 3.14159265359 / 0.01 - 100 = 214.159265359 + Tensor expected = tfo.full({2, 3}, 214); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, HalfInputTest) { + TensorFactory tf_half; + + Tensor input = tf_half.full({2, 3}, 2.5); + double scale = 0.5; + int64_t zero_point = 10; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // 2.5 / 0.5 + 10 = 15 + Tensor expected = tfo.full({2, 3}, 15); + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, TensorArgOverload) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 5}, 4); + Tensor scale = tf_double.make({1}, {0.5}); + Tensor zero_point = tf_long.make({1}, {127}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 5}); + // 4 / 0.5 + 127 + Tensor expected = tfo.full({3, 5}, 135); + auto context = torch::executor::KernelRuntimeContext(); + quantize_per_tensor_tensor_args_out( + context, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Byte, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, TestOutOfBounds) { + // Test where 1.0 / epsilon is larger than 8bit integer. + + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.ones({1, 3, 256, 256}); + + Tensor scale = tf_double.make({1}, {0.0011316323652863503}); + Tensor zero_point = tf_long.make({1}, {0}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({1, 3, 256, 256}); + + Tensor expected = tfo.full({1, 3, 256, 256}, 127); + + auto context = torch::executor::KernelRuntimeContext(); + quantize_per_tensor_tensor_args_out( + context, + input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannel) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 2}, 4); + Tensor scale = tf_double.make({2}, {0.5, 1}); + Tensor zero_point = tf_long.make({2}, {127, 63}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 2}); + // 4 / 0.5 + 127 + // 4 / 1 + 63 + Tensor expected = tfo.make({3, 2}, {135, 67, 135, 67, 135, 67}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelAxis0) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 2}, 4); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 2.0}); + Tensor zero_point = tf_long.make({3}, {100, 50, 25}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 2}); + // Channel 0: 4 / 0.5 + 100 = 108 + // Channel 1: 4 / 1.0 + 50 = 54 + // Channel 2: 4 / 2.0 + 25 = 27 + Tensor expected = tfo.make({3, 2}, {108, 108, 54, 54, 27, 27}); + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannel3D) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test 3D tensor with axis=1 (middle dimension) + Tensor input = tf_float.full({2, 3, 4}, 6); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 1.5}); + Tensor zero_point = tf_long.make({3}, {10, 20, 30}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3, 4}); + // Channel 0: 6 / 0.5 + 10 = 22 + // Channel 1: 6 / 1.0 + 20 = 26 + // Channel 2: 6 / 1.5 + 30 = 34 + Tensor expected = tfo.make( + {2, 3, 4}, + { + 22, 22, 22, 22, // First batch, channel 0 + 26, 26, 26, 26, // First batch, channel 1 + 34, 34, 34, 34, // First batch, channel 2 + 22, 22, 22, 22, // Second batch, channel 0 + 26, 26, 26, 26, // Second batch, channel 1 + 34, 34, 34, 34 // Second batch, channel 2 + }); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannel4D) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test 4D tensor with axis=2 (typical conv weight layout: N,C,H,W) + Tensor input = tf_float.full({2, 2, 3, 2}, 8); + Tensor scale = tf_double.make({3}, {0.25, 0.5, 1.0}); + Tensor zero_point = tf_long.make({3}, {0, 10, 20}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 2, 3, 2}); + // Channel 0: 8 / 0.25 + 0 = 32 + // Channel 1: 8 / 0.5 + 10 = 26 + // Channel 2: 8 / 1.0 + 20 = 28 + std::vector expected_data; + for (int n = 0; n < 2; n++) { + for (int c = 0; c < 2; c++) { + for (int h = 0; h < 3; h++) { + for (int w = 0; w < 2; w++) { + int8_t val = (h == 0) ? 32 : (h == 1) ? 26 : 28; + expected_data.push_back(val); + } + } + } + } + Tensor expected = tfo.make({2, 2, 3, 2}, expected_data); + quantize_per_channel_out( + input, scale, zero_point, 2, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelNegativeAxis) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({2, 3}, 5); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 2.0}); + Tensor zero_point = tf_long.make({3}, {0, 10, 20}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // Using axis=-1 should be equivalent to axis=1 for 2D tensor + // Channel 0: 5 / 0.5 + 0 = 10 + // Channel 1: 5 / 1.0 + 10 = 15 + // Channel 2: 5 / 2.0 + 20 = 22 (rounded from 22.5) + Tensor expected = tfo.make({2, 3}, {10, 15, 22, 10, 15, 22}); + quantize_per_channel_out( + input, + scale, + zero_point, + -1, + quant_min, + quant_max, + ScalarType::Byte, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelSingleChannel) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({3, 1, 4}, 7); + Tensor scale = tf_double.make({1}, {0.5}); + Tensor zero_point = tf_long.make({1}, {128}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({3, 1, 4}); + // Single channel: 7 / 0.5 + 128 = 142 + Tensor expected = tfo.full({3, 1, 4}, 142); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelDifferentInputTypes) { + TensorFactory tf_double_input; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_double_input.full({2, 2}, 3.14159); + Tensor scale = tf_double.make({2}, {0.01, 0.02}); + Tensor zero_point = tf_long.make({2}, {0, 100}); + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 2}); + // Channel 0: 3.14159 / 0.01 + 0 = 314 -> clamped to 127 + // Channel 1: 3.14159 / 0.02 + 100 = 257 -> clamped to 127 + Tensor expected = tfo.make({2, 2}, {127, 127, 127, 127}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelDifferentOutputTypes) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + Tensor input = tf_float.full({2, 2}, 10); + Tensor scale = tf_double.make({2}, {1.0, 2.0}); + Tensor zero_point = tf_long.make({2}, {1000, 2000}); + int64_t quant_min = -32768; + int64_t quant_max = 32767; + + // Test with 16-bit output + TensorFactory tfo; + Tensor out = tfo.zeros({2, 2}); + // Channel 0: 10 / 1.0 + 1000 = 1010 + // Channel 1: 10 / 2.0 + 2000 = 2005 + Tensor expected = tfo.make({2, 2}, {1010, 2005, 1010, 2005}); + quantize_per_channel_out( + input, + scale, + zero_point, + 1, + quant_min, + quant_max, + ScalarType::Short, + out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelMixedValues) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test with different input values per position + Tensor input = tf_float.make({2, 3}, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}); + Tensor scale = tf_double.make({3}, {0.5, 1.0, 1.5}); + Tensor zero_point = tf_long.make({3}, {10, 20, 30}); + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 3}); + // Row 0: [1.0/0.5+10, 2.0/1.0+20, 3.0/1.5+30] = [12, 22, 32] + // Row 1: [4.0/0.5+10, 5.0/1.0+20, 6.0/1.5+30] = [18, 25, 34] + Tensor expected = tfo.make({2, 3}, {12, 22, 32, 18, 25, 34}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, QuantizePerChannelClampingBehavior) { + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + // Test values that will exceed quant_min/quant_max bounds + Tensor input = tf_float.make({1, 3}, {-100.0, 0.0, 100.0}); + Tensor scale = tf_double.make({3}, {1.0, 1.0, 1.0}); + Tensor zero_point = tf_long.make({3}, {0, 0, 0}); + int64_t quant_min = -10; + int64_t quant_max = 10; + + TensorFactory tfo; + Tensor out = tfo.zeros({1, 3}); + // Values: [-100, 0, 100] should be clamped to [-10, 0, 10] + Tensor expected = tfo.make({1, 3}, {-10, 0, 10}); + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargePerChannelClampingSIMDPath) { + // Test quant_min/quant_max clamping with large tensor to exercise SIMD path + // Shape: [3, 80] with axis=0 (3 channels, 80 elements each) + // 80 elements = 10 SIMD iterations (8 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 3; + const int block_size = 80; + std::vector input_data(num_channels * block_size); + + // Create input data with values that exceed quant_min/quant_max + for (int ch = 0; ch < num_channels; ch++) { + for (int i = 0; i < block_size; i++) { + // Generate values from -150 to 150 to test clamping + input_data[ch * block_size + i] = + static_cast((i % 40) - 20) * 5.0f * (ch + 1); + } + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + // Use uniform scale and zero_point for all channels + Tensor scale = tf_double.make({num_channels}, {1.0, 1.0, 1.0}); + Tensor zero_point = tf_long.make({num_channels}, {0, 0, 0}); + + // Set narrow quant_min/quant_max to force clamping + int64_t quant_min = -20; + int64_t quant_max = 20; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values with clamping + std::vector expected_data(num_channels * block_size); + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + // Use double precision to avoid overflow + double val = static_cast(input_data[idx]) / ch_scale; + // Clamp before converting to int to avoid overflow + val = std::max(-1000.0, std::min(1000.0, val)); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + // Apply quant_min/quant_max clamping + qval = std::max( + static_cast(quant_min), + std::min(static_cast(quant_max), qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +// Large tensor tests to ensure ARM NEON SIMD path is exercised + +TEST(OpQuantizeOutTest, LargeTensorUInt8SIMDPath) { + // Test with 64 elements to fully exercise SIMD path (8 elements per + // iteration) + TensorFactory tf_float; + + // Create input with known values for verification + std::vector input_data(64); + for (size_t i = 0; i < 64; i++) { + input_data[i] = static_cast(i) * 0.5f; // 0.0, 0.5, 1.0, 1.5, ... + } + Tensor input = tf_float.make({64}, input_data); + + double scale = 0.1; + int64_t zero_point = 10; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({64}); + + // Compute expected values: round(value / scale) + zero_point + std::vector expected_data(64); + for (size_t i = 0; i < 64; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({64}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargeTensorInt8SIMDPath) { + // Test with 72 elements (9 SIMD iterations of 8) to test both vectorized and + // scalar paths + TensorFactory tf_float; + + std::vector input_data(72); + for (size_t i = 0; i < 72; i++) { + // Mix of positive and negative values + input_data[i] = static_cast(static_cast(i) - 36) * 0.25f; + } + Tensor input = tf_float.make({72}, input_data); + + double scale = 0.2; + int64_t zero_point = 0; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({72}); + + // Compute expected values + std::vector expected_data(72); + for (size_t i = 0; i < 72; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(127, std::max(-128, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({72}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargeTensorWithRemainderUInt8) { + // Test with 100 elements (12 SIMD iterations + 4 remainder) to test remainder + // handling + TensorFactory tf_float; + + std::vector input_data(100); + for (size_t i = 0; i < 100; i++) { + input_data[i] = static_cast(i % 50) * 0.3f; + } + Tensor input = tf_float.make({100}, input_data); + + double scale = 0.15; + int64_t zero_point = 128; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({100}); + + std::vector expected_data(100); + for (size_t i = 0; i < 100; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({100}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargeTensorWithRemainderInt8) { + // Test with 99 elements (12 SIMD iterations + 3 remainder) + TensorFactory tf_float; + + std::vector input_data(99); + for (size_t i = 0; i < 99; i++) { + input_data[i] = std::sin(static_cast(i) * 0.1f) * 10.0f; + } + Tensor input = tf_float.make({99}, input_data); + + double scale = 0.1; + int64_t zero_point = 5; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({99}); + + std::vector expected_data(99); + for (size_t i = 0; i < 99; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(127, std::max(-128, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({99}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, VeryLargeTensor2DUInt8) { + // Test with realistic 2D tensor size that would be used in neural networks + // 256x256 = 65536 elements (8192 SIMD iterations) + TensorFactory tf_float; + + std::vector input_data(256 * 256); + for (size_t i = 0; i < 256 * 256; i++) { + // Generate diverse values in a safe range + input_data[i] = + static_cast((static_cast(i % 256) - 128)) * 0.05f; + } + Tensor input = tf_float.make({256, 256}, input_data); + + double scale = 0.05; + int64_t zero_point = 128; + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({256, 256}); + + // Compute expected values with proper overflow handling + std::vector expected_data(256 * 256); + for (size_t i = 0; i < 256 * 256; i++) { + // Use double precision to avoid overflow + double val = static_cast(input_data[i]) / scale; + // Clamp before converting to int to avoid overflow + val = std::max(-1000.0, std::min(1000.0, val)); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(zero_point); + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({256, 256}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, VeryLargeTensor3DInt8) { + // Test with 3D tensor (batch_size=2, height=64, width=128) = 16384 elements + TensorFactory tf_float; + + const size_t total_elements = 2 * 64 * 128; + std::vector input_data(total_elements); + for (size_t i = 0; i < total_elements; i++) { + input_data[i] = std::cos(static_cast(i) * 0.01f) * 8.0f; + } + Tensor input = tf_float.make({2, 64, 128}, input_data); + + double scale = 0.0625; // 1/16 + int64_t zero_point = -10; + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({2, 64, 128}); + + std::vector expected_data(total_elements); + for (size_t i = 0; i < total_elements; i++) { + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(127, std::max(-128, qval)); + expected_data[i] = static_cast(qval); + } + Tensor expected = tfo.make({2, 64, 128}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, EdgeCaseSizesSIMD) { + // Test specific sizes around SIMD boundaries + TensorFactory tf_float; + TensorFactory tfo; + + double scale = 0.1; + int64_t zero_point = 100; + int64_t quant_min = 0; + int64_t quant_max = 255; + + // Test sizes: 7 (just before SIMD), 8 (exactly 1 SIMD), 9 (1 SIMD + 1), 15, + // 16, 17 + std::vector test_sizes = { + 7, 8, 9, 15, 16, 17, 23, 24, 25, 31, 32, 33}; + + for (size_t size : test_sizes) { + std::vector input_data(size); + std::vector expected_data(size); + + for (size_t i = 0; i < size; i++) { + input_data[i] = static_cast(i) * 0.3f; + float val = input_data[i] / static_cast(scale); + int32_t qval = static_cast(std::nearbyint(val)) + zero_point; + qval = std::min(255, std::max(0, qval)); + expected_data[i] = static_cast(qval); + } + + Tensor input = tf_float.make({static_cast(size)}, input_data); + Tensor out = tfo.zeros({static_cast(size)}); + Tensor expected = tfo.make({static_cast(size)}, expected_data); + + quantize_per_tensor_out( + input, scale, zero_point, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); + } +} + +// Large tensor tests for per-channel quantization to ensure SIMD path is +// exercised + +TEST(OpQuantizeOutTest, LargePerChannelUInt8SIMDPath) { + // Test per-channel quantization with large blocks (64 elements per channel) + // Shape: [4, 64] with axis=1 (4 channels, 64 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 4; + const int block_size = 64; + std::vector input_data(num_channels * block_size); + + // Create varying input data for each channel + for (int ch = 0; ch < num_channels; ch++) { + for (int i = 0; i < block_size; i++) { + input_data[ch * block_size + i] = static_cast((ch + 1) * i) * 0.1f; + } + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + // Different scale and zero_point for each channel + Tensor scale = tf_double.make({num_channels}, {0.1, 0.2, 0.15, 0.25}); + Tensor zero_point = tf_long.make({num_channels}, {10, 20, 15, 25}); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values + std::vector expected_data(num_channels * block_size); + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + float val = input_data[idx] / static_cast(ch_scale); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + qval = std::min(255, std::max(0, qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, LargePerChannelInt8SIMDPath) { + // Test per-channel quantization with int8 and large blocks + // Shape: [3, 100] with axis=1 (3 channels, 100 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 3; + const int block_size = 100; // 12 SIMD iterations + 4 remainder + std::vector input_data(num_channels * block_size); + + // Create varying input data with negative values + for (int ch = 0; ch < num_channels; ch++) { + for (int i = 0; i < block_size; i++) { + input_data[ch * block_size + i] = + static_cast(i - 50) * 0.2f * (ch + 1); + } + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + Tensor scale = tf_double.make({num_channels}, {0.1, 0.15, 0.2}); + Tensor zero_point = tf_long.make({num_channels}, {0, -5, 5}); + + int64_t quant_min = -128; + int64_t quant_max = 127; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values + std::vector expected_data(num_channels * block_size); + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + float val = input_data[idx] / static_cast(ch_scale); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + qval = std::min(127, std::max(-128, qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Char, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, VeryLargePerChannel2DUInt8) { + // Test realistic neural network weight tensor + // Shape: [128, 256] with axis=0 (128 channels, 256 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int num_channels = 128; + const int block_size = 256; + const int total_elements = num_channels * block_size; + + std::vector input_data(total_elements); + for (int i = 0; i < total_elements; i++) { + input_data[i] = std::sin(static_cast(i) * 0.01f) * 5.0f; + } + Tensor input = tf_float.make({num_channels, block_size}, input_data); + + // Create varying scales and zero_points for each channel + std::vector scales(num_channels); + std::vector zero_points(num_channels); + for (int ch = 0; ch < num_channels; ch++) { + scales[ch] = 0.02 + (ch % 10) * 0.001; // Varying scales + zero_points[ch] = 128 + (ch % 5); // Varying zero_points + } + Tensor scale = tf_double.make({num_channels}, scales); + Tensor zero_point = tf_long.make({num_channels}, zero_points); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({num_channels, block_size}); + + // Compute expected values + std::vector expected_data(total_elements); + for (int ch = 0; ch < num_channels; ch++) { + float inv_scale = 1.0f / static_cast(scales[ch]); + int64_t ch_zero_point = zero_points[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = ch * block_size + i; + float val = input_data[idx] * inv_scale; + // Clamp before converting to avoid overflow + val = std::max(-1000.0f, std::min(1000.0f, val)); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + + qval = std::min(255, std::max(0, qval)); + expected_data[idx] = static_cast(qval); + } + } + Tensor expected = tfo.make({num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 0, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} + +TEST(OpQuantizeOutTest, PerChannelAxis1LargeBlocks) { + // Test per-channel quantization with axis=1 and large contiguous blocks + // Shape: [2, 3, 64] with axis=1 (2 batches, 3 channels, 64 elements each) + TensorFactory tf_float; + TensorFactory tf_double; + TensorFactory tf_long; + + const int batch_size = 2; + const int num_channels = 3; + const int block_size = 64; + const int total_elements = batch_size * num_channels * block_size; + + std::vector input_data(total_elements); + for (int i = 0; i < total_elements; i++) { + input_data[i] = static_cast(i % 100) * 0.1f; + } + Tensor input = + tf_float.make({batch_size, num_channels, block_size}, input_data); + + Tensor scale = tf_double.make({num_channels}, {0.05, 0.1, 0.15}); + Tensor zero_point = tf_long.make({num_channels}, {100, 110, 120}); + + int64_t quant_min = 0; + int64_t quant_max = 255; + + TensorFactory tfo; + Tensor out = tfo.zeros({batch_size, num_channels, block_size}); + + // Compute expected values + std::vector expected_data(total_elements); + for (int b = 0; b < batch_size; b++) { + for (int ch = 0; ch < num_channels; ch++) { + double ch_scale = scale.const_data_ptr()[ch]; + int64_t ch_zero_point = zero_point.const_data_ptr()[ch]; + + for (int i = 0; i < block_size; i++) { + int idx = (b * num_channels + ch) * block_size + i; + float val = input_data[idx] / static_cast(ch_scale); + int32_t qval = static_cast(std::nearbyint(val)) + + static_cast(ch_zero_point); + qval = std::min(255, std::max(0, qval)); + expected_data[idx] = static_cast(qval); + } + } + } + Tensor expected = + tfo.make({batch_size, num_channels, block_size}, expected_data); + + quantize_per_channel_out( + input, scale, zero_point, 1, quant_min, quant_max, ScalarType::Byte, out); + + EXPECT_TENSOR_EQ(out, expected); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/quantized_ops_aot_register.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/quantized_ops_aot_register.cpp new file mode 100644 index 0000000..72da666 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/quantized_ops_aot_register.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +namespace torch { +namespace executor { + +namespace native { + +Tensor& quantize_per_token_out( + RuntimeContext& context, + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out); + +Tensor& quantize_per_token_out_no_context( + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + Tensor& out) { + executorch::aten::RuntimeContext context{}; + ::torch::executor::runtime_init(); + quantize_per_token_out( + context, input, scale, zero_point, quant_min, quant_max, dtype, out); + return out; +} + +at::Tensor quantize_per_token_aten( + const at::Tensor& input, + const at::Tensor& scale, + const at::Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + c10::ScalarType dtype) { + auto sizes = input.sizes().vec(); + auto output = at::zeros(sizes, dtype); + TORCH_CHECK(dtype == c10::ScalarType::Char, "dtype must be char"); + WRAP_TO_ATEN(quantize_per_token_out_no_context, 6) + (input, scale, zero_point, quant_min, quant_max, ScalarType::Char, output); + return output; +} + +Tensor& dequantize_per_token_out( + RuntimeContext& context, + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + ScalarType out_dtype, + Tensor& out); + +Tensor& dequantize_per_token_out_no_context( + const Tensor& input, + const Tensor& scale, + const Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + ScalarType dtype, + ScalarType out_dtype, + Tensor& out) { + executorch::aten::RuntimeContext context{}; + ::torch::executor::runtime_init(); + dequantize_per_token_out( + context, + input, + scale, + zero_point, + quant_min, + quant_max, + dtype, + out_dtype, + out); + return out; +} + +at::Tensor dequantize_per_token_aten( + const at::Tensor& input, + const at::Tensor& scale, + const at::Tensor& zero_point, + int64_t quant_min, + int64_t quant_max, + c10::ScalarType dtype, + c10::ScalarType out_dtype) { + auto sizes = input.sizes().vec(); + auto output = at::zeros(sizes, out_dtype); + TORCH_CHECK(dtype == c10::ScalarType::Char, "dtype must be char"); + TORCH_CHECK(out_dtype == c10::ScalarType::Float, "out_dtype must be float"); + WRAP_TO_ATEN(dequantize_per_token_out_no_context, 7) + (input, + scale, + zero_point, + quant_min, + quant_max, + ScalarType::Char, + ScalarType::Float, + output); + return output; +} + +} // namespace native +} // namespace executor +} // namespace torch + +TORCH_LIBRARY(et_quant_test, m) { + m.def( + "quantize_per_token(Tensor input, Tensor scale, Tensor zero_points, int quant_min, int quant_max, ScalarType dtype) -> Tensor"); + m.def( + "dequantize_per_token(Tensor input, Tensor scale, Tensor zero_points, int quant_min, int quant_max, ScalarType dtype, ScalarType out_dtype) -> Tensor"); +} + +TORCH_LIBRARY_IMPL(et_quant_test, CompositeExplicitAutograd, m) { + m.impl( + "quantize_per_token", torch::executor::native::quantize_per_token_aten); + m.impl( + "dequantize_per_token", + torch::executor::native::dequantize_per_token_aten); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/supported_features_def.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/supported_features_def.yaml new file mode 100644 index 0000000..c97183a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/supported_features_def.yaml @@ -0,0 +1 @@ +# no override diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/targets.bzl new file mode 100644 index 0000000..a107efc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/targets.bzl @@ -0,0 +1,41 @@ +load("@fbsource//xplat/executorch/kernels/test:util.bzl", "define_supported_features_lib", "op_test") + +def define_common_targets(): + define_supported_features_lib() + + op_test("op_quantize_test", kernel_name = "quantized") + op_test("op_dequantize_test", kernel_name = "quantized") + op_test("op_choose_qparams_test", kernel_name = "quantized") + op_test("op_add_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_dequantize", + "//executorch/kernels/quantized/cpu:op_quantize", + "//executorch/kernels/quantized/cpu:op_add", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/kernels/portable/cpu:op_add", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) + op_test("op_embedding_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_dequantize", + "//executorch/kernels/quantized/cpu:op_quantize", + "//executorch/kernels/quantized/cpu:op_add", + "//executorch/kernels/quantized/cpu:op_embedding", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/kernels/portable/cpu:op_embedding", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) + op_test("op_embedding2b_test", kernel_name = "quantized") + op_test("op_embedding4b_test", kernel_name = "quantized") + op_test("op_mixed_mm_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_mixed_mm", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) + op_test("op_mixed_linear_test", kernel_name = "quantized", deps = [ + "//executorch/kernels/quantized/cpu:op_mixed_linear", + "//executorch/kernels/quantized:generated_lib_headers", + "//executorch/kernels/portable:generated_lib_headers", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ]) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_out_variants.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_out_variants.py new file mode 100644 index 0000000..ebc94b4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_out_variants.py @@ -0,0 +1,100 @@ +#!/usr/bin/env fbpython +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import executorch.kernels.quantized # noqa[F401] 'executorch.kernels.quantized' imported but unused + +import torch +import torch.ao.quantization.fx._decomposed # noqa[F401] 'torch.ao.quantization.fx._decomposed' imported but unused +from executorch.exir.dialects._ops import ops +from executorch.exir.passes._quant_patterns_and_replacements import ( # noqa + quantized_decomposed_lib, # noqa +) + + +class TestOutVariants(unittest.TestCase): + def setUp(self) -> None: + super().setUp() + + def test_add_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.add.out) + fn = ops.edge.quantized_decomposed.add.default + out_variant = fn.to_out_variant() + self.assertEqual(out_variant.name(), "quantized_decomposed::add.out") + + def test_choose_qparams_tensor_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.choose_qparams.Tensor_out) + choose_qparams = ops.edge.quantized_decomposed.choose_qparams.tensor + out_variant = choose_qparams.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::choose_qparams.Tensor_out" + ) + + def test_dequantize_per_tensor_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.dequantize_per_tensor.out) + fn = ops.edge.quantized_decomposed.dequantize_per_tensor.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::dequantize_per_tensor.out" + ) + + def test_dequantize_per_tensor_tensor_to_out_variant(self) -> None: + self.assertIsNotNone( + ops.edge.quantized_decomposed.dequantize_per_tensor.Tensor_out + ) + fn = ops.edge.quantized_decomposed.dequantize_per_tensor.tensor + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::dequantize_per_tensor.Tensor_out" + ) + + def test_dequantize_per_channel_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.dequantize_per_channel.out) + fn = ops.edge.quantized_decomposed.dequantize_per_channel.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::dequantize_per_channel.out" + ) + + def test_mixed_linear_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.mixed_linear.out) + fn = ops.edge.quantized_decomposed.mixed_linear.default + out_variant = fn.to_out_variant() + self.assertEqual(out_variant.name(), "quantized_decomposed::mixed_linear.out") + + def test_mixed_mm_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.mixed_mm.out) + fn = ops.edge.quantized_decomposed.mixed_mm.default + out_variant = fn.to_out_variant() + self.assertEqual(out_variant.name(), "quantized_decomposed::mixed_mm.out") + + def test_quantize_per_tensor_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.quantize_per_tensor.out) + fn = ops.edge.quantized_decomposed.quantize_per_tensor.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::quantize_per_tensor.out" + ) + + def test_quantize_per_tensor_tensor_to_out_variant(self) -> None: + self.assertIsNotNone( + ops.edge.quantized_decomposed.quantize_per_tensor.Tensor_out + ) + fn = ops.edge.quantized_decomposed.quantize_per_tensor.tensor + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::quantize_per_tensor.Tensor_out" + ) + + def test_quantize_per_channel_to_out_variant(self) -> None: + self.assertIsNotNone(ops.edge.quantized_decomposed.quantize_per_channel.out) + fn = ops.edge.quantized_decomposed.quantize_per_channel.default + out_variant = fn.to_out_variant() + self.assertEqual( + out_variant.name(), "quantized_decomposed::quantize_per_channel.out" + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_quant_dequant_per_token.py b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_quant_dequant_per_token.py new file mode 100644 index 0000000..1286bae --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/kernels/quantized/test/test_quant_dequant_per_token.py @@ -0,0 +1,149 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-unsafe + +import unittest + +import torch +from torch.ao.quantization.fx._decomposed import quantized_decomposed_lib # noqa: F401 + + +class QuantizePerTokenTest(unittest.TestCase): + + def test_quantize_per_token(self): + input_tensor = torch.tensor( + [[-0.5, 0.3, 1.2], [0.1, -0.8, 2.1], [-5, 1, 2]], dtype=torch.float32 + ) + scale = torch.tensor([0.5, 0.8, 1.0], dtype=torch.float64) + scale = scale.unsqueeze(-1) + zero_point = torch.tensor([-1, -2, 0]) + zero_point = zero_point.unsqueeze(-1) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_quantize_per_token_large_tensor(self): + input_tensor = torch.rand((8, 32)) + scale = torch.rand((8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_quantize_per_token_high_rank(self): + input_tensor = torch.rand((1, 3, 8, 32)) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_quantize_per_token_dynamic(self): + input_tensor = torch.rand((1, 1, 8, 1)) + scale = torch.rand((1, 1, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 1, 8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + input_tensor = torch.rand((1, 3, 8, 1)) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + quantized_tensor = torch.ops.quantized_decomposed.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + expected_quantized_tensor = torch.ops.et_quant_test.quantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8 + ) + + self.assertTrue(torch.equal(quantized_tensor, expected_quantized_tensor)) + + def test_dequantize_per_token(self): + input_tensor = torch.randint(-50, 120, (3, 3), dtype=torch.int8) + scale = torch.tensor([0.5, 0.8, 1.0], dtype=torch.float64) + scale = scale.unsqueeze(-1) + zero_point = torch.tensor([-1, -2, 0]) + zero_point = zero_point.unsqueeze(-1) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + def test_dequantize_per_token_large_tensor(self): + input_tensor = torch.randint(-50, 120, (8, 32), dtype=torch.int8) + scale = torch.rand((8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + def test_dequantize_per_token_high_rank(self): + input_tensor = torch.randint(-50, 120, (1, 3, 8, 32), dtype=torch.int8) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + def test_dequantize_per_token_dynamic(self): + input_tensor = torch.randint(-50, 120, (1, 1, 8, 32), dtype=torch.int8) + scale = torch.rand((1, 1, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 1, 8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) + + input_tensor = torch.randint(-50, 120, (1, 3, 8, 32), dtype=torch.int8) + scale = torch.rand((1, 3, 8, 1), dtype=torch.float64) + zero_point = torch.randint(0, 10, (1, 3, 8, 1)) + dequantized_tensor = torch.ops.quantized_decomposed.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + expected_dequantized_tensor = torch.ops.et_quant_test.dequantize_per_token( + input_tensor, scale, zero_point, -128, 127, torch.int8, torch.float32 + ) + + self.assertTrue(torch.allclose(dequantized_tensor, expected_dequantized_tensor)) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/registration/RegisterAllKernels.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/registration/RegisterAllKernels.cpp new file mode 100644 index 0000000..7b35d22 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/registration/RegisterAllKernels.cpp @@ -0,0 +1,5437 @@ +/* + * CMSIS Pack Kernel Registration + * + * Auto-generated by generate_register_all_kernels.py + * + * This file contains all ExecuTorch kernel registrations, with each operator + * guarded by its corresponding RTE_Components_h define. + * + * When a user selects an operator component in the CMSIS pack, that component + * defines RTE_ML_EXECUTORCH_OP__, which enables the registration + * of that operator in this file. + * + * Define naming convention: + * RTE_ML_EXECUTORCH_OP_PORTABLE_ - Portable operators + * RTE_ML_EXECUTORCH_OP_QUANTIZED_ - Quantized operators + * + * This approach allows: + * 1. Only selected operators to be registered (minimizing code size) + * 2. No per-operator registration files needed + * 3. Single static initialization for all selected operators + */ + +#include "RTE_Components.h" + +#include +#include +#include +#include +#include +#include +#include + +using KernelSpan = ::executorch::runtime::Span< + const ::executorch::runtime::Kernel>; + +namespace torch { +namespace executor { + +// Forward declarations for native functions (in torch::executor::native namespace) +namespace native { + +// ===================================================================== +// PORTABLE OPERATOR FORWARD DECLARATIONS +// ===================================================================== + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE_DIM_ORDER +Tensor& _clone_dim_order_out(KernelRuntimeContext& context, const Tensor& self, bool non_blocking, OptionalArrayRef dim_order, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY_DIM_ORDER +Tensor& _empty_dim_order_out(KernelRuntimeContext& context, IntArrayRef size, OptionalIntArrayRef dim_order, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_DIM_ORDER_COPY +Tensor& _to_dim_order_copy_out(KernelRuntimeContext& context, const Tensor& self, bool non_blocking, OptionalArrayRef dim_order, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ABS +Tensor& abs_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOS +Tensor& acos_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOSH +Tensor& acosh_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADD +Tensor& add_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, const Scalar& alpha, Tensor& out); +Tensor& add_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, const Scalar& alpha, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADDMM +Tensor& addmm_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& mat1, const Tensor& mat2, const Scalar& beta, const Scalar& alpha, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALIAS_COPY +Tensor& alias_copy_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALLCLOSE +Tensor& allclose_out(KernelRuntimeContext& context, const Tensor& self, const Tensor& other, double rtol, double atol, bool equal_nan, bool dummy_param, Tensor& out); +Tensor allclose_tensor(KernelRuntimeContext& context, const Tensor& self, const Tensor& other, double rtol, double atol, bool equal_nan, bool dummy_param); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMAX +Tensor& amax_out(KernelRuntimeContext& context, const Tensor& in, ArrayRef dim_list, bool keepdim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMIN +Tensor& amin_out(KernelRuntimeContext& context, const Tensor& in, ArrayRef dim_list, bool keepdim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ANY +Tensor& any_all_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +Tensor& any_dims_out(KernelRuntimeContext& context, const Tensor& in, optional> dim_list, bool keepdim, Tensor& out); +Tensor& any_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, bool keepdim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARANGE +Tensor& arange_out(KernelRuntimeContext& context, const Scalar& end, Tensor& out); +Tensor& arange_start_out(KernelRuntimeContext& context, const Scalar& start, const Scalar& end, const Scalar& step, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMAX +Tensor& argmax_out(KernelRuntimeContext& context, const Tensor& in, optional dim, bool keepdim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMIN +Tensor& argmin_out(KernelRuntimeContext& context, const Tensor& in, optional dim, bool keepdim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AS_STRIDED_COPY +Tensor& as_strided_copy_out(KernelRuntimeContext& context, const Tensor& in, ArrayRef size, ArrayRef stride, optional storage_offset, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASIN +Tensor& asin_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASINH +Tensor& asinh_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN +Tensor& atan_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN2 +Tensor& atan2_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATANH +Tensor& atanh_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AVG_POOL2D +Tensor& avg_pool2d_out(KernelRuntimeContext& context, const Tensor& in, IntArrayRef kernel_size, IntArrayRef stride, IntArrayRef padding, bool ceil_mode, bool count_include_pad, std::optional divisor_override, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_AND +Tensor& bitwise_and_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& bitwise_and_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_LEFT_SHIFT +Tensor& bitwise_left_shift_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +Tensor& bitwise_left_shift_Tensor_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_NOT +Tensor& bitwise_not_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_OR +Tensor& bitwise_or_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& bitwise_or_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_RIGHT_SHIFT +Tensor& bitwise_right_shift_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +Tensor& bitwise_right_shift_Tensor_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_XOR +Tensor& bitwise_xor_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& bitwise_xor_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BMM +Tensor& bmm_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& mat2, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CAT +Tensor& cat_out(KernelRuntimeContext& context, executorch::aten::ArrayRef tensors, int64_t dim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CDIST_FORWARD +Tensor& _cdist_forward_out(KernelRuntimeContext& context, const Tensor& x1, const Tensor& x2, double p, optional compute_mode, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CEIL +Tensor& ceil_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLAMP +Tensor& clamp_out(KernelRuntimeContext& context, const Tensor& in, const std::optional& min_opt, const std::optional& max_opt, Tensor& out); +Tensor& clamp_tensor_out(KernelRuntimeContext& context, const Tensor& in, const std::optional& min_opt, const std::optional& max_opt, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE +Tensor& clone_out(KernelRuntimeContext& context, const Tensor& self, std::optional memory_format, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONSTANT_PAD_ND +Tensor& constant_pad_nd_out(KernelRuntimeContext& context, const Tensor& in, IntArrayRef pad, const Scalar& value, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION +Tensor& convolution_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& weight, const std::optional& bias, IntArrayRef stride, IntArrayRef padding, IntArrayRef dilation, bool transposed, IntArrayRef output_padding, int64_t groups, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION_BACKWARD +std::tuple convolution_backward_out(KernelRuntimeContext& context, const Tensor& grad_output, const Tensor& input, const Tensor& weight, const OptIntArrayRef bias_sizes_opt, IntArrayRef stride, IntArrayRef padding, IntArrayRef dilation, bool transposed, IntArrayRef output_padding, int64_t groups, executorch::aten::ArrayRef output_mask, Tensor& grad_input, Tensor& grad_weight, Tensor& grad_bias); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COPY +Tensor& copy_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& src, bool non_blocking, Tensor& out); +Tensor& copy_(KernelRuntimeContext& context, Tensor& in, const Tensor& src, bool non_blocking); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COS +Tensor& cos_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COSH +Tensor& cosh_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CUMSUM +Tensor& cumsum_out(KernelRuntimeContext& context, const Tensor& self, int64_t dim, optional enforced_dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DETACH_COPY +Tensor& detach_copy_out(KernelRuntimeContext& context, const Tensor& self, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIAGONAL_COPY +Tensor& diagonal_copy_out(KernelRuntimeContext& context, const Tensor& in, int64_t offset, int64_t dim1, int64_t dim2, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIV +Tensor& div_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +Tensor& div_scalar_mode_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, std::optional mode, Tensor& out); +Tensor& div_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& div_out_mode(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, std::optional mode, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ELU +Tensor& elu_out(KernelRuntimeContext& context, const Tensor& in, const Scalar& alpha, const Scalar& scale, const Scalar& input_scale, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMBEDDING +Tensor& embedding_out(KernelRuntimeContext& context, const Tensor& weight, const Tensor& indices, int64_t padding_idx, bool scale_grad_by_freq, bool sparse, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY +Tensor& empty_out(KernelRuntimeContext& context, IntArrayRef size, std::optional memory_format, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EQ +Tensor& eq_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& eq_tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ERF +Tensor& erf_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXP +Tensor& exp_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPAND_COPY +Tensor& expand_copy_out(KernelRuntimeContext& context, const Tensor& self, ArrayRef expand_sizes, bool implicit, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPM1 +Tensor& expm1_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FILL +Tensor& fill_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& fill_tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLIP +Tensor& flip_out(KernelRuntimeContext& context, const Tensor& in, IntArrayRef dims, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR +Tensor& floor_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR_DIVIDE +Tensor& floor_divide_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FMOD +Tensor& fmod_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +Tensor& fmod_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL +Tensor& full_out(KernelRuntimeContext& context, const IntArrayRef sizes, const Scalar& fill_value, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL_LIKE +Tensor& full_like_out(KernelRuntimeContext& context, const Tensor& in, const Scalar& fill_value, optional memory_format, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GATHER +Tensor& gather_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, const Tensor& index, bool sparse_grad, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GE +Tensor& ge_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& ge_tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GELU +Tensor& gelu_out(KernelRuntimeContext& context, const Tensor& in, string_view approximate, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GLU +Tensor& glu_out(KernelRuntimeContext& context, const Tensor& self, int64_t dim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GRID_SAMPLER_2D +Tensor& grid_sampler_2d_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& grid, int64_t interpolation_mode, int64_t padding_mode, bool align_corners, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GT +Tensor& gt_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& gt_tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_HARDTANH +Tensor& hardtanh_out(KernelRuntimeContext& context, const Tensor& in, const Scalar& min, const Scalar& max, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX +Tensor& index_Tensor_out(KernelRuntimeContext& context, const Tensor& in, TensorOptList indices, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_PUT +Tensor& index_put_out(KernelRuntimeContext& context, const Tensor& in, TensorOptList indices, const Tensor& values, const bool accumulate, Tensor& out); +Tensor& index_put_(KernelRuntimeContext& context, Tensor& in, TensorOptList indices, const Tensor& values, const bool accumulate); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_SELECT +Tensor& index_select_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, const Tensor& index, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISINF +Tensor& isinf_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISNAN +Tensor& isnan_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LE +Tensor& le_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& le_tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LEAKY_RELU +Tensor& leaky_relu_out(KernelRuntimeContext& context, const Tensor& in, const Scalar& negative_slope, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LIFT_FRESH_COPY +Tensor& lift_fresh_copy_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG +Tensor& log_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG10 +Tensor& log10_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG1P +Tensor& log1p_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG2 +Tensor& log2_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG_SOFTMAX +Tensor& log_softmax_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, bool half_to_float, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_AND +Tensor& logical_and_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_NOT +Tensor& logical_not_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_OR +Tensor& logical_or_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_XOR +Tensor& logical_xor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGIT +Tensor& logit_out(KernelRuntimeContext& context, const Tensor& in, std::optional eps, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LT +Tensor& lt_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& lt_tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_FILL +Tensor& masked_fill_scalar_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& mask, const Scalar& value, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SCATTER +Tensor& masked_scatter_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& mask, const Tensor& src, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SELECT +Tensor& masked_select_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& mask, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX +std::tuple max_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, bool keepdim, Tensor& max, Tensor& max_indices); +Tensor& max_unary_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES +std::tuple max_pool2d_with_indices_out(KernelRuntimeContext& context, const Tensor& in, IntArrayRef kernel_size, IntArrayRef stride, IntArrayRef padding, IntArrayRef dilation, bool ceil_mode, Tensor& out, Tensor& indices); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES_BACKWARD +Tensor& max_pool2d_with_indices_backward_out(KernelRuntimeContext& context, const Tensor& grad_output, const Tensor& input, IntArrayRef kernel_size, IntArrayRef stride, IntArrayRef padding, IntArrayRef dilation, bool ceil_mode, const Tensor& indices, Tensor& grad_input); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAXIMUM +Tensor& maximum_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MEAN +Tensor& mean_dim_out(KernelRuntimeContext& context, const Tensor& in, optional> dim_list, bool keepdim, optional dtype, Tensor& out); +Tensor& mean_dtype_out(KernelRuntimeContext& context, const Tensor& in, optional dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MIN +std::tuple min_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, bool keepdim, Tensor& min, Tensor& min_indices); +Tensor& min_unary_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MINIMUM +Tensor& minimum_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MM +Tensor& mm_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& mat2, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MUL +Tensor& mul_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +Tensor& mul_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NARROW_COPY +Tensor& narrow_copy_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, int64_t start, int64_t length, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_BATCH_NORM +std::tuple _native_batch_norm_legit_out(KernelRuntimeContext& context, const Tensor& in, const std::optional& weight, const std::optional& bias, Tensor& running_mean, Tensor& running_var, bool training, double momentum, double eps, Tensor& out, Tensor& mean_out, Tensor& invstd_out); +std::tuple _native_batch_norm_legit_no_stats_out(KernelRuntimeContext& context, const Tensor& in, const std::optional& weight, const std::optional& bias, bool training, double momentum, double eps, Tensor& out, Tensor& mean_out, Tensor& invstd_out); +std::tuple _native_batch_norm_legit_no_training_out(KernelRuntimeContext& context, const Tensor& in, const std::optional& weight, const std::optional& bias, const Tensor& running_mean, const Tensor& running_var, double momentum, double eps, Tensor& out, Tensor& mean_out, Tensor& invstd_out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_DROPOUT +std::tuple native_dropout_out(KernelRuntimeContext& context, const Tensor& input, double prob, torch::executor::optional train, Tensor& out, Tensor& mask); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_GROUP_NORM +std::tuple native_group_norm_out(KernelRuntimeContext& context, const Tensor& input, const std::optional& weight, const std::optional& bias, int64_t N, int64_t C, int64_t HxW, int64_t group, double eps, Tensor& out, Tensor& mean_out, Tensor& rstd_out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_LAYER_NORM +std::tuple native_layer_norm_out(KernelRuntimeContext& context, const Tensor& input, IntArrayRef normalized_shape, const std::optional& weight, const std::optional& bias, double eps, Tensor& out, Tensor& mean_out, Tensor& rstd_out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NE +Tensor& ne_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& ne_tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NEG +Tensor& neg_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NONZERO +Tensor& nonzero_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ONES +Tensor& ones_out(KernelRuntimeContext& context, IntArrayRef size, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PDIST_FORWARD +Tensor& _pdist_forward_out(KernelRuntimeContext& context, const Tensor& in, double p, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PERMUTE_COPY +Tensor& permute_copy_out(KernelRuntimeContext& context, const Tensor& in, IntArrayRef dims, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_SHUFFLE +Tensor& pixel_shuffle_out(KernelRuntimeContext& context, const Tensor& in, int64_t upscale_factor, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_UNSHUFFLE +Tensor& pixel_unshuffle_out(KernelRuntimeContext& context, const Tensor& in, int64_t downscale_factor, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_POW +Tensor& pow_Scalar_out(KernelRuntimeContext& context, const Scalar& a, const Tensor& b, Tensor& out); +Tensor& pow_Tensor_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +Tensor& pow_Tensor_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PROD +Tensor& prod_int_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, bool keepdim, optional dtype, Tensor& out); +Tensor& prod_out(KernelRuntimeContext& context, const Tensor& in, optional dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RAND +Tensor& rand_out(KernelRuntimeContext& context, const IntArrayRef sizes, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RANDN +Tensor& randn_out(KernelRuntimeContext& context, const IntArrayRef sizes, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RECIPROCAL +Tensor& reciprocal_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD1D +Tensor& reflection_pad1d_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef padding, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD2D +Tensor& reflection_pad2d_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef padding, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD3D +Tensor& reflection_pad3d_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef padding, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RELU +Tensor& relu_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REMAINDER +Tensor& remainder_Tensor_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, Tensor& out); +Tensor& remainder_Scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT +Tensor& repeat_out(KernelRuntimeContext& context, const Tensor& self, executorch::aten::ArrayRef repeats, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT_INTERLEAVE +Tensor& repeat_interleave_Tensor_out(KernelRuntimeContext& context, const Tensor& repeats, std::optional output_size, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD1D +Tensor& replication_pad1d_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef padding, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD2D +Tensor& replication_pad2d_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef padding, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD3D +Tensor& replication_pad3d_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef padding, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROLL +Tensor& roll_out(KernelRuntimeContext& context, const Tensor& in, IntArrayRef shifts, IntArrayRef dims, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROUND +Tensor& round_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSQRT +Tensor& rsqrt_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSUB +Tensor& rsub_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, const Scalar& alpha, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCALAR_TENSOR +Tensor& scalar_tensor_out(KernelRuntimeContext& context, const Scalar& s, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER +Tensor& scatter_src_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, const Tensor& index, const Tensor& src, Tensor& out); +Tensor& scatter_value_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, const Tensor& index, const Scalar& value, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER_ADD +Tensor& scatter_add_out(KernelRuntimeContext& context, const Tensor& self, int64_t dim, const Tensor& index, const Tensor& src, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_COPY +Tensor& select_copy_int_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, int64_t index, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_SCATTER +Tensor& select_scatter_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& src, int64_t dim, int64_t index, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGMOID +Tensor& sigmoid_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGN +Tensor& sign_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIN +Tensor& sin_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SINH +Tensor& sinh_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_COPY +Tensor& slice_copy_Tensor_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, std::optional start_val, std::optional end_val, int64_t step, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_SCATTER +Tensor& slice_scatter_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& src, int64_t dim, std::optional start_val, std::optional end_val, int64_t step, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SOFTMAX +Tensor& softmax_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, bool half_to_float, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_COPY +void split_copy_Tensor_out(KernelRuntimeContext& context, const Tensor& input, int64_t split_size, int64_t dim, TensorList out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_WITH_SIZES_COPY +void split_with_sizes_copy_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef split_sizes, int64_t dim, TensorList out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQRT +Tensor& sqrt_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQUEEZE_COPY +Tensor& squeeze_copy_dim_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim, Tensor& out); +Tensor& squeeze_copy_dims_out(KernelRuntimeContext& context, const Tensor& in, executorch::aten::ArrayRef dims, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_STACK +Tensor& stack_out(KernelRuntimeContext& context, executorch::aten::ArrayRef tensors, int64_t dim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUB +Tensor& sub_out(KernelRuntimeContext& context, const Tensor& a, const Tensor& b, const Scalar& alpha, Tensor& out); +Tensor& sub_scalar_out(KernelRuntimeContext& context, const Tensor& a, const Scalar& b, const Scalar& alpha, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUM +Tensor& sum_dim_out(KernelRuntimeContext& context, const Tensor& in, optional> dim_list, bool keepdim, optional dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_T_COPY +Tensor& t_copy_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TAN +Tensor& tan_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TANH +Tensor& tanh_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_COPY +Tensor& to_copy_out(KernelRuntimeContext& context, const Tensor& self, bool non_blocking, std::optional memory_format, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TOPK +std::tuple topk_values(KernelRuntimeContext& context, const Tensor& in, int64_t k, int64_t dim, bool largest, bool sorted, Tensor& values, Tensor& indices); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRANSPOSE_COPY +Tensor& transpose_copy_int_out(KernelRuntimeContext& context, const Tensor& in, int64_t dim0, int64_t dim1, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRIL +Tensor& tril_out(KernelRuntimeContext& context, const Tensor& self, int64_t diagonal, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRUNC +Tensor& trunc_out(KernelRuntimeContext& context, const Tensor& in, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNBIND_COPY +void unbind_copy_int_out(KernelRuntimeContext& context, const Tensor& input, int64_t dim, TensorList out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNFOLD_COPY +Tensor& unfold_copy_out(KernelRuntimeContext& context, const Tensor& self, int64_t dim, int64_t size, int64_t step, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNSQUEEZE_COPY +Tensor& unsqueeze_copy_out(KernelRuntimeContext& context, const Tensor& self, int64_t dim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D +Tensor& upsample_bilinear2d_vec_out(KernelRuntimeContext& context, const Tensor& in, const executorch::aten::OptionalArrayRef output_size, bool align_corners, const executorch::aten::OptionalArrayRef scale_factors, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D_AA +Tensor& _upsample_bilinear2d_aa_out(KernelRuntimeContext& context, const Tensor& in, const executorch::aten::ArrayRef output_size, bool align_corners, const std::optional scale_h, const std::optional scale_w, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_NEAREST2D +Tensor& upsample_nearest2d_vec_out(KernelRuntimeContext& context, const Tensor& in, const executorch::aten::OptionalArrayRef output_size, const executorch::aten::OptionalArrayRef scale_factors, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VAR +Tensor& var_correction_out(KernelRuntimeContext& context, const Tensor& in, optional> dim_list, const optional& correction, bool keepdim, Tensor& out); +Tensor& var_out(KernelRuntimeContext& context, const Tensor& in, optional> dim_list, bool unbiased, bool keepdim, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_AS_REAL_COPY +Tensor& view_as_real_copy_out(KernelRuntimeContext& context, const Tensor& self, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_COPY +Tensor& view_copy_out(KernelRuntimeContext& context, const Tensor& self, executorch::aten::ArrayRef size_int64_t, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_WHERE +Tensor& where_out(KernelRuntimeContext& context, const Tensor& cond, const Tensor& a, const Tensor& b, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ZEROS +Tensor& zeros_out(KernelRuntimeContext& context, IntArrayRef size, Tensor& out); +#endif + +// ===================================================================== +// QUANTIZED OPERATOR FORWARD DECLARATIONS +// ===================================================================== + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_ADD +Tensor& quantized_add_out(KernelRuntimeContext& context, const Tensor& a, double a_scale, int64_t a_zero_point, int64_t a_quant_min, int64_t a_quant_max, const Tensor& b, double b_scale, int64_t b_zero_point, int64_t b_quant_min, int64_t b_quant_max, double out_scale, int64_t out_zero_point, int64_t out_quant_min, int64_t out_quant_max, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_CHOOSE_QPARAMS +std::tuple choose_qparams_tensor_out(KernelRuntimeContext& context, const Tensor& input, int64_t quant_min, int64_t quant_max, double eps, ScalarType dtype, Tensor& scale_out, Tensor& zero_point_out); +std::tuple choose_qparams_per_token_asymmetric_out(KernelRuntimeContext& context, const Tensor& input, ScalarType dtype, Tensor& scale_out, Tensor& zero_point_out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_DEQUANTIZE +Tensor& dequantize_per_tensor_out(KernelRuntimeContext& context, const Tensor& input, double scale, int64_t zero_point, int64_t quant_min, int64_t quant_max, ScalarType dtype, std::optional out_dtype, Tensor& out); +Tensor& dequantize_per_tensor_tensor_args_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& scale, const Tensor& zero_point, int64_t quant_min, int64_t quant_max, ScalarType dtype, std::optional out_dtype, Tensor& out); +Tensor& dequantize_per_channel_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& scale, const std::optional& opt_zero_points, int64_t axis, int64_t quant_min, int64_t quant_max, ScalarType dtype, std::optional out_dtype, Tensor& out); +Tensor& dequantize_per_token_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& scale, const Tensor& zero_points, int64_t quant_min, int64_t quant_max, ScalarType dtype, ScalarType out_dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING +Tensor& quantized_embedding_byte_out(KernelRuntimeContext& context, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, const int64_t weight_quant_min, const int64_t weight_quant_max, const Tensor& indices, Tensor& out); +Tensor& quantized_embedding_byte_dtype_out(KernelRuntimeContext& context, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, const int64_t weight_quant_min, const int64_t weight_quant_max, const Tensor& indices, std::optional out_dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING2B +Tensor& quantized_embedding_2bit_out(KernelRuntimeContext& context, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const Tensor& indices, Tensor& out); +Tensor& quantized_embedding_2bit_dtype_out(KernelRuntimeContext& context, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const Tensor& indices, std::optional out_dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING4B +Tensor& quantized_embedding_4bit_out(KernelRuntimeContext& context, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const Tensor& indices, Tensor& out); +Tensor& quantized_embedding_4bit_dtype_out(KernelRuntimeContext& context, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const Tensor& indices, std::optional out_dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_LINEAR +Tensor& quantized_mixed_linear_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, const std::optional dtype, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_MM +Tensor& quantized_mixed_mm_out(KernelRuntimeContext& context, const Tensor& in, const Tensor& weight, const Tensor& weight_scales, const std::optional& opt_weight_zero_points, Tensor& out); +#endif + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_QUANTIZE +Tensor& quantize_per_channel_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& scale, const Tensor& zero_point, int64_t axis, int64_t quant_min, int64_t quant_max, ScalarType dtype, Tensor& out); +Tensor& quantize_per_tensor_out(KernelRuntimeContext& context, const Tensor& input, double scale, int64_t zero_point, int64_t quant_min, int64_t quant_max, ScalarType dtype, Tensor& out); +Tensor& quantize_per_tensor_tensor_args_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& scale, const Tensor& zero_point, int64_t quant_min, int64_t quant_max, ScalarType dtype, Tensor& out); +Tensor& quantize_per_token_out(KernelRuntimeContext& context, const Tensor& input, const Tensor& scale, const Tensor& zero_point, int64_t quant_min, int64_t quant_max, ScalarType dtype, Tensor& out); +#endif + +} // namespace native +} // namespace executor +} // namespace torch + +// Use fully qualified namespace for kernel registration +namespace { + +using namespace torch::executor; +using namespace executorch::runtime; + +// ===================================================================== +// KERNEL REGISTRATION ARRAY +// Each kernel registration is guarded by its operator define. +// ===================================================================== + +static Kernel kernels_to_register[] = { + +// ===================================================================== +// PORTABLE OPERATORS +// ===================================================================== + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE_DIM_ORDER + Kernel( + "dim_order_ops::_clone_dim_order.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& self = *stack[0]; + EValue& non_blocking = *stack[1]; + EValue& dim_order = *stack[2]; + EValue& out = *stack[3]; + const Tensor& self_base = self.to(); + bool non_blocking_base = non_blocking.to(); + // WARNING: auto-generated unpack for OptionalArrayRef + auto dim_order_base = dim_order.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__clone_dim_order.out"); + EXECUTORCH_SCOPE_PROF("native_call__clone_dim_order.out"); + torch::executor::native::_clone_dim_order_out(context, self_base, non_blocking_base, dim_order_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE_DIM_ORDER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY_DIM_ORDER + Kernel( + "dim_order_ops::_empty_dim_order.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& size = *stack[0]; + EValue& dim_order = *stack[1]; + EValue& out = *stack[2]; + auto size_list_out = size.toIntList(); + auto dim_order_opt_out = dim_order.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__empty_dim_order.out"); + EXECUTORCH_SCOPE_PROF("native_call__empty_dim_order.out"); + torch::executor::native::_empty_dim_order_out(context, size_list_out, dim_order_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY_DIM_ORDER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_DIM_ORDER_COPY + Kernel( + "dim_order_ops::_to_dim_order_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& self = *stack[0]; + EValue& non_blocking = *stack[1]; + EValue& dim_order = *stack[2]; + EValue& out = *stack[3]; + const Tensor& self_base = self.to(); + bool non_blocking_base = non_blocking.to(); + // WARNING: auto-generated unpack for OptionalArrayRef + auto dim_order_base = dim_order.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__to_dim_order_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call__to_dim_order_copy.out"); + torch::executor::native::_to_dim_order_copy_out(context, self_base, non_blocking_base, dim_order_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TO_DIM_ORDER_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ABS + Kernel( + "aten::abs.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_abs.out"); + EXECUTORCH_SCOPE_PROF("native_call_abs.out"); + torch::executor::native::abs_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ABS + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOS + Kernel( + "aten::acos.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_acos.out"); + EXECUTORCH_SCOPE_PROF("native_call_acos.out"); + torch::executor::native::acos_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ACOS + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOSH + Kernel( + "aten::acosh.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_acosh.out"); + EXECUTORCH_SCOPE_PROF("native_call_acosh.out"); + torch::executor::native::acosh_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ACOSH + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADD + Kernel( + "aten::add.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& alpha = *stack[2]; + EValue& out = *stack[3]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + const Scalar& alpha_base = alpha.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_add.out"); + EXECUTORCH_SCOPE_PROF("native_call_add.out"); + torch::executor::native::add_out(context, a_base, b_base, alpha_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), + Kernel( + "aten::add.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& alpha = *stack[2]; + EValue& out = *stack[3]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + const Scalar& alpha_base = alpha.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_add.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_add.Scalar_out"); + torch::executor::native::add_scalar_out(context, a_base, b_base, alpha_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ADD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADDMM + Kernel( + "aten::addmm.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected 7 args"); + EValue& in = *stack[0]; + EValue& mat1 = *stack[1]; + EValue& mat2 = *stack[2]; + EValue& beta = *stack[3]; + EValue& alpha = *stack[4]; + EValue& out = *stack[5]; + const Tensor& in_base = in.to(); + const Tensor& mat1_base = mat1.to(); + const Tensor& mat2_base = mat2.to(); + const Scalar& beta_base = beta.to(); + const Scalar& alpha_base = alpha.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_addmm.out"); + EXECUTORCH_SCOPE_PROF("native_call_addmm.out"); + torch::executor::native::addmm_out(context, in_base, mat1_base, mat2_base, beta_base, alpha_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ADDMM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALIAS_COPY + Kernel( + "aten::alias_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_alias_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_alias_copy.out"); + torch::executor::native::alias_copy_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ALIAS_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALLCLOSE + Kernel( + "aten::allclose.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& self = *stack[0]; + EValue& other = *stack[1]; + EValue& rtol = *stack[2]; + EValue& atol = *stack[3]; + EValue& equal_nan = *stack[4]; + EValue& dummy_param = *stack[5]; + EValue& out = *stack[6]; + const Tensor& self_base = self.to(); + const Tensor& other_base = other.to(); + double rtol_base = rtol.to(); + double atol_base = atol.to(); + bool equal_nan_base = equal_nan.to(); + bool dummy_param_base = dummy_param.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_allclose.out"); + EXECUTORCH_SCOPE_PROF("native_call_allclose.out"); + torch::executor::native::allclose_out(context, self_base, other_base, rtol_base, atol_base, equal_nan_base, dummy_param_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), + Kernel( + "aten::allclose.Tensor", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected 7 args"); + EValue& self = *stack[0]; + EValue& other = *stack[1]; + EValue& rtol = *stack[2]; + EValue& atol = *stack[3]; + EValue& equal_nan = *stack[4]; + EValue& dummy_param = *stack[5]; + const Tensor& self_base = self.to(); + const Tensor& other_base = other.to(); + double rtol_base = rtol.to(); + double atol_base = atol.to(); + bool equal_nan_base = equal_nan.to(); + bool dummy_param_base = dummy_param.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_allclose.Tensor"); + EXECUTORCH_SCOPE_PROF("native_call_allclose.Tensor"); + torch::executor::native::allclose_tensor(context, self_base, other_base, rtol_base, atol_base, equal_nan_base, dummy_param_base); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ALLCLOSE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMAX + Kernel( + "aten::amax.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim_list = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto dim_list_list_out = dim_list.toIntList(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_amax.out"); + EXECUTORCH_SCOPE_PROF("native_call_amax.out"); + torch::executor::native::amax_out(context, in_base, dim_list_list_out, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AMAX + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMIN + Kernel( + "aten::amin.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim_list = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto dim_list_list_out = dim_list.toIntList(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_amin.out"); + EXECUTORCH_SCOPE_PROF("native_call_amin.out"); + torch::executor::native::amin_out(context, in_base, dim_list_list_out, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AMIN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ANY + Kernel( + "aten::any.all_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_any.all_out"); + EXECUTORCH_SCOPE_PROF("native_call_any.all_out"); + torch::executor::native::any_all_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), + Kernel( + "aten::any.dims_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim_list = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto dim_list_opt_out = dim_list.toOptional(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_any.dims_out"); + EXECUTORCH_SCOPE_PROF("native_call_any.dims_out"); + torch::executor::native::any_dims_out(context, in_base, dim_list_opt_out, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), + Kernel( + "aten::any.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_any.out"); + EXECUTORCH_SCOPE_PROF("native_call_any.out"); + torch::executor::native::any_out(context, in_base, dim_base, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ANY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARANGE + Kernel( + "aten::arange.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& end = *stack[0]; + EValue& out = *stack[1]; + const Scalar& end_base = end.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_arange.out"); + EXECUTORCH_SCOPE_PROF("native_call_arange.out"); + torch::executor::native::arange_out(context, end_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), + Kernel( + "aten::arange.start_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& start = *stack[0]; + EValue& end = *stack[1]; + EValue& step = *stack[2]; + EValue& out = *stack[3]; + const Scalar& start_base = start.to(); + const Scalar& end_base = end.to(); + const Scalar& step_base = step.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_arange.start_out"); + EXECUTORCH_SCOPE_PROF("native_call_arange.start_out"); + torch::executor::native::arange_start_out(context, start_base, end_base, step_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ARANGE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMAX + Kernel( + "aten::argmax.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto dim_opt_out = dim.toOptional(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_argmax.out"); + EXECUTORCH_SCOPE_PROF("native_call_argmax.out"); + torch::executor::native::argmax_out(context, in_base, dim_opt_out, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMAX + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMIN + Kernel( + "aten::argmin.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto dim_opt_out = dim.toOptional(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_argmin.out"); + EXECUTORCH_SCOPE_PROF("native_call_argmin.out"); + torch::executor::native::argmin_out(context, in_base, dim_opt_out, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMIN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AS_STRIDED_COPY + Kernel( + "aten::as_strided_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& size = *stack[1]; + EValue& stride = *stack[2]; + EValue& storage_offset = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + auto size_list_out = size.toIntList(); + auto stride_list_out = stride.toIntList(); + auto storage_offset_opt_out = storage_offset.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_as_strided_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_as_strided_copy.out"); + torch::executor::native::as_strided_copy_out(context, in_base, size_list_out, stride_list_out, storage_offset_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AS_STRIDED_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASIN + Kernel( + "aten::asin.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_asin.out"); + EXECUTORCH_SCOPE_PROF("native_call_asin.out"); + torch::executor::native::asin_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ASIN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASINH + Kernel( + "aten::asinh.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_asinh.out"); + EXECUTORCH_SCOPE_PROF("native_call_asinh.out"); + torch::executor::native::asinh_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ASINH + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN + Kernel( + "aten::atan.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_atan.out"); + EXECUTORCH_SCOPE_PROF("native_call_atan.out"); + torch::executor::native::atan_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN2 + Kernel( + "aten::atan2.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_atan2.out"); + EXECUTORCH_SCOPE_PROF("native_call_atan2.out"); + torch::executor::native::atan2_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN2 + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATANH + Kernel( + "aten::atanh.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_atanh.out"); + EXECUTORCH_SCOPE_PROF("native_call_atanh.out"); + torch::executor::native::atanh_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ATANH + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AVG_POOL2D + Kernel( + "aten::avg_pool2d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& in = *stack[0]; + EValue& kernel_size = *stack[1]; + EValue& stride = *stack[2]; + EValue& padding = *stack[3]; + EValue& ceil_mode = *stack[4]; + EValue& count_include_pad = *stack[5]; + EValue& divisor_override = *stack[6]; + EValue& out = *stack[7]; + const Tensor& in_base = in.to(); + auto kernel_size_list_out = kernel_size.toIntList(); + auto stride_list_out = stride.toIntList(); + auto padding_list_out = padding.toIntList(); + bool ceil_mode_base = ceil_mode.to(); + bool count_include_pad_base = count_include_pad.to(); + auto divisor_override_opt_out = divisor_override.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_avg_pool2d.out"); + EXECUTORCH_SCOPE_PROF("native_call_avg_pool2d.out"); + torch::executor::native::avg_pool2d_out(context, in_base, kernel_size_list_out, stride_list_out, padding_list_out, ceil_mode_base, count_include_pad_base, divisor_override_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AVG_POOL2D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_AND + Kernel( + "aten::bitwise_and.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_and.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_and.Scalar_out"); + torch::executor::native::bitwise_and_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::bitwise_and.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_and.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_and.Tensor_out"); + torch::executor::native::bitwise_and_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_AND + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_LEFT_SHIFT + Kernel( + "aten::bitwise_left_shift.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_left_shift.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_left_shift.Tensor_out"); + torch::executor::native::bitwise_left_shift_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::bitwise_left_shift.Tensor_Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_left_shift.Tensor_Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_left_shift.Tensor_Scalar_out"); + torch::executor::native::bitwise_left_shift_Tensor_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_LEFT_SHIFT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_NOT + Kernel( + "aten::bitwise_not.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_not.out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_not.out"); + torch::executor::native::bitwise_not_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_NOT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_OR + Kernel( + "aten::bitwise_or.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_or.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_or.Scalar_out"); + torch::executor::native::bitwise_or_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::bitwise_or.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_or.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_or.Tensor_out"); + torch::executor::native::bitwise_or_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_OR + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_RIGHT_SHIFT + Kernel( + "aten::bitwise_right_shift.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_right_shift.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_right_shift.Tensor_out"); + torch::executor::native::bitwise_right_shift_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::bitwise_right_shift.Tensor_Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_right_shift.Tensor_Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_right_shift.Tensor_Scalar_out"); + torch::executor::native::bitwise_right_shift_Tensor_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_RIGHT_SHIFT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_XOR + Kernel( + "aten::bitwise_xor.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_xor.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_xor.Scalar_out"); + torch::executor::native::bitwise_xor_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::bitwise_xor.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_xor.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_bitwise_xor.Tensor_out"); + torch::executor::native::bitwise_xor_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_XOR + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BMM + Kernel( + "aten::bmm.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& mat2 = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + const Tensor& mat2_base = mat2.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bmm.out"); + EXECUTORCH_SCOPE_PROF("native_call_bmm.out"); + torch::executor::native::bmm_out(context, in_base, mat2_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BMM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CAT + Kernel( + "aten::cat.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& tensors = *stack[0]; + EValue& dim = *stack[1]; + EValue& out = *stack[2]; + auto tensors_list_out = tensors.toTensorList(); + int64_t dim_base = dim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cat.out"); + EXECUTORCH_SCOPE_PROF("native_call_cat.out"); + torch::executor::native::cat_out(context, tensors_list_out, dim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CAT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CDIST_FORWARD + Kernel( + "aten::_cdist_forward.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& x1 = *stack[0]; + EValue& x2 = *stack[1]; + EValue& p = *stack[2]; + EValue& compute_mode = *stack[3]; + EValue& out = *stack[4]; + const Tensor& x1_base = x1.to(); + const Tensor& x2_base = x2.to(); + double p_base = p.to(); + auto compute_mode_opt_out = compute_mode.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__cdist_forward.out"); + EXECUTORCH_SCOPE_PROF("native_call__cdist_forward.out"); + torch::executor::native::_cdist_forward_out(context, x1_base, x2_base, p_base, compute_mode_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CDIST_FORWARD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CEIL + Kernel( + "aten::ceil.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ceil.out"); + EXECUTORCH_SCOPE_PROF("native_call_ceil.out"); + torch::executor::native::ceil_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CEIL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLAMP + Kernel( + "aten::clamp.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& min_opt = *stack[1]; + EValue& max_opt = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto min_opt_opt_out = min_opt.toOptional(); + auto max_opt_opt_out = max_opt.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_clamp.out"); + EXECUTORCH_SCOPE_PROF("native_call_clamp.out"); + torch::executor::native::clamp_out(context, in_base, min_opt_opt_out, max_opt_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), + Kernel( + "aten::clamp.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& min_opt = *stack[1]; + EValue& max_opt = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto min_opt_opt_out = min_opt.toOptional(); + auto max_opt_opt_out = max_opt.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_clamp.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_clamp.Tensor_out"); + torch::executor::native::clamp_tensor_out(context, in_base, min_opt_opt_out, max_opt_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CLAMP + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE + Kernel( + "aten::clone.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& self = *stack[0]; + EValue& memory_format = *stack[1]; + EValue& out = *stack[2]; + const Tensor& self_base = self.to(); + // WARNING: auto-generated unpack for std::optional + auto memory_format_base = memory_format.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_clone.out"); + EXECUTORCH_SCOPE_PROF("native_call_clone.out"); + torch::executor::native::clone_out(context, self_base, memory_format_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONSTANT_PAD_ND + Kernel( + "aten::constant_pad_nd.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& pad = *stack[1]; + EValue& value = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto pad_list_out = pad.toIntList(); + const Scalar& value_base = value.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_constant_pad_nd.out"); + EXECUTORCH_SCOPE_PROF("native_call_constant_pad_nd.out"); + torch::executor::native::constant_pad_nd_out(context, in_base, pad_list_out, value_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CONSTANT_PAD_ND + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION + Kernel( + "aten::convolution.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 11, InvalidProgram, /*void*/, "Expected 11 args"); + EValue& in = *stack[0]; + EValue& weight = *stack[1]; + EValue& bias = *stack[2]; + EValue& stride = *stack[3]; + EValue& padding = *stack[4]; + EValue& dilation = *stack[5]; + EValue& transposed = *stack[6]; + EValue& output_padding = *stack[7]; + EValue& groups = *stack[8]; + EValue& out = *stack[9]; + const Tensor& in_base = in.to(); + const Tensor& weight_base = weight.to(); + auto bias_opt_out = bias.toOptional(); + auto stride_list_out = stride.toIntList(); + auto padding_list_out = padding.toIntList(); + auto dilation_list_out = dilation.toIntList(); + bool transposed_base = transposed.to(); + auto output_padding_list_out = output_padding.toIntList(); + int64_t groups_base = groups.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_convolution.out"); + EXECUTORCH_SCOPE_PROF("native_call_convolution.out"); + torch::executor::native::convolution_out(context, in_base, weight_base, bias_opt_out, stride_list_out, padding_list_out, dilation_list_out, transposed_base, output_padding_list_out, groups_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION_BACKWARD + Kernel( + "aten::convolution_backward.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 15, InvalidProgram, /*void*/, "Expected 15 args"); + EValue& grad_output = *stack[0]; + EValue& input = *stack[1]; + EValue& weight = *stack[2]; + EValue& bias_sizes_opt = *stack[3]; + EValue& stride = *stack[4]; + EValue& padding = *stack[5]; + EValue& dilation = *stack[6]; + EValue& transposed = *stack[7]; + EValue& output_padding = *stack[8]; + EValue& groups = *stack[9]; + EValue& output_mask = *stack[10]; + EValue& grad_input = *stack[11]; + EValue& grad_weight = *stack[12]; + EValue& grad_bias = *stack[13]; + const Tensor& grad_output_base = grad_output.to(); + const Tensor& input_base = input.to(); + const Tensor& weight_base = weight.to(); + auto bias_sizes_opt_opt_out = bias_sizes_opt.toOptional(); + auto stride_list_out = stride.toIntList(); + auto padding_list_out = padding.toIntList(); + auto dilation_list_out = dilation.toIntList(); + bool transposed_base = transposed.to(); + auto output_padding_list_out = output_padding.toIntList(); + int64_t groups_base = groups.to(); + auto output_mask_list_out = output_mask.toBoolList(); + Tensor& grad_input_base = grad_input.to(); + Tensor& grad_weight_base = grad_weight.to(); + Tensor& grad_bias_base = grad_bias.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_convolution_backward.out"); + EXECUTORCH_SCOPE_PROF("native_call_convolution_backward.out"); + torch::executor::native::convolution_backward_out(context, grad_output_base, input_base, weight_base, bias_sizes_opt_opt_out, stride_list_out, padding_list_out, dilation_list_out, transposed_base, output_padding_list_out, groups_base, output_mask_list_out, grad_input_base, grad_weight_base, grad_bias_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[11]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[12]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[13]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION_BACKWARD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COPY + Kernel( + "aten::copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& src = *stack[1]; + EValue& non_blocking = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + const Tensor& src_base = src.to(); + bool non_blocking_base = non_blocking.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_copy.out"); + torch::executor::native::copy_out(context, in_base, src_base, non_blocking_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), + Kernel( + "aten::copy_", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& src = *stack[1]; + EValue& non_blocking = *stack[2]; + Tensor& in_base = in.to(); + const Tensor& src_base = src.to(); + bool non_blocking_base = non_blocking.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_copy_"); + EXECUTORCH_SCOPE_PROF("native_call_copy_"); + torch::executor::native::copy_(context, in_base, src_base, non_blocking_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[0]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COS + Kernel( + "aten::cos.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cos.out"); + EXECUTORCH_SCOPE_PROF("native_call_cos.out"); + torch::executor::native::cos_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_COS + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COSH + Kernel( + "aten::cosh.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cosh.out"); + EXECUTORCH_SCOPE_PROF("native_call_cosh.out"); + torch::executor::native::cosh_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_COSH + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CUMSUM + Kernel( + "aten::cumsum.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& self = *stack[0]; + EValue& dim = *stack[1]; + EValue& enforced_dtype = *stack[2]; + EValue& out = *stack[3]; + const Tensor& self_base = self.to(); + int64_t dim_base = dim.to(); + auto enforced_dtype_opt_out = enforced_dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cumsum.out"); + EXECUTORCH_SCOPE_PROF("native_call_cumsum.out"); + torch::executor::native::cumsum_out(context, self_base, dim_base, enforced_dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CUMSUM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DETACH_COPY + Kernel( + "aten::detach_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& self = *stack[0]; + EValue& out = *stack[1]; + const Tensor& self_base = self.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_detach_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_detach_copy.out"); + torch::executor::native::detach_copy_out(context, self_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_DETACH_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIAGONAL_COPY + Kernel( + "aten::diagonal_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& offset = *stack[1]; + EValue& dim1 = *stack[2]; + EValue& dim2 = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + int64_t offset_base = offset.to(); + int64_t dim1_base = dim1.to(); + int64_t dim2_base = dim2.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_diagonal_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_diagonal_copy.out"); + torch::executor::native::diagonal_copy_out(context, in_base, offset_base, dim1_base, dim2_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_DIAGONAL_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIV + Kernel( + "aten::div.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.out"); + EXECUTORCH_SCOPE_PROF("native_call_div.out"); + torch::executor::native::div_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::div.Scalar_mode_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& mode = *stack[2]; + EValue& out = *stack[3]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + auto mode_sv = mode.toStringView(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.Scalar_mode_out"); + EXECUTORCH_SCOPE_PROF("native_call_div.Scalar_mode_out"); + torch::executor::native::div_scalar_mode_out(context, a_base, b_base, mode_sv, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), + Kernel( + "aten::div.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_div.Scalar_out"); + torch::executor::native::div_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::div.out_mode", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& mode = *stack[2]; + EValue& out = *stack[3]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + auto mode_sv = mode.toStringView(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.out_mode"); + EXECUTORCH_SCOPE_PROF("native_call_div.out_mode"); + torch::executor::native::div_out_mode(context, a_base, b_base, mode_sv, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_DIV + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ELU + Kernel( + "aten::elu.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& alpha = *stack[1]; + EValue& scale = *stack[2]; + EValue& input_scale = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + const Scalar& alpha_base = alpha.to(); + const Scalar& scale_base = scale.to(); + const Scalar& input_scale_base = input_scale.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_elu.out"); + EXECUTORCH_SCOPE_PROF("native_call_elu.out"); + torch::executor::native::elu_out(context, in_base, alpha_base, scale_base, input_scale_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ELU + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMBEDDING + Kernel( + "aten::embedding.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected 7 args"); + EValue& weight = *stack[0]; + EValue& indices = *stack[1]; + EValue& padding_idx = *stack[2]; + EValue& scale_grad_by_freq = *stack[3]; + EValue& sparse = *stack[4]; + EValue& out = *stack[5]; + const Tensor& weight_base = weight.to(); + const Tensor& indices_base = indices.to(); + int64_t padding_idx_base = padding_idx.to(); + bool scale_grad_by_freq_base = scale_grad_by_freq.to(); + bool sparse_base = sparse.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding.out"); + EXECUTORCH_SCOPE_PROF("native_call_embedding.out"); + torch::executor::native::embedding_out(context, weight_base, indices_base, padding_idx_base, scale_grad_by_freq_base, sparse_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EMBEDDING + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY + Kernel( + "aten::empty.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& size = *stack[0]; + EValue& memory_format = *stack[1]; + EValue& out = *stack[2]; + auto size_list_out = size.toIntList(); + // WARNING: auto-generated unpack for std::optional + auto memory_format_base = memory_format.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_empty.out"); + EXECUTORCH_SCOPE_PROF("native_call_empty.out"); + torch::executor::native::empty_out(context, size_list_out, memory_format_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EQ + Kernel( + "aten::eq.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_eq.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_eq.Scalar_out"); + torch::executor::native::eq_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::eq.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_eq.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_eq.Tensor_out"); + torch::executor::native::eq_tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EQ + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ERF + Kernel( + "aten::erf.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_erf.out"); + EXECUTORCH_SCOPE_PROF("native_call_erf.out"); + torch::executor::native::erf_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ERF + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXP + Kernel( + "aten::exp.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_exp.out"); + EXECUTORCH_SCOPE_PROF("native_call_exp.out"); + torch::executor::native::exp_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EXP + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPAND_COPY + Kernel( + "aten::expand_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& self = *stack[0]; + EValue& expand_sizes = *stack[1]; + EValue& implicit = *stack[2]; + EValue& out = *stack[3]; + const Tensor& self_base = self.to(); + auto expand_sizes_list_out = expand_sizes.toIntList(); + bool implicit_base = implicit.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_expand_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_expand_copy.out"); + torch::executor::native::expand_copy_out(context, self_base, expand_sizes_list_out, implicit_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EXPAND_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPM1 + Kernel( + "aten::expm1.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_expm1.out"); + EXECUTORCH_SCOPE_PROF("native_call_expm1.out"); + torch::executor::native::expm1_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EXPM1 + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FILL + Kernel( + "aten::fill.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fill.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_fill.Scalar_out"); + torch::executor::native::fill_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::fill.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fill.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_fill.Tensor_out"); + torch::executor::native::fill_tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FILL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLIP + Kernel( + "aten::flip.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& dims = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto dims_list_out = dims.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_flip.out"); + EXECUTORCH_SCOPE_PROF("native_call_flip.out"); + torch::executor::native::flip_out(context, in_base, dims_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FLIP + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR + Kernel( + "aten::floor.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_floor.out"); + EXECUTORCH_SCOPE_PROF("native_call_floor.out"); + torch::executor::native::floor_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR_DIVIDE + Kernel( + "aten::floor_divide.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_floor_divide.out"); + EXECUTORCH_SCOPE_PROF("native_call_floor_divide.out"); + torch::executor::native::floor_divide_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR_DIVIDE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FMOD + Kernel( + "aten::fmod.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fmod.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_fmod.Tensor_out"); + torch::executor::native::fmod_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::fmod.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fmod.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_fmod.Scalar_out"); + torch::executor::native::fmod_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FMOD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL + Kernel( + "aten::full.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& sizes = *stack[0]; + EValue& fill_value = *stack[1]; + EValue& out = *stack[2]; + auto sizes_list_out = sizes.toIntList(); + const Scalar& fill_value_base = fill_value.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_full.out"); + EXECUTORCH_SCOPE_PROF("native_call_full.out"); + torch::executor::native::full_out(context, sizes_list_out, fill_value_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FULL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL_LIKE + Kernel( + "aten::full_like.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& fill_value = *stack[1]; + EValue& memory_format = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + const Scalar& fill_value_base = fill_value.to(); + auto memory_format_opt_out = memory_format.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_full_like.out"); + EXECUTORCH_SCOPE_PROF("native_call_full_like.out"); + torch::executor::native::full_like_out(context, in_base, fill_value_base, memory_format_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FULL_LIKE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GATHER + Kernel( + "aten::gather.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& index = *stack[2]; + EValue& sparse_grad = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + const Tensor& index_base = index.to(); + bool sparse_grad_base = sparse_grad.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gather.out"); + EXECUTORCH_SCOPE_PROF("native_call_gather.out"); + torch::executor::native::gather_out(context, in_base, dim_base, index_base, sparse_grad_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GATHER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GE + Kernel( + "aten::ge.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ge.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_ge.Scalar_out"); + torch::executor::native::ge_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::ge.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ge.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_ge.Tensor_out"); + torch::executor::native::ge_tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GELU + Kernel( + "aten::gelu.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& approximate = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto approximate_sv = approximate.toStringView(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gelu.out"); + EXECUTORCH_SCOPE_PROF("native_call_gelu.out"); + torch::executor::native::gelu_out(context, in_base, approximate_sv, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GELU + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GLU + Kernel( + "aten::glu.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& self = *stack[0]; + EValue& dim = *stack[1]; + EValue& out = *stack[2]; + const Tensor& self_base = self.to(); + int64_t dim_base = dim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_glu.out"); + EXECUTORCH_SCOPE_PROF("native_call_glu.out"); + torch::executor::native::glu_out(context, self_base, dim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GLU + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GRID_SAMPLER_2D + Kernel( + "aten::grid_sampler_2d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected 7 args"); + EValue& input = *stack[0]; + EValue& grid = *stack[1]; + EValue& interpolation_mode = *stack[2]; + EValue& padding_mode = *stack[3]; + EValue& align_corners = *stack[4]; + EValue& out = *stack[5]; + const Tensor& input_base = input.to(); + const Tensor& grid_base = grid.to(); + int64_t interpolation_mode_base = interpolation_mode.to(); + int64_t padding_mode_base = padding_mode.to(); + bool align_corners_base = align_corners.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_grid_sampler_2d.out"); + EXECUTORCH_SCOPE_PROF("native_call_grid_sampler_2d.out"); + torch::executor::native::grid_sampler_2d_out(context, input_base, grid_base, interpolation_mode_base, padding_mode_base, align_corners_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GRID_SAMPLER_2D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GT + Kernel( + "aten::gt.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gt.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_gt.Scalar_out"); + torch::executor::native::gt_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::gt.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gt.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_gt.Tensor_out"); + torch::executor::native::gt_tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_HARDTANH + Kernel( + "aten::hardtanh.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& min = *stack[1]; + EValue& max = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + const Scalar& min_base = min.to(); + const Scalar& max_base = max.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_hardtanh.out"); + EXECUTORCH_SCOPE_PROF("native_call_hardtanh.out"); + torch::executor::native::hardtanh_out(context, in_base, min_base, max_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_HARDTANH + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX + Kernel( + "aten::index.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& indices = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto indices_list_out = indices.toTensorOptList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_index.Tensor_out"); + torch::executor::native::index_Tensor_out(context, in_base, indices_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_PUT + Kernel( + "aten::index_put.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& indices = *stack[1]; + EValue& values = *stack[2]; + EValue& accumulate = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + auto indices_list_out = indices.toTensorOptList(); + const Tensor& values_base = values.to(); + bool accumulate_base = accumulate.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index_put.out"); + EXECUTORCH_SCOPE_PROF("native_call_index_put.out"); + torch::executor::native::index_put_out(context, in_base, indices_list_out, values_base, accumulate_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), + Kernel( + "aten::index_put_", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& indices = *stack[1]; + EValue& values = *stack[2]; + EValue& accumulate = *stack[3]; + Tensor& in_base = in.to(); + auto indices_list_out = indices.toTensorOptList(); + const Tensor& values_base = values.to(); + bool accumulate_base = accumulate.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index_put_"); + EXECUTORCH_SCOPE_PROF("native_call_index_put_"); + torch::executor::native::index_put_(context, in_base, indices_list_out, values_base, accumulate_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[0]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_PUT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_SELECT + Kernel( + "aten::index_select.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& index = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + const Tensor& index_base = index.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index_select.out"); + EXECUTORCH_SCOPE_PROF("native_call_index_select.out"); + torch::executor::native::index_select_out(context, in_base, dim_base, index_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_SELECT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISINF + Kernel( + "aten::isinf.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_isinf.out"); + EXECUTORCH_SCOPE_PROF("native_call_isinf.out"); + torch::executor::native::isinf_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ISINF + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISNAN + Kernel( + "aten::isnan.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_isnan.out"); + EXECUTORCH_SCOPE_PROF("native_call_isnan.out"); + torch::executor::native::isnan_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ISNAN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LE + Kernel( + "aten::le.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_le.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_le.Scalar_out"); + torch::executor::native::le_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::le.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_le.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_le.Tensor_out"); + torch::executor::native::le_tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LEAKY_RELU + Kernel( + "aten::leaky_relu.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& negative_slope = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + const Scalar& negative_slope_base = negative_slope.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_leaky_relu.out"); + EXECUTORCH_SCOPE_PROF("native_call_leaky_relu.out"); + torch::executor::native::leaky_relu_out(context, in_base, negative_slope_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LEAKY_RELU + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LIFT_FRESH_COPY + Kernel( + "aten::lift_fresh_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_lift_fresh_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_lift_fresh_copy.out"); + torch::executor::native::lift_fresh_copy_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LIFT_FRESH_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG + Kernel( + "aten::log.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log.out"); + EXECUTORCH_SCOPE_PROF("native_call_log.out"); + torch::executor::native::log_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG10 + Kernel( + "aten::log10.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log10.out"); + EXECUTORCH_SCOPE_PROF("native_call_log10.out"); + torch::executor::native::log10_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG10 + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG1P + Kernel( + "aten::log1p.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log1p.out"); + EXECUTORCH_SCOPE_PROF("native_call_log1p.out"); + torch::executor::native::log1p_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG1P + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG2 + Kernel( + "aten::log2.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log2.out"); + EXECUTORCH_SCOPE_PROF("native_call_log2.out"); + torch::executor::native::log2_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG2 + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG_SOFTMAX + Kernel( + "aten::_log_softmax.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& half_to_float = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + bool half_to_float_base = half_to_float.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__log_softmax.out"); + EXECUTORCH_SCOPE_PROF("native_call__log_softmax.out"); + torch::executor::native::log_softmax_out(context, in_base, dim_base, half_to_float_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG_SOFTMAX + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_AND + Kernel( + "aten::logical_and.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_and.out"); + EXECUTORCH_SCOPE_PROF("native_call_logical_and.out"); + torch::executor::native::logical_and_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_AND + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_NOT + Kernel( + "aten::logical_not.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_not.out"); + EXECUTORCH_SCOPE_PROF("native_call_logical_not.out"); + torch::executor::native::logical_not_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_NOT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_OR + Kernel( + "aten::logical_or.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_or.out"); + EXECUTORCH_SCOPE_PROF("native_call_logical_or.out"); + torch::executor::native::logical_or_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_OR + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_XOR + Kernel( + "aten::logical_xor.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_xor.out"); + EXECUTORCH_SCOPE_PROF("native_call_logical_xor.out"); + torch::executor::native::logical_xor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_XOR + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGIT + Kernel( + "aten::logit.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& eps = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto eps_opt_out = eps.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logit.out"); + EXECUTORCH_SCOPE_PROF("native_call_logit.out"); + torch::executor::native::logit_out(context, in_base, eps_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGIT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LT + Kernel( + "aten::lt.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_lt.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_lt.Scalar_out"); + torch::executor::native::lt_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::lt.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_lt.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_lt.Tensor_out"); + torch::executor::native::lt_tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_FILL + Kernel( + "aten::masked_fill.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& mask = *stack[1]; + EValue& value = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + const Tensor& mask_base = mask.to(); + const Scalar& value_base = value.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_masked_fill.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_masked_fill.Scalar_out"); + torch::executor::native::masked_fill_scalar_out(context, in_base, mask_base, value_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_FILL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SCATTER + Kernel( + "aten::masked_scatter.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& mask = *stack[1]; + EValue& src = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + const Tensor& mask_base = mask.to(); + const Tensor& src_base = src.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_masked_scatter.out"); + EXECUTORCH_SCOPE_PROF("native_call_masked_scatter.out"); + torch::executor::native::masked_scatter_out(context, in_base, mask_base, src_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SCATTER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SELECT + Kernel( + "aten::masked_select.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& mask = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + const Tensor& mask_base = mask.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_masked_select.out"); + EXECUTORCH_SCOPE_PROF("native_call_masked_select.out"); + torch::executor::native::masked_select_out(context, in_base, mask_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SELECT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX + Kernel( + "aten::max.dim_max", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& max = *stack[3]; + EValue& max_indices = *stack[4]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + bool keepdim_base = keepdim.to(); + Tensor& max_base = max.to(); + Tensor& max_indices_base = max_indices.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max.dim_max"); + EXECUTORCH_SCOPE_PROF("native_call_max.dim_max"); + torch::executor::native::max_out(context, in_base, dim_base, keepdim_base, max_base, max_indices_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), + Kernel( + "aten::max.unary_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max.unary_out"); + EXECUTORCH_SCOPE_PROF("native_call_max.unary_out"); + torch::executor::native::max_unary_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAX + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES + Kernel( + "aten::max_pool2d_with_indices.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& in = *stack[0]; + EValue& kernel_size = *stack[1]; + EValue& stride = *stack[2]; + EValue& padding = *stack[3]; + EValue& dilation = *stack[4]; + EValue& ceil_mode = *stack[5]; + EValue& out = *stack[6]; + EValue& indices = *stack[7]; + const Tensor& in_base = in.to(); + auto kernel_size_list_out = kernel_size.toIntList(); + auto stride_list_out = stride.toIntList(); + auto padding_list_out = padding.toIntList(); + auto dilation_list_out = dilation.toIntList(); + bool ceil_mode_base = ceil_mode.to(); + Tensor& out_base = out.to(); + Tensor& indices_base = indices.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max_pool2d_with_indices.out"); + EXECUTORCH_SCOPE_PROF("native_call_max_pool2d_with_indices.out"); + torch::executor::native::max_pool2d_with_indices_out(context, in_base, kernel_size_list_out, stride_list_out, padding_list_out, dilation_list_out, ceil_mode_base, out_base, indices_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES_BACKWARD + Kernel( + "aten::max_pool2d_with_indices_backward.grad_input", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 10, InvalidProgram, /*void*/, "Expected 10 args"); + EValue& grad_output = *stack[0]; + EValue& input = *stack[1]; + EValue& kernel_size = *stack[2]; + EValue& stride = *stack[3]; + EValue& padding = *stack[4]; + EValue& dilation = *stack[5]; + EValue& ceil_mode = *stack[6]; + EValue& indices = *stack[7]; + EValue& grad_input = *stack[8]; + const Tensor& grad_output_base = grad_output.to(); + const Tensor& input_base = input.to(); + auto kernel_size_list_out = kernel_size.toIntList(); + auto stride_list_out = stride.toIntList(); + auto padding_list_out = padding.toIntList(); + auto dilation_list_out = dilation.toIntList(); + bool ceil_mode_base = ceil_mode.to(); + const Tensor& indices_base = indices.to(); + Tensor& grad_input_base = grad_input.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max_pool2d_with_indices_backward.grad_input"); + EXECUTORCH_SCOPE_PROF("native_call_max_pool2d_with_indices_backward.grad_input"); + torch::executor::native::max_pool2d_with_indices_backward_out(context, grad_output_base, input_base, kernel_size_list_out, stride_list_out, padding_list_out, dilation_list_out, ceil_mode_base, indices_base, grad_input_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES_BACKWARD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAXIMUM + Kernel( + "aten::maximum.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_maximum.out"); + EXECUTORCH_SCOPE_PROF("native_call_maximum.out"); + torch::executor::native::maximum_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAXIMUM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MEAN + Kernel( + "aten::mean.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim_list = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& dtype = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + auto dim_list_opt_out = dim_list.toOptional(); + bool keepdim_base = keepdim.to(); + auto dtype_opt_out = dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mean.out"); + EXECUTORCH_SCOPE_PROF("native_call_mean.out"); + torch::executor::native::mean_dim_out(context, in_base, dim_list_opt_out, keepdim_base, dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), + Kernel( + "aten::mean.dtype_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& dtype = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto dtype_opt_out = dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mean.dtype_out"); + EXECUTORCH_SCOPE_PROF("native_call_mean.dtype_out"); + torch::executor::native::mean_dtype_out(context, in_base, dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MEAN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MIN + Kernel( + "aten::min.dim_min", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& min = *stack[3]; + EValue& min_indices = *stack[4]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + bool keepdim_base = keepdim.to(); + Tensor& min_base = min.to(); + Tensor& min_indices_base = min_indices.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_min.dim_min"); + EXECUTORCH_SCOPE_PROF("native_call_min.dim_min"); + torch::executor::native::min_out(context, in_base, dim_base, keepdim_base, min_base, min_indices_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), + Kernel( + "aten::min.unary_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_min.unary_out"); + EXECUTORCH_SCOPE_PROF("native_call_min.unary_out"); + torch::executor::native::min_unary_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MIN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MINIMUM + Kernel( + "aten::minimum.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_minimum.out"); + EXECUTORCH_SCOPE_PROF("native_call_minimum.out"); + torch::executor::native::minimum_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MINIMUM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MM + Kernel( + "aten::mm.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& mat2 = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + const Tensor& mat2_base = mat2.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mm.out"); + EXECUTORCH_SCOPE_PROF("native_call_mm.out"); + torch::executor::native::mm_out(context, in_base, mat2_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MUL + Kernel( + "aten::mul.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mul.out"); + EXECUTORCH_SCOPE_PROF("native_call_mul.out"); + torch::executor::native::mul_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::mul.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mul.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_mul.Scalar_out"); + torch::executor::native::mul_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MUL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NARROW_COPY + Kernel( + "aten::narrow_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& start = *stack[2]; + EValue& length = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + int64_t start_base = start.to(); + int64_t length_base = length.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_narrow_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_narrow_copy.out"); + torch::executor::native::narrow_copy_out(context, in_base, dim_base, start_base, length_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NARROW_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_BATCH_NORM + Kernel( + "aten::_native_batch_norm_legit.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 12, InvalidProgram, /*void*/, "Expected 12 args"); + EValue& in = *stack[0]; + EValue& weight = *stack[1]; + EValue& bias = *stack[2]; + EValue& running_mean = *stack[3]; + EValue& running_var = *stack[4]; + EValue& training = *stack[5]; + EValue& momentum = *stack[6]; + EValue& eps = *stack[7]; + EValue& out = *stack[8]; + EValue& mean_out = *stack[9]; + EValue& invstd_out = *stack[10]; + const Tensor& in_base = in.to(); + auto weight_opt_out = weight.toOptional(); + auto bias_opt_out = bias.toOptional(); + Tensor& running_mean_base = running_mean.to(); + Tensor& running_var_base = running_var.to(); + bool training_base = training.to(); + double momentum_base = momentum.to(); + double eps_base = eps.to(); + Tensor& out_base = out.to(); + Tensor& mean_out_base = mean_out.to(); + Tensor& invstd_out_base = invstd_out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__native_batch_norm_legit.out"); + EXECUTORCH_SCOPE_PROF("native_call__native_batch_norm_legit.out"); + torch::executor::native::_native_batch_norm_legit_out(context, in_base, weight_opt_out, bias_opt_out, running_mean_base, running_var_base, training_base, momentum_base, eps_base, out_base, mean_out_base, invstd_out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[10]); + } + ), + Kernel( + "aten::_native_batch_norm_legit.no_stats_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 10, InvalidProgram, /*void*/, "Expected 10 args"); + EValue& in = *stack[0]; + EValue& weight = *stack[1]; + EValue& bias = *stack[2]; + EValue& training = *stack[3]; + EValue& momentum = *stack[4]; + EValue& eps = *stack[5]; + EValue& out = *stack[6]; + EValue& mean_out = *stack[7]; + EValue& invstd_out = *stack[8]; + const Tensor& in_base = in.to(); + auto weight_opt_out = weight.toOptional(); + auto bias_opt_out = bias.toOptional(); + bool training_base = training.to(); + double momentum_base = momentum.to(); + double eps_base = eps.to(); + Tensor& out_base = out.to(); + Tensor& mean_out_base = mean_out.to(); + Tensor& invstd_out_base = invstd_out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__native_batch_norm_legit.no_stats_out"); + EXECUTORCH_SCOPE_PROF("native_call__native_batch_norm_legit.no_stats_out"); + torch::executor::native::_native_batch_norm_legit_no_stats_out(context, in_base, weight_opt_out, bias_opt_out, training_base, momentum_base, eps_base, out_base, mean_out_base, invstd_out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); + } + ), + Kernel( + "aten::_native_batch_norm_legit_no_training.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 11, InvalidProgram, /*void*/, "Expected 11 args"); + EValue& in = *stack[0]; + EValue& weight = *stack[1]; + EValue& bias = *stack[2]; + EValue& running_mean = *stack[3]; + EValue& running_var = *stack[4]; + EValue& momentum = *stack[5]; + EValue& eps = *stack[6]; + EValue& out = *stack[7]; + EValue& mean_out = *stack[8]; + EValue& invstd_out = *stack[9]; + const Tensor& in_base = in.to(); + auto weight_opt_out = weight.toOptional(); + auto bias_opt_out = bias.toOptional(); + const Tensor& running_mean_base = running_mean.to(); + const Tensor& running_var_base = running_var.to(); + double momentum_base = momentum.to(); + double eps_base = eps.to(); + Tensor& out_base = out.to(); + Tensor& mean_out_base = mean_out.to(); + Tensor& invstd_out_base = invstd_out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__native_batch_norm_legit_no_training.out"); + EXECUTORCH_SCOPE_PROF("native_call__native_batch_norm_legit_no_training.out"); + torch::executor::native::_native_batch_norm_legit_no_training_out(context, in_base, weight_opt_out, bias_opt_out, running_mean_base, running_var_base, momentum_base, eps_base, out_base, mean_out_base, invstd_out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_BATCH_NORM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_DROPOUT + Kernel( + "aten::native_dropout.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& input = *stack[0]; + EValue& prob = *stack[1]; + EValue& train = *stack[2]; + EValue& out = *stack[3]; + EValue& mask = *stack[4]; + const Tensor& input_base = input.to(); + double prob_base = prob.to(); + // WARNING: auto-generated unpack for torch::executor::optional + auto train_base = train.to(); + Tensor& out_base = out.to(); + Tensor& mask_base = mask.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_native_dropout.out"); + EXECUTORCH_SCOPE_PROF("native_call_native_dropout.out"); + torch::executor::native::native_dropout_out(context, input_base, prob_base, train_base, out_base, mask_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_DROPOUT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_GROUP_NORM + Kernel( + "aten::native_group_norm.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 12, InvalidProgram, /*void*/, "Expected 12 args"); + EValue& input = *stack[0]; + EValue& weight = *stack[1]; + EValue& bias = *stack[2]; + EValue& N = *stack[3]; + EValue& C = *stack[4]; + EValue& HxW = *stack[5]; + EValue& group = *stack[6]; + EValue& eps = *stack[7]; + EValue& out = *stack[8]; + EValue& mean_out = *stack[9]; + EValue& rstd_out = *stack[10]; + const Tensor& input_base = input.to(); + auto weight_opt_out = weight.toOptional(); + auto bias_opt_out = bias.toOptional(); + int64_t N_base = N.to(); + int64_t C_base = C.to(); + int64_t HxW_base = HxW.to(); + int64_t group_base = group.to(); + double eps_base = eps.to(); + Tensor& out_base = out.to(); + Tensor& mean_out_base = mean_out.to(); + Tensor& rstd_out_base = rstd_out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_native_group_norm.out"); + EXECUTORCH_SCOPE_PROF("native_call_native_group_norm.out"); + torch::executor::native::native_group_norm_out(context, input_base, weight_opt_out, bias_opt_out, N_base, C_base, HxW_base, group_base, eps_base, out_base, mean_out_base, rstd_out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[10]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_GROUP_NORM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_LAYER_NORM + Kernel( + "aten::native_layer_norm.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& input = *stack[0]; + EValue& normalized_shape = *stack[1]; + EValue& weight = *stack[2]; + EValue& bias = *stack[3]; + EValue& eps = *stack[4]; + EValue& out = *stack[5]; + EValue& mean_out = *stack[6]; + EValue& rstd_out = *stack[7]; + const Tensor& input_base = input.to(); + auto normalized_shape_list_out = normalized_shape.toIntList(); + auto weight_opt_out = weight.toOptional(); + auto bias_opt_out = bias.toOptional(); + double eps_base = eps.to(); + Tensor& out_base = out.to(); + Tensor& mean_out_base = mean_out.to(); + Tensor& rstd_out_base = rstd_out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_native_layer_norm.out"); + EXECUTORCH_SCOPE_PROF("native_call_native_layer_norm.out"); + torch::executor::native::native_layer_norm_out(context, input_base, normalized_shape_list_out, weight_opt_out, bias_opt_out, eps_base, out_base, mean_out_base, rstd_out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_LAYER_NORM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NE + Kernel( + "aten::ne.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ne.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_ne.Scalar_out"); + torch::executor::native::ne_scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::ne.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ne.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_ne.Tensor_out"); + torch::executor::native::ne_tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NEG + Kernel( + "aten::neg.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_neg.out"); + EXECUTORCH_SCOPE_PROF("native_call_neg.out"); + torch::executor::native::neg_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NEG + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NONZERO + Kernel( + "aten::nonzero.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_nonzero.out"); + EXECUTORCH_SCOPE_PROF("native_call_nonzero.out"); + torch::executor::native::nonzero_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NONZERO + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ONES + Kernel( + "aten::ones.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& size = *stack[0]; + EValue& out = *stack[1]; + auto size_list_out = size.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ones.out"); + EXECUTORCH_SCOPE_PROF("native_call_ones.out"); + torch::executor::native::ones_out(context, size_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ONES + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PDIST_FORWARD + Kernel( + "aten::_pdist_forward.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& p = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + double p_base = p.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__pdist_forward.out"); + EXECUTORCH_SCOPE_PROF("native_call__pdist_forward.out"); + torch::executor::native::_pdist_forward_out(context, in_base, p_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PDIST_FORWARD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PERMUTE_COPY + Kernel( + "aten::permute_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& dims = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto dims_list_out = dims.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_permute_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_permute_copy.out"); + torch::executor::native::permute_copy_out(context, in_base, dims_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PERMUTE_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_SHUFFLE + Kernel( + "aten::pixel_shuffle.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& upscale_factor = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + int64_t upscale_factor_base = upscale_factor.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pixel_shuffle.out"); + EXECUTORCH_SCOPE_PROF("native_call_pixel_shuffle.out"); + torch::executor::native::pixel_shuffle_out(context, in_base, upscale_factor_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_SHUFFLE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_UNSHUFFLE + Kernel( + "aten::pixel_unshuffle.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& downscale_factor = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + int64_t downscale_factor_base = downscale_factor.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pixel_unshuffle.out"); + EXECUTORCH_SCOPE_PROF("native_call_pixel_unshuffle.out"); + torch::executor::native::pixel_unshuffle_out(context, in_base, downscale_factor_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_UNSHUFFLE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_POW + Kernel( + "aten::pow.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Scalar& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pow.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_pow.Scalar_out"); + torch::executor::native::pow_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::pow.Tensor_Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pow.Tensor_Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_pow.Tensor_Scalar_out"); + torch::executor::native::pow_Tensor_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::pow.Tensor_Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pow.Tensor_Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_pow.Tensor_Tensor_out"); + torch::executor::native::pow_Tensor_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_POW + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PROD + Kernel( + "aten::prod.int_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& dtype = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + bool keepdim_base = keepdim.to(); + auto dtype_opt_out = dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_prod.int_out"); + EXECUTORCH_SCOPE_PROF("native_call_prod.int_out"); + torch::executor::native::prod_int_out(context, in_base, dim_base, keepdim_base, dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), + Kernel( + "aten::prod.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& dtype = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto dtype_opt_out = dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_prod.out"); + EXECUTORCH_SCOPE_PROF("native_call_prod.out"); + torch::executor::native::prod_out(context, in_base, dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PROD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RAND + Kernel( + "aten::rand.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& sizes = *stack[0]; + EValue& out = *stack[1]; + auto sizes_list_out = sizes.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_rand.out"); + EXECUTORCH_SCOPE_PROF("native_call_rand.out"); + torch::executor::native::rand_out(context, sizes_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RAND + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RANDN + Kernel( + "aten::randn.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& sizes = *stack[0]; + EValue& out = *stack[1]; + auto sizes_list_out = sizes.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_randn.out"); + EXECUTORCH_SCOPE_PROF("native_call_randn.out"); + torch::executor::native::randn_out(context, sizes_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RANDN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RECIPROCAL + Kernel( + "aten::reciprocal.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reciprocal.out"); + EXECUTORCH_SCOPE_PROF("native_call_reciprocal.out"); + torch::executor::native::reciprocal_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RECIPROCAL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD1D + Kernel( + "aten::reflection_pad1d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& padding = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto padding_list_out = padding.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reflection_pad1d.out"); + EXECUTORCH_SCOPE_PROF("native_call_reflection_pad1d.out"); + torch::executor::native::reflection_pad1d_out(context, in_base, padding_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD1D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD2D + Kernel( + "aten::reflection_pad2d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& padding = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto padding_list_out = padding.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reflection_pad2d.out"); + EXECUTORCH_SCOPE_PROF("native_call_reflection_pad2d.out"); + torch::executor::native::reflection_pad2d_out(context, in_base, padding_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD2D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD3D + Kernel( + "aten::reflection_pad3d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& padding = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto padding_list_out = padding.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reflection_pad3d.out"); + EXECUTORCH_SCOPE_PROF("native_call_reflection_pad3d.out"); + torch::executor::native::reflection_pad3d_out(context, in_base, padding_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD3D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RELU + Kernel( + "aten::relu.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_relu.out"); + EXECUTORCH_SCOPE_PROF("native_call_relu.out"); + torch::executor::native::relu_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RELU + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REMAINDER + Kernel( + "aten::remainder.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_remainder.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_remainder.Tensor_out"); + torch::executor::native::remainder_Tensor_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::remainder.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& out = *stack[2]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_remainder.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_remainder.Scalar_out"); + torch::executor::native::remainder_Scalar_out(context, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REMAINDER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT + Kernel( + "aten::repeat.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& self = *stack[0]; + EValue& repeats = *stack[1]; + EValue& out = *stack[2]; + const Tensor& self_base = self.to(); + auto repeats_list_out = repeats.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_repeat.out"); + EXECUTORCH_SCOPE_PROF("native_call_repeat.out"); + torch::executor::native::repeat_out(context, self_base, repeats_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT_INTERLEAVE + Kernel( + "aten::repeat_interleave.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& repeats = *stack[0]; + EValue& output_size = *stack[1]; + EValue& out = *stack[2]; + const Tensor& repeats_base = repeats.to(); + auto output_size_opt_out = output_size.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_repeat_interleave.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_repeat_interleave.Tensor_out"); + torch::executor::native::repeat_interleave_Tensor_out(context, repeats_base, output_size_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT_INTERLEAVE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD1D + Kernel( + "aten::replication_pad1d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& padding = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto padding_list_out = padding.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_replication_pad1d.out"); + EXECUTORCH_SCOPE_PROF("native_call_replication_pad1d.out"); + torch::executor::native::replication_pad1d_out(context, in_base, padding_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD1D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD2D + Kernel( + "aten::replication_pad2d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& padding = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto padding_list_out = padding.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_replication_pad2d.out"); + EXECUTORCH_SCOPE_PROF("native_call_replication_pad2d.out"); + torch::executor::native::replication_pad2d_out(context, in_base, padding_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD2D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD3D + Kernel( + "aten::replication_pad3d.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& padding = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto padding_list_out = padding.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_replication_pad3d.out"); + EXECUTORCH_SCOPE_PROF("native_call_replication_pad3d.out"); + torch::executor::native::replication_pad3d_out(context, in_base, padding_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD3D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROLL + Kernel( + "aten::roll.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& shifts = *stack[1]; + EValue& dims = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto shifts_list_out = shifts.toIntList(); + auto dims_list_out = dims.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_roll.out"); + EXECUTORCH_SCOPE_PROF("native_call_roll.out"); + torch::executor::native::roll_out(context, in_base, shifts_list_out, dims_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ROLL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROUND + Kernel( + "aten::round.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_round.out"); + EXECUTORCH_SCOPE_PROF("native_call_round.out"); + torch::executor::native::round_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ROUND + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSQRT + Kernel( + "aten::rsqrt.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_rsqrt.out"); + EXECUTORCH_SCOPE_PROF("native_call_rsqrt.out"); + torch::executor::native::rsqrt_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RSQRT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSUB + Kernel( + "aten::rsub.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& alpha = *stack[2]; + EValue& out = *stack[3]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + const Scalar& alpha_base = alpha.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_rsub.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_rsub.Scalar_out"); + torch::executor::native::rsub_scalar_out(context, a_base, b_base, alpha_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RSUB + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCALAR_TENSOR + Kernel( + "aten::scalar_tensor.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& s = *stack[0]; + EValue& out = *stack[1]; + const Scalar& s_base = s.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scalar_tensor.out"); + EXECUTORCH_SCOPE_PROF("native_call_scalar_tensor.out"); + torch::executor::native::scalar_tensor_out(context, s_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SCALAR_TENSOR + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER + Kernel( + "aten::scatter.src_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& index = *stack[2]; + EValue& src = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + const Tensor& index_base = index.to(); + const Tensor& src_base = src.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scatter.src_out"); + EXECUTORCH_SCOPE_PROF("native_call_scatter.src_out"); + torch::executor::native::scatter_src_out(context, in_base, dim_base, index_base, src_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), + Kernel( + "aten::scatter.value_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& index = *stack[2]; + EValue& value = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + const Tensor& index_base = index.to(); + const Scalar& value_base = value.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scatter.value_out"); + EXECUTORCH_SCOPE_PROF("native_call_scatter.value_out"); + torch::executor::native::scatter_value_out(context, in_base, dim_base, index_base, value_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER_ADD + Kernel( + "aten::scatter_add.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& self = *stack[0]; + EValue& dim = *stack[1]; + EValue& index = *stack[2]; + EValue& src = *stack[3]; + EValue& out = *stack[4]; + const Tensor& self_base = self.to(); + int64_t dim_base = dim.to(); + const Tensor& index_base = index.to(); + const Tensor& src_base = src.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scatter_add.out"); + EXECUTORCH_SCOPE_PROF("native_call_scatter_add.out"); + torch::executor::native::scatter_add_out(context, self_base, dim_base, index_base, src_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER_ADD + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_COPY + Kernel( + "aten::select_copy.int_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& index = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + int64_t index_base = index.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_select_copy.int_out"); + EXECUTORCH_SCOPE_PROF("native_call_select_copy.int_out"); + torch::executor::native::select_copy_int_out(context, in_base, dim_base, index_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_SCATTER + Kernel( + "aten::select_scatter.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& src = *stack[1]; + EValue& dim = *stack[2]; + EValue& index = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + const Tensor& src_base = src.to(); + int64_t dim_base = dim.to(); + int64_t index_base = index.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_select_scatter.out"); + EXECUTORCH_SCOPE_PROF("native_call_select_scatter.out"); + torch::executor::native::select_scatter_out(context, in_base, src_base, dim_base, index_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_SCATTER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGMOID + Kernel( + "aten::sigmoid.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sigmoid.out"); + EXECUTORCH_SCOPE_PROF("native_call_sigmoid.out"); + torch::executor::native::sigmoid_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SIGMOID + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGN + Kernel( + "aten::sign.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sign.out"); + EXECUTORCH_SCOPE_PROF("native_call_sign.out"); + torch::executor::native::sign_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SIGN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIN + Kernel( + "aten::sin.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sin.out"); + EXECUTORCH_SCOPE_PROF("native_call_sin.out"); + torch::executor::native::sin_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SIN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SINH + Kernel( + "aten::sinh.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sinh.out"); + EXECUTORCH_SCOPE_PROF("native_call_sinh.out"); + torch::executor::native::sinh_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SINH + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_COPY + Kernel( + "aten::slice_copy.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected 7 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& start_val = *stack[2]; + EValue& end_val = *stack[3]; + EValue& step = *stack[4]; + EValue& out = *stack[5]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + auto start_val_opt_out = start_val.toOptional(); + auto end_val_opt_out = end_val.toOptional(); + int64_t step_base = step.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_slice_copy.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_slice_copy.Tensor_out"); + torch::executor::native::slice_copy_Tensor_out(context, in_base, dim_base, start_val_opt_out, end_val_opt_out, step_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_SCATTER + Kernel( + "aten::slice_scatter.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& input = *stack[0]; + EValue& src = *stack[1]; + EValue& dim = *stack[2]; + EValue& start_val = *stack[3]; + EValue& end_val = *stack[4]; + EValue& step = *stack[5]; + EValue& out = *stack[6]; + const Tensor& input_base = input.to(); + const Tensor& src_base = src.to(); + int64_t dim_base = dim.to(); + auto start_val_opt_out = start_val.toOptional(); + auto end_val_opt_out = end_val.toOptional(); + int64_t step_base = step.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_slice_scatter.out"); + EXECUTORCH_SCOPE_PROF("native_call_slice_scatter.out"); + torch::executor::native::slice_scatter_out(context, input_base, src_base, dim_base, start_val_opt_out, end_val_opt_out, step_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_SCATTER + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SOFTMAX + Kernel( + "aten::_softmax.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& half_to_float = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + bool half_to_float_base = half_to_float.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__softmax.out"); + EXECUTORCH_SCOPE_PROF("native_call__softmax.out"); + torch::executor::native::softmax_out(context, in_base, dim_base, half_to_float_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SOFTMAX + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_COPY + Kernel( + "aten::split_copy.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& input = *stack[0]; + EValue& split_size = *stack[1]; + EValue& dim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& input_base = input.to(); + int64_t split_size_base = split_size.to(); + int64_t dim_base = dim.to(); + auto out_list_out = out.toTensorList(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_split_copy.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_split_copy.Tensor_out"); + torch::executor::native::split_copy_Tensor_out(context, input_base, split_size_base, dim_base, out_list_out); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_WITH_SIZES_COPY + Kernel( + "aten::split_with_sizes_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& split_sizes = *stack[1]; + EValue& dim = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + auto split_sizes_list_out = split_sizes.toIntList(); + int64_t dim_base = dim.to(); + auto out_list_out = out.toTensorList(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_split_with_sizes_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_split_with_sizes_copy.out"); + torch::executor::native::split_with_sizes_copy_out(context, in_base, split_sizes_list_out, dim_base, out_list_out); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_WITH_SIZES_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQRT + Kernel( + "aten::sqrt.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sqrt.out"); + EXECUTORCH_SCOPE_PROF("native_call_sqrt.out"); + torch::executor::native::sqrt_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SQRT + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQUEEZE_COPY + Kernel( + "aten::squeeze_copy.dim_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& dim = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + int64_t dim_base = dim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_squeeze_copy.dim_out"); + EXECUTORCH_SCOPE_PROF("native_call_squeeze_copy.dim_out"); + torch::executor::native::squeeze_copy_dim_out(context, in_base, dim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), + Kernel( + "aten::squeeze_copy.dims_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& in = *stack[0]; + EValue& dims = *stack[1]; + EValue& out = *stack[2]; + const Tensor& in_base = in.to(); + auto dims_list_out = dims.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_squeeze_copy.dims_out"); + EXECUTORCH_SCOPE_PROF("native_call_squeeze_copy.dims_out"); + torch::executor::native::squeeze_copy_dims_out(context, in_base, dims_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SQUEEZE_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_STACK + Kernel( + "aten::stack.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& tensors = *stack[0]; + EValue& dim = *stack[1]; + EValue& out = *stack[2]; + auto tensors_list_out = tensors.toTensorList(); + int64_t dim_base = dim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_stack.out"); + EXECUTORCH_SCOPE_PROF("native_call_stack.out"); + torch::executor::native::stack_out(context, tensors_list_out, dim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_STACK + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUB + Kernel( + "aten::sub.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& alpha = *stack[2]; + EValue& out = *stack[3]; + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + const Scalar& alpha_base = alpha.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sub.out"); + EXECUTORCH_SCOPE_PROF("native_call_sub.out"); + torch::executor::native::sub_out(context, a_base, b_base, alpha_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), + Kernel( + "aten::sub.Scalar_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& a = *stack[0]; + EValue& b = *stack[1]; + EValue& alpha = *stack[2]; + EValue& out = *stack[3]; + const Tensor& a_base = a.to(); + const Scalar& b_base = b.to(); + const Scalar& alpha_base = alpha.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sub.Scalar_out"); + EXECUTORCH_SCOPE_PROF("native_call_sub.Scalar_out"); + torch::executor::native::sub_scalar_out(context, a_base, b_base, alpha_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SUB + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUM + Kernel( + "aten::sum.IntList_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim_list = *stack[1]; + EValue& keepdim = *stack[2]; + EValue& dtype = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + auto dim_list_opt_out = dim_list.toOptional(); + bool keepdim_base = keepdim.to(); + auto dtype_opt_out = dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sum.IntList_out"); + EXECUTORCH_SCOPE_PROF("native_call_sum.IntList_out"); + torch::executor::native::sum_dim_out(context, in_base, dim_list_opt_out, keepdim_base, dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SUM + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_T_COPY + Kernel( + "aten::t_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_t_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_t_copy.out"); + torch::executor::native::t_copy_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_T_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TAN + Kernel( + "aten::tan.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_tan.out"); + EXECUTORCH_SCOPE_PROF("native_call_tan.out"); + torch::executor::native::tan_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TAN + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TANH + Kernel( + "aten::tanh.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_tanh.out"); + EXECUTORCH_SCOPE_PROF("native_call_tanh.out"); + torch::executor::native::tanh_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TANH + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_COPY + Kernel( + "aten::_to_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& self = *stack[0]; + EValue& non_blocking = *stack[1]; + EValue& memory_format = *stack[2]; + EValue& out = *stack[3]; + const Tensor& self_base = self.to(); + bool non_blocking_base = non_blocking.to(); + // WARNING: auto-generated unpack for std::optional + auto memory_format_base = memory_format.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__to_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call__to_copy.out"); + torch::executor::native::to_copy_out(context, self_base, non_blocking_base, memory_format_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TO_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TOPK + Kernel( + "aten::topk.values", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& in = *stack[0]; + EValue& k = *stack[1]; + EValue& dim = *stack[2]; + EValue& largest = *stack[3]; + EValue& sorted = *stack[4]; + EValue& values = *stack[5]; + EValue& indices = *stack[6]; + const Tensor& in_base = in.to(); + int64_t k_base = k.to(); + int64_t dim_base = dim.to(); + bool largest_base = largest.to(); + bool sorted_base = sorted.to(); + Tensor& values_base = values.to(); + Tensor& indices_base = indices.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_topk.values"); + EXECUTORCH_SCOPE_PROF("native_call_topk.values"); + torch::executor::native::topk_values(context, in_base, k_base, dim_base, largest_base, sorted_base, values_base, indices_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TOPK + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRANSPOSE_COPY + Kernel( + "aten::transpose_copy.int_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& dim0 = *stack[1]; + EValue& dim1 = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + int64_t dim0_base = dim0.to(); + int64_t dim1_base = dim1.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_transpose_copy.int_out"); + EXECUTORCH_SCOPE_PROF("native_call_transpose_copy.int_out"); + torch::executor::native::transpose_copy_int_out(context, in_base, dim0_base, dim1_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TRANSPOSE_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRIL + Kernel( + "aten::tril.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& self = *stack[0]; + EValue& diagonal = *stack[1]; + EValue& out = *stack[2]; + const Tensor& self_base = self.to(); + int64_t diagonal_base = diagonal.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_tril.out"); + EXECUTORCH_SCOPE_PROF("native_call_tril.out"); + torch::executor::native::tril_out(context, self_base, diagonal_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TRIL + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRUNC + Kernel( + "aten::trunc.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& in = *stack[0]; + EValue& out = *stack[1]; + const Tensor& in_base = in.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_trunc.out"); + EXECUTORCH_SCOPE_PROF("native_call_trunc.out"); + torch::executor::native::trunc_out(context, in_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TRUNC + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNBIND_COPY + Kernel( + "aten::unbind_copy.int_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& input = *stack[0]; + EValue& dim = *stack[1]; + EValue& out = *stack[2]; + const Tensor& input_base = input.to(); + int64_t dim_base = dim.to(); + auto out_list_out = out.toTensorList(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_unbind_copy.int_out"); + EXECUTORCH_SCOPE_PROF("native_call_unbind_copy.int_out"); + torch::executor::native::unbind_copy_int_out(context, input_base, dim_base, out_list_out); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UNBIND_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNFOLD_COPY + Kernel( + "aten::unfold_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& self = *stack[0]; + EValue& dim = *stack[1]; + EValue& size = *stack[2]; + EValue& step = *stack[3]; + EValue& out = *stack[4]; + const Tensor& self_base = self.to(); + int64_t dim_base = dim.to(); + int64_t size_base = size.to(); + int64_t step_base = step.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_unfold_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_unfold_copy.out"); + torch::executor::native::unfold_copy_out(context, self_base, dim_base, size_base, step_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UNFOLD_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNSQUEEZE_COPY + Kernel( + "aten::unsqueeze_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& self = *stack[0]; + EValue& dim = *stack[1]; + EValue& out = *stack[2]; + const Tensor& self_base = self.to(); + int64_t dim_base = dim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_unsqueeze_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_unsqueeze_copy.out"); + torch::executor::native::unsqueeze_copy_out(context, self_base, dim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UNSQUEEZE_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D + Kernel( + "aten::upsample_bilinear2d.vec_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& output_size = *stack[1]; + EValue& align_corners = *stack[2]; + EValue& scale_factors = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + // WARNING: auto-generated unpack for const executorch::aten::OptionalArrayRef + auto output_size_base = output_size.to(); + bool align_corners_base = align_corners.to(); + auto scale_factors_opt_out = scale_factors.toOptional>(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_upsample_bilinear2d.vec_out"); + EXECUTORCH_SCOPE_PROF("native_call_upsample_bilinear2d.vec_out"); + torch::executor::native::upsample_bilinear2d_vec_out(context, in_base, output_size_base, align_corners_base, scale_factors_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D_AA + Kernel( + "aten::_upsample_bilinear2d_aa.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected 7 args"); + EValue& in = *stack[0]; + EValue& output_size = *stack[1]; + EValue& align_corners = *stack[2]; + EValue& scale_h = *stack[3]; + EValue& scale_w = *stack[4]; + EValue& out = *stack[5]; + const Tensor& in_base = in.to(); + auto output_size_list_out = output_size.toIntList(); + bool align_corners_base = align_corners.to(); + auto scale_h_opt_out = scale_h.toOptional(); + auto scale_w_opt_out = scale_w.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__upsample_bilinear2d_aa.out"); + EXECUTORCH_SCOPE_PROF("native_call__upsample_bilinear2d_aa.out"); + torch::executor::native::_upsample_bilinear2d_aa_out(context, in_base, output_size_list_out, align_corners_base, scale_h_opt_out, scale_w_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D_AA + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_NEAREST2D + Kernel( + "aten::upsample_nearest2d.vec_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& in = *stack[0]; + EValue& output_size = *stack[1]; + EValue& scale_factors = *stack[2]; + EValue& out = *stack[3]; + const Tensor& in_base = in.to(); + // WARNING: auto-generated unpack for const executorch::aten::OptionalArrayRef + auto output_size_base = output_size.to(); + auto scale_factors_opt_out = scale_factors.toOptional>(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_upsample_nearest2d.vec_out"); + EXECUTORCH_SCOPE_PROF("native_call_upsample_nearest2d.vec_out"); + torch::executor::native::upsample_nearest2d_vec_out(context, in_base, output_size_base, scale_factors_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_NEAREST2D + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VAR + Kernel( + "aten::var.correction_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim_list = *stack[1]; + EValue& correction = *stack[2]; + EValue& keepdim = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + auto dim_list_opt_out = dim_list.toOptional(); + auto correction_opt_out = correction.toOptional(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_var.correction_out"); + EXECUTORCH_SCOPE_PROF("native_call_var.correction_out"); + torch::executor::native::var_correction_out(context, in_base, dim_list_opt_out, correction_opt_out, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), + Kernel( + "aten::var.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& dim_list = *stack[1]; + EValue& unbiased = *stack[2]; + EValue& keepdim = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + auto dim_list_opt_out = dim_list.toOptional(); + bool unbiased_base = unbiased.to(); + bool keepdim_base = keepdim.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_var.out"); + EXECUTORCH_SCOPE_PROF("native_call_var.out"); + torch::executor::native::var_out(context, in_base, dim_list_opt_out, unbiased_base, keepdim_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_VAR + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_AS_REAL_COPY + Kernel( + "aten::view_as_real_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& self = *stack[0]; + EValue& out = *stack[1]; + const Tensor& self_base = self.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_view_as_real_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_view_as_real_copy.out"); + torch::executor::native::view_as_real_copy_out(context, self_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_AS_REAL_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_COPY + Kernel( + "aten::view_copy.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected 4 args"); + EValue& self = *stack[0]; + EValue& size_int64_t = *stack[1]; + EValue& out = *stack[2]; + const Tensor& self_base = self.to(); + auto size_int64_t_list_out = size_int64_t.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_view_copy.out"); + EXECUTORCH_SCOPE_PROF("native_call_view_copy.out"); + torch::executor::native::view_copy_out(context, self_base, size_int64_t_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_COPY + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_WHERE + Kernel( + "aten::where.self_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& cond = *stack[0]; + EValue& a = *stack[1]; + EValue& b = *stack[2]; + EValue& out = *stack[3]; + const Tensor& cond_base = cond.to(); + const Tensor& a_base = a.to(); + const Tensor& b_base = b.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_where.self_out"); + EXECUTORCH_SCOPE_PROF("native_call_where.self_out"); + torch::executor::native::where_out(context, cond_base, a_base, b_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_WHERE + +#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ZEROS + Kernel( + "aten::zeros.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected 3 args"); + EValue& size = *stack[0]; + EValue& out = *stack[1]; + auto size_list_out = size.toIntList(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_zeros.out"); + EXECUTORCH_SCOPE_PROF("native_call_zeros.out"); + torch::executor::native::zeros_out(context, size_list_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ZEROS + +// ===================================================================== +// QUANTIZED OPERATORS +// ===================================================================== + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_ADD + Kernel( + "quantized_decomposed::add.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 16, InvalidProgram, /*void*/, "Expected 16 args"); + EValue& a = *stack[0]; + EValue& a_scale = *stack[1]; + EValue& a_zero_point = *stack[2]; + EValue& a_quant_min = *stack[3]; + EValue& a_quant_max = *stack[4]; + EValue& b = *stack[5]; + EValue& b_scale = *stack[6]; + EValue& b_zero_point = *stack[7]; + EValue& b_quant_min = *stack[8]; + EValue& b_quant_max = *stack[9]; + EValue& out_scale = *stack[10]; + EValue& out_zero_point = *stack[11]; + EValue& out_quant_min = *stack[12]; + EValue& out_quant_max = *stack[13]; + EValue& out = *stack[14]; + const Tensor& a_base = a.to(); + double a_scale_base = a_scale.to(); + int64_t a_zero_point_base = a_zero_point.to(); + int64_t a_quant_min_base = a_quant_min.to(); + int64_t a_quant_max_base = a_quant_max.to(); + const Tensor& b_base = b.to(); + double b_scale_base = b_scale.to(); + int64_t b_zero_point_base = b_zero_point.to(); + int64_t b_quant_min_base = b_quant_min.to(); + int64_t b_quant_max_base = b_quant_max.to(); + double out_scale_base = out_scale.to(); + int64_t out_zero_point_base = out_zero_point.to(); + int64_t out_quant_min_base = out_quant_min.to(); + int64_t out_quant_max_base = out_quant_max.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_add.out"); + EXECUTORCH_SCOPE_PROF("native_call_add.out"); + torch::executor::native::quantized_add_out(context, a_base, a_scale_base, a_zero_point_base, a_quant_min_base, a_quant_max_base, b_base, b_scale_base, b_zero_point_base, b_quant_min_base, b_quant_max_base, out_scale_base, out_zero_point_base, out_quant_min_base, out_quant_max_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[14]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_ADD + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_CHOOSE_QPARAMS + Kernel( + "quantized_decomposed::choose_qparams.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& input = *stack[0]; + EValue& quant_min = *stack[1]; + EValue& quant_max = *stack[2]; + EValue& eps = *stack[3]; + EValue& dtype = *stack[4]; + EValue& scale_out = *stack[5]; + EValue& zero_point_out = *stack[6]; + const Tensor& input_base = input.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + double eps_base = eps.to(); + ScalarType dtype_base = dtype.to(); + Tensor& scale_out_base = scale_out.to(); + Tensor& zero_point_out_base = zero_point_out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_choose_qparams.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_choose_qparams.Tensor_out"); + torch::executor::native::choose_qparams_tensor_out(context, input_base, quant_min_base, quant_max_base, eps_base, dtype_base, scale_out_base, zero_point_out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), + Kernel( + "quantized_decomposed::choose_qparams_per_token_asymmetric.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected 5 args"); + EValue& input = *stack[0]; + EValue& dtype = *stack[1]; + EValue& scale_out = *stack[2]; + EValue& zero_point_out = *stack[3]; + const Tensor& input_base = input.to(); + ScalarType dtype_base = dtype.to(); + Tensor& scale_out_base = scale_out.to(); + Tensor& zero_point_out_base = zero_point_out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_choose_qparams_per_token_asymmetric.out"); + EXECUTORCH_SCOPE_PROF("native_call_choose_qparams_per_token_asymmetric.out"); + torch::executor::native::choose_qparams_per_token_asymmetric_out(context, input_base, dtype_base, scale_out_base, zero_point_out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_CHOOSE_QPARAMS + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_DEQUANTIZE + Kernel( + "quantized_decomposed::dequantize_per_tensor.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& zero_point = *stack[2]; + EValue& quant_min = *stack[3]; + EValue& quant_max = *stack[4]; + EValue& dtype = *stack[5]; + EValue& out_dtype = *stack[6]; + EValue& out = *stack[7]; + const Tensor& input_base = input.to(); + double scale_base = scale.to(); + int64_t zero_point_base = zero_point.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + auto out_dtype_opt_out = out_dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_tensor.out"); + EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_tensor.out"); + torch::executor::native::dequantize_per_tensor_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), + Kernel( + "quantized_decomposed::dequantize_per_tensor.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& zero_point = *stack[2]; + EValue& quant_min = *stack[3]; + EValue& quant_max = *stack[4]; + EValue& dtype = *stack[5]; + EValue& out_dtype = *stack[6]; + EValue& out = *stack[7]; + const Tensor& input_base = input.to(); + const Tensor& scale_base = scale.to(); + const Tensor& zero_point_base = zero_point.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + auto out_dtype_opt_out = out_dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_tensor.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_tensor.Tensor_out"); + torch::executor::native::dequantize_per_tensor_tensor_args_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), + Kernel( + "quantized_decomposed::dequantize_per_channel.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 10, InvalidProgram, /*void*/, "Expected 10 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& opt_zero_points = *stack[2]; + EValue& axis = *stack[3]; + EValue& quant_min = *stack[4]; + EValue& quant_max = *stack[5]; + EValue& dtype = *stack[6]; + EValue& out_dtype = *stack[7]; + EValue& out = *stack[8]; + const Tensor& input_base = input.to(); + const Tensor& scale_base = scale.to(); + auto opt_zero_points_opt_out = opt_zero_points.toOptional(); + int64_t axis_base = axis.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + auto out_dtype_opt_out = out_dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_channel.out"); + EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_channel.out"); + torch::executor::native::dequantize_per_channel_out(context, input_base, scale_base, opt_zero_points_opt_out, axis_base, quant_min_base, quant_max_base, dtype_base, out_dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); + } + ), + Kernel( + "quantized_decomposed::dequantize_per_token.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& zero_points = *stack[2]; + EValue& quant_min = *stack[3]; + EValue& quant_max = *stack[4]; + EValue& dtype = *stack[5]; + EValue& out_dtype = *stack[6]; + EValue& out = *stack[7]; + const Tensor& input_base = input.to(); + const Tensor& scale_base = scale.to(); + const Tensor& zero_points_base = zero_points.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + ScalarType out_dtype_base = out_dtype.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_token.out"); + EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_token.out"); + torch::executor::native::dequantize_per_token_out(context, input_base, scale_base, zero_points_base, quant_min_base, quant_max_base, dtype_base, out_dtype_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_DEQUANTIZE + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING + Kernel( + "quantized_decomposed::embedding_byte.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& weight = *stack[0]; + EValue& weight_scales = *stack[1]; + EValue& opt_weight_zero_points = *stack[2]; + EValue& weight_quant_min = *stack[3]; + EValue& weight_quant_max = *stack[4]; + EValue& indices = *stack[5]; + EValue& out = *stack[6]; + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + int64_t weight_quant_min_base = weight_quant_min.to(); + int64_t weight_quant_max_base = weight_quant_max.to(); + const Tensor& indices_base = indices.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_byte.out"); + EXECUTORCH_SCOPE_PROF("native_call_embedding_byte.out"); + torch::executor::native::quantized_embedding_byte_out(context, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), + Kernel( + "quantized_decomposed::embedding_byte.dtype_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& weight = *stack[0]; + EValue& weight_scales = *stack[1]; + EValue& opt_weight_zero_points = *stack[2]; + EValue& weight_quant_min = *stack[3]; + EValue& weight_quant_max = *stack[4]; + EValue& indices = *stack[5]; + EValue& out_dtype = *stack[6]; + EValue& out = *stack[7]; + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + int64_t weight_quant_min_base = weight_quant_min.to(); + int64_t weight_quant_max_base = weight_quant_max.to(); + const Tensor& indices_base = indices.to(); + auto out_dtype_opt_out = out_dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_byte.dtype_out"); + EXECUTORCH_SCOPE_PROF("native_call_embedding_byte.dtype_out"); + torch::executor::native::quantized_embedding_byte_dtype_out(context, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING2B + Kernel( + "quantized_decomposed::embedding_2bit.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& weight = *stack[0]; + EValue& weight_scales = *stack[1]; + EValue& opt_weight_zero_points = *stack[2]; + EValue& weight_quant_min = *stack[3]; + EValue& weight_quant_max = *stack[4]; + EValue& indices = *stack[5]; + EValue& out = *stack[6]; + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + int64_t weight_quant_min_base = weight_quant_min.to(); + int64_t weight_quant_max_base = weight_quant_max.to(); + const Tensor& indices_base = indices.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_2bit.out"); + EXECUTORCH_SCOPE_PROF("native_call_embedding_2bit.out"); + torch::executor::native::quantized_embedding_2bit_out(context, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), + Kernel( + "quantized_decomposed::embedding_2bit.dtype_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& weight = *stack[0]; + EValue& weight_scales = *stack[1]; + EValue& opt_weight_zero_points = *stack[2]; + EValue& weight_quant_min = *stack[3]; + EValue& weight_quant_max = *stack[4]; + EValue& indices = *stack[5]; + EValue& out_dtype = *stack[6]; + EValue& out = *stack[7]; + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + int64_t weight_quant_min_base = weight_quant_min.to(); + int64_t weight_quant_max_base = weight_quant_max.to(); + const Tensor& indices_base = indices.to(); + auto out_dtype_opt_out = out_dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_2bit.dtype_out"); + EXECUTORCH_SCOPE_PROF("native_call_embedding_2bit.dtype_out"); + torch::executor::native::quantized_embedding_2bit_dtype_out(context, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING2B + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING4B + Kernel( + "quantized_decomposed::embedding_4bit.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& weight = *stack[0]; + EValue& weight_scales = *stack[1]; + EValue& opt_weight_zero_points = *stack[2]; + EValue& weight_quant_min = *stack[3]; + EValue& weight_quant_max = *stack[4]; + EValue& indices = *stack[5]; + EValue& out = *stack[6]; + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + int64_t weight_quant_min_base = weight_quant_min.to(); + int64_t weight_quant_max_base = weight_quant_max.to(); + const Tensor& indices_base = indices.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_4bit.out"); + EXECUTORCH_SCOPE_PROF("native_call_embedding_4bit.out"); + torch::executor::native::quantized_embedding_4bit_out(context, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), + Kernel( + "quantized_decomposed::embedding_4bit.dtype_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& weight = *stack[0]; + EValue& weight_scales = *stack[1]; + EValue& opt_weight_zero_points = *stack[2]; + EValue& weight_quant_min = *stack[3]; + EValue& weight_quant_max = *stack[4]; + EValue& indices = *stack[5]; + EValue& out_dtype = *stack[6]; + EValue& out = *stack[7]; + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + int64_t weight_quant_min_base = weight_quant_min.to(); + int64_t weight_quant_max_base = weight_quant_max.to(); + const Tensor& indices_base = indices.to(); + auto out_dtype_opt_out = out_dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_4bit.dtype_out"); + EXECUTORCH_SCOPE_PROF("native_call_embedding_4bit.dtype_out"); + torch::executor::native::quantized_embedding_4bit_dtype_out(context, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING4B + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_LINEAR + Kernel( + "quantized_decomposed::mixed_linear.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected 7 args"); + EValue& in = *stack[0]; + EValue& weight = *stack[1]; + EValue& weight_scales = *stack[2]; + EValue& opt_weight_zero_points = *stack[3]; + EValue& dtype = *stack[4]; + EValue& out = *stack[5]; + const Tensor& in_base = in.to(); + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + auto dtype_opt_out = dtype.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mixed_linear.out"); + EXECUTORCH_SCOPE_PROF("native_call_mixed_linear.out"); + torch::executor::native::quantized_mixed_linear_out(context, in_base, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, dtype_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_LINEAR + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_MM + Kernel( + "quantized_decomposed::mixed_mm.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected 6 args"); + EValue& in = *stack[0]; + EValue& weight = *stack[1]; + EValue& weight_scales = *stack[2]; + EValue& opt_weight_zero_points = *stack[3]; + EValue& out = *stack[4]; + const Tensor& in_base = in.to(); + const Tensor& weight_base = weight.to(); + const Tensor& weight_scales_base = weight_scales.to(); + auto opt_weight_zero_points_opt_out = opt_weight_zero_points.toOptional(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mixed_mm.out"); + EXECUTORCH_SCOPE_PROF("native_call_mixed_mm.out"); + torch::executor::native::quantized_mixed_mm_out(context, in_base, weight_base, weight_scales_base, opt_weight_zero_points_opt_out, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_MM + +#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_QUANTIZE + Kernel( + "quantized_decomposed::quantize_per_channel.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected 9 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& zero_point = *stack[2]; + EValue& axis = *stack[3]; + EValue& quant_min = *stack[4]; + EValue& quant_max = *stack[5]; + EValue& dtype = *stack[6]; + EValue& out = *stack[7]; + const Tensor& input_base = input.to(); + const Tensor& scale_base = scale.to(); + const Tensor& zero_point_base = zero_point.to(); + int64_t axis_base = axis.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_channel.out"); + EXECUTORCH_SCOPE_PROF("native_call_quantize_per_channel.out"); + torch::executor::native::quantize_per_channel_out(context, input_base, scale_base, zero_point_base, axis_base, quant_min_base, quant_max_base, dtype_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); + } + ), + Kernel( + "quantized_decomposed::quantize_per_tensor.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& zero_point = *stack[2]; + EValue& quant_min = *stack[3]; + EValue& quant_max = *stack[4]; + EValue& dtype = *stack[5]; + EValue& out = *stack[6]; + const Tensor& input_base = input.to(); + double scale_base = scale.to(); + int64_t zero_point_base = zero_point.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_tensor.out"); + EXECUTORCH_SCOPE_PROF("native_call_quantize_per_tensor.out"); + torch::executor::native::quantize_per_tensor_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), + Kernel( + "quantized_decomposed::quantize_per_tensor.Tensor_out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& zero_point = *stack[2]; + EValue& quant_min = *stack[3]; + EValue& quant_max = *stack[4]; + EValue& dtype = *stack[5]; + EValue& out = *stack[6]; + const Tensor& input_base = input.to(); + const Tensor& scale_base = scale.to(); + const Tensor& zero_point_base = zero_point.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_tensor.Tensor_out"); + EXECUTORCH_SCOPE_PROF("native_call_quantize_per_tensor.Tensor_out"); + torch::executor::native::quantize_per_tensor_tensor_args_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), + Kernel( + "quantized_decomposed::quantize_per_token.out", + [](torch::executor::KernelRuntimeContext & context, Span stack) { + ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected 8 args"); + EValue& input = *stack[0]; + EValue& scale = *stack[1]; + EValue& zero_point = *stack[2]; + EValue& quant_min = *stack[3]; + EValue& quant_max = *stack[4]; + EValue& dtype = *stack[5]; + EValue& out = *stack[6]; + const Tensor& input_base = input.to(); + const Tensor& scale_base = scale.to(); + const Tensor& zero_point_base = zero_point.to(); + int64_t quant_min_base = quant_min.to(); + int64_t quant_max_base = quant_max.to(); + ScalarType dtype_base = dtype.to(); + Tensor& out_base = out.to(); + executorch::runtime::internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_token.out"); + EXECUTORCH_SCOPE_PROF("native_call_quantize_per_token.out"); + torch::executor::native::quantize_per_token_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_base); + executorch::runtime::internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); + } + ), +#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_QUANTIZE + +// Sentinel to ensure the array has at least one element +// (Required because all operators might be #ifdef'd out) + Kernel(nullptr, nullptr) +}; + +// Calculate the number of kernels (excluding the sentinel) +static constexpr size_t num_kernels = sizeof(kernels_to_register) / sizeof(Kernel) - 1; + +// Explicitly convert to Span, so that the API can take an empty C array of Kernels. +static KernelSpan kernel_span( + kernels_to_register, + kernels_to_register + num_kernels); + +// Return value not used. Keep the static variable assignment to register +// kernels in static initialization time. +static auto success_with_kernel_reg = (num_kernels > 0) ? register_kernels(kernel_span) : Error::Ok; + +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_execution_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/backend_execution_context.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_execution_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/backend_execution_context.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_init_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/backend_init_context.h similarity index 59% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_init_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/backend_init_context.h index 0f649b3..777744e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_init_context.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/backend_init_context.h @@ -7,15 +7,9 @@ */ #pragma once -#include -#include #include #include #include -#include -#include - -#include #ifdef __GNUC__ // Disable -Wdeprecated-declarations, as some builds use 'Werror'. @@ -35,8 +29,7 @@ class BackendInitContext final { MemoryAllocator* runtime_allocator, EventTracer* event_tracer = nullptr, const char* method_name = nullptr, - const NamedDataMap* named_data_map = nullptr, - Span runtime_specs = {}) + const NamedDataMap* named_data_map = nullptr) : runtime_allocator_(runtime_allocator), #ifdef ET_EVENT_TRACER_ENABLED event_tracer_(event_tracer), @@ -44,8 +37,7 @@ class BackendInitContext final { event_tracer_(nullptr), #endif method_name_(method_name), - named_data_map_(named_data_map), - runtime_specs_(runtime_specs) { + named_data_map_(named_data_map) { } /** Get the runtime allocator passed from Method. It's the same runtime @@ -83,58 +75,11 @@ class BackendInitContext final { return named_data_map_; } - /** - * Get the runtime specs (load-time options) for this backend. - * These are per-delegate options passed at Module::load() time. - * - * @return Span of BackendOption containing the runtime specs, or empty span - * if no runtime specs were provided. - */ - Span runtime_specs() const { - return runtime_specs_; - } - - /** - * Get a runtime spec value by key and type. - * - * @tparam T The expected type (bool, int, or const char*) - * @param key The option key to look up. - * @return Result containing the value if found and type matches, - * Error::NotFound if key doesn't exist, - * Error::InvalidArgument if key exists but type doesn't match. - */ - template - Result get_runtime_spec(const char* key) const { - static_assert( - std::is_same_v || std::is_same_v || - std::is_same_v, - "get_runtime_spec only supports bool, int, and const char*"); - - for (size_t i = 0; i < runtime_specs_.size(); ++i) { - const auto& opt = runtime_specs_[i]; - if (std::strcmp(opt.key, key) == 0) { - if constexpr (std::is_same_v) { - if (auto* arr = std::get_if>( - &opt.value)) { - return arr->data(); - } - } else { - if (auto* val = std::get_if(&opt.value)) { - return *val; - } - } - return Error::InvalidArgument; - } - } - return Error::NotFound; - } - private: MemoryAllocator* runtime_allocator_ = nullptr; EventTracer* event_tracer_ = nullptr; const char* method_name_ = nullptr; const NamedDataMap* named_data_map_ = nullptr; - Span runtime_specs_; }; } // namespace ET_RUNTIME_NAMESPACE diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_option_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/backend_option_context.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_option_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/backend_option_context.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/interface.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/interface.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/interface.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/interface.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/interface.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/interface.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/interface.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/options.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/options.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/options.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/options.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/targets.bzl new file mode 100644 index 0000000..606ae32 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/targets.bzl @@ -0,0 +1,33 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + runtime.cxx_library( + name = "interface" + aten_suffix, + srcs = [ + "interface.cpp", + ], + exported_headers = [ + "backend_execution_context.h", + "backend_init_context.h", + "backend_option_context.h", + "options.h", + "interface.h", + ], + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/core:event_tracer" + aten_suffix, + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/core:named_data_map", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_interface_update_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_interface_update_test.cpp new file mode 100644 index 0000000..210f82e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_interface_update_test.cpp @@ -0,0 +1,402 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; +using executorch::runtime::Backend; +using executorch::runtime::BackendExecutionContext; +using executorch::runtime::BackendInitContext; +using executorch::runtime::BackendInterface; +using executorch::runtime::BackendOption; +using executorch::runtime::BackendOptionContext; +using executorch::runtime::BackendOptions; +using executorch::runtime::CompileSpec; +using executorch::runtime::DelegateHandle; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::get_backend_class; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +class MockBackend : public BackendInterface { + public: + ~MockBackend() override = default; + + bool is_available() const override { + return true; + } + + Result init( + __ET_UNUSED BackendInitContext& context, + __ET_UNUSED FreeableBuffer* processed, + __ET_UNUSED ArrayRef compile_specs) const override { + init_called = true; + return nullptr; + } + + Error execute( + __ET_UNUSED BackendExecutionContext& context, + __ET_UNUSED DelegateHandle* handle, + __ET_UNUSED Span args) const override { + execute_count++; + return Error::Ok; + } + + Error set_option( + __ET_UNUSED BackendOptionContext& context, + const executorch::runtime::Span& backend_options) + override { + set_option_count++; + int success_update = 0; + for (const auto& backend_option : backend_options) { + if (strcmp(backend_option.key, "Backend") == 0) { + if (std::holds_alternative< + std::array>( + backend_option.value)) { + // Store the value in our member variable + const auto& arr = + std::get>(backend_option.value); + target_backend = std::string(arr.data()); + success_update++; + } + } else if (strcmp(backend_option.key, "NumberOfThreads") == 0) { + if (std::holds_alternative(backend_option.value)) { + num_threads = std::get(backend_option.value); + success_update++; + } + } else if (strcmp(backend_option.key, "Debug") == 0) { + if (std::holds_alternative(backend_option.value)) { + debug = std::get(backend_option.value); + success_update++; + } + } + } + if (success_update == backend_options.size()) { + return Error::Ok; + } + return Error::InvalidArgument; + } + + // Mutable allows modification in const methods + mutable std::optional target_backend; + mutable int num_threads = 0; + mutable bool debug = false; + + // State tracking + mutable bool init_called = false; + mutable int execute_count = 0; + mutable int set_option_count = 0; +}; + +class BackendInterfaceUpdateTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + mock_backend = std::make_unique(); + // static Error register_success = register_executor_backend(); + } + + std::unique_ptr mock_backend; + BackendOptions<5> options; +}; + +TEST_F(BackendInterfaceUpdateTest, HandlesInvalidOption) { + BackendOptionContext context; + + // Test invalid key case + std::array value_array{"None"}; + BackendOption invalid_option{"InvalidKey", value_array}; + + Error err = mock_backend->set_option(context, invalid_option); + EXPECT_EQ(err, Error::InvalidArgument); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesStringOption) { + BackendOptionContext context; + options.set_option("Backend", "GPU"); + // // Create a backend option to pass to update + + EXPECT_EQ(mock_backend->target_backend, std::nullopt); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + + EXPECT_EQ(mock_backend->target_backend, "GPU"); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesIntOption) { + // Check the default num_threads value is 0 + EXPECT_EQ(mock_backend->debug, false); + // Create a mock context (needs to be defined or mocked) + BackendOptionContext context; + + int expected_num_threads = 4; + + // Create a backend option to pass to update + options.set_option("NumberOfThreads", expected_num_threads); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(mock_backend->num_threads, expected_num_threads); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesBoolOption) { + // Check the default num_threads value is 0 + EXPECT_EQ(mock_backend->debug, false); + // Create a mock context (needs to be defined or mocked) + BackendOptionContext context; + + options.set_option("Debug", true); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + + EXPECT_EQ(mock_backend->debug, true); +} + +TEST_F(BackendInterfaceUpdateTest, HandlesMultipleOptions) { + // Check the default num_threads value is 0 + EXPECT_EQ(mock_backend->debug, false); + // Create a mock context (needs to be defined or mocked) + BackendOptionContext context; + + options.set_option("Debug", true); + options.set_option("NumberOfThreads", 4); + options.set_option("Backend", "GPU"); + + // Test successful update + Error err = mock_backend->set_option(context, options.view()); + EXPECT_EQ(err, Error::Ok); + + EXPECT_EQ(mock_backend->debug, true); + EXPECT_EQ(mock_backend->num_threads, 4); + EXPECT_EQ(mock_backend->target_backend, "GPU"); +} + +TEST_F(BackendInterfaceUpdateTest, UpdateBeforeInit) { + BackendOptionContext option_context; + MemoryAllocator memory_allocator{MemoryAllocator(0, nullptr)}; + + BackendInitContext init_context(&memory_allocator); + + // Create backend option + options.set_option("Backend", "GPU"); + + // Update before init + Error err = mock_backend->set_option(option_context, options.view()); + EXPECT_EQ(err, Error::Ok); + + // Now call init + FreeableBuffer* processed = nullptr; // Not used in mock + ArrayRef compile_specs; // Empty + auto handle_or_error = + mock_backend->init(init_context, processed, compile_specs); + EXPECT_EQ(handle_or_error.error(), Error::Ok); + + // Verify state + EXPECT_TRUE(mock_backend->init_called); + EXPECT_EQ(mock_backend->set_option_count, 1); + EXPECT_EQ(mock_backend->execute_count, 0); + ASSERT_TRUE(mock_backend->target_backend.has_value()); + EXPECT_STREQ(mock_backend->target_backend.value().c_str(), "GPU"); +} + +TEST_F(BackendInterfaceUpdateTest, UpdateAfterInitBeforeExecute) { + BackendOptionContext option_context; + MemoryAllocator init_memory_allocator{MemoryAllocator(0, nullptr)}; + BackendInitContext init_context(&init_memory_allocator); + BackendExecutionContext execute_context; + + // First call init + FreeableBuffer* processed = nullptr; + ArrayRef compile_specs; + auto handle_or_error = + mock_backend->init(init_context, processed, compile_specs); + EXPECT_TRUE(handle_or_error.ok()); + + // Verify init called but execute not called + EXPECT_TRUE(mock_backend->init_called); + EXPECT_EQ(mock_backend->execute_count, 0); + + // Now update + options.set_option("Backend", "CPU"); + Error err = mock_backend->set_option(option_context, options.view()); + EXPECT_EQ(err, Error::Ok); + + // Now execute + DelegateHandle* handle = handle_or_error.get(); + Span args((EValue**)nullptr, (size_t)0); // Not used in mock + err = mock_backend->execute(execute_context, handle, args); + EXPECT_EQ(err, Error::Ok); + + // Verify state + EXPECT_EQ(mock_backend->set_option_count, 1); + EXPECT_EQ(mock_backend->execute_count, 1); + ASSERT_TRUE(mock_backend->target_backend.has_value()); + EXPECT_STREQ(mock_backend->target_backend.value().c_str(), "CPU"); +} + +TEST_F(BackendInterfaceUpdateTest, UpdateBetweenExecutes) { + BackendOptionContext option_context; + MemoryAllocator init_memory_allocator{MemoryAllocator(0, nullptr)}; + BackendInitContext init_context(&init_memory_allocator); + BackendExecutionContext execute_context; + + // Initialize + FreeableBuffer* processed = nullptr; + ArrayRef compile_specs; + auto handle_or_error = + mock_backend->init(init_context, processed, compile_specs); + EXPECT_TRUE(handle_or_error.ok()); + DelegateHandle* handle = handle_or_error.get(); + + // First execute + Span args((EValue**)nullptr, (size_t)0); // Not used in mock + Error err = mock_backend->execute(execute_context, handle, args); + EXPECT_EQ(err, Error::Ok); + + // Update between executes + options.set_option("Backend", "NPU"); + err = mock_backend->set_option(option_context, options.view()); + EXPECT_EQ(err, Error::Ok); + + // Second execute + err = mock_backend->execute(execute_context, handle, args); + EXPECT_EQ(err, Error::Ok); + + // Verify state + EXPECT_EQ(mock_backend->set_option_count, 1); + EXPECT_EQ(mock_backend->execute_count, 2); + ASSERT_TRUE(mock_backend->target_backend.has_value()); + EXPECT_STREQ(mock_backend->target_backend.value().c_str(), "NPU"); +} + +// Mock backend for testing +class StubBackend : public BackendInterface { + public: + ~StubBackend() override = default; + + bool is_available() const override { + return true; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + return nullptr; + } + + Error execute( + BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + return Error::Ok; + } + + Error get_option( + BackendOptionContext& context, + executorch::runtime::Span& + backend_options) override { + // For testing purposes, just record that get_option was called + // and verify the input parameters + get_option_called = true; + get_option_call_count++; + last_get_option_size = backend_options.size(); + + // Verify that the expected option key is present and modify the value + for (size_t i = 0; i < backend_options.size(); ++i) { + if (strcmp(backend_options[i].key, "NumberOfThreads") == 0) { + // Set the value to what was stored by set_option + backend_options[i].value = last_num_threads; + found_expected_key = true; + break; + } + } + + return Error::Ok; + } + + Error set_option( + BackendOptionContext& context, + const executorch::runtime::Span& + backend_options) override { + // Store the options for verification + last_options_size = backend_options.size(); + if (backend_options.size() > 0) { + for (const auto& option : backend_options) { + if (strcmp(option.key, "NumberOfThreads") == 0) { + if (auto* val = std::get_if(&option.value)) { + last_num_threads = *val; + } + } + } + } + return Error::Ok; + } + + // Mutable for testing verification + size_t last_options_size = 0; + int last_num_threads = 0; + bool get_option_called = false; + int get_option_call_count = 0; + size_t last_get_option_size = 0; + bool found_expected_key = false; +}; + +class BackendUpdateTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Register the stub backend + stub_backend = std::make_unique(); + Backend backend_config{"StubBackend", stub_backend.get()}; + auto register_result = register_backend(backend_config); + ASSERT_EQ(register_result, Error::Ok); + } + + std::unique_ptr stub_backend; +}; + +// Test basic string functionality +TEST_F(BackendUpdateTest, TestSetGetOption) { + BackendOptions<1> backend_options; + int new_num_threads = 4; + backend_options.set_option("NumberOfThreads", new_num_threads); + + auto status = set_option("StubBackend", backend_options.view()); + ASSERT_EQ(status, Error::Ok); + + // Set up the default option, which will be populuated by the get_option call + BackendOption ref_backend_option{"NumberOfThreads", 0}; + status = get_option("StubBackend", ref_backend_option); + + // Verify that the backend actually received the options + ASSERT_TRUE(std::get(ref_backend_option.value) == new_num_threads); + + // Verify that the backend actually update the options + ASSERT_EQ(stub_backend->last_options_size, 1); + ASSERT_EQ(stub_backend->last_num_threads, new_num_threads); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_options_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_options_test.cpp new file mode 100644 index 0000000..313cac6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/backend_options_test.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::BackendOptions; +using executorch::runtime::Error; + +class BackendOptionsTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } + BackendOptions<5> options; // Capacity of 5 for testing limits +}; + +// Test basic string functionality +TEST_F(BackendOptionsTest, HandlesStringOptions) { + // Set and retrieve valid string + options.set_option("backend_type", "GPU"); + const char* result = nullptr; + EXPECT_EQ(options.get_option("backend_type", result), Error::Ok); + EXPECT_STREQ(result, "GPU"); + + // Update existing key + options.set_option("backend_type", "CPU"); + EXPECT_EQ(options.get_option("backend_type", result), Error::Ok); + EXPECT_STREQ(result, "CPU"); +} + +// Test boolean options +TEST_F(BackendOptionsTest, HandlesBoolOptions) { + options.set_option("debug", true); + bool debug = false; + EXPECT_EQ(options.get_option("debug", debug), Error::Ok); + EXPECT_TRUE(debug); + + // Test false value + options.set_option("verbose", false); + EXPECT_EQ(options.get_option("verbose", debug), Error::Ok); + EXPECT_FALSE(debug); +} + +// Test integer options +TEST_F(BackendOptionsTest, HandlesIntOptions) { + options.set_option("num_threads", 256); + int num_threads = 0; + EXPECT_EQ(options.get_option("num_threads", num_threads), Error::Ok); + EXPECT_EQ(num_threads, 256); +} + +// Test error conditions +TEST_F(BackendOptionsTest, HandlesErrors) { + // Non-existent key + bool dummy_bool; + EXPECT_EQ(options.get_option("missing", dummy_bool), Error::NotFound); + + // Type mismatch + options.set_option("threshold", 100); + const char* dummy_str = nullptr; + EXPECT_EQ(options.get_option("threshold", dummy_str), Error::InvalidArgument); + + // Null value handling, should expect failure + ET_EXPECT_DEATH( + options.set_option("nullable", static_cast(nullptr)), ""); +} + +// Test type-specific keys +TEST_F(BackendOptionsTest, EnforcesKeyTypes) { + // Same key name - later set operations overwrite earlier ones + options.set_option("flag", true); + options.set_option("flag", 123); // Overwrites the boolean entry + + bool bval; + int ival; + + // Boolean get should fail - type was overwritten to INT + EXPECT_EQ(options.get_option("flag", bval), Error::InvalidArgument); + + // Integer get should succeed with correct value + EXPECT_EQ(options.get_option("flag", ival), Error::Ok); + EXPECT_EQ(ival, 123); +} + +TEST_F(BackendOptionsTest, MutableOption) { + int ival; + options.set_option("flag", 0); + // Integer get should succeed with correct value + EXPECT_EQ(options.get_option("flag", ival), Error::Ok); + EXPECT_EQ(ival, 0); + + options.view()[0].value = 123; // Overwrites the entry + + // Integer get should succeed with the updated value + EXPECT_EQ(options.get_option("flag", ival), Error::Ok); + EXPECT_EQ(ival, 123); +} + +// Test copy constructor +TEST_F(BackendOptionsTest, CopyConstructor) { + // Set up original option + options.set_option("debug", true); + + // Create copy using copy constructor + BackendOptions<5> copied_options(options); + + // Verify option was copied correctly + bool debug_val; + EXPECT_EQ(copied_options.get_option("debug", debug_val), Error::Ok); + EXPECT_TRUE(debug_val); + + // Verify independence - modifying original doesn't affect copy + options.set_option("debug", false); + EXPECT_EQ(copied_options.get_option("debug", debug_val), Error::Ok); + EXPECT_TRUE(debug_val); // Should still be true in copy + + // Verify independence - modifying copy doesn't affect original + copied_options.set_option("debug", false); + EXPECT_EQ(options.get_option("debug", debug_val), Error::Ok); + EXPECT_FALSE(debug_val); // Should be false in original +} + +// Test copy assignment operator +TEST_F(BackendOptionsTest, CopyAssignmentOperator) { + // Set up original option + options.set_option("enable_profiling", true); + + // Create another options object and assign to it + BackendOptions<5> assigned_options; + assigned_options.set_option("temp_option", false); // Add something first + + assigned_options = options; + + // Verify option was copied correctly + bool profiling_val; + EXPECT_EQ( + assigned_options.get_option("enable_profiling", profiling_val), + Error::Ok); + EXPECT_TRUE(profiling_val); + + // Verify the temp_option was overwritten (not present in assigned object) + bool temp_val; + EXPECT_EQ( + assigned_options.get_option("temp_option", temp_val), Error::NotFound); + + // Verify independence - modifying original doesn't affect assigned copy + options.set_option("enable_profiling", false); + EXPECT_EQ( + assigned_options.get_option("enable_profiling", profiling_val), + Error::Ok); + EXPECT_TRUE(profiling_val); // Should still be true in assigned copy +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/targets.bzl new file mode 100644 index 0000000..f9e5c1e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/backend/test/targets.bzl @@ -0,0 +1,26 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "backend_options_test", + srcs = ["backend_options_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/backend:interface", + "//executorch/test/utils:utils", + ], + ) + + runtime.cxx_test( + name = "backend_interface_update_test", + srcs = ["backend_interface_update_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/backend:interface", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/array_ref.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/array_ref.h similarity index 98% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/array_ref.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/array_ref.h index d920761..a23509e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/array_ref.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/array_ref.h @@ -30,7 +30,6 @@ #include #include -#include #include namespace executorch { @@ -162,8 +161,7 @@ class ArrayRef final { /// slice(n, m) - Take M elements of the array starting at element N ArrayRef slice(size_t N, size_t M) const { // cant slice longer then the array - size_t end = 0; - ET_CHECK(!c10::add_overflows(N, M, &end) && end <= size()); + ET_CHECK(N + M <= size()); return ArrayRef(data() + N, M); } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/data_loader.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/data_loader.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/data_loader.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/data_loader.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/defines.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/defines.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/defines.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/defines.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/error.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/error.h similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/error.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/error.h index 80c2ef6..b75f107 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/error.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/error.h @@ -44,9 +44,6 @@ enum class Error : error_code_t { /// Status indicating there are no more steps of execution to run EndOfMethod = 0x03, - /// Status indicating a resource has already been loaded. - AlreadyLoaded = 0x04, - /* * Logical errors. */ @@ -117,8 +114,6 @@ constexpr const char* to_string(const Error error) { return "Error::InvalidState"; case Error::EndOfMethod: return "Error::EndOfMethod"; - case Error::AlreadyLoaded: - return "Error::AlreadyLoaded"; case Error::NotSupported: return "Error::NotSupported"; case Error::NotImplemented: @@ -152,7 +147,6 @@ constexpr const char* to_string(const Error error) { case Error::RegistrationAlreadyRegistered: return "Error::RegistrationAlreadyRegistered"; } - return "Error::Unknown"; } } // namespace runtime diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/evalue.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/evalue.cpp similarity index 54% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/evalue.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/evalue.cpp index 6fd118d..121a9a2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/evalue.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/evalue.cpp @@ -10,10 +10,6 @@ namespace executorch { namespace runtime { - -// Specialize for list of optional tensors, as nullptr is a valid std::nullopt. -// For non-optional types, nullptr is invalid. - template <> executorch::aten::ArrayRef> BoxedEvalueList>::get() const { @@ -31,26 +27,5 @@ BoxedEvalueList>::get() const { return executorch::aten::ArrayRef>{ unwrapped_vals_, wrapped_vals_.size()}; } - -template <> -Result>> -BoxedEvalueList>::tryGet() const { - for (typename executorch::aten::ArrayRef< - std::optional>::size_type i = 0; - i < wrapped_vals_.size(); - i++) { - if (wrapped_vals_[i] == nullptr) { - unwrapped_vals_[i] = std::nullopt; - continue; - } - auto r = wrapped_vals_[i]->tryToOptional(); - if (!r.ok()) { - return r.error(); - } - unwrapped_vals_[i] = std::move(r.get()); - } - return executorch::aten::ArrayRef>{ - unwrapped_vals_, wrapped_vals_.size()}; -} } // namespace runtime } // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/evalue.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/evalue.h similarity index 69% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/evalue.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/evalue.h index eed52bb..18927ab 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/evalue.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/evalue.h @@ -8,7 +8,6 @@ #pragma once #include -#include #include #include @@ -72,30 +71,6 @@ class BoxedEvalueList { */ executorch::aten::ArrayRef get() const; - /** - * Result-returning counterpart of get(). Validates each wrapped EValue's - * tag before materializing; returns Error::InvalidType if any element's - * tag does not match T and Error::InvalidState if any element pointer is - * null. Use this when materializing lists from untrusted .pte data so that - * a malformed program cannot force a process abort inside to() / - * ET_CHECK. - */ - Result> tryGet() const; - - /** - * Destroys the unwrapped elements without re-dereferencing wrapped_vals_. - * This is safe to call during EValue destruction because it does not - * dereference wrapped_vals_, which may point to EValues mutated by - * MoveCall instructions. - */ - void destroy_elements() { - for (typename executorch::aten::ArrayRef::size_type i = 0; - i < wrapped_vals_.size(); - i++) { - unwrapped_vals_[i].~T(); - } - } - private: static EValue** checkWrappedVals(EValue** wrapped_vals, int size) { ET_CHECK_MSG(wrapped_vals != nullptr, "wrapped_vals cannot be null"); @@ -118,10 +93,6 @@ template <> executorch::aten::ArrayRef> BoxedEvalueList>::get() const; -template <> -Result>> -BoxedEvalueList>::tryGet() const; - // Aggregate typing system similar to IValue only slimmed down with less // functionality, no dependencies on atomic, and fewer supported types to better // suit embedded systems (ie no intrusive ptr) @@ -208,13 +179,6 @@ struct EValue { return payload.copyable_union.as_int; } - Result tryToInt() const { - if (!isInt()) { - return Error::InvalidType; - } - return payload.copyable_union.as_int; - } - /****** Double Type ******/ /*implicit*/ EValue(double d) : tag(Tag::Double) { payload.copyable_union.as_double = d; @@ -229,13 +193,6 @@ struct EValue { return payload.copyable_union.as_double; } - Result tryToDouble() const { - if (!isDouble()) { - return Error::InvalidType; - } - return payload.copyable_union.as_double; - } - /****** Bool Type ******/ /*implicit*/ EValue(bool b) : tag(Tag::Bool) { payload.copyable_union.as_bool = b; @@ -250,13 +207,6 @@ struct EValue { return payload.copyable_union.as_bool; } - Result tryToBool() const { - if (!isBool()) { - return Error::InvalidType; - } - return payload.copyable_union.as_bool; - } - /****** Scalar Type ******/ /// Construct an EValue using the implicit value of a Scalar. /*implicit*/ EValue(executorch::aten::Scalar s) { @@ -292,19 +242,6 @@ struct EValue { } } - Result tryToScalar() const { - if (isDouble()) { - return executorch::aten::Scalar(payload.copyable_union.as_double); - } - if (isInt()) { - return executorch::aten::Scalar(payload.copyable_union.as_int); - } - if (isBool()) { - return executorch::aten::Scalar(payload.copyable_union.as_bool); - } - return Error::InvalidType; - } - /****** Tensor Type ******/ /*implicit*/ EValue(executorch::aten::Tensor t) : tag(Tag::Tensor) { // When built in aten mode, at::Tensor has a non trivial constructor @@ -354,16 +291,6 @@ struct EValue { return payload.as_tensor; } - // Returns a copy of the Tensor handle (one intrusive_ptr refcount bump in - // ATen mode; free in lean mode). Unlike toTensor()'s const& / & overloads, - // tryToTensor() cannot return a reference — Result wraps by value. - Result tryToTensor() const { - if (!isTensor()) { - return Error::InvalidType; - } - return payload.as_tensor; - } - /****** String Type ******/ /*implicit*/ EValue(executorch::aten::ArrayRef* s) : tag(Tag::String) { ET_CHECK_MSG(s != nullptr, "ArrayRef pointer cannot be null"); @@ -384,18 +311,6 @@ struct EValue { payload.copyable_union.as_string_ptr->size()); } - Result tryToString() const { - if (!isString()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_string_ptr == nullptr) { - return Error::InvalidState; - } - return std::string_view( - payload.copyable_union.as_string_ptr->data(), - payload.copyable_union.as_string_ptr->size()); - } - /****** Int List Type ******/ /*implicit*/ EValue(BoxedEvalueList* i) : tag(Tag::ListInt) { ET_CHECK_MSG( @@ -415,16 +330,6 @@ struct EValue { return (payload.copyable_union.as_int_list_ptr)->get(); } - Result> tryToIntList() const { - if (!isIntList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_int_list_ptr == nullptr) { - return Error::InvalidState; - } - return (payload.copyable_union.as_int_list_ptr)->tryGet(); - } - /****** Bool List Type ******/ /*implicit*/ EValue(executorch::aten::ArrayRef* b) : tag(Tag::ListBool) { @@ -444,16 +349,6 @@ struct EValue { return *(payload.copyable_union.as_bool_list_ptr); } - Result> tryToBoolList() const { - if (!isBoolList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_bool_list_ptr == nullptr) { - return Error::InvalidState; - } - return *(payload.copyable_union.as_bool_list_ptr); - } - /****** Double List Type ******/ /*implicit*/ EValue(executorch::aten::ArrayRef* d) : tag(Tag::ListDouble) { @@ -473,16 +368,6 @@ struct EValue { return *(payload.copyable_union.as_double_list_ptr); } - Result> tryToDoubleList() const { - if (!isDoubleList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_double_list_ptr == nullptr) { - return Error::InvalidState; - } - return *(payload.copyable_union.as_double_list_ptr); - } - /****** Tensor List Type ******/ /*implicit*/ EValue(BoxedEvalueList* t) : tag(Tag::ListTensor) { @@ -503,17 +388,6 @@ struct EValue { return payload.copyable_union.as_tensor_list_ptr->get(); } - Result> tryToTensorList() - const { - if (!isTensorList()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_tensor_list_ptr == nullptr) { - return Error::InvalidState; - } - return payload.copyable_union.as_tensor_list_ptr->tryGet(); - } - /****** List Optional Tensor Type ******/ /*implicit*/ EValue( BoxedEvalueList>* t) @@ -538,17 +412,6 @@ struct EValue { return payload.copyable_union.as_list_optional_tensor_ptr->get(); } - Result>> - tryToListOptionalTensor() const { - if (!isListOptionalTensor()) { - return Error::InvalidType; - } - if (payload.copyable_union.as_list_optional_tensor_ptr == nullptr) { - return Error::InvalidState; - } - return payload.copyable_union.as_list_optional_tensor_ptr->tryGet(); - } - /****** ScalarType Type ******/ executorch::aten::ScalarType toScalarType() const { ET_CHECK_MSG(isInt(), "EValue is not a ScalarType."); @@ -556,14 +419,6 @@ struct EValue { payload.copyable_union.as_int); } - Result tryToScalarType() const { - if (!isInt()) { - return Error::InvalidType; - } - return static_cast( - payload.copyable_union.as_int); - } - /****** MemoryFormat Type ******/ executorch::aten::MemoryFormat toMemoryFormat() const { ET_CHECK_MSG(isInt(), "EValue is not a MemoryFormat."); @@ -571,27 +426,12 @@ struct EValue { payload.copyable_union.as_int); } - Result tryToMemoryFormat() const { - if (!isInt()) { - return Error::InvalidType; - } - return static_cast( - payload.copyable_union.as_int); - } - /****** Layout Type ******/ executorch::aten::Layout toLayout() const { ET_CHECK_MSG(isInt(), "EValue is not a Layout."); return static_cast(payload.copyable_union.as_int); } - Result tryToLayout() const { - if (!isInt()) { - return Error::InvalidType; - } - return static_cast(payload.copyable_union.as_int); - } - /****** Device Type ******/ executorch::aten::Device toDevice() const { ET_CHECK_MSG(isInt(), "EValue is not a Device."); @@ -601,16 +441,6 @@ struct EValue { -1); } - Result tryToDevice() const { - if (!isInt()) { - return Error::InvalidType; - } - return executorch::aten::Device( - static_cast( - payload.copyable_union.as_int), - -1); - } - template T to() &&; template @@ -618,15 +448,6 @@ struct EValue { template typename internal::evalue_to_ref_overload_return::type to() &; - /** - * Result-returning equivalent of `to()`. Tag mismatch returns - * `Error::InvalidType`; a null list/string payload returns - * `Error::InvalidState`. Specializations are defined below via - * `EVALUE_DEFINE_TRY_TO`. - */ - template - Result tryTo() const; - /** * Converts the EValue to an optional object that can represent both T and * an uninitialized state. @@ -639,23 +460,6 @@ struct EValue { return this->to(); } - /** - * Result-returning equivalent of `toOptional()`. None maps to an empty - * optional; any other tag that doesn't match T propagates `tryTo()`'s - * error (`Error::InvalidType`). - */ - template - inline Result> tryToOptional() const { - if (this->isNone()) { - return std::optional(std::nullopt); - } - auto r = this->tryTo(); - if (!r.ok()) { - return r.error(); - } - return std::optional(std::move(r.get())); - } - private: // Pre cond: the payload value has had its destructor called void clearToNone() noexcept { @@ -687,11 +491,18 @@ struct EValue { } else if ( isTensorList() && payload.copyable_union.as_tensor_list_ptr != nullptr) { - payload.copyable_union.as_tensor_list_ptr->destroy_elements(); + // for (auto& tensor : toTensorList()) { + for (auto& tensor : payload.copyable_union.as_tensor_list_ptr->get()) { + tensor.~Tensor(); + } } else if ( isListOptionalTensor() && payload.copyable_union.as_list_optional_tensor_ptr != nullptr) { - payload.copyable_union.as_list_optional_tensor_ptr->destroy_elements(); + // for (auto& optional_tensor : toListOptionalTensor()) { + for (auto& optional_tensor : + payload.copyable_union.as_list_optional_tensor_ptr->get()) { + optional_tensor.~optional(); + } } } @@ -773,59 +584,6 @@ EVALUE_DEFINE_TO( toListOptionalTensor) #undef EVALUE_DEFINE_TO -#define EVALUE_DEFINE_TRY_TO(T, method_name) \ - template <> \ - inline Result EValue::tryTo() const { \ - return this->method_name(); \ - } - -EVALUE_DEFINE_TRY_TO(executorch::aten::Scalar, tryToScalar) -EVALUE_DEFINE_TRY_TO(int64_t, tryToInt) -EVALUE_DEFINE_TRY_TO(bool, tryToBool) -EVALUE_DEFINE_TRY_TO(double, tryToDouble) -EVALUE_DEFINE_TRY_TO(std::string_view, tryToString) -EVALUE_DEFINE_TRY_TO(executorch::aten::ScalarType, tryToScalarType) -EVALUE_DEFINE_TRY_TO(executorch::aten::MemoryFormat, tryToMemoryFormat) -EVALUE_DEFINE_TRY_TO(executorch::aten::Layout, tryToLayout) -EVALUE_DEFINE_TRY_TO(executorch::aten::Device, tryToDevice) -// Tensor and Optional Tensor -EVALUE_DEFINE_TRY_TO(executorch::aten::Tensor, tryToTensor) -EVALUE_DEFINE_TRY_TO( - std::optional, - tryToOptional) - -// IntList and Optional IntList -EVALUE_DEFINE_TRY_TO(executorch::aten::ArrayRef, tryToIntList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// DoubleList and Optional DoubleList -EVALUE_DEFINE_TRY_TO(executorch::aten::ArrayRef, tryToDoubleList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// BoolList and Optional BoolList -EVALUE_DEFINE_TRY_TO(executorch::aten::ArrayRef, tryToBoolList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// TensorList and Optional TensorList -EVALUE_DEFINE_TRY_TO( - executorch::aten::ArrayRef, - tryToTensorList) -EVALUE_DEFINE_TRY_TO( - std::optional>, - tryToOptional>) - -// List of Optional Tensor -EVALUE_DEFINE_TRY_TO( - executorch::aten::ArrayRef>, - tryToListOptionalTensor) -#undef EVALUE_DEFINE_TRY_TO - template executorch::aten::ArrayRef BoxedEvalueList::get() const { for (typename executorch::aten::ArrayRef::size_type i = 0; @@ -837,23 +595,6 @@ executorch::aten::ArrayRef BoxedEvalueList::get() const { return executorch::aten::ArrayRef{unwrapped_vals_, wrapped_vals_.size()}; } -template -Result> BoxedEvalueList::tryGet() const { - for (typename executorch::aten::ArrayRef::size_type i = 0; - i < wrapped_vals_.size(); - i++) { - if (wrapped_vals_[i] == nullptr) { - return Error::InvalidState; - } - auto r = wrapped_vals_[i]->template tryTo(); - if (!r.ok()) { - return r.error(); - } - unwrapped_vals_[i] = std::move(r.get()); - } - return executorch::aten::ArrayRef{unwrapped_vals_, wrapped_vals_.size()}; -} - } // namespace runtime } // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/event_tracer.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/event_tracer.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/event_tracer.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/event_tracer.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/event_tracer_hooks.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/event_tracer_hooks.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/event_tracer_hooks.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/event_tracer_hooks.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/event_tracer_hooks_delegate.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/event_tracer_hooks_delegate.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/event_tracer_hooks_delegate.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/event_tracer_hooks_delegate.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/exec_aten.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/exec_aten.h similarity index 84% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/exec_aten.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/exec_aten.h index f539414..8c06045 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/exec_aten.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/exec_aten.h @@ -8,10 +8,7 @@ #pragma once -#include // @manual -#include // @manual #include // @manual -#include // @manual #include #ifdef USE_ATEN_LIB #include // @manual @@ -31,7 +28,6 @@ #include // @manual #include // @manual #include // @manual -#include // @manual #include // @manual #include #else // use executor @@ -114,32 +110,6 @@ inline ssize_t compute_numel(const SizesType* sizes, ssize_t dim) { c10::multiply_integers(c10::ArrayRef(sizes, dim))); } -inline ::executorch::runtime::Result safe_numel( - const SizesType* sizes, - ssize_t dim) { - ET_CHECK_OR_RETURN_ERROR( - dim == 0 || sizes != nullptr, - InvalidArgument, - "Sizes must be provided for non-scalar tensors"); - ssize_t numel = 1; - for (ssize_t i = 0; i < dim; i++) { - ET_CHECK_OR_RETURN_ERROR( - sizes[i] >= 0, - InvalidArgument, - "Size must be non-negative, got %zd at dimension %zd", - static_cast(sizes[i]), - i); - ssize_t next_numel; - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(numel, static_cast(sizes[i]), &next_numel), - InvalidArgument, - "Overflow computing numel at dimension %zd", - i); - numel = next_numel; - } - return numel; -} - #undef ET_PRI_TENSOR_SIZE #define ET_PRI_TENSOR_SIZE PRId64 @@ -188,7 +158,6 @@ using OptionalArrayRef = using OptionalIntArrayRef = OptionalArrayRef; using torch::executor::compute_numel; -using torch::executor::safe_numel; #endif // Use ExecuTorch types diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/targets.bzl new file mode 100644 index 0000000..df4a87e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/targets.bzl @@ -0,0 +1,21 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + # Depend on this target if your types (Tensor, ArrayRef, etc) should be flexible between ATen and executor + runtime.cxx_library( + name = "lib" + aten_suffix, + exported_headers = ["exec_aten.h"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + visibility = ["PUBLIC"], + exported_deps = ["//executorch/runtime/core:tensor_shape_dynamism"] + ([] if aten_mode else ["//executorch/runtime/core/portable_type:portable_type"]), + exported_external_deps = ["libtorch"] if aten_mode else [], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/README.md new file mode 100644 index 0000000..e8d52c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/README.md @@ -0,0 +1,4 @@ +This directory contains code to help tests that use the types defined in +`//executorch/runtime/core/portable_type` and `//executorch/runtime/core/exec_aten`. +This code should be treated as test-only, and should not be compiled into production +targets. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/targets.bzl new file mode 100644 index 0000000..fa259b4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/targets.bzl @@ -0,0 +1,32 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "tensor_util" + (aten_suffix), + srcs = ["tensor_util.cpp"], + exported_headers = [ + "tensor_util.h", + "tensor_factory.h", + ], + visibility = ["PUBLIC"], + compiler_flags = ["-Wno-unneeded-internal-declaration"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + exported_external_deps = [ + "gmock" + aten_suffix, + ] + (["libtorch"] if aten_mode else []), + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_factory.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_factory.h new file mode 100644 index 0000000..562db97 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_factory.h @@ -0,0 +1,1133 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef USE_ATEN_LIB +#include +#else // !USE_ATEN_LIB +#include +#include +#include +#endif // !USE_ATEN_LIB + +namespace executorch { +namespace runtime { +namespace testing { + +namespace internal { + +/** + * Returns the number of elements in the tensor, given the dimension + * sizes, assuming contiguous data. + */ +inline size_t sizes_to_numel(const std::vector& sizes) { + size_t n = 1; + for (auto s : sizes) { + n *= s; + } + return n; +} + +/** + * Check if given strides is legal under given sizes. In the `make` function, + * the `strides` shall ensure: + * - a. strides.size() == sizes.size() + * - b. all strides are positive. + * - c. All underlying data be accessed. + * - d. All legal indexes can access an underlying data. + * - e. No two indexes access a same data. + * - f. No out of bounds data can be accessed. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] strides The desired strides for creating new tensor. + * @return The strides is legal or not + */ + +inline bool check_strides( + const std::vector sizes, + const std::vector strides) { + if (sizes.size() != strides.size()) { + // The length of stride vector shall equal to size vector. + return false; + } + + if (strides.size() == 0) { + // Both sizes and strides are empty vector. Legal! + return true; + } + + // Check if input non-empty strides is legal. The defination of legal is in + // the comment above function. To check it, we first reformat the strides into + // contiguous style, in where the strides should be sorted from high to low. + // Then rearrange the size based on same transformation. After that, we can + // check if strides[i] == strides[i + 1] * sizes[i + 1] for all i in + // [0, sizes.size() - 1) and strides[sizes.size() - 1] == 1 + + // Get the mapping between current strides and sorted strides (from high to + // low, if equal then check if correspond size is 1 or 0 in same dimension) + // e.g. a = tensor(3, 2, 1).permute(2, 1, 0), a.size() == (1, 2, 3) and + // a.strides == (1, 1, 2). We want to sort create a mapping to make the + // sorted_stride as (2, 1, 1) while sorted_size == (3, 2, 1) + std::vector sorted_idx(sizes.size()); + for (const auto i : c10::irange(sizes.size())) { + sorted_idx[i] = i; + } + std::sort( + sorted_idx.begin(), + sorted_idx.end(), + [&](const int32_t& a, const int32_t& b) { + if (strides[a] != strides[b]) { + return strides[a] > strides[b]; + } else { + // When strides equal to each other, put the index whose + // coresponding size equal to 0 or 1 to the right. Update the rule to + // the following comparsion to circumvent strict weak ordering. + return (sizes[a] ? sizes[a] : 1) > (sizes[b] ? sizes[b] : 1); + } + }); + + // Use the mapping to rearrange the sizes and strides + std::vector sorted_sizes(sizes.size()); + std::vector sorted_strides(sizes.size()); + for (const auto i : c10::irange(sizes.size())) { + sorted_sizes[i] = sizes[sorted_idx[i]] == 0 ? 1 : sizes[sorted_idx[i]]; + sorted_strides[i] = strides[sorted_idx[i]]; + } + + // All strides should be positive. We have sorted it mainly based on strides, + // so sorted_strides[-1] has lowest value. + if (sorted_strides[strides.size() - 1] <= 0) { + return false; + } + + // Check if strides is legal + bool legal = sorted_strides[strides.size() - 1] == 1; + for (size_t i = 0; i < strides.size() - 1 && legal; i++) { + legal = legal && + (sorted_strides[i] == sorted_strides[i + 1] * sorted_sizes[i + 1]); + } + + return legal; +} + +/** + * Check that a given dim order array is valid. A dim order array is valid if + * each value from 0 to sizes.size() - 1 appears exactly once in the dim_order + * array. + */ +inline bool check_dim_order( + const std::vector& sizes, + const std::vector& dim_order) { + if (sizes.size() != dim_order.size()) { + return false; + } + size_t gauss_sum = 0; + std::vector count(dim_order.size(), 0); + for (const auto i : c10::irange(dim_order.size())) { + if (dim_order[i] >= sizes.size()) { + return false; + } + gauss_sum += static_cast(dim_order[i]) + 1; + } + // Use the gaussian sum to verify each dim appears exactly once + size_t expected_sum = (sizes.size() * (sizes.size() + 1)) / 2; + if (gauss_sum != expected_sum) { + return false; + } + + return true; +} + +inline std::vector strides_from_dim_order( + const std::vector& sizes, + const std::vector& dim_order) { + bool legal = check_dim_order(sizes, dim_order); + ET_CHECK_MSG(legal, "The input dim_order variable is illegal."); + + size_t ndim = sizes.size(); + std::vector strides(ndim); + strides[dim_order[ndim - 1]] = 1; + for (int i = ndim - 2; i >= 0; --i) { + uint8_t cur_dim = dim_order[i]; + uint8_t next_dim = dim_order[i + 1]; + strides[cur_dim] = (!sizes[next_dim]) ? strides[next_dim] + : strides[next_dim] * sizes[next_dim]; + } + return strides; +} + +inline std::vector channels_last_dim_order(size_t dims) { + ET_CHECK_MSG( + dims >= 4 && dims <= 5, + "Channels last dim order only valid for 4-dim and 5-dim tensors!"); + + std::vector dim_order(dims); + // Channels is always assigned to dim 1 + dim_order[dims - 1] = 1; + + dim_order[0] = 0; + int d = 1; + while (d < dims - 1) { + dim_order[d] = d + 1; + d++; + } + return dim_order; +} + +} // namespace internal + +#ifdef USE_ATEN_LIB + +// Note that this USE_ATEN_LIB section uses ATen-specific namespaces instead of +// exec_aten because we know that we're working with ATen, and many of these +// names aren't mapped into executorch::aten::. + +namespace internal { + +// This wrapper lets us override the C type associated with some ScalarType +// values while using the defaults for everything else. +template +struct ScalarTypeToCppTypeWrapper { + using ctype = typename c10::impl::ScalarTypeToCPPTypeT; +}; + +// Use a C type of `uint8_t` instead of `bool`. The C type will be used to +// declare a `std::vector`, and `std::vector` is often optimized to +// store a single bit per entry instead of using an array of separate `bool` +// elements. Since the tensor data will point into the vector, it needs to use +// one byte per element. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint8_t; +}; + +} // namespace internal + +template +class TensorFactory { + public: + /* + * The C types that backs the associated DTYPE. E.g., `float` for + * `ScalarType::Float`. + */ + + /** + * Used for the vector provided to the factory functions. May differ + * from the type usually associate with the ScalarType. + * + * Used for the vector<> parameters passed to the factory functions. + */ + using ctype = typename internal::ScalarTypeToCppTypeWrapper::ctype; + + /** + * The official C type for the scalar type. Used when accessing elements + * of a constructed Tensor. + */ + using true_ctype = typename c10::impl::ScalarTypeToCPPTypeT; + + TensorFactory() = default; + + /** + * Returns a new Tensor with the specified shape, data and stride. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] strides The strides for each dimensions of the Tensor. If empty + * or not specificed, the function will return a contiguous tensor based + * on data and size. If not, the strides shall follow the rules: + * - a. strides.size() == sizes.size(). + * - b. all strides are positive. + * - c. All underlying data be accessed. + * - d. All legal indexes can access an underlying data. + * - e. No two indexes access a same data. + * - f. No out of bounds data can be accessed. + * + * @return A new Tensor with the specified shape and data. + */ + at::Tensor make( + const std::vector& sizes, + const std::vector& data, + const std::vector strides = {}, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + at::Tensor t; + if (strides.empty()) { + t = zeros(sizes); + } else { + bool legal = internal::check_strides(sizes, strides); + ET_CHECK_MSG(legal, "The input strides variable is illegal."); + + t = empty_strided(sizes, strides); + } + if (t.nbytes() > 0) { + std::transform( + data.begin(), data.end(), t.template data(), [](auto x) { + return static_cast(x); + }); + } + return t; + } + + /** + * Returns a new Tensor with the specified shape, data and dim order. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] dim_order The dim order describing how tensor memory is laid + * out. If empty or not specificed, the function will use a contiguous dim + * order of {0, 1, 2, 3, ...} + * + * @return A new Tensor with the specified shape and data. + */ + at::Tensor make_with_dimorder( + const std::vector& sizes, + const std::vector& data, + const std::vector dim_order = {}, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + at::Tensor t; + if (dim_order.empty()) { + t = zeros(sizes); + } else { + auto strides = internal::strides_from_dim_order(sizes, dim_order); + t = empty_strided(sizes, strides); + } + if (t.nbytes() > 0) { + std::transform( + data.begin(), data.end(), t.template data(), [](auto x) { + return static_cast(x); + }); + } + return t; + } + + /** + * Returns a new Tensor with the specified shape and data in channels last + * memory layout. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * + * @return A new Tensor with the specified shape and data. + */ + at::Tensor make_channels_last( + const std::vector& sizes, + const std::vector& data, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + return make_with_dimorder( + sizes, data, internal::channels_last_dim_order(sizes.size()), dynamism); + } + + /** + * Given data in contiguous memory format, returns a new Tensor with the + * specified shape and the same data but in channels last memory format. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data in contiguous memory format that the Tensor should + * be initialized with. The size of this vector must be equal to the product + * of the elements of `sizes`. + * + * @return A new Tensor with the specified shape and data in channls last + * memory format. + */ + at::Tensor channels_last_like( + const at::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + ET_CHECK_MSG( + input.sizes().size() == 4, "Only 4D tensors can be channels last"); + + const std::vector sizes( + input.sizes().begin(), input.sizes().end()); + + std::vector contiguous_dim_order(sizes.size()); + for (uint8_t i = 0; i < sizes.size(); i++) { + contiguous_dim_order[i] = i; + } + std::vector contiguous_strides = + internal::strides_from_dim_order(sizes, contiguous_dim_order); + + for (const auto i : c10::irange(input.dim())) { + ET_CHECK_MSG( + input.strides()[i] == contiguous_strides[i], + "Input tensor is not contiguous"); + } + + int32_t N = sizes[0]; + int32_t C = sizes[1]; + int32_t H = sizes[2]; + int32_t W = sizes[3]; + + std::vector contiguous_data( + input.data_ptr(), input.data_ptr() + input.numel()); + std::vector channels_last_data( + N * C * H * W); // Create a new blob with the same total size to contain + // channels_last data + for (const auto n : c10::irange(N)) { + for (const auto c : c10::irange(C)) { + for (const auto h : c10::irange(H)) { + for (const auto w : c10::irange(W)) { + // Calculate the index in the original blob + int32_t old_index = ((n * C + c) * H + h) * W + w; + // Calculate the index in the new blob + int32_t new_index = ((n * H + h) * W + w) * C + c; + // Copy the data + channels_last_data[new_index] = contiguous_data[old_index]; + } + } + } + } + + return make_with_dimorder( + sizes, + channels_last_data, + internal::channels_last_dim_order(sizes.size()), + dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous + * data will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor full( + const std::vector& sizes, + ctype value, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::full(at::IntArrayRef(sizes64), value, at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the specified shape, containing channels-last + * contiguous data will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor full_channels_last( + const std::vector& sizes, + ctype value, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::full(at::IntArrayRef(sizes64), value, at::dtype(DTYPE)) + .to(at::MemoryFormat::ChannelsLast); + } + + /** + * Returns a new Tensor with the specified shape, containing channels-last + * contiguous data with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor zeros( + const std::vector& sizes, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::zeros(at::IntArrayRef(sizes64), at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor zeros_channels_last( + const std::vector& sizes, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::zeros(at::IntArrayRef(sizes64), at::dtype(DTYPE)) + .to(at::MemoryFormat::ChannelsLast); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * with all `1` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor ones( + const std::vector& sizes, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::ones(at::IntArrayRef(sizes64), at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `0` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor zeros_like( + const at::Tensor& input, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + std::vector sizes64 = {input.sizes().begin(), input.sizes().end()}; + return at::full(at::IntArrayRef(sizes64), 0, at::dtype(DTYPE)); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `1` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + at::Tensor ones_like( + const at::Tensor& input, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + std::vector sizes64 = {input.sizes().begin(), input.sizes().end()}; + return at::full(at::IntArrayRef(sizes64), 1, at::dtype(DTYPE)); + } + + private: + /// Copies an int32_t vector into a new int64_t vector. + static std::vector vec_32_to_64(const std::vector& in) { + std::vector out{}; + out.reserve(in.size()); + for (auto i : in) { + out.push_back(i); + } + return out; + } + + /** + * Returns a new Tensor with the specified shape and stride. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] strides The strides for each dimensions of the Tensor + * @return A new Tensor with the specified shape and strides. + */ + at::Tensor empty_strided( + const std::vector& sizes, + const std::vector& strides, + ET_UNUSED TensorShapeDynamism dynamism = + TensorShapeDynamism::DYNAMIC_UNBOUND) { + auto sizes64 = vec_32_to_64(sizes); + return at::empty_strided( + sizes64, + strides, + DTYPE, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + } +}; + +#else // !USE_ATEN_LIB + +namespace { +/* + * Dimension order represents how dimensions are laid out in memory, + * starting from the inner-most to the outer-most dimension. + * Thus, the conversion from strides is done by sorting the strides + * from larger to smaller since the dimension with the largest stride + * is the outer-most and the dimension with the smallest stride is the + inner-most. + * For example, tensor with sizes = (3, 5, 2) and strides = (5, 1, 15), implies + * dimension order of (2, 0, 1), because 2nd dimension has the biggest stride of + 15, + * followed by 0th dimension with stride of 5 and then innermost dimension being + the 1st + * dimension with size of 1. This order of (2, 0, 1) can be obtained + * by sorting strides from large to smaller. + + * When strides do not convey dimension order unambiguously, dimension order + * returned is dependent on stability of sort. We employ stable sort to preserve + * original order. Thus when strides = (4, 3, 1, 1) returned value is (0, 1, 2, + 3) + * Another example is: sizes = (1, 3, 1, 1) with strides = (3, 1, 3, 3), + returned + * value is (0, 2, 3, 1) +*/ +// copied from +// https://stackoverflow.com/questions/1577475/c-sorting-and-keeping-track-of-indexes +// TODO: Add assert for strides[i] != 0 because strides of 0 is really used, +// by pytorch/aten, to convey broadcasting dim. + +inline std::vector dim_order_from_stride( + const std::vector& v) { + std::vector indices(v.size()); + std::iota(indices.begin(), indices.end(), 0); + stable_sort(indices.begin(), indices.end(), [&v](size_t i1, size_t i2) { + return v[i1] > v[i2]; + }); + return indices; +} + +inline void validate_strides( + const std::vector& sizes, + const std::vector& strides) { + if (sizes.size() != strides.size()) { + ET_CHECK_MSG(false, "Stride and sizes are not equal in length"); + } + for (const auto& s : strides) { + if (s == 0) { + ET_CHECK_MSG(false, "Stride value of 0 is not supported"); + } + } + // No two dimensions can have same stride value + for (const auto i : c10::irange(strides.size())) { + for (int32_t j = i + 1; j < strides.size(); ++j) { + if ((sizes[i] == 0) || (sizes[j] == 0) || + ((sizes[i] == 1) || (sizes[j] == 1))) { + continue; + } + if ((strides[i] == strides[j])) { + ET_CHECK_MSG( + false, + "Stride value and size dont comply at index %d." + " strides[%d]: %d, strides[%d] = %d, sizes[%d] = %d, sizes[%d] = %d", + static_cast(i), + static_cast(i), + strides[i], + j, + strides[j], + static_cast(i), + sizes[i], + j, + sizes[j]); + } + } + } +} + +} // namespace + +// Note that this !USE_ATEN_LIB section uses ExecuTorch-specific namespaces +// instead of exec_aten to make it clear that we're dealing with ETensor, and +// because many of these names aren't mapped into executorch::aten::. + +namespace internal { + +// This wrapper lets us override the C type associated with some ScalarType +// values while using the defaults for everything else. +template +struct ScalarTypeToCppTypeWrapper { + using ctype = + typename ::executorch::runtime::ScalarTypeToCppType::type; +}; + +// Use a C type of `uint8_t` instead of `bool`. The C type will be used to +// declare a `std::vector`, and `std::vector` is often optimized to +// store a single bit per entry instead of using an array of separate `bool` +// elements. Since the tensor data will point into the vector, it needs to use +// one byte per element. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint8_t; +}; + +// Use a C type of `uint16_t` instead of `Bits16` to simplify code reuse when +// testing multiple integer types. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint16_t; +}; + +// Use a C type of `uint16_t` instead of `UInt16` to simplify code reuse when +// testing multiple integer types. +template <> +struct ScalarTypeToCppTypeWrapper { + using ctype = uint16_t; +}; + +// To allow implicit conversion between simple types to `ctype` +#define SPECIALIZE_ScalarTypeToCppTypeWrapper(CTYPE, DTYPE) \ + template <> \ + struct ScalarTypeToCppTypeWrapper { \ + using ctype = typename CTYPE::underlying; \ + }; + +ET_FORALL_QINT_TYPES(SPECIALIZE_ScalarTypeToCppTypeWrapper) + +#undef SPECIALIZE_ScalarTypeToCppTypeWrapper + +} // namespace internal + +/** + * A helper class for creating Tensors, simplifying memory management. + * + * NOTE: A given TensorFactory instance owns the memory pointed to by all + * Tensors that it creates, and must live longer than those Tensors. + * + * Example: + * @code{.cpp} + * // A factory instance will create Tensors of a single dtype. + * TensorFactory tf; + * + * // You can create more factories if you need tensors of multiple + * // dtypes. + * TensorFactory tf_float; + * + * // The factory will copy the vectors provided to it, letting callers provide + * // inline literals. + * Tensor t1 = tf.make( + * {2, 2}, // sizes + * {1, 2, 3, 4}); // data + * + * // There are helpers for creating Tensors with all 1 or 0 elements. + * Tensor z = tf.zeros({2, 2}); + * Tensor o = tf_float.ones({2, 2}); + * + * // Sometimes it's helpful to share parameters. + * std::vector sizes = {2, 2}; + * Tensor t3 = tf.make(sizes, {1, 2, 3, 4}); + * Tensor t4 = tf.ones(sizes); + * + * // But remember that the inputs are copied, so providing the same data vector + * // to two Tensors will not share the same underlying data. + * std::vector data = {1, 2, 3, 4}; + * Tensor t5 = tf.make(sizes, data); + * Tensor t6 = tf.make(sizes, data); + * t5.mutable_data_ptr()[0] = 99; + * EXPECT_NE(t5, t6); + * @endcode + * + * @tparam DTYPE The dtype of Tensors created by this factory, as a ScalarType + * value like `ScalarType::Int`. + */ +template +class TensorFactory { + public: + /** + * The C type that backs the associated DTYPE. E.g., `float` for + * `ScalarType::Float`. + */ + using ctype = typename internal::ScalarTypeToCppTypeWrapper::ctype; + + /** + * The official C type for the scalar type. Used when accessing elements + * of a constructed Tensor. + */ + using true_ctype = + typename executorch::runtime::ScalarTypeToCppType::type; + + TensorFactory() = default; + + /** + * Returns a new Tensor with the specified shape, data and stride. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] strides The strides for each dimensions of the Tensor. If empty + * or not specificed, the function will return a contiguous tensor based + * on data and size. If not, the strides shall follow the rules: + * - a. strides.size() == sizes.size(). + * - b. all strides are positive. + * - c. All underlying data be accessed. + * - d. All legal indexes can access an underlying data. + * - e. No two indexes access a same data. + * - f. No out of bounds data can be accessed. + * + * @return A new Tensor with the specified shape and data. + */ + torch::executor::Tensor make( + const std::vector& sizes, + const std::vector& data, + const std::vector strides = {}, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector default_strides; + // Generate strides from the tensor dimensions, assuming contiguous data if + // given strides is empty. + if (!sizes.empty() && strides.empty()) { + default_strides.resize(sizes.size(), 1); + for (size_t i = sizes.size() - 1; i > 0; --i) { + // For sizes[i] == 0, treat it as 1 to be consistent with core Pytorch + auto sizes_i = sizes[i] ? sizes[i] : 1; + default_strides[i - 1] = default_strides[i] * sizes_i; + } + } + auto& actual_strides = default_strides.empty() ? strides : default_strides; + validate_strides(sizes, actual_strides); + auto dim_order = dim_order_from_stride(actual_strides); + + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + bool legal = internal::check_strides(sizes, actual_strides); + ET_CHECK_MSG(legal, "The input strides variable is illegal."); + + memory_.emplace_back(std::make_unique( + sizes, data, dim_order, actual_strides, dynamism)); + return torch::executor::Tensor(&memory_.back()->impl_); + } + + /** + * Returns a new Tensor with the specified shape, data and dim order. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * @param[in] dim_order The dim order describing how tensor memory is laid + * out. If empty or not specificed, the function will use a contiguous dim + * order of {0, 1, 2, 3, ...} + * + * @return A new Tensor with the specified shape and data. + */ + torch::executor::Tensor make_with_dimorder( + const std::vector& sizes, + const std::vector& data, + const std::vector dim_order = {}, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector default_dim_order; + // Generate strides from the tensor dimensions, assuming contiguous data if + // given strides is empty. + if (!sizes.empty() && dim_order.empty()) { + default_dim_order.resize(sizes.size(), 1); + for (const auto i : c10::irange(sizes.size())) { + default_dim_order[i] = i; + } + } + auto& actual_dim_order = + default_dim_order.empty() ? dim_order : default_dim_order; + + auto strides = internal::strides_from_dim_order(sizes, actual_dim_order); + + auto expected_numel = internal::sizes_to_numel(sizes); + ET_CHECK_MSG( + expected_numel == data.size(), + "Number of data elements %zd " + "does not match expected number of elements %zd", + data.size(), + expected_numel); + + memory_.emplace_back(std::make_unique( + sizes, data, actual_dim_order, strides, dynamism)); + return torch::executor::Tensor(&memory_.back()->impl_); + } + + /** + * Returns a new Tensor with the specified shape and data in channels last + * memory format. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data that the Tensor should be initialized with. The + * size of this vector must be equal to the product of the elements of + * `sizes`. + * + * @return A new Tensor with the specified shape and data. + */ + torch::executor::Tensor make_channels_last( + const std::vector& sizes, + const std::vector& data, + const std::vector dim_order = {}, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return make_with_dimorder( + sizes, data, internal::channels_last_dim_order(sizes.size()), dynamism); + } + + /** + * Given data in contiguous memory format, returns a new Tensor with the + * specified shape and the same data but in channels last memory format. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] data The data in contiguous memory format that the Tensor should + * be initialized with. The size of this vector must be equal to the product + * of the elements of `sizes`. + * + * @return A new Tensor with the specified shape and data in channls last + * memory format. + */ + torch::executor::Tensor channels_last_like( + const torch::executor::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + const std::vector sizes( + input.sizes().begin(), input.sizes().end()); + + ET_CHECK_MSG(sizes.size() == 4, "Only 4D tensors can be channels last"); + ET_CHECK_MSG( + is_contiguous_dim_order(input.dim_order().data(), input.dim()) == true, + "Input tensor is not contiguous"); + int32_t N = sizes[0]; + int32_t C = sizes[1]; + int32_t H = sizes[2]; + int32_t W = sizes[3]; + + std::vector contiguous_data( + input.data_ptr(), input.data_ptr() + input.numel()); + std::vector channels_last_data( + N * C * H * W); // Create a new blob with the same total size to contain + // channels_last data + for (const auto n : c10::irange(N)) { + for (const auto c : c10::irange(C)) { + for (const auto h : c10::irange(H)) { + for (const auto w : c10::irange(W)) { + // Calculate the index in the original blob + int32_t old_index = ((n * C + c) * H + h) * W + w; + // Calculate the index in the new blob + int32_t new_index = ((n * H + h) * W + w) * C + c; + // Copy the data + channels_last_data[new_index] = contiguous_data[old_index]; + } + } + } + } + + return make_with_dimorder( + sizes, + channels_last_data, + internal::channels_last_dim_order(sizes.size()), + dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor full( + const std::vector& sizes, + ctype value, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector data(internal::sizes_to_numel(sizes), value); + return make(sizes, data, /* empty strides */ {}, dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing channels last + * contiguous data will all elements set to `value`. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @param[in] value The value of all elements of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor full_channels_last( + const std::vector& sizes, + ctype value, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector data(internal::sizes_to_numel(sizes), value); + return make_with_dimorder( + sizes, data, internal::channels_last_dim_order(sizes.size()), dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * in channels last memory format with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor zeros_channels_last( + const std::vector& sizes, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return full_channels_last(sizes, 0, dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * in contiguous memory format with all `0` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor zeros( + const std::vector& sizes, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return full(sizes, 0, dynamism); + } + + /** + * Returns a new Tensor with the specified shape, containing contiguous data + * with all `1` elements. + * + * @param[in] sizes The sizes of the dimensions of the Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor ones( + const std::vector& sizes, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + return full(sizes, 1, dynamism); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `0` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor zeros_like( + const torch::executor::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector sizes = {input.sizes().begin(), input.sizes().end()}; + return full(sizes, 0, dynamism); + } + + /** + * Returns a new Tensor with the same shape as the input tensor, containing + * contiguous data with all `1` elements. + * + * @param[in] input The tensor that supplies the shape of the new Tensor. + * @return A new Tensor with the specified shape. + */ + torch::executor::Tensor ones_like( + const torch::executor::Tensor& input, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) { + std::vector sizes = {input.sizes().begin(), input.sizes().end()}; + return full(sizes, 1, dynamism); + } + + private: + /** + * Owns all backing memory for a single Tensor. + */ + struct TensorMemory { + TensorMemory( + const std::vector& sizes, + const std::vector& data, + const std::vector& dim_order, + const std::vector& strides, + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC) + : sizes_(sizes), + data_(data), + dim_order_(dim_order), + strides_(strides), + impl_( + DTYPE, + /*dim=*/sizes_.size(), + sizes_.data(), + data_.data(), + dim_order_.data(), + strides_.data(), + dynamism) { + // The only valid values for bool are 0 and 1; coerce! + if constexpr (std::is_same_v) { + for (auto& x : data_) { + x = static_cast(x); + } + } + } + + std::vector sizes_; + std::vector data_; + std::vector dim_order_; + std::vector strides_; + torch::executor::TensorImpl impl_; + }; + + /** + * The memory pointed to by Tensors created by this factory. This is a vector + * of pointers so that the TensorMemory objects won't move if the vector needs + * to resize/realloc. + */ + std::vector> memory_; +}; + +#endif // !USE_ATEN_LIB + +/** + * A helper class for creating TensorLists, simplifying memory management. + * + * NOTE: A given TensorListFactory owns the memory pointed to by all TensorLists + * (and Tensors they contain), and must live longer than those TensorLists and + * Tensors. + */ +template +class TensorListFactory final { + public: + TensorListFactory() = default; + ~TensorListFactory() = default; + + /** + * Returns a TensorList containing Tensors with the same shapes as the + * provided Tensors, but filled with zero elements. The dtypes of the template + * entries are ignored. + */ + executorch::aten::TensorList zeros_like( + const std::vector& templates) { + memory_.emplace_back( + std::make_unique>()); + auto& vec = memory_.back(); + std::for_each( + templates.begin(), + templates.end(), + [&](const executorch::aten::Tensor& t) { + vec->push_back(tf_.zeros_like(t)); + }); + return executorch::aten::TensorList(vec->data(), vec->size()); + } + + private: + TensorFactory tf_; + /** + * The memory pointed to by TensorLists created by this factory. This is a + * vector of pointers so that the elements won't move if the vector needs to + * resize/realloc. + */ + std::vector>> memory_; +}; + +} // namespace testing +} // namespace runtime +} // namespace executorch + +namespace torch { +namespace executor { +namespace testing { +// TODO(T197294990): Remove these deprecated aliases once all users have moved +// to the new `::executorch` namespaces. +using ::executorch::runtime::testing::TensorFactory; +using ::executorch::runtime::testing::TensorListFactory; +} // namespace testing +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.cpp new file mode 100644 index 0000000..218a64c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using executorch::aten::BFloat16; +using executorch::aten::Half; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; + +namespace executorch { +namespace runtime { +namespace testing { + +namespace { + +/** + * Returns true if the two elements are close according to the description on + * `tensors_are_close()`. + * + * T must be a floating point type. Non-floating point data should be compared + * directly. + */ +template +bool element_is_close(const T a, const T b, double rtol, double atol) { + if constexpr (c10::is_reduced_floating_point_v) { + // MSVC complains about ambiguous overloads, so explicitly cast to float to + // compare. + return element_is_close( + static_cast(a), static_cast(b), rtol, atol); + } else { + if (std::isnan(a) && std::isnan(b)) { + // NaN == NaN + } else if (!std::isfinite(a) && !std::isfinite(b) && ((a > 0) == (b > 0))) { + // -Inf == -Inf + // +Inf == +Inf + } else if (rtol == 0 && atol == 0) { + // Exact comparison; avoid unnecessary math. + if (a != b) { + return false; + } + } else { + auto allowed_error = atol + std::abs(rtol * b); + auto actual_error = std::abs(a - b); + if (!std::isfinite(actual_error) || actual_error > allowed_error) { + return false; + } + } + + return true; + } +} + +/** + * Returns true if the two arrays are close according to the description on + * `tensors_are_close()`. + * + * T must be a floating point type. Non-floating point data should be compared + * directly. + */ +template +bool data_is_close( + const T* a, + const T* b, + size_t numel, + double rtol, + double atol) { + ET_CHECK_MSG( + numel == 0 || (a != nullptr && b != nullptr), + "Pointers must not be null when numel > 0: numel %zu, a 0x%p, b 0x%p", + numel, + a, + b); + if (a == b) { + return true; + } + for (const auto i : c10::irange(numel)) { + const auto ai = a[i]; + const auto bi = b[i]; + + if (!element_is_close(ai, bi, rtol, atol)) { + return false; + } + } + return true; +} + +double default_atol_for_type(ScalarType t) { + if (t == ScalarType::Half) { + return internal::kDefaultHalfAtol; + } + if (t == ScalarType::BFloat16) { + return internal::kDefaultBFloat16Atol; + } + return internal::kDefaultAtol; +} +} // namespace + +bool tensors_are_close( + const Tensor& a, + const Tensor& b, + double rtol, + std::optional opt_atol) { + if (a.scalar_type() != b.scalar_type() || a.sizes() != b.sizes()) { + return false; + } + + // TODO(T132992348): support comparison between tensors of different strides + ET_CHECK_MSG( + a.strides() == b.strides(), + "The two inputs of `tensors_are_close` function shall have same strides"); + + // Since the two tensors have same shape and strides, any two elements that + // share same index from underlying data perspective will also share same + // index from tensor perspective, whatever the size and strides really are. + // e.g. if a[i_1, i_2, ... i_n] = a.const_data_ptr()[m], we can assert + // b[i_1, i_2, ... i_n] = b.const_data_ptr()[m]) + // So we can just compare the two underlying data sequentially to figure out + // if the two tensors are same. + + double atol = opt_atol.value_or(default_atol_for_type(a.scalar_type())); + + if (a.nbytes() == 0) { + // Note that this case is important. It's valid for a zero-size tensor to + // have a null data pointer, but in some environments it's invalid to pass a + // null pointer to memcmp() even when the size is zero. + return true; + } else if (a.scalar_type() == ScalarType::Float) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::Double) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::Half) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::BFloat16) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else { + // Non-floating-point types can be compared bitwise. + return memcmp(a.const_data_ptr(), b.const_data_ptr(), a.nbytes()) == 0; + } +} + +/** + * Asserts that the provided tensors have the same sequence of close + * underlying data elements and same numel. Note that this function is mainly + * about comparing underlying data between two tensors, not relevant with how + * tensor interpret the underlying data. + */ +bool tensor_data_is_close( + const Tensor& a, + const Tensor& b, + double rtol, + std::optional opt_atol) { + if (a.scalar_type() != b.scalar_type() || a.numel() != b.numel()) { + return false; + } + + double atol = opt_atol.value_or(default_atol_for_type(a.scalar_type())); + if (a.nbytes() == 0) { + // Note that this case is important. It's valid for a zero-size tensor to + // have a null data pointer, but in some environments it's invalid to pass a + // null pointer to memcmp() even when the size is zero. + return true; + } else if (a.scalar_type() == ScalarType::Float) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else if (a.scalar_type() == ScalarType::Double) { + return data_is_close( + a.const_data_ptr(), + b.const_data_ptr(), + a.numel(), + rtol, + atol); + } else { + // Non-floating-point types can be compared bitwise. + return memcmp(a.const_data_ptr(), b.const_data_ptr(), a.nbytes()) == 0; + } +} + +bool tensor_lists_are_close( + const executorch::aten::Tensor* tensors_a, + size_t num_tensors_a, + const executorch::aten::Tensor* tensors_b, + size_t num_tensors_b, + double rtol, + std::optional opt_atol) { + if (num_tensors_a != num_tensors_b) { + return false; + } + for (const auto i : c10::irange(num_tensors_a)) { + if (!tensors_are_close(tensors_a[i], tensors_b[i], rtol, opt_atol)) { + return false; + } + } + return true; +} + +} // namespace testing +} // namespace runtime +} // namespace executorch + +// ATen already defines operator<<() for Tensor and ScalarType. +#ifndef USE_ATEN_LIB + +/* + * These functions must be declared in the original namespaces of their + * associated types so that C++ can find them. + */ +namespace executorch { +namespace runtime { +namespace etensor { + +/** + * Prints the ScalarType to the stream as a human-readable string. + */ +std::ostream& operator<<(std::ostream& os, const ScalarType& t) { + const char* s = torch::executor::toString(t); + if (std::strcmp(s, "UNKNOWN_SCALAR") == 0) { + return os << "Unknown(" << static_cast(t) << ")"; + } else { + return os << s; + } +} + +namespace { + +/** + * Prints the elements of `data` to the stream as comma-separated strings. + */ +template +std::ostream& print_data(std::ostream& os, const T* data, size_t numel) { + // TODO(dbort): Make this smarter: show dimensions, listen to strides, + // break up or truncate data when it's huge + for (const auto i : c10::irange(numel)) { + os << data[i]; + if (i < numel - 1) { + os << ", "; + } + } + return os; +} + +template +std::ostream& +print_data(std::ostream& os, const etensor::complex* data, size_t numel) { + for (const auto i : c10::irange(numel)) { + os << data[i].real_ << " + " << data[i].imag_ << "j"; + if (i < numel - 1) { + os << ", "; + } + } + return os; +} +/** + * Prints the elements of `data` to the stream as comma-separated strings. + * + * Specialization for byte tensors as c++ default prints them as chars where as + * debugging is typically easier with numbers here (tensors dont store string + * data) + */ +template <> +std::ostream& print_data(std::ostream& os, const uint8_t* data, size_t numel) { + // TODO(dbort): Make this smarter: show dimensions, listen to strides, + // break up or truncate data when it's huge + for (const auto i : c10::irange(numel)) { + os << (uint64_t)data[i]; + if (i < numel - 1) { + os << ", "; + } + } + return os; +} + +} // namespace + +/** + * Prints the Tensor to the stream as a human-readable string. + */ +std::ostream& operator<<(std::ostream& os, const Tensor& t) { + os << "ETensor(sizes={"; + for (const auto dim : c10::irange(t.dim())) { + os << t.size(dim); + if (dim < t.dim() - 1) { + os << ", "; + } + } + os << "}, dtype=" << t.scalar_type() << ", data={"; + + // Map from the ScalarType to the C type. +#define PRINT_CASE(ctype, stype) \ + case ScalarType::stype: \ + print_data(os, t.const_data_ptr(), t.numel()); \ + break; + + switch (t.scalar_type()) { + ET_FORALL_REAL_TYPES_AND3(Half, Bool, BFloat16, PRINT_CASE) + ET_FORALL_COMPLEX_TYPES(PRINT_CASE) + default: + ET_CHECK_MSG( + false, + "Unhandled dtype %s", + torch::executor::toString(t.scalar_type())); + } + +#undef PRINT_CASE + + os << "})"; + + return os; +} + +} // namespace etensor +} // namespace runtime +} // namespace executorch + +#endif // !USE_ATEN_LIB diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.h new file mode 100644 index 0000000..4284176 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/tensor_util.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include // For MATCHER_P + +#include + +namespace executorch { +namespace runtime { +namespace testing { + +namespace internal { +constexpr double kDefaultRtol = 1e-5; +constexpr double kDefaultAtol = 1e-8; +// Per +// https://en.wikipedia.org/wiki/Half-precision_floating-point_format, +// float16 has about 3.3 digits of precision. +constexpr double kDefaultHalfAtol = 1e-3; + +// Following similar reasoning to float16, BFloat16 has +// math.log10(2**8) = 2.4 digits of precision. +constexpr double kDefaultBFloat16Atol = 1e-2; +} // namespace internal + +/** + * Returns true if the tensors are of the same shape and dtype, and if all + * elements are close to each other. + * + * TODO(T132992348): This function will currently fail an ET_CHECK if the + * strides of the tensors are not identical. Add support for comparing + * tensors with different strides. + * + * Note that gtest users can write `EXPECT_THAT(tensor1, IsCloseTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsCloseTo(tensor2)))`, or use the helper macros + * `EXPECT_TENSOR_CLOSE()` and `EXPECT_TENSOR_NOT_CLOSE()`. + * + * For exact equality, use `EXPECT_THAT(tensor1, IsEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsEqualTo(tensor2)))`, or the helper macros + * `EXPECT_TENSOR_EQ()` and `EXPECT_TENSOR_NE()`. + * + * An element A is close to B when one is true: + * + * (1) A is equal to B. + * (2) A and B are both NaN, are both -infinity, or are both +infinity. + * (3) The error abs(A - B) is finite and less than the max error + * (atol + abs(rtol * B)). + * + * If both rtol/atol are zero, this function checks for exact equality. + * + * NOTE: rtol/atol are ignored and treated as zero for non-floating-point + * dtypes. + * + * @param[in] a The first tensor to compare. + * @param[in] b The second tensor to compare. + * @param[in] rtol Relative tolerance; see note above. + * @param[in] atol Absolute tolerance; see note above. + * @retval true All corresponding elements of the two tensors are within the + * specified tolerance of each other. + * @retval false One or more corresponding elements of the two tensors are + * outside of the specified tolerance of each other. + */ +bool tensors_are_close( + const executorch::aten::Tensor& a, + const executorch::aten::Tensor& b, + double rtol = internal::kDefaultRtol, + std::optional opt_atol = std::nullopt); + +/** + * Returns true if the tensors are of the same numel and dtype, and if all + * elements are close to each other. The tensor shapes do not need to be same. + * + * Note that gtest users can write `EXPECT_THAT(tensor1, + * IsDataCloseTo(tensor2))` or `EXPECT_THAT(tensor1, + * Not(IsDataCloseTo(tensor2)))`, or use the helper macros + * `EXPECT_TENSOR_DATA_CLOSE()` and `EXPECT_TENSOR_DATA_NOT_CLOSE()`. + * + * For exact equality, use `EXPECT_THAT(tensor1, IsDataEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsDataEqualTo(tensor2)))`, or the helper macros + * `EXPECT_TENSOR_DATA_EQ()` and `EXPECT_TENSOR_DATA_NE()`. + * + * The defination of an element A is close to B is in the comment of the + * function `tensors_are_close` + * + * @param[in] a The first tensor to compare. + * @param[in] b The second tensor to compare. + * @param[in] rtol Relative tolerance; see note above. + * @param[in] atol Absolute tolerance; see note above. + * @retval true All corresponding elements of the two tensors are within the + * specified tolerance of each other. + * @retval false One or more corresponding elements of the two tensors are + * outside of the specified tolerance of each other. + */ +bool tensor_data_is_close( + const executorch::aten::Tensor& a, + const executorch::aten::Tensor& b, + double rtol = internal::kDefaultRtol, + std::optional opt_atol = std::nullopt); + +/** + * Returns true if the two lists are of the same length, and + * tensor_data_is_close(tensors_a[i], tensors_b[i], rtol, atol) is true for all + * i. + */ +bool tensor_lists_are_close( + const executorch::aten::Tensor* tensors_a, + size_t num_tensors_a, + const executorch::aten::Tensor* tensors_b, + size_t num_tensors_b, + double rtol = internal::kDefaultRtol, + std::optional opt_atol = std::nullopt); + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsCloseTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsCloseTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_CLOSE()` and `EXPECT_TENSOR_NOT_CLOSE()`. + */ +MATCHER_P(IsCloseTo, other, "") { + return tensors_are_close(arg, other); +} + +/** + * Lets gtest users write + * `EXPECT_THAT(tensor1, IsCloseToWithTol(tensor2, rtol, atol))` + * or `EXPECT_THAT(tensor1, Not(IsCloseToWithTol(tensor2, rtol, atol)))`. + * + * See also `EXPECT_TENSOR_CLOSE_WITH_TOL()` and + * `EXPECT_TENSOR_NOT_CLOSE_WITH_TOL()`. + */ +MATCHER_P3(IsCloseToWithTol, other, rtol, atol, "") { + return tensors_are_close(arg, other, rtol, atol); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsEqualTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_EQ()` and `EXPECT_TENSOR_NE()`. + */ +MATCHER_P(IsEqualTo, other, "") { + return tensors_are_close(arg, other, /*rtol=*/0, /*atol=*/0); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsDataCloseTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsDataCloseTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_DATA_CLOSE()` and `EXPECT_TENSOR_DATA_NOT_CLOSE()`. + */ +MATCHER_P(IsDataCloseTo, other, "") { + return tensor_data_is_close(arg, other); +} + +/** + * Lets gtest users write + * `EXPECT_THAT(tensor1, IsDataCloseToWithTol(tensor2, rtol, atol))` + * or `EXPECT_THAT(tensor1, Not(IsDataCloseToWithTol(tensor2, rtol, atol)))`. + * + * See also `EXPECT_TENSOR_CLOSE_WITH_TOL()` and + * `EXPECT_TENSOR_NOT_CLOSE_WITH_TOL()`. + */ +MATCHER_P3(IsDataCloseToWithTol, other, rtol, atol, "") { + return tensor_data_is_close(arg, other, rtol, atol); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor1, IsDataEqualTo(tensor2))` or + * `EXPECT_THAT(tensor1, Not(IsDataEqualTo(tensor2)))`. + * + * See also `EXPECT_TENSOR_DATA_EQ()` and `EXPECT_TENSOR_DATA_NE()`. + */ +MATCHER_P(IsDataEqualTo, other, "") { + return tensor_data_is_close(arg, other, /*rtol=*/0, /*atol=*/0); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor_list1, + * IsListCloseTo(tensor_list2))` or `EXPECT_THAT(tensor_list1, + * Not(IsListCloseTo(tensor_list2)))`. + * + * The lists can be any container of Tensor that supports ::data() and ::size(). + * + * See also `EXPECT_TENSOR_LISTS_CLOSE()` and `EXPECT_TENSOR_LISTS_NOT_CLOSE()`. + */ +MATCHER_P(IsListCloseTo, other, "") { + return tensor_lists_are_close( + arg.data(), arg.size(), other.data(), other.size()); +} + +/** + * Lets gtest users write `EXPECT_THAT(tensor_list1, + * IsListEqualTo(tensor_list2))` or `EXPECT_THAT(tensor_list1, + * Not(IsListEqualTo(tensor_list2)))`. + * + * The lists can be any container of Tensor that supports ::data() and ::size(). + * + * See also `EXPECT_TENSOR_LISTS_EQ()` and `EXPECT_TENSOR_LISTS_NE()`. + */ +MATCHER_P(IsListEqualTo, other, "") { + return tensor_lists_are_close( + arg.data(), + arg.size(), + other.data(), + other.size(), + /*rtol=*/0, + /*atol=*/0); +} + +/* + * NOTE: Although it would be nice to make `EXPECT_EQ(t1, t2)` and friends work, + * that would require implementing `bool operator==(Tensor, Tensor)`. + * + * at::Tensor implements `Tensor operator==(Tensor, Tensor)`, returning an + * element-by-element comparison. This causes an ambiguous conflict with the + * `bool`-returning operator. + */ +#define EXPECT_TENSOR_EQ(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsEqualTo(t2)) +#define EXPECT_TENSOR_NE(t1, t2) \ + EXPECT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsEqualTo(t2))) +#define ASSERT_TENSOR_EQ(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsEqualTo(t2)) +#define ASSERT_TENSOR_NE(t1, t2) \ + ASSERT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsEqualTo(t2))) + +#define EXPECT_TENSOR_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsCloseTo(t2)) +#define EXPECT_TENSOR_NOT_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsCloseTo(t2))) +#define ASSERT_TENSOR_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsCloseTo(t2)) +#define ASSERT_TENSOR_NOT_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::testing::Not(executorch::runtime::testing::IsCloseTo(t2))) + +#define EXPECT_TENSOR_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), ::executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol)) +#define EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol))) +#define ASSERT_TENSOR_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), ::executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol)) +#define ASSERT_TENSOR_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsCloseToWithTol(t2, rtol, atol))) + +#define EXPECT_TENSOR_DATA_EQ(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsDataEqualTo(t2)) +#define EXPECT_TENSOR_DATA_NE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataEqualTo(t2))) +#define ASSERT_TENSOR_DATA_EQ(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsDataEqualTo(t2)) +#define ASSERT_TENSOR_DATA_NE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataEqualTo(t2))) + +#define EXPECT_TENSOR_DATA_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsDataCloseTo(t2)) +#define EXPECT_TENSOR_DATA_NOT_CLOSE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataCloseTo(t2))) +#define ASSERT_TENSOR_DATA_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsDataCloseTo(t2)) +#define ASSERT_TENSOR_DATA_NOT_CLOSE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsDataCloseTo(t2))) + +#define EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), \ + ::executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol)) +#define EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + EXPECT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol))) +#define ASSERT_TENSOR_DATA_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), \ + ::executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol)) +#define ASSERT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(t1, t2, rtol, atol) \ + ASSERT_THAT( \ + (t1), \ + ::testing::Not( \ + executorch::runtime::testing::IsDataCloseToWithTol(t2, rtol, atol))) + +/* + * Helpers for comparing lists of Tensors. + */ + +#define EXPECT_TENSOR_LISTS_EQ(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsListEqualTo(t2)) +#define EXPECT_TENSOR_LISTS_NE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListEqualTo(t2))) +#define ASSERT_TENSOR_LISTS_EQ(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsListEqualTo(t2)) +#define ASSERT_TENSOR_LISTS_NE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListEqualTo(t2))) + +#define EXPECT_TENSOR_LISTS_CLOSE(t1, t2) \ + EXPECT_THAT((t1), ::executorch::runtime::testing::IsListCloseTo(t2)) +#define EXPECT_TENSOR_LISTS_NOT_CLOSE(t1, t2) \ + EXPECT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListCloseTo(t2))) +#define ASSERT_TENSOR_LISTS_CLOSE(t1, t2) \ + ASSERT_THAT((t1), ::executorch::runtime::testing::IsListCloseTo(t2)) +#define ASSERT_TENSOR_LISTS_NOT_CLOSE(t1, t2) \ + ASSERT_THAT( \ + (t1), ::testing::Not(executorch::runtime::testing::IsListCloseTo(t2))) + +} // namespace testing +} // namespace runtime +} // namespace executorch + +// ATen already defines operator<<() for Tensor and ScalarType. +#ifndef USE_ATEN_LIB + +/* + * These functions must be declared in the original namespaces of their + * associated types so that C++ can find them. + */ +namespace executorch { +namespace runtime { +namespace etensor { + +/** + * Prints the ScalarType to the stream as a human-readable string. + * + * See also executorch::runtime::toString(ScalarType t) in ScalarTypeUtil.h. + */ +std::ostream& operator<<(std::ostream& os, const ScalarType& t); + +/** + * Prints the Tensor to the stream as a human-readable string. + */ +std::ostream& operator<<(std::ostream& os, const Tensor& t); + +} // namespace etensor +} // namespace runtime +} // namespace executorch + +#endif // !USE_ATEN_LIB + +namespace torch { +namespace executor { +namespace testing { +// TODO(T197294990): Remove these deprecated aliases once all users have moved +// to the new `::executorch` namespaces. +using ::executorch::runtime::testing::IsCloseTo; +using ::executorch::runtime::testing::IsCloseToWithTol; +using ::executorch::runtime::testing::IsDataCloseTo; +using ::executorch::runtime::testing::IsDataCloseToWithTol; +using ::executorch::runtime::testing::IsDataEqualTo; +using ::executorch::runtime::testing::IsEqualTo; +using ::executorch::runtime::testing::IsListCloseTo; +using ::executorch::runtime::testing::IsListEqualTo; +using ::executorch::runtime::testing::tensor_data_is_close; +using ::executorch::runtime::testing::tensor_lists_are_close; +using ::executorch::runtime::testing::tensors_are_close; +} // namespace testing +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/CMakeLists.txt new file mode 100644 index 0000000..a51717f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs tensor_util_test.cpp tensor_factory_test.cpp) + +et_cxx_test( + runtime_core_exec_aten_testing_util_test SOURCES ${_test_srcs} EXTRA_LIBS +) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/targets.bzl new file mode 100644 index 0000000..4479699 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/targets.bzl @@ -0,0 +1,30 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "tensor_util_test", + srcs = ["tensor_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [] + + runtime.cxx_test( + name = "tensor_factory_test" + aten_suffix, + srcs = ["tensor_factory_test.cpp"], + preprocessor_flags = preprocessor_flags, + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util" + aten_suffix, + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp new file mode 100644 index 0000000..ab201a0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_factory_test.cpp @@ -0,0 +1,1229 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef USE_ATEN_LIB +#include +#endif // USE_ATEN_LIB + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::StridesType; +using executorch::aten::Tensor; +using executorch::aten::TensorList; +using executorch::ET_RUNTIME_NAMESPACE::resize_tensor; +using executorch::runtime::Error; +using executorch::runtime::TensorShapeDynamism; +using executorch::runtime::testing::TensorFactory; +using executorch::runtime::testing::TensorListFactory; + +// The tensor under test will be modified so pass an rvalue ref +void resize_tensor_to_assert_static(Tensor&& t) { + ASSERT_GT(t.numel(), 1) + << "Need to resize to an 1x1 tensor, so the input size should be > 1"; + // Resizing to an 1x1 tensor doesn't work means it is static +#ifdef USE_ATEN_LIB + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); +#else + EXPECT_NE(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); +#endif +} + +// The tensor under test will be modified so pass an rvalue ref +void resize_tensor_to_assert_dynamic_bound(Tensor&& t) { + ASSERT_GT(t.numel(), 1) + << "Need to resize to an 1x1 tensor, so the input size should be > 1"; + ASSERT_LT(t.numel(), 100 * 100) + << "Need to resize to an 100x100 tensor, so the input size should be < 10000"; +#ifdef USE_ATEN_LIB + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); + EXPECT_EQ(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#else + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); + EXPECT_NE(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#endif +} + +// The tensor under test will be modified so pass an rvalue ref +void resize_tensor_to_assert_dynamic_unbound(Tensor&& t) { + ASSERT_GT(t.numel(), 1) + << "Need to resize to an 1x1 tensor, so the input size should be > 1"; + ASSERT_LT(t.numel(), 100 * 100) + << "Need to resize to an 100x100 tensor, so the input size should be < 10000"; + EXPECT_EQ(resize_tensor(t, ArrayRef({1, 1})), Error::Ok); + +#ifdef USE_ATEN_LIB + EXPECT_EQ(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#else + // TODO(T175194371): For now, we can't resize past the original capacity. + EXPECT_NE(resize_tensor(t, ArrayRef({100, 100})), Error::Ok); +#endif +} + +#ifndef USE_ATEN_LIB +using executorch::aten::DimOrderType; +using torch::executor::TensorImpl; +#endif // !USE_ATEN_LIB + +#define CHECK_ARRAY_REF_EQUAL(a1, a2) \ + ET_CHECK_MSG( \ + a1.size() == a2.size(), \ + "Arrays are not equal size." #a1 " size:%zu," #a2 " size:%zu", \ + a1.size(), \ + a2.size()); \ + for (const auto i : c10::irange(a1.size())) { \ + ET_CHECK_MSG( \ + a1[i] == a2[i], \ + "Value mismatch at index %zu, " #a1 \ + "[%zu] = %hd" \ + ", " #a2 "[%zu] = %hd", \ + i, \ + i, \ + a1[i], \ + i, \ + a2[i]); \ + } + +// +// Tests for TensorFactory +// + +class TensorFactoryTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorFactoryTest, MakeIntTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {1, 2, 3, 4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test Float as a proxy for non-Int dtypes. Don't test as thoroughly as Int, +// which we use for the bulk of the test coverage. +TEST_F(TensorFactoryTest, MakeFloatTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 3.3, 4.4}); + + // A Tensor created manually, that should be identical to `actual`. + float data[] = {1.1, 2.2, 3.3, 4.4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Float)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Float, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Also test Bool, which is a bit of a special case because the factory uses +// `uint8_t` instead of `bool` as the underlying C type. +TEST_F(TensorFactoryTest, MakeBoolTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = + tf.make(/*sizes=*/{2, 2}, /*data=*/{true, false, true, false}); + + // A Tensor created manually, that should be identical to `actual`. + bool data[] = {true, false, true, false}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Bool)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Bool, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, DataIsCopied) { + TensorFactory tf; + + // Create two tensors using the same input data vector. + std::vector data = {1, 2, 3, 4}; + Tensor t1 = tf.make(/*sizes=*/{2, 2}, data); + Tensor t2 = tf.make(/*sizes=*/{2, 2}, data); + + // Demonstrate that they start out identical. + EXPECT_TENSOR_EQ(t1, t2); + + // Modify data in one of them. + t1.mutable_data_ptr()[0] = 99; + + // If they shared the same underlying data, they would still be identical, + // but since they use copies they should now be different. + EXPECT_TENSOR_NE(t1, t2); +} + +TEST_F(TensorFactoryTest, DefaultStridesAreContiguous) { + TensorFactory tf; + + // Create a Tensor with prime number dimensions to more clearly show how the + // strides will be constructed. 30 is 2 * 3 * 5. + Tensor t1 = + tf.make(/*sizes=*/{2, 3, 5}, /*data=*/std::vector(30, 99)); + + // Get the strides into a vector for easy comparison. + std::vector actual_strides(t1.strides().begin(), t1.strides().end()); + + // TensorFactory should have generated a strides list for contiguous data. + // sizes: {D, H, W} + // strides: {H*W, W, 1} + // expected: {3*5, 5, 1} + std::vector expected_strides = {15, 5, 1}; + + EXPECT_EQ(expected_strides, actual_strides); +} + +TEST_F(TensorFactoryTest, StridesForEmptyTensor) { + TensorFactory tf; + + // Create a Tensor with some dim = 0 to clearly demonstrate how the tf.make + // handle empty tensors. + Tensor t1 = + tf.make(/*sizes=*/{2, 0, 3, 0, 5}, /*data=*/std::vector()); + + // Get the strides into a vector for easy comparison. + std::vector actual_strides(t1.strides().begin(), t1.strides().end()); + + // When calculating stride for empty data, TensorFactory should take dim whose + // length equals to zero as equals to one. So the t1's stride should be same + // as tensor(size=(2, 1, 3, 1, 5)) + // expected: {5*1*3*1, 5*1*3, 5*1, 5, 1} -> {15, 15, 5, 5, 1} + std::vector expected_strides = {15, 15, 5, 5, 1}; + + EXPECT_EQ(expected_strides, actual_strides); +} + +TEST_F(TensorFactoryTest, StridesForZeroDimTensor) { + TensorFactory tf; + + // Create a Tensor with zero dimension to clearly demonstrate how the tf.make + // handle zero dim tensors. + Tensor t1 = tf.make( + /*sizes=*/{}, + /*data=*/{1}); + + // Get the strides into a vector for easy comparison. + std::vector actual_strides(t1.strides().begin(), t1.strides().end()); + + // Zero dimension tensor should have zero dimension stride + // expected: {} + std::vector expected_strides = {}; + + EXPECT_EQ(expected_strides, actual_strides); +} + +TEST_F(TensorFactoryTest, NotEnoughDataDies) { + TensorFactory tf; + + // Provide three data elements when the tensor needs four. + ET_EXPECT_DEATH(tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3}), ""); +} + +TEST_F(TensorFactoryTest, TooMuchDataDies) { + TensorFactory tf; + + // Provide five data elements when the tensor needs four. + ET_EXPECT_DEATH(tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4, 5}), ""); +} + +// +// Tests for TensorFactory::make() +// + +// Test if factory can produce strided incontiguous int tensors. +TEST_F(TensorFactoryTest, MakeStridedIntTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{1, 2, 3, 4}, + /*strides=*/{1, 2} /*incontiguous tensor*/); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {1, 2, 3, 4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + std::vector strides = {1, 2}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Int, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {1, 0}; + int32_t strides[dim] = {1, 2}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test if factory can produce strided incontiguous float tensors. +TEST_F(TensorFactoryTest, MakeStridedFloatTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{1.1, 2.2, 3.3, 4.4}, + /*strides=*/{1, 2} /*incontiguous tensor*/); + + // A Tensor created manually, that should be identical to `actual`. + float data[] = {1.1, 2.2, 3.3, 4.4}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + std::vector strides = {1, 2}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Float, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {1, 0}; + int32_t strides[dim] = {1, 2}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Float, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test if factory can produce incontiguous strided bool tensors. +TEST_F(TensorFactoryTest, MakeStridedBoolTensor) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.make( + /*sizes=*/{2, 2}, + /*data=*/{true, false, true, false}, + /*strides=*/{1, 2} /*incontiguous tensor*/); + + // A Tensor created manually, that should be identical to `actual`. + bool data[] = {true, false, true, false}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + std::vector strides = {1, 2}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Bool, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {1, 0}; + int32_t strides[dim] = {1, 2}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Bool, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Test if factory can test the legitimacy of given `strides`, when `strides` +// contains multiple zeros and ones. +TEST_F(TensorFactoryTest, MakeStridedSameStrideTensorSupported) { + TensorFactory tf; + + // A Tensor created by the factory. + // actual = tensor(size=(2, 0 ,3, 0, 0, 0, 1, 5, 0, 1, 2)).permute(0, 6, 8, 2, + // 7, 10, 9, 3, 5, 4, 1) + Tensor actual = tf.make( + /*sizes=*/{2, 1, 0, 3, 5, 2, 1, 0, 0, 0, 0}, + /*data=*/{}, + /*strides=*/ + {30, 10, 2, 10, 2, 1, 2, 10, 10, 10, 30} /*incontiguous tensor*/); + +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 1, 0, 3, 5, 2, 1, 0, 0, 0, 0}; + std::vector strides = {30, 10, 2, 10, 2, 1, 2, 10, 10, 10, 30}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Bool, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); +#else // !USE_ATEN_LIB + constexpr size_t dim = 11; + int32_t sizes[dim] = {2, 1, 0, 3, 5, 2, 1, 0, 0, 0, 0}; + uint8_t dim_order[dim] = {0, 10, 1, 3, 7, 8, 9, 2, 4, 6, 5}; + int32_t strides[dim] = { + 30, 10, 2, 10, 2, 1, 2, 10, 10, 10, 30}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Bool, dim, sizes, {}, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, MakeStridedDataIsCopied) { + TensorFactory tf; + + // Create two tensors using the same input data and strided vector. + std::vector data = {1, 2, 3, 4}; + std::vector strides = {1, 2}; + Tensor t1 = tf.make(/*sizes=*/{2, 2}, data, strides); + Tensor t2 = tf.make(/*sizes=*/{2, 2}, data, strides); + + // Demonstrate that they start out identical. + EXPECT_TENSOR_EQ(t1, t2); + + // Modify data in one of them. + t1.mutable_data_ptr()[0] = 99; + + // If they shared the same underlying data, they would still be identical, + // but since they use copies they should now be different. + EXPECT_TENSOR_NE(t1, t2); +} + +TEST_F(TensorFactoryTest, MakeStridedEmptyDataSupported) { + TensorFactory tf; + + Tensor actual = tf.make( + /*sizes=*/{2, 0, 3, 0, 5}, /*data=*/{}, /*strides=*/{15, 15, 5, 5, 1}); +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 0, 3, 0, 5}; + std::vector strides = {15, 15, 5, 5, 1}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Int, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); +#else // !USE_ATEN_LIB + constexpr size_t dim = 5; + int32_t sizes[dim] = {2, 0, 3, 0, 5}; + uint8_t dim_order[dim] = {0, 1, 2, 3, 4}; + int32_t strides[dim] = {15, 15, 5, 5, 1}; // Incontiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, /*data=*/{}, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, MakeStridedZeroDimSupported) { + TensorFactory tf; + + // Provide three data elements when the tensor needs four. + Tensor actual = tf.make(/*sizes=*/{}, /*data=*/{1}, /*strides=*/{}); + int32_t data[] = {1}; + +#ifdef USE_ATEN_LIB + std::vector sizes = {}; + std::vector strides = {}; + Tensor expected = at::empty_strided( + sizes, + strides, + ScalarType::Int, + /*layout_opt=*/at::Layout::Strided, + /*device_opt=*/at::Device(at::DeviceType::CPU), + /*pin_memory_opt=*/false); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 0; + int32_t sizes[dim] = {}; + uint8_t dim_order[dim] = {}; + int32_t strides[dim] = {}; + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, MakeStridedNotEnoughDataDie) { + TensorFactory tf; + + // Provide three data elements when the tensor needs four. + ET_EXPECT_DEATH( + tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3}, /*strides=*/{1, 2}), ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooMuchDataDie) { + TensorFactory tf; + + // Provide five data elements when the tensor needs four. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4, 5}, /*strides=*/{1, 2}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedNotEnoughStrideDie) { + TensorFactory tf; + + // Provide one stride when the tensor needs two. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, + /*data=*/{1, 2, 3, 4}, + /*strides=*/{1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooMuchStrideDie) { + TensorFactory tf; + + // Provide three strides when the tensor needs two. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{1, 2, 1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooLargeStrideDie) { + TensorFactory tf; + + // Stride is too large. e.g. [0, 1] is the 4th element of data, which jump out + // the bounds [0, 3] + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{1, 4}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedTooSmalleStrideDie) { + TensorFactory tf; + + // Stride is too small (only 0th element can be accessed). + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{1, 1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedNonPositiveStrideDie) { + TensorFactory tf; + + // Stride shall be positive. + ET_EXPECT_DEATH( + tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}, /*strides=*/{2, -1}), + ""); +} + +TEST_F(TensorFactoryTest, MakeStridedWrongStrideForEmptyDataDie) { + TensorFactory tf; + + // When calculating strides based on sizes, we need to treat the size of + // dimension equals to zero as one. + ET_EXPECT_DEATH( + tf.make(/*sizes=*/{0, 2, 2}, /*data=*/{}, /*strides=*/{0, 2, 1}), ""); +} + +TEST_F(TensorFactoryTest, MakeStridedWrongStrideForZeroDimDataDie) { + TensorFactory tf; + + // Stride should be empty + ET_EXPECT_DEATH(tf.make(/*sizes=*/{}, /*data=*/{1}, /*strides=*/{0}), ""); +} + +TEST_F(TensorFactoryTest, Full) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.full(/*sizes=*/{2, 2}, 5); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {5, 5, 5, 5}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +// Use Float as a proxy for demonstrating that full/zeros/ones works for non-Int +// dtypes. +TEST_F(TensorFactoryTest, FullFloat) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.full(/*sizes=*/{2, 2}, 5.5); + + // A Tensor created manually, that should be identical to `actual`. + float data[] = {5.5f, 5.5f, 5.5f, 5.5f}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Float)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Float, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, Zeros) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.zeros(/*sizes=*/{2, 2}); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {0, 0, 0, 0}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, Ones) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor actual = tf.ones(/*sizes=*/{2, 2}); + + // A Tensor created manually, that should be identical to `actual`. + int32_t data[] = {1, 1, 1, 1}; +#ifdef USE_ATEN_LIB + std::vector sizes = {2, 2}; + Tensor expected = + at::zeros(at::IntArrayRef(sizes), at::dtype(ScalarType::Int)); + memcpy(expected.mutable_data_ptr(), data, sizeof(data)); +#else // !USE_ATEN_LIB + constexpr size_t dim = 2; + int32_t sizes[dim] = {2, 2}; + uint8_t dim_order[dim] = {0, 1}; + int32_t strides[dim] = {2, 1}; // Contiguous + TensorImpl impl = + TensorImpl(ScalarType::Int, dim, sizes, data, dim_order, strides); + Tensor expected(&impl); +#endif // !USE_ATEN_LIB + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, ZeroDimensionalTensor) { + TensorFactory tf; + + // Demonstrate that we can create a zero-dimensional tensor in various ways. + { + Tensor t = tf.make({}, {7}); + EXPECT_EQ(t.dim(), 0); + EXPECT_EQ(t.nbytes(), sizeof(int32_t)); + EXPECT_EQ(t.numel(), 1); + EXPECT_EQ(t.const_data_ptr()[0], 7); + } + { + Tensor t = tf.zeros({}); + EXPECT_EQ(t.dim(), 0); + EXPECT_EQ(t.nbytes(), sizeof(int32_t)); + EXPECT_EQ(t.numel(), 1); + EXPECT_EQ(t.const_data_ptr()[0], 0); + } + { + Tensor t = tf.ones({}); + EXPECT_EQ(t.dim(), 0); + EXPECT_EQ(t.nbytes(), sizeof(int32_t)); + EXPECT_EQ(t.numel(), 1); + EXPECT_EQ(t.const_data_ptr()[0], 1); + } +} + +TEST_F(TensorFactoryTest, EmptyTensor) { + TensorFactory tf; + + // Demonstrate that we can create a completely empty tensor by providing + // a zero-width dimension. + { + Tensor t = tf.make({0}, {}); + EXPECT_EQ(t.dim(), 1); + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + } + { + Tensor t = tf.zeros({0}); + EXPECT_EQ(t.dim(), 1); + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + } + { + Tensor t = tf.ones({0}); + EXPECT_EQ(t.dim(), 1); + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + } +} + +void run_zeros_like_test(Tensor input) { + // Demonstrate that we can create a new tensor filled by 0 with same size as + // the given tensor input. + TensorFactory tf; + std::vector input_sizes_64 = { + input.sizes().begin(), input.sizes().end()}; + Tensor actual = tf.zeros_like(input); + + // A Tensor created manually, that should be identical to `actual`. + std::vector expected_data; + for (const auto i : c10::irange(input.numel())) { + expected_data.push_back(0); + } +#ifdef USE_ATEN_LIB + Tensor expected = + at::zeros(at::IntArrayRef(input_sizes_64), at::dtype(ScalarType::Int)); + if (input.numel()) { + // memcpy shouldn't be done if input tensor is empty tensor. Memcpy doesn't + // allow copy null ptr, even if size is 0. + memcpy( + expected.mutable_data_ptr(), + expected_data.data(), + sizeof(int32_t) * input.numel()); + } +#else // !USE_ATEN_LIB + TensorImpl impl = TensorImpl( + ScalarType::Int, + input.dim(), + // static shape tensor so const_cast is fine. + /*sizes=*/const_cast(input.sizes().data()), + /*data=*/expected_data.data(), + /*dim_order=*/const_cast(input.dim_order().data()), + /*strides=*/const_cast(input.strides().data())); + Tensor expected(&impl); +#endif + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, ZerosLike) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{3, 2, 1}, /*data=*/{1, 2, 3, 4, 5, 6}); + run_zeros_like_test(input); +} + +TEST_F(TensorFactoryTest, ZerosLikeZeroDimensionalTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{}, /*data=*/{1}); + run_zeros_like_test(input); +} + +TEST_F(TensorFactoryTest, ZerosLikeEmptyTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{0}, /*data=*/{}); + run_zeros_like_test(input); +} + +void run_ones_like_test(Tensor input) { + // Demonstrate that we can create a new tensor filled by 1 with same size as + // the given tensor input. + TensorFactory tf; + std::vector input_sizes_64 = { + input.sizes().begin(), input.sizes().end()}; + Tensor actual = tf.ones_like(input); + + // A Tensor created manually, that should be identical to `actual`. + std::vector expected_data; + for (const auto i : c10::irange(input.numel())) { + expected_data.push_back(1); + } +#ifdef USE_ATEN_LIB + Tensor expected = + at::zeros(at::IntArrayRef(input_sizes_64), at::dtype(ScalarType::Int)); + if (input.numel()) { + // memcpy shouldn't be done if input tensor is empty tensor. Memcpy doesn't + // allow copy null ptr, even if size is 0. + memcpy( + expected.mutable_data_ptr(), + expected_data.data(), + sizeof(int32_t) * input.numel()); + } +#else // !USE_ATEN_LIB + TensorImpl impl = TensorImpl( + ScalarType::Int, + input.dim(), + // static shape tensor so const_cast is fine. + /*sizes=*/const_cast(input.sizes().data()), + /*data=*/expected_data.data(), + /*dim_order=*/const_cast(input.dim_order().data()), + /*strides=*/const_cast(input.strides().data())); + Tensor expected(&impl); +#endif + + // Ensure that both tensors are identical. + EXPECT_TENSOR_EQ(expected, actual); +} + +TEST_F(TensorFactoryTest, OnesLike) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{3, 2, 1}, /*data=*/{1, 2, 3, 4, 5, 6}); + run_ones_like_test(input); +} + +TEST_F(TensorFactoryTest, OnesLikeZeroDimensionalTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{}, /*data=*/{2}); + run_ones_like_test(input); +} + +TEST_F(TensorFactoryTest, OnesLikeEmptyTensorSupported) { + TensorFactory tf; + Tensor input = tf.make(/*size=*/{0}, /*data=*/{}); + run_ones_like_test(input); +} + +// +// Tests for TensorListFactory +// + +TEST(TensorListFactoryTest, ZerosLike) { + TensorFactory tf; + TensorListFactory tlf; + + // Some templates with different shapes and non-zero element values. + std::vector templates = { + tf.make(/*sizes=*/{1}, /*data=*/{1}), + tf.make(/*sizes=*/{1, 2}, /*data=*/{2, 3}), + tf.make(/*sizes=*/{2, 2, 2}, /*data=*/{4, 5, 6, 7, 8, 9, 10, 11}), + }; + + TensorList actual = tlf.zeros_like(templates); + + // Should have the same shapes as the templates, but all elements should be + // zero. + std::vector expected = { + tf.zeros(/*sizes=*/{1}), + tf.zeros(/*sizes=*/{1, 2}), + tf.zeros(/*sizes=*/{2, 2, 2}), + }; + + EXPECT_TENSOR_LISTS_EQ(actual, expected); +} + +TEST(TensorListFactoryTest, ZerosLikeMixedDtypes) { + TensorFactory tf_byte; + TensorFactory tf_short; + TensorFactory tf_float; + + TensorFactory tf_int; + TensorListFactory tlf; + + // Some templates with different shapes and non-zero element values, and + // different dtypes than the TensorListFactory. Demonstrates that the template + // dtypes don't matter, only the shapes. + std::vector templates = { + tf_byte.make(/*sizes=*/{1}, /*data=*/{1}), + tf_short.make(/*sizes=*/{1, 2}, /*data=*/{2, 3}), + tf_float.make(/*sizes=*/{2, 2, 2}, /*data=*/{4, 5, 6, 7, 8, 9, 10, 11}), + }; + + TensorList actual = tlf.zeros_like(templates); + + // Should have the same shapes as the templates, but all elements should be + // zero, and the dtypes should all be Int. + std::vector expected = { + tf_int.zeros(/*sizes=*/{1}), + tf_int.zeros(/*sizes=*/{1, 2}), + tf_int.zeros(/*sizes=*/{2, 2, 2}), + }; + + EXPECT_TENSOR_LISTS_EQ(actual, expected); +} + +TEST(TensorListFactoryTest, ZerosLikeEmpty) { + TensorListFactory tlf; + + // Empty templates list. + std::vector templates = {}; + + TensorList actual = tlf.zeros_like(templates); + + // Should produce an empty TensorList. + std::vector expected = {}; + + EXPECT_TENSOR_LISTS_EQ(actual, expected); +} + +TEST_F(TensorFactoryTest, ZerosDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static(tf.zeros({2, 2}, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.zeros({2, 2}, TensorShapeDynamism::STATIC), + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.zeros({2, 2}, TensorShapeDynamism::STATIC), + tf.zeros({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, ZerosLikeDynamismParameter) { + TensorFactory tf; + Tensor zeros = tf.zeros({2, 2}); + resize_tensor_to_assert_static( + tf.zeros_like(zeros, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.zeros_like(zeros, TensorShapeDynamism::STATIC), + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.zeros_like(zeros, TensorShapeDynamism::STATIC), + tf.zeros_like(zeros, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, OnesDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static(tf.ones({2, 2}, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.ones({2, 2}, TensorShapeDynamism::STATIC), + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.ones({2, 2}, TensorShapeDynamism::STATIC), + tf.ones({2, 2}, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, OnesLikeDynamismParameter) { + TensorFactory tf; + Tensor ones = tf.ones({2, 2}); + resize_tensor_to_assert_static( + tf.ones_like(ones, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.ones_like(ones, TensorShapeDynamism::STATIC), + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.ones_like(ones, TensorShapeDynamism::STATIC), + tf.ones_like(ones, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, FullDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static( + tf.full({2, 2}, 1, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.full({2, 2}, 1, TensorShapeDynamism::STATIC), + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.full({2, 2}, 1, TensorShapeDynamism::STATIC), + tf.full({2, 2}, 1, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +TEST_F(TensorFactoryTest, MakeDynamismParameter) { + TensorFactory tf; + resize_tensor_to_assert_static( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::STATIC)); + resize_tensor_to_assert_dynamic_bound( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_BOUND)); + resize_tensor_to_assert_dynamic_unbound( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_UNBOUND)); + + // The tensor itself should be equal + EXPECT_TENSOR_EQ( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::STATIC), + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_BOUND)); + EXPECT_TENSOR_EQ( + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::STATIC), + tf.make({2, 2}, {1, 2, 3, 4}, {}, TensorShapeDynamism::DYNAMIC_UNBOUND)); +} + +#if !defined(USE_ATEN_LIB) +TEST_F(TensorFactoryTest, FullDynamic) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor out = tf.full(/*sizes=*/{2, 2}, 5); + int32_t new_sizes[2] = {1, 1}; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + out = tf.full( + /*sizes=*/{2, 2}, 5, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); +} + +TEST_F(TensorFactoryTest, MakeIntTensorDynamic) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor out = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 3, 4}); + + int32_t new_sizes[2] = {1, 1}; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + std::vector data = {1, 2, 3, 4}; + out = tf.make( + /*sizes=*/{2, 2}, data, {}, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); +} + +TEST_F(TensorFactoryTest, MakeZerosDynamic) { + TensorFactory tf; + + // A Tensor created by the factory. + Tensor out = tf.zeros(/*sizes=*/{2, 2}); + + int32_t new_sizes[2] = {1, 1}; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + out = tf.zeros( + /*sizes=*/{2, 2}, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); + + Tensor out_like = tf.zeros_like(out); + new_sizes[0] = 1; + new_sizes[1] = 1; + ET_EXPECT_DEATH(torch::executor::resize(out_like, new_sizes), ""); + + out = tf.zeros_like(out, TensorShapeDynamism::DYNAMIC_BOUND); + new_sizes[1] = 2; + EXPECT_EQ( + torch::executor::resize_tensor(out, new_sizes), + torch::executor::Error::Ok); + new_sizes[0] = 3; + new_sizes[1] = 3; + ET_EXPECT_DEATH(torch::executor::resize(out, new_sizes), ""); +} + +TEST_F(TensorFactoryTest, DimOrderToStrideTest) { + TensorFactory tf; + // A Tensor created by the factory. + Tensor out = tf.zeros(/*sizes=*/{2, 2}); + std::vector dim_order; + + dim_order.resize(2); + dim_order[0] = 0; + dim_order[1] = 1; + executorch::aten::ArrayRef dim_order_ref( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, out.dim_order()); + + out = tf.zeros(/*sizes=*/{1, 2, 5}); + dim_order.resize(out.sizes().size()); + dim_order[0] = 0; + dim_order[1] = 1; + dim_order[2] = 2; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, out.dim_order()); + + std::vector::ctype> data(10); + Tensor strided_out = tf.make({1, 2, 5}, data, {10, 1, 2}); + dim_order.resize(out.sizes().size()); + dim_order[0] = 0; + dim_order[1] = 2; + dim_order[2] = 1; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); + + data.resize(12); + strided_out = tf.make({3, 2, 2}, data, {1, 6, 3}); + dim_order.resize(out.sizes().size()); + dim_order[0] = 1; + dim_order[1] = 2; + dim_order[2] = 0; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); +} + +TEST_F(TensorFactoryTest, AmbgiuousDimOrderToStrideTest) { + TensorFactory tf; + std::vector::ctype> data(10); + Tensor strided_out = tf.make({1, 2, 5}, data, {1, 1, 2}); + std::vector dim_order(strided_out.sizes().size()); + dim_order[0] = 2; + dim_order[1] = 0; + dim_order[2] = 1; + // Note that above strides of {1, 1, 2} can also be + // interpreter as dim_order = {2, 1, 0}, however when converting + // strides to dim order we preseve dimension order, + // using stable_sort when converting strides to dim_order, + // see dim_order_from_stride in TensorFactorh.h, + // and hence valid dim_order = {2, 0, 1} + // Since strides can give ambiguous dimension order when crossing + // boundary from strides land to dim order land, we have to resolve + // such ambiguity in a deterministic way. + // In dim order land, it is less ambiguous + auto dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); + + strided_out = tf.make({1, 2, 5}, data, {1, 1, 2}); + dim_order.resize(strided_out.sizes().size()); + dim_order[0] = 2; + dim_order[1] = 0; + dim_order[2] = 1; + dim_order_ref = executorch::aten::ArrayRef( + dim_order.data(), dim_order.size()); + + CHECK_ARRAY_REF_EQUAL(dim_order_ref, strided_out.dim_order()); +} +#endif // !USE_ATEN_LIB diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp new file mode 100644 index 0000000..b8069e2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp @@ -0,0 +1,848 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::aten::TensorImpl; +using executorch::aten::TensorList; +using executorch::runtime::testing::IsCloseTo; +using executorch::runtime::testing::IsDataCloseTo; +using executorch::runtime::testing::IsDataEqualTo; +using executorch::runtime::testing::IsEqualTo; +using executorch::runtime::testing::IsListCloseTo; +using executorch::runtime::testing::IsListEqualTo; +using executorch::runtime::testing::tensor_data_is_close; +using executorch::runtime::testing::tensor_lists_are_close; +using executorch::runtime::testing::TensorFactory; +using executorch::runtime::testing::tensors_are_close; + +// Exhaustively test all of our comparison functions every time. Also flip the +// params around to demonstrate that the underlying checks are commutative. + +#define EXPECT_TENSORS_CLOSE_AND_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensors_are_close((t1__), (t2__))); \ + EXPECT_TRUE(tensors_are_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsCloseTo((t1__))); \ + EXPECT_TENSOR_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), IsEqualTo(t2__)); \ + EXPECT_THAT((t2__), IsEqualTo(t1__)); \ + EXPECT_TENSOR_EQ((t1__), (t2__)); \ + EXPECT_TENSOR_EQ((t2__), (t1__)); \ + ASSERT_TENSOR_EQ((t1__), (t2__)); \ + ASSERT_TENSOR_EQ((t2__), (t1__)) + +#define EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensors_are_close((t1__), (t2__))); \ + EXPECT_TRUE(tensors_are_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsCloseTo((t1__))); \ + EXPECT_TENSOR_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsEqualTo(t1__))); \ + EXPECT_TENSOR_NE((t1__), (t2__)); \ + EXPECT_TENSOR_NE((t2__), (t1__)); \ + ASSERT_TENSOR_NE((t1__), (t2__)); \ + ASSERT_TENSOR_NE((t2__), (t1__)) + +#define EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(t1__, t2__) \ + EXPECT_FALSE(tensors_are_close((t1__), (t2__))); \ + EXPECT_FALSE(tensors_are_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), Not(IsCloseTo((t2__)))); \ + EXPECT_THAT((t2__), Not(IsCloseTo((t1__)))); \ + EXPECT_TENSOR_NOT_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_NOT_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_NOT_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_NOT_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsEqualTo(t1__))); \ + EXPECT_TENSOR_NE((t1__), (t2__)); \ + EXPECT_TENSOR_NE((t2__), (t1__)); \ + ASSERT_TENSOR_NE((t1__), (t2__)); \ + ASSERT_TENSOR_NE((t2__), (t1__)) + +#define EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensor_data_is_close((t1__), (t2__))); \ + EXPECT_TRUE(tensor_data_is_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsDataCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsDataCloseTo((t1__))); \ + EXPECT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), IsDataEqualTo(t2__)); \ + EXPECT_THAT((t2__), IsDataEqualTo(t1__)); \ + EXPECT_TENSOR_DATA_EQ((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_EQ((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_EQ((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_EQ((t2__), (t1__)) + +#define EXPECT_TENSORS_DATA_CLOSE_BUT_NOT_EQUAL(t1__, t2__) \ + EXPECT_TRUE(tensor_data_is_close((t1__), (t2__))); \ + EXPECT_TRUE(tensor_data_is_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), IsDataCloseTo((t2__))); \ + EXPECT_THAT((t2__), IsDataCloseTo((t1__))); \ + EXPECT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsDataEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsDataEqualTo(t1__))); \ + EXPECT_TENSOR_DATA_NE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_NE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_NE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_NE((t2__), (t1__)) + +#define EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1__, t2__) \ + EXPECT_FALSE(tensor_data_is_close((t1__), (t2__))); \ + EXPECT_FALSE(tensor_data_is_close((t2__), (t1__))); \ + EXPECT_THAT((t1__), Not(IsDataCloseTo((t2__)))); \ + EXPECT_THAT((t2__), Not(IsDataCloseTo((t1__)))); \ + EXPECT_TENSOR_DATA_NOT_CLOSE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_NOT_CLOSE((t2__), (t1__)); \ + ASSERT_TENSOR_NOT_CLOSE((t1__), (t2__)); \ + ASSERT_TENSOR_NOT_CLOSE((t2__), (t1__)); \ + EXPECT_THAT((t1__), Not(IsDataEqualTo(t2__))); \ + EXPECT_THAT((t2__), Not(IsDataEqualTo(t1__))); \ + EXPECT_TENSOR_DATA_NE((t1__), (t2__)); \ + EXPECT_TENSOR_DATA_NE((t2__), (t1__)); \ + ASSERT_TENSOR_DATA_NE((t1__), (t2__)); \ + ASSERT_TENSOR_DATA_NE((t2__), (t1__)) + +#define EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1__, list2__) \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list1__).data(), \ + (list1__).size(), \ + (list2__).data(), \ + (list2__).size())); \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list2__).data(), \ + (list2__).size(), \ + (list1__).data(), \ + (list1__).size())); \ + EXPECT_THAT((list1__), IsListCloseTo((list2__))); \ + EXPECT_THAT((list2__), IsListCloseTo((list1__))); \ + EXPECT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + EXPECT_THAT((list1__), IsListEqualTo(list2__)); \ + EXPECT_THAT((list2__), IsListEqualTo(list1__)); \ + EXPECT_TENSOR_LISTS_EQ((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_EQ((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_EQ((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_EQ((list2__), (list1__)) + +#define EXPECT_TENSOR_LISTS_CLOSE_BUT_NOT_EQUAL(list1__, list2__) \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list1__).data(), \ + (list1__).size(), \ + (list2__).data(), \ + (list2__).size())); \ + EXPECT_TRUE(tensor_lists_are_close( \ + (list2__).data(), \ + (list2__).size(), \ + (list1__).data(), \ + (list1__).size())); \ + EXPECT_THAT((list1__), IsListCloseTo((list2__))); \ + EXPECT_THAT((list2__), IsListCloseTo((list1__))); \ + EXPECT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_CLOSE((list2__), (list1__)); \ + EXPECT_THAT((list1__), Not(IsListEqualTo(list2__))); \ + EXPECT_THAT((list2__), Not(IsListEqualTo(list1__))); \ + EXPECT_TENSOR_LISTS_NE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_NE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_NE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_NE((list2__), (list1__)) + +#define EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1__, list2__) \ + EXPECT_FALSE(tensor_lists_are_close( \ + (list1__).data(), \ + (list1__).size(), \ + (list2__).data(), \ + (list2__).size())); \ + EXPECT_FALSE(tensor_lists_are_close( \ + (list2__).data(), \ + (list2__).size(), \ + (list1__).data(), \ + (list1__).size())); \ + EXPECT_THAT((list1__), Not(IsListCloseTo((list2__)))); \ + EXPECT_THAT((list2__), Not(IsListCloseTo((list1__)))); \ + EXPECT_TENSOR_LISTS_NOT_CLOSE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_NOT_CLOSE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_NOT_CLOSE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_NOT_CLOSE((list2__), (list1__)); \ + EXPECT_THAT((list1__), Not(IsListEqualTo(list2__))); \ + EXPECT_THAT((list2__), Not(IsListEqualTo(list1__))); \ + EXPECT_TENSOR_LISTS_NE((list1__), (list2__)); \ + EXPECT_TENSOR_LISTS_NE((list2__), (list1__)); \ + ASSERT_TENSOR_LISTS_NE((list1__), (list2__)); \ + ASSERT_TENSOR_LISTS_NE((list2__), (list1__)) + +namespace { +// calculate numel given size +int32_t size_to_numel(std::vector sizes) { + int32_t numel = 1; + for (auto size : sizes) { + numel *= size; + } + return numel; +} + +} // namespace + +// Mismatched shapes/types/strides. + +TEST(TensorUtilTest, DifferentDtypesAreNotCloseOrEqual) { + // Create two tensors with identical shape and data, but different dtypes. + TensorFactory tf_int; + Tensor a = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + TensorFactory tf_long; + Tensor b = tf_long.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, DifferentSizesAreNotCloseOrEqual) { + TensorFactory tf; + + // Create two tensors with identical dtype and data, but different shapes. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + Tensor b = tf.make(/*sizes=*/{4}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, DifferentLayoutsDies) { + TensorFactory tf; + + // Create two tensors with identical dtype, data and shapes, but different + // strides. + Tensor a = tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}, /*strided=*/{1, 2}); + Tensor b = tf.make( + /*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}, /*strided=*/{2, 1}); + + // Current `tensors_are_close` does not support comparing two tensors with + // different stride. + // TODO(T132992348): support comparison between tensors of different strides + ET_EXPECT_DEATH(EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b), ""); + ET_EXPECT_DEATH(EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b), ""); +} + +// Int tensors, as a proxy for all non-floating-point types. + +TEST(TensorUtilTest, IntTensorIsCloseAndEqualToItself) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(t, t); +} + +TEST(TensorUtilTest, IdenticalIntTensorsAreCloseAndEqual) { + TensorFactory tf; + + // Create two tensors with identical shape, dtype, and data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +TEST(TensorUtilTest, NonIdenticalIntTensorsAreNotCloseOrEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but different data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{99, 2, 4, 8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, EmptyTensorsAreCloseAndEqual) { + TensorFactory tf; + + // Create two tensors with identical shapes but no data. + Tensor a = tf.make(/*sizes=*/{0, 2}, /*data=*/{}); + EXPECT_EQ(a.numel(), 0); + EXPECT_EQ(a.nbytes(), 0); + Tensor b = tf.make(/*sizes=*/{0, 2}, /*data=*/{}); + EXPECT_EQ(b.numel(), 0); + EXPECT_EQ(b.nbytes(), 0); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +// Float tensors, as a proxy for all floating-point types. + +TEST(TensorUtilTest, FloatTensorIsCloseAndEqualToItself) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(t, t); +} + +TEST(TensorUtilTest, IdenticalFloatTensorsAreCloseAndEqual) { + TensorFactory tf; + + // Create two tensors with identical shape, dtype, and data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +TEST(TensorUtilTest, NearlyIdenticalFloatTensorsAreCloseButNotEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but slightly different + // data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make( + /*sizes=*/{2, 2}, + {// First data element is slightly larger. + std::nextafter(1.1f, 100.0f), + // Remaining data elements are the same. + 2.2, + 4.4, + 8.8}); + + EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(a, b); +} + +TEST(TensorUtilTest, NonIdenticalFloatTensorsAreNotCloseOrEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but different data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{99.99, 2.2, 4.4, 8.8}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, FloatNanElementsAreCloseAndEqual) { + TensorFactory tf; + + // Two identical tensors with NaN elements. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +TEST(TensorUtilTest, FloatNanElementsAreNotEqualToNonNan) { + TensorFactory tf; + + // Regression test ensuring that NaN elements are not compared equal to + // non-NaN finite values. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN}); + Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 0.0, 2.2, 0.0}); + + EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b); +} + +TEST(TensorUtilTest, FloatInfiniteElementsAreCloseAndEqual) { + constexpr auto kInfinity = std::numeric_limits::infinity(); + + TensorFactory tf; + + // Two identical tensors with infinite elements. + Tensor a = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, 1.1, 2.2, kInfinity}); + Tensor b = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, 1.1, 2.2, kInfinity}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +// Double: less test coverage since Float covers all of the branches, but +// demonstrate that it works. + +TEST(TensorUtilTest, NearlyIdenticalDoubleTensorsAreCloseButNotEqual) { + TensorFactory tf; + + // Create two tensors with identical shape and dtype, but slightly different + // data. + Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + Tensor b = tf.make( + /*sizes=*/{2, 2}, + {// First data element is slightly larger. + std::nextafter(1.1f, 100.0f), + // Remaining data elements are the same. + 2.2, + 4.4, + 8.8}); + + EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(a, b); +} + +TEST(TensorUtilTest, DoubleAndInfinitNanElementsAreCloseAndEqual) { + constexpr auto kInfinity = std::numeric_limits::infinity(); + + TensorFactory tf; + + // Two identical tensors with NaN and infinite elements. + Tensor a = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, NAN, 1.1, kInfinity}); + Tensor b = + tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, NAN, 1.1, kInfinity}); + + EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b); +} + +// Testing closeness with tolerances + +TEST(TensorUtilTest, TensorsAreCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.099999, 0.0, -0.05}); + Tensor bf = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.099999, 2.0, 0.05, 0.0}); + + EXPECT_TENSOR_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.199, NAN, -9.0}); + Tensor bd = td.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.0, NAN, -10.0}); + + EXPECT_TENSOR_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +TEST(TensorUtilTest, TensorsAreNotCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{3}, /*data=*/{1.00, NAN, -10.0}); + Tensor bf = tf.make(/*sizes=*/{3}, /*data=*/{1.11, NAN, -10.0}); + + EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{3}, /*data=*/{1.0, 0.0, -10.0}); + Tensor bd = td.make(/*sizes=*/{3}, /*data=*/{1.0, 0.0, -9.0}); + + EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); + + // Create two tensors with identical shape and dtype, but different data. + ad = tf.make(/*sizes=*/{3}, /*data=*/{1.0, 2.0, 0.00001}); + bd = tf.make(/*sizes=*/{3}, /*data=*/{1.0, 2.0, 0.0}); + + EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +// +// Tests for shape-agnostic data equality. +// + +// Common testing for EXPECT_TENSOR_DATA_EQ in different input sizes and +// dtypes. +template +void test_data_equal( + std::vector t1_sizes, + std::vector t2_sizes) { + TensorFactory tf; + + // get corresponding ctype for input DTYPEs + using ctype = typename TensorFactory::ctype; + + // Get the size of data of t1 and t2. + // Make sure the two sizes are equal. + auto numel = size_to_numel(t1_sizes); + ASSERT_EQ(numel, size_to_numel(t2_sizes)); + + // Set up data vector for t1 and t2. + // Set them as a same random vector to test them generally. + std::vector t1_data(numel); + std::generate(t1_data.begin(), t1_data.end(), std::rand); + std::vector t2_data(numel); + t2_data = t1_data; + + Tensor t1 = tf.make(t1_sizes, t1_data); + Tensor t2 = tf.make(t2_sizes, t2_data); + + EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1, t2); +} + +TEST(TensorUtilTest, TensorDataEqualSizeEqual) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 4, 5}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, TensorDataEqualSizeUnequal) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 5, 4}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, EmptyTensorsSupported) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 0, 5}, {3, 4, 0, 5}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, ZeroDimTensorsSupported) { +#define TEST_ENTRY(ctype, dtype) test_data_equal({}, {}); + ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY); +#undef TEST_ENTRY +} + +// Common testing for EXPECT_TENSOR_DATA_CLOSE in different input sizes and +// dtypes. +template < + ScalarType DTYPE, + std::enable_if_t< + DTYPE == ScalarType::Float || DTYPE == ScalarType::Double, + bool> = true> +void test_data_close_but_not_equal( + std::vector t1_sizes, + std::vector t2_sizes) { + TensorFactory tf; + + // get corresponding ctype for input DTYPEs + using ctype = typename TensorFactory::ctype; + + // get the size of data of t1 and t2 + // make sure the two sizes are equal + auto numel = size_to_numel(t1_sizes); + ASSERT_EQ(numel, size_to_numel(t2_sizes)); + + // set up data vector for t1 and t2 + // set them as a almost same random vector (only the first element are + // different if the first element exists) to test them generally + std::vector t1_data(numel); + std::generate(t1_data.begin(), t1_data.end(), std::rand); + std::vector t2_data(numel); + t2_data = t1_data; + + // Set the first element of t2 slightly larger than 0 + // the "first element" only work if t2_numel > 0 + // The checking with ctype.max() is to prevent overflow + if (numel > 0) { + if (t2_data[0] < std::numeric_limits::max() - 100) { + t2_data[0] = std::nextafter(t2_data[0], t2_data[0] + 100.0f); + } else { + t2_data[0] = std::nextafter(t2_data[0], t2_data[0] - 100.f); + } + } + + Tensor t1 = tf.make(t1_sizes, t1_data); + Tensor t2 = tf.make(t2_sizes, t2_data); + + EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1, t2); +} + +TEST(TensorUtilTest, TensorDataCloseNotEqualSizeEqual) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 4, 5}); + ET_FORALL_FLOAT_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +TEST(TensorUtilTest, TensorDataCloseNotEqualSizeUnequal) { +#define TEST_ENTRY(ctype, dtype) \ + test_data_equal({3, 4, 5}, {3, 5, 4}); + ET_FORALL_FLOAT_TYPES(TEST_ENTRY); +#undef TEST_ENTRY +} + +// Common testing for EXPECT_TENSOR_DATA_EQ in different input sizes and +// dtypes. +template +void test_data_equal_but_size_or_dtype_mismatch( + std::vector t1_sizes, + std::vector t2_sizes) { + TensorFactory tf_t1; + TensorFactory tf_t2; + + Tensor t1 = tf_t1.zeros(t1_sizes); + Tensor t2 = tf_t2.zeros(t2_sizes); + + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t2); +} + +TEST(TensorUtilTest, TensorDataTypeMismatched) { + std::vector sizes = {3, 4, 5, 6}; + test_data_equal_but_size_or_dtype_mismatch< + ScalarType::Float, + ScalarType::Double>(sizes, sizes); + test_data_equal_but_size_or_dtype_mismatch< + ScalarType::Int, + ScalarType::Double>(sizes, sizes); +} + +TEST(TensorUtilTest, TensorSizeMismatched) { + std::vector sizes_t1 = {3, 4, 5, 6}; + std::vector sizes_t2 = {3, 4, 5, 7}; + test_data_equal_but_size_or_dtype_mismatch< + ScalarType::Float, + ScalarType::Float>(sizes_t1, sizes_t2); +} + +TEST(TensorUtilTest, TensorDataMismatched) { + TensorFactory tf; + Tensor t1 = tf.make(/*size=*/{3, 2}, /*data=*/{1, 2, 3, 4, 5, 6}); + Tensor t2 = tf.make(/*size=*/{3, 2}, /*data=*/{1, 2, 3, 1, 5, 6}); + Tensor t3 = tf.make(/*size=*/{2, 3}, /*data=*/{1, 2, 3, 1, 5, 6}); + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t2); + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t3); + + Tensor t_zero_dim = tf.make(/*size=*/{}, /*data=*/{0}); + Tensor t_empty = tf.make(/*size=*/{0}, /*data=*/{}); + EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t_zero_dim, t_empty); +} + +// Testing data closeness with tolerances + +TEST(TensorUtilTest, TensorDataCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{4, 1}, /*data=*/{1.0, 2.099, 0.0, -0.05}); + Tensor bf = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.0, 0.05, 0.0}); + + EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.199, NAN, -9.0}); + Tensor bd = td.make(/*sizes=*/{4}, /*data=*/{1.0, 2.0, NAN, -10.0}); + + EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +TEST(TensorUtilTest, TensorDataNotCloseWithTol) { + TensorFactory tf; + TensorFactory td; + + // Create two tensors with identical shape and dtype, but different data. + Tensor af = tf.make(/*sizes=*/{3}, /*data=*/{1.00, 0.0, -10.0}); + Tensor bf = tf.make(/*sizes=*/{3, 1}, /*data=*/{1.11, 0.0, -10.0}); + + EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(af, bf, 0.0, 0.1); + + // Create two tensors with identical shape and dtype, but different data. + Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 0.0, -10.0, 0.0}); + Tensor bd = td.make(/*sizes=*/{4}, /*data=*/{1.0, 0.0, -9.0, 0.0}); + + EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); + + // Create two tensors with identical shape and dtype, but different data. + ad = tf.make(/*sizes=*/{1, 4}, /*data=*/{1.0, 2.0, NAN, 0.00001}); + bd = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.0, NAN, 0.0}); + + EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0); +} + +// +// Tests for TensorList helpers. +// + +TEST(TensorUtilTest, TensorListsCloseAndEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + // Two lists of tensors that should be close and equal. Elements have + // different shapes and dtypes. + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list2(vec2.data(), vec2.size()); + + // Show that we can compare a mix of vectors and TensorLists. + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, list2); + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(vec1, list2); + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, vec2); + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(vec1, vec2); +} + +TEST(TensorUtilTest, EmptyTensorListsAreCloseAndEqual) { + // Two empty lists. + TensorList list1; + EXPECT_EQ(list1.size(), 0); + TensorList list2; + EXPECT_EQ(list2.size(), 0); + + EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, list2); +} + +TEST(TensorUtilTest, TensorListsCloseButNotEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + // Two lists of tensors that should be close and equal. Elements have + // different shapes and dtypes. + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list2(vec2.data(), vec2.size()); + + // Tweak a float value slightly. + vec1[1].mutable_data_ptr()[0] = std::nextafter(1.0f, 100.0f); + + // Show that we can compare a mix of vectors and TensorLists. + EXPECT_TENSOR_LISTS_CLOSE_BUT_NOT_EQUAL(list1, list2); +} + +TEST(TensorUtilTest, TensorListsWithDifferentDataAreNotCloseOrEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.zeros(/*sizes=*/{2, 1}), // vs. ones() in the first list. + }; + TensorList list2(vec2.data(), vec2.size()); + + EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1, list2); +} + +TEST(TensorUtilTest, TensorListsWithDifferentLengthsAreNotCloseOrEqual) { + TensorFactory tf_int; + TensorFactory tf_float; + + std::vector vec1 = { + tf_int.zeros(/*sizes=*/{1, 2}), + tf_float.ones(/*sizes=*/{2, 1}), + }; + TensorList list1(vec1.data(), vec1.size()); + + std::vector vec2 = { + tf_int.zeros(/*sizes=*/{1, 2}), + // Missing second element. + }; + TensorList list2(vec2.data(), vec2.size()); + + EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1, list2); +} + +// We don't need to test the ATen operator<<() implementations since they're +// tested elsewhere. +#ifndef USE_ATEN_LIB + +// Printing/formatting helpers. + +TEST(TensorUtilTest, ScalarTypeStreamSmokeTest) { + // Don't test everything, since operator<<(ScalarType) is just a wrapper + // around a separately-tested function. Just demonstrate that the stream + // wrapper works, and gives us a little more information for unknown types. + { + std::stringstream out; + out << ScalarType::Byte; + EXPECT_STREQ(out.str().c_str(), "Byte"); + } + { + std::stringstream out; + out << static_cast(127); + EXPECT_STREQ(out.str().c_str(), "Unknown(127)"); + } +} + +TEST(TensorUtilTest, TensorStreamInt) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}); + + std::stringstream out; + out << t; + EXPECT_STREQ( + out.str().c_str(), "ETensor(sizes={2, 2}, dtype=Int, data={1, 2, 4, 8})"); +} + +TEST(TensorUtilTest, TensorStreamDouble) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8}); + + std::stringstream out; + out << t; + EXPECT_STREQ( + out.str().c_str(), + "ETensor(sizes={2, 2}, dtype=Double, data={1.1, 2.2, 4.4, 8.8})"); +} + +TEST(TensorUtilTest, TensorStreamBool) { + TensorFactory tf; + + Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{true, false, true, false}); + + std::stringstream out; + out << t; + EXPECT_STREQ( + out.str().c_str(), + "ETensor(sizes={2, 2}, dtype=Bool, data={1, 0, 1, 0})"); +} + +TEST(TensorTest, TestZeroShapeTensorEquality) { + TensorImpl::SizesType sizes[2] = {2, 2}; + TensorImpl::StridesType strides[2] = {2, 1}; + TensorImpl::DimOrderType dim_order[2] = {0, 1}; + + TensorImpl t1(ScalarType::Float, 2, sizes, nullptr, dim_order, strides); + TensorImpl t2(ScalarType::Float, 2, sizes, nullptr, dim_order, strides); + + ET_EXPECT_DEATH({ EXPECT_TENSOR_EQ(Tensor(&t1), Tensor(&t2)); }, ""); + + float data[] = {1.0, 2.0, 3.0, 4.0}; + + t1.set_data(data); + t2.set_data(data); + + EXPECT_TENSOR_EQ(Tensor(&t1), Tensor(&t2)); +} + +#endif // !USE_ATEN_LIB diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/README.md new file mode 100644 index 0000000..910e471 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/README.md @@ -0,0 +1,2 @@ +The targets in this directory are not part of the core `kernel_types` libray, +but are helpful for writing code that uses those types. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/dim_order_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/dim_order_util.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/dim_order_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/dim_order_util.h index ea56827..d01b207 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/exec_aten/util/dim_order_util.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/dim_order_util.h @@ -8,13 +8,13 @@ #pragma once +#include #include #include #include #include #include -#include #include #include @@ -24,22 +24,10 @@ namespace runtime { namespace { template bool validate_dim_order(const DimOrderType* dim_order, const size_t dims) { - static_assert( - kTensorDimensionLimit <= 16, - "Bitmask-based validation requires kTensorDimensionLimit <= 16"); - if (dims > kTensorDimensionLimit) { - return false; - } - uint16_t seen = 0; for (const auto i : c10::irange(dims)) { if (dim_order[i] >= static_cast(dims)) { return false; } - const uint16_t mask = 1u << dim_order[i]; - if (seen & mask) { - return false; - } - seen |= mask; } return true; } @@ -162,7 +150,7 @@ ET_NODISCARD inline Error dim_order_to_stride( ET_CHECK_OR_RETURN_ERROR( validate_dim_order(dim_order, dims), InvalidArgument, - "Invalid dim order: values must be a permutation of [0, %zu)", + "Invalid dim order. One of the value is larger than the number of dims %zu", dims); dim_order_to_stride_nocheck(sizes, dim_order, dims, strides); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/scalar_type_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/scalar_type_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/scalar_type_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/scalar_type_util.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/targets.bzl new file mode 100644 index 0000000..ffdfa4f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/targets.bzl @@ -0,0 +1,85 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + exported_preprocessor_flags_ = [] + exported_deps_ = ["//executorch/runtime/core:core"] + if aten_mode: + exported_preprocessor_flags_ += ["-DUSE_ATEN_LIB"] + else: + exported_deps_ += ["//executorch/runtime/core/portable_type:scalar_type"] + + runtime.cxx_library( + name = "scalar_type_util" + aten_suffix, + srcs = [], + exported_headers = [ + "scalar_type_util.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = exported_preprocessor_flags_, + exported_deps = exported_deps_, + exported_external_deps = ["libtorch"] if aten_mode else [], + ) + + runtime.cxx_library( + name = "dim_order_util" + aten_suffix, + srcs = [], + exported_headers = [ + "dim_order_util.h", + ], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + ) + + runtime.cxx_library( + name = "tensor_util" + aten_suffix, + srcs = ["tensor_util_aten.cpp"] if aten_mode else ["tensor_util_portable.cpp"], + exported_headers = [ + "tensor_util.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + ":tensor_dimension_limit", + "//executorch/runtime/core:core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ] + [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + ":scalar_type_util" + aten_suffix, + ":dim_order_util" + aten_suffix, + ], + # WARNING: using a deprecated API to avoid being built into a shared + # library. In the case of dynamically loading so library we don't want + # it to depend on other so libraries because that way we have to + # specify library directory path. + force_static = True, + ) + + runtime.cxx_library( + name = "tensor_shape_to_c_string" + aten_suffix, + srcs = ["tensor_shape_to_c_string.cpp"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit", + ], + exported_headers = ["tensor_shape_to_c_string.h"], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "tensor_dimension_limit", + exported_headers = ["tensor_dimension_limit.h"], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_dimension_limit.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_dimension_limit.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_dimension_limit.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_dimension_limit.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_shape_to_c_string.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_util.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_util.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_util.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_util_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_util_aten.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_util_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_util_aten.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_util_portable.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_util_portable.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/exec_aten/util/tensor_util_portable.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/tensor_util_portable.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/CMakeLists.txt new file mode 100644 index 0000000..e806419 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs + dim_order_util_test.cpp operator_impl_example_test.cpp + scalar_type_util_test.cpp tensor_shape_to_c_string_test.cpp + tensor_util_test.cpp +) + +et_cxx_test(runtime_core_exec_aten_util_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/dim_order_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/dim_order_util_test.cpp new file mode 100644 index 0000000..fe3c1f6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/dim_order_util_test.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include + +#include + +#include + +using executorch::runtime::dim_order_to_stride; +using executorch::runtime::Error; +using executorch::runtime::is_channels_last_dim_order; +using executorch::runtime::is_contiguous_dim_order; +using executorch::runtime::stride_to_dim_order; + +namespace { +void check_strides_eq( + executorch::aten::ArrayRef strides_a, + executorch::aten::ArrayRef strides_b) { + for (const auto i : c10::irange(strides_a.size())) { + EXPECT_EQ(strides_a[i], strides_b[i]); + } +} + +void check_dim_order_eq( + executorch::aten::ArrayRef dim_order_a, + executorch::aten::ArrayRef dim_order_b) { + for (const auto i : c10::irange(dim_order_a.size())) { + EXPECT_EQ(dim_order_a[i], dim_order_b[i]); + } +} +} // namespace + +TEST(DimOrderUtilTest, DimOrderToStride) { + executorch::aten::SizesType sizes_1[1] = {5}; + executorch::aten::SizesType dim_order_1[1] = {0}; + executorch::aten::SizesType strides_1[1] = {0}; + executorch::aten::SizesType expected_strides_1[1] = {1}; + auto error = dim_order_to_stride(sizes_1, dim_order_1, 1, strides_1); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_1, 1}, {expected_strides_1, 1}); + + executorch::aten::SizesType sizes_2[2] = {2, 5}; + executorch::aten::SizesType dim_order_2[2] = {0, 1}; + executorch::aten::SizesType strides_2[2] = {0, 0}; + executorch::aten::SizesType expected_strides_2[2] = {5, 1}; + error = dim_order_to_stride(sizes_2, dim_order_2, 2, strides_2); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_2, 2}, {expected_strides_2, 2}); + + dim_order_2[0] = 1; + dim_order_2[1] = 0; + expected_strides_2[0] = 1; + expected_strides_2[1] = 2; + error = dim_order_to_stride(sizes_2, dim_order_2, 2, strides_2); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_2, 2}, {expected_strides_2, 2}); + + executorch::aten::SizesType sizes_3[3] = {2, 5, 7}; + executorch::aten::SizesType dim_order_3[3] = {0, 1, 2}; + executorch::aten::SizesType strides_3[3] = {0, 0, 0}; + executorch::aten::SizesType expected_strides_3[3] = {35, 7, 1}; + error = dim_order_to_stride(sizes_3, dim_order_3, 3, strides_3); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3, 3}, {expected_strides_3, 3}); + + // {0, 2, 1} + dim_order_3[0] = 0, dim_order_3[1] = 2, dim_order_3[2] = 1; + // Expected stride {35, 1, 5} + expected_strides_3[0] = 35, expected_strides_3[1] = 1, + expected_strides_3[2] = 5; + error = dim_order_to_stride(sizes_3, dim_order_3, 3, strides_3); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3, 3}, {expected_strides_3, 3}); + + // {2, 5, 7} + // {1, 2, 0} + dim_order_3[0] = 1, dim_order_3[1] = 2, dim_order_3[2] = 0; + // Expected stride {35, 1, 5} + expected_strides_3[0] = 1, expected_strides_3[1] = 14, + expected_strides_3[2] = 2; + error = dim_order_to_stride(sizes_3, dim_order_3, 3, strides_3); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3, 3}, {expected_strides_3, 3}); + + executorch::aten::SizesType sizes_4[4] = {2, 5, 7, 8}; + executorch::aten::SizesType dim_order_4[4] = {0, 1, 2, 3}; + executorch::aten::SizesType strides_4[4] = {0, 0, 0, 0}; + executorch::aten::SizesType expected_strides_4[4] = {280, 56, 8, 1}; + error = dim_order_to_stride(sizes_4, dim_order_4, 4, strides_4); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_4, 4}, {expected_strides_4, 4}); + + // {2, 5, 7, 8} + // {0, 2, 3, 1} + dim_order_4[0] = 0; + dim_order_4[1] = 2; + dim_order_4[2] = 3; + dim_order_4[3] = 1; + // Expected stride {280, 1, 40, 5} + expected_strides_4[0] = 280; + expected_strides_4[1] = 1; + expected_strides_4[2] = 40; + expected_strides_4[3] = 5; + error = dim_order_to_stride(sizes_4, dim_order_4, 4, strides_4); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_4, 4}, {expected_strides_4, 4}); + + // {2, 5, 7, 8} + // {3, 1, 2, 0} + dim_order_4[0] = 3; + dim_order_4[1] = 1; + dim_order_4[2] = 2; + dim_order_4[3] = 0; + // Expected stride {1, 14, 2, 70} + expected_strides_4[0] = 1; + expected_strides_4[1] = 14; + expected_strides_4[2] = 2; + expected_strides_4[3] = 70; + error = dim_order_to_stride(sizes_4, dim_order_4, 4, strides_4); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_4, 4}, {expected_strides_4, 4}); + + executorch::aten::SizesType sizes_5[5] = {2, 5, 7, 8, 9}; + executorch::aten::SizesType dim_order_5[5] = {0, 1, 2, 3, 4}; + executorch::aten::SizesType strides_5[5] = {0, 0, 0, 0, 0}; + executorch::aten::SizesType expected_strides_5[5] = {2520, 504, 72, 9, 1}; + error = dim_order_to_stride(sizes_5, dim_order_5, 5, strides_5); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_5, 5}, {expected_strides_5, 5}); + + // {2, 5, 7, 8, 9} + // {0, 2, 3, 4, 1} + dim_order_5[0] = 0; + dim_order_5[1] = 2; + dim_order_5[2] = 3; + dim_order_5[3] = 4; + dim_order_5[4] = 1; + // Expected stride {2520, 1, 360, 45, 5} + expected_strides_5[0] = 2520; + expected_strides_5[1] = 1; + expected_strides_5[2] = 360; + expected_strides_5[3] = 45; + expected_strides_5[4] = 5; + error = dim_order_to_stride(sizes_5, dim_order_5, 5, strides_5); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_5, 5}, {expected_strides_5, 5}); + + // {2, 5, 7, 8, 9} + // {4, 2, 0, 3, 1} + dim_order_5[0] = 4; + dim_order_5[1] = 2; + dim_order_5[2] = 0; + dim_order_5[3] = 3; + dim_order_5[4] = 1; + // Expected stride {40, 1, 80, 5, 560} + expected_strides_5[0] = 40; + expected_strides_5[1] = 1; + expected_strides_5[2] = 80; + expected_strides_5[3] = 5; + expected_strides_5[4] = 560; + error = dim_order_to_stride(sizes_5, dim_order_5, 5, strides_5); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_5, 5}, {expected_strides_5, 5}); + + // Check 0 sized dims + executorch::aten::SizesType sizes_3_zero[3] = {2, 5, 0}; + executorch::aten::SizesType dim_order_3_zero[3] = {0, 1, 2}; + executorch::aten::SizesType strides_3_zero[3] = {0, 0, 0}; + executorch::aten::SizesType expected_strides_3_zero[3] = {5, 1, 1}; + error = + dim_order_to_stride(sizes_3_zero, dim_order_3_zero, 3, strides_3_zero); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3_zero, 3}, {expected_strides_3_zero, 3}); + + // {0, 2, 1} + // {2, 0, 5} + dim_order_3_zero[0] = 0, dim_order_3_zero[1] = 2, dim_order_3_zero[2] = 1; + // Expected stride {5, 5, 1} + expected_strides_3_zero[0] = 5, expected_strides_3_zero[1] = 1, + expected_strides_3_zero[2] = 5; + error = + dim_order_to_stride(sizes_3_zero, dim_order_3_zero, 3, strides_3_zero); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3_zero, 3}, {expected_strides_3_zero, 3}); + + // {2, 0, 1} + // {0, 2, 5} + dim_order_3_zero[0] = 2, dim_order_3_zero[1] = 0, dim_order_3_zero[2] = 1; + // Expected stride {10, 5, 1} + expected_strides_3_zero[0] = 5, expected_strides_3_zero[1] = 1, + expected_strides_3_zero[2] = 10; + error = + dim_order_to_stride(sizes_3_zero, dim_order_3_zero, 3, strides_3_zero); + EXPECT_EQ(error, Error::Ok); + check_strides_eq({strides_3_zero, 3}, {expected_strides_3_zero, 3}); +} + +TEST(DimOrderUtilTest, StrideToDimOrder) { + executorch::aten::SizesType strides[3] = {5, 1, 15}; + executorch::aten::DimOrderType dim_order[3] = {0, 0, 0}; + + auto error = stride_to_dim_order(strides, 3, dim_order); + + EXPECT_EQ(error, Error::Ok); + + executorch::aten::DimOrderType expected_dim_order[3] = {2, 0, 1}; + check_dim_order_eq(dim_order, expected_dim_order); +} + +TEST(DimOrderUtilTest, StrideToDimOrderSameStrides) { + executorch::aten::SizesType strides[4] = {4, 3, 1, 1}; + executorch::aten::DimOrderType dim_order[4] = {0, 0, 0, 0}; + + auto error = stride_to_dim_order(strides, 4, dim_order); + EXPECT_EQ(error, Error::Ok); + + executorch::aten::DimOrderType expected_dim_order[4] = {0, 1, 2, 3}; + check_dim_order_eq(dim_order, expected_dim_order); +} + +TEST(DimOrderUtilTest, IsDefaultDimOrderTest) { + for (const auto i : c10::irange(1, 7)) { + std::vector dim_order(i); + std::iota(dim_order.begin(), dim_order.end(), 0); + + EXPECT_TRUE(is_contiguous_dim_order(dim_order.data(), dim_order.size())); + + // As a bonus, check that is_channels_last returns false + EXPECT_FALSE( + is_channels_last_dim_order(dim_order.data(), dim_order.size())); + } +} + +TEST(DimOrderUtilTest, IsDefaultDimOrderFailCasesTest) { + // Dims is default order but have two elements swapped + for (const auto i : c10::irange(3, 8)) { + std::vector dim_order(i); + std::iota(dim_order.begin(), dim_order.end(), 0); + std::swap(dim_order[0], dim_order[1]); + + EXPECT_FALSE(is_contiguous_dim_order(dim_order.data(), dim_order.size())); + } + + // Dims is default order but shifted by 1 + for (const auto i : c10::irange(3, 8)) { + std::vector dim_order(i); + for (const auto d : c10::irange(i)) { + dim_order[d] = (d + 1) % i; + } + + EXPECT_FALSE(is_contiguous_dim_order(dim_order.data(), dim_order.size())); + } +} + +TEST(DimOrderUtilTest, IsChannelsLastDimOrderTest) { + executorch::aten::DimOrderType dim_order_4d[4] = {0, 2, 3, 1}; + executorch::aten::DimOrderType dim_order_5d[5] = {0, 2, 3, 4, 1}; + + EXPECT_TRUE(is_channels_last_dim_order(dim_order_4d, 4)); + EXPECT_TRUE(is_channels_last_dim_order(dim_order_5d, 5)); + + // As a bonus, check that is_default returns false + EXPECT_FALSE(is_contiguous_dim_order(dim_order_4d, 4)); + EXPECT_FALSE(is_contiguous_dim_order(dim_order_5d, 5)); +} + +TEST(DimOrderUtilTest, IsChannelsLastDimOrderFailCasesTest) { + // Non 4D and 5D dim order returns false + executorch::aten::DimOrderType dim_order_3d[4] = {1, 2, 0}; + executorch::aten::DimOrderType dim_order_6d[6] = {0, 2, 3, 4, 5, 1}; + + EXPECT_FALSE(is_channels_last_dim_order(dim_order_3d, 3)); + EXPECT_FALSE(is_channels_last_dim_order(dim_order_6d, 6)); + + executorch::aten::DimOrderType dim_order_4d[4] = {0, 3, 2, 1}; + executorch::aten::DimOrderType dim_order_5d[5] = {4, 3, 2, 0, 1}; + + EXPECT_FALSE(is_channels_last_dim_order(dim_order_4d, 4)); + EXPECT_FALSE(is_channels_last_dim_order(dim_order_5d, 5)); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp new file mode 100644 index 0000000..d9d285c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/operator_impl_example_test.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @file + * + * Demonstrates the implementation of a simple operator using the utilities in + * this package. + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::testing::TensorFactory; + +// +// A sample implementation of a PyTorch operator using the utilities in this +// package. +// + +/** + * Adds the elements of `a` and `b`, overwriting `out`. + * + * Assumes that the tensors are contiguous, are the same shape, and have the + * same dtype. CTYPE should be the C type (like `float` or `int`) that matches + * the dtype of the tensors. + */ +template +void add_tensors_impl(const Tensor& a, const Tensor& b, Tensor& out) { + ET_DCHECK(a.numel() == b.numel() && b.numel() == out.numel()); + const size_t n = a.numel(); + const auto data_a = a.const_data_ptr(); + const auto data_b = b.const_data_ptr(); + auto data_out = out.mutable_data_ptr(); + for (const auto i : c10::irange(n)) { + data_out[i] = data_a[i] + data_b[i]; + } +} + +/** + * Element-wise sum of `a` and `b`, overwriting `out`. + * + * Asserts if the tensors are not all the same dtype and shape. + */ +Tensor& add_tensors_op(const Tensor& a, const Tensor& b, Tensor& out) { + ET_CHECK_SAME_SHAPE_AND_DTYPE3(a, b, out); + +// ET_FORALL_REAL_TYPES() will call this macro for every ScalarType backed by a +// real-number C type. `ctype` will be that C type (e.g. `float`), and `dtype` +// will be the unqualified ScalarType enumeration name (e.g., `Float`). +// +// Use this to create a switch statement that dispatches to the impl template +// based on the types of the provided tensors. +#define ADD_TENSORS(ctype, dtype) \ + case ScalarType::dtype: \ + add_tensors_impl(a, b, out); \ + break; + + switch (a.scalar_type()) { + ET_FORALL_REAL_TYPES(ADD_TENSORS) + default: + ET_CHECK_MSG(false, "Unhandled dtype %hhd", a.scalar_type()); + } + +#undef ADD_TENSORS + + return out; +} + +// +// Some basic unit tests demonstrating that the operator implementation works as +// expected. +// + +TEST(OperatorImplExampleTest, AddIntTensors) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + // Destination for the sum. + Tensor out = tf.zeros(sizes); + + // Add two tensors. + add_tensors_op(tf.make(sizes, /*data=*/{1, 2, 4, 8}), tf.ones(sizes), out); + + // Check that it matches the expected output. + EXPECT_TENSOR_EQ(out, tf.make(sizes, /*data=*/{2, 3, 5, 9})); +} + +TEST(OperatorImplExampleTest, AddDoubleTensors) { + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + // Destination for the sum. + Tensor out = tf.zeros(sizes); + + // Add two tensors. + add_tensors_op( + tf.make(sizes, /*data=*/{1.1, 2.2, 4.4, 8.8}), tf.ones(sizes), out); + + // Check that it matches the expected output. + EXPECT_TENSOR_CLOSE(out, tf.make(sizes, /*data=*/{2.1, 3.2, 5.4, 9.8})); +} + +TEST(OperatorImplExampleTest, UnhandledDtypeDies) { + // add_tensors_op() doesn't handle Bool. + TensorFactory tf; + + const std::vector sizes = {2, 2}; + + // Addends. + Tensor a = tf.make(sizes, /*data=*/{false, true, false, true}); + Tensor b = tf.make(sizes, /*data=*/{true, false, true, false}); + + // Destination for the sum. + Tensor out = tf.zeros(sizes); + + // Adding the two boolean tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} + +TEST(OpAddOutKernelTest, MismatchedInputDimsDies) { + TensorFactory tf; + + // Addends with the same number of elements but different dimensions. + Tensor a = tf.ones(/*sizes=*/{4}); + Tensor b = tf.ones(/*sizes=*/{2, 2}); + + // Destination for the sum; matches the shape of one of the inputs. + Tensor out = tf.zeros(/*sizes=*/{4}); + + // Adding the two mismatched tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} + +TEST(OpAddOutKernelTest, MismatchedInputDtypesDies) { + TensorFactory tf_int; + TensorFactory tf_float; + + const std::vector sizes = {2, 2}; + + // Addends with the same shape but different dtypes. + Tensor a = tf_int.ones(sizes); + Tensor b = tf_float.ones(sizes); + + // Destination for the sum; matches the dtype of one of the inputs. + Tensor out = tf_float.zeros(sizes); + + // Adding the two mismatched tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} + +TEST(OpAddOutKernelTest, MixingUnhandledDtypeDies) { + TensorFactory tf_int; + TensorFactory tf_bool; + + const std::vector sizes = {2, 2}; + + // Addends with the same shape but different dtypes, one of which (bool) is + // not supported by add_tensors_op(). + Tensor a = tf_int.ones(sizes); + Tensor b = tf_bool.ones(sizes); + + // Destination for the sum; matches the input with a valid dtype. + Tensor out = tf_int.zeros(sizes); + + // Adding the two mismatched tensors should cause an assertion and kill the + // test process. + ET_EXPECT_DEATH(add_tensors_op(a, b, out), ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp new file mode 100644 index 0000000..e884947 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/scalar_type_util_test.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include +#include + +using namespace ::testing; +using executorch::aten::complex; +using executorch::aten::ScalarType; +using executorch::runtime::elementSize; +using executorch::runtime::isValid; +using executorch::runtime::toString; + +TEST(ScalarTypeUtilTest, ToString) { + // Some known types. + EXPECT_STREQ(toString(ScalarType::Int), "Int"); + EXPECT_STREQ(toString(ScalarType::ComplexHalf), "ComplexHalf"); + + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + EXPECT_STREQ(toString(ScalarType::Undefined), "Undefined"); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + EXPECT_STREQ(toString(ScalarType::NumOptions), "UNKNOWN_SCALAR"); + EXPECT_STREQ(toString(static_cast(127)), "UNKNOWN_SCALAR"); + EXPECT_STREQ(toString(static_cast(-1)), "UNKNOWN_SCALAR"); +} + +TEST(ScalarTypeUtilTest, ElementSize) { + struct TestCase { + ScalarType type; + size_t expected_size; + }; + std::vector test_cases = { + {ScalarType::Byte, sizeof(uint8_t)}, + {ScalarType::Char, sizeof(int8_t)}, + {ScalarType::Short, sizeof(int16_t)}, + {ScalarType::Int, sizeof(int32_t)}, + {ScalarType::Long, sizeof(int64_t)}, + {ScalarType::Half, sizeof(executorch::aten::Half)}, + {ScalarType::Float, sizeof(float)}, + {ScalarType::Double, sizeof(double)}, + {ScalarType::ComplexHalf, + sizeof(::executorch::aten::complex<::executorch::aten::Half>)}, + {ScalarType::ComplexFloat, sizeof(::executorch::aten::complex)}, + {ScalarType::ComplexDouble, sizeof(::executorch::aten::complex)}, + {ScalarType::Bool, sizeof(bool)}, + {ScalarType::QInt8, sizeof(::executorch::aten::qint8)}, + {ScalarType::QUInt8, sizeof(::executorch::aten::quint8)}, + {ScalarType::QInt32, sizeof(::executorch::aten::qint32)}, + {ScalarType::BFloat16, sizeof(::executorch::aten::BFloat16)}, + {ScalarType::QUInt4x2, sizeof(::executorch::aten::quint4x2)}, + {ScalarType::QUInt2x4, sizeof(::executorch::aten::quint2x4)}, + }; + for (const auto& test_case : test_cases) { + EXPECT_EQ(elementSize(test_case.type), test_case.expected_size); + } +} + +TEST(ScalarTypeUtilTest, IsValidTrue) { + // Some valid types. + EXPECT_TRUE(isValid(ScalarType::Byte)); + EXPECT_TRUE(isValid(ScalarType::Float)); + EXPECT_TRUE(isValid(ScalarType::ComplexFloat)); + EXPECT_TRUE(isValid(ScalarType::Bits16)); +} + +TEST(ScalarTypeUtilTest, IsValidFalse) { + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + EXPECT_FALSE(isValid(ScalarType::Undefined)); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + EXPECT_FALSE(isValid(ScalarType::NumOptions)); + EXPECT_FALSE(isValid(static_cast(127))); + EXPECT_FALSE(isValid(static_cast(-1))); +} + +TEST(ScalarTypeUtilTest, UnknownTypeElementSizeDies) { + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + ET_EXPECT_DEATH(elementSize(ScalarType::Undefined), ""); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + ET_EXPECT_DEATH(elementSize(ScalarType::NumOptions), ""); + ET_EXPECT_DEATH(elementSize(static_cast(127)), ""); + ET_EXPECT_DEATH(elementSize(static_cast(-1)), ""); +} + +TEST(ScalarTypeUtilTest, canCastTest) { + using executorch::aten::ScalarType; + using executorch::runtime::canCast; + + // Check some common cases + + // complex to non-complex fails + ET_CHECK(!canCast(ScalarType::ComplexFloat, ScalarType::Float)); + ET_CHECK(!canCast(ScalarType::ComplexDouble, ScalarType::Double)); + + // non-complex to complex is fine + ET_CHECK(canCast(ScalarType::Float, ScalarType::ComplexFloat)); + ET_CHECK(canCast(ScalarType::Float, ScalarType::ComplexDouble)); + ET_CHECK(canCast(ScalarType::Int, ScalarType::ComplexDouble)); + + // float to integral fails + ET_CHECK(!canCast(ScalarType::Float, ScalarType::Int)); + ET_CHECK(!canCast(ScalarType::Double, ScalarType::Long)); + + // integral to float in fine + ET_CHECK(canCast(ScalarType::Int, ScalarType::Float)); + ET_CHECK(canCast(ScalarType::Long, ScalarType::Float)); + + // non-bool to bool fails + ET_CHECK(!canCast(ScalarType::Byte, ScalarType::Bool)); + ET_CHECK(!canCast(ScalarType::Int, ScalarType::Bool)); + + // bool to non-bool is fine + ET_CHECK(canCast(ScalarType::Bool, ScalarType::Byte)); + ET_CHECK(canCast(ScalarType::Bool, ScalarType::Int)); + ET_CHECK(canCast(ScalarType::Bool, ScalarType::Float)); +} + +TEST(ScalarTypeUtilTest, promoteTypesTest) { + using executorch::aten::ScalarType; + using executorch::runtime::promoteTypes; + + // Check some common cases + + EXPECT_EQ( + promoteTypes(ScalarType::Float, ScalarType::Double), ScalarType::Double); + EXPECT_EQ( + promoteTypes(ScalarType::Float, ScalarType::Short), ScalarType::Float); + + EXPECT_EQ( + promoteTypes(ScalarType::Float, ScalarType::Int), ScalarType::Float); + EXPECT_EQ( + promoteTypes(ScalarType::Long, ScalarType::Float), ScalarType::Float); + + EXPECT_EQ(promoteTypes(ScalarType::Bool, ScalarType::Bool), ScalarType::Bool); + + EXPECT_EQ(promoteTypes(ScalarType::Byte, ScalarType::Int), ScalarType::Int); + EXPECT_EQ(promoteTypes(ScalarType::Char, ScalarType::Bool), ScalarType::Char); + EXPECT_EQ(promoteTypes(ScalarType::Bool, ScalarType::Int), ScalarType::Int); + + EXPECT_EQ( + promoteTypes(ScalarType::BFloat16, ScalarType::Half), ScalarType::Float); + EXPECT_EQ( + promoteTypes(ScalarType::BFloat16, ScalarType::Bool), + ScalarType::BFloat16); +} + +template +struct promote_types_is_valid + : std::integral_constant< + bool, + (std::is_same::value || + (!executorch::runtime::is_qint_type::value && + !executorch::runtime::is_qint_type::value && + !executorch::runtime::is_bits_type::value && + !executorch::runtime::is_bits_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_float8_type::value && + !executorch::runtime::is_barebones_unsigned_type::value && + !executorch::runtime::is_barebones_unsigned_type::value))> {}; + +template +struct CompileTimePromoteTypesTestCase { + static void testAll() { +#define CALL_TEST_ONE(cpp_type, scalar_type) \ + testOne::value>(); + ET_FORALL_SCALAR_TYPES(CALL_TEST_ONE) +#undef CALL_TEST_ONE + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + auto actual = executorch::runtime::CppTypeToScalarType< + typename executorch::runtime::promote_types:: + type>::value; + const auto scalarType1 = + executorch::runtime::CppTypeToScalarType::value; + const auto scalarType2 = + executorch::runtime::CppTypeToScalarType::value; + auto expected = executorch::runtime::promoteTypes( + scalarType1, scalarType2, half_to_float); + EXPECT_EQ(actual, expected) + << "promoting " << (int)scalarType1 << " to " << (int)scalarType2 + << " (half to float: " << half_to_float << ')'; + } + + template < + typename T2, + bool valid, + typename std::enable_if::type = true> + static void testOne() { + // Skip invalid case + } +}; + +TEST(ScalarTypeUtilTest, compileTypePromoteTypesTest) { +#define INSTANTIATE_TYPE_TEST(cpp_type, scalar_type) \ + CompileTimePromoteTypesTestCase::testAll(); \ + CompileTimePromoteTypesTestCase::testAll(); + + ET_FORALL_SCALAR_TYPES(INSTANTIATE_TYPE_TEST); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/targets.bzl new file mode 100644 index 0000000..2507755 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/targets.bzl @@ -0,0 +1,60 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "scalar_type_util_test", + srcs = ["scalar_type_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + ) + + runtime.cxx_test( + name = "operator_impl_example_test", + srcs = ["operator_impl_example_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "dim_order_util_test", + srcs = ["dim_order_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core/exec_aten/util:tensor_util", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + runtime.cxx_test( + name = "tensor_util_test" + aten_suffix, + srcs = ["tensor_util_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/testing_util:tensor_util", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "tensor_shape_to_c_string_test", + srcs = ["tensor_shape_to_c_string_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/core/exec_aten/util:tensor_util", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp new file mode 100644 index 0000000..8059360 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_shape_to_c_string_test.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +#include + +#include +#include +#include +#include + +using executorch::runtime::kTensorDimensionLimit; +using executorch::runtime::Span; +using executorch::runtime::tensor_shape_to_c_string; +using executorch::runtime::internal::kMaximumPrintableTensorShapeElement; + +TEST(TensorShapeToCStringTest, Basic) { + std::array sizes = {123, 456, 789}; + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + EXPECT_STREQ(str.data(), "(123, 456, 789)"); + + std::array one_size = {1234567890}; + str = tensor_shape_to_c_string(Span( + one_size.data(), one_size.size())); + EXPECT_STREQ(str.data(), "(1234567890)"); +} + +TEST(TensorShapeToCStringTest, NegativeItems) { + std::array sizes = {-1, -3, -2, 4}; + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + EXPECT_STREQ(str.data(), "(ERR, ERR, ERR, 4)"); + + std::array one_size = {-1234567890}; + str = tensor_shape_to_c_string(Span( + one_size.data(), one_size.size())); + if constexpr (std::numeric_limits::is_signed) { + EXPECT_STREQ(str.data(), "(ERR)"); + } else { + EXPECT_EQ(str.data(), "(" + std::to_string(one_size[0]) + ")"); + } +} +TEST(TensorShapeToCStringTest, MaximumElement) { + std::array sizes = { + 123, std::numeric_limits::max(), 789}; + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + std::ostringstream expected; + expected << '('; + for (const auto elem : sizes) { + expected << elem << ", "; + } + auto expected_str = expected.str(); + expected_str.pop_back(); + expected_str.back() = ')'; + EXPECT_EQ(str.data(), expected_str); +} + +TEST(TensorShapeToCStringTest, MaximumLength) { + std::array sizes; + std::fill(sizes.begin(), sizes.end(), kMaximumPrintableTensorShapeElement); + + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + + std::ostringstream expected; + expected << '(' << kMaximumPrintableTensorShapeElement; + for (int ii = 0; ii < kTensorDimensionLimit - 1; ++ii) { + expected << ", " << kMaximumPrintableTensorShapeElement; + } + expected << ')'; + auto expected_str = expected.str(); + + EXPECT_EQ(expected_str, str.data()); +} + +TEST(TensorShapeToCStringTest, ExceedsDimensionLimit) { + std::array sizes; + std::fill(sizes.begin(), sizes.end(), kMaximumPrintableTensorShapeElement); + + auto str = tensor_shape_to_c_string( + Span(sizes.data(), sizes.size())); + + EXPECT_STREQ(str.data(), "(ERR: tensor ndim exceeds limit)"); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_util_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_util_test.cpp new file mode 100644 index 0000000..842f234 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/exec_aten/util/test/tensor_util_test.cpp @@ -0,0 +1,608 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::extract_scalar_tensor; +using executorch::runtime::testing::TensorFactory; + +class TensorUtilTest : public ::testing::Test { + protected: + // Factories for tests to use. These will be torn down and recreated for each + // test case. + TensorFactory tf_byte_; + TensorFactory tf_int_; + TensorFactory tf_float_; + TensorFactory tf_double_; + TensorFactory tf_bool_; + + void SetUp() override { + // As some of these tests cause ET_LOG to be called, the PAL must be + // initialized first by calling runtime_init(); + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorUtilTest, IdentityChecks) { + Tensor t = tf_byte_.ones({2, 2}); + + // A tensor is the same shape as itself. + ET_CHECK_SAME_SHAPE2(t, t); + ET_CHECK_SAME_SHAPE3(t, t, t); + + // A tensor is the same dtype as itself. + ET_CHECK_SAME_DTYPE2(t, t); + ET_CHECK_SAME_DTYPE3(t, t, t); + + // A tensor is the same shape and dtype as itself. + ET_CHECK_SAME_SHAPE_AND_DTYPE2(t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE3(t, t, t); +} + +TEST_F(TensorUtilTest, SameShapesDifferentDtypes) { + // Three different tensors with the same shape but different dtypes. + Tensor a = tf_byte_.ones({2, 2}); + Tensor b = tf_int_.ones({2, 2}); + Tensor c = tf_float_.ones({2, 2}); + + // The tensors have the same shapes. + ET_CHECK_SAME_SHAPE2(a, b); + ET_CHECK_SAME_SHAPE3(a, b, c); + + // Not the same dtypes. Check both positions. + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE2(b, a), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(b, a), ""); + + // Test with a mismatching tensor in all positions, where the other two agree. + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE3(a, b, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE3(b, a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_DTYPE3(b, b, a), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(a, b, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, b, a), ""); +} + +TEST_F(TensorUtilTest, DifferentShapesSameDtypes) { + // Two different tensors with different shapes but the same dtypes, + // dimensions, and number of elements. + Tensor a = tf_int_.ones({1, 4}); + Tensor b = tf_int_.ones({2, 2}); + // A third tensor with the same shape and dtype as b. + Tensor b2 = tf_int_.ones({2, 2}); + + // The different tensors are not the same shape. Check both positions. + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE2(b, a), ""); + + // Test with the different tensor in all positions. + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE3(a, b, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE3(b, a, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE3(b, b2, a), ""); + + // They are the same dtypes. + ET_CHECK_SAME_DTYPE2(a, b); + ET_CHECK_SAME_DTYPE2(b, a); + ET_CHECK_SAME_DTYPE3(a, b, b2); + ET_CHECK_SAME_DTYPE3(b, a, b2); + ET_CHECK_SAME_DTYPE3(b, b2, a); + + // But not the same shape-and-dtype. + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(a, b), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE2(b, a), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(a, b, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, a, b2), ""); + ET_EXPECT_DEATH(ET_CHECK_SAME_SHAPE_AND_DTYPE3(b, b2, a), ""); +} + +TEST_F(TensorUtilTest, ZeroDimensionalTensor) { + // Create a zero-dimensional tensor. + Tensor t = tf_int_.ones({}); + + // Demonstrate that the tensor has zero dimensions. + EXPECT_EQ(t.dim(), 0); + + // Make sure nothing blows up when the tensor has zero dimensions. + ET_CHECK_SAME_SHAPE2(t, t); + ET_CHECK_SAME_SHAPE3(t, t, t); + ET_CHECK_SAME_DTYPE2(t, t); + ET_CHECK_SAME_DTYPE3(t, t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE2(t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE3(t, t, t); +} + +TEST_F(TensorUtilTest, EmptyTensor) { + // Create a tensor with no elements by providing a zero-width dimension. + Tensor t = tf_int_.ones({0}); + + // Demonstrate that the tensor has no elements. + EXPECT_EQ(t.nbytes(), 0); + EXPECT_EQ(t.numel(), 0); + + // Make sure nothing blows up when the tensor has no elements. + ET_CHECK_SAME_SHAPE2(t, t); + ET_CHECK_SAME_SHAPE3(t, t, t); + ET_CHECK_SAME_DTYPE2(t, t); + ET_CHECK_SAME_DTYPE3(t, t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE2(t, t); + ET_CHECK_SAME_SHAPE_AND_DTYPE3(t, t, t); +} + +TEST_F(TensorUtilTest, GetLeadingDimsSmokeTest) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // getLeadingDims(t, 1) => t.size(0) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 1), 2); + + // getLeadingDims(t, 2) => t.size(0) * t.size(1) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 2), 6); + + // getLeadingDims(t, 3) => t.size(0) * t.size(1) * t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 3), 24); +} + +TEST_F(TensorUtilTest, GetLeadingDimsInputOutOfBoundDies) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // dim needs to be in the range [0, t.dim()] + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, -2), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, -1), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getLeadingDims(t, 4), ""); +} + +TEST_F(TensorUtilTest, GetTrailingDimsSmokeTest) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // getTrailingDims(t, 1) => t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 1), 4); + + // getTrailingDims(t, 0) => t.size(1) * t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 0), 12); + + // getTrailingDims(t, -1) => t.size(0) * t.size(1) * t.size(2) + EXPECT_EQ(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, -1), 24); +} + +TEST_F(TensorUtilTest, GetTrailingDimsInputOutOfBoundDies) { + // Create a tensor with some dimensions + Tensor t = tf_int_.ones({2, 3, 4}); + + // dim needs to be in the range [-1, t.dim() - 1) + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, -2), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 3), ""); + ET_EXPECT_DEATH(executorch::ET_RUNTIME_NAMESPACE::getTrailingDims(t, 4), ""); +} + +TEST_F(TensorUtilTest, ContiguousCheckSupported) { + std::vector data = {1, 2, 3, 4, 5, 6}; + std::vector sizes = {1, 2, 3}; + + Tensor t_contiguous = tf_float_.make(sizes, data); + + // t_incontiguous = tf.make(sizes=(1, 2, 3)).permute(2, 0, 1) + // {3, 1, 2} + // changed stride {1, 3, 1} => {2, 1, 2} because {1, 3, 1} is not + // the right value. + Tensor t_incontiguous = tf_float_.make(sizes, data, /*strides=*/{2, 1, 2}); + + // Assert t_contiguous is contiguous. + ET_CHECK_CONTIGUOUS(t_contiguous); + + // Assert t_incontiguous is incontiguous. + ET_EXPECT_DEATH(ET_CHECK_CONTIGUOUS(t_incontiguous), ""); +} + +TEST_F(TensorUtilTest, CheckSameContiguousStrideSupported) { + // Tensors in the following list share same stride. + std::vector same_stride_tensor_list = { + tf_float_.ones(/*sizes=*/{1, 2, 3, 4}), + tf_byte_.ones(/*sizes=*/{4, 2, 3, 4}), + tf_int_.ones(/*sizes=*/{10, 2, 3, 4}), + tf_float_.make( + /*sizes=*/{0, 2, 3, 4}, /*data=*/{}, /*strides=*/{24, 12, 4, 1})}; + + // different_stride = tensor(size=(0,2,3,4)).permute(0, 2, 3, 1) + // {0, 3, 4, 2} + // stride for (0, 2, 3, 4) with permute = (24, 1, 8, 2) + // So change stride from {24, 3, 1, 6} => {24, 1, 8, 2} + Tensor different_stride = tf_float_.make( + /*sizes=*/{0, 2, 3, 4}, /*data=*/{}, /*strides=*/{24, 1, 8, 2}); + + // Any two tensors in `same_stride_tensor_list` have same strides. The two + // could contain duplicate tensors. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + for (const auto j : c10::irange(i, same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + auto tj = same_stride_tensor_list[j]; + ET_CHECK_SAME_STRIDES2(ti, tj); + } + } + + // Any tensor in `same_stride_tensor_list` shall not have same stride with + // `different_stride`. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + ET_EXPECT_DEATH(ET_CHECK_SAME_STRIDES2(ti, different_stride), ""); + } + + // Any three tensors in same_stride_tensor_list have same strides. The three + // could contain duplicate tensors. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + for (const auto j : c10::irange(i, same_stride_tensor_list.size())) { + for (const auto k : c10::irange(j, same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + auto tj = same_stride_tensor_list[j]; + auto tk = same_stride_tensor_list[k]; + ET_CHECK_SAME_STRIDES3(ti, tj, tk); + } + } + } + + // Any two tensors in same_stride_tensor_list shall not have same strides with + // `different_stride`. The two could contain duplicate tensors. + for (const auto i : c10::irange(same_stride_tensor_list.size())) { + for (const auto j : c10::irange(i, same_stride_tensor_list.size())) { + auto ti = same_stride_tensor_list[i]; + auto tj = same_stride_tensor_list[j]; + ET_EXPECT_DEATH(ET_CHECK_SAME_STRIDES3(ti, tj, different_stride), ""); + } + } +} + +TEST_F(TensorUtilTest, ExtractIntScalarTensorSmoke) { + Tensor t = tf_int_.ones({1}); + bool ok; +#define CASE_INT_DTYPE(ctype, unused) \ + ctype out_##ctype; \ + ok = extract_scalar_tensor(t, &out_##ctype); \ + ASSERT_TRUE(ok); \ + EXPECT_EQ(out_##ctype, 1); + + ET_FORALL_INT_TYPES(CASE_INT_DTYPE); +#undef CASE_INT_DTYPE +} + +TEST_F(TensorUtilTest, ExtractFloatScalarTensorFloatingTypeSmoke) { + Tensor t = tf_float_.ones({1}); + bool ok; +#define CASE_FLOAT_DTYPE(ctype, unused) \ + ctype out_##ctype; \ + ok = extract_scalar_tensor(t, &out_##ctype); \ + ASSERT_TRUE(ok); \ + EXPECT_EQ(out_##ctype, 1.0); + + ET_FORALL_FLOAT_TYPES(CASE_FLOAT_DTYPE); +#undef CASE_FLOAT_DTYPE +} + +TEST_F(TensorUtilTest, ExtractFloatScalarTensorIntegralTypeSmoke) { + Tensor t = tf_int_.ones({1}); + bool ok; +#define CASE_FLOAT_DTYPE(ctype, unused) \ + ctype out_##ctype; \ + ok = extract_scalar_tensor(t, &out_##ctype); \ + ASSERT_TRUE(ok); \ + EXPECT_EQ(out_##ctype, 1.0); + + ET_FORALL_INT_TYPES(CASE_FLOAT_DTYPE); +#undef CASE_FLOAT_DTYPE +} + +TEST_F(TensorUtilTest, ExtractBoolScalarTensorSmoke) { + Tensor t = tf_bool_.ones({1}); + bool out; + bool ok; + ok = extract_scalar_tensor(t, &out); + ASSERT_TRUE(ok); + EXPECT_EQ(out, true); +} + +TEST_F(TensorUtilTest, FloatScalarTensorStressTests) { + float value; + bool ok; + + // Case: Positive Infinity + Tensor t_pos_inf = tf_double_.make({1}, {INFINITY}); + ok = extract_scalar_tensor(t_pos_inf, &value); + EXPECT_TRUE(ok); + EXPECT_TRUE(std::isinf(value)); + + // Case: Negative Infinity + Tensor t_neg_inf = tf_double_.make({1}, {-INFINITY}); + ok = extract_scalar_tensor(t_neg_inf, &value); + EXPECT_TRUE(ok); + EXPECT_TRUE(std::isinf(value)); + + // Case: Not a Number (NaN) - ex: sqrt(-1.0) + Tensor t_nan = tf_double_.make({1}, {NAN}); + ok = extract_scalar_tensor(t_nan, &value); + EXPECT_TRUE(ok); + EXPECT_TRUE(std::isnan(value)); +} + +TEST_F(TensorUtilTest, IntScalarTensorNotIntegralTypeFails) { + Tensor t = tf_float_.ones({1}); + int64_t out; + // Fails since tensor is floating type but attempting to extract integer + // value. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, FloatScalarTensorNotFloatingTypeFails) { + Tensor t = tf_bool_.ones({1}); + double out; + // Fails since tensor is boolean type but attempting to extract float value. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, IntTensorNotScalarFails) { + Tensor t = tf_int_.ones({2, 3}); + int64_t out; + // Fails since tensor has multiple dims and values. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, FloatTensorNotScalarFails) { + Tensor t = tf_float_.ones({2, 3}); + double out; + // Fails since tensor has multiple dims and values. + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, IntTensorOutOfBoundFails) { + Tensor t = tf_int_.make({1}, {256}); + int8_t out; + // Fails since 256 is out of bounds for `int8_t` (-128 to 127). + bool ok = extract_scalar_tensor(t, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, FloatTensorOutOfBoundFails) { + Tensor t = tf_double_.make({1}, {1.0}); // Placeholder value. + float out; + bool ok; + +#define CASE_FLOAT(value) \ + t = tf_double_.make({1}, {value}); \ + ok = extract_scalar_tensor(t, &out); \ + EXPECT_FALSE(ok); + + // Float tensor can't handle double's largest negative value (note the use of + // `lowest` rather than `min`). + CASE_FLOAT(std::numeric_limits::lowest()); + + // Float tensor can't handle double's largest positive value. + CASE_FLOAT(std::numeric_limits::max()); + +#undef CASE_FLOAT +} + +TEST_F(TensorUtilTest, BoolScalarTensorNotBooleanTypeFails) { + Tensor c = tf_byte_.ones({1}); + bool out; + // Fails since tensor is integral type but attempting to extract boolean + // value. + bool ok = extract_scalar_tensor(c, &out); + EXPECT_FALSE(ok); +} + +TEST_F(TensorUtilTest, BoolTensorNotScalarFails) { + Tensor c = tf_bool_.ones({2, 3}); + bool out; + // Fails since tensor has multiple dims and values. + bool ok = extract_scalar_tensor(c, &out); + EXPECT_FALSE(ok); +} + +// +// Tests for utility functions that check tensor attributes +// + +TEST_F(TensorUtilTest, TensorIsRankTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensor_is_rank; + Tensor a = tf_float_.ones({2, 3, 5}); + + EXPECT_TRUE(tensor_is_rank(a, 3)); + EXPECT_FALSE(tensor_is_rank(a, 0)); + EXPECT_FALSE(tensor_is_rank(a, 5)); +} + +TEST_F(TensorUtilTest, TensorHasDimTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensor_has_dim; + Tensor a = tf_float_.ones({2, 3, 5}); + + EXPECT_TRUE(tensor_has_dim(a, 2)); + EXPECT_TRUE(tensor_has_dim(a, 1)); + EXPECT_TRUE(tensor_has_dim(a, 0)); + EXPECT_TRUE(tensor_has_dim(a, -1)); + EXPECT_TRUE(tensor_has_dim(a, -2)); + EXPECT_TRUE(tensor_has_dim(a, -3)); + + EXPECT_FALSE(tensor_has_dim(a, -4)); + EXPECT_FALSE(tensor_has_dim(a, 3)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameDtypeTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_dtype; + Tensor a = tf_float_.ones({2, 3}); + Tensor b = tf_float_.ones({2, 3}); + Tensor c = tf_float_.ones({3, 3}); + Tensor d = tf_int_.ones({4, 3}); + + EXPECT_TRUE(tensors_have_same_dtype(a, b)); + EXPECT_FALSE(tensors_have_same_dtype(a, d)); + EXPECT_TRUE(tensors_have_same_dtype(a, b, c)); + EXPECT_FALSE(tensors_have_same_dtype(a, b, d)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameSizeAtDimTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_size_at_dims; + Tensor a = tf_float_.ones({2, 3, 4, 5}); + Tensor b = tf_float_.ones({5, 4, 3, 2}); + + EXPECT_TRUE(tensors_have_same_size_at_dims(a, 0, b, 3)); + EXPECT_TRUE(tensors_have_same_size_at_dims(a, 1, b, 2)); + EXPECT_FALSE(tensors_have_same_size_at_dims(a, 1, b, 0)); + EXPECT_FALSE(tensors_have_same_size_at_dims(a, 4, b, 0)); + EXPECT_FALSE(tensors_have_same_size_at_dims(a, 2, b, 3)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameShapeTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_shape; + Tensor a = tf_float_.ones({2, 3}); + Tensor b = tf_int_.ones({2, 3}); + Tensor c = tf_byte_.ones({2, 3}); + Tensor d = tf_double_.ones({3, 2}); + Tensor e = tf_bool_.ones({3, 2}); + + EXPECT_TRUE(tensors_have_same_shape(a, b)); + EXPECT_FALSE(tensors_have_same_shape(a, d)); + EXPECT_TRUE(tensors_have_same_shape(d, e)); + EXPECT_TRUE(tensors_have_same_shape(a, b, c)); + EXPECT_FALSE(tensors_have_same_shape(a, b, d)); + EXPECT_FALSE(tensors_have_same_shape(a, d, e)); + + Tensor scalar_a = tf_float_.ones({1, 1}); + Tensor scalar_b = tf_double_.ones({1}); + Tensor scalar_c = tf_int_.ones({1, 1, 1, 1}); + + EXPECT_TRUE(tensors_have_same_shape(scalar_a, scalar_b)); + EXPECT_TRUE(tensors_have_same_shape(scalar_a, scalar_b, scalar_c)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameShapeAndDtypeTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_shape_and_dtype; + Tensor a = tf_float_.ones({2, 3}); + Tensor b = tf_float_.ones({2, 3}); + Tensor c = tf_float_.ones({2, 3}); + Tensor d = tf_double_.ones({2, 3}); + Tensor e = tf_float_.ones({3, 2}); + + EXPECT_TRUE(tensors_have_same_shape_and_dtype(a, b)); + EXPECT_FALSE(tensors_have_same_shape_and_dtype(a, d)); + EXPECT_TRUE(tensors_have_same_shape_and_dtype(a, b, c)); + EXPECT_FALSE(tensors_have_same_shape_and_dtype(a, b, d)); + EXPECT_FALSE(tensors_have_same_shape_and_dtype(a, d, e)); + + Tensor scalar_a = tf_float_.ones({1, 1}); + Tensor scalar_b = tf_float_.ones({1}); + Tensor scalar_c = tf_float_.ones({1, 1, 1, 1}); + + EXPECT_TRUE(tensors_have_same_shape_and_dtype(scalar_a, scalar_b)); + EXPECT_TRUE(tensors_have_same_shape_and_dtype(scalar_a, scalar_b, scalar_c)); +} + +TEST_F(TensorUtilTest, TensorsHaveSameStridesTest) { + using executorch::ET_RUNTIME_NAMESPACE::tensors_have_same_strides; + Tensor a = tf_float_.full_channels_last({4, 5, 2, 3}, 1); + Tensor b = tf_float_.full_channels_last({4, 5, 2, 3}, 2); + Tensor c = tf_float_.full_channels_last({4, 5, 2, 3}, 3); + Tensor d = tf_double_.ones({4, 5, 2, 3}); + Tensor e = tf_float_.ones({4, 5, 2, 3}); + + EXPECT_TRUE(tensors_have_same_strides(a, b)); + EXPECT_FALSE(tensors_have_same_strides(a, d)); + EXPECT_TRUE(tensors_have_same_strides(a, b, c)); + EXPECT_FALSE(tensors_have_same_strides(a, b, d)); + EXPECT_FALSE(tensors_have_same_strides(a, d, e)); +} + +TEST_F(TensorUtilTest, TensorIsContiguous) { + using executorch::ET_RUNTIME_NAMESPACE::tensor_is_contiguous; + // Note that the strides.size() == 0 case is not tested, since + Tensor a = tf_float_.full_channels_last({4, 5, 2, 3}, 1); + Tensor b = tf_float_.ones({4, 5, 2, 3}); + Tensor c = tf_float_.full_channels_last({1, 1, 1, 1}, 1); + Tensor d = tf_float_.ones({}); + + EXPECT_FALSE(tensor_is_contiguous(a)); + EXPECT_TRUE(tensor_is_contiguous(b)); + EXPECT_TRUE(tensor_is_contiguous(c)); + EXPECT_TRUE(tensor_is_contiguous(d)); +} + +TEST_F(TensorUtilTest, ResizeZeroDimTensor) { + Tensor a = tf_float_.ones({}); + + EXPECT_EQ( + executorch::ET_RUNTIME_NAMESPACE::resize_tensor(a, {}), + executorch::runtime::Error::Ok); + EXPECT_EQ(a.dim(), 0); +} + +TEST_F(TensorUtilTest, SameDimOrderContiguous) { + using namespace torch::executor; + // Three different tensors with the same shape and same dim order + // ([0, 1, 2, 3]), but different dtypes and contents. + std::vector sizes = {3, 5, 2, 1}; + Tensor a = tf_byte_.ones(sizes); + Tensor b = tf_int_.zeros(sizes); + Tensor c = tf_float_.full(sizes, 0.1); + + // The tensors have the same dim order, should pass the following checks. + EXPECT_TRUE(tensors_have_same_dim_order(a, b)); + EXPECT_TRUE(tensors_have_same_dim_order(b, a)); + EXPECT_TRUE(tensors_have_same_dim_order(a, b, c)); + EXPECT_TRUE(tensors_have_same_dim_order(b, c, a)); + EXPECT_TRUE(tensors_have_same_dim_order(c, a, b)); +} + +TEST_F(TensorUtilTest, SameDimOrderChannelsLast) { + using namespace torch::executor; + // Three different tensors with the same shape and same dim order + // ([0, 2, 3, 1]), but different dtypes and contents. + std::vector sizes = {3, 5, 2, 1}; + Tensor a = tf_byte_.full_channels_last(sizes, 1); + Tensor b = tf_int_.full_channels_last(sizes, 0); + Tensor c = tf_float_.full_channels_last(sizes, 0.1); + + // The tensors have the same dim order, should pass the following checks. + EXPECT_TRUE(tensors_have_same_dim_order(a, b)); + EXPECT_TRUE(tensors_have_same_dim_order(b, a)); + EXPECT_TRUE(tensors_have_same_dim_order(a, b, c)); + EXPECT_TRUE(tensors_have_same_dim_order(b, c, a)); + EXPECT_TRUE(tensors_have_same_dim_order(c, a, b)); +} + +TEST_F(TensorUtilTest, SameShapesDifferentDimOrder) { + using namespace torch::executor; + // Three different tensors with the same shape but different dtypes and + // contents, where b and c have the same dim order ([0, 2, 3, 1]) while a is + // different ([0, 1, 2, 3]). + std::vector sizes = {3, 5, 2, 1}; + Tensor a = tf_byte_.ones(sizes); + Tensor b = tf_int_.full_channels_last(sizes, 0); + Tensor c = tf_float_.full_channels_last(sizes, 0.1); + + // Not the same dim order. Chec + EXPECT_FALSE(tensors_have_same_dim_order(a, b)); + EXPECT_FALSE(tensors_have_same_dim_order(b, a)); + + // Test with a mismatching tensor in all positions, where the other two agree. + EXPECT_FALSE(tensors_have_same_dim_order(a, b, c)); + EXPECT_FALSE(tensors_have_same_dim_order(a, c, b)); + EXPECT_FALSE(tensors_have_same_dim_order(c, b, a)); +} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/freeable_buffer.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/freeable_buffer.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/freeable_buffer.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/freeable_buffer.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/function_ref.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/function_ref.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/function_ref.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/function_ref.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/hierarchical_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/hierarchical_allocator.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/hierarchical_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/hierarchical_allocator.h index d41b98f..c5dd624 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/hierarchical_allocator.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/hierarchical_allocator.h @@ -9,7 +9,6 @@ #pragma once #include -#include #include #include @@ -59,9 +58,8 @@ class HierarchicalAllocator final { size_t offset_bytes, size_t size_bytes) { // Check for integer overflow in offset_bytes + size_bytes. - size_t end_bytes = 0; ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows(offset_bytes, size_bytes, &end_bytes), + size_bytes <= SIZE_MAX - offset_bytes, InvalidArgument, "Integer overflow in offset_bytes (%" ET_PRIsize_t ") + size_bytes (%" ET_PRIsize_t ")", @@ -75,7 +73,7 @@ class HierarchicalAllocator final { buffers_.size()); Span buffer = buffers_[memory_id]; ET_CHECK_OR_RETURN_ERROR( - end_bytes <= buffer.size(), + offset_bytes + size_bytes <= buffer.size(), MemoryAllocationFailed, "offset_bytes (%" ET_PRIsize_t ") + size_bytes (%" ET_PRIsize_t ") >= allocator size (%" ET_PRIsize_t diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/memory_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/memory_allocator.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/memory_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/memory_allocator.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/named_data_map.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/named_data_map.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/named_data_map.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/named_data_map.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/bfloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/bfloat16.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/bfloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/bfloat16.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/bfloat16_math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/bfloat16_math.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/bfloat16_math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/bfloat16_math.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/bits_types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/bits_types.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/bits_types.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/bits_types.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/README.md b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/README.md new file mode 100644 index 0000000..c0fa01d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/README.md @@ -0,0 +1,20 @@ +This directory contains header files from `c10` in PyTorch core that +need to be used in ExecuTorch core. They are copied here rather than +being found through the torch pip package to keep the core build +hermetic for embedded use cases. The headers should be exact copies +from PyTorch core; if they are out of sync, please send a PR! + +We added an extra c10 directory so that `runtime/core/portable_type/c10` +can be the directory to put on your include path, rather than +`runtime/core/portable_type`, because using `runtime/core/portable_type` +would cause all headers in that directory to be includeable with +`#include `. In particular, that includes +`runtime/core/portable_type/complex.h`, which would shadow the C99 +`complex.h` standard header. + +`torch/headeronly` has been added as an extra "even more bottom of +stack" directory in PyTorch, so we have to add it to our sync +here. The extra "stutter" c10 directory causing `c10/torch/standlone` +is unfortunately awkward; perhaps we can rename the top-level +directory to `pytorch_embedded_mirror` when we have extra time to work +through CI failures. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/macros/Export.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/macros/Export.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/macros/Export.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/macros/Export.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/macros/Macros.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/macros/Macros.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/macros/Macros.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/macros/Macros.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/targets.bzl new file mode 100644 index 0000000..33a5580 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/targets.bzl @@ -0,0 +1,139 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def get_preprocessor_flags(is_fbcode): + flags = ["-DSTANDALONE_TORCH_HEADER"] + if runtime.is_oss: + return flags + # AT_BUILD_ARM_VEC256_WITH_SLEEF is off on Windows because Sleef + # is off on Windows per get_sleef_deps below. + arm64_flags = select({ + "DEFAULT": [ + "-DCPU_CAPABILITY_DEFAULT", + "-DAT_BUILD_ARM_VEC256_WITH_SLEEF", + ], + "ovr_config//os:windows": ["-DCPU_CAPABILITY_DEFAULT"], + }) + + x86_avx2_flags = [ + "-DCPU_CAPABILITY_AVX2", + "-DHAVE_AVX2_CPU_DEFINITION", + ] + default_flags = [ + "-DCPU_CAPABILITY_DEFAULT", + ] + fbcode_flags = select({ + "ovr_config//cpu:x86_64": x86_avx2_flags, + "ovr_config//cpu:arm64": arm64_flags, + "DEFAULT": default_flags, + }) + non_fbcode_flags = select({ + "ovr_config//cpu/x86:avx2": x86_avx2_flags, + "ovr_config//cpu:arm64": arm64_flags, + "DEFAULT": default_flags, + }) + return flags + ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"] + (fbcode_flags if is_fbcode else non_fbcode_flags) + +def get_sleef_deps(): + if runtime.is_oss: + return [] + return select({ + "DEFAULT": select({ + "DEFAULT": [], + "ovr_config//cpu:x86_64": [ + "fbsource//third-party/sleef:sleef", + ], + "ovr_config//cpu:arm64": [ + "fbsource//third-party/sleef:sleef", + ], + }), + "ovr_config//os:windows": [ + "fbsource//third-party/sleef:sleef", + ], + }) + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "aten_headers_for_executorch", + srcs = [], + visibility = ["PUBLIC"], + # select() on ovr_config//runtime:fbcode does not work + # properly in all cases. I have seen + # //xplat/executorch/runtime/core/portable_type/c10/c10:aten_headers_for_executorch + # pass such a select in (at least) arvr mode. Going back to + # fbcode_exported_deps accordingly. + exported_deps = select({ + "DEFAULT": [], + "ovr_config//cpu:arm64": [ + "fbsource//third-party/sleef:sleef", + ] if not runtime.is_oss else [], + }), + xplat_exported_deps = [ + "fbsource//xplat/caffe2:aten_header", + "fbsource//xplat/caffe2/c10:c10_headers", + ] + select({ + "DEFAULT": ["fbsource//xplat/caffe2:generated_aten_config_header"], + "ovr_config//build_mode:arvr_mode": ["fbsource//xplat/caffe2:ovrsource_aten_Config.h"], + }) + get_sleef_deps(), + fbcode_exported_deps = ([ + "//caffe2:aten-headers-cpu", + "//caffe2:generated-config-header", + "//caffe2/c10:c10_headers", + ] + get_sleef_deps()) if not runtime.is_oss else [], + exported_preprocessor_flags = get_preprocessor_flags(is_fbcode=False) + + ([] if runtime.is_oss else ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"]), + fbcode_exported_preprocessor_flags = get_preprocessor_flags(is_fbcode=True) + + ([] if runtime.is_oss else ["-DET_USE_PYTORCH_HEADERS=ET_HAS_EXCEPTIONS"]), + ) + + if runtime.is_oss: + runtime.cxx_library( + name = "c10", + header_namespace = "c10", + exported_headers = [ + "macros/Export.h", + "macros/Macros.h", + "util/BFloat16.h", + "util/BFloat16-inl.h", + "util/BFloat16-math.h", + "util/Half.h", + "util/Half-inl.h", + "util/TypeSafeSignMath.h", + "util/bit_cast.h", + "util/complex.h", + "util/complex_math.h", + "util/complex_utils.h", + "util/floating_point_utils.h", + "util/irange.h", + "util/llvmMathExtras.h", + "util/overflows.h", + "util/safe_numerics.h", + ], + exported_preprocessor_flags = [ + "-DC10_USING_CUSTOM_GENERATED_MACROS", + ] + ([] if runtime.is_oss else [ + "-DC10_USE_GLOG", + "-DC10_USE_MINIMAL_GLOG", + ]), + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/torch/headeronly:torch_headeronly", + ] + select({ + "DEFAULT": [], + # Half-inl.h depends on vec_half.h from ATen, but only when building for x86. + "ovr_config//cpu:x86_64": [ + ":aten_headers_for_executorch", + ], + }), + ) + else: + runtime.cxx_library( + name = "c10", + exported_deps = [":aten_headers_for_executorch"], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/BFloat16-inl.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/BFloat16-math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/BFloat16-math.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/BFloat16-math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/BFloat16-math.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/BFloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/BFloat16.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/BFloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/BFloat16.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/Half-inl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/Half-inl.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/Half-inl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/Half-inl.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/Half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/Half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/Half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/Half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/TypeSafeSignMath.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/bit_cast.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/bit_cast.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/bit_cast.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/bit_cast.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/complex_math.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/complex_math.h similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/complex_math.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/complex_math.h index d369df5..2b59102 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/complex_math.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/complex_math.h @@ -86,41 +86,6 @@ C10_HOST_DEVICE inline c10::complex pow( #endif } -// Regression in ROCm 7.2. See https://github.com/ROCm/rocm-libraries/pull/3836. -// Specialized version for complex on AMD GPUs to use FMA-based -// multiplication -#if defined(__HIPCC__) -namespace detail { -// FMA-aware complex multiplication for float precision on AMD GPUs. -// This prevents SLP vectorizer from breaking FMA formation, which causes -// numerical precision loss in complex arithmetic. -// The issue occurs when vectorizer packs scalar multiplies before backend -// can form FMA instructions, resulting in double rounding instead of single. -C10_HOST_DEVICE inline thrust::complex complex_mul_fma( - thrust::complex a, - thrust::complex b) { - // Complex multiplication: (a.r + a.i*i) * (b.r + b.i*i) - // = (a.r*b.r - a.i*b.i) + (a.r*b.i + a.i*b.r)*i - // Using __builtin_fmaf ensures FMA at source level: - // real: a.r*b.r + (-(a.i*b.i)) = FMA(a.r, b.r, -(a.i*b.i)) - // imag: a.i*b.r + a.r*b.i = FMA(a.r, b.i, a.i*b.r) - float real_part = __builtin_fmaf(a.real(), b.real(), -(a.imag() * b.imag())); - float imag_part = __builtin_fmaf(a.real(), b.imag(), a.imag() * b.real()); - return thrust::complex(real_part, imag_part); -} -} // namespace detail - -template <> -C10_HOST_DEVICE inline c10::complex pow( - const c10::complex& x, - const c10::complex& y) { - auto log_x = thrust::log(static_cast>(x)); - auto y_log_x = - detail::complex_mul_fma(static_cast>(y), log_x); - return static_cast>(thrust::exp(y_log_x)); -} -#endif - template C10_HOST_DEVICE inline c10::complex pow( const c10::complex& x, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/complex_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/complex_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/complex_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/complex_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/floating_point_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/floating_point_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/floating_point_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/floating_point_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/irange.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/irange.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/irange.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/irange.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/llvmMathExtras.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/overflows.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/overflows.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/overflows.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/overflows.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/safe_numerics.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/safe_numerics.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/c10/util/safe_numerics.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/c10/util/safe_numerics.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/BUCK new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/BUCK @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/TARGETS new file mode 100644 index 0000000..0a42614 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/TARGETS @@ -0,0 +1,5 @@ +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h index 14b26c1..8dd2541 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/macros/Export.h @@ -130,6 +130,14 @@ #define TORCH_CUDA_CU_API C10_IMPORT #endif +#if defined(TORCH_HIP_BUILD_MAIN_LIB) +#define TORCH_HIP_CPP_API C10_EXPORT +#define TORCH_HIP_API C10_EXPORT +#else +#define TORCH_HIP_CPP_API C10_IMPORT +#define TORCH_HIP_API C10_IMPORT +#endif + #if defined(TORCH_XPU_BUILD_MAIN_LIB) #define TORCH_XPU_API C10_EXPORT #else diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h index cef99df..63aa0d2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/macros/Macros.h @@ -325,88 +325,41 @@ constexpr uint32_t CUDA_THREADS_PER_BLOCK_FALLBACK = 256; #define C10_HIP_HOST_DEVICE #endif +#if defined(USE_ROCM) // C10_WARP_SIZE is only allowed for device code. -// Host code dynamically-sized launch configs _must_ use at::cuda::warp_size(). -// Host or device statically-sized arrays _must_ use either -// C10_WARP_SIZE_UPPER_BOUND or C10_WARP_SIZE_LOWER_BOUND, as needed. -// +// Host code _must_ use at::cuda::warp_size() // HIP header used to define warpSize as a constexpr that was either 32 or 64 // depending on the target device, and then always set it to 64 for host code. -// For a time, that allowed C10_WARP_SIZE to be defined like so: -// -// #ifdef USE_ROCM -// #define C10_WARP_SIZE warpSize -// #else -// #define C10_WARP_SIZE 32 -// #endif -// -// In ROCm 7, warpSize is no longer constexpr, matching CUDA behavior. -// We can now only use warpSize for C10_WARP_SIZE in device code and this is -// enforced by using __device__ in its definition. In host code where -// C10_WARP_SIZE was previously used as a compile-time constant, this will now -// cause a compile-time error. -// -// If an array was previously expected to be sized at compile-time using -// C10_WARP_SIZE, users must now use either C10_WARP_SIZE_UPPER_BOUND or -// C10_WARP_SIZE_LOWER_BOUND depending on the situation. -// -// If C10_WARP_SIZE was previously used to determine kernel launch sizes, users -// must now use at::cuda::warp_size() for the dynamic runtime query. -// -// Unfortunately, C10_WARP_SIZE has been public and available for both host and -// device since approximately 2019, so forcing it to be device-only would break -// existing code in the wild. -#if defined(USE_ROCM) +// Host pass of HIP compiler needs C10_WARP_SIZE defined to _something_ so we +// set it to something unreasonable to trigger obvious host code errors. + namespace at::cuda { TORCH_CUDA_CPP_API int warp_size(); } -#if defined(__HIPCC__) -static __host__ inline int C10_WARP_SIZE_INTERNAL() { +#ifdef __HIPCC__ +static inline int __host__ C10_WARP_SIZE_INTERNAL() { return at::cuda::warp_size(); } -// NOTE: __device__ C10_WARP_SIZE_INTERNAL -// For __SPIRV__, we must use dynamic warpSize. When not targeting __SPIRV__, -// we can use constexpr. This matches prior behavior. We preserve this for -// backward compatibility instead of forcing old code to use dynamic warpSize -// and losing constexpr. However, compiling for --offload-arch=amdgcnspirv -// could expose where C10_WARP_SIZE was used incorrectly where the dynamic -// warpSize is not allowed. -#if defined(__SPIRV__) -static __device__ inline int C10_WARP_SIZE_INTERNAL() { - return warpSize; -} -#else // __SPIRV__ -static __device__ inline constexpr int C10_WARP_SIZE_INTERNAL() { + +static inline constexpr int __device__ C10_WARP_SIZE_INTERNAL() { #if defined(__GFX9__) return 64; #else // __GFX9__ return 32; #endif // __GFX9__ } -#endif // __SPIRV__ -#if defined(__SPIRV__) -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 64 -#elif defined(__GFX9__) -#define C10_WARP_SIZE_LOWER_BOUND 64 -#define C10_WARP_SIZE_UPPER_BOUND 64 -#else -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 32 -#endif -#else // !__HIPCC__ +#else // __HIPCC__ static inline int C10_WARP_SIZE_INTERNAL() { return at::cuda::warp_size(); } -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 64 #endif // __HIPCC__ + #define C10_WARP_SIZE (C10_WARP_SIZE_INTERNAL()) -#else // !USE_ROCM +#define C10_WARP_SIZE_STATIC 64 + +#else // defined(USE_ROCM) #define C10_WARP_SIZE 32 -#define C10_WARP_SIZE_LOWER_BOUND 32 -#define C10_WARP_SIZE_UPPER_BOUND 32 -#endif // USE_ROCM +#endif #if defined(_MSC_VER) && _MSC_VER <= 1900 #define __func__ __FUNCTION__ @@ -676,7 +629,7 @@ __host__ __device__ // This macro is used to find older C++ compilers // that don't support move optimization for return values. -#if (defined(__GNUC__) && __GNUC__ < 13 && __cplusplus < 202002L) || \ +#if (defined(__GNUC__) && __GNUC__ < 13) || \ (defined(__clang_major__) && __clang_major__ < 13) #define C10_RETURN_MOVE_IF_OLD_COMPILER 1 #else diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/targets.bzl new file mode 100644 index 0000000..0ddce72 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/targets.bzl @@ -0,0 +1,14 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "torch_headeronly", + exported_headers = glob(["**/*.h"]), + header_namespace = "torch/headeronly", + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h index 9aa08c2..64479ba 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/BFloat16.h @@ -12,7 +12,7 @@ #include #include -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) #include #endif @@ -46,7 +46,7 @@ struct alignas(2) BFloat16 { /* implicit */ inline C10_HOST_DEVICE BFloat16(float value); inline C10_HOST_DEVICE operator float() const; -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) inline C10_HOST_DEVICE BFloat16(const __nv_bfloat16& value); explicit inline C10_HOST_DEVICE operator __nv_bfloat16() const; #endif @@ -124,9 +124,8 @@ C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion") /// Constructors inline C10_HOST_DEVICE BFloat16::BFloat16(float value) : -#if defined(__CUDACC__) && \ - (!defined(USE_ROCM) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 || \ - defined(USE_ROCM) && (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) && defined(__CUDA_ARCH__) && \ + __CUDA_ARCH__ >= 800 x(__bfloat16_as_ushort(__float2bfloat16(value))) #elif defined(__SYCL_DEVICE_ONLY__) && \ defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) @@ -140,7 +139,7 @@ inline C10_HOST_DEVICE BFloat16::BFloat16(float value) /// Implicit conversions inline C10_HOST_DEVICE BFloat16::operator float() const { -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) return __bfloat162float(*reinterpret_cast(&x)); #elif defined(__SYCL_DEVICE_ONLY__) && \ defined(SYCL_EXT_ONEAPI_BFLOAT16_MATH_FUNCTIONS) @@ -150,7 +149,7 @@ inline C10_HOST_DEVICE BFloat16::operator float() const { #endif } -#if defined(__CUDACC__) && (!defined(USE_ROCM) || (TORCH_HIP_VERSION >= 702)) +#if defined(__CUDACC__) && !defined(USE_ROCM) inline C10_HOST_DEVICE BFloat16::BFloat16(const __nv_bfloat16& value) { x = *reinterpret_cast(&value); } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/Half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/Half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/Half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/Half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/TypeSafeSignMath.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/bit_cast.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/c10/torch/headeronly/util/floating_point_utils.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/complex.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/complex.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/complex.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/complex.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/device.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/device.h similarity index 57% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/device.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/device.h index 41a8c6b..d789df8 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/device.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/device.h @@ -8,42 +8,38 @@ #pragma once -#include -#include +#include namespace executorch { namespace runtime { namespace etensor { -/// Represents the type of compute device. -/// Note: ExecuTorch Device is distinct from PyTorch Device. +/// Denotes the specific genre of compute device. +/// Subset of https://github.com/pytorch/pytorch/blob/main/c10/core/Device.h enum class DeviceType : int8_t { CPU = 0, - CUDA = 1, }; -/// Total number of device types, used for fixed-size registry arrays. -constexpr size_t kNumDeviceTypes = 2; - -/// An index representing a specific device; e.g. GPU 0 vs GPU 1. +/// An index representing a specific device; For cpu it should always be -1 or 0 using DeviceIndex = int8_t; /** * An abstraction for the compute device on which a tensor is located. + * ExecuTorch doesn't allow dynamic dispatching based on device, so this type is + * just a skeleton to allow certain kernels that expect device as an + * argument to still be run. * - * Tensors carry a Device to express where their underlying data resides - * (e.g. CPU host memory vs CUDA device memory). The runtime uses this to - * dispatch memory allocation to the appropriate device allocator. + * In ExecuTorch this is always expected to be CPU. */ struct Device final { using Type = DeviceType; /// Constructs a new `Device` from a `DeviceType` and an optional device /// index. - /* implicit */ Device(DeviceType type, DeviceIndex index = 0) + /* implicit */ Device(DeviceType type, DeviceIndex index = -1) : type_(type), index_(index) {} - /// Returns the type of device the tensor data resides on. + /// Returns the type of device this is. Only CPU is supported. DeviceType type() const noexcept { return type_; } @@ -53,22 +49,15 @@ struct Device final { return type_ == DeviceType::CPU; } - /// Returns the device index. + /// Returns the device index. Always 0 if specified or -1 if not provided. DeviceIndex index() const noexcept { + ET_CHECK(index_ == 0 || index_ == -1); return index_; } - bool operator==(const Device& other) const noexcept { - return type_ == other.type_ && index_ == other.index_; - } - - bool operator!=(const Device& other) const noexcept { - return !(*this == other); - } - private: DeviceType type_; - DeviceIndex index_ = 0; + DeviceIndex index_ = -1; }; } // namespace etensor diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/half.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/half.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/half.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/half.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/optional.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/optional.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/optional.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/optional.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/qint_types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/qint_types.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/qint_types.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/qint_types.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/scalar.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/scalar.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/scalar.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/scalar.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/scalar_type.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/scalar_type.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/scalar_type.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/scalar_type.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/string_view.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/string_view.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/string_view.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/string_view.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/targets.bzl new file mode 100644 index 0000000..5b6e67f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/targets.bzl @@ -0,0 +1,67 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Internal target for executor tensor. Clients should depend on + # :kernel_types below to be flexible with ATen Tensor and executor Tensor. + runtime.cxx_library( + name = "portable_type", + srcs = ["tensor_impl.cpp"], + exported_headers = [ + "tensor_options.h", + "optional.h", + "scalar.h", + "tensor.h", + "tensor_impl.h", + "string_view.h", + "device.h", + ], + # Only should be depended on by kernel_types:kernel_types, but various suffixes like Android and Static + # mean I cant just expose visibility to a single rule. + visibility = [ + "//executorch/backends/...", + "//executorch/extension/fb/dynamic_shim/...", + "//executorch/kernels/portable/cpu/...", + "//executorch/runtime/core/exec_aten/...", + "//executorch/runtime/core/portable_type/test/...", + ], + deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + exported_deps = [ + ":scalar_type", + "//executorch/runtime/core:core", + "//executorch/runtime/core:tensor_shape_dynamism", + "//executorch/runtime/core/exec_aten/util:dim_order_util", + "//executorch/runtime/core/exec_aten/util:scalar_type_util", + "//executorch/runtime/core/exec_aten/util:tensor_shape_to_c_string", + "//executorch/runtime/core:tag", + ], + ) + + # Set up a specific exported library for scalar_type to avoid circle dependency in ScalarTypeUtil.h + runtime.cxx_library( + name = "scalar_type", + exported_headers = [ + "bfloat16.h", + "bfloat16_math.h", + "complex.h", + "half.h", + "scalar_type.h", + "qint_types.h", + "bits_types.h", + ], + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + visibility = [ + "//executorch/extension/...", + "//executorch/runtime/core/exec_aten/util/...", + "//executorch/kernels/...", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_impl.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_impl.cpp similarity index 79% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_impl.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_impl.cpp index 113a1f0..64ecb73 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/portable_type/tensor_impl.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_impl.cpp @@ -39,33 +39,9 @@ ssize_t compute_numel(const TensorImpl::SizesType* sizes, ssize_t dim) { "Size must be non-negative, got %zd at dimension %zd", static_cast(sizes[i]), i); - numel *= sizes[i]; - } - return numel; -} - -::executorch::runtime::Result safe_numel( - const TensorImpl::SizesType* sizes, - ssize_t dim) { - ET_CHECK_OR_RETURN_ERROR( - dim == 0 || sizes != nullptr, - InvalidArgument, - "Sizes must be provided for non-scalar tensors"); - ssize_t numel = 1; - for (const auto i : c10::irange(dim)) { - ET_CHECK_OR_RETURN_ERROR( - sizes[i] >= 0, - InvalidArgument, - "Size must be non-negative, got %zd at dimension %zd", - static_cast(sizes[i]), - i); - ssize_t next_numel; - ET_CHECK_OR_RETURN_ERROR( - !c10::mul_overflows(numel, static_cast(sizes[i]), &next_numel), - InvalidArgument, - "Overflow computing numel at dimension %zd", - i); - numel = next_numel; + bool overflow = + c10::mul_overflows(numel, static_cast(sizes[i]), &numel); + ET_CHECK_MSG(!overflow, "numel overflowed"); } return numel; } @@ -77,9 +53,7 @@ TensorImpl::TensorImpl( void* data, DimOrderType* dim_order, StridesType* strides, - TensorShapeDynamism dynamism, - DeviceType device_type, - DeviceIndex device_index) + TensorShapeDynamism dynamism) : sizes_(sizes), dim_order_(dim_order), strides_(strides), @@ -88,15 +62,18 @@ TensorImpl::TensorImpl( numel_(compute_numel(sizes, dim)), numel_bound_(numel_), type_(type), - shape_dynamism_(dynamism), - device_(device_type, device_index) { + shape_dynamism_(dynamism) { ET_CHECK_MSG( isValid(type_), "Invalid type %" PRId8, static_cast(type_)); ET_CHECK_MSG(dim_ >= 0, "Dimension must be non-negative, got %zd", dim_); } size_t TensorImpl::nbytes() const { - return numel_ * elementSize(type_); + size_t result; + bool overflow = c10::mul_overflows( + static_cast(numel_), elementSize(type_), &result); + ET_CHECK_MSG(!overflow, "nbytes overflowed"); + return result; } // Return the size of one element of the tensor @@ -147,11 +124,7 @@ Error TensorImpl::internal_resize_contiguous(ArrayRef new_sizes) { // TODO(T175194371): Unbounded dynamic tensor resizing is not yet // supported: treat them as upper-bounded. case TensorShapeDynamism::DYNAMIC_UNBOUND: { - auto new_numel_result = safe_numel(new_sizes.data(), dim_); - if (!new_numel_result.ok()) { - return new_numel_result.error(); - } - const auto new_numel = new_numel_result.get(); + const auto new_numel = compute_numel(new_sizes.data(), dim_); ET_CHECK_OR_RETURN_ERROR( static_cast(new_numel) <= numel_bound_, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_impl.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_impl.h similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_impl.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_impl.h index b01d8fa..1e2b362 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_impl.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_impl.h @@ -10,11 +10,8 @@ #include #include -#include #include -#include #include -#include // Forward declaration of a helper that provides access to internal resizing // methods of TensorImpl. Real definition is in @@ -102,8 +99,6 @@ class TensorImpl { * @param strides Strides of the tensor at each dimension. Must contain `dim` * entries. * @param dynamism The mutability of the shape of the tensor. - * @param device_type The type of device where tensor data resides. - * @param device_index The device index for multi-device scenarios. */ TensorImpl( ScalarType type, @@ -112,9 +107,7 @@ class TensorImpl { void* data = nullptr, DimOrderType* dim_order = nullptr, StridesType* strides = nullptr, - TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC, - DeviceType device_type = DeviceType::CPU, - DeviceIndex device_index = 0); + TensorShapeDynamism dynamism = TensorShapeDynamism::STATIC); /** * Returns the size of the tensor in bytes. @@ -183,21 +176,6 @@ class TensorImpl { return shape_dynamism_; } - /// Returns the device where tensor data resides. - Device device() const { - return device_; - } - - /// Returns the type of device where tensor data resides. - DeviceType device_type() const { - return device_.type(); - } - - /// Returns the device index, or 0 if default/unspecified. - DeviceIndex device_index() const { - return device_.index(); - } - /// Returns a pointer of type T to the constant underlying data blob. template inline const T* data() const { @@ -283,9 +261,6 @@ class TensorImpl { /// Specifies the mutability of the shape of the tensor. const TensorShapeDynamism shape_dynamism_; - - /// Device where tensor data resides (CPU, CUDA, etc.) - Device device_; }; /** @@ -295,16 +270,6 @@ ssize_t compute_numel( const ::executorch::runtime::etensor::TensorImpl::SizesType* sizes, ssize_t dim); -/** - * Compute the number of elements based on the sizes of a tensor. - * Returns Error::InvalidArgument if any intermediate multiplication would - * overflow ssize_t, or if a size is negative. Prefer this over compute_numel() - * for paths that can propagate an Error upward. - */ -::executorch::runtime::Result safe_numel( - const ::executorch::runtime::etensor::TensorImpl::SizesType* sizes, - ssize_t dim); - /// Appropriate format specifier for the result of calling /// size(). Must be used instead of using zd directly to support ATen /// mode. @@ -334,7 +299,6 @@ namespace executor { // TODO(T197294990): Remove these deprecated aliases once all users have moved // to the new `::executorch` namespaces. using ::executorch::runtime::etensor::compute_numel; -using ::executorch::runtime::etensor::safe_numel; using ::executorch::runtime::etensor::TensorImpl; } // namespace executor } // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_options.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_options.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/portable_type/tensor_options.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/tensor_options.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/CMakeLists.txt new file mode 100644 index 0000000..b1f57a9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs + bfloat16_test.cpp + dont_shadow_complex_test.c + half_test.cpp + optional_test.cpp + scalar_test.cpp + tensor_impl_test.cpp + tensor_test.cpp +) + +et_cxx_test(runtime_core_portable_type_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/bfloat16_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/bfloat16_test.cpp new file mode 100644 index 0000000..505f80e --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/bfloat16_test.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include + +using executorch::runtime::etensor::BFloat16; +using executorch::runtime::etensor::internal::f32_from_bits; +using executorch::runtime::etensor::internal::round_to_nearest_even; + +namespace { +float float_from_bytes(uint32_t sign, uint32_t exponent, uint32_t fraction) { + // NOLINTNEXTLINE(cppcoreguidelines-init-variables) + uint32_t bytes; + bytes = 0; + bytes |= sign; + bytes <<= 8; + bytes |= exponent; + bytes <<= 23; + bytes |= fraction; + + // NOLINTNEXTLINE(cppcoreguidelines-init-variables) + float res; + std::memcpy(&res, &bytes, sizeof(res)); + return res; +} + +// Opposite of f32_from_bits. +uint16_t bits_from_f32(float src) { + uint32_t res = 0; + std::memcpy(&res, &src, sizeof(res)); + return res >> 16; +} + +TEST(BFloat16Conversion, FloatToBFloat16AndBack) { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float in[100]; + for (const auto i : c10::irange(100)) { + // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-avoid-magic-numbers) + in[i] = i + 1.25; + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + BFloat16 bfloats[100]; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float out[100]; + + for (const auto i : c10::irange(100)) { + bfloats[i].x = bits_from_f32(in[i]); + out[i] = f32_from_bits(bfloats[i].x); + + // The relative error should be less than 1/(2^7) since BFloat16 + // has 7 bits mantissa. + EXPECT_LE(std::fabs(out[i] - in[i]) / in[i], 1.0 / 128); + } +} + +TEST(BFloat16Conversion, FloatToBFloat16RNEAndBack) { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float in[100]; + for (const auto i : c10::irange(100)) { + // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-avoid-magic-numbers) + in[i] = i + 1.25; + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + BFloat16 bfloats[100]; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-magic-numbers,modernize-avoid-c-arrays) + float out[100]; + + for (const auto i : c10::irange(100)) { + bfloats[i].x = round_to_nearest_even(in[i]); + out[i] = f32_from_bits(bfloats[i].x); + + // The relative error should be less than 1/(2^7) since BFloat16 + // has 7 bits mantissa. + EXPECT_LE(std::fabs(out[i] - in[i]) / in[i], 1.0 / 128); + } +} + +TEST(BFloat16Conversion, NaN) { + float inNaN = float_from_bytes(0, 0xFF, 0x7FFFFF); + EXPECT_TRUE(std::isnan(inNaN)); + + BFloat16 a = BFloat16(inNaN); + float out = f32_from_bits(a.x); + + EXPECT_TRUE(std::isnan(out)); +} + +TEST(BFloat16Conversion, Inf) { + float inInf = float_from_bytes(0, 0xFF, 0); + EXPECT_TRUE(std::isinf(inInf)); + + BFloat16 a = BFloat16(inInf); + float out = f32_from_bits(a.x); + + EXPECT_TRUE(std::isinf(out)); +} + +TEST(BFloat16Conversion, SmallestDenormal) { + float in = std::numeric_limits::denorm_min(); // The smallest non-zero + // subnormal number + BFloat16 a = BFloat16(in); + float out = f32_from_bits(a.x); + + EXPECT_FLOAT_EQ(in, out); +} + +TEST(BFloat16Math, Addition) { + // This test verifies that if only first 7 bits of float's mantissa are + // changed after addition, we should have no loss in precision. + + // input bits + // S | Exponent | Mantissa + // 0 | 10000000 | 10010000000000000000000 = 3.125 + float input = float_from_bytes(0, 0, 0x40480000); + + // expected bits + // S | Exponent | Mantissa + // 0 | 10000001 | 10010000000000000000000 = 6.25 + float expected = float_from_bytes(0, 0, 0x40c80000); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + BFloat16 b; + b.x = bits_from_f32(input); + b = b + b; + + float res = f32_from_bits(b.x); + EXPECT_EQ(res, expected); +} + +TEST(BFloat16Math, Subtraction) { + // This test verifies that if only first 7 bits of float's mantissa are + // changed after subtraction, we should have no loss in precision. + + // input bits + // S | Exponent | Mantissa + // 0 | 10000001 | 11101000000000000000000 = 7.625 + float input = float_from_bytes(0, 0, 0x40f40000); + + // expected bits + // S | Exponent | Mantissa + // 0 | 10000000 | 01010000000000000000000 = 2.625 + float expected = float_from_bytes(0, 0, 0x40280000); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + BFloat16 b; + b.x = bits_from_f32(input); + b = b - 5; + + float res = f32_from_bits(b.x); + EXPECT_EQ(res, expected); +} + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +TEST(BFloat16Math, NextAfterZero) { + const BFloat16 zero{0}; + + auto check_nextafter = [](BFloat16 from, BFloat16 to, BFloat16 expected) { + BFloat16 actual = std::nextafter(from, to); + // Check for bitwise equality! + ASSERT_EQ(actual.x ^ expected.x, uint16_t{0}); + }; + check_nextafter(zero, zero, /*expected=*/zero); + check_nextafter(zero, -zero, /*expected=*/-zero); + check_nextafter(-zero, zero, /*expected=*/zero); + check_nextafter(-zero, -zero, /*expected=*/-zero); +} + +float BinaryToFloat(uint32_t bytes) { + // NOLINTNEXTLINE(cppcoreguidelines-init-variables) + float res; + std::memcpy(&res, &bytes, sizeof(res)); + return res; +} + +struct BFloat16TestParam { + uint32_t input; + uint16_t rne; +}; + +class BFloat16Test : public ::testing::Test, + public ::testing::WithParamInterface {}; + +TEST_P(BFloat16Test, BFloat16RNETest) { + float value = BinaryToFloat(GetParam().input); + uint16_t rounded = round_to_nearest_even(value); + EXPECT_EQ(GetParam().rne, rounded); +} + +INSTANTIATE_TEST_SUITE_P( + BFloat16TestInstantiation, + BFloat16Test, + ::testing::Values( + BFloat16TestParam{0x3F848000, 0x3F84}, + BFloat16TestParam{0x3F848010, 0x3F85}, + BFloat16TestParam{0x3F850000, 0x3F85}, + BFloat16TestParam{0x3F858000, 0x3F86}, + BFloat16TestParam{0x3FFF8000, 0x4000})); + +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/dont_shadow_complex_test.c b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/dont_shadow_complex_test.c new file mode 100644 index 0000000..5654216 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/dont_shadow_complex_test.c @@ -0,0 +1,9 @@ +// This include statement should get the C99 standard header +// complex.h. At one point we messed up our c10 include setup such +// that it instead included runtime/core/portable_type/complex.h. This +// is a regression test for that issue. +#include + +#ifndef complex +#warning "complex.h does not define complex" +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/half_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/half_test.cpp new file mode 100644 index 0000000..0d5dca0 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/half_test.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +using executorch::runtime::etensor::Half; + +namespace { + +/** + * According to the precision limitations listed here: + * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Precision_limitations + * The max precision error for a half in the range [2^n, 2^(n+1)] is 2^(n-10) + */ +float toleranceFloat16(float f) { + return pow(2, static_cast(log2(fabs(f))) - 10); +} + +bool closeEnoughFloat16(float a, float b) { + return fabs(a - b) <= toleranceFloat16(fmax(fabs(a), fabs(b))); +} + +} // namespace + +/// Arithmetic with Halfs + +TEST(HalfTest, ArithmeticHalfAdd) { + float af = 104.35; + Half ah(af); + float bf = 72.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah + bh, af + bf)); + ah += bh; + af += bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +TEST(HalfTest, ArithmeticHalfSub) { + float af = 31.4; + Half ah(af); + float bf = 20.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah - bh, af - bf)); + ah -= bh; + af -= bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +TEST(HalfTest, ArithmeticHalfMul) { + float af = 85.5; + Half ah(af); + float bf = 17.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah * bh, af * bf)); + ah *= bh; + af *= bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +TEST(HalfTest, ArithmeticHalfDiv) { + float af = 96.9; + Half ah(af); + float bf = 12.5; + Half bh(bf); + EXPECT_TRUE(closeEnoughFloat16(ah / bh, af / bf)); + ah /= bh; + af /= bf; + EXPECT_TRUE(closeEnoughFloat16(ah, af)); +} + +/// Arithmetic with floats + +TEST(HalfTest, ArithmeticFloatAdd) { + float af = 104.35; + Half ah(af); + float b = 72.5; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticFloatSub) { + float af = 31.4; + Half ah(af); + float b = 20.5; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticFloatMul) { + float af = 85.5; + Half ah(af); + float b = 17.5; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticFloatDiv) { + float af = 96.9; + Half ah(af); + float b = 12.5; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} + +/// Arithmetic with doubles + +TEST(HalfTest, ArithmeticDoubleAdd) { + float af = 104.35; + Half ah(af); + double b = 72.5; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticDoubleSub) { + float af = 31.4; + Half ah(af); + double b = 20.5; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticDoubleMul) { + float af = 85.5; + Half ah(af); + double b = 17.5; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticDoubleDiv) { + float af = 96.9; + Half ah(af); + double b = 12.5; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} + +/// Arithmetic with ints + +TEST(HalfTest, ArithmeticInt32Add) { + float af = 104.35; + Half ah(af); + int32_t b = 72; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticInt32Sub) { + float af = 31.4; + Half ah(af); + int32_t b = 20; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticInt32Mul) { + float af = 85.5; + Half ah(af); + int32_t b = 17; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticInt32Div) { + float af = 96.9; + Half ah(af); + int32_t b = 12; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} + +//// Arithmetic with int64_t + +TEST(HalfTest, ArithmeticInt64Add) { + float af = 104.35; + Half ah(af); + int64_t b = 72; + EXPECT_TRUE(closeEnoughFloat16(ah + b, af + b)); + EXPECT_TRUE(closeEnoughFloat16(b + ah, b + af)); +} + +TEST(HalfTest, ArithmeticInt64Sub) { + float af = 31.4; + Half ah(af); + int64_t b = 20; + EXPECT_TRUE(closeEnoughFloat16(ah - b, af - b)); + EXPECT_TRUE(closeEnoughFloat16(b - ah, b - af)); +} + +TEST(HalfTest, ArithmeticInt64Mul) { + float af = 85.5; + Half ah(af); + int64_t b = 17; + EXPECT_TRUE(closeEnoughFloat16(ah * b, af * b)); + EXPECT_TRUE(closeEnoughFloat16(b * ah, b * af)); +} + +TEST(HalfTest, ArithmeticInt64Div) { + float af = 96.9; + Half ah(af); + int64_t b = 12; + EXPECT_TRUE(closeEnoughFloat16(ah / b, af / b)); + EXPECT_TRUE(closeEnoughFloat16(b / ah, b / af)); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/optional_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/optional_test.cpp new file mode 100644 index 0000000..60d835d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/optional_test.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::etensor::nullopt; +using executorch::runtime::etensor::optional; + +// Test that optional::value_type matches the template parameter type. +static_assert( + std::is_same::value_type, int32_t>::value, + "Unexpected optional::value_type"); +static_assert( + std::is_same::value_type, std::string>::value, + "Unexpected optional::value_type"); + +TEST(TestOptional, DefaultHasNoValue) { + optional o; + EXPECT_FALSE(o.has_value()); +} + +TEST(TestOptional, NulloptHasNoValue) { + optional o(nullopt); + EXPECT_FALSE(o.has_value()); +} + +TEST(TestOptional, ValueOfEmptyOptionalShouldThrow) { + optional o; + EXPECT_FALSE(o.has_value()); + + EXPECT_THROW({ (void)o.value(); }, std::bad_optional_access); +} + +TEST(TestOptional, IntValue) { + optional o(15); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), 15); +} + +TEST(TestOptional, NonTrivialValueType) { + optional o("hey"); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), "hey"); +} + +TEST(TestOptional, ConstValue) { + const optional o("hey"); + auto s = o.value(); // If this compiles, we're good. + EXPECT_EQ(o.value(), "hey"); +} + +TEST(TestOptional, CopyCtorWithValue) { + optional o1(15); + optional o2(o1); + + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), 15); +} + +TEST(TestOptional, CopyCtorWithNoValue) { + optional o1; + optional o2(o1); + + EXPECT_FALSE(o2.has_value()); +} + +TEST(TestOptional, CopyAssignTrivial) { + optional o1(1); + optional o2(2); + o1 = o2; + + EXPECT_EQ(o1.value(), 2); +} + +TEST(TestOptional, CopyAssignNonTrivial) { + optional o1("abcde"); + optional o2("foo"); + o1 = o2; + + EXPECT_EQ(o1.value(), "foo"); +} + +TEST(TestOptional, CopyAssignNone) { + optional o1(2); + optional o2; + o1 = o2; + EXPECT_FALSE(o1.has_value()); +} + +TEST(TestOptional, MoveCtorWithNoValue) { + optional o1; + optional o2(std::move(o1)); + + EXPECT_FALSE(o2.has_value()); +} + +TEST(TestOptional, MoveCtorWithValue) { + optional o1(15); + optional o2(std::move(o1)); + + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), 15); +} + +TEST(TestOptional, MoveCtorNonTrivialType) { + optional o1("abc"); + optional o2(std::move(o1)); + + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), "abc"); +} + +optional function_returning_optional_of(int32_t value) { + return value; +} + +TEST(TestOptional, ImplicitReturnOfValue) { + auto o = function_returning_optional_of(21); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), 21); +} + +optional function_returning_nullopt() { + return nullopt; +} + +TEST(TestOptional, ImplicitReturnOfNullopt) { + auto o = function_returning_nullopt(); + EXPECT_FALSE(o.has_value()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/scalar_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/scalar_test.cpp new file mode 100644 index 0000000..fd211f9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/scalar_test.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +using executorch::runtime::etensor::Scalar; + +TEST(ScalarTest, ToScalarType) { + Scalar s_d((double)3.141); + EXPECT_EQ(s_d.to(), 3.141); + Scalar s_i((int64_t)3); + EXPECT_EQ(s_i.to(), 3); + Scalar s_b(true); + EXPECT_EQ(s_b.to(), true); +} + +TEST(ScalarTest, ToIntForFalseScalarPasses) { + Scalar s_b(false); + EXPECT_FALSE(s_b.isIntegral(/*includeBool=*/false)); + EXPECT_TRUE(s_b.isIntegral(/*includeBool=*/true)); + EXPECT_EQ(s_b.to(), 0); +} + +TEST(ScalarTest, ToIntForTrueScalarPasses) { + Scalar s_b(true); + EXPECT_FALSE(s_b.isIntegral(/*includeBool=*/false)); + EXPECT_TRUE(s_b.isIntegral(/*includeBool=*/true)); + EXPECT_EQ(s_b.to(), 1); +} + +TEST(ScalarTest, IntConstructor) { + int int_val = 1; + Scalar s_int(int_val); + int32_t int32_val = 1; + Scalar s_int32(int32_val); + int64_t int64_val = 1; + Scalar s_int64(int64_val); + EXPECT_EQ(s_int.to(), s_int32.to()); + EXPECT_EQ(s_int32.to(), s_int64.to()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/targets.bzl new file mode 100644 index 0000000..d8e82a1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/targets.bzl @@ -0,0 +1,58 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "bfloat16_test", + srcs = ["bfloat16_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "optional_test", + srcs = ["optional_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "tensor_test", + srcs = ["tensor_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "half_test", + srcs = ["half_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "scalar_test", + srcs = ["scalar_test.cpp"], + deps = [ + "//executorch/runtime/core/portable_type:portable_type", + ], + ) + + runtime.cxx_test( + name = "tensor_impl_test", + srcs = ["tensor_impl_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten/util:tensor_util", + "//executorch/runtime/core/portable_type:portable_type", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_impl_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_impl_test.cpp new file mode 100644 index 0000000..08b26c6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_impl_test.cpp @@ -0,0 +1,460 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace ::testing; + +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::TensorShapeDynamism; +using executorch::runtime::etensor::ScalarType; +using executorch::runtime::etensor::TensorImpl; +using SizesType = TensorImpl::SizesType; +using DimOrderType = TensorImpl::DimOrderType; +using StridesType = TensorImpl::StridesType; +using executorch::runtime::internal::resize_tensor_impl; + +class TensorImplTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorImplTest, TestCtorAndGetters) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data, dim_order, strides); + + EXPECT_EQ(t.numel(), 6); + EXPECT_EQ(t.nbytes(), 6 * 4); // 6 4 byte floats + EXPECT_EQ(t.dim(), 2); + EXPECT_EQ(t.scalar_type(), ScalarType::Float); + EXPECT_EQ(t.element_size(), 4); + EXPECT_EQ(t.data(), data); + EXPECT_EQ(t.mutable_data(), data); + EXPECT_EQ(t.sizes().data(), sizes); + EXPECT_EQ(t.sizes().size(), 2); + EXPECT_EQ(t.strides().data(), strides); + EXPECT_EQ(t.strides().size(), 2); +} + +// Verify that contig means stride[0] >= stride[1] >= ... stride[size-1] == 1 +TEST_F(TensorImplTest, TestSetSizesContigContract) { + const int RANK = 5; + std::default_random_engine generator; + std::uniform_int_distribution distribution(1, 100); + SizesType sizes[RANK] = {100, 100, 100, 100, 100}; + DimOrderType dim_order[RANK] = {0, 1, 2, 3, 4}; + StridesType strides[RANK] = {100000000, 1000000, 10000, 100, 1}; + float* data = nullptr; + TensorImpl t( + ScalarType::Float, + RANK, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + SizesType new_sizes[RANK] = {0, 0, 0, 0, 0}; + // assign random sizes between 1 and 100 + for (const auto i : c10::irange(RANK)) { + new_sizes[i] = distribution(generator); + } + Error err = resize_tensor_impl(&t, {new_sizes, RANK}); + EXPECT_EQ(err, Error::Ok); + + auto strides_ref = t.strides(); + StridesType prev = strides_ref[0]; + for (auto stride : strides_ref) { + EXPECT_LE(stride, prev); + } + EXPECT_EQ(t.strides()[strides_ref.size() - 1], 1); +} + +TEST_F(TensorImplTest, TestSetSizesContigZeroSizes) { + SizesType sizes[3] = {2, 0, 3}; + DimOrderType dim_order[3] = {0, 1, 2}; + StridesType strides[3] = {3, 3, 1}; + float* data = nullptr; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + SizesType new_sizes_1[3] = {1, 0, 2}; + Error err = resize_tensor_impl(&t, {new_sizes_1, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 0); + + // Treat 0 dimensions as size 1 for stride calculation as thats what aten does + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 2); + EXPECT_EQ(strides_ref[2], 1); + + // Numel is 0 for tensors with a 0 sized dimension + EXPECT_EQ(t.numel(), 0); +} + +TEST_F(TensorImplTest, TestSetSizesContigStatic) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data, dim_order, strides); + + SizesType new_sizes_1[2] = {3, 2}; + Error err = resize_tensor_impl(&t, {new_sizes_1, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 2); + + // strides shouldnt change + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_2[2] = {2, 2}; + // Can't change size of a StaticShape Tensor + err = resize_tensor_impl(&t, {new_sizes_2, 2}); + EXPECT_NE(err, Error::Ok); + + SizesType new_sizes_3[1] = {2}; + // Can't change rank of any Tensor + err = resize_tensor_impl(&t, {new_sizes_3, 1}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestSetSizesContigUpperBounded) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t( + ScalarType::Float, + 2, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + SizesType new_sizes_1[2] = {1, 1}; + // Can resize down + Error err = resize_tensor_impl(&t, {new_sizes_1, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 1); + + // strides contiguous + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 1); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_2[2] = {3, 2}; + // Can resize back up + err = resize_tensor_impl(&t, {new_sizes_2, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 2); + + // Back to original strides + strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_3[2] = {4, 2}; + // Can't execeed capacity of UpperBounded Tensor + err = resize_tensor_impl(&t, {new_sizes_3, 2}); + EXPECT_NE(err, Error::Ok); + + SizesType new_sizes_4[1] = {4}; + // Can't change rank of any Tensor + err = resize_tensor_impl(&t, {new_sizes_4, 1}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestZeroDimSetEmptySizesContig) { + SizesType sizes[0] = {}; + DimOrderType dim_order[0] = {}; + StridesType strides[0] = {}; + float data[1] = {1.0}; + TensorImpl t( + ScalarType::Float, + 0, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_BOUND); + + ArrayRef new_sizes_empty{}; + // Can resize with empty sizes + Error err = resize_tensor_impl(&t, new_sizes_empty); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 0); + + SizesType new_sizes_1[1] = {1}; + // Can't change rank of tensor + err = resize_tensor_impl(&t, {new_sizes_1, 1}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestSetSizesContigUnbounded) { + SizesType sizes[2] = {3, 2}; + DimOrderType dim_order[2] = {0, 1}; + StridesType strides[2] = {2, 1}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t( + ScalarType::Float, + 2, + sizes, + data, + dim_order, + strides, + TensorShapeDynamism::DYNAMIC_UNBOUND); + + SizesType new_sizes_1[2] = {1, 1}; + // Can resize down + Error err = resize_tensor_impl(&t, {new_sizes_1, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 1); + + // strides contiguous + auto strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 1); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_2[2] = {3, 2}; + // Can resize back up + err = resize_tensor_impl(&t, {new_sizes_2, 2}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.size(1), 2); + + // Back to original strides + strides_ref = t.strides(); + EXPECT_EQ(strides_ref[0], 2); + EXPECT_EQ(strides_ref[1], 1); + + SizesType new_sizes_4[1] = {4}; + // Can't change rank of any Tensor + err = resize_tensor_impl(&t, {new_sizes_4, 1}); + EXPECT_NE(err, Error::Ok); + + // TODO(T175194371): For now, we can't resize past the original capacity. + // Once we can, this test should check for that ability. + + SizesType new_sizes_3[2] = {4, 2}; + // Can't execeed original capacity. + err = resize_tensor_impl(&t, {new_sizes_3, 2}); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(TensorImplTest, TestDynamicTensorNoStridesDimOrder) { + SizesType sizes[3] = {2, 3, 4}; + float data[24] = {0}; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.numel(), 24); + EXPECT_EQ(t.nbytes(), 24 * sizeof(float)); + + SizesType new_sizes[3] = {3, 2, 4}; + Error err = resize_tensor_impl(&t, {new_sizes, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.size(0), 3); + EXPECT_EQ(t.size(1), 2); + EXPECT_EQ(t.size(2), 4); + EXPECT_EQ(t.numel(), 3 * 2 * 4); + + const float* y = t.data(); + EXPECT_EQ(y, data); +} + +TEST_F(TensorImplTest, TestDynamicTensorNoStridesDimOrderResizeDown) { + SizesType sizes[3] = {4, 4, 4}; + float data[64] = {0}; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.numel(), 64); + EXPECT_EQ(t.nbytes(), 64 * sizeof(float)); + + SizesType new_sizes[3] = {2, 2, 2}; + Error err = resize_tensor_impl(&t, {new_sizes, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.size(0), 2); + EXPECT_EQ(t.size(1), 2); + EXPECT_EQ(t.size(2), 2); + EXPECT_EQ(t.numel(), 2 * 2 * 2); + + const float* y = t.data(); + EXPECT_EQ(y, data); +} + +TEST_F(TensorImplTest, TestDynamicTensorNoStridesDimOrderResizeZeroDim) { + SizesType sizes[3] = {4, 4, 4}; + float data[64] = {0}; + TensorImpl t( + ScalarType::Float, + 3, + sizes, + data, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.numel(), 64); + EXPECT_EQ(t.nbytes(), 64 * sizeof(float)); + + SizesType new_sizes[3] = {0, 4, 4}; + Error err = resize_tensor_impl(&t, {new_sizes, 3}); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(t.dim(), 3); + EXPECT_EQ(t.size(0), 0); + EXPECT_EQ(t.size(1), 4); + EXPECT_EQ(t.size(2), 4); + EXPECT_EQ(t.numel(), 0); + + const float* y = t.data(); + EXPECT_EQ(y, data); +} + +TEST_F(TensorImplTest, TestWriteRead) { + SizesType sizes[1] = {1}; + DimOrderType dim_order[1] = {0}; + StridesType strides[1] = {1}; + float data[1] = {1.0}; + TensorImpl t(ScalarType::Float, 1, sizes, data, dim_order, strides); + + const float* y = t.data(); + EXPECT_EQ(y[0], 1.0); + + float* x = t.mutable_data(); + x[0] = 22.0; + + EXPECT_EQ(y[0], 22.0); +} + +TEST_F(TensorImplTest, TestInvalidScalarType) { + SizesType sizes[2] = {3, 2}; + ET_EXPECT_DEATH(TensorImpl t(static_cast(-1), 2, sizes), ""); +} + +TEST_F(TensorImplTest, TestNegativeDimension) { + SizesType sizes[2] = {3, 2}; + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, -1, sizes), ""); +} + +TEST_F(TensorImplTest, TestNullSizesNonZeroDim) { + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, 2, nullptr), ""); +} + +TEST_F(TensorImplTest, TestNonNegativeSizes) { + SizesType sizes[2] = {3, -2}; + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, 2, sizes), ""); +} + +TEST_F(TensorImplTest, TestEmptyTensor) { + SizesType sizes[2] = {0, 0}; + TensorImpl t(ScalarType::Float, 2, sizes); + EXPECT_EQ(t.numel(), 0); + EXPECT_EQ(t.data(), nullptr); +} + +TEST_F(TensorImplTest, TestTensorWithNoElementsButAllocatedMemory) { + SizesType sizes[2] = {0, 0}; + float data[1] = {1.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data); + EXPECT_EQ(t.numel(), 0); + EXPECT_EQ(t.data(), data); +} + +TEST_F(TensorImplTest, TestTensorWithShapeButNoMemory) { + SizesType sizes[2] = {3, 2}; + TensorImpl t(ScalarType::Float, 2, sizes); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), nullptr); +} + +TEST_F(TensorImplTest, TestNormalTensor) { + SizesType sizes[2] = {3, 2}; + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + TensorImpl t(ScalarType::Float, 2, sizes, data); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), data); +} + +TEST_F(TensorImplTest, TestResizingTensorToZeroAndBack) { + SizesType sizes[2] = {3, 2}; + TensorImpl t( + ScalarType::Float, + 2, + sizes, + nullptr, + nullptr, + nullptr, + TensorShapeDynamism::DYNAMIC_BOUND); + + float data[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + t.set_data(data); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), data); + + SizesType zero_sizes[2] = {0, 0}; + t.set_sizes_contiguous({zero_sizes, 2}); + EXPECT_EQ(t.numel(), 0); + EXPECT_EQ(t.data(), data); + + SizesType new_sizes[2] = {3, 2}; + t.set_sizes_contiguous({new_sizes, 2}); + EXPECT_GT(t.numel(), 0); + EXPECT_EQ(t.data(), data); +} + +TEST_F(TensorImplTest, TestNbytesOverflow) { + SizesType sizes[3] = { + static_cast(1 << 21), + static_cast(1 << 21), + static_cast(1 << 21)}; + ET_EXPECT_DEATH(TensorImpl t(ScalarType::Float, 3, sizes), ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_test.cpp new file mode 100644 index 0000000..714cdc2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/portable_type/test/tensor_test.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +using executorch::runtime::etensor::ScalarType; +using executorch::runtime::etensor::Tensor; +using executorch::runtime::etensor::TensorImpl; + +class TensorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(TensorTest, InvalidScalarType) { + TensorImpl::SizesType sizes[1] = {1}; + + // Undefined, which is sort of a special case since it's not part of the + // iteration macros but is still a part of the enum. + ET_EXPECT_DEATH({ TensorImpl y(ScalarType::Undefined, 1, sizes); }, ""); + + // Some out-of-range types, also demonstrating that NumOptions is not really a + // scalar type. + ET_EXPECT_DEATH({ TensorImpl y(ScalarType::NumOptions, 1, sizes); }, ""); + ET_EXPECT_DEATH( + { TensorImpl y(static_cast(127), 1, sizes); }, ""); + ET_EXPECT_DEATH({ TensorImpl y(static_cast(-1), 1, sizes); }, ""); +} + +TEST_F(TensorTest, SetData) { + TensorImpl::SizesType sizes[1] = {5}; + TensorImpl::DimOrderType dim_order[1] = {0}; + int32_t data[5] = {0, 0, 1, 0, 0}; + auto a_impl = TensorImpl(ScalarType::Int, 1, sizes, data, dim_order, nullptr); + auto a = Tensor(&a_impl); + EXPECT_EQ(a.const_data_ptr(), data); + a.set_data(nullptr); + EXPECT_EQ(a.const_data_ptr(), nullptr); +} + +TEST_F(TensorTest, Strides) { + TensorImpl::SizesType sizes[2] = {2, 2}; + TensorImpl::DimOrderType dim_order[2] = {0, 1}; + int32_t data[4] = {0, 0, 1, 1}; + TensorImpl::StridesType strides[2] = {2, 1}; + auto a_impl = TensorImpl(ScalarType::Int, 2, sizes, data, dim_order, strides); + Tensor a(&a_impl); + + EXPECT_EQ(a_impl.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.const_data_ptr()[0], 0); + EXPECT_EQ(a.const_data_ptr()[0 + a.strides()[0]], 1); +} + +TEST_F(TensorTest, ModifyDataOfConstTensor) { + TensorImpl::SizesType sizes[1] = {1}; + TensorImpl::DimOrderType dim_order[2] = {0}; + int32_t data[1] = {1}; + auto a_impl = TensorImpl(ScalarType::Int, 1, sizes, data, dim_order); + const Tensor a(&a_impl); + a.mutable_data_ptr()[0] = 0; + + EXPECT_EQ(a_impl.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.scalar_type(), ScalarType::Int); + EXPECT_EQ(a.const_data_ptr()[0], 0); +} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/result.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/result.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/result.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/result.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/span.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/span.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/span.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/span.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tag.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tag.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tag.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tag.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tag.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tag.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tag.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tag.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/targets.bzl new file mode 100644 index 0000000..2c13cdb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/targets.bzl @@ -0,0 +1,157 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def event_tracer_enabled(): + return native.read_config("executorch", "event_tracer_enabled", "false") == "true" + +def get_event_tracer_flags(): + event_tracer_flags = [] + if event_tracer_enabled(): + event_tracer_flags += ["-DET_EVENT_TRACER_ENABLED"] + elif not runtime.is_oss: + event_tracer_flags += select ({ + "DEFAULT": [], + "fbsource//xplat/executorch/tools/buck/constraints:event-tracer-enabled" : ["-DET_EVENT_TRACER_ENABLED"] + }) + return event_tracer_flags + +def build_sdk(): + return native.read_config("executorch", "build_sdk", "false") == "true" + +def get_sdk_flags(): + sdk_flags = [] + if build_sdk(): + sdk_flags += ["-DEXECUTORCH_BUILD_DEVTOOLS"] + return sdk_flags + +def enable_enum_strings(): + return native.read_config("executorch", "enable_enum_strings", "true") == "true" + +def get_core_flags(): + core_flags = [] + core_flags += ["-DET_ENABLE_ENUM_STRINGS=" + ("1" if enable_enum_strings() else "0")] + return core_flags + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "core", + exported_headers = [ + "array_ref.h", # TODO(T157717874): Migrate all users to span and then move this to portable_type + "data_loader.h", + "defines.h", + "error.h", + "freeable_buffer.h", + "function_ref.h", + "result.h", + "span.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = get_core_flags(), + exported_deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_library( + name = "tensor_shape_dynamism", + exported_headers = [ + "tensor_shape_dynamism.h", + ], + visibility = [ + "//executorch/runtime/core/exec_aten/...", + "//executorch/runtime/core/portable_type/...", + ], + ) + + runtime.cxx_library( + name = "memory_allocator", + exported_headers = [ + "hierarchical_allocator.h", + "memory_allocator.h", + ], + exported_deps = [ + ":core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + visibility = ["PUBLIC"], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + runtime.cxx_library( + name = "evalue" + aten_suffix, + exported_headers = [ + "evalue.h", + ], + srcs = ["evalue.cpp"], + visibility = ["PUBLIC"], + exported_deps = [ + ":core", + ":tag", + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "event_tracer" + aten_suffix, + exported_headers = [ + "event_tracer.h", + "event_tracer_hooks.h", + "event_tracer_hooks_delegate.h", + ], + visibility = ["PUBLIC"], + exported_preprocessor_flags = get_event_tracer_flags() + get_sdk_flags(), + exported_deps = [ + "//executorch/runtime/platform:platform", + "//executorch/runtime/core:evalue" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "named_data_map" + aten_suffix, + exported_headers = [ + "named_data_map.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + ":tensor_layout" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + ], + ) + + + runtime.cxx_library( + name = "tensor_layout" + aten_suffix, + srcs = ["tensor_layout.cpp"], + exported_headers = ["tensor_layout.h"], + deps = [ + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + exported_deps = [ + ":core", + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + ], + visibility = ["//executorch/..."], + ) + + runtime.cxx_library( + name = "tag", + srcs = ["tag.cpp"], + exported_headers = [ + "tag.h", + ], + exported_deps = [ + ":core", + "//executorch/runtime/platform:compiler", + ], + visibility = [ + "//executorch/...", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tensor_layout.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tensor_layout.cpp similarity index 77% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tensor_layout.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tensor_layout.cpp index 97abe0b..d33f79f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/tensor_layout.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tensor_layout.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -20,25 +19,15 @@ namespace { Result calculate_nbytes( const Span& sizes, const executorch::aten::ScalarType& scalar_type) { - size_t n = 1; + ssize_t n = 1; for (const auto i : c10::irange(sizes.size())) { if (sizes[i] < 0) { return Error::InvalidArgument; } - size_t next = 0; - if (c10::mul_overflows(n, static_cast(sizes[i]), &next)) { - return Error::InvalidArgument; - } - n = next; + n *= sizes[i]; } // Use the full namespace to disambiguate from c10::elementSize. - const size_t elem_size = - static_cast(executorch::runtime::elementSize(scalar_type)); - size_t total = 0; - if (c10::mul_overflows(n, elem_size, &total)) { - return Error::InvalidArgument; - } - return total; + return n * executorch::runtime::elementSize(scalar_type); } } // namespace diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tensor_layout.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tensor_layout.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tensor_layout.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tensor_layout.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tensor_shape_dynamism.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tensor_shape_dynamism.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/tensor_shape_dynamism.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/tensor_shape_dynamism.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/CMakeLists.txt new file mode 100644 index 0000000..bdc427b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# @generated by test/utils/generate_gtest_cmakelists.py +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +set(_test_srcs + array_ref_test.cpp + error_handling_test.cpp + evalue_test.cpp + event_tracer_test.cpp + freeable_buffer_test.cpp + function_ref_test.cpp + hierarchical_allocator_test.cpp + memory_allocator_test.cpp + span_test.cpp +) + +et_cxx_test(runtime_core_test SOURCES ${_test_srcs} EXTRA_LIBS) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/array_ref_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/array_ref_test.cpp new file mode 100644 index 0000000..7fb8ee2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/array_ref_test.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; + +TEST(TestArrayRef, ImplicitTypeConversion) { + ArrayRef oneElement_1 = {1}; + EXPECT_EQ(oneElement_1.size(), 1); + + ArrayRef oneElement_2 = 1; + EXPECT_EQ(oneElement_2.size(), 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/error_handling_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/error_handling_test.cpp new file mode 100644 index 0000000..c1d48c8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/error_handling_test.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include +#include +#include + +using executorch::runtime::Error; +using executorch::runtime::Result; + +static void* test_ptr = static_cast((uintptr_t*)0xDEADBEEF); + +Result get_abs(int64_t num) { + if (num >= 0) { + return static_cast(num); + } else { + return Error::InvalidArgument; + } +} + +Result get_op_name(int64_t op) { + auto abs_result = get_abs(op); + if (!abs_result.ok()) { + return abs_result.error(); + } + auto unsigned_op = abs_result.get(); + + switch (unsigned_op) { + case 0: + return std::string("Zero"); + case 1: + return std::string("One"); + default: + return Error::Internal; + } +} + +Result get_ptr(int64_t value) { + switch (value) { + case 0: + return nullptr; + case 1: + return test_ptr; + default: + return Error::InvalidArgument; + } +} + +class Uncopiable { + public: + explicit Uncopiable(uint32_t value) : value_(value) {} + Uncopiable(Uncopiable&& rhs) noexcept = default; + ~Uncopiable() = default; + + uint32_t getValue() const { + return value_; + } + + private: + // Delete other rule-of-five methods. + Uncopiable(const Uncopiable& rhs) = delete; + Uncopiable& operator=(Uncopiable&& rhs) noexcept = delete; + Uncopiable& operator=(const Uncopiable& rhs) = delete; + + uint32_t value_; +}; + +Result get_no_copy(uint32_t value) { + return Uncopiable(value); +} + +// A non-trivially-movable type. +class Movable { + public: + explicit Movable(size_t nbytes) : buffer_(malloc(nbytes)) {} + Movable(Movable&& rhs) noexcept : buffer_(rhs.buffer_) { + rhs.buffer_ = nullptr; + } + + ~Movable() { + // This will fail with a double-free if it wasn't moved properly. + free(buffer_); + } + + const void* buffer() const { + return buffer_; + } + + private: + // Delete other rule-of-five methods. + Movable(const Movable& rhs) = delete; + Movable& operator=(Movable&& rhs) noexcept = delete; + Movable& operator=(const Movable& rhs) = delete; + + mutable void* buffer_; +}; + +TEST(ErrorHandlingTest, ResultBasic) { + Result r(1); + ASSERT_TRUE(r.ok()); + ASSERT_EQ(r.error(), Error::Ok); + ASSERT_EQ(r.get(), 1); + ASSERT_EQ(*r, 1); +} + +TEST(ErrorHandlingTest, OkErrorNotPossible) { + executorch::runtime::runtime_init(); + Result r(Error::Ok); + ASSERT_FALSE(r.ok()); + ASSERT_NE(r.error(), Error::Ok); +} + +TEST(ErrorHandlingTest, ResultWithPrimitive) { + auto res = get_abs(100); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + + uint64_t unsigned_result = res.get(); + ASSERT_EQ(unsigned_result, 100); + unsigned_result = *res; + ASSERT_EQ(unsigned_result, 100); + + auto res2 = get_abs(-3); + ASSERT_FALSE(res2.ok()); + ASSERT_EQ(res2.error(), Error::InvalidArgument); +} + +TEST(ErrorHandlingTest, ResultWithCompound) { + auto res = get_op_name(0); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_EQ(res.get(), "Zero"); + ASSERT_EQ(*res, "Zero"); + + auto res2 = get_op_name(1); + ASSERT_TRUE(res2.ok()); + ASSERT_EQ(res2.error(), Error::Ok); + ASSERT_EQ(res2.get(), "One"); + ASSERT_EQ(*res2, "One"); + + auto res3 = get_op_name(2); + ASSERT_FALSE(res3.ok()); + ASSERT_EQ(res3.error(), Error::Internal); +} + +TEST(ErrorHandlingTest, ResultWithPointer) { + auto res = get_ptr(0); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_EQ(res.get(), nullptr); + ASSERT_EQ(*res, nullptr); + + auto res2 = get_ptr(1); + ASSERT_TRUE(res2.ok()); + ASSERT_EQ(res2.error(), Error::Ok); + ASSERT_EQ(res2.get(), test_ptr); + ASSERT_EQ(*res2, test_ptr); + + auto res3 = get_ptr(2); + ASSERT_FALSE(res3.ok()); + ASSERT_EQ(res3.error(), Error::InvalidArgument); +} + +TEST(ErrorHandlingTest, ResultUnwrap) { + auto res = get_op_name(-1); + ASSERT_FALSE(res.ok()); + ASSERT_EQ(res.error(), Error::InvalidArgument); +} + +TEST(ErrorHandlingTest, ResultNoCopy) { + auto res = get_no_copy(2); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_EQ(res.get().getValue(), 2); + ASSERT_EQ(res->getValue(), 2); + + auto res2 = std::move(res); + ASSERT_TRUE(res2.ok()); + ASSERT_EQ(res2.error(), Error::Ok); + ASSERT_EQ(res2.get().getValue(), 2); + ASSERT_EQ(res2->getValue(), 2); + + Uncopiable& uc = *res2; + ASSERT_EQ(uc.getValue(), 2); +} + +TEST(ErrorHandlingTest, ResultMove) { + executorch::runtime::runtime_init(); + + Result res = Movable(2); + ASSERT_TRUE(res.ok()); + ASSERT_EQ(res.error(), Error::Ok); + ASSERT_NE(res.get().buffer(), nullptr); + ASSERT_NE(res->buffer(), nullptr); + + const void* buffer = res->buffer(); + + // Move the value. + Movable m = std::move(*res); + // The target should point to the same buffer as the source originally did. + ASSERT_EQ(m.buffer(), buffer); + // The source inside the Result should no longer point to the buffer. + ASSERT_EQ(res->buffer(), nullptr); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/evalue_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/evalue_test.cpp new file mode 100644 index 0000000..9e91ad7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/evalue_test.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include +#include + +using namespace ::testing; + +using executorch::aten::ScalarType; +using executorch::runtime::BoxedEvalueList; +using executorch::runtime::EValue; +using executorch::runtime::Tag; +using executorch::runtime::testing::TensorFactory; + +class EValueTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +// An utility class used in tests to simulate objects that manage Tensors. +// The overloaded operator*() is used to return the underlying Tensor, mimicking +// behavior of smart pointers. +class TensorWrapper { + public: + explicit TensorWrapper(executorch::aten::Tensor tensor) + : tensor_(std::make_unique(std::move(tensor))) { + } + + executorch::aten::Tensor& operator*() { + return *tensor_; + } + + const executorch::aten::Tensor& operator*() const { + return *tensor_; + } + + operator bool() const { + return static_cast(tensor_); + } + + bool operator==(std::nullptr_t) const { + return tensor_ == nullptr; + } + + bool operator!=(std::nullptr_t) const { + return tensor_ != nullptr; + } + + private: + std::unique_ptr tensor_; +}; + +TEST_F(EValueTest, CopyTrivialType) { + EValue a; + EValue b(true); + EXPECT_TRUE(a.isNone()); + a = b; + EXPECT_TRUE(a.isBool()); + EXPECT_EQ(a.to(), true); + EXPECT_EQ(b.to(), true); +} + +TEST_F(EValueTest, CopyTensor) { + TensorFactory tf; + EValue a(tf.ones({3, 2})); + EValue b(tf.ones({1})); + EXPECT_EQ(a.toTensor().dim(), 2); + a = b; + EXPECT_EQ(a.toTensor().dim(), 1); +} + +TEST_F(EValueTest, TypeMismatchFatals) { + ET_EXPECT_DEATH( + { + auto e = EValue(true); + e.toInt(); + }, + ""); +} + +TEST_F(EValueTest, NoneByDefault) { + EValue e; + EXPECT_TRUE(e.isNone()); +} + +TEST_F(EValueTest, ToOptionalInt) { + EValue e((int64_t)5); + EXPECT_TRUE(e.isInt()); + EXPECT_FALSE(e.isNone()); + + std::optional o = e.toOptional(); + EXPECT_TRUE(o.has_value()); + EXPECT_EQ(o.value(), 5); +} + +TEST_F(EValueTest, NoneToOptionalInt) { + EValue e; + EXPECT_TRUE(e.isNone()); + + std::optional o = e.toOptional(); + EXPECT_FALSE(o.has_value()); +} + +TEST_F(EValueTest, ToOptionalScalar) { + executorch::aten::Scalar s((double)3.141); + EValue e(s); + EXPECT_TRUE(e.isScalar()); + EXPECT_FALSE(e.isNone()); + + std::optional o = + e.toOptional(); + EXPECT_TRUE(o.has_value()); + EXPECT_TRUE(o.value().isFloatingPoint()); + EXPECT_EQ(o.value().to(), 3.141); +} + +TEST_F(EValueTest, ScalarToType) { + executorch::aten::Scalar s_d((double)3.141); + EXPECT_EQ(s_d.to(), 3.141); + executorch::aten::Scalar s_i((int64_t)3); + EXPECT_EQ(s_i.to(), 3); + executorch::aten::Scalar s_b(true); + EXPECT_EQ(s_b.to(), true); +} + +TEST_F(EValueTest, NoneToOptionalScalar) { + EValue e; + EXPECT_TRUE(e.isNone()); + + std::optional o = + e.toOptional(); + EXPECT_FALSE(o.has_value()); +} + +TEST_F(EValueTest, NoneToOptionalTensor) { + EValue e; + EXPECT_TRUE(e.isNone()); + + std::optional o = + e.toOptional(); + EXPECT_FALSE(o.has_value()); +} + +TEST_F(EValueTest, ToScalarType) { + EValue e((int64_t)4); + auto o = e.toScalarType(); + EXPECT_EQ(o, executorch::aten::ScalarType::Long); + EValue f((int64_t)4); + auto o2 = e.toOptional(); + EXPECT_TRUE(o2.has_value()); + EXPECT_EQ(o2.value(), executorch::aten::ScalarType::Long); +} + +TEST_F(EValueTest, toString) { + auto string_ref = + std::make_unique>("foo", 3); + const EValue e(string_ref.get()); + EXPECT_TRUE(e.isString()); + EXPECT_FALSE(e.isNone()); + + std::string_view x = e.toString(); + EXPECT_EQ(x, "foo"); +} + +TEST_F(EValueTest, MemoryFormat) { + const EValue e((int64_t)0); + EXPECT_TRUE(e.isInt()); + const executorch::aten::MemoryFormat m = + e.to(); + EXPECT_EQ(m, executorch::aten::MemoryFormat::Contiguous); +} + +TEST_F(EValueTest, Layout) { + const EValue e((int64_t)0); + EXPECT_TRUE(e.isInt()); + const executorch::aten::Layout l = e.to(); + EXPECT_EQ(l, executorch::aten::Layout::Strided); +} + +TEST_F(EValueTest, Device) { + const EValue e((int64_t)0); + EXPECT_TRUE(e.isInt()); + const executorch::aten::Device d = e.to(); + EXPECT_TRUE(d.is_cpu()); +} + +TEST_F(EValueTest, BoxedEvalueList) { + // create fake values table to point to + EValue values[3] = { + EValue((int64_t)1), EValue((int64_t)2), EValue((int64_t)3)}; + // create wrapped and unwrapped lists + EValue* values_p[3] = {&values[0], &values[1], &values[2]}; + int64_t storage[3] = {0, 0, 0}; + // Create Object List and test + BoxedEvalueList x{values_p, storage, 3}; + auto unwrapped = x.get(); + EXPECT_EQ(unwrapped.size(), 3); + EXPECT_EQ(unwrapped[0], 1); + EXPECT_EQ(unwrapped[1], 2); + EXPECT_EQ(unwrapped[2], 3); +} + +TEST_F(EValueTest, toOptionalTensorList) { + // create list, empty evalue ctor gets tag::None + EValue values[2] = {EValue(), EValue()}; + EValue* values_p[2] = {&values[0], &values[1]}; + std::optional storage[2]; + // wrap in array ref + auto boxed_list = std::make_unique< + BoxedEvalueList>>( + values_p, storage, 2); + + // create Evalue + EValue e(boxed_list.get()); + e.tag = Tag::ListOptionalTensor; + EXPECT_TRUE(e.isListOptionalTensor()); + + // Convert back to list + executorch::aten::ArrayRef> x = + e.toListOptionalTensor(); + EXPECT_EQ(x.size(), 2); + EXPECT_FALSE(x[0].has_value()); + EXPECT_FALSE(x[1].has_value()); +} + +TEST_F(EValueTest, ConstructFromUniquePtr) { + TensorFactory tf; + auto tensor_ptr = std::make_unique(tf.ones({2, 3})); + + EValue evalue(std::move(tensor_ptr)); + + EXPECT_TRUE(evalue.isTensor()); + EXPECT_EQ(evalue.toTensor().dim(), 2); + EXPECT_EQ(evalue.toTensor().numel(), 6); + + EValue evalue2(std::make_unique(tf.ones({4, 5}))); + + EXPECT_TRUE(evalue2.isTensor()); + EXPECT_EQ(evalue2.toTensor().dim(), 2); + EXPECT_EQ(evalue2.toTensor().numel(), 20); +} + +TEST_F(EValueTest, ConstructFromSharedPtr) { + TensorFactory tf; + auto tensor_ptr = std::make_shared(tf.ones({4, 5})); + + EValue evalue(tensor_ptr); + + EXPECT_TRUE(evalue.isTensor()); + EXPECT_EQ(evalue.toTensor().dim(), 2); + EXPECT_EQ(evalue.toTensor().numel(), 20); +} + +TEST_F(EValueTest, ConstructFromTensorWrapper) { + TensorFactory tf; + TensorWrapper tensor_wrapper(tf.ones({4, 5})); + + EValue evalue(tensor_wrapper); + + EXPECT_TRUE(evalue.isTensor()); + EXPECT_EQ(evalue.toTensor().dim(), 2); + EXPECT_EQ(evalue.toTensor().numel(), 20); +} + +TEST_F(EValueTest, ConstructFromNullPtrAborts) { + std::unique_ptr null_ptr; + + ET_EXPECT_DEATH({ EValue evalue(null_ptr); }, ""); +} + +TEST_F(EValueTest, StringConstructorNullCheck) { + executorch::aten::ArrayRef* null_string_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_string_ptr); }, ""); +} + +TEST_F(EValueTest, BoolListConstructorNullCheck) { + executorch::aten::ArrayRef* null_bool_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_bool_list_ptr); }, ""); +} + +TEST_F(EValueTest, DoubleListConstructorNullCheck) { + executorch::aten::ArrayRef* null_double_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_double_list_ptr); }, ""); +} + +TEST_F(EValueTest, IntListConstructorNullCheck) { + BoxedEvalueList* null_int_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_int_list_ptr); }, ""); +} + +TEST_F(EValueTest, TensorListConstructorNullCheck) { + BoxedEvalueList* null_tensor_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_tensor_list_ptr); }, ""); +} + +TEST_F(EValueTest, OptionalTensorListConstructorNullCheck) { + BoxedEvalueList>* + null_optional_tensor_list_ptr = nullptr; + ET_EXPECT_DEATH({ EValue evalue(null_optional_tensor_list_ptr); }, ""); +} + +TEST_F(EValueTest, BoxedEvalueListConstructorNullChecks) { + std::array storage = {0, 0, 0}; + std::array values = { + EValue((int64_t)1), EValue((int64_t)2), EValue((int64_t)3)}; + std::array values_p = {&values[0], &values[1], &values[2]}; + + // Test null wrapped_vals + ET_EXPECT_DEATH( + { BoxedEvalueList list(nullptr, storage.data(), 3); }, ""); + + // Test null unwrapped_vals + ET_EXPECT_DEATH( + { BoxedEvalueList list(values_p.data(), nullptr, 3); }, ""); + + // Test negative size + ET_EXPECT_DEATH( + { BoxedEvalueList list(values_p.data(), storage.data(), -1); }, + ""); +} + +TEST_F(EValueTest, toListOptionalTensorTypeCheck) { + // Create an EValue that's not a ListOptionalTensor + EValue e((int64_t)42); + EXPECT_TRUE(e.isInt()); + EXPECT_FALSE(e.isListOptionalTensor()); + + // Should fail type check + ET_EXPECT_DEATH({ e.toListOptionalTensor(); }, ""); +} + +TEST_F(EValueTest, toStringNullPointerCheck) { + // Create an EValue with String tag but null pointer + EValue e; + e.tag = Tag::String; + e.payload.copyable_union.as_string_ptr = nullptr; + + // Should pass isString() check but fail null pointer check + EXPECT_TRUE(e.isString()); + ET_EXPECT_DEATH({ e.toString(); }, ""); +} + +TEST_F(EValueTest, toIntListNullPointerCheck) { + // Create an EValue with ListInt tag but null pointer + EValue e; + e.tag = Tag::ListInt; + e.payload.copyable_union.as_int_list_ptr = nullptr; + + // Should pass isIntList() check but fail null pointer check + EXPECT_TRUE(e.isIntList()); + ET_EXPECT_DEATH({ e.toIntList(); }, ""); +} + +TEST_F(EValueTest, toBoolListNullPointerCheck) { + // Create an EValue with ListBool tag but null pointer + EValue e; + e.tag = Tag::ListBool; + e.payload.copyable_union.as_bool_list_ptr = nullptr; + + // Should pass isBoolList() check but fail null pointer check + EXPECT_TRUE(e.isBoolList()); + ET_EXPECT_DEATH({ e.toBoolList(); }, ""); +} + +TEST_F(EValueTest, toDoubleListNullPointerCheck) { + // Create an EValue with ListDouble tag but null pointer + EValue e; + e.tag = Tag::ListDouble; + e.payload.copyable_union.as_double_list_ptr = nullptr; + + // Should pass isDoubleList() check but fail null pointer check + EXPECT_TRUE(e.isDoubleList()); + ET_EXPECT_DEATH({ e.toDoubleList(); }, ""); +} + +TEST_F(EValueTest, toTensorListNullPointerCheck) { + // Create an EValue with ListTensor tag but null pointer + EValue e; + e.tag = Tag::ListTensor; + e.payload.copyable_union.as_tensor_list_ptr = nullptr; + + // Should pass isTensorList() check but fail null pointer check + EXPECT_TRUE(e.isTensorList()); + ET_EXPECT_DEATH({ e.toTensorList(); }, ""); +} + +TEST_F(EValueTest, toListOptionalTensorNullPointerCheck) { + // Create an EValue with ListOptionalTensor tag but null pointer + EValue e; + e.tag = Tag::ListOptionalTensor; + e.payload.copyable_union.as_list_optional_tensor_ptr = nullptr; + + // Should pass isListOptionalTensor() check but fail null pointer check + EXPECT_TRUE(e.isListOptionalTensor()); + ET_EXPECT_DEATH({ e.toListOptionalTensor(); }, ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/event_tracer_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/event_tracer_test.cpp new file mode 100644 index 0000000..1c9e1a4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/event_tracer_test.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +// Enable flag for test +#define ET_EVENT_TRACER_ENABLED +#include +#include + +using executorch::aten::Tensor; +using executorch::runtime::AllocatorID; +using executorch::runtime::ArrayRef; +using executorch::runtime::ChainID; +using executorch::runtime::DebugHandle; +using executorch::runtime::DelegateDebugIntId; +using executorch::runtime::EValue; +using executorch::runtime::EventTracer; +using executorch::runtime::EventTracerDebugLogLevel; +using executorch::runtime::EventTracerEntry; +using executorch::runtime::EventTracerFilterBase; +using executorch::runtime::kUnsetChainId; +using executorch::runtime::kUnsetDebugHandle; +using executorch::runtime::kUnsetDelegateDebugIntId; +using executorch::runtime::LoggedEValueType; +using executorch::runtime::Result; + +class DummyEventTracer : public EventTracer { + public: + DummyEventTracer() {} + + ~DummyEventTracer() override {} + + void create_event_block(const char* name) override { + (void)name; + return; + } + + EventTracerEntry start_profiling( + const char* name, + ChainID chain_id = kUnsetChainId, + DebugHandle debug_handle = kUnsetDebugHandle) override { + (void)chain_id; + (void)debug_handle; + ET_CHECK(strlen(name) + 1 < sizeof(event_name_)); + memcpy(event_name_, name, strlen(name) + 1); + return EventTracerEntry(); + } + + void end_profiling(EventTracerEntry prof_entry) override { + (void)prof_entry; + memset(event_name_, 0, sizeof(event_name_)); + return; + } + + void track_allocation(AllocatorID id, size_t size) override { + (void)id; + (void)size; + return; + } + + AllocatorID track_allocator(const char* name) override { + (void)name; + return 0; + } + + EventTracerEntry start_profiling_delegate( + const char* name, + DelegateDebugIntId delegate_debug_id) override { + (void)name; + (void)delegate_debug_id; + return EventTracerEntry(); + } + + void end_profiling_delegate( + ET_UNUSED EventTracerEntry event_tracer_entry, + ET_UNUSED const void* metadata, + ET_UNUSED size_t metadata_len) override { + (void)event_tracer_entry; + (void)metadata; + (void)metadata_len; + } + + void set_delegation_intermediate_output_filter( + EventTracerFilterBase* event_tracer_filter) override { + (void)event_tracer_filter; + } + + void log_profiling_delegate( + const char* name, + DelegateDebugIntId delegate_debug_id, + et_timestamp_t start_time, + et_timestamp_t end_time, + const void* metadata, + size_t metadata_len = 0) override { + (void)name; + (void)delegate_debug_id; + (void)start_time; + (void)end_time; + (void)metadata; + (void)metadata_len; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const Tensor& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const ArrayRef output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const int& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const bool& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + virtual Result log_intermediate_output_delegate( + const char* name, + DelegateDebugIntId delegate_debug_index, + const double& output) override { + (void)name; + (void)delegate_debug_index; + (void)output; + return true; + } + + Result log_evalue(const EValue& evalue, LoggedEValueType evalue_type) + override { + logged_evalue_ = evalue; + logged_evalue_type_ = evalue_type; + return true; + } + + EValue logged_evalue() { + return logged_evalue_; + } + + LoggedEValueType logged_evalue_type() { + return logged_evalue_type_; + } + + char* get_event_name() { + return event_name_; + } + + void reset_logged_value() { + logged_evalue_ = EValue(false); + } + + private: + EValue logged_evalue_ = EValue(false); + LoggedEValueType logged_evalue_type_; + char event_name_[1024]; +}; + +/** + * Exercise all the event_tracer API's for a basic sanity check. + */ +void RunSimpleTracerTest(EventTracer* event_tracer) { + using executorch::runtime::internal::event_tracer_begin_profiling_event; + using executorch::runtime::internal::event_tracer_create_event_block; + using executorch::runtime::internal::event_tracer_end_profiling_event; + using executorch::runtime::internal::event_tracer_track_allocation; + using executorch::runtime::internal::event_tracer_track_allocator; + using executorch::runtime::internal::EventTracerProfileInstructionScope; + using executorch::runtime::internal::EventTracerProfileMethodScope; + + event_tracer_create_event_block(event_tracer, "ExampleEvent"); + event_tracer_create_event_block(event_tracer, "ExampleEvent"); + EventTracerEntry event_entry = + event_tracer_begin_profiling_event(event_tracer, "ExampleEvent"); + event_tracer_end_profiling_event(event_tracer, event_entry); + { + EventTracerProfileMethodScope event_tracer_profile_scope( + event_tracer, "ExampleScope"); + } + { + EventTracerProfileInstructionScope event_tracer_profile_instruction_scope( + event_tracer, 0, 1); + } + AllocatorID allocator_id = + event_tracer_track_allocator(event_tracer, "AllocatorName"); + event_tracer_track_allocation(event_tracer, allocator_id, 64); +} + +TEST(TestEventTracer, SimpleEventTracerTest) { + // Call all the EventTracer macro's with a valid pointer to an event tracer + // and also with a null pointer (to test that the null case works). + DummyEventTracer dummy; + std::vector dummy_event_tracer_arr = {&dummy, nullptr}; + for (const auto i : c10::irange(dummy_event_tracer_arr.size())) { + RunSimpleTracerTest(&dummy); + RunSimpleTracerTest(nullptr); + } +} + +/** + * Exercise all the event_tracer API's for delegates as a basic sanity check. + */ +void RunSimpleTracerTestDelegate(EventTracer* event_tracer) { + EventTracerEntry event_tracer_entry = event_tracer_start_profiling_delegate( + event_tracer, "test_event", kUnsetDelegateDebugIntId); + event_tracer_end_profiling_delegate( + event_tracer, event_tracer_entry, nullptr); + event_tracer_start_profiling_delegate(event_tracer, nullptr, 1); + event_tracer_end_profiling_delegate( + event_tracer, event_tracer_entry, "test_metadata"); + event_tracer_log_profiling_delegate( + event_tracer, "test_event", kUnsetDelegateDebugIntId, 0, 1, nullptr); + event_tracer_log_profiling_delegate(event_tracer, nullptr, 1, 0, 1, nullptr); +} + +TEST(TestEventTracer, SimpleEventTracerTestDelegate) { + // Call all the EventTracer macro's with a valid pointer to an event tracer + // and also with a null pointer (to test that the null case works). + DummyEventTracer dummy; + std::vector dummy_event_tracer_arr = {&dummy, nullptr}; + for (const auto i : c10::irange(dummy_event_tracer_arr.size())) { + RunSimpleTracerTestDelegate(&dummy); + RunSimpleTracerTestDelegate(nullptr); + } +} + +TEST(TestEventTracer, SimpleEventTracerTestLogging) { + using executorch::runtime::internal::event_tracer_log_evalue; + using executorch::runtime::internal::event_tracer_log_evalue_output; + + EValue test_eval(true); + + { + // By default there should be no logging enabled. + DummyEventTracer dummy; + event_tracer_log_evalue(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), false); + } + + { + // Enable only program outputs to be logged. So event_tracer_log_evalue + // should have no effect but event_tracer_log_evalue_output should work. + DummyEventTracer dummy; + dummy.set_event_tracer_debug_level( + EventTracerDebugLogLevel::kProgramOutputs); + event_tracer_log_evalue(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), false); + event_tracer_log_evalue_output(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), true); + EXPECT_EQ(dummy.logged_evalue_type(), LoggedEValueType::kProgramOutput); + } + + { + // Enable all outputs to be logged. So event_tracer_log_evalue and + // event_tracer_log_evalue_output should both work. + DummyEventTracer dummy; + dummy.set_event_tracer_debug_level( + EventTracerDebugLogLevel::kIntermediateOutputs); + event_tracer_log_evalue(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), true); + EXPECT_EQ( + dummy.logged_evalue_type(), LoggedEValueType::kIntermediateOutput); + dummy.reset_logged_value(); + event_tracer_log_evalue_output(&dummy, test_eval); + EXPECT_EQ(dummy.logged_evalue().toBool(), true); + EXPECT_EQ(dummy.logged_evalue_type(), LoggedEValueType::kProgramOutput); + } + + // Test with nullptr's to make sure it goes through smoothly. + event_tracer_log_evalue(nullptr, test_eval); + event_tracer_log_evalue_output(nullptr, test_eval); +} + +// TODO(T163645377): Add more test coverage to log and verify events passed into +// DummyTracer. +TEST(TestEventTracer, EventTracerProfileOpControl) { + DummyEventTracer dummy; + // Op profiling is enabled by default. Test that it works. + { + { + executorch::runtime::internal::EventTracerProfileOpScope + event_tracer_op_scope(&dummy, "ExampleOpScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), "ExampleOpScope"), 0); + } + EXPECT_EQ(strcmp(dummy.get_event_name(), ""), 0); + + // Normal profiling should still work. + { + executorch::runtime::internal::EventTracerProfileMethodScope + event_tracer_profiler_scope(&dummy, "ExampleProfilerScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), "ExampleProfilerScope"), 0); + } + + dummy.set_event_tracer_profiling_level( + executorch::runtime::EventTracerProfilingLevel::kProfileMethodOnly); + + // Op profiling should be disabled now. + { + executorch::runtime::internal::EventTracerProfileOpScope + event_tracer_op_scope(&dummy, "ExampleOpScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), ""), 0); + } + + // Normal profiling should still work. + { + executorch::runtime::internal::EventTracerProfileMethodScope + event_tracer_profiler_scope(&dummy, "1ExampleProfilerScope"); + EXPECT_EQ(strcmp(dummy.get_event_name(), "1ExampleProfilerScope"), 0); + } + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/freeable_buffer_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/freeable_buffer_test.cpp new file mode 100644 index 0000000..2848a6b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/freeable_buffer_test.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +using namespace ::testing; + +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; + +struct FreeCallArgs { + size_t calls; + std::variant data; + size_t size; +}; + +void RecordFree(void* context, void* data, size_t size) { + auto* call = reinterpret_cast(context); + call->calls++; + call->data = data; + call->size = size; +} + +void RecordInt64Free(void* context, uint64_t data, size_t size) { + auto* call = reinterpret_cast(context); + call->calls++; + call->data = data; + call->size = size; +} + +TEST(FreeableBufferTest, EmptyTest) { + FreeableBuffer fb; + EXPECT_EQ(fb.data(), nullptr); + EXPECT_EQ(fb.data_safe().error(), Error::Ok); + EXPECT_EQ(fb.data_safe().get(), nullptr); + EXPECT_EQ(fb.size(), 0); +} + +TEST(FreeableBufferTest, DataAndSizeTest) { + int i; + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/nullptr); + + // It should return the ctor params unmodified. + EXPECT_EQ(fb.size(), sizeof(i)); + EXPECT_EQ(fb.data(), &i); + EXPECT_EQ(fb.data_safe().error(), Error::Ok); + EXPECT_EQ(fb.data_safe().get(), &i); + + // Freeing should clear them, even though free_fn is nullptr. + fb.Free(); + EXPECT_EQ(fb.size(), 0); + EXPECT_EQ(fb.data(), nullptr); + EXPECT_EQ(fb.data_safe().error(), Error::Ok); + EXPECT_EQ(fb.data_safe().get(), nullptr); + + // Use uint64_t constructor. + const uint64_t i64 = 1; + FreeableBuffer fb2( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/nullptr); + + // It should return the ctor params unmodified. + EXPECT_EQ(fb2.size(), sizeof(i64)); + EXPECT_EQ(fb2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb2.data_uint64_type().get(), i64); + + // Freeing should clear them, even though free_fn is nullptr. + fb2.Free(); + EXPECT_EQ(fb2.size(), 0); + EXPECT_EQ(fb2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb2.data_uint64_type().get(), 0); +} + +TEST(FreeableBufferTest, FreeTest) { + // Updated when RecordFree() is called. + FreeCallArgs call = {}; + + { + // Create a FreeableBuffer with a free_fn that records when it's called. + int i; + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/RecordFree, + /*free_fn_context=*/&call); + + // Not called during construction. + EXPECT_EQ(call.calls, 0); + + // Called once during Free() with the expected data/size. + fb.Free(); + EXPECT_EQ(call.calls, 1); + EXPECT_EQ(std::get(call.data), &i); + EXPECT_EQ(call.size, sizeof(i)); + + // A second call to Free() should not call the function again. + fb.Free(); + EXPECT_EQ(call.calls, 1); + } + + // The destructor should not have called the function again. + EXPECT_EQ(call.calls, 1); + + // Test with uint64_t constructor and free function. + FreeCallArgs call2 = {}; + { + uint64_t i64 = 1; + FreeableBuffer fb( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/RecordInt64Free, + /*free_fn_context=*/&call2); + + // Not called during construction. + EXPECT_EQ(call2.calls, 0); + + // Called once during Free() with the expected data/size. + fb.Free(); + EXPECT_EQ(call2.calls, 1); + EXPECT_EQ(std::get(call2.data), i64); + EXPECT_EQ(call2.size, sizeof(i64)); + + // A second call to Free() should not call the function again. + fb.Free(); + EXPECT_EQ(call2.calls, 1); + } + EXPECT_EQ(call2.calls, 1); +} + +TEST(FreeableBufferTest, DestructorTest) { + // Updated when RecordFree() is called. + FreeCallArgs call = {}; + int i; + + { + // Create a FreeableBuffer with a free_fn that records when it's called. + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/RecordFree, + /*free_fn_context=*/&call); + + // Not called during construction. + EXPECT_EQ(call.calls, 0); + } + + // The destructor should have freed the data. + EXPECT_EQ(call.calls, 1); + EXPECT_EQ(std::get(call.data), &i); + EXPECT_EQ(call.size, sizeof(i)); + + // Test with uint64_t constructor and free function. + FreeCallArgs call2 = {}; + uint64_t i64 = 1; + { + FreeableBuffer fb2( + /*data_uint64=*/i64, + /*size=*/sizeof(i), + /*free_fn=*/RecordInt64Free, + /*free_fn_context=*/&call2); + EXPECT_EQ(call2.calls, 0); + } + // The destructor should have freed the data. + EXPECT_EQ(call2.calls, 1); + EXPECT_EQ(std::get(call2.data), i64); + EXPECT_EQ(call2.size, sizeof(i)); +} + +TEST(FreeableBufferTest, MoveTest) { + // Updated when RecordFree() is called. + FreeCallArgs call = {}; + int i; + + // Create a FreeableBuffer with some data. + FreeableBuffer fb_src( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/RecordFree, + /*free_fn_context=*/&call); + EXPECT_EQ(fb_src.size(), sizeof(i)); + EXPECT_EQ(fb_src.data(), &i); + + // Move it into a second FreeableBuffer. + FreeableBuffer fb_dst(std::move(fb_src)); + + // The source FreeableBuffer should now be empty. + EXPECT_EQ(fb_src.size(), 0); // NOLINT(bugprone-use-after-move) + EXPECT_EQ(fb_src.data(), nullptr); // NOLINT(bugprone-use-after-move) + + // The destination FreeableBuffer should have the data. + EXPECT_EQ(fb_dst.size(), sizeof(i)); + EXPECT_EQ(fb_dst.data(), &i); + // Freeing the source FreeableBuffer should not call the free function. + fb_src.Free(); + EXPECT_EQ(call.calls, 0); + + // Freeing the destination FreeableBuffer should call the free function. + fb_dst.Free(); + EXPECT_EQ(call.calls, 1); + EXPECT_EQ(call.size, sizeof(i)); + + // Test with uint64_t constructor and free function. + FreeCallArgs call2 = {}; + const uint64_t i64 = 1; + FreeableBuffer fb_src2( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/RecordInt64Free, + /*free_fn_context=*/&call2); + EXPECT_EQ(fb_src2.size(), sizeof(i64)); + EXPECT_EQ(fb_src2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb_src2.data_uint64_type().get(), i64); + + // Move it into a second FreeableBuffer. + FreeableBuffer fb_dst2(std::move(fb_src2)); + + // The source FreeableBuffer should now be empty. + EXPECT_EQ(fb_src2.size(), 0); // NOLINT(bugprone-use-after-move) + EXPECT_EQ( + fb_src2.data_uint64_type().error(), + Error::Ok); // NOLINT(bugprone-use-after-move) + EXPECT_EQ( + fb_src2.data_uint64_type().get(), 0); // NOLINT(bugprone-use-after-move) + + // The destination FreeableBuffer should have the data. + EXPECT_EQ(fb_dst2.size(), sizeof(i64)); + EXPECT_EQ(fb_dst2.data_uint64_type().error(), Error::Ok); + EXPECT_EQ(fb_dst2.data_uint64_type().get(), i64); + // Freeing the source FreeableBuffer should not call the free function. + fb_src2.Free(); + EXPECT_EQ(call2.calls, 0); + + // Freeing the destination FreeableBuffer should call the free function. + fb_dst2.Free(); + EXPECT_EQ(call2.calls, 1); + EXPECT_EQ(call2.size, sizeof(i64)); +} + +TEST(FreeableBufferTest, APIMisuseDeathTest) { + executorch::runtime::pal_init(); + int i; + FreeableBuffer fb( + /*data=*/&i, + /*size=*/sizeof(i), + /*free_fn=*/nullptr); + EXPECT_EQ(fb.data_uint64_type().error(), Error::InvalidType); + + uint64_t i64 = 1; + FreeableBuffer fb2( + /*data_uint64=*/i64, + /*size=*/sizeof(i64), + /*free_fn=*/nullptr); + EXPECT_EQ(fb2.data_safe().error(), Error::InvalidType); + ET_EXPECT_DEATH(fb2.data(), ".*"); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/function_ref_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/function_ref_test.cpp new file mode 100644 index 0000000..beef008 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/function_ref_test.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; + +using ::executorch::runtime::FunctionRef; + +namespace { +void one(int32_t& i) { + i = 1; +} + +} // namespace + +TEST(FunctionRefTest, CapturingLambda) { + auto one = 1; + auto f = [&](int32_t& i) { i = one; }; + int32_t val = 0; + FunctionRef{f}(val); + EXPECT_EQ(val, 1); + // ERROR: + // Item item1(0, f); + // Item item2(0, [&](int32_t& i) { i = 2; }); + // FunctionRef ref([&](int32_t&){}); +} + +TEST(FunctionRefTest, NonCapturingLambda) { + int32_t val = 0; + FunctionRef ref([](int32_t& i) { i = 1; }); + ref(val); + EXPECT_EQ(val, 1); + + val = 0; + auto lambda = [](int32_t& i) { i = 1; }; + FunctionRef ref1(lambda); + ref1(val); + EXPECT_EQ(val, 1); +} + +TEST(FunctionRefTest, FunctionPointer) { + int32_t val = 0; + FunctionRef ref(one); + ref(val); + EXPECT_EQ(val, 1); + + val = 0; + FunctionRef ref2(one); + ref2(val); + EXPECT_EQ(val, 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/hierarchical_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/hierarchical_allocator_test.cpp new file mode 100644 index 0000000..e25e1eb --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/hierarchical_allocator_test.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::HierarchicalAllocator; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +class HierarchicalAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(HierarchicalAllocatorTest, Smoke) { + constexpr size_t n_buffers = 2; + constexpr size_t size0 = 4; + constexpr size_t size1 = 8; + uint8_t mem0[size0]; + uint8_t mem1[size1]; + Span buffers[n_buffers]{ + {mem0, size0}, + {mem1, size1}, + }; + + HierarchicalAllocator allocator({buffers, n_buffers}); + + // get_offset_address() success cases + { + // Total size is 4, so off=0 + size=2 fits. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem0); + } + { + // Total size is 8, so off=4 + size=4 fits exactly. + Result address = allocator.get_offset_address( + /*memory_id=*/1, /*offset_bytes=*/4, /*size_bytes=*/4); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem1 + 4); + } + + // get_offset_address() failure cases + { + // Total size is 4, so off=0 + size=5 is too large. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/4, /*size_bytes=*/5); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // Total size is 4, so off=8 + size=0 is off the end. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/8, /*size_bytes=*/0); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // ID too large; only two zero-indexed entries in the allocator. + Result address = allocator.get_offset_address( + /*memory_id=*/2, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } +} + +// TODO(T162089316): Tests the deprecated API. Remove this when removing the +// API. +TEST_F(HierarchicalAllocatorTest, DEPRECATEDSmoke) { + constexpr size_t n_allocators = 2; + constexpr size_t size0 = 4; + constexpr size_t size1 = 8; + uint8_t mem0[size0]; + uint8_t mem1[size1]; + MemoryAllocator allocators[n_allocators]{ + MemoryAllocator(size0, mem0), MemoryAllocator(size1, mem1)}; + + HierarchicalAllocator allocator(n_allocators, allocators); + + // get_offset_address() success cases + { + // Total size is 4, so off=0 + size=2 fits. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem0); + } + { + // Total size is 8, so off=4 + size=4 fits exactly. + Result address = allocator.get_offset_address( + /*memory_id=*/1, /*offset_bytes=*/4, /*size_bytes=*/4); + ASSERT_EQ(address.error(), Error::Ok); + ASSERT_NE(address.get(), nullptr); + ASSERT_EQ(address.get(), mem1 + 4); + } + + // get_offset_address() failure cases + { + // Total size is 4, so off=0 + size=5 is too large. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/4, /*size_bytes=*/5); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // Total size is 4, so off=8 + size=0 is off the end. + Result address = allocator.get_offset_address( + /*memory_id=*/0, /*offset_bytes=*/8, /*size_bytes=*/0); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } + { + // ID too large; only two zero-indexed entries in the allocator. + Result address = allocator.get_offset_address( + /*memory_id=*/2, /*offset_bytes=*/0, /*size_bytes=*/2); + ASSERT_FALSE(address.ok()); + ASSERT_NE(address.error(), Error::Ok); + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/memory_allocator_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/memory_allocator_test.cpp new file mode 100644 index 0000000..fee95a6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/memory_allocator_test.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::MemoryAllocator; + +struct TestType8 { + char data[8]; +}; +static_assert(sizeof(TestType8) == 8); + +struct TestType1024 { + char data[1024]; +}; +static_assert(sizeof(TestType1024) == 1024); + +class MemoryAllocatorTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +TEST_F(MemoryAllocatorTest, MemoryAllocator) { + constexpr size_t mem_size = 16; + uint8_t mem_pool[mem_size]; + MemoryAllocator allocator(mem_size, mem_pool); + ASSERT_NE(nullptr, allocator.allocate(7)); + ASSERT_NE(nullptr, allocator.allocate(6)); + ASSERT_EQ(nullptr, allocator.allocate(3)); + + allocator.reset(); + ASSERT_EQ(mem_pool, allocator.allocate(0)); + ASSERT_NE(nullptr, allocator.allocate(16)); +} + +TEST_F(MemoryAllocatorTest, MemoryAllocatorAlignment) { + constexpr size_t arr_size = 6; + size_t allocation[arr_size] = {7, 6, 3, 76, 4, 1}; + size_t alignment[arr_size] = { + MemoryAllocator::kDefaultAlignment, + MemoryAllocator::kDefaultAlignment, + 4, + 32, + 128, + 2}; + + for (const auto i : c10::irange(arr_size)) { + auto align_size = alignment[i]; + constexpr size_t mem_size = 1000; + uint8_t mem_pool[mem_size]; + MemoryAllocator allocator = MemoryAllocator(mem_size, mem_pool); + for (const auto j : c10::irange(arr_size)) { + auto size = allocation[j]; + void* start = allocator.allocate(size, align_size); + EXPECT_ALIGNED(start, align_size); + } + } +} + +TEST_F(MemoryAllocatorTest, MemoryAllocatorNonPowerOfTwoAlignment) { + constexpr size_t mem_size = 128; + uint8_t mem_pool[mem_size]; + MemoryAllocator allocator(mem_size, mem_pool); + + size_t alignment[5] = {0, 5, 6, 12, 34}; + for (const auto i : c10::irange(5)) { + ASSERT_EQ(nullptr, allocator.allocate(8, alignment[i])); + } +} + +TEST_F(MemoryAllocatorTest, MemoryAllocatorTooLargeFailButSucceedAfterwards) { + constexpr size_t kPoolSize = 10; + uint8_t mem_pool[kPoolSize]; + MemoryAllocator allocator(kPoolSize, mem_pool); + // Align to 1 byte so the entire pool is used. The default alignment could + // skip over the first few bytes depending on the alignment of `mem_pool`. + ASSERT_EQ(nullptr, allocator.allocate(kPoolSize + 2, /*alignment=*/1)); + ASSERT_NE(nullptr, allocator.allocate(kPoolSize - 1, /*alignment=*/1)); +} + +template +static void test_allocate_instance() { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Default alignment + auto p = allocator.allocateInstance(); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignof(T)); + memset(p, 0x55, sizeof(T)); + + // Override alignment + constexpr size_t kHigherAlignment = 64; + EXPECT_GT(kHigherAlignment, alignof(T)); + p = allocator.allocateInstance(kHigherAlignment); + EXPECT_NE(p, nullptr); + EXPECT_ALIGNED(p, kHigherAlignment); + memset(p, 0x55, sizeof(T)); +} + +TEST_F(MemoryAllocatorTest, AllocateInstance) { + test_allocate_instance(); + test_allocate_instance(); + test_allocate_instance(); + test_allocate_instance(); + test_allocate_instance(); + + struct StructWithPointer { + void* p; + int i; + }; + test_allocate_instance(); + + struct StructWithLargestType { + std::max_align_t max; + int i; + }; + test_allocate_instance(); +} + +TEST_F(MemoryAllocatorTest, AllocateInstanceFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + auto p = allocator.allocateInstance(); + EXPECT_EQ(p, nullptr); +} + +template +static void test_allocate_list() { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Default alignment + constexpr size_t kNumElem = 5; + auto p = allocator.allocateList(kNumElem); + ASSERT_NE(p, nullptr); + EXPECT_ALIGNED(p, alignof(T)); + memset(p, 0x55, kNumElem * sizeof(T)); + + // Override alignment + constexpr size_t kHigherAlignment = 64; + EXPECT_GT(kHigherAlignment, alignof(T)); + p = allocator.allocateList(kNumElem, kHigherAlignment); + ASSERT_NE(p, nullptr); + EXPECT_ALIGNED(p, kHigherAlignment); + memset(p, 0x55, kNumElem * sizeof(T)); +} + +TEST_F(MemoryAllocatorTest, AllocateList) { + test_allocate_list(); + test_allocate_list(); + test_allocate_list(); + test_allocate_list(); + test_allocate_list(); + + struct StructWithPointer { + void* p; + char c; + }; + test_allocate_instance(); + + struct StructWithLargestType { + std::max_align_t max; + int i; + }; + test_allocate_instance(); +} + +TEST_F(MemoryAllocatorTest, AllocateListFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + auto p = allocator.allocateList(10); + EXPECT_EQ(p, nullptr); +} + +class HelperMacrosTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + } +}; + +/** + * An Error value that doesn't map to anything defined in Error.h. Helps + * demonstrate that the code here is being executed, and that the macro isn't + * returning a canned Error value. + */ +static const Error kTestFailureValue = static_cast(12345); + +TEST_F(HelperMacrosTest, TryAllocateSuccess) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate less memory than the allocator provides, which should succeed. + void* p = allocator.allocate(allocator.size() / 2); + EXPECT_NE(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + void* p = allocator.allocate(allocator.size() * 2); + EXPECT_EQ(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateInstanceSuccess) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate less memory than the allocator provides, which should succeed. + TestType8* p = allocator.allocateInstance(); + EXPECT_NE(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateInstanceFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + TestType1024* p = allocator.allocateInstance(); + EXPECT_EQ(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateListSuccess) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate less memory than the allocator provides, which should succeed. + void* p = allocator.allocateList(allocator.size() / 2); + EXPECT_NE(p, nullptr); +} + +TEST_F(HelperMacrosTest, TryAllocateListFailure) { + std::array buffer; + MemoryAllocator allocator(buffer.size(), buffer.data()); + + // Allocate more memory than the allocator provides, which should fail. + void* p = allocator.allocateList(allocator.size() * 2); + EXPECT_EQ(p, nullptr); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/span_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/span_test.cpp new file mode 100644 index 0000000..51063b8 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/span_test.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; +using executorch::runtime::Span; + +TEST(SpanTest, Ctors) { + int64_t x[2] = {1, 2}; + + Span span_range = {x, x + 2}; + Span span_array = {x}; + + EXPECT_EQ(span_range.size(), 2); + EXPECT_EQ(span_array.size(), 2); + + EXPECT_EQ(span_range.begin(), x); + EXPECT_EQ(span_range.end(), x + 2); + + EXPECT_EQ(span_array.begin(), x); + EXPECT_EQ(span_array.end(), x + 2); +} + +TEST(SpanTest, MutableElements) { + int64_t x[2] = {1, 2}; + Span span = {x, 2}; + EXPECT_EQ(span.size(), 2); + EXPECT_EQ(span[0], 1); + span[0] = 2; + EXPECT_EQ(span[0], 2); +} + +TEST(SpanTest, Empty) { + int64_t x[2] = {1, 2}; + Span span_full = {x, 2}; + Span span_empty = {x, (size_t)0}; + + EXPECT_FALSE(span_full.empty()); + EXPECT_TRUE(span_empty.empty()); +} + +TEST(SpanTest, Data) { + int64_t x[2] = {1, 2}; + Span span = {x, 2}; + EXPECT_EQ(span.data(), x); +} + +TEST(SpanTest, TriviallyCopyable) { + int64_t x[2] = {1, 2}; + Span span = {x, 2}; + Span span_copy = span; + EXPECT_EQ(span.data(), span_copy.data()); + EXPECT_EQ(span.size(), span_copy.size()); + EXPECT_TRUE(std::is_trivially_copyable>::value); +} + +TEST(SpanTest, SingleElementConstructor) { + int64_t single_value = 42; + Span span = single_value; + + EXPECT_EQ(span.size(), 1); + EXPECT_EQ(span.data(), &single_value); + EXPECT_EQ(span[0], 42); + EXPECT_EQ(*span.begin(), 42); + EXPECT_EQ(span.end(), span.begin() + 1); + + // Test that modifying through span affects original value + span[0] = 100; + EXPECT_EQ(single_value, 100); + EXPECT_EQ(span[0], 100); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tag_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tag_test.cpp new file mode 100644 index 0000000..00800df --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tag_test.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::kTagNameBufferSize; +using executorch::runtime::Tag; +using executorch::runtime::tag_to_string; + +// The behavior of tag_to_string depends on the value of ET_ENABLE_ENUM_STRINGS. +// If it is not set, tag_to_string will return a string representation of the +// enum index value. As this behavior is compile-time gated, tests must also +// be compile-time gated. +#if ET_ENABLE_ENUM_STRINGS +TEST(TagToString, TagValues) { + std::array name; + + tag_to_string(Tag::Tensor, name.data(), name.size()); + EXPECT_STREQ("Tensor", name.data()); + + tag_to_string(Tag::Int, name.data(), name.size()); + EXPECT_STREQ("Int", name.data()); + + tag_to_string(Tag::Double, name.data(), name.size()); + EXPECT_STREQ("Double", name.data()); + + tag_to_string(Tag::Bool, name.data(), name.size()); + EXPECT_STREQ("Bool", name.data()); +} + +TEST(TagToString, PrintTag) { + const char* name = tag_to_string(Tag::Tensor); + EXPECT_STREQ("Tensor", name); + + name = tag_to_string(Tag::Int); + EXPECT_STREQ("Int", name); + + name = tag_to_string(Tag::Double); + EXPECT_STREQ("Double", name); + + name = tag_to_string(Tag::Bool); + EXPECT_STREQ("Bool", name); +} + +TEST(TagToString, TagNameBufferSize) { + // Validate that kTagNameBufferSize is large enough to hold the all tag + // strings without truncation. + std::array name; + + // Note that the return value of tag_to_string does not include the null + // terminator. + size_t longest = 0; + +#define TEST_CASE(tag) \ + auto tag##_len = tag_to_string(Tag::tag, name.data(), name.size()); \ + EXPECT_LT(tag##_len, kTagNameBufferSize) \ + << "kTagNameBufferSize is too small to hold " #tag; \ + longest = std::max(longest, tag##_len); + + EXECUTORCH_FORALL_TAGS(TEST_CASE) +#undef TEST_CASE + + EXPECT_EQ(longest + 1, kTagNameBufferSize) + << "kTagNameBufferSize has incorrect value, expected " << longest + 1; +} + +TEST(TagToString, FitsExact) { + std::array name; + + auto ret = tag_to_string(Tag::Int, name.data(), name.size()); + + EXPECT_EQ(3, ret); + EXPECT_STREQ("Int", name.data()); +} + +TEST(TagToString, Truncate) { + std::array name; + std::fill(name.begin(), name.end(), '-'); + + auto ret = tag_to_string(Tag::Double, name.data(), name.size()); + EXPECT_EQ(6, ret); + EXPECT_TRUE(name[name.size() - 1] == 0); + EXPECT_STREQ("Doubl", name.data()); +} +#endif // ET_ENABLE_ENUM_STRINGS diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/targets.bzl new file mode 100644 index 0000000..1ad0940 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/targets.bzl @@ -0,0 +1,130 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "span_test", + srcs = ["span_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "tensor_layout_test", + srcs = ["tensor_layout_test.cpp"], + deps = [ + "//executorch/runtime/core:tensor_layout", + ], + ) + + runtime.cxx_test( + name = "error_handling_test", + srcs = [ + "error_handling_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "function_ref_test", + srcs = [ + "function_ref_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "event_tracer_test", + srcs = [ + "event_tracer_test.cpp", + ], + deps = [ + "//executorch/runtime/core:event_tracer", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "freeable_buffer_test", + srcs = [ + "freeable_buffer_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "array_ref_test", + srcs = ["array_ref_test.cpp"], + deps = [ + "//executorch/runtime/core:core", + ], + ) + + runtime.cxx_test( + name = "memory_allocator_test", + srcs = [ + "memory_allocator_test.cpp", + ], + deps = [ + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/core/portable_type/c10/c10:c10", + ], + ) + + runtime.cxx_test( + name = "hierarchical_allocator_test", + srcs = [ + "hierarchical_allocator_test.cpp", + ], + deps = [ + "//executorch/runtime/core:memory_allocator", + ], + ) + + runtime.cxx_test( + name = "tag_test", + srcs = [ + "tag_test.cpp", + ], + deps = [ + "//executorch/runtime/core:tag", + ], + preprocessor_flags = [ + "-DET_ENABLE_ENUM_STRINGS" + ], + ) + + if True in get_aten_mode_options(): + runtime.cxx_test( + name = "tensor_shape_dynamism_test_aten", + srcs = ["tensor_shape_dynamism_test_aten.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib_aten", + "//executorch/runtime/core/exec_aten/testing_util:tensor_util_aten", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_test( + name = "evalue_test" + aten_suffix, + srcs = ["evalue_test.cpp"], + deps = [ + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/testing_util:tensor_util" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_layout_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_layout_test.cpp new file mode 100644 index 0000000..0039745 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_layout_test.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::runtime::Error; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorLayout; + +TEST(TestTensorLayout, Ctor) { + std::array sizes = {1, 2}; + std::array dim_order = {0, 1}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_TRUE(layout_res.ok()); + + TensorLayout layout = layout_res.get(); + EXPECT_EQ(layout.scalar_type(), ScalarType::Float); + + EXPECT_EQ(layout.sizes().size(), sizes_span.size()); + EXPECT_EQ(layout.sizes()[0], sizes_span[0]); + EXPECT_EQ(layout.sizes()[1], sizes_span[1]); + + EXPECT_EQ(layout.dim_order().size(), dim_order_span.size()); + EXPECT_EQ(layout.dim_order()[0], dim_order_span[0]); + EXPECT_EQ(layout.dim_order()[1], dim_order_span[1]); + + EXPECT_EQ(layout.nbytes(), 8); +} + +TEST(TestTensorLayout, Ctor_InvalidDimOrder) { + std::array sizes = {2}; + std::array dim_order = {1}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_EQ(layout_res.error(), Error::InvalidArgument); +} + +TEST(TestTensorLayout, Ctor_InvalidSizes) { + std::array sizes = {-1}; + std::array dim_order = {0}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_EQ(layout_res.error(), Error::InvalidArgument); +} + +TEST(TestTensorLayout, Ctor_SizesDimOrderMismatch) { + std::array sizes = {2}; + std::array dim_order = {0, 1}; + Span sizes_span = {sizes.data(), sizes.size()}; + Span dim_order_span = {dim_order.data(), dim_order.size()}; + + Result layout_res = + TensorLayout::create(sizes_span, dim_order_span, ScalarType::Float); + EXPECT_EQ(layout_res.error(), Error::InvalidArgument); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_shape_dynamism_test_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_shape_dynamism_test_aten.cpp new file mode 100644 index 0000000..509efee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/test/tensor_shape_dynamism_test_aten.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +using namespace ::testing; +using executorch::runtime::TensorShapeDynamism; + +TEST(TensorShapeDynamismTest, CanBuildInATenMode) { + // Demonstrate that aten mode can include the header and see the enum. If this + // builds, the test passes. + +#ifndef USE_ATEN_LIB +#error "This test should only be built in aten mode" +#endif + + EXPECT_NE(TensorShapeDynamism::STATIC, TensorShapeDynamism::DYNAMIC_BOUND); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.cpp new file mode 100644 index 0000000..27a340a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +namespace executorch { +namespace runtime { + +// This needs to be defined in the SAME namespace that defines Error. +// C++'s look-up rules rely on that. +void PrintTo(const Error& error, std::ostream* os) { + *os << ::executorch::runtime::to_string(error); +} + +} // namespace runtime +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.h new file mode 100644 index 0000000..9522030 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/error_matchers.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @file + * Testing utilities for working with `executorch::runtime::Result` and + * `executorch::runtime::Error`. Provides matchers similar to `absl::StatusOr` + * and `absl::Status`. + * + * Defines the following utilities: + * + * =============== + * `IsOkAndHolds(m)` + * =============== + * + * This gMock matcher matches a Result value whose error is Ok + * and whose inner value matches matcher m. Example: + * + * ``` + * using ::testing::MatchesRegex; + * using ::executorch::runtime::testing::IsOkAndHolds; + * ... + * executorch::runtime::Result maybe_name = ...; + * EXPECT_THAT(maybe_name, IsOkAndHolds(MatchesRegex("John .*"))); + * ``` + * + * =============== + * `ErrorIs(Error::error_code)` + * =============== + * + * This gMock matcher matches a Result value whose error matches + * the given error matcher. Example: + * + * ``` + * using ::executorch::runtime::testing::ErrorIs; + * ... + * executorch::runtime::Result maybe_name = ...; + * EXPECT_THAT(maybe_name, ErrorIs(Error::InvalidArgument)); + * ``` + * + * =============== + * `IsOk()` + * =============== + * + * Matches an `executorch::runtime::Result` value whose error value + * is `executorch::runtime::Error::Ok`. + * + * Example: + * ``` + * using ::executorch::runtime::testing::IsOk; + * ... + * executorch::runtime::Result maybe_name = ...; + * EXPECT_THAT(maybe_name, IsOk()); + * ``` + */ + +#pragma once + +#include +#include + +#include +#include + +#include +#include + +/** + * Unwrap a Result to obtain its value. If the Result contains an error, + * fail the test with ASSERT_TRUE. + * + * This macro is useful for test code where you want to extract the value + * from a Result and fail the test if the Result contains an error. + * + * Example usage: + * ``` + * Result maybe_value = GetSomeValue(); + * int value = ASSERT_OK_AND_UNWRAP(maybe_value); + * // Use value... + * ``` + * + * @param[in] result__ Expression yielding the Result to unwrap. + */ +#define ASSERT_OK_AND_UNWRAP(result__) \ + ({ \ + auto&& et_result__ = (result__); \ + ASSERT_TRUE(et_result__.ok()); \ + std::move(*et_result__); \ + }) + +namespace executorch { +namespace runtime { +namespace testing { +namespace internal { + +// Helper function to get the error from a Result +template +inline Error GetError(const Result& result) { + return result.error(); +} + +// Helper function to get the error from a raw Error (identity function) +inline Error GetError(const Error& error) { + return error; +} + +//////////////////////////////////////////////////////////// +// Implementation of IsOkAndHolds(). + +// Monomorphic implementation of matcher IsOkAndHolds(m). ResultType is a +// reference to Result. +template +class IsOkAndHoldsMatcherImpl : public ::testing::MatcherInterface { + public: + typedef + typename std::remove_reference::type::value_type value_type; + + template + explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher) + : inner_matcher_(::testing::SafeMatcherCast( + std::forward(inner_matcher))) {} + + void DescribeTo(std::ostream* os) const override { + *os << "is OK and has a value that "; + inner_matcher_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "isn't OK or has a value that "; + inner_matcher_.DescribeNegationTo(os); + } + + bool MatchAndExplain( + ResultType actual_value, + ::testing::MatchResultListener* result_listener) const override { + if (!actual_value.ok()) { + *result_listener << "which has error " + << ::executorch::runtime::to_string( + GetError(actual_value)); + return false; + } + + // Call through to the inner matcher. + return inner_matcher_.MatchAndExplain(*actual_value, result_listener); + } + + private: + const ::testing::Matcher inner_matcher_; +}; + +// Implements IsOkAndHolds(m) as a polymorphic matcher. +template +class IsOkAndHoldsMatcher { + public: + explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher) + : inner_matcher_(std::forward(inner_matcher)) {} + + // Converts this polymorphic matcher to a monomorphic matcher of the + // given type. ResultType can be either Result or a + // reference to Result. + template + operator ::testing::Matcher() const { // NOLINT + return ::testing::Matcher( + new IsOkAndHoldsMatcherImpl(inner_matcher_)); + } + + private: + const InnerMatcher inner_matcher_; +}; + +//////////////////////////////////////////////////////////// +// Implementation of IsOk(). + +// Monomorphic implementation of matcher IsOk() for a given type T. +// T can be Result, Error, or references to either. +template +class MonoIsOkMatcherImpl : public ::testing::MatcherInterface { + public: + void DescribeTo(std::ostream* os) const override { + *os << "is OK"; + } + void DescribeNegationTo(std::ostream* os) const override { + *os << "is not OK"; + } + bool MatchAndExplain( + T actual_value, + ::testing::MatchResultListener* result_listener) const override { + const Error error = GetError(actual_value); + if (error != Error::Ok) { + *result_listener << "which has error " + << ::executorch::runtime::to_string(error); + return false; + } + return true; + } +}; + +// Implements IsOk() as a polymorphic matcher. +class IsOkMatcher { + public: + template + operator ::testing::Matcher() const { // NOLINT + return ::testing::Matcher(new MonoIsOkMatcherImpl()); + } +}; + +//////////////////////////////////////////////////////////// +// Implementation of ErrorIs(). + +// Monomorphic implementation of matcher ErrorIs() for a given type T. +// T can be Result or a reference to Result. +template +class MonoErrorIsMatcherImpl : public ::testing::MatcherInterface { + public: + explicit MonoErrorIsMatcherImpl(::testing::Matcher error_matcher) + : error_matcher_(std::move(error_matcher)) {} + + void DescribeTo(std::ostream* os) const override { + *os << "has an error that "; + error_matcher_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const override { + *os << "does not have an error that "; + error_matcher_.DescribeNegationTo(os); + } + + bool MatchAndExplain( + T actual_value, + ::testing::MatchResultListener* result_listener) const override { + Error actual_error = GetError(actual_value); + *result_listener << "which has error " + << ::executorch::runtime::to_string(actual_error); + return error_matcher_.MatchAndExplain(actual_error, result_listener); + } + + private: + const ::testing::Matcher error_matcher_; +}; + +// Implements ErrorIs() as a polymorphic matcher. +template +class ErrorIsMatcher { + public: + explicit ErrorIsMatcher(ErrorMatcher error_matcher) + : error_matcher_(std::forward(error_matcher)) {} + + // Converts this polymorphic matcher to a monomorphic matcher of the + // given type. T can be Result or a reference to Result. + template + operator ::testing::Matcher() const { // NOLINT + return ::testing::Matcher(new MonoErrorIsMatcherImpl( + ::testing::MatcherCast(error_matcher_))); + } + + private: + const ErrorMatcher error_matcher_; +}; + +} // namespace internal + +// Returns a gMock matcher that matches a Result<> whose error is +// OK and whose value matches the inner matcher. +template +internal::IsOkAndHoldsMatcher::type> +IsOkAndHolds(InnerMatcherT&& inner_matcher) { + return internal::IsOkAndHoldsMatcher< + typename std::decay::type>( + std::forward(inner_matcher)); +} + +// Returns a gMock matcher that matches a Result<> whose error matches +// the given error matcher. +template +internal::ErrorIsMatcher::type> ErrorIs( + ErrorMatcherT&& error_matcher) { + return internal::ErrorIsMatcher::type>( + std::forward(error_matcher)); +} + +// Returns a gMock matcher that matches a Result<> which is OK. +inline internal::IsOkMatcher IsOk() { + return internal::IsOkMatcher(); +} + +} // namespace testing +} // namespace runtime +} // namespace executorch + +namespace executorch { +namespace runtime { + +// This needs to be defined in the SAME namespace that defines Error. +// C++'s look-up rules rely on that. +void PrintTo(const Error& error, std::ostream* os); + +} // namespace runtime +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/targets.bzl new file mode 100644 index 0000000..dbab597 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/targets.bzl @@ -0,0 +1,25 @@ + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_library( + name = "error_matchers", + srcs = [ + "error_matchers.cpp", + ], + exported_headers = [ + "error_matchers.h", + ], + visibility = ["PUBLIC"], + exported_external_deps = [ + "gmock", + ], + exported_deps = [ + "//executorch/runtime/core:core", + ] + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/TARGETs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/TARGETs new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/TARGETs @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/targets.bzl new file mode 100644 index 0000000..ebfbe35 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/targets.bzl @@ -0,0 +1,19 @@ + +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + runtime.cxx_test( + name = "test_error_matchers", + srcs = [ + "test_error_matchers.cpp", + ], + visibility = ["//executorch/..."], + deps = [ + "//executorch/runtime/core/testing_util:error_matchers", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/test_error_matchers.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/test_error_matchers.cpp new file mode 100644 index 0000000..4e320cc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/core/testing_util/test/test_error_matchers.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +#include +#include + +namespace executorch::runtime::testing { +namespace { + +using ::executorch::runtime::Error; +using ::executorch::runtime::Result; +using ::executorch::runtime::testing::ErrorIs; +using ::executorch::runtime::testing::IsOk; +using ::executorch::runtime::testing::IsOkAndHolds; +using ::testing::AnyOf; +using ::testing::DescribeMatcher; +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::Matcher; +using ::testing::Not; + +TEST(ResultMatchersTest, IsOkMatchesOkResult) { + Result ok_result(42); + EXPECT_THAT(ok_result, IsOk()); +} + +TEST(ResultMatchersTest, IsOkDoesNotMatchErrorResult) { + Result error_result(Error::InvalidArgument); + EXPECT_THAT(error_result, Not(IsOk())); +} + +TEST(ResultMatchersTest, IsOkAndHoldsMatchesOkResultWithMatchingValue) { + Result ok_result(42); + EXPECT_THAT(ok_result, IsOkAndHolds(42)); + EXPECT_THAT(ok_result, IsOkAndHolds(Eq(42))); +} + +TEST(ResultMatchersTest, IsOkAndHoldsDoesNotMatchErrorResult) { + Result error_result(Error::InvalidArgument); + EXPECT_THAT(error_result, Not(IsOkAndHolds(42))); +} + +TEST(ResultMatchersTest, ErrorIsMatchesSpecificError) { + Error error = Error::InvalidArgument; + Result invalid_arg_result(Error::InvalidArgument); + Result ok_result(42); + + EXPECT_THAT(error, ErrorIs(Error::InvalidArgument)); + EXPECT_THAT(invalid_arg_result, ErrorIs(Error::InvalidArgument)); + EXPECT_THAT(invalid_arg_result, Not(ErrorIs(Error::NotFound))); + EXPECT_THAT(ok_result, Not(ErrorIs(Error::InvalidArgument))); +} + +TEST(ResultMatchersTest, ErrorIsWorksWithMatchers) { + Result invalid_arg_result(Error::InvalidArgument); + Result ok_result(42); + + EXPECT_THAT(invalid_arg_result, ErrorIs(Eq(Error::InvalidArgument))); + EXPECT_THAT( + invalid_arg_result, + ErrorIs(AnyOf(Error::InvalidArgument, Error::NotFound))); + EXPECT_THAT( + ok_result, Not(ErrorIs(AnyOf(Error::InvalidArgument, Error::NotFound)))); +} + +TEST(ResultMatchersTest, ErrorIsWorksWithDifferentResultTypes) { + Result string_error_result(Error::InvalidType); + Result double_error_result(Error::MemoryAllocationFailed); + + EXPECT_THAT(string_error_result, ErrorIs(Error::InvalidType)); + EXPECT_THAT(double_error_result, ErrorIs(Error::MemoryAllocationFailed)); + EXPECT_THAT(string_error_result, Not(ErrorIs(Error::MemoryAllocationFailed))); +} + +TEST(ResultMatchersTest, ErrorIsDoesNotMatchOkResult) { + Result ok_result(42); + + EXPECT_THAT(ok_result, Not(ErrorIs(Error::InvalidArgument))); + EXPECT_THAT(ok_result, Not(ErrorIs(Error::NotFound))); + EXPECT_THAT(ok_result, ErrorIs(Error::Ok)); +} + +TEST(ResultMatchersTest, AssertOkAndUnwrapWorksWithOkResult) { + Result ok_result(42); + int value = ASSERT_OK_AND_UNWRAP(Result(42)); + EXPECT_EQ(42, value); +} + +TEST(ResultMatchersTest, AssertOkAndUnwrapWorksWithStringResult) { + std::string value = ASSERT_OK_AND_UNWRAP(Result("hello world")); + EXPECT_EQ("hello world", value); +} + +TEST(ResultMatchersTest, AssertOkAndUnwrapWorksWithMoveOnlyTypes) { + Result> ok_result(std::make_unique(42)); + std::unique_ptr value = ASSERT_OK_AND_UNWRAP(std::move(ok_result)); + EXPECT_EQ(42, *value); +} + +TEST(ResultMatchersTest, MatcherDescriptions) { + Matcher> is_ok_matcher = IsOk(); + Matcher> is_ok_and_holds_matcher = IsOkAndHolds(42); + Matcher> error_is_matcher = ErrorIs(Error::InvalidArgument); + + EXPECT_EQ("is OK", DescribeMatcher>(is_ok_matcher)); + EXPECT_EQ("is not OK", DescribeMatcher>(is_ok_matcher, true)); + EXPECT_THAT( + DescribeMatcher>(is_ok_and_holds_matcher), + HasSubstr("is OK and has a value that")); + EXPECT_THAT( + DescribeMatcher>(is_ok_and_holds_matcher, true), + HasSubstr("isn't OK or has a value that")); + EXPECT_THAT( + DescribeMatcher>(error_is_matcher), + HasSubstr("has an error that")); + EXPECT_THAT( + DescribeMatcher>(error_is_matcher, true), + HasSubstr("does not have an error that")); +} + +} // namespace +} // namespace executorch::runtime::testing diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/memory_manager.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/memory_manager.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/memory_manager.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/memory_manager.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/merged_data_map.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/merged_data_map.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/merged_data_map.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/merged_data_map.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method.cpp similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method.cpp index 8eb4848..a830c2e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include // @donotremove #include @@ -38,20 +37,6 @@ namespace ET_RUNTIME_NAMESPACE { using internal::PlatformMemoryAllocator; -// Maximum number of instructions that Method::execute() will run before -// returning an error. Prevents infinite loops caused by malformed programs -// (e.g., JumpFalseCall instructions whose destination_instruction points to -// themselves). Override at compile time via -DET_MAX_INSTRUCTIONS=. -#ifndef ET_MAX_INSTRUCTIONS -#define ET_MAX_INSTRUCTIONS 10000000 -#endif -static_assert( - (ET_MAX_INSTRUCTIONS) > 0, - "ET_MAX_INSTRUCTIONS must be positive. 0 would reject every program on " - "its first instruction; negative values wrap to SIZE_MAX when assigned " - "to size_t, silently disabling the infinite-loop guard."); -static constexpr size_t kMaxInstructions = ET_MAX_INSTRUCTIONS; - /** * Runtime state for a backend delegate. */ @@ -101,17 +86,14 @@ class BackendDelegate final { } // Parse compilation specs from program - CompileSpec* compile_specs = nullptr; - size_t num_compile_specs = 0; - if (delegate.compile_specs() != nullptr) { - Error err = PopulateCompileSpecs( - delegate.compile_specs(), backend_init_context, &compile_specs); - if (err != Error::Ok) { - ET_LOG(Error, "Failed to get compile specs for backend %s", backend_id); - return err; - } - num_compile_specs = delegate.compile_specs()->size(); + CompileSpec* compile_specs; + Error err = PopulateCompileSpecs( + delegate.compile_specs(), backend_init_context, &compile_specs); + if (err != Error::Ok) { + ET_LOG(Error, "Failed to get compile specs for backend %s", backend_id); + return err; } + size_t num_compile_specs = delegate.compile_specs()->size(); out->backend_ = backend; out->handle_ = nullptr; @@ -428,7 +410,6 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { const size_t n_value = flatbuffer_values->size(); values_ = memory_manager_->method_allocator()->allocateList(n_value); if (values_ == nullptr) { - ET_LOG(Error, "Failed to allocate values array of size %zu", n_value); return Error::MemoryAllocationFailed; } const size_t n_input = inputs_size(); @@ -436,7 +417,6 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { input_set_ = memory_manager_->method_allocator()->allocateList(n_input); if (input_set_ == nullptr) { - ET_LOG(Error, "Failed to allocate input_set array of size %zu", n_input); return Error::MemoryAllocationFailed; } for (size_t i = 0; i < n_input; ++i) { @@ -460,10 +440,6 @@ Error Method::parse_values(const NamedDataMap* external_data_map) { memory_manager_->method_allocator()->allocateList( max_external_constants.get()); if (external_constants_ == nullptr) { - ET_LOG( - Error, - "Failed to allocate external_constants array of size %zu", - max_external_constants.get()); return Error::MemoryAllocationFailed; } Error err = parse_external_constants(external_data_map); @@ -802,19 +778,8 @@ Error Method::resolve_operator( } // Find a kernel with the matching name and tensor meta. - // Try method-scoped registry first (if provided), then fall back to global. - auto resolve_op_function = [&]() -> Result { - if (!kernel_registry_.empty()) { - Result method_scoped_op_function = - get_op_function_from_registry( - operator_name, {meta, count}, kernel_registry_); - if (method_scoped_op_function.ok()) { - return method_scoped_op_function; - } - } - return get_op_function_from_registry(operator_name, {meta, count}); - }; - Result op_function = resolve_op_function(); + Result op_function = + get_op_function_from_registry(operator_name, {meta, count}); if (!op_function.ok()) { ET_LOG( Error, @@ -841,25 +806,21 @@ Result Method::load( const Program* program, MemoryManager* memory_manager, EventTracer* event_tracer, - const NamedDataMap* external_data_map, - const LoadBackendOptionsMap* backend_options, - Span kernel_registry) { + const NamedDataMap* external_data_map) { MemoryAllocator* temp_allocator = memory_manager->temp_allocator(); if (temp_allocator == nullptr) { PlatformMemoryAllocator* platform_allocator = memory_manager->method_allocator() ->allocateInstance(); if (platform_allocator == nullptr) { - ET_LOG(Error, "Failed to allocate PlatformMemoryAllocator"); return Error::MemoryAllocationFailed; } new (platform_allocator) PlatformMemoryAllocator(); temp_allocator = platform_allocator; } - Method method( - program, memory_manager, event_tracer, temp_allocator, kernel_registry); + Method method(program, memory_manager, event_tracer, temp_allocator); ET_LOG(Debug, "Loading method: %s.", s_plan->name()->c_str()); - Error err = method.init(s_plan, external_data_map, backend_options); + Error err = method.init(s_plan, external_data_map); if (err != Error::Ok) { return err; } else { @@ -868,20 +829,11 @@ Result Method::load( } } -/// Validate that a value index from a FlatBuffer instruction is in bounds. -#define ET_CHECK_VALID_VALUE_INDEX(index, n_value) \ - ET_CHECK_OR_RETURN_ERROR( \ - (index) >= 0 && static_cast(index) < (n_value), \ - InvalidProgram, \ - "Index %zd negative or >= %" ET_PRIsize_t, \ - static_cast(index), \ - (n_value)) - Error Method::init( executorch_flatbuffer::ExecutionPlan* s_plan, - const NamedDataMap* external_data_map, - const LoadBackendOptionsMap* backend_options) { - internal::EventTracerProfileMethodScope event_tracer_scope = + const NamedDataMap* external_data_map) { + EXECUTORCH_SCOPE_PROF("Method::init"); + internal::EventTracerProfileMethodScope event_tracer_profile_scope = internal::EventTracerProfileMethodScope(event_tracer_, "Method::init"); ET_CHECK_OR_RETURN_ERROR( // Don't use !initialized() here because we also want to fail on the @@ -910,8 +862,6 @@ Error Method::init( size_t n_delegate = delegates->size(); delegates_ = method_allocator->allocateList(n_delegate); if (delegates_ == nullptr) { - ET_LOG( - Error, "Failed to allocate delegates array of size %zu", n_delegate); return Error::MemoryAllocationFailed; } @@ -935,7 +885,6 @@ Error Method::init( merged_data_map_ = method_allocator->allocateInstance(); if (merged_data_map_ == nullptr) { - ET_LOG(Error, "Failed to allocate MergedDataMap"); return Error::MemoryAllocationFailed; } new (merged_data_map_) internal::MergedDataMap(std::move(merged.get())); @@ -953,21 +902,11 @@ Error Method::init( for (size_t i = 0; i < n_delegate; ++i) { const auto& delegate = *delegates->Get(i); - - // Get per-delegate runtime specs from the LoadBackendOptionsMap if - // provided - Span delegate_runtime_specs; - if (backend_options != nullptr && delegate.id() != nullptr) { - delegate_runtime_specs = - backend_options->get_options(delegate.id()->c_str()); - } - BackendInitContext backend_init_context( method_allocator, /*event_tracer=*/event_tracer_, /*method_name=*/serialization_plan_->name()->c_str(), - /*named_data_map=*/named_data_map, - /*runtime_specs=*/delegate_runtime_specs); + /*named_data_map=*/named_data_map); Error err = BackendDelegate::Init( delegate, program_, backend_init_context, &delegates_[i]); if (err != Error::Ok) { @@ -988,7 +927,6 @@ Error Method::init( n_chains_ = chains->size(); chains_ = method_allocator->allocateList(n_chains_); if (chains_ == nullptr) { - ET_LOG(Error, "Failed to allocate chains array of size %zu", n_chains_); return Error::MemoryAllocationFailed; } @@ -1008,15 +946,11 @@ Error Method::init( auto chain_instruction_kernels = method_allocator->allocateList(num_instructions); if (chain_instruction_kernels == nullptr) { - ET_LOG( - Error, "Failed to allocate instruction kernels for chain %zu", i); return Error::MemoryAllocationFailed; } auto chain_instruction_arg_lists = method_allocator->allocateList(num_instructions); if (chain_instruction_arg_lists == nullptr) { - ET_LOG( - Error, "Failed to allocate instruction arg lists for chain %zu", i); return Error::MemoryAllocationFailed; } @@ -1086,34 +1020,23 @@ Error Method::init( chain_instruction_arg_lists[instr_idx] = res.get(); } break; case executorch_flatbuffer::InstructionArguments::JumpFalseCall: { + // Validate the index at load time so we can trust it during + // execution. auto index = static_cast( instr_args) ->cond_value_index(); - ET_CHECK_VALID_VALUE_INDEX(index, n_value_); - chain_instruction_arg_lists[instr_idx] = InstructionArgs(); - } break; - case executorch_flatbuffer::InstructionArguments::MoveCall: { - auto move_call = - static_cast(instr_args); - ET_CHECK_VALID_VALUE_INDEX(move_call->move_from(), n_value_); - ET_CHECK_VALID_VALUE_INDEX(move_call->move_to(), n_value_); + ET_CHECK_OR_RETURN_ERROR( + index >= 0 && static_cast(index) < n_value_, + InvalidProgram, + "Index %zd negative or >= %" ET_PRIsize_t, + static_cast(index), + n_value_); chain_instruction_arg_lists[instr_idx] = InstructionArgs(); } break; - case executorch_flatbuffer::InstructionArguments::FreeCall: { - auto index = - static_cast(instr_args) - ->value_index(); - ET_CHECK_VALID_VALUE_INDEX(index, n_value_); + default: { chain_instruction_arg_lists[instr_idx] = InstructionArgs(); } break; - default: { - ET_LOG( - Error, - "Invalid instruction type %hhu", - static_cast(instruction->instr_args_type())); - return Error::InvalidProgram; - } } } chains_[i] = Chain{ @@ -1208,33 +1131,6 @@ Method::set_input(const EValue& input_evalue, size_t input_idx) { input_idx, executorch::runtime::toString(t_dst.scalar_type()), executorch::runtime::toString(t_src.scalar_type())); - - ssize_t numel = 1; - for (ssize_t i = 0; i < t_src.dim(); i++) { - bool overflow = c10::mul_overflows( - numel, static_cast(t_src.size(i)), &numel); - ET_CHECK_OR_RETURN_ERROR( - !overflow, - InvalidArgument, - "Input %" ET_PRIsize_t - ": numel overflowed at dimension %zd with size %zd", - input_idx, - (size_t)i, - (size_t)t_src.size(i)); - } - size_t nbytes; - bool nbytes_overflow = c10::mul_overflows( - static_cast(numel), - executorch::runtime::elementSize(t_src.scalar_type()), - &nbytes); - ET_CHECK_OR_RETURN_ERROR( - !nbytes_overflow, - InvalidArgument, - "Input %" ET_PRIsize_t - ": nbytes overflowed: numel %zd with element size %zu", - input_idx, - numel, - executorch::runtime::elementSize(t_src.scalar_type())); // Reset the shape for the Method's input as the size of forwarded input // tensor for shape dynamism. Also is a safety check if need memcpy. ET_CHECK_OK_OR_RETURN_ERROR( @@ -1579,16 +1475,8 @@ Error Method::execute_instruction() { // We know that instr_args_as_FreeCall is non-null because it was checked // at init time. auto free_call = instruction->instr_args_as_FreeCall(); - auto t = mutable_value(free_call->value_index()).tryToTensor(); - if (!t.ok()) { - ET_LOG( - Error, - "FreeCall target at index %u is not a Tensor", - static_cast(free_call->value_index())); - err = t.error(); - break; - } - internal::reset_data_ptr(t.get()); + auto t = values_[free_call->value_index()].toTensor(); + internal::reset_data_ptr(t); } break; default: ET_LOG( @@ -1718,7 +1606,6 @@ Error Method::execute() { // Chains are executed sequentially today, but future async designs may // branch and run many in parallel or out of order. - size_t instruction_count = 0; for (step_state_.chain_idx = 0; step_state_.chain_idx < n_chains_; ++step_state_.chain_idx) { Chain& chain = chains_[step_state_.chain_idx]; @@ -1732,21 +1619,6 @@ Error Method::execute() { // Loop over instructions step_state_.instr_idx = 0; while (step_state_.instr_idx < chain.s_chain_->instructions()->size()) { - if (instruction_count >= kMaxInstructions) { - ET_LOG( - Error, - "Instruction execution limit (%" ET_PRIsize_t - ") exceeded at chain %" ET_PRIsize_t ", instruction %" ET_PRIsize_t - ". Possible infinite loop detected. If this is a legitimate " - "large model, raise the limit by rebuilding with " - "-DET_MAX_INSTRUCTIONS=.", - kMaxInstructions, - step_state_.chain_idx, - step_state_.instr_idx); - step_state_ = StepState{0, 0}; - return Error::InvalidProgram; - } - ++instruction_count; EXECUTORCH_PROFILE_INSTRUCTION_SCOPE( static_cast(step_state_.chain_idx), static_cast(step_state_.instr_idx)); diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method.h index 834325f..cd121a5 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/method.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method.h @@ -14,7 +14,6 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif -#include #include #include #include @@ -23,7 +22,6 @@ #include #include #include -#include #include // Forward declare flatbuffer types. This is a public header and must not @@ -83,7 +81,6 @@ class Method final { merged_data_map_(std::move(rhs.merged_data_map_)), external_constants_(rhs.external_constants_), n_external_constants_(rhs.n_external_constants_), - kernel_registry_(rhs.kernel_registry_), init_state_(rhs.init_state_) { // Required: clear out fields that the dtor looks at, so that we don't free // anything twice. @@ -333,8 +330,7 @@ class Method final { const Program* program, MemoryManager* memory_manager, EventTracer* event_tracer, - MemoryAllocator* temp_allocator, - Span kernel_registry = {}) + MemoryAllocator* temp_allocator) : step_state_(), program_(program), memory_manager_(memory_manager), @@ -351,7 +347,6 @@ class Method final { merged_data_map_(nullptr), external_constants_(nullptr), n_external_constants_(0), - kernel_registry_(kernel_registry), init_state_(InitializationState::Uninitialized) {} /// Static factory used by Program. @@ -360,9 +355,7 @@ class Method final { const Program* program, MemoryManager* memory_manager, EventTracer* event_tracer, - const NamedDataMap* named_data_map, - const LoadBackendOptionsMap* backend_options = nullptr, - Span kernel_registry = {}); + const NamedDataMap* named_data_map); /** * Initialize the method from its serialized representation. @@ -371,8 +364,7 @@ class Method final { */ ET_NODISCARD Error init( executorch_flatbuffer::ExecutionPlan* s_plan, - const NamedDataMap* named_data_map, - const LoadBackendOptionsMap* backend_options); + const NamedDataMap* named_data_map); /// Returns true if the Method was successfully initialized. inline bool initialized() const { @@ -408,8 +400,6 @@ class Method final { NamedData* external_constants_; size_t n_external_constants_ = 0; - Span kernel_registry_; - InitializationState init_state_; /** diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method_meta.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method_meta.cpp similarity index 79% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method_meta.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method_meta.cpp index 0af97b3..75dadfd 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method_meta.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method_meta.cpp @@ -6,8 +6,6 @@ * LICENSE file in the root directory of this source tree. */ -#include // @donotremove - #include #include #include @@ -60,20 +58,13 @@ Result calculate_nbytes( executorch::aten::ScalarType scalar_type) { size_t n = 1; for (size_t i = 0; i < sizes.size(); i++) { - ET_CHECK_OR_RETURN_ERROR( - sizes[i] >= 0, - InvalidProgram, - "Invalid size[%zu]: %" PRId32 ". Size must not be negative", - i, - sizes[i]); size_t next_n; bool overflow = c10::mul_overflows(n, static_cast(sizes[i]), &next_n); ET_CHECK_OR_RETURN_ERROR( !overflow, InvalidArgument, - "Invalid size[%zu]: %" PRId32 - ". Potentially overflowed, expect to be 0 or n: %zu", + "Invalid size[%zu]: %d. Potentially overflowed, expect to be 0 or n: %zu", i, sizes[i], n); @@ -195,12 +186,6 @@ Result MethodMeta::input_tensor_meta(size_t index) const { auto input_index = s_plan_->inputs()->Get(index); // input_index was already validated by input_tag(). auto tensor_value = s_plan_->values()->Get(input_index)->val_as_Tensor(); - ET_CHECK_OR_RETURN_ERROR( - tensor_value != nullptr && tensor_value->sizes() != nullptr && - tensor_value->dim_order() != nullptr, - InvalidProgram, - "Null tensor metadata for input %zu", - index); return TensorInfo::create( Span( tensor_value->sizes()->data(), tensor_value->sizes()->size()), @@ -252,12 +237,7 @@ Result MethodMeta::output_tensor_meta(size_t index) const { auto output_index = s_plan_->outputs()->Get(index); // output_index was already validated by output_tag(). auto tensor_value = s_plan_->values()->Get(output_index)->val_as_Tensor(); - ET_CHECK_OR_RETURN_ERROR( - tensor_value != nullptr && tensor_value->sizes() != nullptr && - tensor_value->dim_order() != nullptr, - InvalidProgram, - "Null tensor metadata for output %zu", - index); + return TensorInfo::create( Span( tensor_value->sizes()->data(), tensor_value->sizes()->size()), @@ -277,10 +257,7 @@ size_t MethodMeta::num_attributes() const { auto value = values->Get(i); if (value->val_type() == executorch_flatbuffer::KernelTypes::Tensor) { auto tensor_value = value->val_as_Tensor(); - if (tensor_value != nullptr && - tensor_value->extra_tensor_info() != nullptr && - tensor_value->extra_tensor_info()->fully_qualified_name() != - nullptr && + if (tensor_value->extra_tensor_info() != nullptr && tensor_value->extra_tensor_info()->fully_qualified_name()->c_str() != nullptr) { ++counter; @@ -297,19 +274,10 @@ Result MethodMeta::attribute_tensor_meta(size_t index) const { auto value = values->Get(i); if (value->val_type() == executorch_flatbuffer::KernelTypes::Tensor) { auto tensor_value = value->val_as_Tensor(); - if (tensor_value != nullptr && - tensor_value->extra_tensor_info() != nullptr && - tensor_value->extra_tensor_info()->fully_qualified_name() != - nullptr && + if (tensor_value->extra_tensor_info() != nullptr && tensor_value->extra_tensor_info()->fully_qualified_name()->c_str() != nullptr) { if (counter == index) { - ET_CHECK_OR_RETURN_ERROR( - tensor_value->sizes() != nullptr && - tensor_value->dim_order() != nullptr, - InvalidProgram, - "Null tensor metadata for attribute %zu", - index); auto t_name = tensor_value->extra_tensor_info()->fully_qualified_name(); // Count constant returns as memory planned @@ -354,50 +322,7 @@ Result MethodMeta::memory_planned_buffer_size(size_t index) const { num_buffers); // Index zero is reserved internally, and we hide it from users. Adjust the // provided index to point to one of the actual buffers. - int64_t size = s_plan_->non_const_buffer_sizes()->Get(index + 1); - ET_CHECK_OR_RETURN_ERROR( - size >= 0, - InvalidProgram, - "memory_planned_buffer_size(%zu) has invalid negative size: %" PRId64, - index, - size); - return size; -} - -Result MethodMeta::memory_planned_buffer_device( - size_t index) const { - auto num_buffers = this->num_memory_planned_buffers(); - ET_CHECK_OR_RETURN_ERROR( - index < num_buffers, - InvalidArgument, - "index %zu out of range. num_buffers: %zu", - index, - num_buffers); - - // The non_const_buffer_device field is optional and only present when the - // program contains non-CPU buffers. For CPU-only programs (or legacy PTE - // files), this field is null and all buffers default to CPU. - auto* buffer_devices = s_plan_->non_const_buffer_device(); - if (buffer_devices == nullptr) { - return etensor::Device{etensor::DeviceType::CPU, 0}; - } - - // The sparse list only contains entries for non-CPU buffers. - // buffer_idx uses the same indexing as non_const_buffer_sizes (1-based, - // with index 0 reserved). The user-facing index is 0-based, so we - // compare against index + 1. - const auto internal_idx = static_cast(index + 1); - for (size_t i = 0; i < buffer_devices->size(); ++i) { - auto entry = buffer_devices->Get(i); - if (entry->buffer_idx() == internal_idx) { - return etensor::Device{ - static_cast(entry->device_type()), - static_cast(entry->device_index())}; - } - } - - // Not found in the sparse list — this buffer is on CPU. - return etensor::Device{etensor::DeviceType::CPU, 0}; + return s_plan_->non_const_buffer_sizes()->Get(index + 1); } bool MethodMeta::uses_backend(const char* backend_name) const { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method_meta.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method_meta.h similarity index 92% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method_meta.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method_meta.h index e0fa16c..79fd05c 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/method_meta.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/method_meta.h @@ -9,7 +9,6 @@ #pragma once #include -#include #include #include #include @@ -235,19 +234,6 @@ class MethodMeta final { */ Result memory_planned_buffer_size(size_t index) const; - /** - * Get the device placement for the specified memory-planned buffer. - * - * For CPU-only programs (no non_const_buffer_device in the PTE), all buffers - * default to Device{CPU, 0}. For programs with device annotations, returns - * the device type and index that the buffer should be allocated on. - * - * @param[in] index The index of the buffer to look up (0-based, same - * indexing as memory_planned_buffer_size()). - * @returns The Device on success, or an error on failure. - */ - Result memory_planned_buffer_device(size_t index) const; - /** * Check to see if a backend is used in this method. * diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/platform_memory_allocator.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/platform_memory_allocator.h similarity index 85% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/platform_memory_allocator.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/platform_memory_allocator.h index 601a4c1..5951f11 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/platform_memory_allocator.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/platform_memory_allocator.h @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -47,20 +46,8 @@ class PlatformMemoryAllocator final : public MemoryAllocator { return nullptr; } - // Check for overflow before computing total allocation size. - // Allocate enough for the node, data, and alignment bump (at most - // alignment - 1 extra bytes to align the data pointer). - size_t alloc_size = 0; - if (c10::add_overflows(sizeof(AllocationNode), size, &alloc_size) || - c10::add_overflows(alloc_size, alignment - 1, &alloc_size)) { - ET_LOG( - Error, - "Allocation size overflow: size %zu, alignment %zu", - size, - alignment); - return nullptr; - } - + // Allocate enough memory for the node, the data and the alignment bump. + size_t alloc_size = sizeof(AllocationNode) + size + alignment; void* node_memory = runtime::pal_allocate(alloc_size); // If allocation failed, log message and return nullptr. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/program.cpp similarity index 76% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/program.cpp index 4c0337e..344e3c7 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/program.cpp @@ -11,11 +11,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -29,14 +27,6 @@ #define ET_ENABLE_PROGRAM_VERIFICATION 1 #endif -/* - * The constant_buffer path is deprecated from ExecuTorch 0.7. Disable it by - * passing -DET_ENABLE_DEPRECATED_CONSTANT_BUFFER=0. - */ -#ifndef ET_ENABLE_DEPRECATED_CONSTANT_BUFFER -#define ET_ENABLE_DEPRECATED_CONSTANT_BUFFER 1 -#endif - namespace executorch { namespace ET_RUNTIME_NAMESPACE { namespace { @@ -59,8 +49,7 @@ Result get_execution_plan( auto execution_plans = program->execution_plan(); for (size_t i = 0; i < execution_plans->size(); i++) { auto plan = execution_plans->GetMutableObject(i); - if (plan != nullptr && plan->name() != nullptr && - std::strcmp(plan->name()->c_str(), method_name) == 0) { + if (std::strcmp(plan->name()->c_str(), method_name) == 0) { return plan; } } @@ -101,12 +90,6 @@ Result get_execution_plan( // is positive (0-value may indicate no segments) if ((segment_data_size == 0 && segment_base_offset == 0) || segment_data_size > 0) { - ET_CHECK_OR_RETURN_ERROR( - segment_base_offset <= SIZE_MAX - segment_data_size, - InvalidProgram, - "segment_base_offset %zu + segment_data_size %zu overflows", - segment_base_offset, - segment_data_size); size_t expected = segment_base_offset == 0 ? program_size : segment_base_offset + segment_data_size; @@ -143,25 +126,6 @@ Result get_execution_plan( } EXECUTORCH_END_PROF(prof_tok); - // The flatbuffer data must start at an aligned address to ensure internal - // alignment of flatbuffer fields. - ET_CHECK_OR_RETURN_ERROR( - IsAligned(program_data->data()), - InvalidArgument, - "Program data 0x%p must be aligned to %zu", - program_data->data(), - kMinimumAlignment); - - // Minimum size: root offset + file identifier (i.e., the flatbuffer header - // before the extended header begins). - constexpr size_t kMinBufferSize = ExtendedHeader::kHeaderOffset; - ET_CHECK_OR_RETURN_ERROR( - program_data->size() >= kMinBufferSize, - InvalidProgram, - "Program data size %zu is too small (minimum %zu)", - program_data->size(), - kMinBufferSize); - // Make sure the magic header matches the expected version. if (!executorch_flatbuffer::ProgramBufferHasIdentifier( program_data->data())) { @@ -173,7 +137,7 @@ Result get_execution_plan( return Error::InvalidProgram; } - // Do verification based on the requested level. + // Do extra verification if requested. if (verification == Verification::InternalConsistency) { #if ET_ENABLE_PROGRAM_VERIFICATION EXECUTORCH_SCOPE_PROF("Program::verify_internal_consistency"); @@ -185,43 +149,21 @@ Result get_execution_plan( ok, InvalidProgram, "Verification failed; data may be truncated or corrupt"); - const executorch_flatbuffer::Program* flatbuffer_program = - executorch_flatbuffer::GetProgram(program_data->data()); - Error err = validate_program(flatbuffer_program); - ET_CHECK_OR_RETURN_ERROR( - err == Error::Ok, - InvalidProgram, - "Program validation failed: likely a corrupt file"); #else ET_LOG( - Info, - "InternalConsistency verification requested but not available; " - "falling back to Minimal verification. " - "Build with ET_ENABLE_PROGRAM_VERIFICATION=1 for full verification."); + Info, "InternalConsistency verification requested but not available"); #endif } - if (verification == Verification::Minimal -#if !ET_ENABLE_PROGRAM_VERIFICATION - || verification == Verification::InternalConsistency -#endif - ) { - // Verify that the root table offset is within bounds. - // In InternalConsistency mode this is done by VerifyProgramBuffer above. - uint32_t root_offset = - flatbuffers::ReadScalar(program_data->data()); - // The root table is at buf + root_offset. It must not point into the - // header (offset + file identifier = 8 bytes) and must leave room for - // at least a vtable offset (soffset_t) at its position. - ET_CHECK_OR_RETURN_ERROR( - root_offset >= kMinBufferSize && - root_offset <= - program_data->size() - sizeof(flatbuffers::soffset_t), - InvalidProgram, - "Root table offset %u is invalid for program size %zu", - root_offset, - program_data->size()); - } + // The flatbuffer data must start at an aligned address to ensure internal + // alignment of flatbuffer fields. + ET_CHECK_OR_RETURN_ERROR( + IsAligned(program_data->data()), + InvalidArgument, + "Program data 0x%p must be aligned to %zu", + program_data->data(), + kMinimumAlignment); + // Get the pointer to the root flatbuffer table. const executorch_flatbuffer::Program* flatbuffer_program = executorch_flatbuffer::GetProgram(program_data->data()); @@ -314,7 +256,6 @@ Result get_execution_plan( // https://docs.pytorch.org/executorch/stable/api-life-cycle.html#deprecation-policy. // For support, contact the PyTorch Edge team or make an issue in: // https://github.com/pytorch/executorch/issues. -#if ET_ENABLE_DEPRECATED_CONSTANT_BUFFER ET_LOG( Error, "!!DEPRECATED!! This branch is deprecated from ExecuTorch 0.7; re-export this PTE file to ensure support on newer runtimes."); @@ -325,13 +266,6 @@ Result get_execution_plan( flatbuffer_program, /*constant_segment_data=*/FreeableBuffer{}, std::move(pte_data_map)); -#else - ET_LOG( - Error, - "PTE file relies on the constant_buffer path, which is disabled in this" - " build (ET_ENABLE_DEPRECATED_CONSTANT_BUFFER=0). Please re-export the PTE file."); - return Error::InvalidProgram; -#endif } } @@ -348,11 +282,6 @@ size_t Program::num_methods() const { Result Program::get_method_name(size_t plan_index) const { if (plan_index >= this->num_methods()) { - ET_LOG( - Error, - "Plan index %zu >= num methods %zu", - plan_index, - this->num_methods()); return Error::InvalidArgument; } auto internal_program = @@ -360,7 +289,6 @@ Result Program::get_method_name(size_t plan_index) const { // We know that the execution plan exists because num_methods() returned > 0. auto name = internal_program->execution_plan()->Get(plan_index)->name(); if (name == nullptr) { - ET_LOG(Error, "Execution plan %zu has null name", plan_index); return Error::InvalidProgram; } return name->c_str(); @@ -370,9 +298,7 @@ Result Program::load_method( const char* method_name, MemoryManager* memory_manager, EventTracer* event_tracer, - const NamedDataMap* named_data_map, - const LoadBackendOptionsMap* backend_options, - Span kernel_registry) const { + const NamedDataMap* named_data_map) const { EXECUTORCH_SCOPE_PROF("Program::load_method"); internal::event_tracer_create_event_block(event_tracer, "Default"); internal::EventTracerProfileMethodScope event_tracer_scope = @@ -390,13 +316,7 @@ Result Program::load_method( return plan.error(); } return Method::load( - plan.get(), - this, - memory_manager, - event_tracer, - named_data_map, - backend_options, - kernel_registry); + plan.get(), this, memory_manager, event_tracer, named_data_map); } Result Program::method_meta(const char* method_name) const { @@ -454,7 +374,7 @@ Result Program::get_constant_buffer_data( size_t size = constant_segment_data_.size(); ET_CHECK_OR_RETURN_ERROR( - offset <= size && nbytes <= size - offset, + offset + nbytes <= size, InvalidArgument, "Constant segment offset %" PRIu64 " + size_bytes %zu invalid for program constant segment size %zu", @@ -467,7 +387,6 @@ Result Program::get_constant_buffer_data( static_cast(constant_segment_data_.data()) + offset); } else { -#if ET_ENABLE_DEPRECATED_CONSTANT_BUFFER // Otherwise, the constant data is stored inside Program.constant_buffer. const auto* constant_buffer_ptr = internal_program->constant_buffer(); size_t num_elems = @@ -482,26 +401,14 @@ Result Program::get_constant_buffer_data( const auto& constant_buffer = *constant_buffer_ptr; const auto* storage = constant_buffer[buffer_index]->storage(); auto storage_size = storage == nullptr ? 0 : storage->size(); - // nbytes (requested from the program) should be less than storage_size - // (size of the constant buffer from PTE), to prevent reading out of bounds. - // in some cases storage size may be larger than nbytes because of padding; - // executorch-tensor-alignment, or 16 by default. ET_CHECK_OR_RETURN_ERROR( - nbytes <= storage_size, + storage_size <= nbytes, InvalidArgument, - "Requested nbytes %zu exceeds constant buffer storage size %zu", - nbytes, - static_cast(storage_size)); + "Constant buffer size %zu larger than allocated nbytes %zu", + static_cast(constant_buffer[buffer_index]->storage()->size()), + nbytes); return storage->data(); -#else - (void)buffer_index; - (void)nbytes; - ET_LOG( - Error, - "constant_buffer path is disabled (ET_ENABLE_DEPRECATED_CONSTANT_BUFFER=0). Please re-export the PTE file."); - return Error::InvalidProgram; -#endif } } @@ -518,17 +425,7 @@ Result Program::get_output_flattening_encoding( if (!plan.ok()) { return plan.error(); } - auto* container_meta_type = plan.get()->container_meta_type(); - ET_CHECK_OR_RETURN_ERROR( - container_meta_type != nullptr, - InvalidProgram, - "Missing container_meta_type in execution plan"); - auto* encoded_out_str = container_meta_type->encoded_out_str(); - ET_CHECK_OR_RETURN_ERROR( - encoded_out_str != nullptr, - InvalidProgram, - "Missing encoded_out_str in container_meta_type"); - return encoded_out_str->c_str(); + return plan.get()->container_meta_type()->encoded_out_str()->c_str(); } Error Program::get_backend_delegate_data( @@ -588,18 +485,8 @@ Result Program::LoadSegment( // Could fail if offset and size are out of bound for the data, or if this // is reading from a file and fails, or for many other reasons depending on // the implementation of the loader. - uint64_t seg_offset = segment->offset(); - uint64_t absolute_offset = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows( - segment_base_offset_, seg_offset, &absolute_offset) && - absolute_offset <= SIZE_MAX, - InvalidProgram, - "segment_base_offset %zu + segment offset %" PRIu64 " overflows", - segment_base_offset_, - seg_offset); return loader_->load( - static_cast(absolute_offset), segment->size(), segment_info); + segment_base_offset_ + segment->offset(), segment->size(), segment_info); } Error Program::load_mutable_subsegment_into( @@ -666,15 +553,8 @@ Error Program::load_mutable_subsegment_into( auto segment = internal_program_->segments()->Get(segment_offsets->segment_index()); - // Check size (with overflow protection) - size_t end_offset = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows(offset, size, &end_offset), - InvalidProgram, - "offset %zu + size %zu overflows", - offset, - size); - if (end_offset > segment->size()) { + // Check size + if (offset + size > segment->size()) { ET_LOG( Error, "offset %zu + size %zu out of range > %" PRIu64, @@ -689,26 +569,9 @@ Error Program::load_mutable_subsegment_into( segment_offsets->segment_index(), nullptr); - // Load the data (with overflow protection on the addition chain) - uint64_t seg_offset = segment->offset(); - uint64_t base_plus_seg_64 = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows( - segment_base_offset_, seg_offset, &base_plus_seg_64) && - base_plus_seg_64 <= SIZE_MAX, - InvalidProgram, - "segment_base_offset %zu + segment offset %" PRIu64 " overflows", - segment_base_offset_, - seg_offset); - size_t base_plus_seg = static_cast(base_plus_seg_64); - size_t total_offset = 0; - ET_CHECK_OR_RETURN_ERROR( - !c10::add_overflows(base_plus_seg, offset, &total_offset), - InvalidProgram, - "segment base+offset %zu + subsegment offset %zu overflows", - base_plus_seg, - offset); - return loader_->load_into(total_offset, size, info, buffer); + // Load the data + return loader_->load_into( + segment_base_offset_ + segment->offset() + offset, size, info, buffer); } } // namespace ET_RUNTIME_NAMESPACE diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/program.h similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/program.h index e1208e5..768928a 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/program.h @@ -8,10 +8,10 @@ #pragma once +#include #include #include -#include #include #include #include @@ -21,7 +21,6 @@ #include #include #include -#include #include // Forward declare flatbuffer types. This is a public header and must not @@ -59,15 +58,10 @@ class Program final { */ Minimal, /** - * When ET_ENABLE_PROGRAM_VERIFICATION is enabled, * Do full verification of the data, ensuring that internal pointers are * self-consistent and that the data has not been truncated or obviously * corrupted. May not catch all types of corruption, but should guard * against illegal memory operations during parsing. - * Also performs additional semantic validation such as: - * - Tensor numel overflow checks (ensuring size calculations don't - * overflow) - * - List element type validation * * Will have higher runtime overhead, scaling with the complexity of the * proram data. @@ -141,9 +135,6 @@ class Program final { * @param[in] event_tracer The event tracer to use for this method run. * @param[in] named_data_map An optional map of {name, blob} used to resolve * data that is external to the PTE, if any. - * @param[in] backend_options An optional map of per-backend load-time options - * (RuntimeSpecs). Each backend will receive its corresponding options - * during initialization. * * @returns The loaded method on success, or an error on failure. */ @@ -151,9 +142,7 @@ class Program final { const char* method_name, MemoryManager* memory_manager, EventTracer* event_tracer = nullptr, - const NamedDataMap* named_data_map = nullptr, - const LoadBackendOptionsMap* backend_options = nullptr, - Span kernel_registry = {}) const; + const NamedDataMap* named_data_map = nullptr) const; /** * Gathers metadata for the named method. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/pte_data_map.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/pte_data_map.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/pte_data_map.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/pte_data_map.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/pte_data_map.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/pte_data_map.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/pte_data_map.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/pte_data_map.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/targets.bzl new file mode 100644 index 0000000..28defd6 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/targets.bzl @@ -0,0 +1,127 @@ +load("@fbsource//xplat/executorch/build:build_variables.bzl", "PROGRAM_NO_PRIM_OPS_SRCS") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def _program_preprocessor_flags(): + """Returns the preprocessor_flags to use when building Program.cpp""" + + # The code for flatbuffer verification can add ~30k of .text to the binary. + # It's a valuable feature, but make it optional for space-constrained + # systems. + enable_verification = native.read_config( + "executorch", + "enable_program_verification", + # Default value + "true", + ) + if enable_verification == "false": + return ["-DET_ENABLE_PROGRAM_VERIFICATION=0"] + elif enable_verification == "true": + # Enabled by default. + return [] + else: + fail("executorch.enable_program_verification must be one of 'true' or 'false'; saw '" + + enable_verification + "'") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "memory_manager", + exported_headers = [ + "memory_manager.h", + ], + exported_deps = [ + "//executorch/runtime/core:memory_allocator", + ], + visibility = ["PUBLIC"], + ) + + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_library( + name = "pte_data_map" + aten_suffix, + srcs = [ + "pte_data_map.cpp", + ], + exported_headers = [ + "pte_data_map.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:named_data_map" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + ], + deps = [ + "//executorch/schema:program", + ], + exported_preprocessor_flags = [] if runtime.is_oss else ["-DEXECUTORCH_INTERNAL_FLATBUFFERS=1"], + ) + + runtime.cxx_library( + name = "merged_data_map" + aten_suffix, + exported_headers = [ + "merged_data_map.h", + ], + exported_deps = [ + "//executorch/runtime/core:named_data_map" + aten_suffix, + ], + ) + + runtime.cxx_library( + name = "program" + aten_suffix, + exported_deps = [ + ":program_no_prim_ops" + aten_suffix, + "//executorch/kernels/prim_ops:prim_ops_registry" + aten_suffix, + ], + visibility = ["PUBLIC"], + ) + + runtime.cxx_library( + name = "program_no_prim_ops" + aten_suffix, + srcs = PROGRAM_NO_PRIM_OPS_SRCS + [ + "tensor_parser{}.cpp".format(aten_suffix if aten_mode else "_portable"), + ], + headers = [ + "platform_memory_allocator.h", + ], + exported_headers = [ + "method.h", + "method_meta.h", + "program.h", + "tensor_parser.h", + ], + compiler_flags = select({ + "ovr_config//os:windows": [], + "DEFAULT" :["-Wno-error=deprecated-declarations"] + }), + preprocessor_flags = _program_preprocessor_flags(), + exported_deps = [ + ":memory_manager", + ":pte_data_map" + aten_suffix, + ":merged_data_map" + aten_suffix, + "//executorch/runtime/backend:interface" + aten_suffix, + "//executorch/runtime/core:core", + "//executorch/runtime/core:named_data_map" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/core:event_tracer" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + "//executorch/runtime/kernel:operator_registry" + aten_suffix, + "//executorch/runtime/platform:platform", + "//executorch/schema:extended_header", + ], + deps = [ + "//executorch/schema:program", + "//executorch/runtime/core/exec_aten/util:tensor_dimension_limit" + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser.h similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser.h index d4ab2ff..fae183e 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser.h @@ -97,12 +97,8 @@ ET_NODISCARD Result>> parseListOptionalType( InvalidProgram, "Invalid value index %" PRId32 " for ListOptional", index); - auto optional_result = values[index].tryToOptional(); - if (!optional_result.ok()) { - return optional_result.error(); - } new (&optional_tensor_list[output_idx]) - std::optional(std::move(optional_result.get())); + std::optional(values[index].toOptional()); evalp_list[output_idx] = &values[static_cast(index)]; } output_idx++; diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_aten.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_aten.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_exec_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_exec_aten.cpp similarity index 87% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_exec_aten.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_exec_aten.cpp index 31ec237..2e91833 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/tensor_parser_exec_aten.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_exec_aten.cpp @@ -41,10 +41,6 @@ ET_NODISCARD Result getMemPlannedPtr( const executorch_flatbuffer::AllocationDetails* allocation_info, size_t nbytes, HierarchicalAllocator* allocator) { - ET_CHECK_OR_RETURN_ERROR( - allocator != nullptr, - InvalidState, - "HierarchicalAllocator must not be null for memory-planned tensor"); // Normal non-constant Tensor. Allocate data using mem_id and offset. // TODO(T142455629): make the allocator actually id based and not indexed @@ -102,15 +98,10 @@ ET_NODISCARD Result> parseTensorList( "Invalid value index %" PRId32 " for TensorList", tensor_index); - auto tensor_result = - values[static_cast(tensor_index)].tryToTensor(); - if (!tensor_result.ok()) { - return tensor_result.error(); - } // Placement new as the list elements are not initialized, so calling // copy assignment is not defined if it's non trivial. - new (&tensor_list[output_idx]) - executorch::aten::Tensor(std::move(tensor_result.get())); + new (&tensor_list[output_idx]) executorch::aten::Tensor( + values[static_cast(tensor_index)].toTensor()); evalp_list[output_idx] = &values[static_cast(tensor_index)]; output_idx++; } @@ -138,12 +129,6 @@ ET_NODISCARD Error validateTensorLayout( "Dim mismatch. Expected %d, got %zu.", dim, expected_layout.sizes().size()); - ET_CHECK_OR_RETURN_ERROR( - s_tensor->dim_order()->size() == static_cast(dim), - InvalidExternalData, - "Dim order size mismatch. Expected %d, got %u.", - dim, - s_tensor->dim_order()->size()); for (int i = 0; i < dim; i++) { ET_CHECK_OR_RETURN_ERROR( s_tensor->sizes()->Get(i) == expected_layout.sizes()[i], @@ -174,14 +159,6 @@ NamedData* get_data_by_key(const char* key, Span entries) { return nullptr; } -// Suppress a GCC 11 false positive -Wstringop-overread triggered by -// flatbuffers' GetPointer inlining into string_view construction. -// Guarded to GCC >= 11 since the warning doesn't exist on older GCC or Clang. -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 11 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstringop-overread" -#endif - ET_NODISCARD Result getTensorDataPtr( const executorch_flatbuffer::Tensor* s_tensor, const Program* program, @@ -193,13 +170,6 @@ ET_NODISCARD Result getTensorDataPtr( const executorch_flatbuffer::AllocationDetails* allocation_info = s_tensor->allocation_info(); - if (allocation_info != nullptr) { - ET_CHECK_OR_RETURN_ERROR( - allocator != nullptr, - InvalidState, - "HierarchicalAllocator is null but tensor has allocation_info requiring memory-planned buffers"); - } - // External tensors. if (s_tensor->extra_tensor_info() != nullptr && s_tensor->extra_tensor_info()->location() == @@ -289,10 +259,6 @@ ET_NODISCARD Result getTensorDataPtr( } } -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 11 -#pragma GCC diagnostic pop -#endif - } // namespace deserialization } // namespace ET_RUNTIME_NAMESPACE } // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_portable.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_portable.cpp similarity index 90% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_portable.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_portable.cpp index 2fc9a2d..02cb019 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/tensor_parser_portable.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/tensor_parser_portable.cpp @@ -147,18 +147,6 @@ Result parseTensor( Internal, "dim_order_to_stride returned invalid status"); - // Extract device info from serialized tensor metadata. - // Defaults to CPU/0 for backward compatibility when extra_tensor_info is - // absent (e.g., older PTE files without device annotations). - auto device_type = executorch::runtime::etensor::DeviceType::CPU; - executorch::runtime::etensor::DeviceIndex device_index = 0; - if (s_tensor->extra_tensor_info() != nullptr) { - device_type = static_cast( - s_tensor->extra_tensor_info()->device_type()); - device_index = static_cast( - s_tensor->extra_tensor_info()->device_index()); - } - auto* tensor_impl = method_allocator->allocateInstance(); if (tensor_impl == nullptr) { return Error::MemoryAllocationFailed; @@ -173,9 +161,7 @@ Result parseTensor( /*data=*/nullptr, dim_order, strides, - dynamism, - device_type, - device_index); + dynamism); // Now that we know how big the tensor is, find and assign its memory. Result data_ptr = getTensorDataPtr( diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/CMakeLists.txt new file mode 100644 index 0000000..5477831 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/CMakeLists.txt @@ -0,0 +1,194 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + # Use a wrapper script to set up the environment for MSVC to make Dynamo + # export work. + set(_export_program_cmd + powershell + ${EXECUTORCH_ROOT}/kernels/test/export_test_model.ps1 + -Modules + "\"ModuleAdd,ModuleAddHalf,ModuleAddMul,ModuleDynamicCatUnallocatedIO,ModuleIndex,ModuleMultipleEntry,ModuleSimpleTrain,ModuleStateful\"" + -outDir + "${CMAKE_CURRENT_BINARY_DIR}" + -CondaEnv + $ENV{CONDA_DEFAULT_ENV} + ) +else() + set(_export_program_cmd + ${PYTHON_EXECUTABLE} + -m + test.models.export_program + --modules + "ModuleAdd,ModuleAddHalf,ModuleAddMul,ModuleDynamicCatUnallocatedIO,ModuleIndex,ModuleMultipleEntry,ModuleSimpleTrain,ModuleStateful" + --outdir + "${CMAKE_CURRENT_BINARY_DIR}" + ) +endif() + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddHalf.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMul.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.ptd" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleDynamicCatUnallocatedIO.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleIndex.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleMultipleEntry.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleSimpleTrain.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleStateful.pte" + "${CMAKE_CURRENT_BINARY_DIR}/delegated/ModuleAddMul.pte" + COMMAND ${_export_program_cmd} + COMMAND + ${PYTHON_EXECUTABLE} -m test.models.export_program --modules "ModuleAddMul" + --external-constants --outdir "${CMAKE_CURRENT_BINARY_DIR}" + COMMAND + ${PYTHON_EXECUTABLE} -m test.models.export_delegated_program --modules + "ModuleAddMul" --backend_id "StubBackend" --outdir + "${CMAKE_CURRENT_BINARY_DIR}/delegated/" + WORKING_DIRECTORY ${EXECUTORCH_ROOT} +) + +add_custom_target( + generated_pte_files + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddHalf.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMul.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.ptd" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleDynamicCatUnallocatedIO.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleIndex.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleMultipleEntry.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleSimpleTrain.pte" + "${CMAKE_CURRENT_BINARY_DIR}/ModuleStateful.pte" +) + +set(test_env + "DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH=${EXECUTORCH_ROOT}/test/models/deprecated/ModuleLinear-no-constant-segment.pte" + "ET_MODULE_ADD_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAdd.pte" + "ET_MODULE_ADD_HALF_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddHalf.pte" + "ET_MODULE_ADD_MUL_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMul.pte" + "ET_MODULE_ADD_MUL_PROGRAM_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.pte" + "ET_MODULE_ADD_MUL_DATA_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleAddMulProgram.ptd" + "ET_MODULE_DYNAMIC_CAT_UNALLOCATED_IO_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleDynamicCatUnallocatedIO.pte" + "ET_MODULE_INDEX_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleIndex.pte" + "ET_MODULE_MULTI_ENTRY_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleMultipleEntry.pte" + "ET_MODULE_SIMPLE_TRAIN_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleSimpleTrain.pte" + "ET_MODULE_STATEFUL_PATH=${CMAKE_CURRENT_BINARY_DIR}/ModuleStateful.pte" + "ET_MODULE_ADD_MUL_DELEGATED_PATH=${CMAKE_CURRENT_BINARY_DIR}/delegated/ModuleAddMul.pte" +) + +et_cxx_test( + runtime_executor_test SOURCES executor_test.cpp EXTRA_LIBS portable_ops_lib + portable_kernels +) +add_dependencies(runtime_executor_test generated_pte_files) +set_property(TEST runtime_executor_test PROPERTY ENVIRONMENT ${test_env}) + +et_cxx_test( + allocation_failure_stress_test + SOURCES + allocation_failure_stress_test.cpp + EXTRA_LIBS + portable_ops_lib + portable_kernels + extension_data_loader + extension_runner_util +) +add_dependencies(allocation_failure_stress_test generated_pte_files) +set_property( + TEST allocation_failure_stress_test PROPERTY ENVIRONMENT ${test_env} +) + +et_cxx_test( + method_test + SOURCES + method_test.cpp + EXTRA_LIBS + portable_ops_lib + portable_kernels + extension_data_loader + extension_flat_tensor + extension_runner_util +) +add_dependencies(method_test generated_pte_files) +set_property(TEST method_test PROPERTY ENVIRONMENT ${test_env}) + +# TODO(T191569140): Enable this test. et_cxx_test(method_meta_test SOURCES +# method_meta_test.cpp EXTRA_LIBS extension_data_loader) + +# TODO(T191569140): Enable this test. et_cxx_test( program_test SOURCES +# program_test.cpp EXTRA_LIBS extension_data_loader ) + +# target_include_directories( program_test PRIVATE +# "${CMAKE_INSTALL_PREFIX}/schema/include" +# "${EXECUTORCH_ROOT}/third-party/flatbuffers/include" ) + +et_cxx_test( + kernel_resolution_test SOURCES kernel_resolution_test.cpp EXTRA_LIBS + extension_data_loader +) +add_dependencies(kernel_resolution_test generated_pte_files) +set_property(TEST kernel_resolution_test PROPERTY ENVIRONMENT ${test_env}) + +et_cxx_test( + kernel_integration_test SOURCES kernel_integration_test.cpp EXTRA_LIBS + extension_data_loader extension_runner_util +) +add_dependencies(kernel_integration_test generated_pte_files) +set_property(TEST kernel_integration_test PROPERTY ENVIRONMENT ${test_env}) + +# TODO(T191569140): Enable this test. et_cxx_test( backend_integration_test +# SOURCES backend_integration_test.cpp EXTRA_LIBS extension_data_loader +# extension_runner_util ) + +et_cxx_test(memory_manager_test SOURCES memory_manager_test.cpp) +add_dependencies(memory_manager_test generated_pte_files) +set_property(TEST memory_manager_test PROPERTY ENVIRONMENT ${test_env}) + +et_cxx_test( + tensor_parser_test + SOURCES + tensor_parser_test.cpp + EXTRA_LIBS + portable_ops_lib + portable_kernels + extension_data_loader + extension_runner_util + program_schema +) +add_dependencies(tensor_parser_test generated_pte_files) +set_property(TEST tensor_parser_test PROPERTY ENVIRONMENT ${test_env}) + +target_include_directories( + tensor_parser_test + PRIVATE "${CMAKE_INSTALL_PREFIX}/schema/include" + "${EXECUTORCH_ROOT}/third-party/flatbuffers/include" +) + +list(TRANSFORM _test_backend_compiler_lib__srcs PREPEND "${EXECUTORCH_ROOT}/") +add_library( + test_backend_compiler_lib STATIC ${_test_backend_compiler_lib__srcs} +) + +target_link_libraries(test_backend_compiler_lib PUBLIC executorch_core) + +executorch_target_link_options_shared_lib(test_backend_compiler_lib) + +install(TARGETS test_backend_compiler_lib DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/TARGETS new file mode 100644 index 0000000..a6c52d1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets(is_fbcode = True) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/allocation_failure_stress_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/allocation_failure_stress_test.cpp new file mode 100644 index 0000000..37f3a51 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/allocation_failure_stress_test.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::aten::Scalar; +using executorch::aten::Tensor; +using executorch::extension::FileDataLoader; +using executorch::extension::prepare_input_tensors; +using executorch::runtime::Error; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::MemoryManager; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::testing::ManagedMemoryManager; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class AllocationFailureStressTest : public ::testing::Test { + protected: + void SetUp() override { + executorch::runtime::runtime_init(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + } + + private: + // Must outlive program_, but tests shouldn't need to touch it. + std::unique_ptr loader_; + + protected: + std::unique_ptr program_; +}; + +/** + * Slowly increases the amount of available runtime memory until load_method() + * and execute() succeed. This should cause every runtime allocation to fail at + * some point, exercising every allocation failure path reachable by the test + * model. + */ +TEST_F(AllocationFailureStressTest, End2EndIncreaseRuntimeMemUntilSuccess) { + size_t runtime_mem_bytes = 0; + Error err = Error::Internal; + size_t num_load_failures = 0; + while (runtime_mem_bytes < kDefaultRuntimeMemBytes && err != Error::Ok) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, runtime_mem_bytes); + + // Loading should fail several times from allocation failures. + Result method = program_->load_method("forward", &mmm.get()); + if (method.error() != Error::Ok) { + runtime_mem_bytes += sizeof(size_t); + num_load_failures++; + continue; + } + + // Execution does not use the runtime allocator, so it should always succeed + // once load was successful. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + err = method->execute(); + ASSERT_EQ(err, Error::Ok); + } + EXPECT_GT(num_load_failures, 0) << "Expected at least some failures"; + EXPECT_EQ(err, Error::Ok) + << "Did not succeed after increasing runtime_mem_bytes to " + << runtime_mem_bytes; +} + +/** + * Slowly increases the amount of available non-constant memory until + * load_method() and execute() succeed. This should cause every non-const + * allocation to fail at some point, exercising every allocation failure path + * reachable by the test model. + */ +TEST_F(AllocationFailureStressTest, End2EndNonConstantMemUntilSuccess) { + size_t non_constant_mem_bytes = 0; + Error err = Error::Internal; + size_t num_load_failures = 0; + while (non_constant_mem_bytes < kDefaultNonConstMemBytes && + err != Error::Ok) { + ManagedMemoryManager mmm(non_constant_mem_bytes, kDefaultRuntimeMemBytes); + + // Loading should fail several times from allocation failures. + Result method = program_->load_method("forward", &mmm.get()); + if (method.error() != Error::Ok) { + non_constant_mem_bytes += sizeof(size_t); + num_load_failures++; + continue; + } + + // Execution does not use the runtime allocator, so it should always succeed + // once load was successful. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + err = method->execute(); + ASSERT_EQ(err, Error::Ok); + } + EXPECT_GT(num_load_failures, 0) << "Expected at least some failures"; + EXPECT_EQ(err, Error::Ok) + << "Did not succeed after increasing non_constant_mem_bytes to " + << non_constant_mem_bytes; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_data_separation_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_data_separation_test.cpp new file mode 100644 index 0000000..f6af25c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_data_separation_test.cpp @@ -0,0 +1,116 @@ + +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::FlatTensorDataMap; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class BackendDataSeparationTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Make sure that the backend has been registered. Safe to call multiple + // times. Doing this at runtime ensures that it's only registered if these + // tests are run. + ASSERT_EQ(example::register_executor_backend(), Error::Ok); + + // Create data loaders. + Result linear_program_loader = FileDataLoader::from( + std::getenv("ET_MODULE_LINEAR_DELEGATE_PROGRAM_PATH")); + ASSERT_EQ(linear_program_loader.error(), Error::Ok); + linear_program_loader_ = std::make_unique( + std::move(linear_program_loader.get())); + + Result linear_data_loader = + FileDataLoader::from(std::getenv("ET_MODULE_LINEAR_DATA_PATH")); + ASSERT_EQ(linear_data_loader.error(), Error::Ok); + linear_data_loader_ = + std::make_unique(std::move(linear_data_loader.get())); + + // Create programs. + Result linear_program = Program::load( + linear_program_loader_.get(), + Program::Verification::InternalConsistency); + ASSERT_EQ(linear_program.error(), Error::Ok); + linear_program_ = + std::make_unique(std::move(linear_program.get())); + + Result linear_data_map = + FlatTensorDataMap::load(linear_data_loader_.get()); + EXPECT_EQ(linear_data_map.error(), Error::Ok); + linear_data_map_ = + std::make_unique(std::move(linear_data_map.get())); + + ET_LOG( + Info, + "setup done, named_data_map_ = %lu", + linear_data_map_->get_num_keys().get()); + } + + private: + std::unique_ptr linear_program_loader_; + std::unique_ptr linear_data_loader_; + + protected: + std::unique_ptr linear_program_; + std::unique_ptr linear_data_map_; +}; + +TEST_F(BackendDataSeparationTest, TestSeparation) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = linear_program_->load_method( + "forward", + &mmm.get(), + /*event_tracer=*/nullptr, + /*named_data_map=*/linear_data_map_.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[1] = {3}; + uint8_t dim_order[1] = {0}; + int32_t strides[1] = {1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 1, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_integration_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_integration_test.cpp new file mode 100644 index 0000000..c55269d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/backend_integration_test.cpp @@ -0,0 +1,745 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::runtime::BackendExecutionContext; +using executorch::runtime::BackendInitContext; +using executorch::runtime::BackendInterface; +using executorch::runtime::CompileSpec; +using executorch::runtime::DataLoader; +using executorch::runtime::DelegateHandle; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +/** + * A backend class whose methods can be overridden individually. + */ +class StubBackend final : public BackendInterface { + public: + // Function signature types that match the BackendInterface methods. + using IsAvailableFn = std::function; + using InitFn = std::function( + FreeableBuffer*, + ArrayRef, + BackendInitContext&)>; + using ExecuteFn = std::function< + Error(BackendExecutionContext&, DelegateHandle*, Span)>; + using DestroyFn = std::function; + + // Default name that this backend is registered as. + static constexpr char kName[] = "StubBackend"; + + void install_is_available(IsAvailableFn fn) { + is_available_fn_ = fn; + } + + bool is_available() const override { + if (is_available_fn_) { + return is_available_fn_.value()(); + } + // Return a benign value otherwise. + return true; + } + + void install_init(InitFn fn) { + init_fn_ = fn; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + if (init_fn_) { + return init_fn_.value()(processed, compile_specs, context); + } + // Return a benign value otherwise. + return nullptr; + } + + void install_execute(ExecuteFn fn) { + execute_fn_ = fn; + } + + Error execute( + BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + if (execute_fn_) { + return execute_fn_.value()(context, handle, args); + } + // Return a benign value otherwise. + return Error::Ok; + } + + void install_destroy(DestroyFn fn) { + destroy_fn_ = fn; + } + + void destroy(DelegateHandle* handle) const override { + if (destroy_fn_) { + destroy_fn_.value()(handle); + } + } + + /** + * Resets to the original constructed state. + */ + void reset() { + is_available_fn_.reset(); + init_fn_.reset(); + execute_fn_.reset(); + destroy_fn_.reset(); + } + + /** + * Registers the singleton instance if not already registered. + * + * Note that this can be used to install the stub as the implementation for + * any export-time backend by passing in the right name, as long as no other + * backend with that name has been registered yet. + */ + static Error register_singleton(const char* name = kName) { + if (!registered_) { + registered_ = true; + return executorch::runtime::register_backend({name, &singleton_}); + } + return Error::Ok; + } + + /** + * Returns the instance that was added to the backend registry. + */ + static StubBackend& singleton() { + return singleton_; + } + + private: + static bool registered_; + static StubBackend singleton_; + + std::optional is_available_fn_; + std::optional init_fn_; + std::optional execute_fn_; + std::optional destroy_fn_; +}; + +bool StubBackend::registered_ = false; +StubBackend StubBackend::singleton_; + +/** + * A DataLoader that wraps a real DataLoader and records the operations + * performed on it and the FreeableBuffers it loads. + */ +class DataLoaderSpy final : public DataLoader { + public: + /// A record of an operation performed on this DataLoader. + struct Operation { + enum { Load, Free } op; + size_t offset; // Set for Load; zero for Free. + void* data; // Set for Free; nullptr for Load. + size_t size; // Set for Load and Free. + std::unique_ptr + segment_info; // Set for Load; nullptr for Free. + }; + + explicit DataLoaderSpy(DataLoader* delegate) : delegate_(delegate) {} + + Result load( + size_t offset, + size_t size, + const SegmentInfo& segment_info) const override { + Result buf = delegate_->load(offset, size, segment_info); + if (!buf.ok()) { + return buf.error(); + } + + auto segment_info_cpy = + std::make_unique(segment_info); + operations_.push_back( + {Operation::Load, + offset, + /*data=*/nullptr, + size, + /*segment_info=*/std::move(segment_info_cpy)}); + auto* context = new SpyContext(&operations_, std::move(buf.get())); + // Use context->buffer since buf has been moved. + return FreeableBuffer( + context->buffer.data(), context->buffer.size(), FreeBuffer, context); + } + + Result size() const override { + return delegate_->size(); + } + + /** + * Returns records of the operations performed on this DataLoader and the + * FreeableBuffers it returned, in order they were performed. + */ + const std::vector& operations() const { + return operations_; + } + + /** + * Returns true if the DataLoader::load() method was called with the correct + * segment info. + */ + bool UsedLoad( + DataLoader::SegmentInfo::Type segment_type, + const char* descriptor = nullptr) const { + for (const auto& op : operations_) { + if (op.op != Operation::Load) { + continue; + } + // We have a load op. + if (op.segment_info->segment_type == segment_type) { + if (segment_type != DataLoader::SegmentInfo::Type::Backend) { + // For non-backend segments, the descriptor is irrelevant / a nullptr. + return true; + } else { + if (strcmp(op.segment_info->descriptor, descriptor) == 0) { + return true; + } + } + } + } + return false; + } + + /** + * Returns true if the operations list shows that the provided data pointer + * was freed. + */ + bool WasFreed(const void* data) const { + for (const auto& op : operations_) { + if (op.op == Operation::Free && op.data == data) { + return true; + } + } + return false; + } + + private: + struct SpyContext { + SpyContext(std::vector* operations, FreeableBuffer&& buffer) + : operations(operations), buffer(std::move(buffer)) {} + std::vector* operations; + FreeableBuffer buffer; + }; + + static void FreeBuffer(void* context, void* data, size_t size) { + auto* sc = reinterpret_cast(context); + sc->operations->push_back( + {Operation::Free, /*offset=*/0, data, size, /*segment_info=*/nullptr}); + delete sc; + } + + /// The real loader to delegate to. + DataLoader* delegate_; + + mutable std::vector operations_; +}; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024; + +class BackendIntegrationTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Make sure that the backend has been registered. Safe to call multiple + // times. Doing this at runtime ensures that it's only registered if these + // tests are run. + ASSERT_EQ(StubBackend::register_singleton(), Error::Ok); + + // Paths to the test program files. + program_path_ = std::getenv("ET_MODULE_ADD_MUL_DELEGATED_PATH"); + ASSERT_FALSE(program_path_.empty()); + program_nosegments_path_ = std::getenv("ET_MODULE_ADD_MUL_NOSEGMENTS_PATH"); + ASSERT_FALSE(program_nosegments_path_.empty()); + } + + void TearDown() override { + // Clean up any modifications to the singleton. + StubBackend::singleton().reset(); + } + + /** + * Returns true if program_path() returns a file with extracted segments. + */ + bool using_segments() const { + return GetParam(); + } + + /** + * Returns tha path to the program to load. May or may not have extracted + * segments, depending on the return value of using_segments(). + */ + const char* program_path() const { + if (using_segments()) { + return program_path_.c_str(); + } else { + return program_nosegments_path_.c_str(); + } + } + + private: + std::string program_path_; + std::string program_nosegments_path_; +}; + +TEST_P(BackendIntegrationTest, BackendIsPresent) { + BackendInterface* backend = + executorch::runtime::get_backend_class(StubBackend::kName); + ASSERT_EQ(backend, &StubBackend::singleton()); +} + +// Demonstrate that installed StubBackend initializes successfully by default. +TEST_P(BackendIntegrationTest, BasicInitSucceeds) { + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + + Result program = Program::load(&loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + auto method_meta = program->method_meta("forward"); + EXPECT_EQ(method_meta->uses_backend(StubBackend::kName), true); + EXPECT_EQ(method_meta->uses_backend("INVALID_BACKEND_NAME"), false); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_EQ(method_res.error(), Error::Ok); +} + +TEST_P(BackendIntegrationTest, GetBackendNamesSuccess) { + // Load the program from file. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + + Result program = Program::load(&loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // Get method metadata for the "forward" method. + auto method_meta = program->method_meta("forward"); + + // Ensure the StubBackend is used. + EXPECT_TRUE(method_meta->uses_backend(StubBackend::kName)); + + // Retrieve the number of backends. + const size_t num_backends = method_meta->num_backends(); + EXPECT_GT(num_backends, 0u); + + // Iterate through each backend and verify its name. + for (size_t i = 0; i < num_backends; ++i) { + auto backend_name_result = method_meta->get_backend_name(i); + ASSERT_TRUE(backend_name_result.ok()); + const char* name = backend_name_result.get(); + // For this test, we expect that the only backend is StubBackend. + EXPECT_STREQ(name, StubBackend::kName); + } + // Check that an out-of-range index returns an error. + auto out_of_range_result = method_meta->get_backend_name(num_backends); + EXPECT_FALSE(out_of_range_result.ok()); +} + +TEST_P(BackendIntegrationTest, FreeingProcessedBufferSucceeds) { + // Install an init() implementation that frees its processed buffer, and lets + // us know that it was actually called by setting init_called. + bool init_called = false; + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + init_called = true; + processed_data = processed->data(); + processed->Free(); + return nullptr; + }); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_EQ(method_res.error(), Error::Ok); + + // Demonstrate that our installed init was called. + EXPECT_TRUE(init_called); + + // See if the processed data was freed. + bool processed_was_freed = spy_loader.WasFreed(processed_data); + if (using_segments()) { + // Used the loader to create the FreeableBuffer that was passed to the + // backend, so we can see its Free() call. + EXPECT_TRUE(processed_was_freed); + } else { + // Didn't use the loader to create the FreeableBuffer that was passed to the + // backend, so we can't see its Free() call. + EXPECT_FALSE(processed_was_freed); + } +} + +TEST_P(BackendIntegrationTest, EndToEndTestWithProcessedAsHandle) { + // Install an init() implementation that does not free its processed buffer, + // and returns the FreeableBuffer as the delegate handle. + FreeableBuffer* init_processed = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + init_processed = processed; + return processed; + }); + + // Install an execute() that expects the handle to be the processed + // FreeableBuffer. + DelegateHandle* execute_handle = nullptr; + StubBackend::singleton().install_execute( + [&](ET_UNUSED BackendExecutionContext& backend_execution_context, + DelegateHandle* handle, + ET_UNUSED Span args) -> Error { + execute_handle = handle; + auto* processed = reinterpret_cast(handle); + + // Read the data, which will tend to cause an ASAN error if it's not + // valid. + auto copy = std::make_unique(processed->size()); + std::memcpy(copy.get(), processed->data(), processed->size()); + + return Error::Ok; + }); + + // Install a destroy() that expects the handle to be the processed + // FreeableBuffer. + DelegateHandle* destroy_handle = nullptr; + StubBackend::singleton().install_destroy( + [&](DelegateHandle* handle) -> void { destroy_handle = handle; }); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + + // Hold onto the address of the processed buffer so we can compare against + // it after the FreeableBuffer has been destroyed. + const void* processed_data; + + // Add a scope so we can watch executor be destroyed. + { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method_res.ok()); + + // Demonstrate that our installed init was called. + EXPECT_NE(init_processed, nullptr); + // Not freed yet. + EXPECT_GT(init_processed->size(), 0); + EXPECT_NE(init_processed->data(), nullptr); + processed_data = init_processed->data(); + + // The processed data should not have been freed during init. + EXPECT_FALSE(spy_loader.WasFreed(init_processed->data())); + auto method(std::move(method_res.get())); + // Execute the model. + auto input_cleanup = executorch::extension::prepare_input_tensors(method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto err = method.execute(); + EXPECT_EQ(err, Error::Ok); + + // Check that the processed buffer was passed to execute() as the handle. + EXPECT_EQ(init_processed, execute_handle); + + // The processed data should not have been freed during execution. + EXPECT_FALSE(spy_loader.WasFreed(init_processed->data())); + } + + // `executor` has now been destroyed, which should have freed the processed + // data. + bool processed_was_freed = spy_loader.WasFreed(processed_data); + if (using_segments()) { + // Used the loader to create the FreeableBuffer that was passed to the + // backend, so we can see its Free() call. + EXPECT_TRUE(processed_was_freed); + } else { + // Didn't use the loader to create the FreeableBuffer that was passed to the + // backend, so we can't see its Free() call. + EXPECT_FALSE(processed_was_freed); + } + + // And it should have destroyed the backend handle. + EXPECT_EQ(execute_handle, destroy_handle); +} + +/** + * Tests that the DataLoader's load is receiving the correct segment info for + * different types of segments. + */ +TEST_P(BackendIntegrationTest, SegmentInfoIsPassedIntoDataLoader) { + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + processed_data = processed->data(); + processed->Free(); + return nullptr; + }); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + // Expect that load was called correctly on program segments. + bool program_load_was_called = + spy_loader.UsedLoad(DataLoader::SegmentInfo::Type::Program, nullptr); + + // Load a method. + Result method_res = program->load_method("forward", &mmm.get()); + EXPECT_EQ(method_res.error(), Error::Ok); + + // Expect that load was called correctly on a backend segment. + bool backend_load_was_called = spy_loader.UsedLoad( + DataLoader::SegmentInfo::Type::Backend, + "StubBackend"); // This backend id is taken from the StubBackend defined + // in export_delegated_program.py. + + EXPECT_TRUE(program_load_was_called); + EXPECT_EQ(backend_load_was_called, using_segments()); +} + +TEST_P(BackendIntegrationTest, GetMethodNameDuringInitSuccess) { + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + auto method_name = backend_init_context.get_method_name(); + // Ensure that we can get the method name during init via context + EXPECT_STREQ(method_name, "forward"); + processed_data = processed->data(); + return nullptr; + }); + Result program = Program::load(&loader.get()); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method.ok()); + ASSERT_EQ(program.error(), Error::Ok); +} + +TEST_P(BackendIntegrationTest, GetMethodNameDuringExecuteSuccess) { + Result loader = FileDataLoader::from(program_path()); + ASSERT_EQ(loader.error(), Error::Ok); + StubBackend::singleton().install_execute( + [&](BackendExecutionContext& backend_execution_context, + ET_UNUSED DelegateHandle* handle, + ET_UNUSED Span args) -> Error { + // Ensure that we can get the method name during execution via context + auto method_name = backend_execution_context.get_method_name(); + EXPECT_STREQ(method_name, "forward"); + return Error::Ok; + }); + Result program = Program::load(&loader.get()); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method.ok()); + + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 1); + input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 2); + ASSERT_EQ(input_err, Error::Ok); + + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +// TODO: Add more tests for the runtime-to-backend interface. E.g.: +// - Errors during init() or execute() result in runtime init/execution failures +// - Correct values are passed to init()/execute() +// - Demonstrate use of the runtime allocator +// - ... + +// Run all BackendIntegrationTests multiple times, varying the return value of +// `GetParam()` based on the `testing::Values` list. The tests will interpret +// the boolean as "using segments". +INSTANTIATE_TEST_SUITE_P( + VariedSegments, + BackendIntegrationTest, + testing::Values(false, true)); + +class DelegateDataAlignmentTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Make sure that the backend has been registered. Safe to call multiple + // times. Doing this at runtime ensures that it's only registered if these + // tests are run. + ASSERT_EQ(StubBackend::register_singleton(), Error::Ok); + + // Paths to the test program files. + default_alignment_program_path_ = + std::getenv("ET_MODULE_ADD_MUL_NOSEGMENTS_PATH"); + ASSERT_FALSE(default_alignment_program_path_.empty()); + override_alignment_program_path_ = + std::getenv("ET_MODULE_ADD_MUL_NOSEGMENTS_DA1024_PATH"); + ASSERT_FALSE(override_alignment_program_path_.empty()); + } + + void TearDown() override { + // Clean up any modifications to the singleton. + StubBackend::singleton().reset(); + } + + /** + * Returns the expected minimum alignment of inline tensor data, given + * the testing parameter. + */ + size_t expected_alignment() const { + if (GetParam()) { + // The delegate data inline alignment used by the -da1024 file. + return 1024; + } else { + // Minimum alignment expected by program.cpp. + return alignof(std::max_align_t); + } + } + + /** + * Returns tha path to the program to load. May or may not have an alignment + * override, depending on the return value of expected_alignment(). + */ + const char* program_path() const { + if (GetParam()) { + return override_alignment_program_path_.c_str(); + } else { + return default_alignment_program_path_.c_str(); + } + } + + private: + std::string default_alignment_program_path_; + std::string override_alignment_program_path_; +}; + +TEST_P(DelegateDataAlignmentTest, ExpectedDataAlignment) { + // Install an init() implementation that records the pointer to the delegate + // data blob so we can check its alignment. + const void* processed_data = nullptr; + StubBackend::singleton().install_init( + [&](FreeableBuffer* processed, + ET_UNUSED ArrayRef compile_specs, + ET_UNUSED BackendInitContext& backend_init_context) + -> Result { + processed_data = processed->data(); + return nullptr; + }); + + // Create a loader that can satisfy the alignment required by this program. + Result loader = + FileDataLoader::from(program_path(), /*alignment=*/expected_alignment()); + ASSERT_EQ(loader.error(), Error::Ok); + + // Wrap the real loader in a spy so we can see which operations were + // performed. + DataLoaderSpy spy_loader(&loader.get()); + + // Load the program. + Result program = Program::load(&spy_loader); + ASSERT_EQ(program.error(), Error::Ok); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = program->load_method("forward", &mmm.get()); + EXPECT_TRUE(method.ok()); + + // Demonstrate that our installed init was called. + EXPECT_NE(processed_data, nullptr); + + // Check that it had the required alignment. The alignment of 1024 is larger + // than the test file with default alignment, so the default alignment cannot + // accidentally satisfy it. + EXPECT_ALIGNED(processed_data, expected_alignment()); +} + +// Run all DelegateDataAlignmentTests multiple times, varying the return value +// of `GetParam()` based on the `testing::Values` list. The tests will interpret +// the boolean as "was inline delegate data alignment overridden to 1024". +INSTANTIATE_TEST_SUITE_P( + VariedAlignment, + DelegateDataAlignmentTest, + testing::Values(false, true)); diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/executor_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/executor_test.cpp new file mode 100644 index 0000000..de5597a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/executor_test.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using executorch::aten::IntArrayRef; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::SizesType; +using executorch::aten::Tensor; +using executorch::ET_RUNTIME_NAMESPACE::get_op_function_from_registry; +using executorch::ET_RUNTIME_NAMESPACE::Kernel; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using executorch::ET_RUNTIME_NAMESPACE::OpFunction; +using executorch::ET_RUNTIME_NAMESPACE::register_kernel; +using executorch::ET_RUNTIME_NAMESPACE::registry_has_op_function; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::testing::TensorFactory; + +namespace pytree = ::executorch::extension::pytree; + +class ExecutorTest : public ::testing::Test { + protected: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(ExecutorTest, Tensor) { + TensorFactory tf; + Tensor a = tf.make({2, 2}, {1, 2, 3, 4}); + + auto data_p = a.const_data_ptr(); + ASSERT_EQ(data_p[0], 1); + ASSERT_EQ(data_p[1], 2); + ASSERT_EQ(data_p[2], 3); + ASSERT_EQ(data_p[3], 4); +} + +TEST_F(ExecutorTest, EValue) { + TensorFactory tf; + Tensor a = tf.make({2, 2}, {1, 2, 3, 4}); + + EValue v(a); + ASSERT_TRUE(v.isTensor()); + ASSERT_EQ(v.toTensor().nbytes(), 16); +} + +/** + * According to the precision limitations listed here: + * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Precision_limitations + * The max precision error for a half in the range [2^n, 2^(n+1)] is 2^(n-10) + */ +float toleranceFloat16(float f) { + return pow(2, static_cast(log2(fabs(f))) - 10); +} + +TEST_F(ExecutorTest, TensorHalf) { + TensorFactory tf; + Tensor a = tf.make({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + + ASSERT_EQ(a.nbytes(), 8); + ASSERT_EQ(a.element_size(), 2); + ASSERT_EQ(a.numel(), 4); + ASSERT_EQ(a.scalar_type(), ScalarType::Half); + + auto data_p = a.const_data_ptr(); + ASSERT_NEAR( + data_p[0], 1.0f, toleranceFloat16(fmax(fabs(1.0f), fabs(data_p[0])))); + ASSERT_NEAR( + data_p[1], 2.0f, toleranceFloat16(fmax(fabs(2.0f), fabs(data_p[1])))); +} + +TEST_F(ExecutorTest, RegistryLookupAndCall) { + const char* op_name = "aten::add.out"; + Result func = get_op_function_from_registry(op_name); + ASSERT_EQ(func.error(), Error::Ok); + ASSERT_NE(*func, nullptr); + + TensorFactory tf; + constexpr size_t num_evalues = 4; + EValue evalues[num_evalues] = { + tf.make({2, 2}, {1, 2, 3, 4}), + tf.make({2, 2}, {5, 6, 7, 8}), + Scalar(1), + tf.make({2, 2}, {0, 0, 0, 0}), + }; + + EValue* kernel_args[5]; + for (size_t i = 0; i < num_evalues; i++) { + kernel_args[i] = &evalues[i]; + } + // x and x_out args are same evalue for out variant kernels + kernel_args[4] = &evalues[3]; + + KernelRuntimeContext context{}; + (*func)(context, Span(kernel_args)); + auto c_ptr = evalues[3].toTensor().const_data_ptr(); + ASSERT_EQ(c_ptr[3], 12); +} + +TEST_F(ExecutorTest, IntArrayRefSingleElement) { + // Create an IntArrayRef with a single element. `ref` will contain a pointer + // to `one`, which must outlive the array ref. + const IntArrayRef::value_type one = 1; + IntArrayRef ref(one); + EXPECT_EQ(ref[0], 1); +} + +TEST_F(ExecutorTest, IntArrayRefDataAndLength) { + // Create an IntArrayRef from an array. `ref` will contain a pointer to + // `array`, which must outlive the array ref. + const IntArrayRef::value_type array[4] = {5, 6, 7, 8}; + const IntArrayRef::size_type length = 4; + IntArrayRef ref(array, length); + + EXPECT_EQ(ref.size(), length); + EXPECT_EQ(ref.front(), 5); + EXPECT_EQ(ref.back(), 8); +} + +TEST_F(ExecutorTest, EValueFromScalar) { + Scalar b((bool)true); + Scalar i((int64_t)2); + Scalar d((double)3.0); + + EValue evalue_b(b); + ASSERT_TRUE(evalue_b.isScalar()); + ASSERT_TRUE(evalue_b.isBool()); + ASSERT_EQ(evalue_b.toBool(), true); + + EValue evalue_i(i); + ASSERT_TRUE(evalue_i.isScalar()); + ASSERT_TRUE(evalue_i.isInt()); + ASSERT_EQ(evalue_i.toInt(), 2); + + EValue evalue_d(d); + ASSERT_TRUE(evalue_d.isScalar()); + ASSERT_TRUE(evalue_d.isDouble()); + ASSERT_NEAR(evalue_d.toDouble(), 3.0, 0.01); +} + +TEST_F(ExecutorTest, EValueToScalar) { + EValue v((int64_t)2); + ASSERT_TRUE(v.isScalar()); + + Scalar s = v.toScalar(); + ASSERT_TRUE(s.isIntegral(false)); + ASSERT_EQ(s.to(), 2); +} + +void test_op(KernelRuntimeContext& /*unused*/, Span /*unused*/) {} + +TEST_F(ExecutorTest, OpRegistration) { + auto s1 = register_kernel(Kernel("test", test_op)); + auto s2 = register_kernel(Kernel("test_2", test_op)); + ASSERT_EQ(Error::Ok, s1); + ASSERT_EQ(Error::Ok, s2); + ET_EXPECT_DEATH( + []() { (void)register_kernel(Kernel("test", test_op)); }(), ""); + + ASSERT_TRUE(registry_has_op_function("test")); + ASSERT_TRUE(registry_has_op_function("test_2")); +} + +TEST_F(ExecutorTest, OpRegistrationWithContext) { + auto op = Kernel( + "test_op_with_context", + [](KernelRuntimeContext& context, Span values) { + (void)context; + *(values[0]) = Scalar(100); + }); + auto s1 = register_kernel(op); + ASSERT_EQ(Error::Ok, s1); + + Result func = + get_op_function_from_registry("test_op_with_context"); + ASSERT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} + +TEST_F(ExecutorTest, AddMulAlreadyRegistered) { + ASSERT_TRUE(registry_has_op_function("aten::add.out")); + ASSERT_TRUE(registry_has_op_function("aten::mul.out")); +} + +TEST(PyTreeEValue, List) { + std::string spec = "L2#1#1($,$)"; + + Scalar i((int64_t)2); + Scalar d((double)3.0); + EValue items[2] = {i, d}; + + auto c = pytree::unflatten(spec, items); + ASSERT_TRUE(c.isList()); + ASSERT_EQ(c.size(), 2); + + const auto& child0 = c[0]; + const auto& child1 = c[1]; + + ASSERT_TRUE(child0.isLeaf()); + ASSERT_TRUE(child1.isLeaf()); + + EValue ev_child0 = child0; + ASSERT_TRUE(ev_child0.isScalar()); + ASSERT_TRUE(ev_child0.isInt()); + ASSERT_EQ(ev_child0.toInt(), 2); + + ASSERT_TRUE(child1.leaf().isScalar()); + ASSERT_TRUE(child1.leaf().isDouble()); + ASSERT_NEAR(child1.leaf().toDouble(), 3.0, 0.01); +} + +auto unflatten(EValue* items) { + std::string spec = "D4#1#1#1#1('key0':$,1:$,23:$,123:$)"; + return pytree::unflatten(spec, items); +} + +TEST(PyTreeEValue, DestructedSpec) { + Scalar i0((int64_t)2); + Scalar d1((double)3.0); + Scalar i2((int64_t)4); + Scalar d3((double)5.0); + EValue items[4] = {i0, d1, i2, d3}; + auto c = unflatten(items); + + ASSERT_TRUE(c.isDict()); + ASSERT_EQ(c.size(), 4); + + auto& key0 = c.key(0); + auto& key1 = c.key(1); + + ASSERT_TRUE(key0 == pytree::Key("key0")); + ASSERT_TRUE(key1 == pytree::Key(1)); + + const auto& child0 = c[0]; + const auto& child1 = c[1]; + ASSERT_TRUE(child0.isLeaf()); + ASSERT_TRUE(child1.isLeaf()); + + EValue ev_child0 = child0; + ASSERT_TRUE(ev_child0.isScalar()); + ASSERT_TRUE(ev_child0.isInt()); + ASSERT_EQ(ev_child0.toInt(), 2); + + ASSERT_TRUE(child1.leaf().isScalar()); + ASSERT_TRUE(child1.leaf().isDouble()); + ASSERT_NEAR(child1.leaf().toDouble(), 3.0, 0.01); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_integration_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_integration_test.cpp new file mode 100644 index 0000000..3b5e547 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_integration_test.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Kernel; +using executorch::runtime::KernelKey; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +/** + * Used to control and observe the behavior of a kernel. + */ +struct KernelControl { + public: + // The number of times the kernel has been called. + int call_count = 0; + + // If true, the kernel should call `context.fail(error_to_set)`. If false, + // the kernel should not call `context.fail()`. + bool call_context_fail = true; + + // The error value that the kernel should pass to `context.fail()` before + // returning. + Error fail_value = Error::Ok; + + // If true, the kernel should allocate temporary memory. + bool allocate_temp_memory = false; + + // If true, the kernel should simulate allocating temporary memory. + bool simulate_temp_memory_allocation = false; + + // The size of the temporary memory to allocate. + int temp_memory_size = 0; + + // The total size of all allocations. + int total_allocated_size = 0; + + void reset() { + call_count = 0; + call_context_fail = false; + fail_value = Error::Ok; + allocate_temp_memory = false; + simulate_temp_memory_allocation = false; + temp_memory_size = 0; + total_allocated_size = 0; + } + + /** + * Registers a kernel that uses the singleton instance to record and control + * its behavior. + */ + static void register_singleton() { + if (registered_) { + return; + } + + // This test helper installs itself as aten::add.out: + // + // add.out(Tensor self, Tensor other, *, Scalar alpha=1, Tensor(a!) out) -> + // Tensor(a!) + // + // The arguments are: `self, other, out, out` (we repeat the out argument in + // the program). And since we traced using randn(2, 2), all the args are + // Float with dim order (0, 1) + + // Construct a kernel key with the following meta: + // executorch::aten::DimOrderType contiguous[] = {0, 1}; + // TensorMeta float_contiguous[] = { + // TensorMeta(ScalarType::Float, contiguous), // self + // TensorMeta(ScalarType::Float, contiguous), // other + // TensorMeta(ScalarType::Float, contiguous), // out + // TensorMeta(ScalarType::Float, contiguous)}; // out (repeated) + KernelKey key = + executorch::runtime::KernelKey("v1/6;0,1|6;0,1|6;0,1|6;0,1"); + Kernel kernel = executorch::runtime::Kernel( + "aten::add.out", key, KernelControl::kernel_hook); + Error err = executorch::runtime::register_kernel(kernel); + EXPECT_EQ(err, Error::Ok); + + registered_ = true; + } + + static KernelControl* singleton() { + return &singleton_; + } + + private: + /** + * An OpFunction-compatible function that uses the singleton KernelControl + * to record and determine its behavior. + */ + static void kernel_hook( + KernelRuntimeContext& context, + ET_UNUSED Span args) { + auto* control = KernelControl::singleton(); + control->call_count++; + if (control->call_context_fail) { + context.fail(control->fail_value); + } + + // Allocate temporary memory. + if (control->allocate_temp_memory) { + Result temp_mem_res = + context.allocate_temp(control->temp_memory_size); + if (temp_mem_res.ok()) { + control->total_allocated_size += control->temp_memory_size; + // We actually use the memory, to test default memory allocation was + // successful. + uint8_t* array = (uint8_t*)(temp_mem_res.get()); + for (int i = 0; i < control->temp_memory_size; i++) { + array[i] = i % 256; + } + } + } + + // Simulate allocating temporary memory. We use this, for testing that when + // a temp allocator is provided, the kernel will use it, instead of + // allocating memory with the default platform memory allocator. + // The provided TempMemoryAllocator class in this file, simulates allocating + // memory instead of actually allocating anything. + if (control->simulate_temp_memory_allocation) { + Result temp_mem_res = + context.allocate_temp(control->temp_memory_size); + control->total_allocated_size += control->temp_memory_size; + EXPECT_EQ(temp_mem_res.error(), Error::Ok); + } + } + + static bool registered_; + static KernelControl singleton_; +}; + +bool KernelControl::registered_ = false; +KernelControl KernelControl::singleton_; + +/** + * MemoryAllocator that keeps track of the number/sizes of its allocations, + * to test the case where the user provides a temp allocator. + */ +class TempMemoryAllocator final : public MemoryAllocator { + public: + TempMemoryAllocator() : MemoryAllocator(0, nullptr) {} + + // The number of times allocate() has been called. + int number_of_allocations = 0; + + // The number of times reset() has been called. + int number_of_resets = 0; + + // The amount of memory currently allocated (should go to 0 when reset is + // called). + int currently_allocated_size = 0; + + // The total size of all allocations. + int total_allocated_size = 0; + + void* allocate(size_t size, ET_UNUSED size_t alignment = kDefaultAlignment) + override { + number_of_allocations += 1; + currently_allocated_size += size; + total_allocated_size += size; + // This is a simulation, we don't actually allocate memory. But we need to + // return a non-null pointer, so we return a bad, non-zero address that will + // crash if anyone tries to dereference it. + return (void*)1; + } + + void reset() override { + number_of_resets += 1; + currently_allocated_size = 0; + } +}; + +class KernelIntegrationTest : public ::testing::Test { + protected: + void SetUp() override { + executorch::runtime::runtime_init(); + + // Register the controllable kernel hook. + KernelControl::register_singleton(); + // Ensure that its state is clear. + KernelControl::singleton()->reset(); + // Provide the singleton to the tests. + control_ = KernelControl::singleton(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + + // Load the forward method. + mmm_ = std::make_unique( + kDefaultNonConstMemBytes, + kDefaultRuntimeMemBytes, + temp_allocator_.get()); + Result method = program_->load_method("forward", &mmm_->get()); + ASSERT_EQ(method.error(), Error::Ok); + method_ = std::make_unique(std::move(method.get())); + + // Set up its inputs. + auto inputs_cleanup = + executorch::extension::prepare_input_tensors(*method_); + ASSERT_EQ(inputs_cleanup.error(), Error::Ok); + inputs_cleanup_ = std::make_unique( + std::move(*inputs_cleanup)); + auto input_err = method_->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + } + + void TearDown() override { + inputs_cleanup_.reset(); + } + + private: + // Must outlive program_ + std::unique_ptr loader_; + + // Must outlive method_ + std::unique_ptr program_; + std::unique_ptr mmm_; + std::unique_ptr inputs_cleanup_; + + protected: + // An executable method that will call the kernel associated with control_. + // Its inputs will have been allocated and initialized. + std::unique_ptr method_; + + // The KernelControl associated with method_. + KernelControl* control_; + + // The temp memory allocator provided by the user. By default, none is + // provided. + std::unique_ptr temp_allocator_ = nullptr; +}; + +class KernelTempMemoryAllocatorIntegrationTest : public KernelIntegrationTest { + protected: + void SetUp() override { + // Create a temp allocator for the test before calling the parent SetUp. + temp_allocator_ = std::make_unique(); + KernelIntegrationTest::SetUp(); + } +}; + +TEST_F(KernelIntegrationTest, KernelHookIsCalled) { + // Demonstrate that the kernel hook is called in the default state. + EXPECT_EQ(control_->call_count, 0); + Error err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 1); + + // Calling it again bumps the count. + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 2); +} + +TEST_F(KernelIntegrationTest, FailurePropagates) { + // Tell the kernel to fail. + control_->call_context_fail = true; + + // We should see the error from the kernel. + control_->fail_value = Error::InvalidArgument; + Error err = method_->execute(); + EXPECT_EQ(err, Error::InvalidArgument); + EXPECT_EQ(control_->call_count, 1); + + // Have it fail with a different error to show that it's not a coincidence. + control_->fail_value = Error::MemoryAllocationFailed; + err = method_->execute(); + EXPECT_EQ(err, Error::MemoryAllocationFailed); + EXPECT_EQ(control_->call_count, 2); + + // Returning an Ok does not cause the execution to fail. + control_->fail_value = Error::Ok; + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 3); +} + +TEST_F(KernelIntegrationTest, DefaultPlatformMemoryAllocator) { + // Tell the kernel to allocate memory. Since no temp allocator is provided, + // this will allocate memory using the default platform memory allocator. + control_->allocate_temp_memory = true; + + control_->temp_memory_size = 4; + // This is not a simulation. This actually allocates memory, using the + // default platform memory allocator. + Error err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 1); + EXPECT_EQ(control_->total_allocated_size, 4); + + control_->temp_memory_size = 8; + // This is not a simulation. This actually allocates memory, using the + // default platform memory allocator. + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 2); + EXPECT_EQ(control_->total_allocated_size, 12); +} + +TEST_F(KernelTempMemoryAllocatorIntegrationTest, UsingTempMemoryAllocator) { + // In this test we provide a temp allocator to the method, and tell the kernel + // to allocate memory using it. We want to make sure that the kernel uses the + // temp allocator, and that the temp allocator is reset after the execution. + // Since we are testing that the kernel uses the temp allocator, and not the + // temp allocator itself, we don't need to test the actual allocation of + // memory. Therefore, we set simulate_temp_memory_allocation to true, so that + // the kernel will not actually allocate memory, but will instead simulate + // allocating memory. + // The provided TempMemoryAllocator, simulates allocating memory by increasing + // total_allocated_size and currently_allocated_size by the requested size. + // We simulate resetting the allocator by setting currently_allocated_size + // back to 0. + control_->simulate_temp_memory_allocation = true; + + control_->temp_memory_size = 4; + Error err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 1); + EXPECT_EQ(control_->total_allocated_size, 4); + EXPECT_EQ(temp_allocator_->number_of_allocations, 1); + EXPECT_EQ(temp_allocator_->total_allocated_size, 4); + // The temp allocator should have been reset after the execution and before + // method execution. + EXPECT_EQ(temp_allocator_->number_of_resets, 2); + EXPECT_EQ(temp_allocator_->currently_allocated_size, 0); + + control_->temp_memory_size = 8; + err = method_->execute(); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(control_->call_count, 2); + EXPECT_EQ(control_->total_allocated_size, 12); + EXPECT_EQ(temp_allocator_->number_of_allocations, 2); + EXPECT_EQ(temp_allocator_->total_allocated_size, 12); + // The temp allocator should have been reset after the execution. + EXPECT_EQ(temp_allocator_->number_of_resets, 4); + EXPECT_EQ(temp_allocator_->currently_allocated_size, 0); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_resolution_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_resolution_test.cpp new file mode 100644 index 0000000..d3861ad --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/kernel_resolution_test.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Kernel; +using executorch::runtime::KernelKey; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::register_kernel; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorMeta; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class KernelResolutionTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Create a loader for the serialized ModuleAdd program. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loader_ = std::make_unique(std::move(loader.get())); + + // Use it to load the program. + Result program = Program::load( + loader_.get(), Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + program_ = std::make_unique(std::move(program.get())); + } + + std::unique_ptr loader_; + std::unique_ptr program_; +}; + +/** + * Test if the program can initialize properly. + */ +TEST_F(KernelResolutionTest, InitExecutionPlanSuccess) { + // register kernel with fallback kernel key + Kernel kernel_1 = Kernel( + "aten::add.out", + {}, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + auto s1 = register_kernel(kernel_1); + EXPECT_EQ(s1, executorch::runtime::Error::Ok); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + auto method = program_->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); +} + +/** + * Test if we can resolve the kernel key correctly. + */ +TEST_F(KernelResolutionTest, ResolveKernelKeySuccess) { + // getting all these TensorMeta from args to this kernel_call in the program. + // particularly for aten::add.out: + // add.out(Tensor self, Tensor other, *, Scalar alpha=1, Tensor(a!) out) -> + // Tensor(a!) The arguments are: `self, other, out, out` (we repeat out + // argument in the program) Also since we traced using randn(2, 2), all the + // args are Float with dim order (0, 1) + + // Construct a kernel key with the following meta: + // executorch::aten::DimOrderType contiguous[] = {0, 1}; + // TensorMeta float_contiguous[] = { + // TensorMeta(ScalarType::Float, contiguous), + // TensorMeta(ScalarType::Float, contiguous), + // TensorMeta(ScalarType::Float, contiguous), + // TensorMeta(ScalarType::Float, contiguous)}; + KernelKey key = KernelKey("v1/6;0,1|6;0,1|6;0,1|6;0,1"); + Kernel kernel_1 = Kernel( + "aten::add.out", + key, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + auto s1 = register_kernel(kernel_1); + EXPECT_EQ(s1, executorch::runtime::Error::Ok); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + auto method = program_->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/managed_memory_manager.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/managed_memory_manager.h new file mode 100644 index 0000000..a010915 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/managed_memory_manager.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace executorch { +namespace runtime { +namespace testing { + +/** + * Creates and owns a MemoryManager and the allocators that it points to. Easier + * to manage than creating the allocators separately. + */ +class ManagedMemoryManager { + public: + ManagedMemoryManager( + size_t planned_memory_bytes, + size_t method_allocator_bytes, + MemoryAllocator* temp_allocator = nullptr) + : planned_memory_buffer_(new uint8_t[planned_memory_bytes]), + planned_memory_span_( + planned_memory_buffer_.get(), + planned_memory_bytes), + planned_memory_({&planned_memory_span_, 1}), + method_allocator_pool_(new uint8_t[method_allocator_bytes]), + method_allocator_(method_allocator_bytes, method_allocator_pool_.get()), + memory_manager_(&method_allocator_, &planned_memory_, temp_allocator) {} + + MemoryManager& get() { + return memory_manager_; + } + + private: + std::unique_ptr planned_memory_buffer_; + Span planned_memory_span_; + HierarchicalAllocator planned_memory_; + + std::unique_ptr method_allocator_pool_; + MemoryAllocator method_allocator_; + + MemoryManager memory_manager_; +}; + +} // namespace testing +} // namespace runtime +} // namespace executorch + +namespace torch { +namespace executor { +namespace testing { +// TODO(T197294990): Remove these deprecated aliases once all users have moved +// to the new `::executorch` namespaces. +using ::executorch::runtime::testing::ManagedMemoryManager; +} // namespace testing +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/memory_manager_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/memory_manager_test.cpp new file mode 100644 index 0000000..ecbb60f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/memory_manager_test.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::HierarchicalAllocator; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::MemoryManager; + +TEST(MemoryManagerTest, MinimalCtor) { + MemoryAllocator method_allocator(0, nullptr); + + MemoryManager mm(&method_allocator); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), nullptr); + EXPECT_EQ(mm.temp_allocator(), nullptr); +} + +TEST(MemoryManagerTest, CtorWithPlannedMemory) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + + MemoryManager mm(&method_allocator, &planned_memory); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), &planned_memory); + EXPECT_EQ(mm.temp_allocator(), nullptr); +} + +TEST(MemoryManagerTest, CtorWithPlannedMemoryAndTemp) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator temp_allocator(0, nullptr); + + MemoryManager mm(&method_allocator, &planned_memory, &temp_allocator); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), &planned_memory); + EXPECT_EQ(mm.temp_allocator(), &temp_allocator); +} + +TEST(MemoryManagerTest, DEPRECATEDCtor) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator temp_allocator(0, nullptr); + MemoryAllocator const_allocator(0, nullptr); + + // NOLINTNEXTLINE(facebook-hte-Deprecated) + MemoryManager mm( + /*constant_allocator=*/&const_allocator, + /*non_constant_allocator=*/&planned_memory, + /*runtime_allocator=*/&method_allocator, + /*temporary_allocator=*/&temp_allocator); + + EXPECT_EQ(mm.method_allocator(), &method_allocator); + EXPECT_EQ(mm.planned_memory(), &planned_memory); + EXPECT_EQ(mm.temp_allocator(), &temp_allocator); +} + +TEST(MemoryManagerTest, DeprecatedCtorWithSameAllocator) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator const_allocator(0, nullptr); + ET_EXPECT_DEATH( + MemoryManager( + /*constant_allocator=*/&const_allocator, + /*non_constant_allocator=*/&planned_memory, + /*runtime_allocator=*/&method_allocator, + /*temp_allocator=*/&method_allocator), + ""); +} + +TEST(MemoryManagerTest, CtorWithSameAllocator) { + MemoryAllocator method_allocator(0, nullptr); + HierarchicalAllocator planned_memory({}); + MemoryAllocator const_allocator(0, nullptr); + ET_EXPECT_DEATH( + MemoryManager( + /*runtime_allocator=*/&method_allocator, + /*non_constant_allocator=*/&planned_memory, + /*temp_allocator=*/&method_allocator), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/merged_data_map_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/merged_data_map_test.cpp new file mode 100644 index 0000000..c9d1d51 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/merged_data_map_test.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::FileDataLoader; +using executorch::extension::FlatTensorDataMap; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::NamedDataMap; +using executorch::runtime::Result; +using executorch::runtime::TensorLayout; +using executorch::runtime::internal::MergedDataMap; + +class MergedDataMapTest : public ::testing::Test { + protected: + void load_flat_tensor_data_map(const char* path, const char* module_name) { + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + Result data_map = + FlatTensorDataMap::load(loaders_[module_name].get()); + EXPECT_EQ(data_map.error(), Error::Ok); + + data_maps_.insert( + {module_name, + std::make_unique(std::move(data_map.get()))}); + } + + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Load FlatTensor data maps. + // The eager addmul and linear models are defined at: + // //executorch/test/models/export_program.py + load_flat_tensor_data_map( + std::getenv("ET_MODULE_ADD_MUL_DATA_PATH"), "addmul"); + load_flat_tensor_data_map( + std::getenv("ET_MODULE_LINEAR_DATA_PATH"), "linear"); + } + + private: + // Must outlive data_maps_, but tests shouldn't need to touch it. + std::unordered_map> loaders_; + + protected: + std::unordered_map> data_maps_; +}; + +// Check that two tensor layouts are equivalent. +void check_tensor_layout(TensorLayout& layout1, TensorLayout& layout2) { + EXPECT_EQ(layout1.scalar_type(), layout2.scalar_type()); + EXPECT_EQ(layout1.nbytes(), layout2.nbytes()); + EXPECT_EQ(layout1.sizes().size(), layout2.sizes().size()); + for (size_t i = 0; i < layout1.sizes().size(); i++) { + EXPECT_EQ(layout1.sizes()[i], layout2.sizes()[i]); + } + EXPECT_EQ(layout1.dim_order().size(), layout2.dim_order().size()); + for (size_t i = 0; i < layout1.dim_order().size(); i++) { + EXPECT_EQ(layout1.dim_order()[i], layout2.dim_order()[i]); + } +} + +// Given that ndm is part of merged, check that all the API calls on ndm produce +// the same results as merged. +void compare_ndm_api_calls( + const NamedDataMap* ndm, + const NamedDataMap* merged) { + uint32_t num_keys = ndm->get_num_keys().get(); + for (uint32_t i = 0; i < num_keys; i++) { + auto key = ndm->get_key(i).get(); + + // Compare get_tensor_layout. + auto ndm_meta = ndm->get_tensor_layout(key).get(); + auto merged_meta = merged->get_tensor_layout(key).get(); + check_tensor_layout(ndm_meta, merged_meta); + + // Coompare get_data. + auto ndm_data = ndm->get_data(key); + auto merged_data = merged->get_data(key); + EXPECT_EQ(ndm_data.get().size(), merged_data.get().size()); + for (size_t j = 0; j < ndm_meta.nbytes(); j++) { + EXPECT_EQ( + ((uint8_t*)ndm_data.get().data())[j], + ((uint8_t*)merged_data.get().data())[j]); + } + ndm_data->Free(); + merged_data->Free(); + } +} + +TEST_F(MergedDataMapTest, LoadNullDataMap) { + Result merged_map = MergedDataMap::load(nullptr, nullptr); + EXPECT_EQ(merged_map.error(), Error::InvalidArgument); +} + +TEST_F(MergedDataMapTest, LoadMultipleDataMaps) { + Result merged_map = MergedDataMap::load( + data_maps_["addmul"].get(), data_maps_["linear"].get()); + EXPECT_EQ(merged_map.error(), Error::Ok); +} + +TEST_F(MergedDataMapTest, LoadDuplicateDataMapsFail) { + Result merged_map = MergedDataMap::load( + data_maps_["addmul"].get(), data_maps_["addmul"].get()); + EXPECT_EQ(merged_map.error(), Error::InvalidArgument); +} + +TEST_F(MergedDataMapTest, CheckDataMapContents) { + Result merged_map = MergedDataMap::load( + data_maps_["addmul"].get(), data_maps_["linear"].get()); + EXPECT_EQ(merged_map.error(), Error::Ok); + + // Num keys. + size_t addmul_num_keys = data_maps_["addmul"]->get_num_keys().get(); + size_t linear_num_keys = data_maps_["linear"]->get_num_keys().get(); + EXPECT_EQ( + merged_map->get_num_keys().get(), addmul_num_keys + linear_num_keys); + + // Load data into is not implemented for the merged data map. + void* memory_block = malloc(10); + ASSERT_EQ( + Error::NotImplemented, merged_map->load_data_into("a", memory_block, 10)); + free(memory_block); + + // API calls produce equivalent results. + compare_ndm_api_calls(data_maps_["addmul"].get(), &merged_map.get()); + compare_ndm_api_calls(data_maps_["linear"].get(), &merged_map.get()); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_meta_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_meta_test.cpp new file mode 100644 index 0000000..e4ef2e7 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_meta_test.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::MethodMeta; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorInfo; +using torch::executor::util::FileDataLoader; + +namespace executorch { +namespace runtime { +namespace testing { +// Provides access to private TensorInfo methods. +class TensorInfoTestFriend final { + public: + ET_NODISCARD static TensorInfo get( + Span sizes, + Span dim_order, + executorch::aten::ScalarType scalar_type, + const bool is_memory_planned, + executorch::aten::string_view name) { + return TensorInfo::create( + Span(sizes.data(), sizes.size()), + Span(dim_order.data(), dim_order.size()), + scalar_type, + is_memory_planned, + name) + .get(); + } +}; +} // namespace testing +} // namespace runtime +} // namespace executorch + +class MethodMetaTest : public ::testing::Test { + protected: + void load_program(const char* path, const char* module_name) { + // Create a loader for the serialized program. + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + // Use it to load the program. + Result program = Program::load( + loaders_[module_name].get(), + Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + programs_.insert( + {module_name, std::make_unique(std::move(program.get()))}); + } + + void SetUp() override { + load_program(std::getenv("ET_MODULE_ADD_PATH"), "add"); + load_program(std::getenv("ET_MODULE_STATEFUL_PATH"), "stateful"); + } + + private: + // Must outlive program_, but tests shouldn't need to touch it. + std::unordered_map> loaders_; + + protected: + std::unordered_map> programs_; +}; + +namespace { + +// Check TensorInfo against hard coded values from AddModule. +void check_tensor(const TensorInfo& tensor_info) { + auto sizes = tensor_info.sizes(); + auto dim_order = tensor_info.dim_order(); + EXPECT_EQ(sizes.size(), 2); + EXPECT_EQ(sizes[0], 2); + EXPECT_EQ(sizes[1], 2); + EXPECT_EQ(tensor_info.scalar_type(), executorch::aten::ScalarType::Float); + EXPECT_EQ(dim_order.size(), 2); + EXPECT_EQ(dim_order[0], 0); + EXPECT_EQ(dim_order[1], 1); + EXPECT_EQ(tensor_info.is_memory_planned(), true); + EXPECT_EQ(tensor_info.nbytes(), 16); +} +} // namespace + +TEST_F(MethodMetaTest, MethodMetaApi) { + Result method_meta = programs_["add"]->method_meta("forward"); + ASSERT_EQ(method_meta.error(), Error::Ok); + + // Appropriate amount of inputs + EXPECT_EQ(method_meta->num_inputs(), 3); + + // Appropriate amount of outputs + EXPECT_EQ(method_meta->num_outputs(), 1); + + // Appropriate amount of planned buffers + EXPECT_EQ(method_meta->num_memory_planned_buffers(), 1); + EXPECT_EQ(method_meta->num_non_const_buffers(), 1); // Deprecated API + + // Appropriate size of planned buffer + EXPECT_EQ(method_meta->memory_planned_buffer_size(0).get(), 48); + EXPECT_EQ(method_meta->non_const_buffer_size(0).get(), 48); // Deprecated API + + // Invalid index Errors + EXPECT_EQ( + method_meta->memory_planned_buffer_size(1).error(), + Error::InvalidArgument); + EXPECT_EQ( + method_meta->non_const_buffer_size(1).error(), + Error::InvalidArgument); // Deprecated API + + // Number instructions in method is nonzero + EXPECT_NE(method_meta->num_instructions(), 0); + + // Missing method fails + EXPECT_EQ( + programs_["add"]->method_meta("not_a_method").error(), + Error::InvalidArgument); +} + +TEST_F(MethodMetaTest, TensorInfoApi) { + Result method_meta = programs_["add"]->method_meta("forward"); + ASSERT_EQ(method_meta.error(), Error::Ok); + + // Input 1 + Result in_1 = method_meta->input_tensor_meta(0); + ASSERT_TRUE(in_1.ok()); + check_tensor(in_1.get()); + + // Input 2 + Result in_2 = method_meta->input_tensor_meta(1); + ASSERT_TRUE(in_2.ok()); + check_tensor(in_2.get()); + + // Output 1 + Result out_1 = method_meta->output_tensor_meta(0); + ASSERT_TRUE(out_1.ok()); + check_tensor(out_1.get()); + + // Copyable + Result info = method_meta->input_tensor_meta(0); + TensorInfo info_copy_ctor(info.get()); + TensorInfo info_copy_assign(out_1.get()); + info_copy_assign = info.get(); + check_tensor(info_copy_ctor); + check_tensor(info_copy_assign); + + // Move-able + TensorInfo info_move_ctor(std::move(info.get())); + check_tensor(info_move_ctor); + + // Errors + EXPECT_EQ(method_meta->input_tensor_meta(3).error(), Error::InvalidArgument); + EXPECT_EQ(method_meta->input_tensor_meta(-1).error(), Error::InvalidArgument); + EXPECT_EQ(method_meta->output_tensor_meta(3).error(), Error::InvalidArgument); + EXPECT_EQ( + method_meta->output_tensor_meta(-1).error(), Error::InvalidArgument); +} + +TEST_F(MethodMetaTest, MethodMetaAttribute) { + Result method_meta = + programs_["stateful"]->method_meta("forward"); + ASSERT_EQ(method_meta.error(), Error::Ok); + + ASSERT_EQ(method_meta->num_attributes(), 1); + auto state = method_meta->attribute_tensor_meta(0); + ASSERT_TRUE(state.ok()); + + ASSERT_EQ(state->name(), "state"); + ASSERT_FALSE(state->is_memory_planned()); + + auto bad_access = method_meta->attribute_tensor_meta(1); + ASSERT_EQ(bad_access.error(), Error::InvalidArgument); +} + +TEST_F(MethodMetaTest, TensorInfoSizeOverflow) { + // Create sizes that will cause overflow when multiplied + std::vector overflow_sizes = { + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + }; + + // Create a minimal dim_order + std::vector dim_order = {0, 1, 2, 3}; + + // Create a TensorInfo with the overflow sizes and expect it to fail. + ET_EXPECT_DEATH( + executorch::runtime::testing::TensorInfoTestFriend::get( + Span(overflow_sizes.data(), overflow_sizes.size()), + Span(dim_order.data(), dim_order.size()), + executorch::aten::ScalarType::Float, + false, // is_memory_planned + executorch::aten::string_view{nullptr, 0}), + ""); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_test.cpp new file mode 100644 index 0000000..a60740f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/method_test.cpp @@ -0,0 +1,547 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ArrayRef; +using executorch::extension::FlatTensorDataMap; +using executorch::extension::prepare_input_tensors; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Method; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class MethodTest : public ::testing::Test { + protected: + void load_program(const char* path, const char* module_name) { + // Create a loader for the serialized program. + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + // Use it to load the program. + Result program = Program::load( + loaders_[module_name].get(), + Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::Ok); + programs_.insert( + {module_name, std::make_unique(std::move(program.get()))}); + } + + void load_data_map(const char* path, const char* module_name) { + // Create a loader for the serialized data map. + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + loaders_.insert( + {module_name, + std::make_unique(std::move(loader.get()))}); + + Result data_map = + FlatTensorDataMap::load(loaders_[module_name].get()); + EXPECT_EQ(data_map.error(), Error::Ok); + + data_maps_.insert( + {module_name, + std::make_unique(std::move(data_map.get()))}); + } + + void SetUp() override { + executorch::runtime::runtime_init(); + + load_program(std::getenv("ET_MODULE_ADD_PATH"), "add"); + load_program(std::getenv("ET_MODULE_INDEX_PATH"), "index"); + load_program( + std::getenv("ET_MODULE_DYNAMIC_CAT_UNALLOCATED_IO_PATH"), "cat"); + load_program(std::getenv("ET_MODULE_ADD_MUL_PATH"), "add_mul"); + load_program(std::getenv("ET_MODULE_STATEFUL_PATH"), "stateful"); + load_program( + std::getenv("DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH"), + "linear_constant_buffer"); + + load_program( + std::getenv("ET_MODULE_ADD_MUL_PROGRAM_PATH"), "add_mul_program"); + load_data_map(std::getenv("ET_MODULE_ADD_MUL_DATA_PATH"), "add_mul_data"); + } + + private: + // Must outlive program_, but tests shouldn't need to touch it. + std::unordered_map> loaders_; + + protected: + std::unordered_map> programs_; + std::unordered_map> + data_maps_; +}; + +TEST_F(MethodTest, MoveTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set dummy inputs. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(executorch::runtime::EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); + + // Move into a new Method. + Method new_method(std::move(method.get())); + + // Can't execute the old method. + err = method->execute(); + ASSERT_NE(err, Error::Ok); + + // Can execute the new method. + err = new_method.execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, GetInputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_inputs = method->inputs_size(); + ASSERT_GT(num_inputs, 0); + + // In-range inputs should succeed without aborting. + method->get_input(0); + method->get_input(num_inputs - 1); + + // Out-of-range inputs should abort. + ET_EXPECT_DEATH(method->get_input(num_inputs), ""); + ET_EXPECT_DEATH(method->get_input(num_inputs + 1), ""); +} + +TEST_F(MethodTest, MutableInputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_inputs = method->inputs_size(); + ASSERT_GT(num_inputs, 0); + + // In-range inputs should succeed without aborting. + method->mutable_input(0); + method->mutable_input(num_inputs - 1); + + // Out-of-range inputs should abort. + ET_EXPECT_DEATH(method->mutable_input(num_inputs), ""); + ET_EXPECT_DEATH(method->mutable_input(num_inputs + 1), ""); +} + +TEST_F(MethodTest, GetOutputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_outputs = method->outputs_size(); + ASSERT_GT(num_outputs, 0); + + // In-range outputs should succeed without aborting. + method->get_output(0); + method->get_output(num_outputs - 1); + + // Out-of-range outputs should abort. + ET_EXPECT_DEATH(method->get_output(num_outputs), ""); + ET_EXPECT_DEATH(method->get_output(num_outputs + 1), ""); +} + +TEST_F(MethodTest, MutableOutputTests) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + size_t num_outputs = method->outputs_size(); + ASSERT_GT(num_outputs, 0); + + // In-range outputs should succeed without aborting. + method->mutable_output(0); + method->mutable_output(num_outputs - 1); + + // Out-of-range outputs should abort. + ET_EXPECT_DEATH(method->mutable_output(num_outputs), ""); + ET_EXPECT_DEATH(method->mutable_output(num_outputs + 1), ""); +} + +TEST_F(MethodTest, SetPrimInputTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Can execute the method. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + + // The args to the method are x, y, alpha. x and y are tensors handled above + // alpha is a prim. + + // Traced prim input was '1.0' so 3.0 should error. + auto input_err = method->set_input(EValue(3.0), 2); + EXPECT_EQ(input_err, Error::InvalidArgument); + + // Traced prim input was '1.0' so '1.0' should be ok. + input_err = method->set_input(EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + Error err = method->execute(); + EXPECT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, MethodMetaTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto method_meta = method->method_meta(); + + EXPECT_EQ(method_meta.num_inputs(), method->inputs_size()); + EXPECT_EQ(method_meta.num_outputs(), method->outputs_size()); +} + +TEST_F(MethodTest, AliasedIOTest) { + // TODO(T163238401) + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["cat"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set up io. Input and Output should share the same memory. + constexpr int buffer_size = 16; + float buffer[buffer_size]; // Initial input is (2,4) we then cat a (1,4) to it + // twice for a final shape of (4,4) + for (int i = 0; i < buffer_size; ++i) { + buffer[i] = 0.f; + } + int32_t sizes[2] = {2, 4}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {4, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + buffer, + dim_order, + strides); + + auto input_err = + method->set_input(EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + auto output_err = method->set_output_data_ptr(buffer, sizeof(buffer), 0); + ASSERT_EQ(output_err, Error::Ok); + ASSERT_EQ(method->get_output(0).toTensor().const_data_ptr(), buffer); + + // Execute the method once. Cat a 1x4 to a 2x4. + auto execute_error = method->execute(); + ASSERT_EQ(execute_error, Error::Ok); + + auto output = method->get_output(0); + ASSERT_TRUE(output.isTensor()); + EXPECT_EQ(output.toTensor().sizes()[0], 3); + EXPECT_EQ(output.toTensor().sizes()[1], 4); + // Original input should be 0. + for (size_t i = 0; i < 2 * 4; i++) { + EXPECT_FLOAT_EQ(output.toTensor().const_data_ptr()[i], 0.f); + } + // Section that was cat on should be 1. + for (size_t i = 0; i < 1 * 4; i++) { + EXPECT_FLOAT_EQ( + output.toTensor().const_data_ptr()[(2 * 4) + i], 1.f); + } + + // Set the input again to update the size. + sizes[0] = output.toTensor().sizes()[0]; + executorch::aten::TensorImpl impl_2( + executorch::aten::ScalarType::Float, + 2, + sizes, + buffer, + dim_order, + strides); + input_err = method->set_input(EValue(executorch::aten::Tensor(&impl_2)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Execute the method again. Cat a 1x4 to a 3x4. + execute_error = method->execute(); + ASSERT_EQ(execute_error, Error::Ok); + + output = method->get_output(0); + EXPECT_EQ(output.toTensor().sizes()[0], 4); + EXPECT_EQ(output.toTensor().sizes()[1], 4); + // Original input should be 0. + for (size_t i = 0; i < 2 * 4; i++) { + EXPECT_FLOAT_EQ(output.toTensor().const_data_ptr()[i], 0.f); + } + // Previous section and the new one that were cat on should be 1. + for (size_t i = 0; i < 2 * 4; i++) { + EXPECT_FLOAT_EQ( + output.toTensor().const_data_ptr()[(2 * 4) + i], 1.f); + } +} + +TEST_F(MethodTest, ConstantSegmentTest) { + // Execute model with constants stored in segment. + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["add_mul"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, ConstantBufferTest) { + // Execute model with constants stored in the program flatbuffer. + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["linear_constant_buffer"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, ProgramDataSeparationTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add_mul_program"]->load_method( + "forward", &mmm.get(), nullptr, data_maps_["add_mul_data"].get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Set a dummy input. + int32_t sizes[2] = {2, 2}; + uint8_t dim_order[2] = {0, 1}; + int32_t strides[2] = {2, 1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 2, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, MethodGetAttributeTest) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["stateful"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto res = method->get_attribute("state"); + ASSERT_TRUE(res.ok()); + // expect data to be empty + EXPECT_EQ(res->const_data_ptr(), nullptr); + + int32_t data = 0; + res->set_data(&data); + + // expect data to be set + EXPECT_EQ(res->const_data_ptr(), &data); + + // Set a dummy input. + int32_t sizes[1] = {1}; + uint8_t dim_order[1] = {0}; + int32_t strides[1] = {1}; + executorch::aten::TensorImpl impl( + executorch::aten::ScalarType::Float, + 1, + sizes, + nullptr, + dim_order, + strides); + auto input_err = method->set_input( + executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0); + ASSERT_EQ(input_err, Error::Ok); + + // Can execute the method. + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); + + // Expect the state to be incremented + EXPECT_EQ(res->const_data_ptr()[0], 1); +} + +TEST_F(MethodTest, InProgressInitialState) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + EXPECT_FALSE(method->in_progress()); +} + +TEST_F(MethodTest, InProgressDuringStepExecution) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["add_mul"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + + Error err = method->step(); + ASSERT_EQ(err, Error::Ok); + + EXPECT_TRUE(method->in_progress()); + + while (err != Error::EndOfMethod) { + err = method->step(); + ASSERT_TRUE(err == Error::Ok || err == Error::EndOfMethod); + } + + EXPECT_FALSE(method->in_progress()); +} + +TEST_F(MethodTest, ExecuteFailsWhenInProgress) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = + programs_["add_mul"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + + Error err = method->step(); + ASSERT_EQ(err, Error::Ok); + ASSERT_TRUE(method->in_progress()); + + err = method->execute(); + EXPECT_EQ(err, Error::InvalidState); +} + +TEST_F(MethodTest, ExecuteSucceedsAfterReset) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + Error err = Error::Ok; + while (err != Error::EndOfMethod) { + err = method->step(); + ASSERT_TRUE(err == Error::Ok || err == Error::EndOfMethod); + } + + err = method->reset_execution(); + ASSERT_EQ(err, Error::Ok); + EXPECT_FALSE(method->in_progress()); + + err = method->execute(); + EXPECT_EQ(err, Error::Ok); +} + +TEST_F(MethodTest, ExecuteResetsOnError) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + Result method = programs_["add"]->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + Error err = method->execute(); + EXPECT_NE(err, Error::Ok); + + EXPECT_FALSE(method->in_progress()); + + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + auto input_err = method->set_input(EValue(1.0), 2); + ASSERT_EQ(input_err, Error::Ok); + + err = method->execute(); + EXPECT_EQ(err, Error::Ok); +} + +/* + * TODO(T161163608): Test is disabled due to a resize bug in tensor_index_out of + * the portable op lib + +TEST_F(MethodTest, OptionalTensorListDeserialization) { + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, + kDefaultRuntimeMemBytes); Result method = + index_program_->load_method("forward", &mmm.get()); + ASSERT_EQ(method.error(), Error::Ok); + + // Can execute the method. + auto input_cleanup = prepare_input_tensors(*method); + ASSERT_EQ(input_cleanup.error(), Error::Ok); + Error err = method->execute(); + ASSERT_EQ(err, Error::Ok); + + EXPECT_EQ(method->inputs_size(), 1); + + auto outputs = method->get_output(0); + EXPECT_EQ(outputs.toTensor().dim(), 3); + EXPECT_EQ(outputs.toTensor().size(0), 5); + EXPECT_EQ(outputs.toTensor().size(1), 2); + EXPECT_EQ(outputs.toTensor().size(2), 10); +} +*/ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/program_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/program_test.cpp new file mode 100644 index 0000000..3afb71b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/program_test.cpp @@ -0,0 +1,595 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Program; +using executorch::runtime::Result; +using torch::executor::util::BufferDataLoader; +using torch::executor::util::FileDataLoader; + +// Verification level to use for tests not specifically focused on verification. +// Use the highest level to exercise it more. +constexpr Program::Verification kDefaultVerification = + Program::Verification::InternalConsistency; + +class ProgramTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Load the serialized ModuleAdd data. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result loader = FileDataLoader::from(path); + ASSERT_EQ(loader.error(), Error::Ok); + + // This file should always be compatible. + Result header = loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(header->data(), header->size()), + Program::HeaderStatus::CompatibleVersion); + + add_loader_ = std::make_unique(std::move(loader.get())); + + // Load the serialized ModuleMultiEntry data. + path = std::getenv("ET_MODULE_MULTI_ENTRY_PATH"); + Result multi_loader = FileDataLoader::from(path); + ASSERT_EQ(multi_loader.error(), Error::Ok); + + // This file should always be compatible. + Result multi_header = multi_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(multi_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(multi_header->data(), multi_header->size()), + Program::HeaderStatus::CompatibleVersion); + + multi_loader_ = + std::make_unique(std::move(multi_loader.get())); + } + + std::unique_ptr add_loader_; + std::unique_ptr multi_loader_; +}; + +namespace executorch { +namespace runtime { +namespace testing { +// Provides access to private Program methods. +class ProgramTestFriend final { + public: + ET_NODISCARD static Result LoadSegment( + const Program* program, + const DataLoader::SegmentInfo& segment_info) { + return program->LoadSegment(segment_info); + } + + ET_NODISCARD static Error load_mutable_subsegment_into( + const Program* program, + size_t mutable_data_segments_index, + size_t offset_index, + size_t size, + void* buffer) { + return program->load_mutable_subsegment_into( + mutable_data_segments_index, offset_index, size, buffer); + } + + const static executorch_flatbuffer::Program* GetInternalProgram( + const Program* program) { + return program->internal_program_; + } +}; +} // namespace testing +} // namespace runtime +} // namespace executorch + +using executorch::runtime::testing::ProgramTestFriend; + +TEST_F(ProgramTest, DataParsesWithMinimalVerification) { + // Parse the Program from the data. + Result program = + Program::load(add_loader_.get(), Program::Verification::Minimal); + + // Should have succeeded. + EXPECT_EQ(program.error(), Error::Ok); +} + +TEST_F(ProgramTest, DataParsesWithInternalConsistencyVerification) { + // Parse the Program from the data. + Result program = Program::load( + add_loader_.get(), Program::Verification::InternalConsistency); + + // Should have succeeded. + EXPECT_EQ(program.error(), Error::Ok); +} + +TEST_F(ProgramTest, BadMagicFailsToLoad) { + // Make a local copy of the data. + size_t data_len = add_loader_->size().get(); + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Corrupt the magic value. + EXPECT_EQ(data[4], 'E'); + data[4] = 'X'; + EXPECT_EQ(data[5], 'T'); + data[5] = 'Y'; + + // Wrap the modified data in a loader. + BufferDataLoader data_loader(data.get(), data_len); + + { + // Parse the Program from the data. Use minimal verification to show that + // even this catches the header problem. + Result program = + Program::load(&data_loader, Program::Verification::Minimal); + + // Should fail. + ASSERT_EQ(program.error(), Error::InvalidProgram); + } + + // Fix the data. + data[4] = 'E'; + data[5] = 'T'; + + { + // Parse the Program from the data again. + Result program = + Program::load(&data_loader, Program::Verification::Minimal); + + // Should now succeed. + ASSERT_EQ(program.error(), Error::Ok); + } +} + +TEST_F(ProgramTest, VerificationCatchesTruncation) { + // Get the program data. + size_t full_data_len = add_loader_->size().get(); + Result full_data = add_loader_->load( + /*offset=*/0, + full_data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(full_data.error(), Error::Ok); + + // Make a loader that only exposes half of the data. + BufferDataLoader half_data_loader(full_data->data(), full_data_len / 2); + + // Loading with full verification should fail. + Result program = Program::load( + &half_data_loader, Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::InvalidProgram); +} + +TEST_F(ProgramTest, VerificationCatchesCorruption) { + // Make a local copy of the data. + size_t data_len = add_loader_->size().get(); + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Corrupt the second half of the data. + std::memset(&data[data_len / 2], 0x55, data_len - (data_len / 2)); + + // Wrap the corrupted data in a loader. + BufferDataLoader data_loader(data.get(), data_len); + + // Should fail to parse corrupted data when using full verification. + Result program = + Program::load(&data_loader, Program::Verification::InternalConsistency); + ASSERT_EQ(program.error(), Error::InvalidProgram); +} + +TEST_F(ProgramTest, UnalignedProgramDataFails) { + // Make a local copy of the data, on an odd alignment. + size_t data_len = add_loader_->size().get(); + auto data = std::make_unique(data_len + 1); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get() + 1, src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Wrap the offset data in a loader. + BufferDataLoader data_loader(data.get() + 1, data_len); + + // Should refuse to accept unaligned data. + Result program = + Program::load(&data_loader, Program::Verification::Minimal); + ASSERT_NE(program.error(), Error::Ok); +} + +TEST_F(ProgramTest, LoadSegmentWithNoSegments) { + // Load a program with no appended segments. + Result program = + Program::load(add_loader_.get(), kDefaultVerification); + EXPECT_EQ(program.error(), Error::Ok); + + // Loading a non-program segment should fail. + const auto segment_info = DataLoader::SegmentInfo( + DataLoader::SegmentInfo::Type::Backend, + /*segment_index=*/0, + "some-backend"); + Result segment = + ProgramTestFriend::LoadSegment(&program.get(), segment_info); + EXPECT_NE(segment.error(), Error::Ok); +} + +TEST_F(ProgramTest, ShortDataHeader) { + Result header = add_loader_->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(header.error(), Error::Ok); + + // Provide less than the required amount of data. + EXPECT_EQ( + Program::check_header(header->data(), Program::kMinHeadBytes - 1), + Program::HeaderStatus::ShortData); +} + +TEST_F(ProgramTest, IncompatibleHeader) { + // Make a local copy of the header. + size_t data_len = Program::kMinHeadBytes; + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Change the number part of the magic value to a different value. + EXPECT_EQ(data[4], 'E'); + EXPECT_EQ(data[5], 'T'); + EXPECT_TRUE(std::isdigit(data[6])) << "Not a digit: " << data[6]; + EXPECT_TRUE(std::isdigit(data[7])) << "Not a digit: " << data[7]; + + // Modify the tens digit. + if (data[6] == '9') { + data[6] = '0'; + } else { + data[6] += 1; + } + EXPECT_TRUE(std::isdigit(data[6])) << "Not a digit: " << data[6]; + + // Should count as present but incompatible. + EXPECT_EQ( + Program::check_header(data.get(), data_len), + Program::HeaderStatus::IncompatibleVersion); +} + +TEST_F(ProgramTest, HeaderNotPresent) { + // Make a local copy of the header. + size_t data_len = Program::kMinHeadBytes; + auto data = std::make_unique(data_len); + { + Result src = add_loader_->load( + /*offset=*/0, + data_len, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(src.error(), Error::Ok); + ASSERT_EQ(src->size(), data_len); + memcpy(data.get(), src->data(), data_len); + // FreeableBuffer goes out of scope and frees its data. + } + + // Corrupt the magic value. + EXPECT_EQ(data[4], 'E'); + data[4] = 'X'; + EXPECT_EQ(data[5], 'T'); + data[5] = 'Y'; + + // The header is not present. + EXPECT_EQ( + Program::check_header(data.get(), data_len), + Program::HeaderStatus::NotPresent); +} + +TEST_F(ProgramTest, getMethods) { + // Parse the Program from the data. + Result program_res = + Program::load(multi_loader_.get(), kDefaultVerification); + EXPECT_EQ(program_res.error(), Error::Ok); + + Program program(std::move(program_res.get())); + + // Method calls should succeed without hitting ET_CHECK. + EXPECT_EQ(program.num_methods(), 2); + auto res = program.get_method_name(0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(strcmp(res.get(), "forward"), 0); + auto res2 = program.get_method_name(1); + EXPECT_TRUE(res2.ok()); + EXPECT_EQ(strcmp(res2.get(), "forward2"), 0); +} + +TEST_F(ProgramTest, GetNamedDataMap_Fail) { + Result program = + Program::load(add_loader_.get(), kDefaultVerification); + ASSERT_EQ(program.error(), Error::Ok); + + // Get the named data map. Expect to fail, as add.pte does not have any + // named data segments. + Result named_data_map = + program->get_named_data_map(); + EXPECT_EQ(named_data_map.error(), Error::NotFound); +} + +// Test that the deprecated Load method (capital 'L') still works. +TEST_F(ProgramTest, DEPRECATEDLoad) { + // Parse the Program from the data. + // NOLINTNEXTLINE(facebook-hte-Deprecated) + Result program_res = Program::Load(multi_loader_.get()); + EXPECT_EQ(program_res.error(), Error::Ok); +} + +TEST_F(ProgramTest, LoadConstantSegmentWithNoConstantSegment) { + Result program = + Program::load(add_loader_.get(), kDefaultVerification); + ASSERT_EQ(program.error(), Error::Ok); + + // Load constant segment data should fail. + const auto segment_info = DataLoader::SegmentInfo( + DataLoader::SegmentInfo::Type::Constant, + /*segment_index=*/0); + Result segment = + ProgramTestFriend::LoadSegment(&program.get(), segment_info); + EXPECT_NE(segment.error(), Error::Ok); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // The constant buffer should be empty. + EXPECT_EQ(flatbuffer_program->constant_buffer()->size(), 0); + + // Expect 1 constant segment, placeholder for non-const tensors. + EXPECT_EQ(flatbuffer_program->segments()->size(), 1); +} + +TEST_F(ProgramTest, LoadConstantSegment) { + // Load the serialized ModuleAddMul data, with constants in the segment. + const char* linear_path = std::getenv("ET_MODULE_ADD_MUL_PATH"); + Result linear_loader = FileDataLoader::from(linear_path); + ASSERT_EQ(linear_loader.error(), Error::Ok); + + // This file should always be compatible. + Result linear_header = linear_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(linear_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(linear_header->data(), linear_header->size()), + Program::HeaderStatus::CompatibleVersion); + + Result program = Program::load(&linear_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // Load constant segment data, which is currently always in segment index + // zero. + const auto segment_info = DataLoader::SegmentInfo( + DataLoader::SegmentInfo::Type::Constant, + /*segment_index=*/0); + Result segment = + ProgramTestFriend::LoadSegment(&program.get(), segment_info); + EXPECT_EQ(segment.error(), Error::Ok); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // Expect one segment containing the constants. + EXPECT_EQ(flatbuffer_program->segments()->size(), 1); + + // The constant buffer should be empty. + EXPECT_EQ(flatbuffer_program->constant_buffer()->size(), 0); + + // Check constant segment offsets. + EXPECT_EQ(flatbuffer_program->constant_segment()->segment_index(), 0); + EXPECT_GE(flatbuffer_program->constant_segment()->offsets()->size(), 1); +} + +TEST_F(ProgramTest, LoadConstantSegmentWhenConstantBufferExists) { + // Load the serialized ModuleAddMul data, with constants in the flatbuffer and + // no constants in the segment. + const char* linear_path = + std::getenv("DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH"); + Result linear_loader = FileDataLoader::from(linear_path); + ASSERT_EQ(linear_loader.error(), Error::Ok); + + // This file should always be compatible. + Result linear_header = linear_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + /*segment_info=*/ + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(linear_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(linear_header->data(), linear_header->size()), + Program::HeaderStatus::CompatibleVersion); + + Result program = Program::load(&linear_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // Expect no segments. + EXPECT_EQ(flatbuffer_program->segments()->size(), 0); + + // The constant buffer should exist. + EXPECT_GE(flatbuffer_program->constant_buffer()->size(), 1); +} + +TEST_F(ProgramTest, LoadFromMutableSegment) { + // Load the serialized ModuleSimpleTrain data. + auto path = std::getenv("ET_MODULE_SIMPLE_TRAIN_PATH"); + Result training_loader = FileDataLoader::from(path); + ASSERT_EQ(training_loader.error(), Error::Ok); + + // This file should always be compatible. + Result training_header = training_loader->load( + /*offset=*/0, + Program::kMinHeadBytes, + DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(training_header.error(), Error::Ok); + EXPECT_EQ( + Program::check_header(training_header->data(), training_header->size()), + Program::HeaderStatus::CompatibleVersion); + + Result program = Program::load(&training_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // dummy buffers to load into + uint8_t buffer[1] = {0}; + uint8_t buffer2[1] = {0}; + + // Load some mutable segment data + Error err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 0, 1, 1, buffer); + EXPECT_EQ(err, Error::Ok); + + // Check that the data loaded correctly, and then mutate it + EXPECT_EQ(buffer[0], 232); // 232 comes from inspecting the file itself. The + // file is seeded so this value should be stable. + buffer[0] = 0; + + // Load the same mutable segment data from file into a different buffer. + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), + 0, // mutable_data_segments_index + 1, // offset_index + 1, // size + buffer2); + EXPECT_EQ(err, Error::Ok); + + // Check that new data loaded from the file does not reflect the change to + // buffer. + EXPECT_EQ(buffer2[0], 232); + + const executorch_flatbuffer::Program* flatbuffer_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + + // Expect 2 segments. 1 mutable segment and 1 constant segment. + EXPECT_EQ(flatbuffer_program->segments()->size(), 2); + + // Expect a mutable data segment. + EXPECT_EQ(flatbuffer_program->mutable_data_segments()->size(), 1); + + // Expect the 0 index to be reserved and the offsets for weight and bias of + // linear to be indices 1 and 2. + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->size(), + 3); + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->Get(0), + 0); + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->Get(1), + 0); + EXPECT_EQ( + flatbuffer_program->mutable_data_segments()->Get(0)->offsets()->Get(2), + 36); + + // Loading beyond file should fail + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 0, 1, 500, buffer); + EXPECT_NE(err, Error::Ok); + + // Loading beyond offsets should fail + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 0, 500, 1, buffer); + EXPECT_NE(err, Error::Ok); + + // Loading beyond segments should fail + err = ProgramTestFriend::load_mutable_subsegment_into( + &program.get(), 500, 1, 1, buffer); + EXPECT_NE(err, Error::Ok); +} + +TEST_F(ProgramTest, LoadAndCheckPTESize) { + // Load the serialized ModuleAddMul data, with constants in the segment. + const char* linear_path = std::getenv("ET_MODULE_ADD_MUL_PATH"); + Result linear_loader = FileDataLoader::from(linear_path); + ASSERT_EQ(linear_loader.error(), Error::Ok); + Result program = Program::load(&linear_loader.get()); + ASSERT_EQ(program.error(), Error::Ok); + + // Create a truncated file. + Result truncated_file = linear_loader->load( + 0, 200, DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::Program)); + ASSERT_EQ(truncated_file.error(), Error::Ok); + + BufferDataLoader truncated_loader = + BufferDataLoader(truncated_file->data(), 200); + Result truncated_program = Program::load(&truncated_loader); + ASSERT_EQ(truncated_program.error(), Error::InvalidProgram); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/pte_data_map_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/pte_data_map_test.cpp new file mode 100644 index 0000000..5b13191 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/pte_data_map_test.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::extension::FileDataLoader; +using executorch::extension::testing::TempFile; +using executorch::runtime::DataLoader; +using executorch::runtime::Error; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Result; +using executorch::runtime::internal::PteDataMap; + +class PteDataMapTest : public ::testing::Test { + protected: + void SetUp() override { + // Since these tests cause ET_LOG to be called, the PAL must be initialized + // first. + executorch::runtime::runtime_init(); + + // Create a sample Program with only named_data and segments. Technically + // not a valid Program; only used to test the PteDataMap. + // Create named data. + std::array, 4> + named_data_arr = { + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key0", /*segment_index=*/0), + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key1", /*segment_index=*/1), + // Note: key2 points to the same segment as key0. + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key2", /*segment_index=*/0), + // This is invalid, as segment_index=10 is out of range when the + // number of segments is 2. + executorch_flatbuffer::CreateNamedDataDirect( + builder_, "key_invalid", /*segment_index=*/10), + }; + const auto named_data = + builder_.CreateVector(named_data_arr.data(), named_data_arr.size()); + + // Create segments. + std::array, 2> + segment_arr = {// @lint-ignore CLANGTIDY facebook-hte-BadArgumentComment + executorch_flatbuffer::CreateDataSegment( + builder_, /*offset=*/0, /*size=*/kSegmentSizes[0]), + // @lint-ignore CLANGTIDY facebook-hte-BadArgumentComment + executorch_flatbuffer::CreateDataSegment( + builder_, + /*offset=*/kSegmentAlignment * 2, + /*size=*/kSegmentSizes[1])}; + const auto segments = + builder_.CreateVector(segment_arr.data(), segment_arr.size()); + + // Create Program. + const auto program = executorch_flatbuffer::CreateProgram( + builder_, 0, 0, 0, 0, segments, 0, 0, named_data); + + builder_.Finish(program); + program_ = executorch_flatbuffer::GetProgram(builder_.GetBufferPointer()); + + // Create sample segment data. + for (int i = 0; i < kSegmentSizes[0]; i++) { + sample_data_[i] = 1; + } + for (int i = kSegmentOffsets[1]; i < kSegmentOffsets[1] + kSegmentSizes[1]; + i++) { + sample_data_[i] = 2; + } + TempFile tf(sample_data_.data(), sizeof(sample_data_)); + + // Wrap the sample data in a loader. + Result loader = + FileDataLoader::from(tf.path().c_str(), kSegmentAlignment); + ASSERT_EQ(loader.error(), Error::Ok); + data_map_loader_ = + std::make_unique(std::move(loader.get())); + } + + // Program builder constants. + static constexpr int kSegmentAlignment = 16; + static constexpr std::array kSegmentSizes{17, 8}; + static constexpr std::array kSegmentOffsets{0, kSegmentAlignment * 2}; + std::array sample_data_; + + // Program builder. + flatbuffers::FlatBufferBuilder builder_; + const executorch_flatbuffer::Program* program_; + + // Data loader for the sample data. + std::unique_ptr data_map_loader_; +}; + +TEST_F(PteDataMapTest, Load) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); +} + +TEST_F(PteDataMapTest, LoadFail) { + Result data_map = PteDataMap::create( + /*loader=*/nullptr, + /*segment_base_offset=*/0, + program_->named_data(), + program_->segments()); + EXPECT_EQ(data_map.error(), Error::InvalidArgument); +} + +TEST_F(PteDataMapTest, UnimplementedMethods) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ; + + // Check get_tensor_layout is not implemented. + auto result = data_map->get_tensor_layout("sample_key"); + EXPECT_EQ(result.error(), Error::NotImplemented); + + // Check load_data_into is not implemented. + auto err = data_map->load_data_into("sample_key", nullptr, 0); + EXPECT_EQ(err, Error::NotImplemented); +} + +TEST_F(PteDataMapTest, Keys) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + // Check get_num_keys. + auto num_keys = data_map->get_num_keys(); + EXPECT_EQ(num_keys.error(), Error::Ok); + EXPECT_EQ(num_keys.get(), 4); + + // Check get_key_at. + auto key0 = data_map->get_key(0); + EXPECT_EQ(strcmp(key0.get(), "key0"), 0); + auto key1 = data_map->get_key(1); + EXPECT_EQ(strcmp(key1.get(), "key1"), 0); + auto key2 = data_map->get_key(2); + EXPECT_EQ(strcmp(key2.get(), "key2"), 0); + + // This key is invalid because it points to a segment_index=10, which is out + // of range for this example with segment size=2. + // Note: practically, a PTE should not have invalid keys. + auto key_invalid = data_map->get_key(3); + EXPECT_EQ(strcmp(key_invalid.get(), "key_invalid"), 0); + + // Returns an error on non-existent key. + auto nonexistent_key = data_map->get_key(10); + EXPECT_EQ(nonexistent_key.error(), Error::InvalidArgument); +} + +TEST_F(PteDataMapTest, GetData) { + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + Result data0 = data_map->get_data("key0"); + EXPECT_EQ(data0.error(), Error::Ok); + EXPECT_EQ(data0.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data0.get().data(), sample_data_.data(), data0.get().size()), 0); + + Result data1 = data_map->get_data("key1"); + EXPECT_EQ(data1.error(), Error::Ok); + EXPECT_EQ(data1.get().size(), kSegmentSizes[1]); + EXPECT_EQ( + memcmp( + data1.get().data(), + sample_data_.data() + kSegmentOffsets[1], + data1.get().size()), + 0); + + Result data2 = data_map->get_data("key2"); + EXPECT_EQ(data2.error(), Error::Ok); + // Expect the same values as data0, as key0 and key2 point to the same + // segment. + EXPECT_EQ(data2.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data2.get().data(), sample_data_.data(), data2.get().size()), 0); + + // Free data. + data0->Free(); + data1->Free(); + data2->Free(); + + // Returns an error, as key_invalid contains segment_index=10, which + // is out of range for segments.size()=2. + Result data_invalid = data_map->get_data("key_invalid"); + EXPECT_EQ(data_invalid.error(), Error::InvalidArgument); + + // Returns an error on nonexistent key. + Result data_nonexistent = + data_map->get_data("nonexistent_key"); + EXPECT_EQ(data_nonexistent.error(), Error::NotFound); +} + +TEST_F(PteDataMapTest, FreeAndReload) { + // Load a key, free it, and then load it again, and ensure that the + // core data map can return a new FreeableBuffer with the same data. + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + // Load data0. + Result data0 = data_map->get_data("key0"); + EXPECT_EQ(data0.error(), Error::Ok); + EXPECT_EQ(data0.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data0.get().data(), sample_data_.data(), data0.get().size()), 0); + data0->Free(); + + // Reload data0, ensure that the core data map can return a new + // FreeableBuffer with the same data. + Result data0_reload = data_map->get_data("key0"); + EXPECT_EQ(data0_reload.error(), Error::Ok); + EXPECT_EQ(data0_reload.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp( + data0_reload.get().data(), + sample_data_.data(), + data0_reload.get().size()), + 0); + data0_reload->Free(); +} + +TEST_F(PteDataMapTest, ReloadAndFree) { + // Load the same key multiple times, and then free one and ensure that the + // data in the other is still valid. + Result data_map = PteDataMap::create( + data_map_loader_.get(), 0, program_->named_data(), program_->segments()); + ASSERT_TRUE(data_map.ok()); + + // Load data0. + Result data0 = data_map->get_data("key0"); + EXPECT_EQ(data0.error(), Error::Ok); + EXPECT_EQ(data0.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp(data0.get().data(), sample_data_.data(), data0.get().size()), 0); + + // Reload data0. + Result data0_reload = data_map->get_data("key0"); + EXPECT_EQ(data0_reload.error(), Error::Ok); + EXPECT_EQ(data0_reload.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp( + data0_reload.get().data(), + sample_data_.data(), + data0_reload.get().size()), + 0); + + // Free data0 and check that data0_reload is still valid. + data0->Free(); + EXPECT_EQ(data0_reload.get().size(), kSegmentSizes[0]); + EXPECT_EQ( + memcmp( + data0_reload.get().data(), + sample_data_.data(), + data0_reload.get().size()), + 0); + + // Free data_reload0. + data0_reload->Free(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/targets.bzl new file mode 100644 index 0000000..0fac69b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/targets.bzl @@ -0,0 +1,300 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def define_common_targets(is_fbcode = False): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + for aten_mode in get_aten_mode_options(): + aten_suffix = ("_aten" if aten_mode else "") + + runtime.cxx_library( + name = "test_backend_compiler_lib" + aten_suffix, + srcs = [ + "test_backend_compiler_lib.cpp", + ], + visibility = [ + "//executorch/exir/backend/test/...", + "//executorch/runtime/backend/...", + "//executorch/extension/pybindings/...", + "//executorch/devtools/fb/runners/...", + "//executorch/test/...", + "//executorch/examples/...", + ], + # registration of backends is done through a static global + compiler_flags = ["-Wno-global-constructors"], + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + "//executorch/runtime/backend:interface" + aten_suffix, + ], + # TestBackendCompilerLib.cpp needs to compile with executor as whole + # @lint-ignore BUCKLINT: Avoid `link_whole=True` (https://fburl.com/avoid-link-whole) + link_whole = True, + ) + + runtime.cxx_library( + name = "test_backend_with_delegate_mapping" + aten_suffix, + srcs = [ + "test_backend_with_delegate_mapping.cpp", + ], + visibility = [ + "//executorch/exir/backend/test/...", + "//executorch/runtime/backend/...", + "//executorch/extension/pybindings/...", + "//executorch/devtools/fb/runners/...", + "//executorch/test/...", + "//executorch/examples/...", + ], + # registration of backends is done through a static global + compiler_flags = ["-Wno-global-constructors"], + preprocessor_flags = ["-DUSE_ATEN_LIB"] if aten_mode else [], + exported_deps = [ + "//executorch/runtime/backend:interface" + aten_suffix, + ], + # TestBackendCompilerLib.cpp needs to compile with executor as whole + # @lint-ignore BUCKLINT: Avoid `link_whole=True` (https://fburl.com/avoid-link-whole) + link_whole = True, + ) + + runtime.cxx_test( + name = "executor_test" + aten_suffix, + srcs = [ + "executor_test.cpp", + ], + deps = [ + "//executorch/extension/pytree:pytree", + "//executorch/kernels/portable:generated_lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/testing_util:tensor_util" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core:evalue" + aten_suffix, + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + "//executorch/runtime/kernel:operator_registry" + aten_suffix, + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_library( + name = "managed_memory_manager", + srcs = [], + exported_headers = [ + "managed_memory_manager.h", + ], + visibility = ["PUBLIC"], + deps = [ + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/executor:memory_manager", + ], + ) + + runtime.cxx_test( + name = "pte_data_map_test", + srcs = [ + "pte_data_map_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/testing_util:temp_file", + "//executorch/runtime/executor:pte_data_map", + "//executorch/schema:program", + ], + ) + + # TODO(dbort): Find a way to make these run for ANDROID/APPLE in xplat. The + # android and ios test determinators don't like the reference to the model + # file in fbcode. See https://fburl.com/9esapdmd + if not runtime.is_oss and is_fbcode: + modules_env = { + # Deprecated model that still works with ExecuTorch runtime. + "DEPRECATED_ET_MODULE_LINEAR_CONSTANT_BUFFER_PATH": "$(location fbcode//executorch/test/models/deprecated:ModuleLinear-no-constant-segment.pte)", + # The tests use this var to find the program file to load. This uses + # an fbcode target path because the authoring/export tools + # intentionally don't work in xplat (since they're host-only tools). + "ET_MODULE_ADD_HALF_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAddHalf.pte])", + "ET_MODULE_ADD_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAdd.pte])", + "ET_MODULE_DYNAMIC_CAT_UNALLOCATED_IO_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleDynamicCatUnallocatedIO.pte])", + "ET_MODULE_INDEX_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleIndex.pte])", + "ET_MODULE_ADD_MUL_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleAddMul.pte])", + "ET_MODULE_MULTI_ENTRY_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleMultipleEntry.pte])", + "ET_MODULE_SIMPLE_TRAIN_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleSimpleTrain.pte])", + "ET_MODULE_STATEFUL_PATH": "$(location fbcode//executorch/test/models:exported_programs[ModuleStateful.pte])", + "ET_MODULE_ADD_MUL_PROGRAM_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleAddMul.pte])", + "ET_MODULE_ADD_MUL_DATA_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleAddMul.ptd])", + "ET_MODULE_LINEAR_DATA_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleLinear.ptd])", + } + + runtime.cxx_test( + name = "allocation_failure_stress_test", + srcs = [ + "allocation_failure_stress_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/kernels/portable:generated_lib", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/runner_util:inputs", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "merged_data_map_test", + srcs = [ + "merged_data_map_test.cpp", + ], + deps = [ + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/flat_tensor:flat_tensor_data_map", + "//executorch/runtime/executor:merged_data_map", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "method_test", + srcs = [ + "method_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:merged_data_map", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/flat_tensor:flat_tensor_data_map", + "//executorch/extension/runner_util:inputs", + "//executorch/kernels/portable:generated_lib", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "method_meta_test", + srcs = [ + "method_meta_test.cpp", + ], + deps = [ + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "program_test", + srcs = [ + "program_test.cpp", + ], + deps = [ + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:buffer_data_loader", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/schema:program", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "kernel_resolution_test", + srcs = [ + "kernel_resolution_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/runtime/kernel:operator_registry", + "//executorch/extension/data_loader:file_data_loader", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "kernel_integration_test", + srcs = [ + "kernel_integration_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/runner_util:inputs", + "//executorch/runtime/core:core", + "//executorch/runtime/executor:program", + "//executorch/runtime/kernel:kernel_runtime_context", + "//executorch/runtime/kernel:operator_registry", + "//executorch/runtime/platform:platform", + ], + env = modules_env, + ) + + runtime.cxx_test( + name = "backend_integration_test", + srcs = [ + "backend_integration_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/backend:interface", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:buffer_data_loader", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/extension/runner_util:inputs", + ], + env = { + # The tests use these vars to find the program files to load. + # Uses an fbcode target path because the authoring/export tools + # intentionally don't work in xplat (since they're host-only + # tools). + "ET_MODULE_ADD_MUL_NOSEGMENTS_DA1024_PATH": "$(location fbcode//executorch/test/models:exported_delegated_add_mul[ModuleAddMul-nosegments-da1024.pte])", + "ET_MODULE_ADD_MUL_NOSEGMENTS_PATH": "$(location fbcode//executorch/test/models:exported_delegated_add_mul[ModuleAddMul-nosegments.pte])", + "ET_MODULE_ADD_MUL_DELEGATED_PATH": "$(location fbcode//executorch/test/models:exported_delegated_add_mul[ModuleAddMul.pte])", + }, + ) + + runtime.cxx_test( + name = "backend_data_separation_test", + srcs = [ + "backend_data_separation_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/exir/backend/test/demos/rpc:executor_backend", + "//executorch/exir/backend/test/demos/rpc:executor_backend_register", + "//executorch/extension/flat_tensor:flat_tensor_data_map", + ], + env = { + # The tests use these vars to find the program files to load. + # Uses an fbcode target path because the authoring/export tools + # intentionally don't work in xplat (since they're host-only + # tools). + "ET_MODULE_LINEAR_DELEGATE_PROGRAM_PATH": "$(location fbcode//executorch/test/models:exported_executor_backend_program_and_data[ModuleLinear-e.pte])", + "ET_MODULE_LINEAR_DATA_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleLinear.ptd])", + }, + ) + runtime.cxx_test( + name = "memory_manager_test", + srcs = [ + "memory_manager_test.cpp", + ], + deps = [ + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/executor:memory_manager", + ], + ) + + runtime.cxx_test( + name = "tensor_parser_test", + srcs = [ + "tensor_parser_test.cpp", + ], + deps = [ + ":managed_memory_manager", + "//executorch/runtime/executor:program", + "//executorch/extension/data_loader:file_data_loader", + "//executorch/kernels/portable:generated_lib", + "//executorch/schema:program", + ], + env = modules_env, + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/tensor_parser_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/tensor_parser_test.cpp new file mode 100644 index 0000000..b193ab2 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/tensor_parser_test.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::Program; +using executorch::runtime::Result; +using executorch::runtime::deserialization::parseTensor; +using executorch::runtime::testing::ManagedMemoryManager; +using torch::executor::util::FileDataLoader; + +constexpr size_t kDefaultNonConstMemBytes = 32 * 1024U; +constexpr size_t kDefaultRuntimeMemBytes = 32 * 1024U; + +class TensorParserTest : public ::testing::Test { + protected: + void SetUp() override { + // Load the serialized ModuleAdd data. + const char* path = std::getenv("ET_MODULE_ADD_PATH"); + Result float_loader = FileDataLoader::from(path); + ASSERT_EQ(float_loader.error(), Error::Ok); + float_loader_ = + std::make_unique(std::move(float_loader.get())); + + // Load the serialized ModuleAddHalf data. + const char* half_path = std::getenv("ET_MODULE_ADD_HALF_PATH"); + Result half_loader = FileDataLoader::from(half_path); + ASSERT_EQ(half_loader.error(), Error::Ok); + half_loader_ = + std::make_unique(std::move(half_loader.get())); + } + + std::unique_ptr float_loader_; + std::unique_ptr half_loader_; +}; + +namespace executorch { +namespace runtime { +namespace testing { +// Provides access to private Program methods. +class ProgramTestFriend final { + public: + const static executorch_flatbuffer::Program* GetInternalProgram( + const Program* program) { + return program->internal_program_; + } +}; +} // namespace testing +} // namespace runtime +} // namespace executorch + +using executorch::runtime::testing::ProgramTestFriend; + +void test_module_add( + std::unique_ptr& loader, + ScalarType scalar_type, + int type_size) { + Result program = + Program::load(loader.get(), Program::Verification::Minimal); + EXPECT_EQ(program.error(), Error::Ok); + + const Program* program_ = &program.get(); + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + const executorch_flatbuffer::Program* internal_program = + ProgramTestFriend::GetInternalProgram(program_); + executorch_flatbuffer::ExecutionPlan* execution_plan = + internal_program->execution_plan()->GetMutableObject(0); + auto flatbuffer_values = execution_plan->values(); + + int tensor_count = 0; + int double_count = 0; + for (size_t i = 0; i < flatbuffer_values->size(); ++i) { + auto serialization_value = flatbuffer_values->Get(i); + if (serialization_value->val_type() == + executorch_flatbuffer::KernelTypes::Tensor) { + tensor_count++; + Result tensor = parseTensor( + program_, &mmm.get(), serialization_value->val_as_Tensor()); + Tensor t = tensor.get(); + ASSERT_EQ(scalar_type, t.scalar_type()); + ASSERT_EQ(2, t.dim()); // [2, 2] + ASSERT_EQ(4, t.numel()); + ASSERT_EQ(type_size * t.numel(), t.nbytes()); + } else if ( + serialization_value->val_type() == + executorch_flatbuffer::KernelTypes::Double) { + double_count++; + ASSERT_EQ(1.0, serialization_value->val_as_Double()->double_val()); + } + } + ASSERT_EQ(3, tensor_count); // input x2, output + ASSERT_EQ(2, double_count); // alpha x2 +} + +TEST_F(TensorParserTest, TestModuleAddFloat) { + test_module_add(float_loader_, ScalarType::Float, sizeof(float)); +} + +TEST_F(TensorParserTest, TestModuleAddHalf) { + test_module_add( + half_loader_, ScalarType::Half, sizeof(executorch::aten::Half)); +} + +TEST_F(TensorParserTest, TestMutableState) { + // Load the serialized ModuleSimpleTrain data. + const char* path = std::getenv("ET_MODULE_SIMPLE_TRAIN_PATH"); + Result train_loader = FileDataLoader::from(path); + ASSERT_EQ(train_loader.error(), Error::Ok); + + Result program = + Program::load(&train_loader.get(), Program::Verification::Minimal); + EXPECT_EQ(program.error(), Error::Ok); + + ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + ManagedMemoryManager mmm_copy( + kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes); + + const executorch_flatbuffer::Program* internal_program = + ProgramTestFriend::GetInternalProgram(&program.get()); + executorch_flatbuffer::ExecutionPlan* execution_plan = + internal_program->execution_plan()->GetMutableObject(0); + auto flatbuffer_values = execution_plan->values(); + + size_t num_mutable_tensors = 0; + for (size_t i = 0; i < flatbuffer_values->size(); ++i) { + auto serialization_value = flatbuffer_values->Get(i); + if (serialization_value->val_type() == + executorch_flatbuffer::KernelTypes::Tensor && + serialization_value->val_as_Tensor()->allocation_info() != nullptr && + serialization_value->val_as_Tensor()->data_buffer_idx() > 0) { + num_mutable_tensors++; + Result tensor = parseTensor( + &program.get(), &mmm.get(), serialization_value->val_as_Tensor()); + torch::executor::Tensor t = tensor.get(); + float loaded_value = t.const_data_ptr()[0]; + ASSERT_NE(nullptr, t.const_data_ptr()); + ASSERT_NE(t.mutable_data_ptr()[0], 0.5); + t.mutable_data_ptr()[0] = 0.5; + ASSERT_EQ( + t.mutable_data_ptr()[0], + 0.5); // 0.5 can be represented perfectly by float so EQ and NE work + // fine here. Any power of 2 rational can be perfectly + // represented. See dyadic rationals for more info. + + // Load the same tensor using the same mem manager and show the value is + // updated again. + Result tensor1_alias = parseTensor( + &program.get(), &mmm.get(), serialization_value->val_as_Tensor()); + torch::executor::Tensor t2 = tensor.get(); + ASSERT_NE(t2.mutable_data_ptr()[0], 0.5); + + // Show the tensors are equivalent + ASSERT_EQ(t.const_data_ptr(), t2.const_data_ptr()); + // Set mutable tensor value back to 0.5 since it got overwritten by second + // parse. + t.mutable_data_ptr()[0] = 0.5; + + // Load the same tensor using a different mem manager and show the value + // is not the same as t. + Result tensor_new = parseTensor( + &program.get(), + &mmm_copy.get(), + serialization_value->val_as_Tensor()); + torch::executor::Tensor t3 = tensor_new.get(); + ASSERT_NE(t3.mutable_data_ptr()[0], 0.5); + ASSERT_NE(t3.const_data_ptr(), t.const_data_ptr()); + ASSERT_EQ(loaded_value, t3.const_data_ptr()[0]); + } + } + ASSERT_EQ(num_mutable_tensors, 2); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_compiler_lib.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_compiler_lib.cpp new file mode 100644 index 0000000..8ad48e4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_compiler_lib.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include /* strtol */ + +using executorch::ET_RUNTIME_NAMESPACE::Backend; +using executorch::ET_RUNTIME_NAMESPACE::BackendExecutionContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInitContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInterface; +using executorch::ET_RUNTIME_NAMESPACE::CompileSpec; +using executorch::ET_RUNTIME_NAMESPACE::DelegateHandle; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +struct DemoOp { + const char* name; + long int numel; + const char* dtype; + long int debug_handle; +}; + +struct DemoOpList { + DemoOp* ops; + size_t numops; +}; + +class BackendWithCompiler final : public BackendInterface { + int max_shape = 4; + + public: + ~BackendWithCompiler() override = default; + + bool is_available() const override { + return true; + } + + // The delegate blob schema will be a list of instruction: + // {op: {str}, numel: {long}, dtype: {type}}n + // Instruction will be separated by #, for example: + // 'op:demo::mul.Tensor, numel:4, dtype:torch.float322\ + // #op:demo::add.Tensor, numel:4, dtype:torch.float324#' + void parse_delegate(const char* str, const char* sub, DemoOp* op_list) const { + const char* kOpLiteral = "op:"; + const char* kNumelLiteral = "numel:"; + const char* kDtypeliteral = "dtype:"; + const char* kDebugHandleLiteral = ""; + + const char* kComma = ","; + + int cnt = 0; + const char* left = str; + const char* right; + + // iter 0: + // op:demo::sin.default, numel:1, dtype:torch.float321# + // |<--left right-->| + // iter 1: + // op:demo::add.Tensor, numel:4, dtype:torch.float324# + // |<--left right-->| + while ((right = strstr(left, sub))) { + // Get operator name + const char* op_start = strstr(left, kOpLiteral) + strlen(kOpLiteral); + const char* op_end = strstr(op_start, kComma); + + op_list[cnt].name = op_start; + + // Get numel + const char* numel_start = + strstr(op_end, kNumelLiteral) + strlen(kNumelLiteral); + char* numel_end = const_cast(strstr(numel_start, kComma)); + op_list[cnt].numel = strtol(numel_start, &numel_end, 10); + + // Get dtype + const char* dtype_start = + strstr(numel_end, kDtypeliteral) + strlen(kDtypeliteral); + const char* dtype_end = strstr(dtype_start, kDebugHandleLiteral); + op_list[cnt].dtype = dtype_start; + + // Get debug handle + const char* debug_handle_start = + strstr(dtype_end, kDebugHandleLiteral) + strlen(kDebugHandleLiteral); + char* debug_end = const_cast(strstr(debug_handle_start, kComma)); + op_list[cnt].debug_handle = strtol(debug_handle_start, &debug_end, 10); + + // Move left pointer to the start of next instruction + left = right + 1; + cnt++; + } + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + MemoryAllocator* runtime_allocator = context.get_runtime_allocator(); + int shape = *(int*)(compile_specs.at(0).value.buffer); + ET_CHECK_OR_RETURN_ERROR( + shape <= max_shape, + InvalidArgument, + "The input number is %d and it's larger than the max number %d " + "supported by this backend.", + shape, + max_shape); + + const char* kSignLiteral = "#"; + // The first number is the number of total instruction + const char* start = static_cast(processed->data()); + + const char* kVersion = "version:"; + const long int kRuntimeVersion = 0; + char* version_start = + const_cast(strstr(start, kVersion)) + strlen(kVersion); + char* version_end; + char* instruction_set_start = + const_cast(strstr(start, kSignLiteral)); + + long int version = strtol(version_start, &version_end, 10); + ET_CHECK_OR_RETURN_ERROR( + version == kRuntimeVersion, + DelegateInvalidCompatibility, + "The version of BackendWithCompiler runtime is %ld, but received an incompatible version %ld instead.", + kRuntimeVersion, + version); + char* instruction_number_end; + long int instruction_number = strtol(start, &instruction_number_end, 10); + + ET_CHECK_OR_RETURN_ERROR( + instruction_number >= 0, + InvalidArgument, + "Instruction count must be non-negative: %ld", + instruction_number); + + auto op_list = runtime_allocator->allocateInstance(); + if (op_list == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->ops = runtime_allocator->allocateList(instruction_number); + if (op_list->ops == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->numops = static_cast(instruction_number); + + parse_delegate(instruction_set_start + 1, kSignLiteral, op_list->ops); + + // Can't call `processed->Free()` because op_list points into it. + + return op_list; + } + + // Function that actually executes the model in the backend. Here there is + // nothing to dispatch to, so the backend is implemented locally within + // execute and it only supports add, subtract, and constant. In a non toy + // backend you can imagine how this function could be used to actually + // dispatch the inputs to the relevant backend/device. + Error execute( + ET_UNUSED BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + EXECUTORCH_SCOPE_PROF("BackendWithCompiler::execute"); + + // example: [('prim::Constant#1', 14), ('aten::add', 15)] + auto op_list = static_cast(handle); + + const char* kDemoAdd = "demo::aten.add.Tensor"; + const char* kDemoMul = "demo::aten.mm.default"; + const char* kDemoSin = "demo::aten.sin.default"; + const char* kTorchFloat32 = "torch.float32"; + + for (size_t index = 0; index < op_list->numops; index++) { + auto instruction = op_list->ops[index]; + ET_CHECK_OR_RETURN_ERROR( + strncmp(instruction.dtype, kTorchFloat32, strlen(kTorchFloat32)) == 0, + NotSupported, + "BackendWithCompiler only support float and doesn't support %s, " + "debug handle is: %ld", + instruction.dtype, + instruction.debug_handle); + if (strncmp(instruction.name, kDemoAdd, strlen(kDemoAdd)) == 0) { + // z = z + b + const float* b_ptr = args[2]->toTensor().const_data_ptr(); + float* z_ptr = args[3]->toTensor().mutable_data_ptr(); + for (size_t j = 0; j < instruction.numel; j++) { + z_ptr[j] = b_ptr[j] + z_ptr[j]; + } + } else if (strncmp(instruction.name, kDemoMul, strlen(kDemoMul)) == 0) { + ET_CHECK_OR_RETURN_ERROR( + instruction.numel == 4, + NotSupported, + "BackendWithCompiler only support 2 x 2 matrix multiplication, " + "debug handle is %ld", + instruction.debug_handle); + // z = a * x + const float* a_ptr = args[0]->toTensor().const_data_ptr(); + const float* x_ptr = args[1]->toTensor().const_data_ptr(); + float* z_ptr = args[3]->toTensor().mutable_data_ptr(); + + z_ptr[0] = a_ptr[0] * x_ptr[0] + a_ptr[1] * x_ptr[2]; + z_ptr[1] = a_ptr[0] * x_ptr[1] + a_ptr[1] * x_ptr[3]; + z_ptr[2] = a_ptr[2] * x_ptr[0] + a_ptr[3] * x_ptr[2]; + z_ptr[3] = a_ptr[2] * x_ptr[1] + a_ptr[3] * x_ptr[3]; + } else if (strncmp(instruction.name, kDemoSin, strlen(kDemoSin)) == 0) { + const float* x_ptr = args[0]->toTensor().const_data_ptr(); + float* y_ptr = args[1]->toTensor().mutable_data_ptr(); + // Taylor series: an approximation of sin x around the point x = 0 + // sin(x) = x - x^3 / 3! + x^5 / 5! - x^7 / 7! ... + // Use the first two items as proof of concept + for (size_t j = 0; j < instruction.numel; j++) { + y_ptr[j] = x_ptr[j] - x_ptr[j] * x_ptr[j] * x_ptr[j] / 6.0; + } + } + } + return Error::Ok; + } +}; + +namespace { +auto cls = BackendWithCompiler(); +Backend backend{"BackendWithCompilerDemo", &cls}; +static auto success_with_compiler = register_backend(backend); +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_with_delegate_mapping.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_with_delegate_mapping.cpp new file mode 100644 index 0000000..feeff88 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/executor/test/test_backend_with_delegate_mapping.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include /* strtol */ +#include + +using executorch::ET_RUNTIME_NAMESPACE::Backend; +using executorch::ET_RUNTIME_NAMESPACE::BackendExecutionContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInitContext; +using executorch::ET_RUNTIME_NAMESPACE::BackendInterface; +using executorch::ET_RUNTIME_NAMESPACE::CompileSpec; +using executorch::ET_RUNTIME_NAMESPACE::DelegateHandle; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::FreeableBuffer; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; +using executorch::runtime::Span; + +struct DemoOp { + const char* name; + long int debug_handle; +}; + +struct DemoOpList { + DemoOp* ops; + size_t numops; +}; + +class BackendWithDelegateMapping final : public BackendInterface { + public: + ~BackendWithDelegateMapping() override = default; + + bool is_available() const override { + return true; + } + + // The delegate blob schema will be a list of instruction: + // {op_name:{str},delegate debug identifier:{int}} + // Instructions will be separated by #, for example: + // `op_name:demo_linear,delegate debug + // identifier:0#op_name:mm_decomp_from_addmm,\ delegate debug + // identifier:1#op_name:mm_decomp_from_addmm,delegate debug identifier:2` + Error parse_delegate( + const char* str, + DemoOpList* op_list, + MemoryAllocator* runtime_allocator) const { + char* op_name; + char* delegate_debug_identifier; + size_t num_ops = 0; + char* copy = strdup(str); + + while (true) { + char* saveptr = nullptr; + op_name = strtok_r(copy, ",", &saveptr); + delegate_debug_identifier = strtok_r(nullptr, ",", &saveptr); + + if (op_name == nullptr || delegate_debug_identifier == nullptr) { + break; + } + + if (op_name != nullptr && delegate_debug_identifier != nullptr) { + char* op_name_mem = + (char*)runtime_allocator->allocate(strlen(op_name) + 1); + if (op_name_mem == nullptr) { + return Error::MemoryAllocationFailed; + } + memcpy(op_name_mem, op_name, strlen(op_name) + 1); + op_list->ops[num_ops].name = op_name_mem; + op_list->ops[num_ops].debug_handle = atoi(delegate_debug_identifier); + } + + num_ops += 1; + if (num_ops == op_list->numops) { + break; + } + copy = nullptr; + } + + free(copy); + return Error::Ok; + } + + Result init( + BackendInitContext& context, + FreeableBuffer* processed, + ArrayRef compile_specs) const override { + MemoryAllocator* runtime_allocator = context.get_runtime_allocator(); + (void)compile_specs; + const char* kSignLiteral = "#"; + // The first number is the number of total instruction + const char* start = static_cast(processed->data()); + char* instruction_number_end = + const_cast(strstr(start, kSignLiteral)); + long int instruction_number = strtol(start, &instruction_number_end, 10); + ET_CHECK_OR_RETURN_ERROR( + instruction_number >= 0, + InvalidArgument, + "Instruction count must be non-negative: %ld", + instruction_number); + + auto op_list = runtime_allocator->allocateInstance(); + if (op_list == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->ops = runtime_allocator->allocateList(instruction_number); + if (op_list->ops == nullptr) { + return Error::MemoryAllocationFailed; + } + + op_list->numops = static_cast(instruction_number); + + Error error = + parse_delegate(instruction_number_end + 1, op_list, runtime_allocator); + if (error != Error::Ok) { + return error; + } + + return op_list; + } + + // This function doesn't actually execute the op but just prints out the op + // name and the corresponding delegate debug identifier. + Error execute( + ET_UNUSED BackendExecutionContext& context, + DelegateHandle* handle, + Span args) const override { + (void)args; + // example: [('prim::Constant#1', 14), ('aten::add', 15)] + auto op_list = static_cast(handle); + + for (size_t index = 0; index < op_list->numops; index++) { + ET_LOG( + Info, + "Op name = %s Delegate debug index = %ld", + op_list->ops[index].name, + op_list->ops[index].debug_handle); + event_tracer_log_profiling_delegate( + context.event_tracer(), + nullptr, + op_list->ops[index].debug_handle, + 0, + 1); + /** + If you used string based delegate debug identifiers then the profiling + call would be as below. + event_tracer_log_profiling_delegate( + context.event_tracer(), + pointer_to_delegate_debug_string, + -1, + 0, + 1); + */ + } + + return Error::Ok; + } +}; + +namespace { +auto cls = BackendWithDelegateMapping(); +Backend backend{"BackendWithDelegateMappingDemo", &cls}; +static auto success_with_compiler = register_backend(backend); +} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/kernel_includes.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/kernel_includes.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/kernel_includes.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/kernel_includes.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/kernel_runtime_context.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/kernel_runtime_context.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/kernel_runtime_context.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/kernel_runtime_context.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/operator_registry.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/operator_registry.cpp similarity index 82% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/operator_registry.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/operator_registry.cpp index a5803cd..3738f82 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/kernel/operator_registry.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/operator_registry.cpp @@ -20,27 +20,14 @@ namespace ET_RUNTIME_NAMESPACE { namespace { // Maximum number of operators and their associated kernels that can be -// registered. Resolution order: -// 1. User-defined -DMAX_KERNEL_NUM wins. -// 2. Otherwise, if selective build generated selected_max_kernel_num.h and -// it defines EXECUTORCH_SELECTED_MAX_KERNEL_NUM, use that. (When a -// selective-build YAML opts into all operators the header is emitted -// without the define, and we fall through.) -// 3. Otherwise, fall back to a conservative default of 2000 slots. -#if defined(MAX_KERNEL_NUM) +// registered. +#ifdef MAX_KERNEL_NUM constexpr uint32_t kMaxRegisteredKernels = MAX_KERNEL_NUM; #else -#if __has_include() -#include -#endif -#if defined(EXECUTORCH_SELECTED_MAX_KERNEL_NUM) -constexpr uint32_t kMaxRegisteredKernels = EXECUTORCH_SELECTED_MAX_KERNEL_NUM; -#else constexpr uint32_t kMaxOperators = 250; constexpr uint32_t kMaxKernelsPerOp = 8; constexpr uint32_t kMaxRegisteredKernels = kMaxOperators * kMaxKernelsPerOp; #endif -#endif // Data that backs the kernel table. Since Kernel has a custom default // constructor (implicitly, because it contains KernelKey, which has a custom @@ -101,13 +88,6 @@ Error register_kernels_internal(const Span kernels) { kernel.kernel_key_ == k.kernel_key_) { ET_LOG(Error, "Re-registering %s, from %s", k.name_, lib_name); ET_LOG_KERNEL_KEY(k.kernel_key_); - ET_CHECK_MSG( - false, - "Kernel registration failed with error %" PRIu32 - ", Re-registering %s, from %s", - static_cast(Error::RegistrationAlreadyRegistered), - k.name_, - lib_name); return Error::RegistrationAlreadyRegistered; } } @@ -249,8 +229,7 @@ bool registry_has_op_function( Result get_op_function_from_registry( const char* name, - Span meta_list, - Span kernel_list) { + Span meta_list) { std::array key_string; Error err = internal::make_kernel_key_string( meta_list, key_string.data(), key_string.size()); @@ -261,31 +240,24 @@ Result get_op_function_from_registry( KernelKey kernel_key = KernelKey(key_string.data()); int32_t fallback_idx = -1; - for (size_t idx = 0; idx < kernel_list.size(); idx++) { - if (strcmp(kernel_list[idx].name_, name) == 0) { - if (kernel_list[idx].kernel_key_ == kernel_key) { - return kernel_list[idx].op_; + for (size_t idx = 0; idx < num_registered_kernels; idx++) { + if (strcmp(registered_kernels[idx].name_, name) == 0) { + if (registered_kernels[idx].kernel_key_ == kernel_key) { + return registered_kernels[idx].op_; } - if (kernel_list[idx].kernel_key_.is_fallback()) { + if (registered_kernels[idx].kernel_key_.is_fallback()) { fallback_idx = idx; } } } if (fallback_idx != -1) { - return kernel_list[fallback_idx].op_; + return registered_kernels[fallback_idx].op_; } ET_LOG(Error, "kernel '%s' not found.", name); ET_LOG_TENSOR_META(meta_list); return Error::OperatorMissing; } -Result get_op_function_from_registry( - const char* name, - Span meta_list) { - return get_op_function_from_registry( - name, meta_list, get_registered_kernels()); -} - Span get_registered_kernels() { return {registered_kernels, num_registered_kernels}; } diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/operator_registry.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/operator_registry.h similarity index 93% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/operator_registry.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/operator_registry.h index 4f69bb7..dfae7c2 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/operator_registry.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/operator_registry.h @@ -123,14 +123,14 @@ struct KernelKey { * for all input tensor dtypes and dim orders if the specialized kernel is not * registered. */ - constexpr KernelKey() = default; + KernelKey() = default; /** * Creates a specialized (non-fallback) kernel key that matches a specific * set of input tensor dtypes and dim orders. See the class comment for the * expected format of `kernel_key_data`. */ - /* implicit */ constexpr KernelKey(const char* kernel_key_data) + /* implicit */ KernelKey(const char* kernel_key_data) : kernel_key_data_(kernel_key_data) {} bool operator==(const KernelKey& other) const { @@ -188,13 +188,12 @@ struct Kernel { * itself, we require the lifetime of the operator name to be at least as long * as the operator registry. */ - constexpr explicit Kernel(const char* name, OpFunction func) - : name_(name), op_(func) {} + explicit Kernel(const char* name, OpFunction func) : name_(name), op_(func) {} - constexpr explicit Kernel(const char* name, KernelKey key, OpFunction func) + explicit Kernel(const char* name, KernelKey key, OpFunction func) : name_(name), kernel_key_(key), op_(func) {} - constexpr Kernel() : name_(nullptr), op_(nullptr) {} + Kernel() {} }; namespace internal { @@ -233,15 +232,6 @@ ::executorch::runtime::Result get_op_function_from_registry( const char* name, Span meta_list = {}); -/** - * Returns the operator with a given name and TensorMeta list from the provided - * kernel list instead of the global registry. - */ -::executorch::runtime::Result get_op_function_from_registry( - const char* name, - Span meta_list, - Span kernel_list); - /** * Returns all registered kernels. */ diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/targets.bzl new file mode 100644 index 0000000..123dc1a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/targets.bzl @@ -0,0 +1,97 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") + +def _operator_registry_preprocessor_flags(): + max_kernel_num = native.read_config("executorch", "max_kernel_num", None) + if max_kernel_num != None: + return select({ + "DEFAULT": ["-DMAX_KERNEL_NUM=" + max_kernel_num], + "ovr_config//build_mode/constraints:arvr_is_host_platform": [] + }) + elif not runtime.is_oss: + return select({ + "DEFAULT": [], + "fbsource//xplat/executorch/tools/buck/constraints:executorch-max-kernel-num-256": ["-DMAX_KERNEL_NUM=256"], + "fbsource//xplat/executorch/tools/buck/constraints:executorch-max-kernel-num-128": ["-DMAX_KERNEL_NUM=128"], + "fbsource//xplat/executorch/tools/buck/constraints:executorch-max-kernel-num-64": ["-DMAX_KERNEL_NUM=64"], + }) + else: + return [] + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_library( + name = "operator_registry_MAX_NUM_KERNELS_TEST_ONLY", + srcs = ["operator_registry.cpp"], + exported_headers = ["operator_registry.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:evalue", + ], + preprocessor_flags = ["-DMAX_KERNEL_NUM=1"], + ) + + runtime.cxx_library( + name = "thread_parallel_interface", + exported_headers = ["thread_parallel_interface.h"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core/portable_type/c10/c10:c10", + "//executorch/runtime/platform:platform", + ], + # Don't depend on this target, depend on //executorch/extension/threadpool:threadpool. + visibility = [ + "//executorch/extension/threadpool/...", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_library( + name = "operator_registry" + aten_suffix, + srcs = ["operator_registry.cpp"], + exported_headers = ["operator_registry.h"], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/core:evalue" + aten_suffix, + ], + preprocessor_flags = _operator_registry_preprocessor_flags(), + ) + + runtime.cxx_library( + name = "kernel_runtime_context" + aten_suffix, + exported_headers = [ + "kernel_runtime_context.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + "//executorch/runtime/core:memory_allocator", + "//executorch/runtime/core:event_tracer" + aten_suffix, + # TODO(T147221312): This will eventually depend on exec_aten + # once KernelRuntimeContext support tensor resizing, which is + # why this target supports aten mode. + ], + ) + + runtime.cxx_library( + name = "kernel_includes" + aten_suffix, + exported_headers = [ + "kernel_includes.h", + ], + visibility = ["PUBLIC"], + exported_deps = [ + ":kernel_runtime_context" + aten_suffix, + "//executorch/runtime/core/exec_aten:lib" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix, + "//executorch/runtime/core/exec_aten/util:tensor_util" + aten_suffix, + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/CMakeLists.txt new file mode 100644 index 0000000..a816601 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +add_executable(operator_registry_test operator_registry_test.cpp) +target_link_libraries( + operator_registry_test GTest::gtest GTest::gtest_main GTest::gmock + executorch_core +) +target_include_directories(operator_registry_test PRIVATE ${EXECUTORCH_ROOT}/..) +add_test(operator_registry_test operator_registry_test) + +add_executable(kernel_runtime_context_test kernel_runtime_context_test.cpp) +target_link_libraries( + kernel_runtime_context_test GTest::gtest GTest::gtest_main GTest::gmock + executorch_core +) +target_include_directories( + kernel_runtime_context_test PRIVATE ${EXECUTORCH_ROOT}/.. +) +add_test(kernel_runtime_context_test kernel_runtime_context_test) + +add_executable( + operator_registry_max_kernel_num_test + operator_registry_max_kernel_num_test.cpp +) +target_link_libraries( + operator_registry_max_kernel_num_test GTest::gtest GTest::gtest_main + GTest::gmock executorch_core +) +target_compile_definitions( + operator_registry_max_kernel_num_test PRIVATE "-DMAX_KERNEL_NUM=1" +) +# TODO: This is currently not working! +# add_test(operator_registry_max_kernel_num_test +# operator_registry_max_kernel_num_test) + +# TODO: Migrate kernel_double_registration_test and +# test_kernel_manual_registration. Make sure dtype selective build is working. diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/functions.yaml b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/functions.yaml new file mode 100644 index 0000000..81f0e5f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/functions.yaml @@ -0,0 +1,13 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. + +- func: add.out(Tensor self, Tensor other, *, Scalar alpha=1, Tensor(a!) out) -> Tensor(a!) + type_alias: + T0: [Double] + dim_order_alias: + D0: [0, 1, 2, 3] + kernels: + - arg_meta: + self: [T0, D0] + other: [T0 , D0] + out: [T0, D0] + kernel_name: torch::executor::add_out diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_double_registration_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_double_registration_test.cpp new file mode 100644 index 0000000..11026fd --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_double_registration_test.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +using namespace ::testing; + +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Kernel; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::register_kernels; +using executorch::runtime::Span; + +class KernelDoubleRegistrationTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(KernelDoubleRegistrationTest, Basic) { + Kernel kernels[] = {Kernel( + "aten::add.out", + "v1/7;0,1,2,3|7;0,1,2,3|7;0,1,2,3", + [](KernelRuntimeContext&, Span) {})}; + Error err = Error::RegistrationAlreadyRegistered; + + ET_EXPECT_DEATH( + { (void)register_kernels({kernels}); }, + std::to_string(static_cast(err))); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_runtime_context_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_runtime_context_test.cpp new file mode 100644 index 0000000..2c3b536 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/kernel_runtime_context_test.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include + +using namespace ::testing; +using executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext; +using executorch::runtime::Error; +using executorch::runtime::MemoryAllocator; +using executorch::runtime::Result; + +class KernelRuntimeContextTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +class TestMemoryAllocator : public MemoryAllocator { + public: + TestMemoryAllocator(uint32_t size, uint8_t* base_address) + : MemoryAllocator(size, base_address), last_seen_alignment(0) {} + void* allocate(size_t size, size_t alignment) override { + last_seen_alignment = alignment; + return MemoryAllocator::allocate(size, alignment); + } + size_t last_seen_alignment; +}; + +TEST_F(KernelRuntimeContextTest, FailureStateDefaultsToOk) { + KernelRuntimeContext context; + + EXPECT_EQ(context.failure_state(), Error::Ok); +} + +TEST_F(KernelRuntimeContextTest, FailureStateReflectsFailure) { + KernelRuntimeContext context; + + // Starts off Ok. + EXPECT_EQ(context.failure_state(), Error::Ok); + + // Failing should update the failure state. + context.fail(Error::MemoryAllocationFailed); + EXPECT_EQ(context.failure_state(), Error::MemoryAllocationFailed); + + // State can be overwritten. + context.fail(Error::Internal); + EXPECT_EQ(context.failure_state(), Error::Internal); + + // And can be cleared. + context.fail(Error::Ok); + EXPECT_EQ(context.failure_state(), Error::Ok); +} + +TEST_F(KernelRuntimeContextTest, FailureNoMemoryAllocatorProvided) { + KernelRuntimeContext context; + Result allocated_memory = context.allocate_temp(4); + EXPECT_EQ(allocated_memory.error(), Error::NotFound); +} + +TEST_F(KernelRuntimeContextTest, SuccessfulMemoryAllocation) { + constexpr size_t temp_memory_allocator_pool_size = 4; + auto temp_memory_allocator_pool = + std::make_unique(temp_memory_allocator_pool_size); + MemoryAllocator temp_allocator( + temp_memory_allocator_pool_size, temp_memory_allocator_pool.get()); + KernelRuntimeContext context(nullptr, &temp_allocator); + Result allocated_memory = context.allocate_temp(4); + EXPECT_EQ(allocated_memory.ok(), true); +} + +TEST_F(KernelRuntimeContextTest, FailureMemoryAllocationInsufficientSpace) { + constexpr size_t temp_memory_allocator_pool_size = 4; + auto temp_memory_allocator_pool = + std::make_unique(temp_memory_allocator_pool_size); + MemoryAllocator temp_allocator( + temp_memory_allocator_pool_size, temp_memory_allocator_pool.get()); + KernelRuntimeContext context(nullptr, &temp_allocator); + Result allocated_memory = context.allocate_temp(8); + EXPECT_EQ(allocated_memory.error(), Error::MemoryAllocationFailed); +} + +TEST_F(KernelRuntimeContextTest, MemoryAllocatorAlignmentPassed) { + constexpr size_t temp_memory_allocator_pool_size = 4; + auto temp_memory_allocator_pool = + std::make_unique(temp_memory_allocator_pool_size); + TestMemoryAllocator temp_allocator( + temp_memory_allocator_pool_size, temp_memory_allocator_pool.get()); + KernelRuntimeContext context(nullptr, &temp_allocator); + Result allocated_memory = context.allocate_temp(4, 2); + EXPECT_EQ(allocated_memory.ok(), true); + EXPECT_EQ(temp_allocator.last_seen_alignment, 2); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp new file mode 100644 index 0000000..627638d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_max_kernel_num_test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::runtime::ArrayRef; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::Kernel; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::register_kernels; +using executorch::runtime::registry_has_op_function; +using executorch::runtime::Span; + +class OperatorRegistryMaxKernelNumTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +// Register one kernel when max_kernel_num=1; success +TEST_F(OperatorRegistryMaxKernelNumTest, RegisterOneOp) { + Kernel kernels[] = { + Kernel("foo", [](KernelRuntimeContext&, Span) {})}; + auto s1 = register_kernels({kernels}); + EXPECT_EQ(s1, Error::Ok); + EXPECT_FALSE(registry_has_op_function("fpp")); + EXPECT_TRUE(registry_has_op_function("foo")); +} + +// Register two kernels when max_kernel_num=1; fail +TEST_F(OperatorRegistryMaxKernelNumTest, RegisterTwoOpsFail) { + Kernel kernels[] = { + Kernel("foo1", [](KernelRuntimeContext&, Span) {}), + Kernel("foo2", [](KernelRuntimeContext&, Span) {})}; + ET_EXPECT_DEATH( + { (void)register_kernels({kernels}); }, + "The total number of kernels to be registered is larger than the limit 1"); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_test.cpp new file mode 100644 index 0000000..b06633d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/operator_registry_test.cpp @@ -0,0 +1,517 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::Scalar; +using executorch::aten::ScalarType; +using executorch::aten::Tensor; +using executorch::runtime::Error; +using executorch::runtime::EValue; +using executorch::runtime::get_op_function_from_registry; +using executorch::runtime::Kernel; +using executorch::runtime::KernelKey; +using executorch::runtime::KernelRuntimeContext; +using executorch::runtime::OpFunction; +using executorch::runtime::register_kernels; +using executorch::runtime::registry_has_op_function; +using executorch::runtime::Result; +using executorch::runtime::Span; +using executorch::runtime::TensorMeta; +using executorch::runtime::internal::kKernelKeyBufSize; +using executorch::runtime::testing::make_kernel_key; + +// +// Tests for make_kernel_key_string +// + +// Helper for testing make_kernel_key_string. +void test_make_kernel_key_string( + const std::vector>>& tensors, + const char* expected_key) { + const size_t min_buf_size = strlen(expected_key) + 1; + + // Sweep across too-small buffer sizes, exercising all possible failure + // checks. Rely on ASAN to detect buffer overflows. + for (size_t buf_size = 0; buf_size < min_buf_size; buf_size++) { + std::vector actual_key(buf_size, 0x55); + Error err = make_kernel_key( + tensors, + // nullptr should be valid for buf_size == 0 because it won't be written + // to. + buf_size == 0 ? nullptr : actual_key.data(), + actual_key.size()); + EXPECT_NE(err, Error::Ok); + } + + // Demonstrate that it succeeds for buffers of exactly the right size or + // larger. + for (size_t buf_size = min_buf_size; buf_size < min_buf_size + 1; + buf_size++) { + std::vector actual_key(buf_size, 0x55); + Error err = make_kernel_key(tensors, actual_key.data(), actual_key.size()); + ASSERT_EQ(err, Error::Ok); + EXPECT_STREQ(actual_key.data(), expected_key); + } +} + +TEST(MakeKernelKeyStringTest, ZeroTensorSuccessWithNullBuffer) { + Error err = make_kernel_key({}, nullptr, 0); + EXPECT_EQ(err, Error::Ok); +} + +TEST(MakeKernelKeyStringTest, ZeroTensorSuccessMakesEmptyString) { + char buf = 0x55; + Error err = make_kernel_key({}, &buf, 1); + EXPECT_EQ(err, Error::Ok); + EXPECT_EQ(buf, '\0'); +} + +TEST(MakeKernelKeyStringTest, OneTensorSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 1, 2, 3}}}, "v1/4;0,1,2,3"); +} + +TEST(MakeKernelKeyStringTest, TwoTensorSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 1, 2, 3}}, {ScalarType::Double, {3, 2, 1, 0}}}, + "v1/4;0,1,2,3|7;3,2,1,0"); +} + +TEST(MakeKernelKeyStringTest, ThreeTensorSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 1, 2, 3}}, + {ScalarType::Double, {3, 2, 1, 0}}, + {ScalarType::Byte, {2, 1, 3, 0}}}, + "v1/4;0,1,2,3|7;3,2,1,0|0;2,1,3,0"); +} + +TEST(MakeKernelKeyStringTest, TwoDigitDimOrderSuccess) { + test_make_kernel_key_string( + {{ScalarType::Long, {0, 10, 2, 99}}}, "v1/4;0,10,2,99"); +} + +TEST(MakeKernelKeyStringTest, ThreeDigitDimOrderFailure) { + std::vector actual_key(1024, 0x55); // Large enough for any key. + Error err = make_kernel_key( + // Cannot represent a dim order entry with more than two digits. + {{ScalarType::Long, {0, 100, 2, 255}}}, + actual_key.data(), + actual_key.size()); + EXPECT_NE(err, Error::Ok); +} + +TEST(MakeKernelKeyStringTest, NegativeScalarTypeFailure) { + std::vector actual_key(1024, 0x55); // Large enough for any key. + Error err = make_kernel_key( + // Cannot represent a ScalarType (aka int8_t) with a negative value. + {{(ScalarType)-1, {0, 1, 2, 3}}}, + actual_key.data(), + actual_key.size()); + EXPECT_NE(err, Error::Ok); +} + +TEST(MakeKernelKeyStringTest, KeyBufSizeMeetsAssumptions) { + // Create the longest key that fits in the assupmtions of kKernelKeyBufSize: + // 16 tensors, 16 dims, with two-digit ScalarTypes. + std::vector>> + tensors; + tensors.reserve(16); + for (int i = 0; i < 16; i++) { + std::vector dims; + dims.reserve(16); + for (int j = 0; j < 16; j++) { + dims.emplace_back(j); + } + tensors.emplace_back((ScalarType)10, dims); + } + + std::vector actual_key(kKernelKeyBufSize, 0x55); + Error err = make_kernel_key(tensors, actual_key.data(), actual_key.size()); + ASSERT_EQ(err, Error::Ok); + EXPECT_STREQ( + actual_key.data(), + "v1/" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15|" + "10;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"); + EXPECT_LE(strlen(actual_key.data()) + 1, kKernelKeyBufSize); +} + +// +// Tests for public operator registry APIs +// + +class OperatorRegistryTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(OperatorRegistryTest, Basic) { + Kernel kernels[] = { + Kernel("foo", [](KernelRuntimeContext&, Span) {})}; + Span kernels_span(kernels); + Error err = register_kernels(kernels_span); + ASSERT_EQ(err, Error::Ok); + EXPECT_FALSE(registry_has_op_function("fpp")); + EXPECT_TRUE(registry_has_op_function("foo")); +} + +TEST_F(OperatorRegistryTest, RegisterOpsMoreThanOnceDie) { + Kernel kernels[] = { + Kernel("foo", [](KernelRuntimeContext&, Span) {}), + Kernel("foo", [](KernelRuntimeContext&, Span) {})}; + Span kernels_span = Span(kernels); + ET_EXPECT_DEATH({ (void)register_kernels(kernels_span); }, ""); +} + +TEST_F(OperatorRegistryTest, KernelKeyEquals) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey long_contiguous = KernelKey(buf_long_contiguous.data()); + + KernelKey long_key_1 = KernelKey(long_contiguous); + + KernelKey long_key_2 = KernelKey(long_contiguous); + + EXPECT_EQ(long_key_1, long_key_2); + + std::array buf_float_contiguous; + err = make_kernel_key( + {{ScalarType::Float, {0, 1, 2, 3}}}, + buf_float_contiguous.data(), + buf_float_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey float_key = KernelKey(buf_float_contiguous.data()); + + EXPECT_NE(long_key_1, float_key); + + std::array buf_channel_first; + err = make_kernel_key( + {{ScalarType::Long, {0, 3, 1, 2}}}, + buf_channel_first.data(), + buf_channel_first.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey long_key_3 = KernelKey(buf_channel_first.data()); + + EXPECT_NE(long_key_1, long_key_3); +} + +TEST_F(OperatorRegistryTest, GetOpFailsForLongKernelKey) { + // Looking up a way-too-long kernel key should fail with an error. + std::vector>> + tensors; + // 1000 is a lot of tensors. + tensors.reserve(1000); + for (int i = 0; i < 1000; i++) { + std::vector dims; + dims.reserve(16); + for (int j = 0; j < 16; j++) { + dims.emplace_back(j); + } + tensors.emplace_back((ScalarType)10, dims); + } + std::vector meta; + for (auto& t : tensors) { + Span dim_order( + t.second.data(), t.second.size()); + meta.emplace_back(t.first, dim_order); + } + Span metadata(meta.data(), meta.size()); + + auto op = get_op_function_from_registry("test::not-real", metadata); + EXPECT_NE(op.error(), Error::Ok); + EXPECT_NE(op.error(), Error::OperatorMissing); + // The lookup failed, but not because the operator is missing. +} + +TEST_F(OperatorRegistryTest, RegisterKernels) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::boo", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + err = register_kernels({&kernel_1, 1}); + ASSERT_EQ(err, Error::Ok); + + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key(meta); + + // no fallback kernel is registered + EXPECT_FALSE(registry_has_op_function("test::boo", {})); + Result fallback_func = + get_op_function_from_registry("test::boo", {}); + EXPECT_NE(fallback_func.error(), Error::Ok); + + EXPECT_TRUE(registry_has_op_function("test::boo", user_kernel_key)); + Result func = + get_op_function_from_registry("test::boo", user_kernel_key); + EXPECT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} + +TEST_F(OperatorRegistryTest, RegisterTwoKernels) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key_1 = KernelKey(buf_long_contiguous.data()); + + std::array buf_float_contiguous; + err = make_kernel_key( + {{ScalarType::Float, {0, 1, 2, 3}}}, + buf_float_contiguous.data(), + buf_float_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key_2 = KernelKey(buf_float_contiguous.data()); + Kernel kernel_1 = Kernel( + "test::bar", + key_1, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + Kernel kernel_2 = Kernel( + "test::bar", + key_2, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(50); + }); + Kernel kernels[] = {kernel_1, kernel_2}; + err = register_kernels(kernels); + ASSERT_EQ(err, Error::Ok); + + // has both kernels + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key_1(meta); + + TensorMeta meta_2[] = {TensorMeta(ScalarType::Float, dim_order_type)}; + Span user_kernel_key_2(meta_2); + + // no fallback kernel is registered + EXPECT_FALSE(registry_has_op_function("test::bar", {})); + Result fallback_func = + get_op_function_from_registry("test::bar", {}); + EXPECT_NE(fallback_func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* evalues[1]; + evalues[0] = &values[0]; + KernelRuntimeContext context{}; + + // test kernel_1 + EXPECT_TRUE(registry_has_op_function("test::bar", user_kernel_key_1)); + Result func_1 = + get_op_function_from_registry("test::bar", user_kernel_key_1); + EXPECT_EQ(func_1.error(), Error::Ok); + (*func_1)(context, Span(evalues)); + + auto val_1 = values[0].toScalar().to(); + ASSERT_EQ(val_1, 100); + + // test kernel_2 + EXPECT_TRUE(registry_has_op_function("test::bar", user_kernel_key_2)); + Result func_2 = + get_op_function_from_registry("test::bar", user_kernel_key_2); + EXPECT_EQ(func_2.error(), Error::Ok); + values[0] = Scalar(0); + (*func_2)(context, Span(evalues)); + + auto val_2 = values[0].toScalar().to(); + ASSERT_EQ(val_2, 50); +} + +TEST_F(OperatorRegistryTest, DoubleRegisterKernelsDies) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::baz", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + Kernel kernel_2 = Kernel( + "test::baz", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(50); + }); + Kernel kernels[] = {kernel_1, kernel_2}; + // clang-tidy off + ET_EXPECT_DEATH({ (void)register_kernels(kernels); }, ""); + // clang-tidy on +} + +TEST_F(OperatorRegistryTest, ExecutorChecksKernel) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::qux", key, [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + err = register_kernels({&kernel_1, 1}); + ASSERT_EQ(err, Error::Ok); + + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key_1(meta); + EXPECT_TRUE(registry_has_op_function("test::qux", user_kernel_key_1)); + + Tensor::DimOrderType dims_channel_first[] = {0, 3, 1, 2}; + auto dim_order_type_channel_first = + Span(dims_channel_first, 4); + TensorMeta meta_channel_first[] = { + TensorMeta(ScalarType::Long, dim_order_type_channel_first)}; + Span user_kernel_key_2(meta_channel_first); + EXPECT_FALSE(registry_has_op_function("test::qux", user_kernel_key_2)); + + TensorMeta meta_float[] = {TensorMeta(ScalarType::Float, dim_order_type)}; + Span user_kernel_key_3(meta_float); + EXPECT_FALSE(registry_has_op_function("test::qux", user_kernel_key_3)); +} + +TEST_F(OperatorRegistryTest, ExecutorUsesKernel) { + std::array buf_long_contiguous; + Error err = make_kernel_key( + {{ScalarType::Long, {0, 1, 2, 3}}}, + buf_long_contiguous.data(), + buf_long_contiguous.size()); + ASSERT_EQ(err, Error::Ok); + KernelKey key = KernelKey(buf_long_contiguous.data()); + + Kernel kernel_1 = Kernel( + "test::quux", + key, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + err = register_kernels({&kernel_1, 1}); + ASSERT_EQ(err, Error::Ok); + + Tensor::DimOrderType dims[] = {0, 1, 2, 3}; + auto dim_order_type = Span(dims, 4); + TensorMeta meta[] = {TensorMeta(ScalarType::Long, dim_order_type)}; + Span user_kernel_key_1(meta); + + EXPECT_TRUE(registry_has_op_function("test::quux", user_kernel_key_1)); + Result func = + get_op_function_from_registry("test::quux", user_kernel_key_1); + EXPECT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} + +TEST_F(OperatorRegistryTest, ExecutorUsesFallbackKernel) { + Kernel kernel_1 = Kernel( + "test::corge", + KernelKey{}, + [](KernelRuntimeContext& context, Span stack) { + (void)context; + *(stack[0]) = Scalar(100); + }); + Error err = register_kernels({&kernel_1, 1}); + EXPECT_EQ(err, Error::Ok); + + EXPECT_TRUE(registry_has_op_function("test::corge")); + EXPECT_TRUE(registry_has_op_function("test::corge", {})); + + Result func = get_op_function_from_registry("test::corge", {}); + EXPECT_EQ(func.error(), Error::Ok); + + EValue values[1]; + values[0] = Scalar(0); + EValue* kernels[1]; + kernels[0] = &values[0]; + KernelRuntimeContext context{}; + (*func)(context, Span(kernels)); + + auto val = values[0].toScalar().to(); + ASSERT_EQ(val, 100); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/targets.bzl new file mode 100644 index 0000000..4b3ed0f --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/targets.bzl @@ -0,0 +1,116 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "get_aten_mode_options", "runtime") +load("@fbsource//xplat/executorch/codegen:codegen.bzl", "et_operator_library", "executorch_generated_lib") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "operator_registry_test", + srcs = [ + "operator_registry_test.cpp", + ], + headers = ["test_util.h"], + deps = [ + "//executorch/runtime/kernel:operator_registry", + "//executorch/runtime/kernel:kernel_runtime_context", + ], + ) + + runtime.cxx_test( + name = "operator_registry_max_kernel_num_test", + srcs = [ + "operator_registry_max_kernel_num_test.cpp", + ], + deps = [ + "//executorch/runtime/kernel:operator_registry_MAX_NUM_KERNELS_TEST_ONLY", + "//executorch/runtime/kernel:kernel_runtime_context", + ], + ) + + et_operator_library( + name = "executorch_all_ops", + include_all_operators = True, + define_static_targets = True, + ) + + runtime.export_file( + name = "functions.yaml", + ) + + executorch_generated_lib( + name = "specialized_kernel_generated_lib", + deps = [ + ":executorch_all_ops", + "//executorch/kernels/portable:operators", + ], + functions_yaml_target = ":functions.yaml", + visibility = [ + "//executorch/...", + ], + ) + + runtime.cxx_test( + name = "kernel_double_registration_test", + srcs = [ + "kernel_double_registration_test.cpp", + ], + deps = [ + "//executorch/runtime/kernel:operator_registry", + ":specialized_kernel_generated_lib", + ], + ) + + executorch_generated_lib( + name = "test_manual_registration_lib", + deps = [ + ":executorch_all_ops", + "//executorch/kernels/portable:operators", + ], + functions_yaml_target = "//executorch/kernels/portable:functions.yaml", + manual_registration = True, + visibility = [ + "//executorch/...", + ], + ) + + runtime.cxx_test( + name = "test_kernel_manual_registration", + srcs = [ + "test_kernel_manual_registration.cpp", + ], + deps = [ + "//executorch/runtime/kernel:operator_registry", + ":test_manual_registration_lib", + ], + ) + + for aten_mode in get_aten_mode_options(): + aten_suffix = "_aten" if aten_mode else "" + + runtime.cxx_test( + name = "kernel_runtime_context_test" + aten_suffix, + srcs = [ + "kernel_runtime_context_test.cpp", + ], + deps = [ + "//executorch/runtime/kernel:kernel_runtime_context" + aten_suffix, + ":specialized_kernel_generated_lib", + ], + ) + + if aten_mode: + # Make sure we can depend on both generated_lib and generated_lib_aten + # in the same binary. + runtime.cxx_test( + name = "test_generated_lib_and_aten", + srcs = ["test_generated_lib_and_aten.cpp"], + deps = [ + "//executorch/kernels/portable:generated_lib", + "//executorch/kernels/portable:generated_lib_aten", + "//executorch/runtime/kernel:operator_registry_aten", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_generated_lib_and_aten.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_generated_lib_and_aten.cpp new file mode 100644 index 0000000..f9bfebc --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_generated_lib_and_aten.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::testing; +using executorch::aten::ScalarType; +using executorch::runtime::Error; +using executorch::runtime::EValue; + +class GeneratedLibAndAtenTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(GeneratedLibAndAtenTest, GetKernelsFromATenRegistry) { + // Check if the kernel exists in the ATen registry + bool has_kernel = + executorch::runtime::aten::registry_has_op_function("aten::add.out"); + EXPECT_TRUE(has_kernel) + << "Kernel 'aten::add.out' not found in ATen registry"; + + // Get the kernel from the ATen registry + auto result = + executorch::runtime::aten::get_op_function_from_registry("aten::add.out"); + EXPECT_EQ(result.error(), Error::Ok) + << "Failed to get kernel from ATen registry"; + EXPECT_NE(*result, nullptr) << "Kernel function from ATen registry is null"; +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_kernel_manual_registration.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_kernel_manual_registration.cpp new file mode 100644 index 0000000..de8853c --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_kernel_manual_registration.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include +#include + +using namespace ::testing; +using executorch::runtime::Error; +using executorch::runtime::registry_has_op_function; + +class KernelManualRegistrationTest : public ::testing::Test { + public: + void SetUp() override { + executorch::runtime::runtime_init(); + } +}; + +TEST_F(KernelManualRegistrationTest, ManualRegister) { + // Before registering, we can't find the add operator. + EXPECT_FALSE(registry_has_op_function("aten::add.out")); + + // Call the generated registration function. + Error result = torch::executor::register_all_kernels(); + EXPECT_EQ(result, Error::Ok); + + // We can now find the registered add operator. + EXPECT_TRUE(registry_has_op_function("aten::add.out")); + + // We can't find a random other operator. + EXPECT_FALSE(registry_has_op_function("fpp")); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_util.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_util.h new file mode 100644 index 0000000..be77df1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/test/test_util.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include + +namespace executorch { +namespace runtime { + +namespace testing { + +inline Error make_kernel_key( + const std::vector>>& tensors, + char* buf, + size_t buf_size) { + std::vector meta; + for (auto& t : tensors) { + Span dim_order( + const_cast(t.second.data()), t.second.size()); + meta.emplace_back(t.first, dim_order); + } + Span metadata(meta.data(), meta.size()); + return internal::make_kernel_key_string(metadata, buf, buf_size); +} + +} // namespace testing + +} // namespace runtime +} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/thread_parallel_interface.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/thread_parallel_interface.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/kernel/thread_parallel_interface.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/kernel/thread_parallel_interface.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/abort.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/abort.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/abort.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/abort.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/abort.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/abort.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/abort.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/abort.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/assert.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/assert.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/assert.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/assert.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/clock.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/clock.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/clock.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/clock.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/compat_unistd.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/compat_unistd.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/compat_unistd.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/compat_unistd.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/compiler.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/compiler.h similarity index 99% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/compiler.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/compiler.h index edd340d..ab2f45f 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/compiler.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/compiler.h @@ -179,7 +179,7 @@ #endif // ifndef // Define size_t and ssize_t. -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__ARMCC_VERSION) #include #else #include diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/android.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/android.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/android.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/android.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/minimal.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/minimal.cpp similarity index 53% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/minimal.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/minimal.cpp index 720922c..8236f99 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/platform/default/minimal.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/minimal.cpp @@ -10,32 +10,23 @@ * @file * Fallback PAL implementations that do not depend on any assumptions about * capabililties of the system. - * - * Each et_pal_* fallback is marked ET_WEAK directly on its definition, - * not just on the declaration in platform.h. The weak attribute is a - * property of a specific symbol *definition* in the ELF symbol table — - * it is not transitively inherited from a forward declaration. GCC - * 13/14/15 and armclang 6.24 follow that rule: a definition without an - * explicit weak attribute emits a STB_GLOBAL (strong) symbol, even if - * the matching declaration was weak. (Older GCCs were laxer about this; - * the current behaviour is the standards-aligned one.) Without the - * direct ET_WEAK on each definition, a downstream consumer that - * supplies its own et_pal_* override hits a multi-def link error - * against this fallback. */ +// This cpp file will provide weak implementations of the symbols declared in +// Platform.h. Client users can strongly define any or all of the functions to +// override them. #define ET_INTERNAL_PLATFORM_WEAKNESS ET_WEAK #include #include -ET_WEAK void et_pal_init(void) {} +void et_pal_init(void) {} -ET_WEAK ET_NORETURN void et_pal_abort(void) { +ET_NORETURN void et_pal_abort(void) { __builtin_trap(); } -ET_WEAK et_timestamp_t et_pal_current_ticks(void) { +et_timestamp_t et_pal_current_ticks(void) { // This file cannot make any assumptions about the presence of functions that // return the current time, so all users should provide a strong override for // it. To help make it more obvious when this weak version is being used, @@ -43,12 +34,12 @@ ET_WEAK et_timestamp_t et_pal_current_ticks(void) { return 11223344; } -ET_WEAK et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) { +et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) { // Since we don't define a tick rate, return a conversion ratio of 1. return {1, 1}; } -ET_WEAK void et_pal_emit_log_message( +void et_pal_emit_log_message( ET_UNUSED et_timestamp_t timestamp, ET_UNUSED et_pal_log_level_t level, ET_UNUSED const char* filename, @@ -57,8 +48,8 @@ ET_WEAK void et_pal_emit_log_message( ET_UNUSED const char* message, ET_UNUSED size_t length) {} -ET_WEAK void* et_pal_allocate(ET_UNUSED size_t size) { +void* et_pal_allocate(ET_UNUSED size_t size) { return nullptr; } -ET_WEAK void et_pal_free(ET_UNUSED void* ptr) {} +void et_pal_free(ET_UNUSED void* ptr) {} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/posix.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/posix.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/posix.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/posix.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/zephyr.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/zephyr.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/default/zephyr.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/default/zephyr.cpp diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.bzl new file mode 100644 index 0000000..04a3de1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.bzl @@ -0,0 +1,22 @@ +def et_logging_enabled(): + return native.read_config("executorch", "enable_et_log", "true") == "true" + +def et_log_level(): + raw_level = native.read_config("executorch", "log_level", "Info").lower() + if raw_level == "debug": + return "Debug" + elif raw_level == "info": + return "Info" + elif raw_level == "error": + return "Error" + elif raw_level == "fatal": + return "Fatal" + else: + fail("Unknown log level '{}'. Expected one of 'Debug', 'Info', 'Error', or 'Fatal'.".format(raw_level)) + +def get_et_logging_flags(): + if et_logging_enabled(): + # On by default. + return ["-DET_MIN_LOG_LEVEL=" + et_log_level()] + else: + return ["-DET_LOG_ENABLED=0"] diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/log.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/log.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/log.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/log.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/log.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/platform.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/platform.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/platform.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/platform.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/platform.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/platform.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/platform.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/platform.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/profiler.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/profiler.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/profiler.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/profiler.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/profiler.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/profiler.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/profiler.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/profiler.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/runtime.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/runtime.cpp similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/runtime.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/runtime.cpp diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/runtime.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/runtime.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/runtime.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/runtime.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/system.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/system.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/system.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/system.h diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/targets.bzl new file mode 100644 index 0000000..65d92b1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/targets.bzl @@ -0,0 +1,120 @@ +load("@fbsource//xplat/executorch/build:build_variables.bzl", "PLATFORM_SRCS") +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") +load(":log.bzl", "get_et_logging_flags") + +def _select_pal(dict_): + """Returns an element of `dict_` based on the value of the + `executorch.pal_default` build config value. Fails if no corresponding entry + exists. + """ + pal_default = native.read_config("executorch", "pal_default", "posix") + if not pal_default in dict_: + fail("Missing key for executorch.pal_default value '{}' in dict '{}'".format(pal_default, dict_)) + return dict_[pal_default] + +def profiling_enabled(): + return native.read_config("executorch", "prof_enabled", "false") == "true" + +def get_profiling_flags(): + profiling_flags = [] + if profiling_enabled(): + profiling_flags += ["-DPROFILING_ENABLED"] + prof_buf_size = native.read_config("executorch", "prof_buf_size", None) + if prof_buf_size != None: + if not profiling_enabled(): + fail("Cannot set profiling buffer size without enabling profiling first.") + profiling_flags += ["-DMAX_PROFILE_EVENTS={}".format(prof_buf_size), "-DMAX_MEM_PROFILE_EVENTS={}".format(prof_buf_size)] + num_prof_blocks = native.read_config("executorch", "num_prof_blocks", None) + if num_prof_blocks != None: + if not profiling_enabled(): + fail("Cannot configure number of profiling blocks without enabling profiling first.") + profiling_flags += ["-DMAX_PROFILE_BLOCKS={}".format(num_prof_blocks)] + return profiling_flags + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + # Default implementations of pal functions. These are weak symbols, so + # client defined implementations will overide them. + runtime.cxx_library( + name = "platform_private", + srcs = select({ + "ovr_config//os:android": ["default/android.cpp"], + "DEFAULT": _select_pal({ + "minimal": ["default/minimal.cpp"], + "posix": ["default/posix.cpp"], + })}), + deps = [ + ":pal_interface", + ], + external_deps = ["log"], + visibility = [ + "//executorch/core/...", + ], + # WARNING: using a deprecated API to avoid being built into a shared + # library. In the case of dynamically loading .so library we don't want + # it to depend on other .so libraries because that way we have to + # specify library directory path. + force_static = True, + ) + + # Interfaces for executorch users + runtime.cxx_library( + name = "platform", + exported_headers = [ + "abort.h", + "assert.h", + "clock.h", + "log.h", + "profiler.h", + "runtime.h", + "compat_unistd.h", + ], + srcs = PLATFORM_SRCS, + exported_preprocessor_flags = get_profiling_flags() + get_et_logging_flags(), + exported_deps = [ + "//executorch/runtime/platform:pal_interface", + ":compiler", + ":platform_private", + ], + visibility = ["PUBLIC"], + # WARNING: using a deprecated API to avoid being built into a shared + # library. In the case of dynamically loading so library we don't want + # it to depend on other so libraries because that way we have to + # specify library directory path. + force_static = True, + ) + + # Library for backend implementers to define implementations against. + runtime.cxx_library( + name = "pal_interface", + exported_headers = [ + "platform.h", + "system.h", + "types.h", + ], + exported_deps = [ + ":compiler", + ], + exported_preprocessor_flags = select( + { + "DEFAULT": [], + "ovr_config//os:linux": ["-DET_USE_LIBDL"], + "ovr_config//os:macos": ["-DET_USE_LIBDL"], + }, + ), + visibility = ["PUBLIC"], + ) + + # Common compiler directives such as 'unlikely' or 'deprecated' + runtime.cxx_library( + name = "compiler", + exported_headers = [ + "compiler.h", + ], + visibility = ["PUBLIC"], + ) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/BUCK b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/BUCK new file mode 100644 index 0000000..1e8cc17 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/BUCK @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain xplat-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/CMakeLists.txt b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/CMakeLists.txt new file mode 100644 index 0000000..dd480ee --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# This file should be formatted with +# ~~~ +# cmake-format -i CMakeLists.txt +# ~~~ +# It should also be cmake-lint clean. +# + +cmake_minimum_required(VERSION 3.19) + +set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${EXECUTORCH_ROOT}/tools/cmake/Test.cmake) + +et_cxx_test(platform_test SOURCES executor_pal_test.cpp) + +et_cxx_test( + platform_runtime_override_test SOURCES executor_pal_runtime_override_test.cpp + stub_platform.cpp +) + +et_cxx_test( + platform_static_runtime_override_test SOURCES + executor_pal_static_runtime_override_test.cpp +) + +# TODO: Re-enable this test on OSS +# +# et_cxx_test(platform_death_test SOURCES executor_pal_death_test.cpp) + +# No weak function symbols on Windows/MSVC, thus PAL intercept doesn't work. +# Skip logging tests in Release mode. +if(NOT WIN32 AND NOT CMAKE_BUILD_TYPE STREQUAL "Release") + et_cxx_test(logging_test SOURCES logging_test.cpp stub_platform.cpp) + set_source_files_properties( + logging_test.cpp PROPERTIES COMPILE_DEFINITIONS "ET_MIN_LOG_LEVEL=Debug" + ) +endif() + +# TODO: Re-enable this test on OSS +# +# et_cxx_test(clock_test SOURCES clock_test.cpp stub_platform.cpp) diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/TARGETS b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/TARGETS new file mode 100644 index 0000000..2341af9 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/TARGETS @@ -0,0 +1,8 @@ +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain fbcode-only targets. + +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +define_common_targets() diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/clock_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/clock_test.cpp new file mode 100644 index 0000000..396a4a4 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/clock_test.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +#include + +using namespace ::testing; + +class PalSpy : public PlatformIntercept { + public: + et_tick_ratio_t ticks_to_ns_multiplier() override { + return tick_ns_multiplier; + } + + et_tick_ratio_t tick_ns_multiplier = {1, 1}; +}; + +TEST(ClockTest, ConvertTicksToNsSanity) { + PalSpy spy; + InterceptWith iw(spy); + + spy.tick_ns_multiplier = {3, 2}; + auto ns = executorch::runtime::ticks_to_ns(10); + ASSERT_EQ(15, ns); // 10 ticks * 3/2 = 15 ns + + spy.tick_ns_multiplier = {2, 7}; + ns = executorch::runtime::ticks_to_ns(14); + ASSERT_EQ(4, ns); // 14 ticks * 2/7 = 4 ns +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_death_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_death_test.cpp new file mode 100644 index 0000000..dba38ce --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_death_test.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +TEST(ExecutorPalTest, UninitializedPalDeath) { + // Check for assertion failure on debug builds. + +#ifndef NDEBUG + + ET_EXPECT_DEATH({ et_pal_current_ticks(); }, ""); + + ET_EXPECT_DEATH( + { + et_pal_emit_log_message( + 0, et_pal_log_level_t::kFatal, "", "", 0, "", 0); + }, + ""); + +#endif // !defined(NDEBUG) +} + +/// Override the default weak main declaration. +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + // Purposefully do not initialize the PAL. + return RUN_ALL_TESTS(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_override_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_override_test.cpp new file mode 100644 index 0000000..07cf749 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_override_test.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +#include + +using namespace ::testing; +using executorch::runtime::LogLevel; + +// Demonstrate what would happen if we didn't intercept the PAL calls. +TEST(ExecutorPalOverrideTest, DiesIfNotIntercepted) { + ET_EXPECT_DEATH( + executorch::runtime::runtime_init(), + "et_pal_init call was not intercepted"); +} + +TEST(ExecutorPalOverrideTest, InitIsRegistered) { + PalSpy spy; + InterceptWith iw(spy); + + EXPECT_EQ(spy.init_call_count, 0); + executorch::runtime::runtime_init(); + EXPECT_EQ(spy.init_call_count, 1); +} + +#if ET_LOG_ENABLED +TEST(ExecutorPalOverrideTest, LogSmokeTest) { + PalSpy spy; + InterceptWith iw(spy); + + EXPECT_EQ(spy.current_ticks_call_count, 0); + EXPECT_EQ(spy.emit_log_message_call_count, 0); + + // Use the highest log level, which isn't likely to be disabled. + ASSERT_GE(LogLevel::Fatal, LogLevel::ET_MIN_LOG_LEVEL); + ET_LOG(Fatal, "Test log"); + + EXPECT_EQ(spy.emit_log_message_call_count, 1); + // Logging a message should also cause et_pal_current_ticks to be called once. + EXPECT_EQ(spy.current_ticks_call_count, 1); + + const auto& args = spy.last_log_message_args; + EXPECT_EQ(args.timestamp, PalSpy::kTimestamp); + EXPECT_EQ(args.level, et_pal_log_level_t::kFatal); + // Ignore filename/function/line to avoid fragility. + EXPECT_EQ(args.message, "Test log"); + EXPECT_EQ(args.length, sizeof("Test log") - 1); +} + +TEST(ExecutorPalOverrideTest, LogLevels) { + PalSpy spy; + InterceptWith iw(spy); + const auto& args = spy.last_log_message_args; + + // Test all log levels. Demonstrates the mapping between LogLevel and + // et_pal_log_level_t. + if (LogLevel::Debug >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Debug, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kDebug); + } + + if (LogLevel::Info >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Info, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kInfo); + } + + if (LogLevel::Error >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Error, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kError); + } + + if (LogLevel::Fatal >= LogLevel::ET_MIN_LOG_LEVEL) { + ET_LOG(Fatal, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kFatal); + } + + // An invalid LogLevel should map to kUnknown. + ET_LOG(NumLevels, "Test log"); + EXPECT_EQ(args.level, et_pal_log_level_t::kUnknown); +} + +TEST(ExecutorPalOverrideTest, TickToNsMultiplier) { + PalSpy spy; + InterceptWith iw(spy); + + // Validate that tick to ns multipliers are overridden. + spy.tick_ns_multiplier = {2, 3}; + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().numerator, 2); + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().denominator, 3); + + spy.tick_ns_multiplier = {3, 1}; + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().numerator, 3); + EXPECT_EQ(et_pal_ticks_to_ns_multiplier().denominator, 1); +} + +TEST(ExecutorPalOverrideTest, AllocateSmokeTest) { + PalSpy spy; + InterceptWith iw(spy); + + // Validate that et_pal_allocate is overridden. + EXPECT_EQ(spy.allocate_call_count, 0); + EXPECT_EQ(spy.last_allocated_ptr, nullptr); + et_pal_allocate(4); + EXPECT_EQ(spy.allocate_call_count, 1); + EXPECT_EQ(spy.last_allocated_size, 4); + EXPECT_EQ(spy.last_allocated_ptr, (void*)0x1234); +} + +TEST(ExecutorPalOverrideTest, FreeSmokeTest) { + PalSpy spy; + InterceptWith iw(spy); + + et_pal_allocate(4); + EXPECT_EQ(spy.last_allocated_size, 4); + EXPECT_EQ(spy.last_allocated_ptr, (void*)0x1234); + + // Validate that et_pal_free is overridden. + EXPECT_EQ(spy.free_call_count, 0); + EXPECT_EQ(spy.last_freed_ptr, nullptr); + et_pal_free(spy.last_allocated_ptr); + EXPECT_EQ(spy.free_call_count, 1); + EXPECT_EQ(spy.last_freed_ptr, (void*)0x1234); +} + +#endif diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_runtime_override_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_runtime_override_test.cpp new file mode 100644 index 0000000..ee0526a --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_runtime_override_test.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +namespace { +PalSpy* active_spy; + +void pal_init(void) { + active_spy->init(); +} + +et_timestamp_t pal_current_ticks(void) { + return active_spy->current_ticks(); +} + +et_tick_ratio_t pal_ticks_to_ns_multiplier(void) { + return active_spy->ticks_to_ns_multiplier(); +} + +void pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + ET_UNUSED const char* function, + size_t line, + const char* message, + ET_UNUSED size_t length) { + active_spy->emit_log_message( + timestamp, level, filename, function, line, message, length); +} + +void* pal_allocate(size_t size) { + return active_spy->allocate(size); +} + +void pal_free(void* ptr) { + active_spy->free(ptr); +} +} // namespace + +class RuntimePalOverrideTest : public ::testing::Test { + protected: + void SetUp() override { + // Capture the current PAL implementation so that it can be restored + // after the test. + _original_pal_impl = *executorch::runtime::get_pal_impl(); + } + + void TearDown() override { + // Restore the original PAL implementation. + + // This is a slightly hacky way to allow this test to exist alongside + // the executor_pal_override_test, which provides a build-time override + // for et_pal_init. This implementation asserts that an intercept exists. + // Since register_pal calls init, we need to make sure that an intercept + // is registered. It will be deregistered when it goes out of scope, + // allowing the tests to run in any order. + InterceptWith iw(_spy); + auto success = executorch::runtime::register_pal(_original_pal_impl); + if (!success) { + throw std::runtime_error("Failed to restore PAL implementation."); + } + } + + void RegisterSpy() { + active_spy = &_spy; + + executorch::runtime::register_pal(executorch::runtime::PalImpl::create( + pal_init, + nullptr, // abort + pal_current_ticks, + pal_ticks_to_ns_multiplier, + pal_emit_log_message, + pal_allocate, + pal_free, + __FILE__)); + } + + PalSpy _spy; + + private: + // The PAL implementation at the time of setup. + executorch::runtime::PalImpl _original_pal_impl; +}; + +TEST_F(RuntimePalOverrideTest, SmokeTest) { + EXPECT_EQ(_spy.init_call_count, 0); + EXPECT_EQ(_spy.current_ticks_call_count, 0); + EXPECT_EQ(_spy.allocate_call_count, 0); + EXPECT_EQ(_spy.free_call_count, 0); + + RegisterSpy(); + + // Expect register to call init. + EXPECT_EQ(_spy.init_call_count, 1); + + EXPECT_EQ(executorch::runtime::pal_current_ticks(), 1234); + EXPECT_EQ(_spy.current_ticks_call_count, 1); + + et_tick_ratio_t ticks_to_ns_multiplier = + executorch::runtime::pal_ticks_to_ns_multiplier(); + EXPECT_EQ(ticks_to_ns_multiplier.numerator, 1); + EXPECT_EQ(ticks_to_ns_multiplier.denominator, 1); + + executorch::runtime::pal_emit_log_message( + 5, kError, "test.cpp", "test_function", 6, "test message", 7); + EXPECT_EQ(_spy.emit_log_message_call_count, 1); + EXPECT_EQ(_spy.last_log_message_args.timestamp, 5); + EXPECT_EQ(_spy.last_log_message_args.level, kError); + EXPECT_EQ(_spy.last_log_message_args.filename, "test.cpp"); + EXPECT_EQ(_spy.last_log_message_args.function, "test_function"); + EXPECT_EQ(_spy.last_log_message_args.line, 6); + EXPECT_EQ(_spy.last_log_message_args.message, "test message"); + EXPECT_EQ(_spy.last_log_message_args.length, 7); + + executorch::runtime::pal_allocate(16); + EXPECT_EQ(_spy.allocate_call_count, 1); + + executorch::runtime::pal_free(nullptr); + EXPECT_EQ(_spy.free_call_count, 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_static_runtime_override_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_static_runtime_override_test.cpp new file mode 100644 index 0000000..baf5da5 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_static_runtime_override_test.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +namespace { +PalSpy spy = PalSpy(); + +void pal_init(void) { + spy.init(); +} + +et_timestamp_t pal_current_ticks(void) { + return spy.current_ticks(); +} + +et_tick_ratio_t pal_ticks_to_ns_multiplier(void) { + return spy.ticks_to_ns_multiplier(); +} + +void pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + ET_UNUSED const char* function, + size_t line, + const char* message, + ET_UNUSED size_t length) { + spy.emit_log_message( + timestamp, level, filename, function, line, message, length); +} + +void* pal_allocate(size_t size) { + return spy.allocate(size); +} + +void pal_free(void* ptr) { + spy.free(ptr); +} + +// Statically register PAL impleementation. +bool registration_result = + executorch::runtime::register_pal(executorch::runtime::PalImpl::create( + pal_init, + nullptr, // abort + pal_current_ticks, + pal_ticks_to_ns_multiplier, + pal_emit_log_message, + pal_allocate, + pal_free, + __FILE__)); +} // namespace + +TEST(RuntimePalOverrideTest, SmokeTest) { + EXPECT_EQ(spy.current_ticks_call_count, 0); + EXPECT_EQ(spy.allocate_call_count, 0); + EXPECT_EQ(spy.free_call_count, 0); + + // Expect registration to call init. + EXPECT_EQ(spy.init_call_count, 1); + + EXPECT_EQ(executorch::runtime::pal_current_ticks(), 1234); + EXPECT_EQ(spy.current_ticks_call_count, 1); + + et_tick_ratio_t ticks_to_ns_multiplier = + executorch::runtime::pal_ticks_to_ns_multiplier(); + EXPECT_EQ(ticks_to_ns_multiplier.numerator, 1); + EXPECT_EQ(ticks_to_ns_multiplier.denominator, 1); + + executorch::runtime::pal_emit_log_message( + 5, kError, "test.cpp", "test_function", 6, "test message", 7); + EXPECT_EQ(spy.emit_log_message_call_count, 1); + EXPECT_EQ(spy.last_log_message_args.timestamp, 5); + EXPECT_EQ(spy.last_log_message_args.level, kError); + EXPECT_EQ(spy.last_log_message_args.filename, "test.cpp"); + EXPECT_EQ(spy.last_log_message_args.function, "test_function"); + EXPECT_EQ(spy.last_log_message_args.line, 6); + EXPECT_EQ(spy.last_log_message_args.message, "test message"); + EXPECT_EQ(spy.last_log_message_args.length, 7); + + executorch::runtime::pal_allocate(16); + EXPECT_EQ(spy.allocate_call_count, 1); + + executorch::runtime::pal_free(nullptr); + EXPECT_EQ(spy.free_call_count, 1); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_test.cpp new file mode 100644 index 0000000..51a0aaf --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/executor_pal_test.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +TEST(ExecutorPalTest, Initialization) { + /* + * Ensure `et_pal_init` can be called multiple times. + * It has already been called once in the main() function. + */ + et_pal_init(); +} + +TEST(ExecutorPalTest, TimestampCoherency) { + et_pal_init(); + + et_timestamp_t time_a = et_pal_current_ticks(); + ASSERT_TRUE(time_a >= 0); + + et_timestamp_t time_b = et_pal_current_ticks(); + ASSERT_TRUE(time_b >= time_a); +} + +TEST(ExecutorPalTest, TickRateRatioSanity) { + auto tick_ns_ratio = et_pal_ticks_to_ns_multiplier(); + ASSERT_TRUE(tick_ns_ratio.numerator > 0); + ASSERT_TRUE(tick_ns_ratio.denominator > 0); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/logging_test.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/logging_test.cpp new file mode 100644 index 0000000..3ddc506 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/logging_test.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include + +using namespace executorch::runtime; + +class LoggingTest : public ::testing::Test {}; + +TEST_F(LoggingTest, LogLevels) { + PalSpy spy; + InterceptWith iw(spy); + + ET_LOG(Debug, "Debug log."); + EXPECT_EQ(spy.last_log_message_args.message, "Debug log."); + + ET_LOG(Info, "Info log."); + EXPECT_EQ(spy.last_log_message_args.message, "Info log."); + + ET_LOG(Error, "Error log."); + EXPECT_EQ(spy.last_log_message_args.message, "Error log."); + + ET_LOG(Fatal, "Fatal log."); + EXPECT_EQ(spy.last_log_message_args.message, "Fatal log."); +} + +TEST_F(LoggingTest, LogFormatting) { + PalSpy spy; + InterceptWith iw(spy); + + ET_LOG(Info, "Sample log with integer: %u", 100); + EXPECT_EQ(spy.last_log_message_args.message, "Sample log with integer: 100"); +} + +static std::string get_prefix(std::size_t length, bool use_multibyte) { + if (!use_multibyte) { + return std::string(length, 'A'); + } + std::ostringstream result; + result << std::string(length % 4, 'A'); + std::size_t remaining = length - (length % 4); + while (remaining > 0) { + result << "\xF0\x9F\x91\x8D"; + remaining -= 4; + } + return result.str(); +} + +TEST_F(LoggingTest, Utf8Truncation) { + PalSpy spy; + InterceptWith iw(spy); + + const char euro[] = "\xE2\x82\xAC"; + const char thumbs_up[] = "\xF0\x9F\x91\x8D"; + const char e_acute[] = "\xC3\xA9"; + const char capital_a_tilde[] = "\xC3\x83"; + + struct TruncCase { + size_t prefix_length; + const char* codepoint; + }; + const TruncCase cases[] = { + {253, euro}, + {252, thumbs_up}, + {254, e_acute}, + {254, capital_a_tilde}, + }; + for (bool use_multibyte_prefix : {false, true}) { + for (const auto& c : cases) { + const std::string prefix = + get_prefix(c.prefix_length, use_multibyte_prefix); + const std::string suffix = "_SHOULD_BE_CUT"; + ET_LOG(Info, "%s%s%s", prefix.c_str(), c.codepoint, suffix.c_str()); + EXPECT_EQ(spy.last_log_message_args.message, prefix); + EXPECT_EQ(spy.last_log_message_args.length, prefix.size()); + } + } +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/pal_spy.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/pal_spy.h new file mode 100644 index 0000000..5831ba1 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/pal_spy.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include + +class PalSpy : public PlatformIntercept { + public: + PalSpy() = default; + + void init() override { + ++init_call_count; + } + + static constexpr et_timestamp_t kTimestamp = 1234; + + et_timestamp_t current_ticks() override { + ++current_ticks_call_count; + return kTimestamp; + } + + et_tick_ratio_t ticks_to_ns_multiplier() override { + return tick_ns_multiplier; + } + + void emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + const char* function, + size_t line, + const char* message, + size_t length) override { + ++emit_log_message_call_count; + last_log_message_args.timestamp = timestamp; + last_log_message_args.level = level; + last_log_message_args.filename = filename; + last_log_message_args.function = function; + last_log_message_args.line = line; + last_log_message_args.message = message; + last_log_message_args.length = length; + } + + void* allocate(size_t size) override { + ++allocate_call_count; + last_allocated_size = size; + last_allocated_ptr = (void*)0x1234; + return nullptr; + } + + void free(void* ptr) override { + ++free_call_count; + last_freed_ptr = ptr; + } + + virtual ~PalSpy() = default; + + size_t init_call_count = 0; + size_t current_ticks_call_count = 0; + size_t emit_log_message_call_count = 0; + et_tick_ratio_t tick_ns_multiplier = {1, 1}; + size_t allocate_call_count = 0; + size_t free_call_count = 0; + size_t last_allocated_size = 0; + void* last_allocated_ptr = nullptr; + void* last_freed_ptr = nullptr; + + /// The args that were passed to the most recent call to emit_log_message(). + struct { + et_timestamp_t timestamp; + et_pal_log_level_t level; + std::string filename; // Copy of the char* to avoid lifetime issues. + std::string function; + size_t line; + std::string message; + size_t length; + } last_log_message_args = {}; +}; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.cpp new file mode 100644 index 0000000..8cee404 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +/** + * @file + * An implementation of the PAL to help with testing. + */ + +static PlatformIntercept* platform_intercept; + +void InterceptWith::install(PlatformIntercept* pi) { + platform_intercept = pi; +} + +/// Prints a message and aborts if an intercept is not installed. +#define ASSERT_INTERCEPT_INSTALLED() \ + ({ \ + if (platform_intercept == nullptr) { \ + fprintf(stderr, "%s call was not intercepted\n", ET_FUNCTION); \ + fflush(stderr); \ + __builtin_trap(); \ + } \ + }) + +extern "C" { + +void et_pal_init(void) { + ASSERT_INTERCEPT_INSTALLED(); + platform_intercept->init(); +} + +ET_NORETURN void et_pal_abort(void) { + ASSERT_INTERCEPT_INSTALLED(); + // We can't properly intercept this since it's marked NORETURN. + fprintf(stderr, "StubPlatform et_pal_abort called\n"); + fflush(stderr); + __builtin_trap(); +} + +et_timestamp_t et_pal_current_ticks(void) { + ASSERT_INTERCEPT_INSTALLED(); + return platform_intercept->current_ticks(); +} + +et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) { + ASSERT_INTERCEPT_INSTALLED(); + return platform_intercept->ticks_to_ns_multiplier(); +} + +void et_pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + ET_UNUSED const char* function, + size_t line, + const char* message, + ET_UNUSED size_t length) { + ASSERT_INTERCEPT_INSTALLED(); + platform_intercept->emit_log_message( + timestamp, level, filename, function, line, message, length); +} + +void* et_pal_allocate(size_t size) { + ASSERT_INTERCEPT_INSTALLED(); + return platform_intercept->allocate(size); +} + +void et_pal_free(void* ptr) { + ASSERT_INTERCEPT_INSTALLED(); + platform_intercept->free(ptr); +} + +} // extern "C" + +#include + +// Use a version of main() that does not call runtime_init(). +// +// By default, executorch tests are built with a main() that calls +// runtime_init(), and ultimately et_pal_init(). The StubPlatform override of +// et_pal_init() will fail if it isn't intercepted, so we can't call it at start +// time. +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + // Purposefully do not initialize the PAL. + return RUN_ALL_TESTS(); +} diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.h new file mode 100644 index 0000000..de5599b --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/stub_platform.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include + +/** + * An interface for intercepting calls to the PAL layer. + */ +class PlatformIntercept { + public: + PlatformIntercept() = default; + + /// Called when et_pal_init() is called. + virtual void init() {} + + // We can't intercept et_pal_abort() since it's marked NORETURN. + + /// Called when et_pal_current_ticks() is called. + virtual et_timestamp_t current_ticks() { + return 0; + } + + virtual et_tick_ratio_t ticks_to_ns_multiplier() { + return {1, 1}; + } + + /// Called when et_pal_emit_log_message() is called. + virtual void emit_log_message( + ET_UNUSED et_timestamp_t timestamp, + ET_UNUSED et_pal_log_level_t level, + ET_UNUSED const char* filename, + ET_UNUSED const char* function, + ET_UNUSED size_t line, + ET_UNUSED const char* message, + ET_UNUSED size_t length) {} + + virtual void* allocate(ET_UNUSED size_t size) { + return nullptr; + } + + virtual void free(ET_UNUSED void* ptr) {} + + virtual ~PlatformIntercept() = default; +}; + +/** + * RAII type to install a PlatformIntercept for the duration of a test case. + */ +class InterceptWith { + public: + explicit InterceptWith(PlatformIntercept& pi) { + InterceptWith::install(&pi); + } + + ~InterceptWith() { + InterceptWith::install(nullptr); + } + + private: + /** + * Installs the PlatformIntercept to forward to when et_pal_* functions are + * called. To uninstall, pass in `nullptr`. + */ + static void install(PlatformIntercept* pi); +}; diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/targets.bzl b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/targets.bzl new file mode 100644 index 0000000..a5d77ef --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/test/targets.bzl @@ -0,0 +1,109 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + """Defines targets that should be shared between fbcode and xplat. + + The directory containing this targets.bzl file should also contain both + TARGETS and BUCK files that call this function. + """ + + runtime.cxx_test( + name = "platform_test", + srcs = [ + "executor_pal_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_test( + name = "platform_death_test", + srcs = [ + "executor_pal_death_test.cpp", + ], + deps = [ + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + # This is an example of a target that provides a PAL implementation. Note + # the `link_whole = True` parameter, which is necessary to ensure that the + # symbols make their way into the top-level binary. If this target were to + # be added to a library instead of directly to a binary, it would need to be + # in that library's `exported_deps`. + runtime.cxx_library( + name = "stub_platform", + srcs = [ + "stub_platform.cpp", + ], + exported_headers = [ + "pal_spy.h", + "stub_platform.h", + ], + deps = [ + "//executorch/runtime/platform:compiler", + "//executorch/runtime/platform:platform", + "//executorch/test/utils:utils", # gtest.h + ], + visibility = [], + ) + + runtime.cxx_test( + name = "platform_override_test", + srcs = [ + "executor_pal_override_test.cpp", + ], + deps = [ + # This must come first to ensure that the weak platform + # calls are overriden. + # buildifier: do not sort + ":stub_platform", + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_test( + name = "runtime_platform_override_test", + srcs = [ + "executor_pal_runtime_override_test.cpp", + ], + deps = [ + ":stub_platform", + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) + + runtime.cxx_test( + name = "logging_test", + srcs = [ + "logging_test.cpp", + ], + deps = [ + ":stub_platform", + "//executorch/runtime/platform:platform", + ], + compiler_flags = [ + # Turn on debug logging. + "-DET_MIN_LOG_LEVEL=Debug", + ], + ) + + runtime.cxx_test( + name = "clock_test", + srcs = [ + "clock_test.cpp", + ], + deps = [ + # This must come first to ensure that the weak platform + # calls are overriden. + # buildifier: do not sort + ":stub_platform", + "//executorch/runtime/core:core", + "//executorch/runtime/platform:platform", + ], + ) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/types.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/types.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/platform/types.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/runtime/platform/types.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/extended_header.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/extended_header.cpp similarity index 96% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/extended_header.cpp rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/extended_header.cpp index 2645fb1..bd923bb 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/extended_header.cpp +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/extended_header.cpp @@ -70,11 +70,6 @@ uint64_t GetUInt64LE(const uint8_t* data) { const void* data, size_t size) { if (size < ExtendedHeader::kNumHeadBytes) { - ET_LOG( - Error, - "Extended header data size %zu < minimum %zu", - size, - ExtendedHeader::kNumHeadBytes); return Error::InvalidArgument; } const uint8_t* header = diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/extended_header.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/extended_header.h similarity index 100% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/extended_header.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/extended_header.h diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/program.fbs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/program.fbs similarity index 88% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/program.fbs rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/program.fbs index aa191e0..7308cc6 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/program.fbs +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/program.fbs @@ -1,5 +1,4 @@ // Copyright (c) Meta Platforms, Inc. and affiliates. -// Copyright 2026 Arm Limited and/or its affiliates. // // See README.md before modifying this file. @@ -62,13 +61,6 @@ enum TensorDataLocation : byte { EXTERNAL = 1, } -// Device type enum indicating where a tensor resides or should be allocated. -// Please keep this in sync with executorch/runtime/core/portable_type/device.h -enum DeviceType : byte { - CPU = 0, - CUDA = 1, -} - // Table to put additional information about tensors in that is not applicable // to the vast majority of tensors in the vast majority of programs. table ExtraTensorInfo { @@ -87,14 +79,6 @@ table ExtraTensorInfo { // must be non-empty, and is used as a key to find the tensor's external // data. Tensor.data_buffer_idx is ignored. location: TensorDataLocation; - - // [Optional] The device type where this tensor resides or should be allocated. - // Defaults to CPU for backward compatibility with existing PTE files. - device_type: DeviceType = CPU; - - // [Optional] The device index for multi-device scenarios (e.g., cuda:0, cuda:1). - // Defaults to 0 (the first device of the given type). - device_index: byte = 0; } table Tensor { @@ -125,7 +109,7 @@ table Tensor { // Overall, a Tensor is either constant or mutable. At method load time // constant tensors receive a dataptr into the serialized program. Mutable - // tensors can either receive a pointer from the hierarchical allocator or a + // tensors can either receive a pointer from the heirarchical allocator or a // nullptr if they will receive a data pointer at execution time (inputs // and control flow placeholders can be like this). Mutable tensors may or // may not also have an initial value in the serialized program. @@ -402,34 +386,9 @@ table ExecutionPlan { // constants memory buffer size, and ignore non_const_buffer_sizes[0]. non_const_buffer_sizes: [int64]; - // [Optional] Per-buffer device mapping, parallel to non_const_buffer_sizes. - // Each entry maps a non-constant buffer to the device where it should be - // allocated. For CPU-only programs, this field is absent and all buffers - // default to CPU, ensuring zero regression. - non_const_buffer_device: [NonConstBufferDevice]; - -} - -// Maps a non-constant buffer to the device where it should be allocated. -// When present as part of ExecutionPlan.non_const_buffer_device, each entry -// describes the device placement for the corresponding planned memory buffer. -// For CPU-only programs, this table is absent (all buffers default to CPU). -table NonConstBufferDevice { - // Index into the non_const_buffer_sizes list. - buffer_idx: int; - - // The device type for this buffer (CPU, CUDA, etc.). - device_type: DeviceType = CPU; - - // The device index for multi-device scenarios (e.g., cuda:0, cuda:1). - device_index: byte = 0; } // Constant tensor data stored directly in the flatbuffer. -// NOTE: If you change Buffer or BackendDelegateInlineData fields, update the -// custom packers in exir/_serialize/_flatbuffer_program.py -// (_pack_buffer and _pack_backend_delegate_inline_data); -// they override the flatc-generated packers. table Buffer { // During serialization, this alignment may be rewritten to a larger value. // The magic "@executorch-tensor-alignment" comment tells EXIR which lines to @@ -440,10 +399,6 @@ table Buffer { // Delegate data stored directly in the flatbuffer. This is a different type // than Buffer because tensors and delegates can have different alignment // requirements. -// NOTE: If you change Buffer or BackendDelegateInlineData fields, update the -// custom packers in exir/_serialize/_flatbuffer_program.py -// (_pack_buffer and _pack_backend_delegate_inline_data); -// they override the flatc-generated packers. table BackendDelegateInlineData { // During serialization, this alignment may be rewritten to a larger value. // The magic "@executorch-delegate-alignment" comment tells EXIR which lines diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/program_generated.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/program_generated.h similarity index 94% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/program_generated.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/program_generated.h index bb37bbe..f1659af 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/program_generated.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/program_generated.h @@ -104,9 +104,6 @@ struct ChainBuilder; struct ExecutionPlan; struct ExecutionPlanBuilder; -struct NonConstBufferDevice; -struct NonConstBufferDeviceBuilder; - struct Buffer; struct BufferBuilder; @@ -188,36 +185,6 @@ inline const char *EnumNameTensorDataLocation(TensorDataLocation e) { return EnumNamesTensorDataLocation()[index]; } -enum class DeviceType : int8_t { - CPU = 0, - CUDA = 1, - MIN = CPU, - MAX = CUDA -}; - -inline const DeviceType (&EnumValuesDeviceType())[2] { - static const DeviceType values[] = { - DeviceType::CPU, - DeviceType::CUDA - }; - return values; -} - -inline const char * const *EnumNamesDeviceType() { - static const char * const names[3] = { - "CPU", - "CUDA", - nullptr - }; - return names; -} - -inline const char *EnumNameDeviceType(DeviceType e) { - if (::flatbuffers::IsOutRange(e, DeviceType::CPU, DeviceType::CUDA)) return ""; - const size_t index = static_cast(e); - return EnumNamesDeviceType()[index]; -} - enum class KernelTypes : uint8_t { NONE = 0, Null = 1, @@ -603,9 +570,7 @@ struct ExtraTensorInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_MUTABLE_DATA_SEGMENTS_IDX = 4, VT_FULLY_QUALIFIED_NAME = 6, - VT_LOCATION = 8, - VT_DEVICE_TYPE = 10, - VT_DEVICE_INDEX = 12 + VT_LOCATION = 8 }; uint64_t mutable_data_segments_idx() const { return GetField(VT_MUTABLE_DATA_SEGMENTS_IDX, 0); @@ -625,26 +590,12 @@ struct ExtraTensorInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { bool mutate_location(executorch_flatbuffer::TensorDataLocation _location = static_cast(0)) { return SetField(VT_LOCATION, static_cast(_location), 0); } - executorch_flatbuffer::DeviceType device_type() const { - return static_cast(GetField(VT_DEVICE_TYPE, 0)); - } - bool mutate_device_type(executorch_flatbuffer::DeviceType _device_type = static_cast(0)) { - return SetField(VT_DEVICE_TYPE, static_cast(_device_type), 0); - } - int8_t device_index() const { - return GetField(VT_DEVICE_INDEX, 0); - } - bool mutate_device_index(int8_t _device_index = 0) { - return SetField(VT_DEVICE_INDEX, _device_index, 0); - } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_MUTABLE_DATA_SEGMENTS_IDX, 8) && VerifyOffset(verifier, VT_FULLY_QUALIFIED_NAME) && verifier.VerifyString(fully_qualified_name()) && VerifyField(verifier, VT_LOCATION, 1) && - VerifyField(verifier, VT_DEVICE_TYPE, 1) && - VerifyField(verifier, VT_DEVICE_INDEX, 1) && verifier.EndTable(); } }; @@ -662,12 +613,6 @@ struct ExtraTensorInfoBuilder { void add_location(executorch_flatbuffer::TensorDataLocation location) { fbb_.AddElement(ExtraTensorInfo::VT_LOCATION, static_cast(location), 0); } - void add_device_type(executorch_flatbuffer::DeviceType device_type) { - fbb_.AddElement(ExtraTensorInfo::VT_DEVICE_TYPE, static_cast(device_type), 0); - } - void add_device_index(int8_t device_index) { - fbb_.AddElement(ExtraTensorInfo::VT_DEVICE_INDEX, device_index, 0); - } explicit ExtraTensorInfoBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -683,14 +628,10 @@ inline ::flatbuffers::Offset CreateExtraTensorInfo( ::flatbuffers::FlatBufferBuilder &_fbb, uint64_t mutable_data_segments_idx = 0, ::flatbuffers::Offset<::flatbuffers::String> fully_qualified_name = 0, - executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT, - executorch_flatbuffer::DeviceType device_type = executorch_flatbuffer::DeviceType::CPU, - int8_t device_index = 0) { + executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT) { ExtraTensorInfoBuilder builder_(_fbb); builder_.add_mutable_data_segments_idx(mutable_data_segments_idx); builder_.add_fully_qualified_name(fully_qualified_name); - builder_.add_device_index(device_index); - builder_.add_device_type(device_type); builder_.add_location(location); return builder_.Finish(); } @@ -699,17 +640,13 @@ inline ::flatbuffers::Offset CreateExtraTensorInfoDirect( ::flatbuffers::FlatBufferBuilder &_fbb, uint64_t mutable_data_segments_idx = 0, const char *fully_qualified_name = nullptr, - executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT, - executorch_flatbuffer::DeviceType device_type = executorch_flatbuffer::DeviceType::CPU, - int8_t device_index = 0) { + executorch_flatbuffer::TensorDataLocation location = executorch_flatbuffer::TensorDataLocation::SEGMENT) { auto fully_qualified_name__ = fully_qualified_name ? _fbb.CreateString(fully_qualified_name) : 0; return executorch_flatbuffer::CreateExtraTensorInfo( _fbb, mutable_data_segments_idx, fully_qualified_name__, - location, - device_type, - device_index); + location); } struct Tensor FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { @@ -2444,8 +2381,7 @@ struct ExecutionPlan FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { VT_CHAINS = 14, VT_OPERATORS = 16, VT_DELEGATES = 18, - VT_NON_CONST_BUFFER_SIZES = 20, - VT_NON_CONST_BUFFER_DEVICE = 22 + VT_NON_CONST_BUFFER_SIZES = 20 }; const ::flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -2501,12 +2437,6 @@ struct ExecutionPlan FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { ::flatbuffers::Vector *mutable_non_const_buffer_sizes() { return GetPointer<::flatbuffers::Vector *>(VT_NON_CONST_BUFFER_SIZES); } - const ::flatbuffers::Vector<::flatbuffers::Offset> *non_const_buffer_device() const { - return GetPointer> *>(VT_NON_CONST_BUFFER_DEVICE); - } - ::flatbuffers::Vector<::flatbuffers::Offset> *mutable_non_const_buffer_device() { - return GetPointer<::flatbuffers::Vector<::flatbuffers::Offset> *>(VT_NON_CONST_BUFFER_DEVICE); - } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NAME) && @@ -2531,9 +2461,6 @@ struct ExecutionPlan FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { verifier.VerifyVectorOfTables(delegates()) && VerifyOffset(verifier, VT_NON_CONST_BUFFER_SIZES) && verifier.VerifyVector(non_const_buffer_sizes()) && - VerifyOffset(verifier, VT_NON_CONST_BUFFER_DEVICE) && - verifier.VerifyVector(non_const_buffer_device()) && - verifier.VerifyVectorOfTables(non_const_buffer_device()) && verifier.EndTable(); } }; @@ -2569,9 +2496,6 @@ struct ExecutionPlanBuilder { void add_non_const_buffer_sizes(::flatbuffers::Offset<::flatbuffers::Vector> non_const_buffer_sizes) { fbb_.AddOffset(ExecutionPlan::VT_NON_CONST_BUFFER_SIZES, non_const_buffer_sizes); } - void add_non_const_buffer_device(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> non_const_buffer_device) { - fbb_.AddOffset(ExecutionPlan::VT_NON_CONST_BUFFER_DEVICE, non_const_buffer_device); - } explicit ExecutionPlanBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -2593,10 +2517,8 @@ inline ::flatbuffers::Offset CreateExecutionPlan( ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> chains = 0, ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> operators = 0, ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> delegates = 0, - ::flatbuffers::Offset<::flatbuffers::Vector> non_const_buffer_sizes = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> non_const_buffer_device = 0) { + ::flatbuffers::Offset<::flatbuffers::Vector> non_const_buffer_sizes = 0) { ExecutionPlanBuilder builder_(_fbb); - builder_.add_non_const_buffer_device(non_const_buffer_device); builder_.add_non_const_buffer_sizes(non_const_buffer_sizes); builder_.add_delegates(delegates); builder_.add_operators(operators); @@ -2619,8 +2541,7 @@ inline ::flatbuffers::Offset CreateExecutionPlanDirect( const std::vector<::flatbuffers::Offset> *chains = nullptr, const std::vector<::flatbuffers::Offset> *operators = nullptr, const std::vector<::flatbuffers::Offset> *delegates = nullptr, - const std::vector *non_const_buffer_sizes = nullptr, - const std::vector<::flatbuffers::Offset> *non_const_buffer_device = nullptr) { + const std::vector *non_const_buffer_sizes = nullptr) { auto name__ = name ? _fbb.CreateString(name) : 0; auto values__ = values ? _fbb.CreateVector<::flatbuffers::Offset>(*values) : 0; auto inputs__ = inputs ? _fbb.CreateVector(*inputs) : 0; @@ -2629,7 +2550,6 @@ inline ::flatbuffers::Offset CreateExecutionPlanDirect( auto operators__ = operators ? _fbb.CreateVector<::flatbuffers::Offset>(*operators) : 0; auto delegates__ = delegates ? _fbb.CreateVector<::flatbuffers::Offset>(*delegates) : 0; auto non_const_buffer_sizes__ = non_const_buffer_sizes ? _fbb.CreateVector(*non_const_buffer_sizes) : 0; - auto non_const_buffer_device__ = non_const_buffer_device ? _fbb.CreateVector<::flatbuffers::Offset>(*non_const_buffer_device) : 0; return executorch_flatbuffer::CreateExecutionPlan( _fbb, name__, @@ -2640,78 +2560,7 @@ inline ::flatbuffers::Offset CreateExecutionPlanDirect( chains__, operators__, delegates__, - non_const_buffer_sizes__, - non_const_buffer_device__); -} - -struct NonConstBufferDevice FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef NonConstBufferDeviceBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_BUFFER_IDX = 4, - VT_DEVICE_TYPE = 6, - VT_DEVICE_INDEX = 8 - }; - int32_t buffer_idx() const { - return GetField(VT_BUFFER_IDX, 0); - } - bool mutate_buffer_idx(int32_t _buffer_idx = 0) { - return SetField(VT_BUFFER_IDX, _buffer_idx, 0); - } - executorch_flatbuffer::DeviceType device_type() const { - return static_cast(GetField(VT_DEVICE_TYPE, 0)); - } - bool mutate_device_type(executorch_flatbuffer::DeviceType _device_type = static_cast(0)) { - return SetField(VT_DEVICE_TYPE, static_cast(_device_type), 0); - } - int8_t device_index() const { - return GetField(VT_DEVICE_INDEX, 0); - } - bool mutate_device_index(int8_t _device_index = 0) { - return SetField(VT_DEVICE_INDEX, _device_index, 0); - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField(verifier, VT_BUFFER_IDX, 4) && - VerifyField(verifier, VT_DEVICE_TYPE, 1) && - VerifyField(verifier, VT_DEVICE_INDEX, 1) && - verifier.EndTable(); - } -}; - -struct NonConstBufferDeviceBuilder { - typedef NonConstBufferDevice Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_buffer_idx(int32_t buffer_idx) { - fbb_.AddElement(NonConstBufferDevice::VT_BUFFER_IDX, buffer_idx, 0); - } - void add_device_type(executorch_flatbuffer::DeviceType device_type) { - fbb_.AddElement(NonConstBufferDevice::VT_DEVICE_TYPE, static_cast(device_type), 0); - } - void add_device_index(int8_t device_index) { - fbb_.AddElement(NonConstBufferDevice::VT_DEVICE_INDEX, device_index, 0); - } - explicit NonConstBufferDeviceBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - return o; - } -}; - -inline ::flatbuffers::Offset CreateNonConstBufferDevice( - ::flatbuffers::FlatBufferBuilder &_fbb, - int32_t buffer_idx = 0, - executorch_flatbuffer::DeviceType device_type = executorch_flatbuffer::DeviceType::CPU, - int8_t device_index = 0) { - NonConstBufferDeviceBuilder builder_(_fbb); - builder_.add_buffer_idx(buffer_idx); - builder_.add_device_index(device_index); - builder_.add_device_type(device_type); - return builder_.Finish(); + non_const_buffer_sizes__); } struct Buffer FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/scalar_type.fbs b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/scalar_type.fbs similarity index 97% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/scalar_type.fbs rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/scalar_type.fbs index 47e3386..e9c830b 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/schema/scalar_type.fbs +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/scalar_type.fbs @@ -21,7 +21,6 @@ enum ScalarType : byte { QINT8 = 12, QUINT8 = 13, QINT32 = 14, - BFLOAT16 = 15, QUINT4X2 = 16, QUINT2X4 = 17, BITS16 = 22, @@ -36,6 +35,7 @@ enum ScalarType : byte { // COMPLEXHALF = 8, // COMPLEXFLOAT = 9, // COMPLEXDOUBLE = 10, + // BFLOAT16 = 15, // BITS1x8 = 18, // BITS2x4 = 19, // BITS4x2 = 20, diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/scalar_type_generated.h b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/scalar_type_generated.h similarity index 95% rename from packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/scalar_type_generated.h rename to packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/scalar_type_generated.h index 06b7460..56f5062 100644 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/schema/scalar_type_generated.h +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/schema/scalar_type_generated.h @@ -28,7 +28,6 @@ enum class ScalarType : int8_t { QINT8 = 12, QUINT8 = 13, QINT32 = 14, - BFLOAT16 = 15, QUINT4X2 = 16, QUINT2X4 = 17, BITS16 = 22, @@ -43,7 +42,7 @@ enum class ScalarType : int8_t { MAX = UINT64 }; -inline const ScalarType (&EnumValuesScalarType())[23] { +inline const ScalarType (&EnumValuesScalarType())[22] { static const ScalarType values[] = { ScalarType::BYTE, ScalarType::CHAR, @@ -57,7 +56,6 @@ inline const ScalarType (&EnumValuesScalarType())[23] { ScalarType::QINT8, ScalarType::QUINT8, ScalarType::QINT32, - ScalarType::BFLOAT16, ScalarType::QUINT4X2, ScalarType::QUINT2X4, ScalarType::BITS16, @@ -89,7 +87,7 @@ inline const char * const *EnumNamesScalarType() { "QINT8", "QUINT8", "QINT32", - "BFLOAT16", + "", "QUINT4X2", "QUINT2X4", "", diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/posix_stub.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/posix_stub.cpp new file mode 100644 index 0000000..9ea5521 --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/posix_stub.cpp @@ -0,0 +1,56 @@ +/** + * @file posix_stub.cpp + * @brief Stub implementation of posix.cpp functions for ARM Clang + * + * This file provides weak symbol implementations that will be overridden + * by the strong symbols in arm_executor_runner.cpp. + * + * This is needed because the original posix.cpp uses std::chrono::steady_clock + * which is not available in ARM Clang's bare-metal libc++. + */ + +#include +#include +#include +#include + +namespace torch { +namespace executor { + +// Weak symbol - will be overridden by arm_executor_runner.cpp +__attribute__((weak)) void et_pal_init(void) { + // Empty stub - actual implementation in arm_executor_runner.cpp +} + +// Weak symbol - will be overridden by arm_executor_runner.cpp +__attribute__((weak)) et_timestamp_t et_pal_current_ticks(void) { + // Return dummy value - actual implementation in arm_executor_runner.cpp + return 0; +} + +// Weak symbol - will be overridden by arm_executor_runner.cpp +__attribute__((weak)) et_tick_ratio_t et_pal_ticks_to_ns_multiplier(void) { + return {1, 1}; +} + +// Weak symbol - will be overridden by arm_executor_runner.cpp +__attribute__((weak)) void et_pal_emit_log_message( + et_timestamp_t timestamp, + et_pal_log_level_t level, + const char* filename, + const char* function, + size_t line, + const char* message, + size_t length) { + // Empty stub - actual implementation in arm_executor_runner.cpp + (void)timestamp; + (void)level; + (void)filename; + (void)function; + (void)line; + (void)message; + (void)length; +} + +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/random_ops_stubs.cpp b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/random_ops_stubs.cpp new file mode 100644 index 0000000..d04327d --- /dev/null +++ b/packs/PyTorch.ExecuTorch.1.1.0-rc1-build.12/src/stubs/random_ops_stubs.cpp @@ -0,0 +1,65 @@ +/* + * Stub implementations for random operations not supported on ARM Clang bare-metal. + * + * ARM Clang V22's libc++ disables std::random_device for bare-metal targets + * (_LIBCPP_HAS_RANDOM_DEVICE=0). These stubs satisfy the linker for the operator + * registrations and abort at runtime if called. + */ + +#include +#include // for abort() + +namespace torch { +namespace executor { +namespace native { + +using executorch::aten::IntArrayRef; +using Tensor = executorch::aten::Tensor; + +// Stub for rand_out - random operations require std::random_device which is not +// available in ARM Clang bare-metal libc++ +Tensor& rand_out( + KernelRuntimeContext& ctx, + const IntArrayRef sizes, + Tensor& out) { + (void)ctx; + (void)sizes; + // Random operations are not supported on bare-metal ARM Clang + // (no std::random_device available) + ET_LOG(Error, "rand_out: Random operations not supported on this platform"); + abort(); + return out; +} + +// Stub for randn_out - random operations require std::random_device +Tensor& randn_out( + KernelRuntimeContext& ctx, + const IntArrayRef sizes, + Tensor& out) { + (void)ctx; + (void)sizes; + ET_LOG(Error, "randn_out: Random operations not supported on this platform"); + abort(); + return out; +} + +// Stub for native_dropout_out - requires std::random_device +std::tuple native_dropout_out( + KernelRuntimeContext& ctx, + const Tensor& input, + double p, + std::optional train, + Tensor& out, + Tensor& mask) { + (void)ctx; + (void)input; + (void)p; + (void)train; + ET_LOG(Error, "native_dropout_out: Random operations not supported on this platform"); + abort(); + return std::tie(out, mask); +} + +} // namespace native +} // namespace executor +} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/LICENSE b/packs/PyTorch.ExecuTorch.1.3.1-rc8/LICENSE deleted file mode 100644 index c16e596..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/LICENSE +++ /dev/null @@ -1,37 +0,0 @@ -BSD License - -For "ExecuTorch" software - -Copyright (c) Meta Platforms, Inc. and affiliates. -Copyright 2023 Arm Limited and/or its affiliates. -Copyright (c) Qualcomm Innovation Center, Inc. -Copyright (c) 2023 Apple Inc. -Copyright (c) 2024 MediaTek Inc. -Copyright 2023 NXP -Copyright (c) 2025 Samsung Electronics Co. LTD -Copyright (c) Intel Corporation - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name Meta nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/armclang_shims/sys/types.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/armclang_shims/sys/types.h deleted file mode 100644 index d762122..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/armclang_shims/sys/types.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - * - * Shim for Arm Compiler 6 (AC6). - * - * runtime/platform/compiler.h includes on every non-MSVC - * compiler to pick up ssize_t. AC6 targeting arm-arm-none-eabi is a - * freestanding toolchain and ships no such header in its sysroot, so the - * include fails. GCC (newlib) and ATfE / arm-llvm-embedded (picolibc) - * both ship a real , so for them this shim forwards via - * #include_next; for AC6 it provides the minimal subset ExecuTorch needs. - * - * This file is part of the PyTorch::ExecuTorch CMSIS Pack and is added - * to the include search path only when the AC6 condition is active - * (see the Runtime component in PyTorch.ExecuTorch.pdsc). - */ -#ifndef PYTORCH_EXECUTORCH_AC6_SYS_TYPES_H -#define PYTORCH_EXECUTORCH_AC6_SYS_TYPES_H - -#if !defined(__ARMCC_VERSION) -/* GCC newlib / ATfE picolibc — forward to the real header. */ -#include_next -#else -/* AC6 — provide the minimal set ExecuTorch needs. */ -#include -#include - -#if !defined(_SSIZE_T_DEFINED) && !defined(__ssize_t_defined) -#define _SSIZE_T_DEFINED -#define __ssize_t_defined -#ifdef __cplusplus -using ssize_t = ptrdiff_t; -#else -typedef ptrdiff_t ssize_t; -#endif -#endif - -#endif /* !__ARMCC_VERSION */ - -#endif /* PYTORCH_EXECUTORCH_AC6_SYS_TYPES_H */ diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend.cpp deleted file mode 100644 index 4b78f9a..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright 2023-2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Common Arm backend for Ethos-U. Please see - * EthosUBackend_Cortex_*.cpp for specific backends. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -// Overridable memcpy used by the EthosU backend for input/output scratch -// shuffling. Default (weak) implementation in EthosUBackend_IoMemcpy.cpp does -// std::memcpy. Firmware targets can supply a strong override (e.g. routing -// through a DMA engine) to reduce CPU memcpy load on the host MCU. -extern "C" void arm_ethos_io_memcpy(void* dst, const void* src, size_t size); - -using namespace std; - -using executorch::aten::ScalarType; -using executorch::runtime::ArrayRef; -using executorch::runtime::Backend; -using executorch::runtime::BackendExecutionContext; -using executorch::runtime::BackendInitContext; -using executorch::runtime::CompileSpec; -using executorch::runtime::DelegateHandle; -using executorch::runtime::Error; -using executorch::runtime::EValue; -using executorch::runtime::FreeableBuffer; -using executorch::runtime::MemoryAllocator; -using executorch::runtime::Result; -using executorch::runtime::Span; - -namespace executorch { -namespace backends { -namespace arm { - -extern "C" { -void __attribute__((weak)) EthosUBackend_execute_begin() {} -void __attribute__((weak)) EthosUBackend_execute_end() {} -__attribute__((weak)) unsigned char* ethosu_fast_scratch = nullptr; -__attribute__((weak)) size_t ethosu_fast_scratch_size = 0; -} - -class EthosUBackendExecuteCallbacks { - public: - EthosUBackendExecuteCallbacks() { - EthosUBackend_execute_begin(); - } - ~EthosUBackendExecuteCallbacks() { - EthosUBackend_execute_end(); - } -}; - -class EthosUBackend final : public ::executorch::runtime::BackendInterface { - public: - EthosUBackend() {} - - ~EthosUBackend() = default; - - virtual bool is_available() const override { - // TODO: revise to use a register check/init function - return 1; - } - - Result init( - BackendInitContext& context, - FreeableBuffer* processed, - ArrayRef compile_specs) const override { - ET_LOG(Info, "data:%p", processed->data()); - - const char* data = static_cast(processed->data()); - size_t size = processed->size(); - - // Verify format of vela_bin - if (vela_bin_validate(data, size) == false) { - ET_LOG(Error, "Malformed vela_bin_stream found"); - return Error::InvalidProgram; - } - - MemoryAllocator* allocator = context.get_runtime_allocator(); - ExecutionHandle* handle = new (std::nothrow) ExecutionHandle(); - if (handle == nullptr) { - return Error::MemoryAllocationFailed; - } - - handle->processed = processed; - handle->platform_state = platform_init(compile_specs, allocator); - - // Return the same buffer we were passed - this data will be - // executed directly - return handle; - } - - Error execute( - BackendExecutionContext& context, - DelegateHandle* input_handle, - Span args) const override { -#if defined(ET_EVENT_TRACER_ENABLED) - EventTracer* event_tracer = context.event_tracer(); - EventTracerEntry event_tracer_local_scope; -#endif - - EXECUTORCH_PROF_SCOPE(event_tracer, "EthosUBackend::execute()"); - - // CollectArm_CPU_Cycles is just used to save the numbers of CPU cycles - // used, If etdump is used the EXECUTORCH_PROF_SCOPE() above will do the - // same. If not, this is a cheap way of getting some stats and the - // CollectArm_CPU_Cycles object can safely be removed in production code. - // - // The EthosUBackendExecuteCallbacks class uses the C++ - // constructor/destructor to make sure that EthosUBackend_execute_begin() - // and EthosUBackend_execute_end() is called while CollectArm_CPU_Cycles is - // in scope. e.g. We meassure from now until we exit this metod (in any way - // we might do it). - EthosUBackendExecuteCallbacks CollectArm_CPU_Cycles; - - ExecutionHandle* execution_handle = - static_cast(input_handle); - VelaHandles handles; - - // Command stream - we know at this point it's aligned - EXECUTORCH_PROF_START( - event_tracer, - event_tracer_local_scope, - "+EthosUBackend::execute()processed_data"); - const char* data = - static_cast(execution_handle->processed->data()); - EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); - - ET_LOG(Debug, "data:%p", data); - - EXECUTORCH_PROF_START( - event_tracer, - event_tracer_local_scope, - "+EthosUBackend::execute()vela_bin_read()"); - // Read key sections from the vela_bin_stream - if (vela_bin_read(data, &handles, execution_handle->processed->size()) == - false) { - ET_LOG(Error, "vela_read: error, invalid binary layout"); - return Error::InvalidProgram; - } - EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); - - const int input_count = handles.inputs ? handles.inputs->count : 0; - const int output_count = handles.outputs ? handles.outputs->count : 0; - - MemoryAllocator* temp_allocator = context.get_temp_allocator(); - // Use a temporary allocator for the intermediate tensors of the - // computation. The allocator is released in runtime/executor/method.cpp at - // the end of the execution of the Ethos-U custom delegate - // Ethos-U driver requires 16 bit alignment. - char* ethosu_scratch = static_cast( - temp_allocator->allocate(handles.scratch_data_size, 16UL)); - if (ethosu_scratch == nullptr) { - ET_LOG( - Error, - "Failed to allocate scratch buffer of %zu bytes from temp_allocator", - handles.scratch_data_size); - return Error::MemoryAllocationFailed; - } - ET_LOG( - Debug, - "Running program data:\n cmd %p %zu\n weight %p %zu\n scratch %p %zu\n fast scratch %p %zu\n", - handles.cmd_data, - handles.cmd_data_size, - handles.weight_data, - handles.weight_data_size, - ethosu_scratch, - handles.scratch_data_size, - ethosu_fast_scratch, - ethosu_fast_scratch_size); - - // Write argument values (from EValue tensor) into Ethos-U scratch - // TODO(MLETORCH-123): Optimise into direct write from Vela into the SRAM - // or DRAM output for compatible data layouts. - for (int i = 0; i < input_count; i++) { - auto tensor_count = 1, io_count = 1; - auto tensor_in = args[i]->toTensor(); - char* scratch_addr = ethosu_scratch + handles.inputs->io[i].offset; - - // We accept: - bool supported = 0; - // 32 bit int (simple non-quantised test cases) - supported |= - (tensor_in.scalar_type() == ScalarType::Int && - handles.inputs->io[i].elem_size == 4); - // 8 bit int (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Char && - handles.inputs->io[i].elem_size == 1); - // 8 bit uint8 (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Byte && - handles.inputs->io[i].elem_size == 1); - // 16 bit int (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Short && - handles.inputs->io[i].elem_size == 2); - // bool (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Bool && - handles.inputs->io[i].elem_size == 1); - if (!supported) { - ET_LOG( - Error, - "Input %d expected Integer (4 byte), Char (1 byte) or Bool (1 byte) integer inputs, got ScalarType id %s size %d", - i, - executorch::runtime::toString(tensor_in.scalar_type()), - handles.inputs->io[i].elem_size); - return Error::InvalidProgram; - } - - // Select a compatible copy routine including checking for input layouts - // which require permutation. - bool both_int = tensor_in.scalar_type() == ScalarType::Int && - handles.inputs->io[i].elem_size == 4; - bool both_char = (tensor_in.scalar_type() == ScalarType::Char || - tensor_in.scalar_type() == ScalarType::Byte) && - handles.inputs->io[i].elem_size == 1; - bool both_short = tensor_in.scalar_type() == ScalarType::Short && - handles.inputs->io[i].elem_size == 2; - bool both_bool = tensor_in.scalar_type() == ScalarType::Bool && - (handles.inputs->io[i].elem_size == 1); - - if (both_char || both_int || both_short || both_bool) { - EXECUTORCH_PROF_SCOPE( - event_tracer, "+EthosUBackend::execute()handles.input.memcpy()"); - // Sizes match and elt size matches so memcpy. - // Routed through arm_ethos_io_memcpy so firmware can DMA-accelerate. - arm_ethos_io_memcpy( - scratch_addr, - tensor_in.mutable_data_ptr(), - tensor_in.nbytes()); - } else { - ET_LOG(Error, "No matching input copy routine"); - return Error::InvalidProgram; - } - calculate_dimensions( - tensor_in, &handles.inputs->io[i], &tensor_count, &io_count); - if (tensor_count != io_count) { - ET_LOG(Error, "Input tensor sizes do not match"); - ET_LOG( - Error, - "Program expects %d elements but got %d", - io_count, - tensor_count); - return Error::InvalidProgram; - } - } - - EXECUTORCH_PROF_START( - event_tracer, event_tracer_local_scope, "+EthosUBackend::execute()NPU"); - Error platform_status = platform_execute( - context, - execution_handle, - handles, - input_count, - output_count, - args, - ethosu_scratch); - EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); - return platform_status; - } - - void destroy(DelegateHandle* handle) const override { - if (handle == nullptr) { - return; - } - - // Explicitly destroy platform-specific state before releasing the - // execution handle to avoid leaking resources such as std::string. - auto* exec_handle = reinterpret_cast(handle); - - if (exec_handle->platform_state != nullptr) { - platform_destroy(exec_handle->platform_state); - } - - delete exec_handle; - } - - private: - // No platform-specific members. -}; - -Error copy_with_layout_adjustment( - const VelaIO& output_io, - int output_index, - const char* src, - executorch::aten::Tensor& tensor_out, - size_t tensor_bytes) { - const int elem_size = output_io.elem_size; - if (elem_size == 0) { - ET_LOG(Error, "Ethos-U output %d reports zero element size", output_index); - return Error::InvalidProgram; - } - - size_t chunk_count = 1; - for (int dim = 0; dim < shapeDim - 1; ++dim) { - const int vela_dim = output_io.shape[dim]; - chunk_count *= static_cast(vela_dim == 0 ? 1 : vela_dim); - } - const int last_dim = output_io.shape[shapeDim - 1]; - const size_t vela_chunk_elems = - static_cast(last_dim == 0 ? 1 : last_dim); - const size_t vela_chunk_size = - vela_chunk_elems * static_cast(elem_size); - - if (tensor_bytes % chunk_count != 0) { - ET_LOG( - Error, - "Ethos-U output %d tensor bytes %zu not divisible by chunk count %zu", - output_index, - tensor_bytes, - chunk_count); - return Error::InvalidProgram; - } - - const size_t chunk_size = tensor_bytes / chunk_count; - - // If Vela writes fewer bytes than the tensor expects we may need to - // expand 4-bit data to 8-bit. Ethos-U outputs may be - // packed 4-bit values but ExecuTorch tensors are at least 8-bit. - if (vela_chunk_size < chunk_size) { - if (chunk_size % vela_chunk_size != 0) { - ET_LOG( - Error, - "Ethos-U output %d chunk bytes %zu not divisible by vela chunk bytes %zu", - output_index, - chunk_size, - vela_chunk_size); - return Error::InvalidProgram; - } - - const size_t expand_factor = chunk_size / vela_chunk_size; - if (expand_factor == 2 && elem_size == 1 && - tensor_out.scalar_type() == ScalarType::Char) { - const uint8_t* src_bytes = reinterpret_cast(src); - int8_t* dest = tensor_out.mutable_data_ptr(); - const uint8_t* chunk_src = src_bytes; - int8_t* chunk_dest = dest; - for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { - for (size_t byte_idx = 0; byte_idx < vela_chunk_size; ++byte_idx) { - const uint8_t packed = chunk_src[byte_idx]; - int8_t low = static_cast(packed & 0x0F); - int8_t high = static_cast((packed >> 4) & 0x0F); - if (low >= 8) { - low -= 16; - } - if (high >= 8) { - high -= 16; - } - chunk_dest[2 * byte_idx] = low; - chunk_dest[2 * byte_idx + 1] = high; - } - chunk_src += vela_chunk_size; - chunk_dest += chunk_size; - } - return Error::Ok; - } - - ET_LOG( - Error, - "Ethos-U output %d expansion factor %zu with element size %d not supported", - output_index, - expand_factor, - elem_size); - return Error::InvalidProgram; - } - - if (src == nullptr) { - ET_LOG(Error, "Ethos-U padded copy received null buffer"); - return Error::InvalidState; - } - char* dest = tensor_out.mutable_data_ptr(); - if (dest == nullptr) { - ET_LOG(Error, "Ethos-U padded copy received null destination"); - return Error::InvalidState; - } - const char* src_bytes = src; - for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { - // Routed through arm_ethos_io_memcpy so firmware can DMA-accelerate. - arm_ethos_io_memcpy(dest, src_bytes, chunk_size); - src_bytes += vela_chunk_size; - dest += chunk_size; - } - return Error::Ok; -} - -void calculate_dimensions( - const executorch::aten::Tensor tensor, - VelaIO* io, - int* tensor_count, - int* io_count) { - for (int i = 0; i < tensor.dim(); i++) { - *tensor_count = *tensor_count * tensor.size(i); - } - - // The VelaIO type has a shape of fixed size 6 - for (int i = 0; i < shapeDim; i++) { - *io_count = *io_count * io->shape[i]; - } -} - -namespace { -auto EthosUBackend_backend = EthosUBackend(); -Backend EthosUBackend_id{"EthosUBackend", &EthosUBackend_backend}; -static executorch::runtime::Error EthosUBackend_registered = - register_backend(EthosUBackend_id); - -// DEPRECATED in Executorch 1.2 -// Remove it from your code and make sure to add this to your CMAKE rules -// instead: -// executorch_target_link_options_shared_lib(executorch_delegate_ethos_u) -extern "C" ET_DEPRECATED executorch::runtime::Error -executorch_delegate_EthosUBackend_registered() { - return EthosUBackend_registered; -} - -} // namespace - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_A.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_A.cpp deleted file mode 100644 index 5da0996..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_A.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Arm backend for Ethos-U Linux driver stack, this relies on the - * ethos-u-linux-driver-stack for hardware interaction. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -using executorch::runtime::ArrayRef; -using executorch::runtime::BackendExecutionContext; -using executorch::runtime::CompileSpec; -using executorch::runtime::Error; -using executorch::runtime::MemoryAllocator; -using executorch::runtime::Span; - -namespace executorch { -namespace backends { -namespace arm { - -constexpr int64_t kDefaultEthosUTimeoutNs = 60000000000LL; - -struct LinuxDriverOptions { - std::string device_path = "/dev/ethosu0"; - int64_t timeout_ns = kDefaultEthosUTimeoutNs; - bool enable_cycle_counter = true; - std::array pmu_events{}; -}; - -struct PlatformState { - LinuxDriverOptions options; -}; - -namespace { - -template -bool read_scalar_value(const CompileSpec& spec, T* out) { - if (spec.value.buffer == nullptr || spec.value.nbytes != sizeof(T)) { - return false; - } - std::memcpy(out, spec.value.buffer, sizeof(T)); - return true; -} - -std::string read_string_value(const CompileSpec& spec) { - if (spec.value.buffer == nullptr || spec.value.nbytes == 0) { - return ""; - } - const char* raw_begin = static_cast(spec.value.buffer); - const char* raw_end = raw_begin + spec.value.nbytes; - std::string result(raw_begin, raw_end); - while (!result.empty() && result.back() == '\0') { - result.pop_back(); - } - return result; -} - -LinuxDriverOptions parse_linux_options(ArrayRef specs) { - LinuxDriverOptions options; - constexpr char kDeviceKey[] = "ethosu.device"; - constexpr char kTimeoutKey[] = "ethosu.timeout_ns"; - constexpr char kCycleCounterKey[] = "ethosu.enable_cycle_counter"; - constexpr char kPmuPrefix[] = "ethosu.pmu_event"; - - for (const CompileSpec& spec : specs) { - if (spec.key == nullptr) { - continue; - } - - if (strcmp(spec.key, kDeviceKey) == 0) { - std::string device_path = read_string_value(spec); - if (!device_path.empty()) { - options.device_path = device_path; - } - continue; - } - - if (strcmp(spec.key, kTimeoutKey) == 0) { - int64_t timeout = 0; - if (read_scalar_value(spec, &timeout) && timeout > 0) { - options.timeout_ns = timeout; - } - continue; - } - - if (strcmp(spec.key, kCycleCounterKey) == 0) { - uint8_t enabled = 0; - if (read_scalar_value(spec, &enabled)) { - options.enable_cycle_counter = enabled != 0; - } - continue; - } - - if (strncmp(spec.key, kPmuPrefix, strlen(kPmuPrefix)) == 0) { - const char* index_str = spec.key + strlen(kPmuPrefix); - char* endptr = nullptr; - long idx = std::strtol(index_str, &endptr, 10); - if (endptr != index_str && idx >= 0 && - idx < static_cast(ETHOSU_PMU_EVENT_MAX)) { - uint32_t event = 0; - if (read_scalar_value(spec, &event)) { - options.pmu_events[static_cast(idx)] = event; - } - } - } - } - - return options; -} - -class EthosULinuxDeviceCache { - public: - EthosU::Device& get(const std::string& device_path) { - std::lock_guard lock(mutex_); - if (!device_ || device_path != active_path_) { - device_ = std::make_unique(device_path.c_str()); - active_path_ = device_path; - } - return *device_; - } - - private: - std::mutex mutex_; - std::string active_path_; - std::unique_ptr device_; -}; - -EthosULinuxDeviceCache& get_linux_device_cache() { - static EthosULinuxDeviceCache cache; - return cache; -} - -/* - * Used for logging when building in Debug mode, but unused building - * for Release. - */ -[[maybe_unused]] const char* inference_status_to_string( - EthosU::InferenceStatus status) { - switch (status) { - case EthosU::InferenceStatus::OK: - return "OK"; - case EthosU::InferenceStatus::ERROR: - return "ERROR"; - case EthosU::InferenceStatus::RUNNING: - return "RUNNING"; - case EthosU::InferenceStatus::REJECTED: - return "REJECTED"; - case EthosU::InferenceStatus::ABORTED: - return "ABORTED"; - case EthosU::InferenceStatus::ABORTING: - return "ABORTING"; - case EthosU::InferenceStatus::PENDING: - return "PENDING"; - } - return "UNKNOWN"; -} - -Error invoke_linux_driver( - const VelaHandles& handles, - const std::vector& input_ptrs, - const std::vector& output_ptrs, - const std::vector& input_copy_sizes, - const std::vector& output_copy_sizes, - const LinuxDriverOptions& options) { - if (handles.outputs == nullptr) { - ET_LOG(Error, "Ethos-U backend missing output metadata"); - return Error::InvalidProgram; - } - - try { - EthosU::Device& device = get_linux_device_cache().get(options.device_path); - auto network = std::make_shared( - device, - reinterpret_cast(handles.cmd_data), - handles.cmd_data_size); - - std::shared_ptr constant_buffer = - std::make_shared(); - if (handles.weight_data_size > 0) { - auto constant_buffers = device.createBuffers({handles.weight_data_size}); - constant_buffer = constant_buffers.front(); - constant_buffer->write( - const_cast(handles.weight_data), handles.weight_data_size); - } - - std::shared_ptr intermediate_buffer = - std::make_shared(); - if (handles.scratch_data_size > 0) { - auto scratch_buffers = device.createBuffers({handles.scratch_data_size}); - intermediate_buffer = scratch_buffers.front(); - } - - std::vector> ifm_buffers; - if (handles.inputs != nullptr && handles.inputs->count > 0) { - if (input_copy_sizes.size() != - static_cast(handles.inputs->count)) { - ET_LOG( - Error, - "Mismatch between input metadata (%d) and copy plan (%zu)", - handles.inputs->count, - input_copy_sizes.size()); - return Error::InvalidProgram; - } - if (input_ptrs.size() != input_copy_sizes.size()) { - ET_LOG( - Error, - "Mismatch between input metadata and runtime pointers (%zu vs %zu)", - input_ptrs.size(), - input_copy_sizes.size()); - return Error::InvalidState; - } - ifm_buffers = device.createBuffers(input_copy_sizes); - for (int i = 0; i < handles.inputs->count; ++i) { - const size_t copy_size = input_copy_sizes[i]; - if (copy_size == 0) { - continue; - } - const char* src = input_ptrs[i]; - if (src == nullptr) { - ET_LOG(Error, "Missing input buffer for index %d", i); - return Error::InvalidState; - } - ifm_buffers[i]->write(const_cast(src), copy_size); - } - } - - if (output_copy_sizes.size() != - static_cast(handles.outputs->count)) { - ET_LOG( - Error, - "Mismatch between output metadata (%d) and copy plan (%zu)", - handles.outputs->count, - output_copy_sizes.size()); - return Error::InvalidProgram; - } - if (output_ptrs.size() != output_copy_sizes.size()) { - ET_LOG( - Error, - "Mismatch between output metadata and runtime buffers (%zu vs %zu)", - output_ptrs.size(), - output_copy_sizes.size()); - return Error::InvalidState; - } - auto ofm_buffers = device.createBuffers(output_copy_sizes); - - auto inference = std::make_unique( - network, - ifm_buffers.begin(), - ifm_buffers.end(), - ofm_buffers.begin(), - ofm_buffers.end(), - intermediate_buffer, - constant_buffer, - options.pmu_events, - options.enable_cycle_counter); - - if (inference->wait(options.timeout_ns)) { - ET_LOG( - Error, - "Ethos-U inference timed out after %lld ns", - static_cast(options.timeout_ns)); - return Error::InvalidState; - } - - auto status = inference->status(); - if (status != EthosU::InferenceStatus::OK) { - ET_LOG( - Error, - "Ethos-U inference failed with status %s", - inference_status_to_string(status)); - return Error::InvalidState; - } - - if (options.enable_cycle_counter) { - try { - ET_LOG( - Info, - "Ethos-U Linux delegate cycle counter: %llu", - static_cast(inference->getCycleCounter())); - } catch (const std::exception& e) { - ET_LOG(Debug, "Failed to read Ethos-U cycle counter: %s", e.what()); - } - } - - for (int i = 0; i < handles.outputs->count; ++i) { - const size_t copy_size = output_copy_sizes[i]; - if (copy_size == 0) { - continue; - } - char* dst = output_ptrs[i]; - if (dst == nullptr) { - ET_LOG(Error, "Missing output buffer for index %d", i); - return Error::InvalidState; - } - ofm_buffers[i]->read(dst, copy_size); - } - } catch (const std::exception& e) { - ET_LOG(Error, "Ethos-U Linux driver invocation failed: %s", e.what()); - return Error::InvalidState; - } - - return Error::Ok; -} -} // namespace - -PlatformState* platform_init( - ArrayRef specs, - MemoryAllocator* allocator) { - (void)allocator; - PlatformState* state = new (std::nothrow) PlatformState(); - if (state == nullptr) { - return nullptr; - } - state->options = parse_linux_options(specs); - return state; -} - -void platform_destroy(PlatformState* state) { - delete state; -} - -Error platform_execute( - BackendExecutionContext& /*context*/, - const ExecutionHandle* execution_handle, - const VelaHandles& handles, - int input_count, - int output_count, - Span args, - char* /*ethosu_scratch*/) { - std::vector input_copy_sizes(input_count, 0); - std::vector linux_input_ptrs(input_count, nullptr); - - std::vector output_io_bytes(output_count, 0); - std::vector linux_output_ptrs(output_count, nullptr); - std::vector> output_scratch_buffers(output_count); - std::vector output_needs_adjustment(output_count, false); - - for (int i = 0; i < input_count; ++i) { - auto tensor_in = args[i]->toTensor(); - linux_input_ptrs[i] = tensor_in.const_data_ptr(); - input_copy_sizes[i] = tensor_in.nbytes(); - } - - if (handles.outputs != nullptr) { - for (int i = 0; i < output_count; ++i) { - int tensor_count = 1, io_count = 1; - auto tensor_out = args[input_count + i]->toTensor(); - calculate_dimensions( - tensor_out, &handles.outputs->io[i], &tensor_count, &io_count); - if (i < static_cast(output_io_bytes.size())) { - output_io_bytes[i] = static_cast(io_count) * - static_cast(handles.outputs->io[i].elem_size); - } - const size_t tensor_nbytes = tensor_out.nbytes(); - if (i < static_cast(output_io_bytes.size()) && - output_io_bytes[i] != tensor_nbytes) { - output_scratch_buffers[i].resize(output_io_bytes[i]); - linux_output_ptrs[i] = output_scratch_buffers[i].data(); - output_needs_adjustment[i] = true; - } else { - linux_output_ptrs[i] = tensor_out.mutable_data_ptr(); - } - } - } - - const PlatformState* state = execution_handle->platform_state; - if (state == nullptr) { - ET_LOG(Error, "Ethos-U Linux backend missing platform state"); - return Error::InvalidState; - } - - Error status = invoke_linux_driver( - handles, - linux_input_ptrs, - linux_output_ptrs, - input_copy_sizes, - output_io_bytes, - state->options); - if (status != Error::Ok) { - return status; - } - - if (handles.outputs != nullptr) { - for (int i = 0; i < output_count; ++i) { - if (!output_needs_adjustment[i]) { - continue; - } - auto tensor_out = args[input_count + i]->toTensor(); - const size_t tensor_nbytes = tensor_out.nbytes(); - Error adjust_status = copy_with_layout_adjustment( - handles.outputs->io[i], - i, - output_scratch_buffers[i].data(), - tensor_out, - tensor_nbytes); - if (adjust_status != Error::Ok) { - return adjust_status; - } - } - } - - return Error::Ok; -} - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_M.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_M.cpp deleted file mode 100644 index 9639876..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Cortex_M.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Arm backend for Ethos-U baremetal driver stack, this relies on the - * ethos-u-core-driver for hardware interaction. - */ - -#include -#include -#include -#include - -#include - -#include -#include - -using executorch::runtime::BackendExecutionContext; -using executorch::runtime::Error; -using executorch::runtime::Span; - -// Compatibility hooks for multi-device driver / non-multi-device driver code -// When multi-device driver code is available, these declarations are overridden -extern "C" __attribute__((weak)) int ethosu_get_product_config_from_cop_data( - const void*, - const int, - uint32_t* product_out, - uint32_t* log2_macs_out) { - *product_out = 0; - *log2_macs_out = 0; - return 0; -} - -extern "C" __attribute__((weak)) struct ethosu_driver* ethosu_reserve_driver_ex( - uint32_t, - uint32_t) { - return ethosu_reserve_driver(); -} - -// Overridable memcpy used by the EthosU backend for output scratch -// shuffling. Default (weak) implementation in EthosUBackend_IoMemcpy.cpp does -// std::memcpy. Firmware targets can supply a strong override (e.g. routing -// through a DMA engine) to reduce CPU memcpy load on the host MCU. -extern "C" void arm_ethos_io_memcpy(void* dst, const void* src, size_t size); - -namespace executorch { -namespace backends { -namespace arm { - -struct PlatformState {}; - -PlatformState* platform_init( - executorch::runtime::ArrayRef /*specs*/, - executorch::runtime::MemoryAllocator* /*allocator*/) { - return nullptr; -} - -void platform_destroy(PlatformState* state) { - delete state; -} - -Error platform_execute( - BackendExecutionContext& /*context*/, - const ExecutionHandle* /*execution_handle*/, - const VelaHandles& handles, - int input_count, - int output_count, - Span args, - char* ethosu_scratch) { - // Parse product config from command stream to reserve the correct driver - uint32_t product, log2_macs; - // The weak fallback below always returns 0, but some builds replace it - // with a real driver implementation that can return an error code. - const int product_config_status = ethosu_get_product_config_from_cop_data( - handles.cmd_data, handles.cmd_data_size, &product, &log2_macs); - if (product_config_status != 0) { // cppcheck-suppress knownConditionTrueFalse - ET_LOG(Error, "Failed to parse product config from command stream"); - return Error::InvalidProgram; - } - - // Allocate driver handle and synchronously invoke driver - auto driver = - std::unique_ptr( - ethosu_reserve_driver_ex(product, log2_macs), ethosu_release_driver); - if (driver == nullptr) { - ET_LOG(Error, "ethosu_reserve_driver_ex failed"); - return Error::InvalidState; - } - - // Ethos-U low level driver expected order for Ethos U-55, we have - // constant weight data, then scratch (which contains input and output) - // scratch is written above in this function. - uint64_t bases[ETHOSU_NUM_BASE_ADDRS] = { - static_cast(reinterpret_cast((handles.weight_data))), - static_cast(reinterpret_cast(ethosu_scratch)), - static_cast(reinterpret_cast(ethosu_fast_scratch))}; - size_t bases_size[ETHOSU_NUM_BASE_ADDRS] = { - handles.weight_data_size, - handles.scratch_data_size, - ethosu_fast_scratch_size}; - int result = ethosu_invoke_v3( - driver.get(), - static_cast(handles.cmd_data), - handles.cmd_data_size, - bases, - bases_size, - ETHOSU_NUM_BASE_ADDRS, /* fixed array of pointers to binary interface*/ - nullptr); - - if (result != 0) { - ET_LOG(Error, "Ethos-U invocation failed error (%d)", result); - return Error::InvalidProgram; - } - - size_t tensor_bytes_total = 0; - size_t io_bytes_total = 0; - // Write outputs from scratch into EValue pointers - for (int i = 0; i < output_count; i++) { - int tensor_count = 1, io_count = 1; - const char* output_addr = ethosu_scratch + handles.outputs->io[i].offset; - // Process input EValue into scratch - // Outputs are in the index immediately after inputs - auto tensor_out = args[input_count + i]->toTensor(); - - calculate_dimensions( - tensor_out, &handles.outputs->io[i], &tensor_count, &io_count); - - size_t tensor_bytes = tensor_out.nbytes(); - size_t io_bytes = static_cast(io_count) * - static_cast(handles.outputs->io[i].elem_size); - - if (tensor_bytes != io_bytes) { - Error status = copy_with_layout_adjustment( - handles.outputs->io[i], i, output_addr, tensor_out, tensor_bytes); - if (status != Error::Ok) { - return status; - } - io_bytes_total += tensor_bytes; - } else { - // Routed through arm_ethos_io_memcpy so firmware can DMA-accelerate. - arm_ethos_io_memcpy( - tensor_out.mutable_data_ptr(), - static_cast(output_addr), - tensor_bytes); - io_bytes_total += io_bytes; - } - - // At times the topological order of the outputs may change. - // Lets instead ensure that the sum of output bytes match. - tensor_bytes_total += tensor_bytes; - } - if (tensor_bytes_total != io_bytes_total) { - ET_LOG(Error, "Total output tensor sizes do not match"); - ET_LOG( - Error, - "Program expects %zu bytes but got %zu", - io_bytes_total, - tensor_bytes_total); - return Error::InvalidProgram; - } - return Error::Ok; -} - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Internal.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Internal.h deleted file mode 100644 index f3b05fa..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_Internal.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -// Workaround for runtime/core/portable_type/c10/c10/util/Float16-math.h -#if defined(__GNUC__) && defined(__ZEPHYR__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdouble-promotion" -#endif - -#include -#include - -#include -#include -#include -#include - -#if defined(__GNUC__) && defined(__ZEPHYR__) -#pragma GCC diagnostic pop -#endif - -#if defined(ET_EVENT_TRACER_ENABLED) -#include -#include -using executorch::runtime::EventTracer; -using executorch::runtime::EventTracerEntry; - -class EventTraceScope { - public: - EventTraceScope(EventTracer* event_tracer_, const char* name) { - event_tracer = event_tracer_; - event_tracer_entry_scope = event_tracer->start_profiling(name); - } - ~EventTraceScope() { - event_tracer->end_profiling(event_tracer_entry_scope); - } - - private: - EventTracer* event_tracer; - EventTracerEntry event_tracer_entry_scope; -}; -#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) \ - EventTraceScope event_tracer_scope = EventTraceScope(EVENTTRACER, NAME) -#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) \ - SCOPE = EVENTTRACER->start_profiling(NAME) -#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) \ - EVENTTRACER->end_profiling(SCOPE) -#else -#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) -#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) -#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) -#endif - -#define ETHOSU_NUM_BASE_ADDRS 3 - -namespace executorch { -namespace backends { -namespace arm { - -struct PlatformState; - -struct ExecutionHandle { - executorch::runtime::FreeableBuffer* processed; - PlatformState* platform_state; -}; - -extern "C" { -void EthosUBackend_execute_begin(); -void EthosUBackend_execute_end(); -extern unsigned char* ethosu_fast_scratch; -extern size_t ethosu_fast_scratch_size; -} - -PlatformState* platform_init( - executorch::runtime::ArrayRef specs, - executorch::runtime::MemoryAllocator* allocator); -void platform_destroy(PlatformState* state); -executorch::runtime::Error platform_execute( - executorch::runtime::BackendExecutionContext& context, - const ExecutionHandle* execution_handle, - const VelaHandles& handles, - int input_count, - int output_count, - executorch::runtime::Span args, - char* ethosu_scratch); - -executorch::runtime::Error copy_with_layout_adjustment( - const VelaIO& output_io, - int output_index, - const char* src, - executorch::aten::Tensor& tensor_out, - size_t tensor_bytes); - -void calculate_dimensions( - const executorch::aten::Tensor tensor, - VelaIO* io, - int* tensor_count, - int* io_count); - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp deleted file mode 100644 index 1ef5b74..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -// Weak default for arm_ethos_io_memcpy. Firmware targets can provide a -// strong-symbol override (e.g. routing through DMA on Cortex-M55) without -// touching the upstream EthosUBackend code. Lives in its own translation -// unit so the compiler in the call-site TUs cannot inline this body and -// bypass the link-time override (same trick as bolt_arm_memcpy_external). -extern "C" __attribute__((weak)) void -arm_ethos_io_memcpy(void* dst, const void* src, size_t size) { - std::memcpy(dst, src, size); -} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h deleted file mode 100644 index 4c0f83d..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/cortex_m_ops_common.h +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "arm_nn_types.h" -#include "arm_nnfunctions.h" - -using Tensor = torch::executor::Tensor; -using ScalarType = executorch::aten::ScalarType; -using Error = executorch::runtime::Error; -using Int64ArrayRef = executorch::aten::ArrayRef; -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -// From arm_nn_math_types.h -#define ARM_NN_Q31_MAX ((int32_t)(0x7FFFFFFFL)) -#define ARM_NN_Q31_MIN ((int32_t)(0x80000000L)) - -// 16-byte alignment for MVE vector operations. -constexpr size_t kCortexMMveAlignment = 16; - -// Basic tensor type / layout validation and dimension order checking -inline void validate_cmsis_nn_tensor_requirements( - const Tensor& input1, - const Tensor& input2, - Tensor& output, - ScalarType expected_dtype = ScalarType::Char, - bool require_channels_last = false, - bool require_same_sizes = true) { - // Basic dtype validation - ET_CHECK_MSG( - input1.scalar_type() == expected_dtype, - "Input1 dtype must be %d, got %d", - static_cast(expected_dtype), - static_cast(input1.scalar_type())); - ET_CHECK_MSG( - input2.scalar_type() == expected_dtype, - "Input2 dtype must be %d, got %d", - static_cast(expected_dtype), - static_cast(input2.scalar_type())); - ET_CHECK_MSG( - output.scalar_type() == expected_dtype, - "Output dtype must be %d, got %d", - static_cast(expected_dtype), - static_cast(output.scalar_type())); - if (require_same_sizes) { - ET_CHECK_MSG( - input1.sizes() == input2.sizes(), - "Input1 and Input2 must have the same sizes"); - ET_CHECK_MSG( - output.sizes() == input1.sizes(), - "Output must have the same sizes as inputs"); - } - - // TBD (#16032): Validate dim_order - // TBD: Validate memory alignment (CMSIS-NN requirement) -} - -inline void validate_single_quant_params( - const int64_t zero_point, - const int64_t multiplier, - const int64_t shift, - const char* param_name) { - (void)zero_point; - ET_CHECK_MSG( - multiplier >= std::numeric_limits::min() && - multiplier <= std::numeric_limits::max(), - "%s multiplier must be in int32 range [Value: %" PRIi64 "]", - param_name, - multiplier); - - ET_CHECK_MSG( - shift >= -31 && shift <= 31, - "%s shift must be in range [-31, 31] [Value: %" PRIi64 "]", - param_name, - shift); -} - -/** - * Validate quantization parameters for inputs and output. - * - * Checks that zero points fit in int8 range, multipliers fit in int32 range, - * and shifts are within a valid bit-shift range (0-31). - * - * Ensures parameters comply with Ahead-Of-Time (AOT) quantization requirements - * and CMSIS-NN kernel expectations. - * - * Raises errors via ET_KERNEL_CHECK if any check fails. - */ -inline void validate_quantization_params( - const int64_t zero_point1, - const int64_t multiplier1, - const int64_t shift1, - const int64_t zero_point2, - const int64_t multiplier2, - const int64_t shift2, - const int64_t output_zero_point, - const int64_t output_multiplier, - const int64_t output_shift, - Tensor& output) { - validate_single_quant_params( - zero_point1, multiplier1, shift1, "Single quant Input1"); - validate_single_quant_params( - zero_point2, multiplier2, shift2, "Single quant Input2"); - validate_single_quant_params( - output_zero_point, - output_multiplier, - output_shift, - "Single quant Output"); -} - -inline bool is_channels_last_tensor(const Tensor& tensor) { - if (tensor.dim() != 4) { - return false; - } - - // When channels or spatial dims are 1 the layout information is ambiguous. - if (tensor.size(1) == 1 || (tensor.size(2) == 1 && tensor.size(3) == 1)) { - return true; - } - - constexpr executorch::aten::DimOrderType kChannelsLastDimOrder[] = { - 0, 2, 3, 1}; - executorch::aten::ArrayRef - channels_last_order(kChannelsLastDimOrder, 4); - - return tensor.dim_order() == channels_last_order; -} - -inline bool is_channel_broadcast(const Tensor& tensor1, const Tensor& tensor2) { - if (tensor1.dim() != tensor2.dim()) { - return false; - } - - if (tensor1.dim() != 4) { - return false; - } - - if (tensor1.size(1) != tensor2.size(1)) { - return false; - } - - const bool tensor1_channels_only = tensor1.numel() == tensor1.size(1); - const bool tensor2_channels_only = tensor2.numel() == tensor2.size(1); - - return tensor1_channels_only || tensor2_channels_only; -} - -inline bool check_int32_within_range( - KernelRuntimeContext& context, - const char* op_name, - int64_t value, - const char* value_name, - int32_t& out_value) { - if (value < std::numeric_limits::min() || - value > std::numeric_limits::max()) { - ET_LOG( - Error, - "%s: %s value (%" PRIi64 ") exceeds int32_t range", - op_name, - value_name, - value); - context.fail(Error::InvalidArgument); - return false; - } - out_value = static_cast(value); - return true; -} - -struct CmsisPool2DConfig { - cmsis_nn_pool_params pool_params; - cmsis_nn_dims input_dims; - cmsis_nn_dims filter_dims; - cmsis_nn_dims output_dims; -}; - -inline bool prepare_cmsis_pool2d_config( - KernelRuntimeContext& context, - const char* op_name, - const Tensor& input, - Tensor& output, - const Int64ArrayRef& kernel_size, - const Int64ArrayRef& stride, - const Int64ArrayRef& padding, - const Int64ArrayRef& dilation, - bool ceil_mode, - int64_t activation_min, - int64_t activation_max, - CmsisPool2DConfig& config, - bool require_channels_last = true, - bool allow_ceil_mode = false) { - if (input.dim() != 4 || output.dim() != 4) { - ET_LOG(Error, "%s: tensors must be 4-D", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (input.scalar_type() != ScalarType::Char || - output.scalar_type() != ScalarType::Char) { - ET_LOG(Error, "%s: tensors must be int8", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (input.size(0) != output.size(0) || input.size(1) != output.size(1)) { - ET_LOG( - Error, - "%s: batch and channel dimensions must match between input and output", - op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (require_channels_last) { - if (!is_channels_last_tensor(input) || !is_channels_last_tensor(output)) { - ET_LOG( - Error, "%s: tensors must use channels_last dimension order", op_name); - context.fail(Error::InvalidArgument); - return false; - } - } - - auto check_tuple_len = [&](const Int64ArrayRef& arr, - const char* name) -> bool { - if (arr.size() != 2) { - ET_LOG(Error, "%s: %s must have length 2", op_name, name); - context.fail(Error::InvalidArgument); - return false; - } - return true; - }; - - if (!check_tuple_len(kernel_size, "kernel_size") || - !check_tuple_len(stride, "stride") || - !check_tuple_len(padding, "padding") || - !check_tuple_len(dilation, "dilation")) { - return false; - } - - if (!allow_ceil_mode && ceil_mode) { - ET_LOG(Error, "%s: ceil_mode=True is not supported", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (activation_min > activation_max) { - ET_LOG( - Error, - "%s: activation_min (%lld) must be <= activation_max (%lld)", - op_name, - static_cast(activation_min), - static_cast(activation_max)); - context.fail(Error::InvalidArgument); - return false; - } - - int32_t activation_min_i32, activation_max_i32; - if (!check_int32_within_range( - context, - op_name, - activation_min, - "activation_min", - activation_min_i32) || - !check_int32_within_range( - context, - op_name, - activation_max, - "activation_max", - activation_max_i32)) { - return false; - } - - int32_t kernel_h, kernel_w, stride_h, stride_w, pad_h, pad_w, dil_h, dil_w; - if (!check_int32_within_range( - context, op_name, kernel_size[0], "kernel_size[0]", kernel_h) || - !check_int32_within_range( - context, op_name, kernel_size[1], "kernel_size[1]", kernel_w) || - !check_int32_within_range( - context, op_name, stride[0], "stride[0]", stride_h) || - !check_int32_within_range( - context, op_name, stride[1], "stride[1]", stride_w) || - !check_int32_within_range( - context, op_name, padding[0], "padding[0]", pad_h) || - !check_int32_within_range( - context, op_name, padding[1], "padding[1]", pad_w) || - !check_int32_within_range( - context, op_name, dilation[0], "dilation[0]", dil_h) || - !check_int32_within_range( - context, op_name, dilation[1], "dilation[1]", dil_w)) { - return false; - } - - if (dil_h != 1 || dil_w != 1) { - ET_LOG(Error, "%s: dilation other than 1 is unsupported", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - int32_t batch, channels, input_h, input_w, output_h, output_w; - if (!check_int32_within_range( - context, op_name, input.size(0), "input batch", batch) || - !check_int32_within_range( - context, op_name, input.size(1), "input channels", channels) || - !check_int32_within_range( - context, op_name, input.size(2), "input height", input_h) || - !check_int32_within_range( - context, op_name, input.size(3), "input width", input_w) || - !check_int32_within_range( - context, op_name, output.size(2), "output height", output_h) || - !check_int32_within_range( - context, op_name, output.size(3), "output width", output_w)) { - return false; - } - - config.input_dims = cmsis_nn_dims{batch, input_h, input_w, channels}; - config.filter_dims = cmsis_nn_dims{1, kernel_h, kernel_w, 1}; - config.output_dims = cmsis_nn_dims{batch, output_h, output_w, channels}; - config.pool_params.padding.h = pad_h; - config.pool_params.padding.w = pad_w; - config.pool_params.stride.h = stride_h; - config.pool_params.stride.w = stride_w; - config.pool_params.activation.min = activation_min_i32; - config.pool_params.activation.max = activation_max_i32; - - return true; -} - -// Refer to CMSIS-NN 'arm_nn_requantize' implementation for details: -// https://github.com/ARM-software/CMSIS-NN/blob/main/Include/arm_nnsupportfunctions.h#L1625 -// multiplier: Range {ARM_NN_Q31_MIN + 1, Q32_MAX} -// shift : Range {-31, 30} -inline bool validate_per_channel_quant_params( - const Int64ArrayRef multipliers, - const Int64ArrayRef shifts, - int num_channels) { - for (int i = 0; i < num_channels; ++i) { - // Multiplier: {ARM_NN_Q31_MIN + 1, ARM_NN_Q31_MAX} - if (multipliers[i] <= ARM_NN_Q31_MIN || multipliers[i] > ARM_NN_Q31_MAX) { - ET_LOG( - Error, - "weight_multiplier[%d] out of CMSIS-NN range: %" PRIi64, - i, - multipliers[i]); - return false; - } - // Shift: {-31, 30} for arm_nn_requantize - if (shifts[i] < -31 || shifts[i] > 30) { - ET_LOG(Error, "weight_shift[%d] out of range: %" PRIi64, i, shifts[i]); - return false; - } - } - return true; -} - -inline Error resize_to_broadcast_target_size( - const Tensor& input1, - const Tensor& input2, - Tensor& output) { - static constexpr int kTensorDimensionLimit = 5; - Tensor::SizesType expected_output_size[kTensorDimensionLimit]; - size_t expected_output_dim = 0; - auto err = torch::executor::get_broadcast_target_size( - input1, - input2, - expected_output_size, - kTensorDimensionLimit, - &expected_output_dim); - - if (err != Error::Ok) - return err; - - return executorch::runtime::resize_tensor( - output, {expected_output_size, expected_output_dim}); -} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp deleted file mode 100644 index ca648f7..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_dequantize_per_tensor.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -// Check for Helium/MVE support -#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) -#include -#define HAS_HELIUM_SIMD 1 -#endif - -namespace cortex_m { -namespace native { - -using Tensor = executorch::aten::Tensor; -using ScalarType = executorch::aten::ScalarType; -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -/** - * Asserts that the parameters are valid for int8/int16 to float dequantization. - */ -void check_dequantize_args( - const Tensor& input, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // dtype must be Char (int8) or Short (int16) - ET_CHECK_MSG( - dtype == ScalarType::Char || dtype == ScalarType::Short, - "dtype %" PRId8 " is not int8 (Char) or int16 (Short)", - static_cast(dtype)); - - // Input scalar type must match dtype - ET_CHECK_MSG( - input.scalar_type() == dtype, - "input.scalar_type() %" PRId8 " does not match dtype %" PRId8, - static_cast(input.scalar_type()), - static_cast(dtype)); - - // Check zp range - ET_CHECK_MSG( - zero_point >= quant_min, - "zero_point must be %" PRId64 " <= quant_min %" PRId64, - zero_point, - quant_min); - ET_CHECK_MSG( - zero_point <= quant_max, - "zero_point must be %" PRId64 " >= quant_max %" PRId64, - zero_point, - quant_max); - - // Check output dtype is float - ET_CHECK_MSG( - out.scalar_type() == ScalarType::Float, - "out.scalar_type() %" PRId8 " is not float", - static_cast(out.scalar_type())); - - // Validate quant_min and quant_max bounds per dtype - int32_t quant_min_lower_bound, quant_max_upper_bound; - if (dtype == ScalarType::Char) { - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } else { // Short - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } - - ET_CHECK_MSG( - quant_min >= quant_min_lower_bound, - "quant_min out of bound, expected quant_min_lower_bound: %" PRId32 - " actual quant_min: %" PRId64, - quant_min_lower_bound, - quant_min); - - ET_CHECK_MSG( - quant_max <= quant_max_upper_bound, - "quant_max out of bound, expected quant_max_upper_bound: %" PRId32 - " actual quant_max: %" PRId64, - quant_max_upper_bound, - quant_max); -} - -/** - * Scalar implementation of quantization for a single value. - */ -template -F dequantize_val(float scale, int32_t zero_point, Q qvalue) { - return static_cast((static_cast(qvalue) - zero_point) * scale); -} -} // namespace - -Tensor& dequantize_per_tensor_out( - KernelRuntimeContext& context, - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // Ignore context for now - (void)context; - - // Resize output tensor to match input dimensions - torch::executor::Error err = resize_tensor(out, input.sizes()); - ET_CHECK_MSG( - err == torch::executor::Error::Ok, - "Failed to resize out Tensor in dequantize_per_tensor_out"); - - // Validate input parameters - check_dequantize_args(input, zero_point, quant_min, quant_max, dtype, out); - - int32_t zp = static_cast(zero_point); - - // Get pointer to output data - float* out_data = out.mutable_data_ptr(); - const size_t numel = input.numel(); - - size_t i = 0; - - if (dtype == ScalarType::Char) { - const int8_t* input_data = input.const_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for int8 to float quantization - static uint8x16_t voffset{ - 0x0, - 0x8, - 0x4, - 0xC, - 0x1, - 0x9, - 0x5, - 0xD, - 0x2, - 0xA, - 0x6, - 0xE, - 0x3, - 0xB, - 0x7, - 0xF}; - - int16x8_t vzp = vdupq_n_s16(static_cast(zp)); - float32x4_t vscale = vdupq_n_f32(static_cast(scale)); - - for (; i + 15 < numel; i += 16) { - int8x16_t in_084C195D2A6E3B7F = - vldrbq_gather_offset_s8(input_data, voffset); - - int16x8_t in_04152637 = vsubq_s16(vmovlbq_s8(in_084C195D2A6E3B7F), vzp); - int16x8_t in_8C9DAEBF = vsubq_s16(vmovltq_s8(in_084C195D2A6E3B7F), vzp); - - float32x4_t inf_0123 = vcvtq_f32_s32(vmovlbq_s16(in_04152637)); - float32x4_t inf_4567 = vcvtq_f32_s32(vmovltq_s16(in_04152637)); - float32x4_t inf_89AB = vcvtq_f32_s32(vmovlbq_s16(in_8C9DAEBF)); - float32x4_t inf_CDEF = vcvtq_f32_s32(vmovltq_s16(in_8C9DAEBF)); - - float32x4_t out_0123 = vmulq_f32(inf_0123, vscale); - float32x4_t out_4567 = vmulq_f32(inf_4567, vscale); - float32x4_t out_89AB = vmulq_f32(inf_89AB, vscale); - float32x4_t out_CDEF = vmulq_f32(inf_CDEF, vscale); - - vstrwq_f32(out_data + 0, out_0123); - vstrwq_f32(out_data + 4, out_4567); - vstrwq_f32(out_data + 8, out_89AB); - vstrwq_f32(out_data + 12, out_CDEF); - - input_data += 16; - out_data += 16; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = dequantize_val(scale, zp, *input_data); - input_data++; - out_data++; - } - } else { // ScalarType::Short — int16 input - const int16_t* input_data = input.const_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for int16 to float dequantization, processing - // 8 elements per iteration. Mirrors the int8 byte-gather trick at halfword - // granularity: the gather pattern {0,4,1,5,2,6,3,7} arranges int16 lanes - // so that vmovlbq/vmovltq_s16 (which read even/odd lanes of int16x8 - // widened to int32x4) yield sequential values, allowing a sequential - // vstrwq_f32 store. - static uint16x8_t voffset_h{0, 4, 1, 5, 2, 6, 3, 7}; - - int32x4_t vzp = vdupq_n_s32(zp); - float32x4_t vscale = vdupq_n_f32(static_cast(scale)); - - for (; i + 7 < numel; i += 8) { - int16x8_t in_04152637 = - vldrhq_gather_shifted_offset_s16(input_data, voffset_h); - - int32x4_t in_0123 = vsubq_s32(vmovlbq_s16(in_04152637), vzp); - int32x4_t in_4567 = vsubq_s32(vmovltq_s16(in_04152637), vzp); - - float32x4_t out_0123 = vmulq_f32(vcvtq_f32_s32(in_0123), vscale); - float32x4_t out_4567 = vmulq_f32(vcvtq_f32_s32(in_4567), vscale); - - vstrwq_f32(out_data + 0, out_0123); - vstrwq_f32(out_data + 4, out_4567); - - input_data += 8; - out_data += 8; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = dequantize_val(scale, zp, *input_data); - input_data++; - out_data++; - } - } - return out; -} - -Tensor& dequantize_per_tensor_out( - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - KernelRuntimeContext context; - return dequantize_per_tensor_out( - context, input, scale, zero_point, quant_min, quant_max, dtype, out); -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_pad.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_pad.cpp deleted file mode 100644 index e59f986..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_pad.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -constexpr size_t kMaxSupportedDims = 4; - -} // namespace - -Tensor& pad_out( - KernelRuntimeContext& context, - const Tensor& input, - const Int64ArrayRef pre_pad, - const Int64ArrayRef post_pad, - int64_t pad_value, - Tensor& out) { - if (input.scalar_type() != ScalarType::Char || - out.scalar_type() != ScalarType::Char) { - ET_LOG( - Error, - "pad_out: only int8 tensors are supported (input=%d, out=%d)", - static_cast(input.scalar_type()), - static_cast(out.scalar_type())); - context.fail(Error::InvalidArgument); - return out; - } - - const size_t rank = input.dim(); - if (rank == 0 || rank > kMaxSupportedDims) { - ET_LOG( - Error, - "pad_out: expected tensor rank in [1, %zu], got %zu", - kMaxSupportedDims, - rank); - context.fail(Error::InvalidArgument); - return out; - } - - // Permute logical sizes to physical memory order. - // Padding is already in physical order from the AOT pass. - constexpr size_t kNhwcDimOrder[] = {0, 2, 3, 1}; - const size_t offset = kMaxSupportedDims - rank; - const bool nhwc = is_channels_last_tensor(input); - - int32_t dims[kMaxSupportedDims] = {1, 1, 1, 1}; - for (size_t i = 0; i < rank; ++i) { - const size_t src = nhwc ? kNhwcDimOrder[offset + i] : i; - dims[offset + i] = static_cast(input.size(src)); - } - - cmsis_nn_dims input_dims = {dims[0], dims[1], dims[2], dims[3]}; - cmsis_nn_dims cmsis_pre_pad = { - static_cast(pre_pad[0]), - static_cast(pre_pad[1]), - static_cast(pre_pad[2]), - static_cast(pre_pad[3])}; - cmsis_nn_dims cmsis_post_pad = { - static_cast(post_pad[0]), - static_cast(post_pad[1]), - static_cast(post_pad[2]), - static_cast(post_pad[3])}; - - const int8_t* input_data = input.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - - const arm_cmsis_nn_status status = arm_pad_s8( - input_data, - output_data, - static_cast(pad_value), - &input_dims, - &cmsis_pre_pad, - &cmsis_post_pad); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "pad_out: arm_pad_s8 failed with status [%d]", - static_cast(status)); - context.fail(Error::Internal); - return out; - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp deleted file mode 100644 index 7809db3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantize_per_tensor.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -// Check for Helium/MVE support -#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) -#include -#define HAS_HELIUM_SIMD 1 -#endif - -namespace cortex_m { -namespace native { - -using Tensor = executorch::aten::Tensor; -using ScalarType = executorch::aten::ScalarType; -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -/** - * Asserts that the parameters are valid for float to int8/int16 quantization. - */ -void check_quantize_args( - const Tensor& input, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // Ensure input is float type - ET_CHECK_MSG( - input.scalar_type() == ScalarType::Float, - "input.scalar_type() %" PRId8 " is not float type", - static_cast(input.scalar_type())); - - // Check output dtype matches dtype param (Char/int8 or Short/int16) - ET_CHECK_MSG( - dtype == ScalarType::Char || dtype == ScalarType::Short, - "dtype %" PRId8 " is not int8 (Char) or int16 (Short)", - static_cast(dtype)); - ET_CHECK_MSG( - out.scalar_type() == dtype, - "out.scalar_type() %" PRId8 " does not match dtype %" PRId8, - static_cast(out.scalar_type()), - static_cast(dtype)); - - // Validate quant_min and quant_max bounds per dtype - int32_t quant_min_lower_bound, quant_max_upper_bound; - if (dtype == ScalarType::Char) { - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } else { // Short - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } - - ET_CHECK_MSG( - quant_min >= quant_min_lower_bound, - "quant_min out of bound, expected quant_min_lower_bound: %" PRId32 - " actual quant_min: %" PRId64, - quant_min_lower_bound, - quant_min); - - ET_CHECK_MSG( - quant_max <= quant_max_upper_bound, - "quant_max out of bound, expected quant_max_upper_bound: %" PRId32 - " actual quant_max: %" PRId64, - quant_max_upper_bound, - quant_max); -} - -/** - * Scalar implementation of quantization for a single value. - */ -template -Q quantize_val( - F inv_scale, - int32_t zero_point, - F value, - int64_t quant_min, - int64_t quant_max) { - int32_t qvalue = - zero_point + static_cast(std::nearbyint(inv_scale * value)); - qvalue = std::max(qvalue, static_cast(quant_min)); - qvalue = std::min(qvalue, static_cast(quant_max)); - return static_cast(qvalue); -} - -} // namespace - -Tensor& quantize_per_tensor_out( - KernelRuntimeContext& context, - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // Ignore context for now - (void)context; - - // Resize output tensor to match input dimensions - torch::executor::Error err = resize_tensor(out, input.sizes()); - ET_CHECK_MSG( - err == torch::executor::Error::Ok, - "Failed to resize out Tensor in quantize_per_tensor_out"); - - // Validate input parameters - check_quantize_args(input, quant_min, quant_max, dtype, out); - - // Pre-compute inverse scale for better performance - float inv_scale = 1.0f / static_cast(scale); - int32_t zp = static_cast(zero_point); - int32_t qmin = static_cast(quant_min); - int32_t qmax = static_cast(quant_max); - - // Get pointers to input and output data - const float* input_data = input.const_data_ptr(); - const size_t numel = input.numel(); - - size_t i = 0; - - if (dtype == ScalarType::Char) { - int8_t* out_data = out.mutable_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for float32 to int8 quantization - static uint8x16_t voffset{ - 0x0, - 0x8, - 0x4, - 0xC, - 0x1, - 0x9, - 0x5, - 0xD, - 0x2, - 0xA, - 0x6, - 0xE, - 0x3, - 0xB, - 0x7, - 0xF}; - - float32x4_t inv_scale_vec = vdupq_n_f32(inv_scale); - - // Magic number for float to int conversion, round to nearest even integer - // int magic_round(float f): interpret_as_int32(f + magic_float) - magic_int - // where, - // magic_float = 12582912.0f = (2 ** 23 + 2 ** 22) = (1.5 * 2 ** 23) - // magic_int = 1262485504 = 0x4B400000 = - // bit_pattern_as_int32(magic_float) - - float magic_float = 12582912.0f; - int32_t magic_int = 1262485504; - - float32x4_t vmagic_float = vdupq_n_f32(magic_float); - int32x4_t vmagic_int_less_zp = - vdupq_n_s32(magic_int - static_cast(zp)); - - int16x8_t vqmin = vdupq_n_s16(qmin); - int16x8_t vqmax = vdupq_n_s16(qmax); - - // TODO: Measure performnce, we are spilling - for (; i + 15 < numel; i += 16) { - float32x4_t in_0123 = vldrwq_f32(input_data + 0); - float32x4_t in_4567 = vldrwq_f32(input_data + 4); - float32x4_t in_89AB = vldrwq_f32(input_data + 8); - float32x4_t in_CDEF = vldrwq_f32(input_data + 12); - - float32x4_t outf_0123 = vfmaq_f32(vmagic_float, in_0123, inv_scale_vec); - float32x4_t outf_4567 = vfmaq_f32(vmagic_float, in_4567, inv_scale_vec); - float32x4_t outf_89AB = vfmaq_f32(vmagic_float, in_89AB, inv_scale_vec); - float32x4_t outf_CDEF = vfmaq_f32(vmagic_float, in_CDEF, inv_scale_vec); - - int32x4_t out_0123 = - vsubq_s32(vreinterpretq_s32_f32(outf_0123), vmagic_int_less_zp); - int32x4_t out_4567 = - vsubq_s32(vreinterpretq_s32_f32(outf_4567), vmagic_int_less_zp); - int32x4_t out_89AB = - vsubq_s32(vreinterpretq_s32_f32(outf_89AB), vmagic_int_less_zp); - int32x4_t out_CDEF = - vsubq_s32(vreinterpretq_s32_f32(outf_CDEF), vmagic_int_less_zp); - - int16x8_t out_04152637; - int16x8_t out_8C9DAEBF; - out_04152637 = vmovnbq_s32(out_04152637, out_0123); - out_04152637 = vmovntq_s32(out_04152637, out_4567); - out_8C9DAEBF = vmovnbq_s32(out_8C9DAEBF, out_89AB); - out_8C9DAEBF = vmovntq_s32(out_8C9DAEBF, out_CDEF); - - int16x8_t out_04152637_clamped = - vminq_s16(vmaxq_s16(out_04152637, vqmin), vqmax); - int16x8_t out_8C9DAEBF_clamped = - vminq_s16(vmaxq_s16(out_8C9DAEBF, vqmin), vqmax); - - int8x16_t out_084C195D2A6E3B7F; - out_084C195D2A6E3B7F = - vmovnbq_s16(out_084C195D2A6E3B7F, out_04152637_clamped); - out_084C195D2A6E3B7F = - vmovntq_s16(out_084C195D2A6E3B7F, out_8C9DAEBF_clamped); - - vstrbq_scatter_offset_s8(out_data, voffset, out_084C195D2A6E3B7F); - input_data += 16; - out_data += 16; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = - quantize_val(inv_scale, zp, *input_data, qmin, qmax); - input_data++; - out_data++; - } - } else { // ScalarType::Short — int16 - int16_t* out_data = out.mutable_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for float32 to int16 quantization, processing - // 8 elements per iteration. Uses the same magic-number rounding trick as - // the int8 path. Output goes through vstrhq_s32 (narrow int32->int16 - // sequential store), so no deinterleave dance is needed. - float magic_float = 12582912.0f; - int32_t magic_int = 1262485504; - - float32x4_t inv_scale_vec = vdupq_n_f32(inv_scale); - float32x4_t vmagic_float = vdupq_n_f32(magic_float); - int32x4_t vmagic_int_less_zp = - vdupq_n_s32(magic_int - static_cast(zp)); - - int32x4_t vqmin = vdupq_n_s32(qmin); - int32x4_t vqmax = vdupq_n_s32(qmax); - - for (; i + 7 < numel; i += 8) { - float32x4_t in_0123 = vldrwq_f32(input_data + 0); - float32x4_t in_4567 = vldrwq_f32(input_data + 4); - - float32x4_t outf_0123 = vfmaq_f32(vmagic_float, in_0123, inv_scale_vec); - float32x4_t outf_4567 = vfmaq_f32(vmagic_float, in_4567, inv_scale_vec); - - int32x4_t out_0123 = - vsubq_s32(vreinterpretq_s32_f32(outf_0123), vmagic_int_less_zp); - int32x4_t out_4567 = - vsubq_s32(vreinterpretq_s32_f32(outf_4567), vmagic_int_less_zp); - - // Clamp at int32 width before narrowing. - out_0123 = vminq_s32(vmaxq_s32(out_0123, vqmin), vqmax); - out_4567 = vminq_s32(vmaxq_s32(out_4567, vqmin), vqmax); - - // Narrow store: low 16 bits of each int32 lane stored sequentially. - vstrhq_s32(out_data + 0, out_0123); - vstrhq_s32(out_data + 4, out_4567); - - input_data += 8; - out_data += 8; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = - quantize_val(inv_scale, zp, *input_data, qmin, qmax); - input_data++; - out_data++; - } - } - - return out; -} - -Tensor& quantize_per_tensor_out( - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - KernelRuntimeContext context; - return quantize_per_tensor_out( - context, input, scale, zero_point, quant_min, quant_max, dtype, out); -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp deleted file mode 100644 index fc04edc..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2025-2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -Tensor& quantized_avg_pool2d_out( - KernelRuntimeContext& context, - const Tensor& input, - const Int64ArrayRef kernel_size, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const int64_t zero_point, - const int64_t multiplier, - const int64_t shift, - Tensor& out) { - constexpr int32_t activation_min = std::numeric_limits::min(); - constexpr int32_t activation_max = std::numeric_limits::max(); - - const int64_t dilation_values[2] = {1, 1}; - const Int64ArrayRef dilation(dilation_values, 2); - CmsisPool2DConfig pool_config; - if (!prepare_cmsis_pool2d_config( - context, - "quantized_avg_pool2d_out", - input, - out, - kernel_size, - stride, - padding, - dilation, - false, - activation_min, - activation_max, - pool_config)) { - return out; - } - - cmsis_nn_context cmsis_ctx; - cmsis_ctx.buf = nullptr; - cmsis_ctx.size = 0; - - const int8_t* input_data = input.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - - const arm_cmsis_nn_status status = arm_avgpool_s8( - &cmsis_ctx, - &pool_config.pool_params, - &pool_config.input_dims, - input_data, - &pool_config.filter_dims, - &pool_config.output_dims, - output_data); - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_avg_pool2d_out: arm_avgpool_s8 failed with status [%d]", - status); - context.fail(Error::Internal); - } - - (void)zero_point; - (void)multiplier; - (void)shift; - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_batch_matmul.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_batch_matmul.cpp deleted file mode 100644 index e6bc5a9..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_batch_matmul.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -extern "C" { -#include "arm_nnfunctions.h" -} - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -bool validate_batch_matmul_arguments( - KernelRuntimeContext& context, - const Tensor& lhs, - const Tensor& rhs_transposed, - const Tensor& out) { - if (lhs.scalar_type() != ScalarType::Char || - rhs_transposed.scalar_type() != ScalarType::Char || - out.scalar_type() != ScalarType::Char) { - ET_LOG(Error, "quantized_batch_matmul: all tensors must be int8"); - context.fail(Error::InvalidArgument); - return false; - } - - if (lhs.dim() != 3 || rhs_transposed.dim() != 3 || out.dim() != 3) { - ET_LOG(Error, "quantized_batch_matmul: all tensors must be 3-D"); - context.fail(Error::InvalidArgument); - return false; - } - - if (lhs.size(0) != rhs_transposed.size(0)) { - ET_LOG(Error, "quantized_batch_matmul: batch dims must match"); - context.fail(Error::InvalidArgument); - return false; - } - - if (lhs.size(2) != rhs_transposed.size(2)) { - ET_LOG(Error, "quantized_batch_matmul: inner dims must match"); - context.fail(Error::InvalidArgument); - return false; - } - - if (out.size(0) != lhs.size(0) || out.size(1) != lhs.size(1) || - out.size(2) != rhs_transposed.size(1)) { - ET_LOG(Error, "quantized_batch_matmul: output shape mismatch"); - context.fail(Error::InvalidArgument); - return false; - } - - return true; -} - -} // namespace - -Tensor& quantized_batch_matmul_out( - KernelRuntimeContext& context, - const Tensor& lhs, - int64_t lhs_offset, - const Tensor& rhs_transposed, - int64_t rhs_offset, - int64_t output_offset, - int64_t output_multiplier, - int64_t output_shift, - Tensor& out) { - if (!validate_batch_matmul_arguments(context, lhs, rhs_transposed, out)) { - return out; - } - - const int32_t batch = static_cast(lhs.size(0)); - const int32_t lhs_rows = static_cast(lhs.size(1)); - const int32_t inner = static_cast(lhs.size(2)); - const int32_t rhs_cols = static_cast(rhs_transposed.size(1)); - - const cmsis_nn_dims lhs_dims = {1, batch, lhs_rows, inner}; - const cmsis_nn_dims rhs_dims = {1, batch, rhs_cols, inner}; - const cmsis_nn_dims out_dims = {1, batch, lhs_rows, rhs_cols}; - - const cmsis_nn_bmm_params bmm_params = { - /* adj_x */ false, - /* adj_y */ false, - /* fc_params */ - {static_cast(lhs_offset), - static_cast(rhs_offset), - static_cast(output_offset), - /* activation */ - {std::numeric_limits::min(), - std::numeric_limits::max()}}}; - - cmsis_nn_per_tensor_quant_params quant_params; - quant_params.multiplier = static_cast(output_multiplier); - quant_params.shift = static_cast(output_shift); - - const int32_t buf_size = arm_fully_connected_s8_get_buffer_size(&out_dims); - - cmsis_nn_context ctx; - ctx.buf = nullptr; - ctx.size = 0; - - if (buf_size > 0) { - auto buffer_or_error = context.allocate_temp(buf_size); - if (!buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_batch_matmul: failed to allocate scratch buffer (%d bytes)", - buf_size); - context.fail(buffer_or_error.error()); - return out; - } - ctx.buf = buffer_or_error.get(); - ctx.size = buf_size; - } - - const arm_cmsis_nn_status status = arm_batch_matmul_s8( - &ctx, - &bmm_params, - &quant_params, - &lhs_dims, - lhs.const_data_ptr(), - &rhs_dims, - rhs_transposed.const_data_ptr(), - &out_dims, - out.mutable_data_ptr()); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_batch_matmul: arm_batch_matmul_s8 failed with status [%d]", - status); - context.fail(Error::Internal); - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_max_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_max_pool2d.cpp deleted file mode 100644 index 181a29c..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_max_pool2d.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -Tensor& quantized_max_pool2d_out( - KernelRuntimeContext& context, - const Tensor& input, - const Int64ArrayRef kernel_size, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef dilation, - const bool ceil_mode, - const int64_t input_zero_point, - const int64_t output_zero_point, - const int64_t activation_min, - const int64_t activation_max, - Tensor& out) { - CmsisPool2DConfig pool_config; - if (!prepare_cmsis_pool2d_config( - context, - "quantized_max_pool2d_out", - input, - out, - kernel_size, - stride, - padding, - dilation, - ceil_mode, - activation_min, - activation_max, - pool_config)) { - return out; - } - - auto validate_int8_zero_point = [&](int64_t zp, const char* name) -> bool { - if (zp < std::numeric_limits::min() || - zp > std::numeric_limits::max()) { - ET_LOG( - Error, - "quantized_max_pool2d_out: %s must be int8, got %ld", - name, - zp); - context.fail(Error::InvalidArgument); - return false; - } - return true; - }; - - if (!validate_int8_zero_point(input_zero_point, "input zero point") || - !validate_int8_zero_point(output_zero_point, "output zero point")) { - return out; - } - - if (input_zero_point != output_zero_point) { - ET_LOG( - Error, - "quantized_max_pool2d_out: input and output zero points must match"); - context.fail(Error::InvalidArgument); - return out; - } - - cmsis_nn_context cmsis_context; - cmsis_context.buf = nullptr; - cmsis_context.size = 0; - - const int8_t* input_data = input.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - - const arm_cmsis_nn_status status = arm_max_pool_s8( - &cmsis_context, - &pool_config.pool_params, - &pool_config.input_dims, - input_data, - &pool_config.filter_dims, - &pool_config.output_dims, - output_data); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_max_pool2d_out: arm_max_pool_s8 failed with status %d", - status); - context.fail(Error::Internal); - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp deleted file mode 100644 index e3f6135..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { -constexpr int64_t kConvTransposeDim = 4; - -bool validate_transpose_conv2d_arguments( - KernelRuntimeContext& context, - const Tensor& input, - const Tensor& weight, - const torch::executor::optional& bias, - const Tensor& output, - const Tensor& requantize_multipliers, - const Tensor& requantize_shifts) { - if (input.dim() != kConvTransposeDim || weight.dim() != kConvTransposeDim || - output.dim() != kConvTransposeDim) { - ET_LOG(Error, "quantized_transpose_conv2d_out: tensors must be 4-D"); - context.fail(Error::InvalidArgument); - return false; - } - - if (!is_channels_last_tensor(input)) { - ET_LOG( - Error, "quantized_transpose_conv2d_out: input must be channels_last"); - context.fail(Error::InvalidArgument); - return false; - } - - if (!is_channels_last_tensor(output)) { - ET_LOG( - Error, "quantized_transpose_conv2d_out: output must be channels_last"); - context.fail(Error::InvalidArgument); - return false; - } - - if (input.scalar_type() != ScalarType::Char || - output.scalar_type() != ScalarType::Char) { - ET_LOG( - Error, "quantized_transpose_conv2d_out: input and output must be int8"); - context.fail(Error::InvalidArgument); - return false; - } - - if (weight.scalar_type() != ScalarType::Char) { - ET_LOG(Error, "quantized_transpose_conv2d_out: weight must be int8"); - context.fail(Error::InvalidArgument); - return false; - } - - if (bias.has_value() && bias.value().scalar_type() != ScalarType::Int) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: bias must be int32 if provided"); - context.fail(Error::InvalidArgument); - return false; - } - - const int64_t out_channels = output.size(1); - if (requantize_multipliers.size(0) != out_channels || - requantize_shifts.size(0) != out_channels) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: per-channel params must match output channels (%zd)", - out_channels); - context.fail(Error::InvalidArgument); - return false; - } - - return true; -} -} // namespace - -Tensor& quantized_transpose_conv2d_out( - KernelRuntimeContext& context, - const Tensor& input, - const Tensor& weight, - const torch::executor::optional& bias, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef output_padding, - const Int64ArrayRef dilation, - const int64_t input_offset, - const int64_t output_offset, - const Tensor& requantize_multipliers, - const Tensor& requantize_shifts, - const int64_t activation_min, - const int64_t activation_max, - Tensor& out) { - if (!validate_transpose_conv2d_arguments( - context, - input, - weight, - bias, - out, - requantize_multipliers, - requantize_shifts)) { - return out; - } - - const int32_t batch = static_cast(input.size(0)); - const int32_t input_channels = static_cast(input.size(1)); - const int32_t input_height = static_cast(input.size(2)); - const int32_t input_width = static_cast(input.size(3)); - - const int32_t kernel_output_channels = static_cast(weight.size(0)); - const int32_t kernel_height = static_cast(weight.size(1)); - const int32_t kernel_width = static_cast(weight.size(2)); - const int32_t kernel_input_channels = static_cast(weight.size(3)); - - const int32_t output_channels = static_cast(out.size(1)); - const int32_t output_height = static_cast(out.size(2)); - const int32_t output_width = static_cast(out.size(3)); - - if (kernel_output_channels != output_channels) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: weight output channels (%d) != output channels (%d)", - kernel_output_channels, - output_channels); - context.fail(Error::InvalidArgument); - return out; - } - - const int32_t input_offset_val = static_cast(input_offset); - const int32_t output_offset_val = static_cast(output_offset); - const int32_t activation_min_val = static_cast(activation_min); - const int32_t activation_max_val = static_cast(activation_max); - - const cmsis_nn_dims input_dims{ - batch, input_height, input_width, input_channels}; - const cmsis_nn_dims filter_dims{ - kernel_output_channels, - kernel_height, - kernel_width, - kernel_input_channels}; - const cmsis_nn_dims output_dims{ - batch, output_height, output_width, output_channels}; - const cmsis_nn_dims bias_dims{1, 1, 1, output_channels}; - - // Setup transposed convolution parameters - cmsis_nn_transpose_conv_params transpose_conv_params; - transpose_conv_params.input_offset = input_offset_val; - transpose_conv_params.output_offset = output_offset_val; - transpose_conv_params.stride.h = static_cast(stride[0]); - transpose_conv_params.stride.w = static_cast(stride[1]); - transpose_conv_params.padding.h = static_cast(padding[0]); - transpose_conv_params.padding.w = static_cast(padding[1]); - // padding_offsets corresponds to output_padding in PyTorch - transpose_conv_params.padding_offsets.h = - static_cast(output_padding[0]); - transpose_conv_params.padding_offsets.w = - static_cast(output_padding[1]); - transpose_conv_params.dilation.h = static_cast(dilation[0]); - transpose_conv_params.dilation.w = static_cast(dilation[1]); - transpose_conv_params.activation.min = activation_min_val; - transpose_conv_params.activation.max = activation_max_val; - - cmsis_nn_per_channel_quant_params quant_params; - quant_params.multiplier = requantize_multipliers.data_ptr(); - quant_params.shift = requantize_shifts.data_ptr(); - - const int8_t* input_data = input.const_data_ptr(); - const int8_t* weight_data = weight.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - const int32_t* bias_data = - bias.has_value() ? bias.value().const_data_ptr() : nullptr; - - cmsis_nn_context cmsis_context; - cmsis_context.buf = nullptr; - cmsis_context.size = 0; - - cmsis_nn_context output_context; - output_context.buf = nullptr; - output_context.size = 0; - - const int32_t buffer_bytes = arm_transpose_conv_s8_get_buffer_size( - &transpose_conv_params, &input_dims, &filter_dims, &output_dims); - auto buffer_or_error = context.allocate_temp( - static_cast(buffer_bytes), kCortexMMveAlignment); - if (!buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: failed to allocate scratch buffer (%d bytes, error %d)", - buffer_bytes, - static_cast(buffer_or_error.error())); - context.fail(buffer_or_error.error()); - return out; - } - cmsis_context.buf = buffer_or_error.get(); - cmsis_context.size = buffer_bytes; - - const int32_t output_buffer_bytes = - arm_transpose_conv_s8_get_reverse_conv_buffer_size( - &transpose_conv_params, &input_dims, &filter_dims); - auto output_buffer_or_error = context.allocate_temp( - static_cast(output_buffer_bytes), kCortexMMveAlignment); - if (!output_buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: failed to allocate output scratch buffer (%d bytes, error %d)", - output_buffer_bytes, - static_cast(output_buffer_or_error.error())); - context.fail(output_buffer_or_error.error()); - return out; - } - output_context.buf = output_buffer_or_error.get(); - output_context.size = output_buffer_bytes; - - const arm_cmsis_nn_status status = arm_transpose_conv_wrapper_s8( - &cmsis_context, - &output_context, - &transpose_conv_params, - &quant_params, - &input_dims, - input_data, - &filter_dims, - weight_data, - &bias_dims, - bias_data, - &output_dims, - output_data); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: arm_transpose_conv_wrapper_s8 failed with status %d", - status); - context.fail(Error::Internal); - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp deleted file mode 100644 index 1ae679a..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include -#include - -namespace torch { -namespace executor { -namespace native { - -using Tensor = executorch::aten::Tensor; -using ScalarType = executorch::aten::ScalarType; -using IntArrayRef = executorch::aten::ArrayRef; - -namespace { - -inline int64_t -adaptive_start_index(int64_t out_idx, int64_t out_size, int64_t in_size) { - return static_cast( - std::floor(static_cast(out_idx * in_size) / out_size)); -} - -inline int64_t -adaptive_end_index(int64_t out_idx, int64_t out_size, int64_t in_size) { - return static_cast( - std::ceil(static_cast((out_idx + 1) * in_size) / out_size)); -} - -} // namespace - -Tensor& _adaptive_avg_pool2d_out( - KernelRuntimeContext& ctx, - const Tensor& in, - IntArrayRef output_size, - Tensor& out) { - ET_KERNEL_CHECK( - ctx, - check_adaptive_avg_pool2d_args(in, output_size, out), - InvalidArgument, - out); - - ET_KERNEL_CHECK( - ctx, tensors_have_same_dim_order(in, out), InvalidArgument, out); - - ET_KERNEL_CHECK(ctx, tensor_is_default_dim_order(in), InvalidArgument, out); - - size_t output_ndim = 0; - executorch::aten::SizesType output_sizes[kTensorDimensionLimit]; - get_adaptive_avg_pool2d_out_target_size( - in, output_size, output_sizes, &output_ndim); - - ET_KERNEL_CHECK( - ctx, - output_size_is_valid({output_sizes, output_ndim}, 2), - InvalidArgument, - out); - - ET_KERNEL_CHECK( - ctx, - resize_tensor(out, {output_sizes, output_ndim}) == Error::Ok, - InvalidArgument, - out); - - ScalarType in_type = in.scalar_type(); - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "_adaptive_avg_pool2d.out"; - - ET_SWITCH_FLOATHBF16_TYPES_AND(Long, in_type, ctx, op_name, CTYPE, [&]() { - const CTYPE* const in_ptr = in.const_data_ptr(); - CTYPE* const out_ptr = out.mutable_data_ptr(); - - const size_t ndim = in.dim(); - const int64_t in_H = in.size(ndim - 2); - const int64_t in_W = in.size(ndim - 1); - const int64_t out_H = output_size[0]; - const int64_t out_W = output_size[1]; - - const size_t channels = in.size(ndim - 3); - const size_t batch_size = ndim == 4 ? in.size(0) : 1; - - const size_t in_plane_size = in_H * in_W; - const size_t out_plane_size = out_H * out_W; - - for (size_t b = 0; b < batch_size; ++b) { - for (size_t c = 0; c < channels; ++c) { - const size_t plane_idx = b * channels + c; - const CTYPE* plane_in = in_ptr + plane_idx * in_plane_size; - CTYPE* plane_out = out_ptr + plane_idx * out_plane_size; - - for (int64_t oh = 0; oh < out_H; ++oh) { - int64_t ih0 = adaptive_start_index(oh, out_H, in_H); - int64_t ih1 = adaptive_end_index(oh, out_H, in_H); - - for (int64_t ow = 0; ow < out_W; ++ow) { - int64_t iw0 = adaptive_start_index(ow, out_W, in_W); - int64_t iw1 = adaptive_end_index(ow, out_W, in_W); - - float sum = 0; - for (int64_t ih = ih0; ih < ih1; ++ih) { - for (int64_t iw = iw0; iw < iw1; ++iw) { - sum += plane_in[ih * in_W + iw]; - } - } - - int64_t count = (ih1 - ih0) * (iw1 - iw0); - plane_out[oh * out_W + ow] = - static_cast(sum / static_cast(count)); - } - } - } - } - }); - - return out; -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__conj_physical.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__conj_physical.cpp deleted file mode 100644 index 4352ab3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__conj_physical.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -namespace torch { -namespace executor { -namespace native { - -using executorch::aten::Tensor; - -Tensor& -_conj_physical_out(KernelRuntimeContext& ctx, const Tensor& in, Tensor& out) { - ET_KERNEL_CHECK_MSG( - ctx, - resize_tensor(out, in.sizes()) == Error::Ok, - InvalidArgument, - out, - "Failed to resize output tensor."); - - ET_KERNEL_CHECK(ctx, tensors_have_same_dtype(in, out), InvalidArgument, out); - - ET_KERNEL_CHECK( - ctx, tensors_have_same_dim_order(in, out), InvalidArgument, out); - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "_conj_physical.out"; - - ET_SWITCH_COMPLEXH_TYPES(in.scalar_type(), ctx, op_name, CTYPE, [&] { - apply_unary_map_fn( - [](const CTYPE val_in) -> CTYPE { - return CTYPE(val_in.real_, -val_in.imag_); - }, - in.const_data_ptr(), - out.mutable_data_ptr(), - in.numel()); - }); - - return out; -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp deleted file mode 100644 index 14124d3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op__to_dim_order_copy.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include -#include -#include - -namespace torch { -namespace executor { -namespace native { - -using Tensor = executorch::aten::Tensor; -using SizesArrayRef = executorch::aten::ArrayRef; -using DimOrderArrayRef = - executorch::aten::ArrayRef; -using MemoryFormat = executorch::aten::MemoryFormat; - -template -using OptionalArrayRef = executorch::aten::OptionalArrayRef; - -template -using Optional = std::optional; - -// _to_dim_order_copy.out(Tensor self, *, bool non_blocking=False, int[]? -// dim_order=None, Tensor(a!) out) -> Tensor(a!) -Tensor& _to_dim_order_copy_out( - KernelRuntimeContext& ctx, - const Tensor& self, - bool non_blocking, - OptionalArrayRef dim_order, - Tensor& out) { - (void)ctx; - ET_KERNEL_CHECK( - ctx, - check__to_dim_order_copy_args(self, non_blocking, dim_order, out), - InvalidArgument, - out); - - ET_KERNEL_CHECK( - ctx, - resize_tensor(out, self.sizes()) == torch::executor::Error::Ok, - InvalidArgument, - out); - - if (self.numel() == 0) { - return out; - } - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = - "dim_order_ops::_to_dim_order_copy.out"; - - const bool in_is_complex = - executorch::runtime::isComplexType(self.scalar_type()); - const bool out_is_complex = - executorch::runtime::isComplexType(out.scalar_type()); - - if (in_is_complex && out_is_complex) { - // Complex to complex: same type copy - ET_SWITCH_COMPLEXH_TYPES(self.scalar_type(), ctx, op_name, CTYPE, [&] { - _to_dim_order_copy_impl(self, out); - }); - } else if (!in_is_complex && out_is_complex) { - // Real to complex: convert real value to complex with zero imaginary part - ET_SWITCH_FLOATH_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { - ET_SWITCH_COMPLEXH_TYPES(out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { - auto self_data = self.mutable_data_ptr(); - auto out_data = out.mutable_data_ptr(); - for (const auto [unused_index, self_data_index, out_data_index] : - BroadcastIndexesRange< - 2, - /*support_noncontiguous_input_tensors=*/true>( - /*dummy output*/ self, self, out)) { - (void)unused_index; - out_data[out_data_index].real_ = self_data[self_data_index]; - out_data[out_data_index].imag_ = 0; - } - }); - }); - } else if (in_is_complex && !out_is_complex) { - // Complex to real: take real part - ET_SWITCH_COMPLEXH_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { - ET_SWITCH_FLOATH_TYPES(out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { - auto self_data = self.mutable_data_ptr(); - auto out_data = out.mutable_data_ptr(); - for (const auto [unused_index, self_data_index, out_data_index] : - BroadcastIndexesRange< - 2, - /*support_noncontiguous_input_tensors=*/true>( - /*dummy output*/ self, self, out)) { - (void)unused_index; - out_data[out_data_index] = - static_cast(self_data[self_data_index].real_); - } - }); - }); - } else { - // Real to real - ET_SWITCH_REALHBBF16_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { - ET_SWITCH_REALHBBF16_TYPES( - out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { - _to_dim_order_copy_impl(self, out); - }); - }); - } - - return out; -} - -Tensor& _to_dim_order_copy_out( - const Tensor& self, - bool non_blocking, - OptionalArrayRef dim_order, - Tensor& out) { - executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext context{}; - return _to_dim_order_copy_out(context, self, non_blocking, dim_order, out); -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_var_mean.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_var_mean.cpp deleted file mode 100644 index dbb88f2..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/kernels/portable/cpu/op_var_mean.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -#include -#include -#include - -namespace torch { -namespace executor { -namespace native { -namespace { - -template -void compute_var_mean( - KernelRuntimeContext& ctx, - const Tensor& in, - Tensor& var_out, - Tensor& mean_out, - optional> dim_list, - const size_t num, - const double denominator) { - CTYPE_OUT* var_data = var_out.mutable_data_ptr(); - CTYPE_OUT* mean_data = mean_out.mutable_data_ptr(); - if (num == 0 || denominator <= 0) { - for (const auto out_ix : c10::irange(var_out.numel())) { - var_data[out_ix] = NAN; - mean_data[out_ix] = NAN; - } - } else if (in.numel() > 0) { - // Fast path: contiguous tensor, single innermost dim reduction, same dtype. - bool used_fast_path = false; - if (dim_list.has_value() && dim_list.value().size() == 1 && - in.scalar_type() == var_out.scalar_type()) { - const int64_t d = dim_list.value()[0] < 0 ? dim_list.value()[0] + in.dim() - : dim_list.value()[0]; - if (d >= 0 && d < in.dim() && d == in.dim() - 1 && - tensor_is_contiguous(in)) { - used_fast_path = true; - const int64_t reduce_size = in.size(d); - const int64_t outer_size = in.numel() / reduce_size; - const CTYPE_OUT cnum = static_cast(num); - const CTYPE_OUT cdenom = static_cast(denominator); - const CTYPE_IN* in_data = in.const_data_ptr(); - for (int64_t i = 0; i < outer_size; i++) { - const CTYPE_IN* row = in_data + i * reduce_size; - // Pass 1: compute mean - CTYPE_OUT sum = 0; - for (int64_t j = 0; j < reduce_size; j++) { - sum += static_cast(row[j]); - } - CTYPE_OUT mean = sum / cnum; - mean_data[i] = mean; - // Pass 2: compute variance - CTYPE_OUT sum2 = 0; - for (int64_t j = 0; j < reduce_size; j++) { - CTYPE_OUT diff = static_cast(row[j]) - mean; - sum2 += diff * diff; - } - var_data[i] = sum2 / cdenom; - } - } - } - if (!used_fast_path) { - MapReduceOverDimListPlan plan(in, dim_list); - const bool success = parallel_for_each_reduce_over_dim_list_output_index( - in, dim_list, var_out, [&](const auto begin, const auto end) { - for (const auto out_ix : c10::irange(begin, end)) { - // Pass 1: compute sum -> mean - CTYPE_OUT sum = plan.execute( - [](CTYPE_IN v) { return static_cast(v); }, - [](CTYPE_OUT outv, CTYPE_OUT acc) { return acc + outv; }, - out_ix); - CTYPE_OUT mean = sum / static_cast(num); - mean_data[out_ix] = mean; - // Pass 2: compute sum of squared deviations - CTYPE_OUT sum2 = plan.execute( - [mean](CTYPE_IN v) { - return ( - (static_cast(v) - mean) * - (static_cast(v) - mean)); - }, - [](CTYPE_OUT outv, CTYPE_OUT acc) { return acc + outv; }, - out_ix); - var_data[out_ix] = sum2 / denominator; - } - }); - ET_KERNEL_CHECK_MSG(ctx, success, Internal, , "parallel_for failed"); - } // !used_fast_path - } -} - -} // namespace - -std::tuple var_mean_correction_out( - KernelRuntimeContext& ctx, - const Tensor& in, - optional> dim_list, - const optional& correction, - bool keepdim, - Tensor& out0, - Tensor& out1) { - (void)ctx; - - std::tuple ret_val(out0, out1); - - ET_KERNEL_CHECK( - ctx, - check_reduction_args(in, dim_list, keepdim, {}, out0), - InvalidArgument, - ret_val); - - ET_KERNEL_CHECK( - ctx, - check_reduction_args(in, dim_list, keepdim, {}, out1), - InvalidArgument, - ret_val); - - ET_KERNEL_CHECK( - ctx, - resize_reduction_out(in, dim_list, keepdim, out0) == Error::Ok, - InvalidArgument, - ret_val); - - ET_KERNEL_CHECK( - ctx, - resize_reduction_out(in, dim_list, keepdim, out1) == Error::Ok, - InvalidArgument, - ret_val); - - static constexpr auto name = "var_mean.correction_out"; - - double correction_val = 1; - if (correction.has_value()) { - correction_val = utils::scalar_to(correction.value()); - } - - const size_t num = get_reduced_dim_product(in, dim_list); - const double denom = num - correction_val; - - ET_SWITCH_FLOATHBF16_TYPES(in.scalar_type(), ctx, name, CTYPE_IN, [&] { - ET_SWITCH_FLOATHBF16_TYPES(out0.scalar_type(), ctx, name, CTYPE_OUT, [&] { - compute_var_mean( - ctx, in, out0, out1, dim_list, num, denom); - }); - }); - - return ret_val; -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_options_map.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_options_map.h deleted file mode 100644 index f0c6a68..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/backend/backend_options_map.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include - -#include - -namespace executorch { -namespace runtime { - -/** - * Maps backend IDs to their load-time options. - * - * This class is used to provide per-delegate configuration at Module::load() - * time. Users can set options for multiple backends, and the runtime will - * route the appropriate options to each backend during initialization. - * - * Example usage: - * @code - * BackendOptions<4> coreml_opts; - * coreml_opts.set_option("compute_unit", "cpu_and_gpu"); - * - * LoadBackendOptionsMap map; - * map.set_options("CoreMLBackend", coreml_opts.view()); - * - * // Later, during backend init: - * auto opts = map.get_options("CoreMLBackend"); - * @endcode - * - * Note: This class does NOT take ownership of the option spans. The caller - * must ensure that the BackendOptions objects outlive the LoadBackendOptionsMap - * and any loaded models that use it. - */ -class LoadBackendOptionsMap final { - public: - /** - * Default constructor - creates an empty map. - */ - LoadBackendOptionsMap() : size_(0) { - for (size_t i = 0; i < kMaxBackends; ++i) { - entries_[i].backend_id[0] = '\0'; - } - } - - /** - * Sets options for a specific backend. - * - * If options for the given backend_id already exist, they will be replaced. - * - * @param backend_id The backend identifier (e.g., "CoreMLBackend", - * "XNNPACKBackend"). Must not be null or empty. - * @param options Span of BackendOption to associate with this backend. - * The span's underlying data must outlive this map and any - * models loaded with it. - * @return Error::Ok on success. - * Error::InvalidArgument if backend_id is null/empty or max backends - * exceeded. - */ - Error set_options(const char* backend_id, Span options) { - if (backend_id == nullptr || backend_id[0] == '\0') { - return Error::InvalidArgument; - } - - return set_options_impl(backend_id, options); - } - - /** - * Sets options from a backend options builder. - * - * This convenience overload accepts any builder type that provides - * backend_id() and view() methods, allowing simpler usage: - * - * @code - * ExampleBackendOptions opts; - * opts.setNumThreads(4).setEnableOptimization(true); - * map.set_options(opts); - * @endcode - * - * @param builder A backend options builder with backend_id() and view() - * methods. - * @return Error::Ok on success, Error::InvalidArgument on failure. - */ - template - Error set_options(Builder& builder) { - return set_options_impl(builder.backend_id(), builder.view()); - } - - private: - Error set_options_impl(const char* backend_id, Span options) { - // Check if backend already exists and update it - for (size_t i = 0; i < size_; ++i) { - if (std::strcmp(entries_[i].backend_id, backend_id) == 0) { - entries_[i].options = options; - return Error::Ok; - } - } - - // Add new entry if space available - if (size_ >= kMaxBackends) { - return Error::InvalidArgument; - } - - const size_t id_len = std::strlen(backend_id); - if (id_len >= kMaxBackendIdLength) { - return Error::InvalidArgument; - } - std::memcpy(entries_[size_].backend_id, backend_id, id_len); - entries_[size_].backend_id[id_len] = '\0'; - entries_[size_].options = options; - ++size_; - - return Error::Ok; - } - - public: - /** - * Gets options for a specific backend. - * - * @param backend_id The backend identifier to look up. - * @return Span of options for this backend, or an empty span if the backend - * has no options configured or backend_id is null. - */ - Span get_options(const char* backend_id) const { - if (backend_id == nullptr) { - return Span(nullptr, static_cast(0)); - } - - for (size_t i = 0; i < size_; ++i) { - if (std::strcmp(entries_[i].backend_id, backend_id) == 0) { - return Span( - entries_[i].options.data(), entries_[i].options.size()); - } - } - - return Span(nullptr, static_cast(0)); - } - - /** - * Checks if options have been configured for a specific backend. - * - * @param backend_id The backend identifier to check. - * @return true if options are set for this backend, false otherwise. - */ - bool has_options(const char* backend_id) const { - if (backend_id == nullptr) { - return false; - } - - for (size_t i = 0; i < size_; ++i) { - if (std::strcmp(entries_[i].backend_id, backend_id) == 0) { - return true; - } - } - - return false; - } - - /** - * Returns the number of backends with configured options. - */ - size_t size() const { - return size_; - } - - /** - * Non-owning view of a single (backend_id, options) entry, returned by - * entry_at(). The pointer / span are valid until the map is mutated or - * destroyed. - */ - struct EntryView { - const char* backend_id = nullptr; - Span options; - }; - - /** - * Returns the (backend_id, options) entry at the given index for - * enumeration over the map's contents. - * - * @param index The entry index. Must be < size(); behavior is undefined - * otherwise. Use this together with size() to walk every entry. - * @return EntryView referencing the entry's backend_id and options. The - * view is valid until the next mutation of, or destruction of, this - * map. - * - * Example: - * @code - * for (size_t i = 0; i < map.size(); ++i) { - * const auto entry = map.entry_at(i); - * // use entry.backend_id and entry.options ... - * } - * @endcode - */ - EntryView entry_at(size_t index) const { - ET_DCHECK_MSG( - index < size_, - "entry_at index %zu out of bounds (size=%zu)", - index, - size_); - return EntryView{ - entries_[index].backend_id, - Span( - entries_[index].options.data(), entries_[index].options.size())}; - } - - private: - static constexpr size_t kMaxBackends = 8; - static constexpr size_t kMaxBackendIdLength = 64; - - struct Entry { - char backend_id[kMaxBackendIdLength]; - Span options; - }; - - Entry entries_[kMaxBackends]; - size_t size_; -}; - -} // namespace runtime -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.cpp deleted file mode 100644 index 91b3257..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include - -namespace executorch { -namespace runtime { - -DeviceAllocatorRegistry& DeviceAllocatorRegistry::instance() { - static DeviceAllocatorRegistry registry; - return registry; -} - -void DeviceAllocatorRegistry::register_allocator(DeviceAllocator* alloc) { - ET_CHECK_MSG(alloc != nullptr, "Cannot register a null allocator"); - auto type = alloc->device_type(); - auto index = static_cast(type); - ET_CHECK_MSG( - index < etensor::kNumDeviceTypes, - "Invalid device type: %d", - static_cast(type)); - ET_CHECK_MSG( - allocators_[index] == nullptr, - "Allocator already registered for device type: %d", - static_cast(type)); - allocators_[index] = alloc; -} - -DeviceAllocator* DeviceAllocatorRegistry::get_allocator( - etensor::DeviceType type) { - auto index = static_cast(type); - if (index >= etensor::kNumDeviceTypes) { - return nullptr; - } - return allocators_[index]; -} - -// Convenience free functions - -void register_device_allocator(DeviceAllocator* alloc) { - DeviceAllocatorRegistry::instance().register_allocator(alloc); -} - -DeviceAllocator* get_device_allocator(etensor::DeviceType type) { - return DeviceAllocatorRegistry::instance().get_allocator(type); -} - -} // namespace runtime -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.h deleted file mode 100644 index 259bdb9..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_allocator.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -namespace executorch { -namespace runtime { - -/** - * Abstract interface for device-specific memory allocation. - * - * Each device type (CUDA, etc.) provides a concrete implementation - * that handles memory allocation on that device. Implementations are - * expected to be singletons with static lifetime, registered via - * DeviceAllocatorRegistry. - */ -class DeviceAllocator { - public: - /** - * Default alignment of memory returned by allocate(). Reuses - * MemoryAllocator::kDefaultAlignment so host- and device-side allocations - * share the same baseline contract. Backends whose underlying device APIs - * already provide stronger guarantees (e.g. cudaMalloc returns 256-byte - * aligned pointers) will trivially satisfy this. - */ - static constexpr size_t kDefaultAlignment = - MemoryAllocator::kDefaultAlignment; - - virtual ~DeviceAllocator() = default; - /** - * Allocate device memory. - * - * @param nbytes Number of bytes to allocate. - * @param index The device index. - * @param alignment Minimum alignment of the returned pointer in bytes. - * Must be a power of 2. Defaults to kDefaultAlignment. - * @return A Result containing the device pointer on success, or an error. - */ - virtual Result allocate( - size_t nbytes, - etensor::DeviceIndex index, - size_t alignment = kDefaultAlignment) = 0; - - /** - * Deallocate device memory previously allocated via allocate(). - * - * @param ptr Pointer to the memory to deallocate. - * @param index The device index. - */ - virtual void deallocate(void* ptr, etensor::DeviceIndex index) = 0; - - /** - * Copy data from host memory to device memory. - * - * @param dst Destination pointer (device memory). - * @param src Source pointer (host memory). - * @param nbytes Number of bytes to copy. - * @param index The device index. - * @return Error::Ok on success, or an appropriate error code on failure. - */ - virtual Error copy_host_to_device( - void* dst, - const void* src, - size_t nbytes, - etensor::DeviceIndex index) = 0; - - /** - * Copy data from device memory to host memory. - * - * @param dst Destination pointer (host memory). - * @param src Source pointer (device memory). - * @param nbytes Number of bytes to copy. - * @param index The device index. - * @return Error::Ok on success, or an appropriate error code on failure. - */ - virtual Error copy_device_to_host( - void* dst, - const void* src, - size_t nbytes, - etensor::DeviceIndex index) = 0; - - /** - * Returns the device type this allocator handles. - */ - virtual etensor::DeviceType device_type() const = 0; -}; - -/** - * Registry for device allocators. - * - * Provides a global mapping from DeviceType to DeviceAllocator instances. - * Device allocators register themselves at static initialization time, - * and the runtime queries the registry to find the appropriate allocator - * for a given device type. - * - * Threading contract: - * - Registration is expected to happen once per device type during static - * initialization (single-threaded). The registry itself does not perform - * any locking around register_allocator()/get_allocator(), and concurrent - * registration is not supported. - * - After registration, get_allocator() is safe to call concurrently from - * multiple threads because the underlying array is never mutated again. - * - The DeviceAllocator implementation is responsible for its own - * thread-safety. When multiple Programs are loaded concurrently and each - * needs device memory, the allocator must serialize access to any shared - * state internally (similar to how XNNPACK's weight cache guards its - * internal state). The registry does not provide any synchronization on - * behalf of the allocator. - */ -class DeviceAllocatorRegistry { - public: - /** - * Returns the singleton instance of the registry. - */ - static DeviceAllocatorRegistry& instance(); - - /** - * Register an allocator. The device type is taken from - * alloc->device_type(). Each device type may only be registered once; - * attempting to register a second allocator for the same device type - * will abort. - * - * Not thread-safe. Expected to be called during static initialization. - * - * @param alloc Pointer to the allocator (must have static lifetime). - */ - void register_allocator(DeviceAllocator* alloc); - - /** - * Get the allocator for a specific device type. - * - * Safe to call concurrently with other get_allocator() calls. - * - * @param type The device type. - * @return Pointer to the allocator, or nullptr if not registered. - */ - DeviceAllocator* get_allocator(etensor::DeviceType type); - - private: - DeviceAllocatorRegistry() = default; - - // Singletons must not be copied or moved; instance() returns a reference, - // and silently shallow-copying the registry would lead to confusing bugs - // where modifications to the copy don't affect the real singleton. - DeviceAllocatorRegistry(const DeviceAllocatorRegistry&) = delete; - DeviceAllocatorRegistry& operator=(const DeviceAllocatorRegistry&) = delete; - DeviceAllocatorRegistry(DeviceAllocatorRegistry&&) = delete; - DeviceAllocatorRegistry& operator=(DeviceAllocatorRegistry&&) = delete; - - // Fixed-size array indexed by device type. This avoids dynamic allocation - // and is suitable for embedded environments. - DeviceAllocator* allocators_[etensor::kNumDeviceTypes] = {}; -}; - -// Convenience free functions - -/** - * Register a device allocator. The device type is taken from - * alloc->device_type(). See DeviceAllocatorRegistry::register_allocator() - * for the threading contract. - * - * @param alloc Pointer to the allocator (must have static lifetime). - */ -void register_device_allocator(DeviceAllocator* alloc); - -/** - * Get the device allocator for a specific device type. - * - * @param type The device type. - * @return Pointer to the allocator, or nullptr if not registered. - */ -DeviceAllocator* get_device_allocator(etensor::DeviceType type); - -} // namespace runtime -} // namespace executorch - -namespace torch { -namespace executor { -// TODO(T197294990): Remove these deprecated aliases once all users have moved -// to the new `::executorch` namespaces. -using ::executorch::runtime::DeviceAllocator; -using ::executorch::runtime::DeviceAllocatorRegistry; -using ::executorch::runtime::get_device_allocator; -using ::executorch::runtime::register_device_allocator; -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.cpp deleted file mode 100644 index 26faba3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -namespace executorch::runtime { - -Result DeviceMemoryBuffer::create( - size_t size, - etensor::DeviceType type, - etensor::DeviceIndex index, - size_t alignment) { - DeviceAllocator* allocator = get_device_allocator(type); - if (allocator == nullptr) { - ET_LOG( - Error, - "No device allocator registered for device type %d", - static_cast(type)); - return Error::NotFound; - } - - auto result = allocator->allocate(size, index, alignment); - if (!result.ok()) { - return result.error(); - } - - return DeviceMemoryBuffer(result.get(), size, allocator, index); -} - -} // namespace executorch::runtime diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.h deleted file mode 100644 index 929460c..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/device_memory_buffer.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -namespace executorch::runtime { - -/** - * RAII wrapper that owns a single device memory allocation. - * - * On destruction, calls DeviceAllocator::deallocate() to free the memory. - * This mirrors the role of std::vector for CPU planned buffers, - * but for device memory (CUDA, etc.). - * - * Move-only: cannot be copied, but can be moved to transfer ownership. - */ -class DeviceMemoryBuffer final { - public: - /** - * Creates a DeviceMemoryBuffer by allocating device memory. - * - * Looks up the DeviceAllocator for the given device type via the - * DeviceAllocatorRegistry. If no allocator is registered for the type, - * returns Error::NotFound. - * - * @param size Number of bytes to allocate. - * @param type The device type (e.g., CUDA). - * @param index The device index (e.g., 0 for cuda:0). - * @param alignment Minimum alignment of the returned pointer in bytes. - * Must be a power of 2. Defaults to DeviceAllocator::kDefaultAlignment. - * @return A Result containing the DeviceMemoryBuffer on success, or an error. - */ - static Result create( - size_t size, - etensor::DeviceType type, - etensor::DeviceIndex index = 0, - size_t alignment = DeviceAllocator::kDefaultAlignment); - - DeviceMemoryBuffer() = default; - - ~DeviceMemoryBuffer() { - if (ptr_ != nullptr && allocator_ != nullptr) { - allocator_->deallocate(ptr_, device_index_); - } - } - - // Move constructor: transfer ownership. - DeviceMemoryBuffer(DeviceMemoryBuffer&& other) noexcept - : ptr_(other.ptr_), - size_(other.size_), - allocator_(other.allocator_), - device_index_(other.device_index_) { - other.ptr_ = nullptr; - other.size_ = 0; - other.allocator_ = nullptr; - } - - // Move assignment: release current, take ownership. - DeviceMemoryBuffer& operator=(DeviceMemoryBuffer&& other) noexcept { - if (this != &other) { - if (ptr_ != nullptr && allocator_ != nullptr) { - allocator_->deallocate(ptr_, device_index_); - } - ptr_ = other.ptr_; - size_ = other.size_; - allocator_ = other.allocator_; - device_index_ = other.device_index_; - other.ptr_ = nullptr; - other.size_ = 0; - other.allocator_ = nullptr; - } - return *this; - } - - // Non-copyable. - DeviceMemoryBuffer(const DeviceMemoryBuffer&) = delete; - DeviceMemoryBuffer& operator=(const DeviceMemoryBuffer&) = delete; - - /// Returns the device pointer, or nullptr if empty/moved-from. - void* data() const { - return ptr_; - } - - /// Returns the size in bytes of the allocation. - size_t size() const { - return size_; - } - - /** - * Returns a Span wrapping the device pointer. - * - * This is intended for use with HierarchicalAllocator, which only performs - * pointer arithmetic on the span data and never dereferences it. Device - * pointers are valid for pointer arithmetic from the CPU side. - */ - Span as_span() const { - return {static_cast(ptr_), size_}; - } - - private: - DeviceMemoryBuffer( - void* ptr, - size_t size, - DeviceAllocator* allocator, - etensor::DeviceIndex device_index) - : ptr_(ptr), - size_(size), - allocator_(allocator), - device_index_(device_index) {} - - void* ptr_ = nullptr; - size_t size_ = 0; - DeviceAllocator* allocator_ = nullptr; - etensor::DeviceIndex device_index_ = 0; -}; - -} // namespace executorch::runtime diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/version.h.in b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/version.h.in deleted file mode 100644 index 4b19f35..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/core/version.h.in +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * @file - * ExecuTorch version information. - * - * This file is auto-generated by CMake from version.h.in. - * Do not edit directly. - */ - -#pragma once - -/// ExecuTorch major version number. -#define ET_VERSION_MAJOR @ET_VERSION_MAJOR@ - -/// ExecuTorch minor version number. -#define ET_VERSION_MINOR @ET_VERSION_MINOR@ - -/// ExecuTorch patch version number. -#define ET_VERSION_PATCH @ET_VERSION_PATCH@ - -/// ExecuTorch version string (e.g., "1.2.0"). -#define ET_VERSION "@ET_VERSION_MAJOR@.@ET_VERSION_MINOR@.@ET_VERSION_PATCH@" - -/** - * ExecuTorch version as an integer. - * Format: (MAJOR << 16) | (MINOR << 8) | PATCH - */ -#define ET_VERSION_CODE \ - ((ET_VERSION_MAJOR << 16) | (ET_VERSION_MINOR << 8) | ET_VERSION_PATCH) - -/** - * Helper macro for version comparisons. - * Usage: #if ET_VERSION_CODE >= ET_VERSION_CHECK(1, 2, 0) - */ -#define ET_VERSION_CHECK(major, minor, patch) \ - (((major) << 16) | ((minor) << 8) | (patch)) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.cpp deleted file mode 100644 index 448edc6..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include - -#include -#include -#include - -#include - -namespace executorch { -namespace runtime { - -ET_NODISCARD Error -validate_tensor(const executorch_flatbuffer::Tensor* tensor) { - if (tensor == nullptr) { - ET_LOG(Error, "Tensor is null"); - return Error::InvalidProgram; - } - - const auto* sizes = tensor->sizes(); - if (sizes == nullptr) { - ET_LOG(Error, "Tensor has null sizes"); - return Error::InvalidProgram; - } - - ssize_t numel = 1; - bool numel_overflowed = false; - for (flatbuffers::uoffset_t i = 0; i < sizes->size(); i++) { - int32_t size = sizes->Get(i); - - if (size < 0) { - ET_LOG( - Error, - "Size must be non-negative, got %d at dimension %u", - size, - static_cast(i)); - return Error::InvalidProgram; - } - - if (!numel_overflowed) { - numel_overflowed = - c10::mul_overflows(numel, static_cast(size), &numel); - } - } - - auto scalar_type = - static_cast(tensor->scalar_type()); - if (!executorch::runtime::isValid(scalar_type)) { - ET_LOG(Error, "Invalid ScalarType %d", static_cast(scalar_type)); - return Error::InvalidProgram; - } - - if (numel_overflowed) { - return Error::InvalidProgram; - } - - size_t nbytes; - bool nbytes_overflow = c10::mul_overflows( - static_cast(numel), - executorch::runtime::elementSize(scalar_type), - &nbytes); - if (nbytes_overflow) { - return Error::InvalidProgram; - } - - return Error::Ok; -} - -ET_NODISCARD Error -validate_program(const executorch_flatbuffer::Program* program) { - if (program == nullptr) { - ET_LOG(Error, "Program is null"); - return Error::InvalidProgram; - } - - // Validate all execution plans. - const auto* execution_plans = program->execution_plan(); - if (execution_plans == nullptr) { - ET_LOG(Error, "Program has null execution_plan"); - return Error::InvalidProgram; - } - - for (flatbuffers::uoffset_t plan_idx = 0; plan_idx < execution_plans->size(); - plan_idx++) { - const auto* plan = execution_plans->Get(plan_idx); - if (plan == nullptr) { - ET_LOG( - Error, "Execution plan %u is null", static_cast(plan_idx)); - return Error::InvalidProgram; - } - - // Validate all values in the plan. - const auto* values = plan->values(); - if (values == nullptr) { - ET_LOG( - Error, - "Execution plan %u has null values table", - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - const auto* inputs = plan->inputs(); - auto is_dynamic_input = [&](flatbuffers::uoffset_t idx) -> bool { - if (inputs == nullptr) { - return false; - } - for (flatbuffers::uoffset_t i = 0; i < inputs->size(); i++) { - if (inputs->Get(i) == static_cast(idx)) { - const auto* value = values->Get(idx); - if (value == nullptr) { - return false; - } - const auto* tensor = - static_cast(value->val()); - return tensor != nullptr && - tensor->shape_dynamism() != - executorch_flatbuffer::TensorShapeDynamism::STATIC; - } - } - return false; - }; - - for (flatbuffers::uoffset_t value_idx = 0; value_idx < values->size(); - value_idx++) { - const auto* value = values->Get(value_idx); - if (value == nullptr) { - continue; - } - - // Check if this value is a tensor. - if (value->val_type() == executorch_flatbuffer::KernelTypes::Tensor) { - const auto* tensor = - static_cast(value->val()); - - Error err = validate_tensor(tensor); - if (err != Error::Ok) { - // Dynamic input tensors may have upper-bound sizes serialized for - // 64-bit machines that would overflow on 32-bit. Since their actual - // sizes are provided at set_input time, we defer overflow checks - // for those to Method::set_input. - if (is_dynamic_input(value_idx)) { - ET_LOG( - Info, - "Skipping validation failure for dynamic input tensor " - "at value %u in execution plan %u", - static_cast(value_idx), - static_cast(plan_idx)); - } else { - ET_LOG( - Error, - "Tensor validation failed for value %u in execution plan %u", - static_cast(value_idx), - static_cast(plan_idx)); - return err; - } - } - } - - // Check if this value is a TensorList. - if (value->val_type() == executorch_flatbuffer::KernelTypes::TensorList) { - const auto* tensor_list = - static_cast(value->val()); - - if (tensor_list == nullptr) { - ET_LOG( - Error, - "TensorList is null for value %u in execution plan %u", - static_cast(value_idx), - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - const auto* items = tensor_list->items(); - if (items == nullptr) { - ET_LOG(Error, "TensorList items is null"); - return Error::InvalidProgram; - } - - // Validate that each item index points to a Tensor evalue. - for (flatbuffers::uoffset_t item_idx = 0; item_idx < items->size(); - item_idx++) { - int32_t evalue_index = items->Get(item_idx); - - // Check bounds. - if (evalue_index < 0 || - static_cast(evalue_index) >= - values->size()) { - ET_LOG( - Error, - "TensorList item %u has out-of-bounds index %d (values size " - "%u) in execution plan %u", - static_cast(item_idx), - evalue_index, - static_cast(values->size()), - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - // Check that the referenced evalue is actually a Tensor. - const auto* referenced_value = values->Get(evalue_index); - if (referenced_value == nullptr) { - ET_LOG( - Error, - "TensorList item %u references null evalue at index %d in " - "execution plan %u", - static_cast(item_idx), - evalue_index, - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - if (referenced_value->val_type() != - executorch_flatbuffer::KernelTypes::Tensor) { - ET_LOG( - Error, - "TensorList item %u references non-Tensor evalue (type %d) at " - "index %d in execution plan %u", - static_cast(item_idx), - static_cast(referenced_value->val_type()), - evalue_index, - static_cast(plan_idx)); - return Error::InvalidProgram; - } - } - } - } - } - - return Error::Ok; -} - -} // namespace runtime -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.h deleted file mode 100644 index 68e4ff7..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/include/executorch/runtime/executor/program_validation.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -// Forward declare flatbuffer types. -namespace executorch_flatbuffer { -struct ExecutionPlan; -struct Program; -struct Tensor; -struct TensorList; -} // namespace executorch_flatbuffer - -namespace executorch { -namespace runtime { - -/** - * Validates that a tensor's metadata is semantically valid: sizes are - * non-negative, scalar type is valid, and computing numel/nbytes will not - * overflow. - * - * @param[in] tensor The flatbuffer Tensor to validate. - * @return Error::Ok if validation passes, Error::InvalidProgram otherwise. - */ -ET_NODISCARD Error validate_tensor(const executorch_flatbuffer::Tensor* tensor); - -/** - * Performs validation of all tensors and lists in the program, checking that - * their metadata is semantically valid and will not cause issues during - * execution. - * - * Currently validates: - * - Tensor numel overflow (all tensors) - * - TensorList element types (all TensorLists) - * - * @param[in] program The flatbuffer Program to validate. - * @return Error::Ok if validation passes, Error::InvalidProgram if any - * validation check fails. - */ -ET_NODISCARD Error -validate_program(const executorch_flatbuffer::Program* program); - -} // namespace runtime -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend.cpp deleted file mode 100644 index 4b78f9a..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright 2023-2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Common Arm backend for Ethos-U. Please see - * EthosUBackend_Cortex_*.cpp for specific backends. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -// Overridable memcpy used by the EthosU backend for input/output scratch -// shuffling. Default (weak) implementation in EthosUBackend_IoMemcpy.cpp does -// std::memcpy. Firmware targets can supply a strong override (e.g. routing -// through a DMA engine) to reduce CPU memcpy load on the host MCU. -extern "C" void arm_ethos_io_memcpy(void* dst, const void* src, size_t size); - -using namespace std; - -using executorch::aten::ScalarType; -using executorch::runtime::ArrayRef; -using executorch::runtime::Backend; -using executorch::runtime::BackendExecutionContext; -using executorch::runtime::BackendInitContext; -using executorch::runtime::CompileSpec; -using executorch::runtime::DelegateHandle; -using executorch::runtime::Error; -using executorch::runtime::EValue; -using executorch::runtime::FreeableBuffer; -using executorch::runtime::MemoryAllocator; -using executorch::runtime::Result; -using executorch::runtime::Span; - -namespace executorch { -namespace backends { -namespace arm { - -extern "C" { -void __attribute__((weak)) EthosUBackend_execute_begin() {} -void __attribute__((weak)) EthosUBackend_execute_end() {} -__attribute__((weak)) unsigned char* ethosu_fast_scratch = nullptr; -__attribute__((weak)) size_t ethosu_fast_scratch_size = 0; -} - -class EthosUBackendExecuteCallbacks { - public: - EthosUBackendExecuteCallbacks() { - EthosUBackend_execute_begin(); - } - ~EthosUBackendExecuteCallbacks() { - EthosUBackend_execute_end(); - } -}; - -class EthosUBackend final : public ::executorch::runtime::BackendInterface { - public: - EthosUBackend() {} - - ~EthosUBackend() = default; - - virtual bool is_available() const override { - // TODO: revise to use a register check/init function - return 1; - } - - Result init( - BackendInitContext& context, - FreeableBuffer* processed, - ArrayRef compile_specs) const override { - ET_LOG(Info, "data:%p", processed->data()); - - const char* data = static_cast(processed->data()); - size_t size = processed->size(); - - // Verify format of vela_bin - if (vela_bin_validate(data, size) == false) { - ET_LOG(Error, "Malformed vela_bin_stream found"); - return Error::InvalidProgram; - } - - MemoryAllocator* allocator = context.get_runtime_allocator(); - ExecutionHandle* handle = new (std::nothrow) ExecutionHandle(); - if (handle == nullptr) { - return Error::MemoryAllocationFailed; - } - - handle->processed = processed; - handle->platform_state = platform_init(compile_specs, allocator); - - // Return the same buffer we were passed - this data will be - // executed directly - return handle; - } - - Error execute( - BackendExecutionContext& context, - DelegateHandle* input_handle, - Span args) const override { -#if defined(ET_EVENT_TRACER_ENABLED) - EventTracer* event_tracer = context.event_tracer(); - EventTracerEntry event_tracer_local_scope; -#endif - - EXECUTORCH_PROF_SCOPE(event_tracer, "EthosUBackend::execute()"); - - // CollectArm_CPU_Cycles is just used to save the numbers of CPU cycles - // used, If etdump is used the EXECUTORCH_PROF_SCOPE() above will do the - // same. If not, this is a cheap way of getting some stats and the - // CollectArm_CPU_Cycles object can safely be removed in production code. - // - // The EthosUBackendExecuteCallbacks class uses the C++ - // constructor/destructor to make sure that EthosUBackend_execute_begin() - // and EthosUBackend_execute_end() is called while CollectArm_CPU_Cycles is - // in scope. e.g. We meassure from now until we exit this metod (in any way - // we might do it). - EthosUBackendExecuteCallbacks CollectArm_CPU_Cycles; - - ExecutionHandle* execution_handle = - static_cast(input_handle); - VelaHandles handles; - - // Command stream - we know at this point it's aligned - EXECUTORCH_PROF_START( - event_tracer, - event_tracer_local_scope, - "+EthosUBackend::execute()processed_data"); - const char* data = - static_cast(execution_handle->processed->data()); - EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); - - ET_LOG(Debug, "data:%p", data); - - EXECUTORCH_PROF_START( - event_tracer, - event_tracer_local_scope, - "+EthosUBackend::execute()vela_bin_read()"); - // Read key sections from the vela_bin_stream - if (vela_bin_read(data, &handles, execution_handle->processed->size()) == - false) { - ET_LOG(Error, "vela_read: error, invalid binary layout"); - return Error::InvalidProgram; - } - EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); - - const int input_count = handles.inputs ? handles.inputs->count : 0; - const int output_count = handles.outputs ? handles.outputs->count : 0; - - MemoryAllocator* temp_allocator = context.get_temp_allocator(); - // Use a temporary allocator for the intermediate tensors of the - // computation. The allocator is released in runtime/executor/method.cpp at - // the end of the execution of the Ethos-U custom delegate - // Ethos-U driver requires 16 bit alignment. - char* ethosu_scratch = static_cast( - temp_allocator->allocate(handles.scratch_data_size, 16UL)); - if (ethosu_scratch == nullptr) { - ET_LOG( - Error, - "Failed to allocate scratch buffer of %zu bytes from temp_allocator", - handles.scratch_data_size); - return Error::MemoryAllocationFailed; - } - ET_LOG( - Debug, - "Running program data:\n cmd %p %zu\n weight %p %zu\n scratch %p %zu\n fast scratch %p %zu\n", - handles.cmd_data, - handles.cmd_data_size, - handles.weight_data, - handles.weight_data_size, - ethosu_scratch, - handles.scratch_data_size, - ethosu_fast_scratch, - ethosu_fast_scratch_size); - - // Write argument values (from EValue tensor) into Ethos-U scratch - // TODO(MLETORCH-123): Optimise into direct write from Vela into the SRAM - // or DRAM output for compatible data layouts. - for (int i = 0; i < input_count; i++) { - auto tensor_count = 1, io_count = 1; - auto tensor_in = args[i]->toTensor(); - char* scratch_addr = ethosu_scratch + handles.inputs->io[i].offset; - - // We accept: - bool supported = 0; - // 32 bit int (simple non-quantised test cases) - supported |= - (tensor_in.scalar_type() == ScalarType::Int && - handles.inputs->io[i].elem_size == 4); - // 8 bit int (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Char && - handles.inputs->io[i].elem_size == 1); - // 8 bit uint8 (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Byte && - handles.inputs->io[i].elem_size == 1); - // 16 bit int (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Short && - handles.inputs->io[i].elem_size == 2); - // bool (IOQDQ pass prepared networks) - supported |= - (tensor_in.scalar_type() == ScalarType::Bool && - handles.inputs->io[i].elem_size == 1); - if (!supported) { - ET_LOG( - Error, - "Input %d expected Integer (4 byte), Char (1 byte) or Bool (1 byte) integer inputs, got ScalarType id %s size %d", - i, - executorch::runtime::toString(tensor_in.scalar_type()), - handles.inputs->io[i].elem_size); - return Error::InvalidProgram; - } - - // Select a compatible copy routine including checking for input layouts - // which require permutation. - bool both_int = tensor_in.scalar_type() == ScalarType::Int && - handles.inputs->io[i].elem_size == 4; - bool both_char = (tensor_in.scalar_type() == ScalarType::Char || - tensor_in.scalar_type() == ScalarType::Byte) && - handles.inputs->io[i].elem_size == 1; - bool both_short = tensor_in.scalar_type() == ScalarType::Short && - handles.inputs->io[i].elem_size == 2; - bool both_bool = tensor_in.scalar_type() == ScalarType::Bool && - (handles.inputs->io[i].elem_size == 1); - - if (both_char || both_int || both_short || both_bool) { - EXECUTORCH_PROF_SCOPE( - event_tracer, "+EthosUBackend::execute()handles.input.memcpy()"); - // Sizes match and elt size matches so memcpy. - // Routed through arm_ethos_io_memcpy so firmware can DMA-accelerate. - arm_ethos_io_memcpy( - scratch_addr, - tensor_in.mutable_data_ptr(), - tensor_in.nbytes()); - } else { - ET_LOG(Error, "No matching input copy routine"); - return Error::InvalidProgram; - } - calculate_dimensions( - tensor_in, &handles.inputs->io[i], &tensor_count, &io_count); - if (tensor_count != io_count) { - ET_LOG(Error, "Input tensor sizes do not match"); - ET_LOG( - Error, - "Program expects %d elements but got %d", - io_count, - tensor_count); - return Error::InvalidProgram; - } - } - - EXECUTORCH_PROF_START( - event_tracer, event_tracer_local_scope, "+EthosUBackend::execute()NPU"); - Error platform_status = platform_execute( - context, - execution_handle, - handles, - input_count, - output_count, - args, - ethosu_scratch); - EXECUTORCH_PROF_END(event_tracer, event_tracer_local_scope); - return platform_status; - } - - void destroy(DelegateHandle* handle) const override { - if (handle == nullptr) { - return; - } - - // Explicitly destroy platform-specific state before releasing the - // execution handle to avoid leaking resources such as std::string. - auto* exec_handle = reinterpret_cast(handle); - - if (exec_handle->platform_state != nullptr) { - platform_destroy(exec_handle->platform_state); - } - - delete exec_handle; - } - - private: - // No platform-specific members. -}; - -Error copy_with_layout_adjustment( - const VelaIO& output_io, - int output_index, - const char* src, - executorch::aten::Tensor& tensor_out, - size_t tensor_bytes) { - const int elem_size = output_io.elem_size; - if (elem_size == 0) { - ET_LOG(Error, "Ethos-U output %d reports zero element size", output_index); - return Error::InvalidProgram; - } - - size_t chunk_count = 1; - for (int dim = 0; dim < shapeDim - 1; ++dim) { - const int vela_dim = output_io.shape[dim]; - chunk_count *= static_cast(vela_dim == 0 ? 1 : vela_dim); - } - const int last_dim = output_io.shape[shapeDim - 1]; - const size_t vela_chunk_elems = - static_cast(last_dim == 0 ? 1 : last_dim); - const size_t vela_chunk_size = - vela_chunk_elems * static_cast(elem_size); - - if (tensor_bytes % chunk_count != 0) { - ET_LOG( - Error, - "Ethos-U output %d tensor bytes %zu not divisible by chunk count %zu", - output_index, - tensor_bytes, - chunk_count); - return Error::InvalidProgram; - } - - const size_t chunk_size = tensor_bytes / chunk_count; - - // If Vela writes fewer bytes than the tensor expects we may need to - // expand 4-bit data to 8-bit. Ethos-U outputs may be - // packed 4-bit values but ExecuTorch tensors are at least 8-bit. - if (vela_chunk_size < chunk_size) { - if (chunk_size % vela_chunk_size != 0) { - ET_LOG( - Error, - "Ethos-U output %d chunk bytes %zu not divisible by vela chunk bytes %zu", - output_index, - chunk_size, - vela_chunk_size); - return Error::InvalidProgram; - } - - const size_t expand_factor = chunk_size / vela_chunk_size; - if (expand_factor == 2 && elem_size == 1 && - tensor_out.scalar_type() == ScalarType::Char) { - const uint8_t* src_bytes = reinterpret_cast(src); - int8_t* dest = tensor_out.mutable_data_ptr(); - const uint8_t* chunk_src = src_bytes; - int8_t* chunk_dest = dest; - for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { - for (size_t byte_idx = 0; byte_idx < vela_chunk_size; ++byte_idx) { - const uint8_t packed = chunk_src[byte_idx]; - int8_t low = static_cast(packed & 0x0F); - int8_t high = static_cast((packed >> 4) & 0x0F); - if (low >= 8) { - low -= 16; - } - if (high >= 8) { - high -= 16; - } - chunk_dest[2 * byte_idx] = low; - chunk_dest[2 * byte_idx + 1] = high; - } - chunk_src += vela_chunk_size; - chunk_dest += chunk_size; - } - return Error::Ok; - } - - ET_LOG( - Error, - "Ethos-U output %d expansion factor %zu with element size %d not supported", - output_index, - expand_factor, - elem_size); - return Error::InvalidProgram; - } - - if (src == nullptr) { - ET_LOG(Error, "Ethos-U padded copy received null buffer"); - return Error::InvalidState; - } - char* dest = tensor_out.mutable_data_ptr(); - if (dest == nullptr) { - ET_LOG(Error, "Ethos-U padded copy received null destination"); - return Error::InvalidState; - } - const char* src_bytes = src; - for (size_t chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) { - // Routed through arm_ethos_io_memcpy so firmware can DMA-accelerate. - arm_ethos_io_memcpy(dest, src_bytes, chunk_size); - src_bytes += vela_chunk_size; - dest += chunk_size; - } - return Error::Ok; -} - -void calculate_dimensions( - const executorch::aten::Tensor tensor, - VelaIO* io, - int* tensor_count, - int* io_count) { - for (int i = 0; i < tensor.dim(); i++) { - *tensor_count = *tensor_count * tensor.size(i); - } - - // The VelaIO type has a shape of fixed size 6 - for (int i = 0; i < shapeDim; i++) { - *io_count = *io_count * io->shape[i]; - } -} - -namespace { -auto EthosUBackend_backend = EthosUBackend(); -Backend EthosUBackend_id{"EthosUBackend", &EthosUBackend_backend}; -static executorch::runtime::Error EthosUBackend_registered = - register_backend(EthosUBackend_id); - -// DEPRECATED in Executorch 1.2 -// Remove it from your code and make sure to add this to your CMAKE rules -// instead: -// executorch_target_link_options_shared_lib(executorch_delegate_ethos_u) -extern "C" ET_DEPRECATED executorch::runtime::Error -executorch_delegate_EthosUBackend_registered() { - return EthosUBackend_registered; -} - -} // namespace - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_A.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_A.cpp deleted file mode 100644 index 5da0996..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_A.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Arm backend for Ethos-U Linux driver stack, this relies on the - * ethos-u-linux-driver-stack for hardware interaction. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -using executorch::runtime::ArrayRef; -using executorch::runtime::BackendExecutionContext; -using executorch::runtime::CompileSpec; -using executorch::runtime::Error; -using executorch::runtime::MemoryAllocator; -using executorch::runtime::Span; - -namespace executorch { -namespace backends { -namespace arm { - -constexpr int64_t kDefaultEthosUTimeoutNs = 60000000000LL; - -struct LinuxDriverOptions { - std::string device_path = "/dev/ethosu0"; - int64_t timeout_ns = kDefaultEthosUTimeoutNs; - bool enable_cycle_counter = true; - std::array pmu_events{}; -}; - -struct PlatformState { - LinuxDriverOptions options; -}; - -namespace { - -template -bool read_scalar_value(const CompileSpec& spec, T* out) { - if (spec.value.buffer == nullptr || spec.value.nbytes != sizeof(T)) { - return false; - } - std::memcpy(out, spec.value.buffer, sizeof(T)); - return true; -} - -std::string read_string_value(const CompileSpec& spec) { - if (spec.value.buffer == nullptr || spec.value.nbytes == 0) { - return ""; - } - const char* raw_begin = static_cast(spec.value.buffer); - const char* raw_end = raw_begin + spec.value.nbytes; - std::string result(raw_begin, raw_end); - while (!result.empty() && result.back() == '\0') { - result.pop_back(); - } - return result; -} - -LinuxDriverOptions parse_linux_options(ArrayRef specs) { - LinuxDriverOptions options; - constexpr char kDeviceKey[] = "ethosu.device"; - constexpr char kTimeoutKey[] = "ethosu.timeout_ns"; - constexpr char kCycleCounterKey[] = "ethosu.enable_cycle_counter"; - constexpr char kPmuPrefix[] = "ethosu.pmu_event"; - - for (const CompileSpec& spec : specs) { - if (spec.key == nullptr) { - continue; - } - - if (strcmp(spec.key, kDeviceKey) == 0) { - std::string device_path = read_string_value(spec); - if (!device_path.empty()) { - options.device_path = device_path; - } - continue; - } - - if (strcmp(spec.key, kTimeoutKey) == 0) { - int64_t timeout = 0; - if (read_scalar_value(spec, &timeout) && timeout > 0) { - options.timeout_ns = timeout; - } - continue; - } - - if (strcmp(spec.key, kCycleCounterKey) == 0) { - uint8_t enabled = 0; - if (read_scalar_value(spec, &enabled)) { - options.enable_cycle_counter = enabled != 0; - } - continue; - } - - if (strncmp(spec.key, kPmuPrefix, strlen(kPmuPrefix)) == 0) { - const char* index_str = spec.key + strlen(kPmuPrefix); - char* endptr = nullptr; - long idx = std::strtol(index_str, &endptr, 10); - if (endptr != index_str && idx >= 0 && - idx < static_cast(ETHOSU_PMU_EVENT_MAX)) { - uint32_t event = 0; - if (read_scalar_value(spec, &event)) { - options.pmu_events[static_cast(idx)] = event; - } - } - } - } - - return options; -} - -class EthosULinuxDeviceCache { - public: - EthosU::Device& get(const std::string& device_path) { - std::lock_guard lock(mutex_); - if (!device_ || device_path != active_path_) { - device_ = std::make_unique(device_path.c_str()); - active_path_ = device_path; - } - return *device_; - } - - private: - std::mutex mutex_; - std::string active_path_; - std::unique_ptr device_; -}; - -EthosULinuxDeviceCache& get_linux_device_cache() { - static EthosULinuxDeviceCache cache; - return cache; -} - -/* - * Used for logging when building in Debug mode, but unused building - * for Release. - */ -[[maybe_unused]] const char* inference_status_to_string( - EthosU::InferenceStatus status) { - switch (status) { - case EthosU::InferenceStatus::OK: - return "OK"; - case EthosU::InferenceStatus::ERROR: - return "ERROR"; - case EthosU::InferenceStatus::RUNNING: - return "RUNNING"; - case EthosU::InferenceStatus::REJECTED: - return "REJECTED"; - case EthosU::InferenceStatus::ABORTED: - return "ABORTED"; - case EthosU::InferenceStatus::ABORTING: - return "ABORTING"; - case EthosU::InferenceStatus::PENDING: - return "PENDING"; - } - return "UNKNOWN"; -} - -Error invoke_linux_driver( - const VelaHandles& handles, - const std::vector& input_ptrs, - const std::vector& output_ptrs, - const std::vector& input_copy_sizes, - const std::vector& output_copy_sizes, - const LinuxDriverOptions& options) { - if (handles.outputs == nullptr) { - ET_LOG(Error, "Ethos-U backend missing output metadata"); - return Error::InvalidProgram; - } - - try { - EthosU::Device& device = get_linux_device_cache().get(options.device_path); - auto network = std::make_shared( - device, - reinterpret_cast(handles.cmd_data), - handles.cmd_data_size); - - std::shared_ptr constant_buffer = - std::make_shared(); - if (handles.weight_data_size > 0) { - auto constant_buffers = device.createBuffers({handles.weight_data_size}); - constant_buffer = constant_buffers.front(); - constant_buffer->write( - const_cast(handles.weight_data), handles.weight_data_size); - } - - std::shared_ptr intermediate_buffer = - std::make_shared(); - if (handles.scratch_data_size > 0) { - auto scratch_buffers = device.createBuffers({handles.scratch_data_size}); - intermediate_buffer = scratch_buffers.front(); - } - - std::vector> ifm_buffers; - if (handles.inputs != nullptr && handles.inputs->count > 0) { - if (input_copy_sizes.size() != - static_cast(handles.inputs->count)) { - ET_LOG( - Error, - "Mismatch between input metadata (%d) and copy plan (%zu)", - handles.inputs->count, - input_copy_sizes.size()); - return Error::InvalidProgram; - } - if (input_ptrs.size() != input_copy_sizes.size()) { - ET_LOG( - Error, - "Mismatch between input metadata and runtime pointers (%zu vs %zu)", - input_ptrs.size(), - input_copy_sizes.size()); - return Error::InvalidState; - } - ifm_buffers = device.createBuffers(input_copy_sizes); - for (int i = 0; i < handles.inputs->count; ++i) { - const size_t copy_size = input_copy_sizes[i]; - if (copy_size == 0) { - continue; - } - const char* src = input_ptrs[i]; - if (src == nullptr) { - ET_LOG(Error, "Missing input buffer for index %d", i); - return Error::InvalidState; - } - ifm_buffers[i]->write(const_cast(src), copy_size); - } - } - - if (output_copy_sizes.size() != - static_cast(handles.outputs->count)) { - ET_LOG( - Error, - "Mismatch between output metadata (%d) and copy plan (%zu)", - handles.outputs->count, - output_copy_sizes.size()); - return Error::InvalidProgram; - } - if (output_ptrs.size() != output_copy_sizes.size()) { - ET_LOG( - Error, - "Mismatch between output metadata and runtime buffers (%zu vs %zu)", - output_ptrs.size(), - output_copy_sizes.size()); - return Error::InvalidState; - } - auto ofm_buffers = device.createBuffers(output_copy_sizes); - - auto inference = std::make_unique( - network, - ifm_buffers.begin(), - ifm_buffers.end(), - ofm_buffers.begin(), - ofm_buffers.end(), - intermediate_buffer, - constant_buffer, - options.pmu_events, - options.enable_cycle_counter); - - if (inference->wait(options.timeout_ns)) { - ET_LOG( - Error, - "Ethos-U inference timed out after %lld ns", - static_cast(options.timeout_ns)); - return Error::InvalidState; - } - - auto status = inference->status(); - if (status != EthosU::InferenceStatus::OK) { - ET_LOG( - Error, - "Ethos-U inference failed with status %s", - inference_status_to_string(status)); - return Error::InvalidState; - } - - if (options.enable_cycle_counter) { - try { - ET_LOG( - Info, - "Ethos-U Linux delegate cycle counter: %llu", - static_cast(inference->getCycleCounter())); - } catch (const std::exception& e) { - ET_LOG(Debug, "Failed to read Ethos-U cycle counter: %s", e.what()); - } - } - - for (int i = 0; i < handles.outputs->count; ++i) { - const size_t copy_size = output_copy_sizes[i]; - if (copy_size == 0) { - continue; - } - char* dst = output_ptrs[i]; - if (dst == nullptr) { - ET_LOG(Error, "Missing output buffer for index %d", i); - return Error::InvalidState; - } - ofm_buffers[i]->read(dst, copy_size); - } - } catch (const std::exception& e) { - ET_LOG(Error, "Ethos-U Linux driver invocation failed: %s", e.what()); - return Error::InvalidState; - } - - return Error::Ok; -} -} // namespace - -PlatformState* platform_init( - ArrayRef specs, - MemoryAllocator* allocator) { - (void)allocator; - PlatformState* state = new (std::nothrow) PlatformState(); - if (state == nullptr) { - return nullptr; - } - state->options = parse_linux_options(specs); - return state; -} - -void platform_destroy(PlatformState* state) { - delete state; -} - -Error platform_execute( - BackendExecutionContext& /*context*/, - const ExecutionHandle* execution_handle, - const VelaHandles& handles, - int input_count, - int output_count, - Span args, - char* /*ethosu_scratch*/) { - std::vector input_copy_sizes(input_count, 0); - std::vector linux_input_ptrs(input_count, nullptr); - - std::vector output_io_bytes(output_count, 0); - std::vector linux_output_ptrs(output_count, nullptr); - std::vector> output_scratch_buffers(output_count); - std::vector output_needs_adjustment(output_count, false); - - for (int i = 0; i < input_count; ++i) { - auto tensor_in = args[i]->toTensor(); - linux_input_ptrs[i] = tensor_in.const_data_ptr(); - input_copy_sizes[i] = tensor_in.nbytes(); - } - - if (handles.outputs != nullptr) { - for (int i = 0; i < output_count; ++i) { - int tensor_count = 1, io_count = 1; - auto tensor_out = args[input_count + i]->toTensor(); - calculate_dimensions( - tensor_out, &handles.outputs->io[i], &tensor_count, &io_count); - if (i < static_cast(output_io_bytes.size())) { - output_io_bytes[i] = static_cast(io_count) * - static_cast(handles.outputs->io[i].elem_size); - } - const size_t tensor_nbytes = tensor_out.nbytes(); - if (i < static_cast(output_io_bytes.size()) && - output_io_bytes[i] != tensor_nbytes) { - output_scratch_buffers[i].resize(output_io_bytes[i]); - linux_output_ptrs[i] = output_scratch_buffers[i].data(); - output_needs_adjustment[i] = true; - } else { - linux_output_ptrs[i] = tensor_out.mutable_data_ptr(); - } - } - } - - const PlatformState* state = execution_handle->platform_state; - if (state == nullptr) { - ET_LOG(Error, "Ethos-U Linux backend missing platform state"); - return Error::InvalidState; - } - - Error status = invoke_linux_driver( - handles, - linux_input_ptrs, - linux_output_ptrs, - input_copy_sizes, - output_io_bytes, - state->options); - if (status != Error::Ok) { - return status; - } - - if (handles.outputs != nullptr) { - for (int i = 0; i < output_count; ++i) { - if (!output_needs_adjustment[i]) { - continue; - } - auto tensor_out = args[input_count + i]->toTensor(); - const size_t tensor_nbytes = tensor_out.nbytes(); - Error adjust_status = copy_with_layout_adjustment( - handles.outputs->io[i], - i, - output_scratch_buffers[i].data(), - tensor_out, - tensor_nbytes); - if (adjust_status != Error::Ok) { - return adjust_status; - } - } - } - - return Error::Ok; -} - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_M.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_M.cpp deleted file mode 100644 index 9639876..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Cortex_M.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Arm backend for Ethos-U baremetal driver stack, this relies on the - * ethos-u-core-driver for hardware interaction. - */ - -#include -#include -#include -#include - -#include - -#include -#include - -using executorch::runtime::BackendExecutionContext; -using executorch::runtime::Error; -using executorch::runtime::Span; - -// Compatibility hooks for multi-device driver / non-multi-device driver code -// When multi-device driver code is available, these declarations are overridden -extern "C" __attribute__((weak)) int ethosu_get_product_config_from_cop_data( - const void*, - const int, - uint32_t* product_out, - uint32_t* log2_macs_out) { - *product_out = 0; - *log2_macs_out = 0; - return 0; -} - -extern "C" __attribute__((weak)) struct ethosu_driver* ethosu_reserve_driver_ex( - uint32_t, - uint32_t) { - return ethosu_reserve_driver(); -} - -// Overridable memcpy used by the EthosU backend for output scratch -// shuffling. Default (weak) implementation in EthosUBackend_IoMemcpy.cpp does -// std::memcpy. Firmware targets can supply a strong override (e.g. routing -// through a DMA engine) to reduce CPU memcpy load on the host MCU. -extern "C" void arm_ethos_io_memcpy(void* dst, const void* src, size_t size); - -namespace executorch { -namespace backends { -namespace arm { - -struct PlatformState {}; - -PlatformState* platform_init( - executorch::runtime::ArrayRef /*specs*/, - executorch::runtime::MemoryAllocator* /*allocator*/) { - return nullptr; -} - -void platform_destroy(PlatformState* state) { - delete state; -} - -Error platform_execute( - BackendExecutionContext& /*context*/, - const ExecutionHandle* /*execution_handle*/, - const VelaHandles& handles, - int input_count, - int output_count, - Span args, - char* ethosu_scratch) { - // Parse product config from command stream to reserve the correct driver - uint32_t product, log2_macs; - // The weak fallback below always returns 0, but some builds replace it - // with a real driver implementation that can return an error code. - const int product_config_status = ethosu_get_product_config_from_cop_data( - handles.cmd_data, handles.cmd_data_size, &product, &log2_macs); - if (product_config_status != 0) { // cppcheck-suppress knownConditionTrueFalse - ET_LOG(Error, "Failed to parse product config from command stream"); - return Error::InvalidProgram; - } - - // Allocate driver handle and synchronously invoke driver - auto driver = - std::unique_ptr( - ethosu_reserve_driver_ex(product, log2_macs), ethosu_release_driver); - if (driver == nullptr) { - ET_LOG(Error, "ethosu_reserve_driver_ex failed"); - return Error::InvalidState; - } - - // Ethos-U low level driver expected order for Ethos U-55, we have - // constant weight data, then scratch (which contains input and output) - // scratch is written above in this function. - uint64_t bases[ETHOSU_NUM_BASE_ADDRS] = { - static_cast(reinterpret_cast((handles.weight_data))), - static_cast(reinterpret_cast(ethosu_scratch)), - static_cast(reinterpret_cast(ethosu_fast_scratch))}; - size_t bases_size[ETHOSU_NUM_BASE_ADDRS] = { - handles.weight_data_size, - handles.scratch_data_size, - ethosu_fast_scratch_size}; - int result = ethosu_invoke_v3( - driver.get(), - static_cast(handles.cmd_data), - handles.cmd_data_size, - bases, - bases_size, - ETHOSU_NUM_BASE_ADDRS, /* fixed array of pointers to binary interface*/ - nullptr); - - if (result != 0) { - ET_LOG(Error, "Ethos-U invocation failed error (%d)", result); - return Error::InvalidProgram; - } - - size_t tensor_bytes_total = 0; - size_t io_bytes_total = 0; - // Write outputs from scratch into EValue pointers - for (int i = 0; i < output_count; i++) { - int tensor_count = 1, io_count = 1; - const char* output_addr = ethosu_scratch + handles.outputs->io[i].offset; - // Process input EValue into scratch - // Outputs are in the index immediately after inputs - auto tensor_out = args[input_count + i]->toTensor(); - - calculate_dimensions( - tensor_out, &handles.outputs->io[i], &tensor_count, &io_count); - - size_t tensor_bytes = tensor_out.nbytes(); - size_t io_bytes = static_cast(io_count) * - static_cast(handles.outputs->io[i].elem_size); - - if (tensor_bytes != io_bytes) { - Error status = copy_with_layout_adjustment( - handles.outputs->io[i], i, output_addr, tensor_out, tensor_bytes); - if (status != Error::Ok) { - return status; - } - io_bytes_total += tensor_bytes; - } else { - // Routed through arm_ethos_io_memcpy so firmware can DMA-accelerate. - arm_ethos_io_memcpy( - tensor_out.mutable_data_ptr(), - static_cast(output_addr), - tensor_bytes); - io_bytes_total += io_bytes; - } - - // At times the topological order of the outputs may change. - // Lets instead ensure that the sum of output bytes match. - tensor_bytes_total += tensor_bytes; - } - if (tensor_bytes_total != io_bytes_total) { - ET_LOG(Error, "Total output tensor sizes do not match"); - ET_LOG( - Error, - "Program expects %zu bytes but got %zu", - io_bytes_total, - tensor_bytes_total); - return Error::InvalidProgram; - } - return Error::Ok; -} - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Internal.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Internal.h deleted file mode 100644 index f3b05fa..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_Internal.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -// Workaround for runtime/core/portable_type/c10/c10/util/Float16-math.h -#if defined(__GNUC__) && defined(__ZEPHYR__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdouble-promotion" -#endif - -#include -#include - -#include -#include -#include -#include - -#if defined(__GNUC__) && defined(__ZEPHYR__) -#pragma GCC diagnostic pop -#endif - -#if defined(ET_EVENT_TRACER_ENABLED) -#include -#include -using executorch::runtime::EventTracer; -using executorch::runtime::EventTracerEntry; - -class EventTraceScope { - public: - EventTraceScope(EventTracer* event_tracer_, const char* name) { - event_tracer = event_tracer_; - event_tracer_entry_scope = event_tracer->start_profiling(name); - } - ~EventTraceScope() { - event_tracer->end_profiling(event_tracer_entry_scope); - } - - private: - EventTracer* event_tracer; - EventTracerEntry event_tracer_entry_scope; -}; -#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) \ - EventTraceScope event_tracer_scope = EventTraceScope(EVENTTRACER, NAME) -#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) \ - SCOPE = EVENTTRACER->start_profiling(NAME) -#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) \ - EVENTTRACER->end_profiling(SCOPE) -#else -#define EXECUTORCH_PROF_SCOPE(EVENTTRACER, NAME) -#define EXECUTORCH_PROF_START(EVENTTRACER, SCOPE, NAME) -#define EXECUTORCH_PROF_END(EVENTTRACER, SCOPE) -#endif - -#define ETHOSU_NUM_BASE_ADDRS 3 - -namespace executorch { -namespace backends { -namespace arm { - -struct PlatformState; - -struct ExecutionHandle { - executorch::runtime::FreeableBuffer* processed; - PlatformState* platform_state; -}; - -extern "C" { -void EthosUBackend_execute_begin(); -void EthosUBackend_execute_end(); -extern unsigned char* ethosu_fast_scratch; -extern size_t ethosu_fast_scratch_size; -} - -PlatformState* platform_init( - executorch::runtime::ArrayRef specs, - executorch::runtime::MemoryAllocator* allocator); -void platform_destroy(PlatformState* state); -executorch::runtime::Error platform_execute( - executorch::runtime::BackendExecutionContext& context, - const ExecutionHandle* execution_handle, - const VelaHandles& handles, - int input_count, - int output_count, - executorch::runtime::Span args, - char* ethosu_scratch); - -executorch::runtime::Error copy_with_layout_adjustment( - const VelaIO& output_io, - int output_index, - const char* src, - executorch::aten::Tensor& tensor_out, - size_t tensor_bytes); - -void calculate_dimensions( - const executorch::aten::Tensor tensor, - VelaIO* io, - int* tensor_count, - int* io_count); - -} // namespace arm -} // namespace backends -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp deleted file mode 100644 index 1ef5b74..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/arm/runtime/EthosUBackend_IoMemcpy.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -// Weak default for arm_ethos_io_memcpy. Firmware targets can provide a -// strong-symbol override (e.g. routing through DMA on Cortex-M55) without -// touching the upstream EthosUBackend code. Lives in its own translation -// unit so the compiler in the call-site TUs cannot inline this body and -// bypass the link-time override (same trick as bolt_arm_memcpy_external). -extern "C" __attribute__((weak)) void -arm_ethos_io_memcpy(void* dst, const void* src, size_t size) { - std::memcpy(dst, src, size); -} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/cortex_m_ops_common.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/cortex_m_ops_common.h deleted file mode 100644 index 4c0f83d..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/cortex_m_ops_common.h +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * Copyright 2025-2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "arm_nn_types.h" -#include "arm_nnfunctions.h" - -using Tensor = torch::executor::Tensor; -using ScalarType = executorch::aten::ScalarType; -using Error = executorch::runtime::Error; -using Int64ArrayRef = executorch::aten::ArrayRef; -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -// From arm_nn_math_types.h -#define ARM_NN_Q31_MAX ((int32_t)(0x7FFFFFFFL)) -#define ARM_NN_Q31_MIN ((int32_t)(0x80000000L)) - -// 16-byte alignment for MVE vector operations. -constexpr size_t kCortexMMveAlignment = 16; - -// Basic tensor type / layout validation and dimension order checking -inline void validate_cmsis_nn_tensor_requirements( - const Tensor& input1, - const Tensor& input2, - Tensor& output, - ScalarType expected_dtype = ScalarType::Char, - bool require_channels_last = false, - bool require_same_sizes = true) { - // Basic dtype validation - ET_CHECK_MSG( - input1.scalar_type() == expected_dtype, - "Input1 dtype must be %d, got %d", - static_cast(expected_dtype), - static_cast(input1.scalar_type())); - ET_CHECK_MSG( - input2.scalar_type() == expected_dtype, - "Input2 dtype must be %d, got %d", - static_cast(expected_dtype), - static_cast(input2.scalar_type())); - ET_CHECK_MSG( - output.scalar_type() == expected_dtype, - "Output dtype must be %d, got %d", - static_cast(expected_dtype), - static_cast(output.scalar_type())); - if (require_same_sizes) { - ET_CHECK_MSG( - input1.sizes() == input2.sizes(), - "Input1 and Input2 must have the same sizes"); - ET_CHECK_MSG( - output.sizes() == input1.sizes(), - "Output must have the same sizes as inputs"); - } - - // TBD (#16032): Validate dim_order - // TBD: Validate memory alignment (CMSIS-NN requirement) -} - -inline void validate_single_quant_params( - const int64_t zero_point, - const int64_t multiplier, - const int64_t shift, - const char* param_name) { - (void)zero_point; - ET_CHECK_MSG( - multiplier >= std::numeric_limits::min() && - multiplier <= std::numeric_limits::max(), - "%s multiplier must be in int32 range [Value: %" PRIi64 "]", - param_name, - multiplier); - - ET_CHECK_MSG( - shift >= -31 && shift <= 31, - "%s shift must be in range [-31, 31] [Value: %" PRIi64 "]", - param_name, - shift); -} - -/** - * Validate quantization parameters for inputs and output. - * - * Checks that zero points fit in int8 range, multipliers fit in int32 range, - * and shifts are within a valid bit-shift range (0-31). - * - * Ensures parameters comply with Ahead-Of-Time (AOT) quantization requirements - * and CMSIS-NN kernel expectations. - * - * Raises errors via ET_KERNEL_CHECK if any check fails. - */ -inline void validate_quantization_params( - const int64_t zero_point1, - const int64_t multiplier1, - const int64_t shift1, - const int64_t zero_point2, - const int64_t multiplier2, - const int64_t shift2, - const int64_t output_zero_point, - const int64_t output_multiplier, - const int64_t output_shift, - Tensor& output) { - validate_single_quant_params( - zero_point1, multiplier1, shift1, "Single quant Input1"); - validate_single_quant_params( - zero_point2, multiplier2, shift2, "Single quant Input2"); - validate_single_quant_params( - output_zero_point, - output_multiplier, - output_shift, - "Single quant Output"); -} - -inline bool is_channels_last_tensor(const Tensor& tensor) { - if (tensor.dim() != 4) { - return false; - } - - // When channels or spatial dims are 1 the layout information is ambiguous. - if (tensor.size(1) == 1 || (tensor.size(2) == 1 && tensor.size(3) == 1)) { - return true; - } - - constexpr executorch::aten::DimOrderType kChannelsLastDimOrder[] = { - 0, 2, 3, 1}; - executorch::aten::ArrayRef - channels_last_order(kChannelsLastDimOrder, 4); - - return tensor.dim_order() == channels_last_order; -} - -inline bool is_channel_broadcast(const Tensor& tensor1, const Tensor& tensor2) { - if (tensor1.dim() != tensor2.dim()) { - return false; - } - - if (tensor1.dim() != 4) { - return false; - } - - if (tensor1.size(1) != tensor2.size(1)) { - return false; - } - - const bool tensor1_channels_only = tensor1.numel() == tensor1.size(1); - const bool tensor2_channels_only = tensor2.numel() == tensor2.size(1); - - return tensor1_channels_only || tensor2_channels_only; -} - -inline bool check_int32_within_range( - KernelRuntimeContext& context, - const char* op_name, - int64_t value, - const char* value_name, - int32_t& out_value) { - if (value < std::numeric_limits::min() || - value > std::numeric_limits::max()) { - ET_LOG( - Error, - "%s: %s value (%" PRIi64 ") exceeds int32_t range", - op_name, - value_name, - value); - context.fail(Error::InvalidArgument); - return false; - } - out_value = static_cast(value); - return true; -} - -struct CmsisPool2DConfig { - cmsis_nn_pool_params pool_params; - cmsis_nn_dims input_dims; - cmsis_nn_dims filter_dims; - cmsis_nn_dims output_dims; -}; - -inline bool prepare_cmsis_pool2d_config( - KernelRuntimeContext& context, - const char* op_name, - const Tensor& input, - Tensor& output, - const Int64ArrayRef& kernel_size, - const Int64ArrayRef& stride, - const Int64ArrayRef& padding, - const Int64ArrayRef& dilation, - bool ceil_mode, - int64_t activation_min, - int64_t activation_max, - CmsisPool2DConfig& config, - bool require_channels_last = true, - bool allow_ceil_mode = false) { - if (input.dim() != 4 || output.dim() != 4) { - ET_LOG(Error, "%s: tensors must be 4-D", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (input.scalar_type() != ScalarType::Char || - output.scalar_type() != ScalarType::Char) { - ET_LOG(Error, "%s: tensors must be int8", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (input.size(0) != output.size(0) || input.size(1) != output.size(1)) { - ET_LOG( - Error, - "%s: batch and channel dimensions must match between input and output", - op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (require_channels_last) { - if (!is_channels_last_tensor(input) || !is_channels_last_tensor(output)) { - ET_LOG( - Error, "%s: tensors must use channels_last dimension order", op_name); - context.fail(Error::InvalidArgument); - return false; - } - } - - auto check_tuple_len = [&](const Int64ArrayRef& arr, - const char* name) -> bool { - if (arr.size() != 2) { - ET_LOG(Error, "%s: %s must have length 2", op_name, name); - context.fail(Error::InvalidArgument); - return false; - } - return true; - }; - - if (!check_tuple_len(kernel_size, "kernel_size") || - !check_tuple_len(stride, "stride") || - !check_tuple_len(padding, "padding") || - !check_tuple_len(dilation, "dilation")) { - return false; - } - - if (!allow_ceil_mode && ceil_mode) { - ET_LOG(Error, "%s: ceil_mode=True is not supported", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - if (activation_min > activation_max) { - ET_LOG( - Error, - "%s: activation_min (%lld) must be <= activation_max (%lld)", - op_name, - static_cast(activation_min), - static_cast(activation_max)); - context.fail(Error::InvalidArgument); - return false; - } - - int32_t activation_min_i32, activation_max_i32; - if (!check_int32_within_range( - context, - op_name, - activation_min, - "activation_min", - activation_min_i32) || - !check_int32_within_range( - context, - op_name, - activation_max, - "activation_max", - activation_max_i32)) { - return false; - } - - int32_t kernel_h, kernel_w, stride_h, stride_w, pad_h, pad_w, dil_h, dil_w; - if (!check_int32_within_range( - context, op_name, kernel_size[0], "kernel_size[0]", kernel_h) || - !check_int32_within_range( - context, op_name, kernel_size[1], "kernel_size[1]", kernel_w) || - !check_int32_within_range( - context, op_name, stride[0], "stride[0]", stride_h) || - !check_int32_within_range( - context, op_name, stride[1], "stride[1]", stride_w) || - !check_int32_within_range( - context, op_name, padding[0], "padding[0]", pad_h) || - !check_int32_within_range( - context, op_name, padding[1], "padding[1]", pad_w) || - !check_int32_within_range( - context, op_name, dilation[0], "dilation[0]", dil_h) || - !check_int32_within_range( - context, op_name, dilation[1], "dilation[1]", dil_w)) { - return false; - } - - if (dil_h != 1 || dil_w != 1) { - ET_LOG(Error, "%s: dilation other than 1 is unsupported", op_name); - context.fail(Error::InvalidArgument); - return false; - } - - int32_t batch, channels, input_h, input_w, output_h, output_w; - if (!check_int32_within_range( - context, op_name, input.size(0), "input batch", batch) || - !check_int32_within_range( - context, op_name, input.size(1), "input channels", channels) || - !check_int32_within_range( - context, op_name, input.size(2), "input height", input_h) || - !check_int32_within_range( - context, op_name, input.size(3), "input width", input_w) || - !check_int32_within_range( - context, op_name, output.size(2), "output height", output_h) || - !check_int32_within_range( - context, op_name, output.size(3), "output width", output_w)) { - return false; - } - - config.input_dims = cmsis_nn_dims{batch, input_h, input_w, channels}; - config.filter_dims = cmsis_nn_dims{1, kernel_h, kernel_w, 1}; - config.output_dims = cmsis_nn_dims{batch, output_h, output_w, channels}; - config.pool_params.padding.h = pad_h; - config.pool_params.padding.w = pad_w; - config.pool_params.stride.h = stride_h; - config.pool_params.stride.w = stride_w; - config.pool_params.activation.min = activation_min_i32; - config.pool_params.activation.max = activation_max_i32; - - return true; -} - -// Refer to CMSIS-NN 'arm_nn_requantize' implementation for details: -// https://github.com/ARM-software/CMSIS-NN/blob/main/Include/arm_nnsupportfunctions.h#L1625 -// multiplier: Range {ARM_NN_Q31_MIN + 1, Q32_MAX} -// shift : Range {-31, 30} -inline bool validate_per_channel_quant_params( - const Int64ArrayRef multipliers, - const Int64ArrayRef shifts, - int num_channels) { - for (int i = 0; i < num_channels; ++i) { - // Multiplier: {ARM_NN_Q31_MIN + 1, ARM_NN_Q31_MAX} - if (multipliers[i] <= ARM_NN_Q31_MIN || multipliers[i] > ARM_NN_Q31_MAX) { - ET_LOG( - Error, - "weight_multiplier[%d] out of CMSIS-NN range: %" PRIi64, - i, - multipliers[i]); - return false; - } - // Shift: {-31, 30} for arm_nn_requantize - if (shifts[i] < -31 || shifts[i] > 30) { - ET_LOG(Error, "weight_shift[%d] out of range: %" PRIi64, i, shifts[i]); - return false; - } - } - return true; -} - -inline Error resize_to_broadcast_target_size( - const Tensor& input1, - const Tensor& input2, - Tensor& output) { - static constexpr int kTensorDimensionLimit = 5; - Tensor::SizesType expected_output_size[kTensorDimensionLimit]; - size_t expected_output_dim = 0; - auto err = torch::executor::get_broadcast_target_size( - input1, - input2, - expected_output_size, - kTensorDimensionLimit, - &expected_output_dim); - - if (err != Error::Ok) - return err; - - return executorch::runtime::resize_tensor( - output, {expected_output_size, expected_output_dim}); -} diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp deleted file mode 100644 index ca648f7..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_dequantize_per_tensor.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -// Check for Helium/MVE support -#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) -#include -#define HAS_HELIUM_SIMD 1 -#endif - -namespace cortex_m { -namespace native { - -using Tensor = executorch::aten::Tensor; -using ScalarType = executorch::aten::ScalarType; -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -/** - * Asserts that the parameters are valid for int8/int16 to float dequantization. - */ -void check_dequantize_args( - const Tensor& input, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // dtype must be Char (int8) or Short (int16) - ET_CHECK_MSG( - dtype == ScalarType::Char || dtype == ScalarType::Short, - "dtype %" PRId8 " is not int8 (Char) or int16 (Short)", - static_cast(dtype)); - - // Input scalar type must match dtype - ET_CHECK_MSG( - input.scalar_type() == dtype, - "input.scalar_type() %" PRId8 " does not match dtype %" PRId8, - static_cast(input.scalar_type()), - static_cast(dtype)); - - // Check zp range - ET_CHECK_MSG( - zero_point >= quant_min, - "zero_point must be %" PRId64 " <= quant_min %" PRId64, - zero_point, - quant_min); - ET_CHECK_MSG( - zero_point <= quant_max, - "zero_point must be %" PRId64 " >= quant_max %" PRId64, - zero_point, - quant_max); - - // Check output dtype is float - ET_CHECK_MSG( - out.scalar_type() == ScalarType::Float, - "out.scalar_type() %" PRId8 " is not float", - static_cast(out.scalar_type())); - - // Validate quant_min and quant_max bounds per dtype - int32_t quant_min_lower_bound, quant_max_upper_bound; - if (dtype == ScalarType::Char) { - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } else { // Short - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } - - ET_CHECK_MSG( - quant_min >= quant_min_lower_bound, - "quant_min out of bound, expected quant_min_lower_bound: %" PRId32 - " actual quant_min: %" PRId64, - quant_min_lower_bound, - quant_min); - - ET_CHECK_MSG( - quant_max <= quant_max_upper_bound, - "quant_max out of bound, expected quant_max_upper_bound: %" PRId32 - " actual quant_max: %" PRId64, - quant_max_upper_bound, - quant_max); -} - -/** - * Scalar implementation of quantization for a single value. - */ -template -F dequantize_val(float scale, int32_t zero_point, Q qvalue) { - return static_cast((static_cast(qvalue) - zero_point) * scale); -} -} // namespace - -Tensor& dequantize_per_tensor_out( - KernelRuntimeContext& context, - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // Ignore context for now - (void)context; - - // Resize output tensor to match input dimensions - torch::executor::Error err = resize_tensor(out, input.sizes()); - ET_CHECK_MSG( - err == torch::executor::Error::Ok, - "Failed to resize out Tensor in dequantize_per_tensor_out"); - - // Validate input parameters - check_dequantize_args(input, zero_point, quant_min, quant_max, dtype, out); - - int32_t zp = static_cast(zero_point); - - // Get pointer to output data - float* out_data = out.mutable_data_ptr(); - const size_t numel = input.numel(); - - size_t i = 0; - - if (dtype == ScalarType::Char) { - const int8_t* input_data = input.const_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for int8 to float quantization - static uint8x16_t voffset{ - 0x0, - 0x8, - 0x4, - 0xC, - 0x1, - 0x9, - 0x5, - 0xD, - 0x2, - 0xA, - 0x6, - 0xE, - 0x3, - 0xB, - 0x7, - 0xF}; - - int16x8_t vzp = vdupq_n_s16(static_cast(zp)); - float32x4_t vscale = vdupq_n_f32(static_cast(scale)); - - for (; i + 15 < numel; i += 16) { - int8x16_t in_084C195D2A6E3B7F = - vldrbq_gather_offset_s8(input_data, voffset); - - int16x8_t in_04152637 = vsubq_s16(vmovlbq_s8(in_084C195D2A6E3B7F), vzp); - int16x8_t in_8C9DAEBF = vsubq_s16(vmovltq_s8(in_084C195D2A6E3B7F), vzp); - - float32x4_t inf_0123 = vcvtq_f32_s32(vmovlbq_s16(in_04152637)); - float32x4_t inf_4567 = vcvtq_f32_s32(vmovltq_s16(in_04152637)); - float32x4_t inf_89AB = vcvtq_f32_s32(vmovlbq_s16(in_8C9DAEBF)); - float32x4_t inf_CDEF = vcvtq_f32_s32(vmovltq_s16(in_8C9DAEBF)); - - float32x4_t out_0123 = vmulq_f32(inf_0123, vscale); - float32x4_t out_4567 = vmulq_f32(inf_4567, vscale); - float32x4_t out_89AB = vmulq_f32(inf_89AB, vscale); - float32x4_t out_CDEF = vmulq_f32(inf_CDEF, vscale); - - vstrwq_f32(out_data + 0, out_0123); - vstrwq_f32(out_data + 4, out_4567); - vstrwq_f32(out_data + 8, out_89AB); - vstrwq_f32(out_data + 12, out_CDEF); - - input_data += 16; - out_data += 16; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = dequantize_val(scale, zp, *input_data); - input_data++; - out_data++; - } - } else { // ScalarType::Short — int16 input - const int16_t* input_data = input.const_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for int16 to float dequantization, processing - // 8 elements per iteration. Mirrors the int8 byte-gather trick at halfword - // granularity: the gather pattern {0,4,1,5,2,6,3,7} arranges int16 lanes - // so that vmovlbq/vmovltq_s16 (which read even/odd lanes of int16x8 - // widened to int32x4) yield sequential values, allowing a sequential - // vstrwq_f32 store. - static uint16x8_t voffset_h{0, 4, 1, 5, 2, 6, 3, 7}; - - int32x4_t vzp = vdupq_n_s32(zp); - float32x4_t vscale = vdupq_n_f32(static_cast(scale)); - - for (; i + 7 < numel; i += 8) { - int16x8_t in_04152637 = - vldrhq_gather_shifted_offset_s16(input_data, voffset_h); - - int32x4_t in_0123 = vsubq_s32(vmovlbq_s16(in_04152637), vzp); - int32x4_t in_4567 = vsubq_s32(vmovltq_s16(in_04152637), vzp); - - float32x4_t out_0123 = vmulq_f32(vcvtq_f32_s32(in_0123), vscale); - float32x4_t out_4567 = vmulq_f32(vcvtq_f32_s32(in_4567), vscale); - - vstrwq_f32(out_data + 0, out_0123); - vstrwq_f32(out_data + 4, out_4567); - - input_data += 8; - out_data += 8; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = dequantize_val(scale, zp, *input_data); - input_data++; - out_data++; - } - } - return out; -} - -Tensor& dequantize_per_tensor_out( - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - KernelRuntimeContext context; - return dequantize_per_tensor_out( - context, input, scale, zero_point, quant_min, quant_max, dtype, out); -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_pad.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_pad.cpp deleted file mode 100644 index e59f986..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_pad.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -constexpr size_t kMaxSupportedDims = 4; - -} // namespace - -Tensor& pad_out( - KernelRuntimeContext& context, - const Tensor& input, - const Int64ArrayRef pre_pad, - const Int64ArrayRef post_pad, - int64_t pad_value, - Tensor& out) { - if (input.scalar_type() != ScalarType::Char || - out.scalar_type() != ScalarType::Char) { - ET_LOG( - Error, - "pad_out: only int8 tensors are supported (input=%d, out=%d)", - static_cast(input.scalar_type()), - static_cast(out.scalar_type())); - context.fail(Error::InvalidArgument); - return out; - } - - const size_t rank = input.dim(); - if (rank == 0 || rank > kMaxSupportedDims) { - ET_LOG( - Error, - "pad_out: expected tensor rank in [1, %zu], got %zu", - kMaxSupportedDims, - rank); - context.fail(Error::InvalidArgument); - return out; - } - - // Permute logical sizes to physical memory order. - // Padding is already in physical order from the AOT pass. - constexpr size_t kNhwcDimOrder[] = {0, 2, 3, 1}; - const size_t offset = kMaxSupportedDims - rank; - const bool nhwc = is_channels_last_tensor(input); - - int32_t dims[kMaxSupportedDims] = {1, 1, 1, 1}; - for (size_t i = 0; i < rank; ++i) { - const size_t src = nhwc ? kNhwcDimOrder[offset + i] : i; - dims[offset + i] = static_cast(input.size(src)); - } - - cmsis_nn_dims input_dims = {dims[0], dims[1], dims[2], dims[3]}; - cmsis_nn_dims cmsis_pre_pad = { - static_cast(pre_pad[0]), - static_cast(pre_pad[1]), - static_cast(pre_pad[2]), - static_cast(pre_pad[3])}; - cmsis_nn_dims cmsis_post_pad = { - static_cast(post_pad[0]), - static_cast(post_pad[1]), - static_cast(post_pad[2]), - static_cast(post_pad[3])}; - - const int8_t* input_data = input.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - - const arm_cmsis_nn_status status = arm_pad_s8( - input_data, - output_data, - static_cast(pad_value), - &input_dims, - &cmsis_pre_pad, - &cmsis_post_pad); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "pad_out: arm_pad_s8 failed with status [%d]", - static_cast(status)); - context.fail(Error::Internal); - return out; - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp deleted file mode 100644 index 7809db3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantize_per_tensor.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -// Check for Helium/MVE support -#if defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE & 1) -#include -#define HAS_HELIUM_SIMD 1 -#endif - -namespace cortex_m { -namespace native { - -using Tensor = executorch::aten::Tensor; -using ScalarType = executorch::aten::ScalarType; -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -/** - * Asserts that the parameters are valid for float to int8/int16 quantization. - */ -void check_quantize_args( - const Tensor& input, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // Ensure input is float type - ET_CHECK_MSG( - input.scalar_type() == ScalarType::Float, - "input.scalar_type() %" PRId8 " is not float type", - static_cast(input.scalar_type())); - - // Check output dtype matches dtype param (Char/int8 or Short/int16) - ET_CHECK_MSG( - dtype == ScalarType::Char || dtype == ScalarType::Short, - "dtype %" PRId8 " is not int8 (Char) or int16 (Short)", - static_cast(dtype)); - ET_CHECK_MSG( - out.scalar_type() == dtype, - "out.scalar_type() %" PRId8 " does not match dtype %" PRId8, - static_cast(out.scalar_type()), - static_cast(dtype)); - - // Validate quant_min and quant_max bounds per dtype - int32_t quant_min_lower_bound, quant_max_upper_bound; - if (dtype == ScalarType::Char) { - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } else { // Short - quant_min_lower_bound = std::numeric_limits::min(); - quant_max_upper_bound = std::numeric_limits::max(); - } - - ET_CHECK_MSG( - quant_min >= quant_min_lower_bound, - "quant_min out of bound, expected quant_min_lower_bound: %" PRId32 - " actual quant_min: %" PRId64, - quant_min_lower_bound, - quant_min); - - ET_CHECK_MSG( - quant_max <= quant_max_upper_bound, - "quant_max out of bound, expected quant_max_upper_bound: %" PRId32 - " actual quant_max: %" PRId64, - quant_max_upper_bound, - quant_max); -} - -/** - * Scalar implementation of quantization for a single value. - */ -template -Q quantize_val( - F inv_scale, - int32_t zero_point, - F value, - int64_t quant_min, - int64_t quant_max) { - int32_t qvalue = - zero_point + static_cast(std::nearbyint(inv_scale * value)); - qvalue = std::max(qvalue, static_cast(quant_min)); - qvalue = std::min(qvalue, static_cast(quant_max)); - return static_cast(qvalue); -} - -} // namespace - -Tensor& quantize_per_tensor_out( - KernelRuntimeContext& context, - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - // Ignore context for now - (void)context; - - // Resize output tensor to match input dimensions - torch::executor::Error err = resize_tensor(out, input.sizes()); - ET_CHECK_MSG( - err == torch::executor::Error::Ok, - "Failed to resize out Tensor in quantize_per_tensor_out"); - - // Validate input parameters - check_quantize_args(input, quant_min, quant_max, dtype, out); - - // Pre-compute inverse scale for better performance - float inv_scale = 1.0f / static_cast(scale); - int32_t zp = static_cast(zero_point); - int32_t qmin = static_cast(quant_min); - int32_t qmax = static_cast(quant_max); - - // Get pointers to input and output data - const float* input_data = input.const_data_ptr(); - const size_t numel = input.numel(); - - size_t i = 0; - - if (dtype == ScalarType::Char) { - int8_t* out_data = out.mutable_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for float32 to int8 quantization - static uint8x16_t voffset{ - 0x0, - 0x8, - 0x4, - 0xC, - 0x1, - 0x9, - 0x5, - 0xD, - 0x2, - 0xA, - 0x6, - 0xE, - 0x3, - 0xB, - 0x7, - 0xF}; - - float32x4_t inv_scale_vec = vdupq_n_f32(inv_scale); - - // Magic number for float to int conversion, round to nearest even integer - // int magic_round(float f): interpret_as_int32(f + magic_float) - magic_int - // where, - // magic_float = 12582912.0f = (2 ** 23 + 2 ** 22) = (1.5 * 2 ** 23) - // magic_int = 1262485504 = 0x4B400000 = - // bit_pattern_as_int32(magic_float) - - float magic_float = 12582912.0f; - int32_t magic_int = 1262485504; - - float32x4_t vmagic_float = vdupq_n_f32(magic_float); - int32x4_t vmagic_int_less_zp = - vdupq_n_s32(magic_int - static_cast(zp)); - - int16x8_t vqmin = vdupq_n_s16(qmin); - int16x8_t vqmax = vdupq_n_s16(qmax); - - // TODO: Measure performnce, we are spilling - for (; i + 15 < numel; i += 16) { - float32x4_t in_0123 = vldrwq_f32(input_data + 0); - float32x4_t in_4567 = vldrwq_f32(input_data + 4); - float32x4_t in_89AB = vldrwq_f32(input_data + 8); - float32x4_t in_CDEF = vldrwq_f32(input_data + 12); - - float32x4_t outf_0123 = vfmaq_f32(vmagic_float, in_0123, inv_scale_vec); - float32x4_t outf_4567 = vfmaq_f32(vmagic_float, in_4567, inv_scale_vec); - float32x4_t outf_89AB = vfmaq_f32(vmagic_float, in_89AB, inv_scale_vec); - float32x4_t outf_CDEF = vfmaq_f32(vmagic_float, in_CDEF, inv_scale_vec); - - int32x4_t out_0123 = - vsubq_s32(vreinterpretq_s32_f32(outf_0123), vmagic_int_less_zp); - int32x4_t out_4567 = - vsubq_s32(vreinterpretq_s32_f32(outf_4567), vmagic_int_less_zp); - int32x4_t out_89AB = - vsubq_s32(vreinterpretq_s32_f32(outf_89AB), vmagic_int_less_zp); - int32x4_t out_CDEF = - vsubq_s32(vreinterpretq_s32_f32(outf_CDEF), vmagic_int_less_zp); - - int16x8_t out_04152637; - int16x8_t out_8C9DAEBF; - out_04152637 = vmovnbq_s32(out_04152637, out_0123); - out_04152637 = vmovntq_s32(out_04152637, out_4567); - out_8C9DAEBF = vmovnbq_s32(out_8C9DAEBF, out_89AB); - out_8C9DAEBF = vmovntq_s32(out_8C9DAEBF, out_CDEF); - - int16x8_t out_04152637_clamped = - vminq_s16(vmaxq_s16(out_04152637, vqmin), vqmax); - int16x8_t out_8C9DAEBF_clamped = - vminq_s16(vmaxq_s16(out_8C9DAEBF, vqmin), vqmax); - - int8x16_t out_084C195D2A6E3B7F; - out_084C195D2A6E3B7F = - vmovnbq_s16(out_084C195D2A6E3B7F, out_04152637_clamped); - out_084C195D2A6E3B7F = - vmovntq_s16(out_084C195D2A6E3B7F, out_8C9DAEBF_clamped); - - vstrbq_scatter_offset_s8(out_data, voffset, out_084C195D2A6E3B7F); - input_data += 16; - out_data += 16; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = - quantize_val(inv_scale, zp, *input_data, qmin, qmax); - input_data++; - out_data++; - } - } else { // ScalarType::Short — int16 - int16_t* out_data = out.mutable_data_ptr(); - -#if defined(HAS_HELIUM_SIMD) - // Helium MVE implementation for float32 to int16 quantization, processing - // 8 elements per iteration. Uses the same magic-number rounding trick as - // the int8 path. Output goes through vstrhq_s32 (narrow int32->int16 - // sequential store), so no deinterleave dance is needed. - float magic_float = 12582912.0f; - int32_t magic_int = 1262485504; - - float32x4_t inv_scale_vec = vdupq_n_f32(inv_scale); - float32x4_t vmagic_float = vdupq_n_f32(magic_float); - int32x4_t vmagic_int_less_zp = - vdupq_n_s32(magic_int - static_cast(zp)); - - int32x4_t vqmin = vdupq_n_s32(qmin); - int32x4_t vqmax = vdupq_n_s32(qmax); - - for (; i + 7 < numel; i += 8) { - float32x4_t in_0123 = vldrwq_f32(input_data + 0); - float32x4_t in_4567 = vldrwq_f32(input_data + 4); - - float32x4_t outf_0123 = vfmaq_f32(vmagic_float, in_0123, inv_scale_vec); - float32x4_t outf_4567 = vfmaq_f32(vmagic_float, in_4567, inv_scale_vec); - - int32x4_t out_0123 = - vsubq_s32(vreinterpretq_s32_f32(outf_0123), vmagic_int_less_zp); - int32x4_t out_4567 = - vsubq_s32(vreinterpretq_s32_f32(outf_4567), vmagic_int_less_zp); - - // Clamp at int32 width before narrowing. - out_0123 = vminq_s32(vmaxq_s32(out_0123, vqmin), vqmax); - out_4567 = vminq_s32(vmaxq_s32(out_4567, vqmin), vqmax); - - // Narrow store: low 16 bits of each int32 lane stored sequentially. - vstrhq_s32(out_data + 0, out_0123); - vstrhq_s32(out_data + 4, out_4567); - - input_data += 8; - out_data += 8; - } -#endif // defined(HAS_HELIUM_SIMD) - - for (; i < numel; i++) { - *out_data = - quantize_val(inv_scale, zp, *input_data, qmin, qmax); - input_data++; - out_data++; - } - } - - return out; -} - -Tensor& quantize_per_tensor_out( - const Tensor& input, - double scale, - int64_t zero_point, - int64_t quant_min, - int64_t quant_max, - ScalarType dtype, - Tensor& out) { - KernelRuntimeContext context; - return quantize_per_tensor_out( - context, input, scale, zero_point, quant_min, quant_max, dtype, out); -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp deleted file mode 100644 index fc04edc..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_avg_pool2d.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2025-2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -Tensor& quantized_avg_pool2d_out( - KernelRuntimeContext& context, - const Tensor& input, - const Int64ArrayRef kernel_size, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const int64_t zero_point, - const int64_t multiplier, - const int64_t shift, - Tensor& out) { - constexpr int32_t activation_min = std::numeric_limits::min(); - constexpr int32_t activation_max = std::numeric_limits::max(); - - const int64_t dilation_values[2] = {1, 1}; - const Int64ArrayRef dilation(dilation_values, 2); - CmsisPool2DConfig pool_config; - if (!prepare_cmsis_pool2d_config( - context, - "quantized_avg_pool2d_out", - input, - out, - kernel_size, - stride, - padding, - dilation, - false, - activation_min, - activation_max, - pool_config)) { - return out; - } - - cmsis_nn_context cmsis_ctx; - cmsis_ctx.buf = nullptr; - cmsis_ctx.size = 0; - - const int8_t* input_data = input.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - - const arm_cmsis_nn_status status = arm_avgpool_s8( - &cmsis_ctx, - &pool_config.pool_params, - &pool_config.input_dims, - input_data, - &pool_config.filter_dims, - &pool_config.output_dims, - output_data); - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_avg_pool2d_out: arm_avgpool_s8 failed with status [%d]", - status); - context.fail(Error::Internal); - } - - (void)zero_point; - (void)multiplier; - (void)shift; - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_batch_matmul.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_batch_matmul.cpp deleted file mode 100644 index e6bc5a9..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_batch_matmul.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -extern "C" { -#include "arm_nnfunctions.h" -} - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { - -bool validate_batch_matmul_arguments( - KernelRuntimeContext& context, - const Tensor& lhs, - const Tensor& rhs_transposed, - const Tensor& out) { - if (lhs.scalar_type() != ScalarType::Char || - rhs_transposed.scalar_type() != ScalarType::Char || - out.scalar_type() != ScalarType::Char) { - ET_LOG(Error, "quantized_batch_matmul: all tensors must be int8"); - context.fail(Error::InvalidArgument); - return false; - } - - if (lhs.dim() != 3 || rhs_transposed.dim() != 3 || out.dim() != 3) { - ET_LOG(Error, "quantized_batch_matmul: all tensors must be 3-D"); - context.fail(Error::InvalidArgument); - return false; - } - - if (lhs.size(0) != rhs_transposed.size(0)) { - ET_LOG(Error, "quantized_batch_matmul: batch dims must match"); - context.fail(Error::InvalidArgument); - return false; - } - - if (lhs.size(2) != rhs_transposed.size(2)) { - ET_LOG(Error, "quantized_batch_matmul: inner dims must match"); - context.fail(Error::InvalidArgument); - return false; - } - - if (out.size(0) != lhs.size(0) || out.size(1) != lhs.size(1) || - out.size(2) != rhs_transposed.size(1)) { - ET_LOG(Error, "quantized_batch_matmul: output shape mismatch"); - context.fail(Error::InvalidArgument); - return false; - } - - return true; -} - -} // namespace - -Tensor& quantized_batch_matmul_out( - KernelRuntimeContext& context, - const Tensor& lhs, - int64_t lhs_offset, - const Tensor& rhs_transposed, - int64_t rhs_offset, - int64_t output_offset, - int64_t output_multiplier, - int64_t output_shift, - Tensor& out) { - if (!validate_batch_matmul_arguments(context, lhs, rhs_transposed, out)) { - return out; - } - - const int32_t batch = static_cast(lhs.size(0)); - const int32_t lhs_rows = static_cast(lhs.size(1)); - const int32_t inner = static_cast(lhs.size(2)); - const int32_t rhs_cols = static_cast(rhs_transposed.size(1)); - - const cmsis_nn_dims lhs_dims = {1, batch, lhs_rows, inner}; - const cmsis_nn_dims rhs_dims = {1, batch, rhs_cols, inner}; - const cmsis_nn_dims out_dims = {1, batch, lhs_rows, rhs_cols}; - - const cmsis_nn_bmm_params bmm_params = { - /* adj_x */ false, - /* adj_y */ false, - /* fc_params */ - {static_cast(lhs_offset), - static_cast(rhs_offset), - static_cast(output_offset), - /* activation */ - {std::numeric_limits::min(), - std::numeric_limits::max()}}}; - - cmsis_nn_per_tensor_quant_params quant_params; - quant_params.multiplier = static_cast(output_multiplier); - quant_params.shift = static_cast(output_shift); - - const int32_t buf_size = arm_fully_connected_s8_get_buffer_size(&out_dims); - - cmsis_nn_context ctx; - ctx.buf = nullptr; - ctx.size = 0; - - if (buf_size > 0) { - auto buffer_or_error = context.allocate_temp(buf_size); - if (!buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_batch_matmul: failed to allocate scratch buffer (%d bytes)", - buf_size); - context.fail(buffer_or_error.error()); - return out; - } - ctx.buf = buffer_or_error.get(); - ctx.size = buf_size; - } - - const arm_cmsis_nn_status status = arm_batch_matmul_s8( - &ctx, - &bmm_params, - &quant_params, - &lhs_dims, - lhs.const_data_ptr(), - &rhs_dims, - rhs_transposed.const_data_ptr(), - &out_dims, - out.mutable_data_ptr()); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_batch_matmul: arm_batch_matmul_s8 failed with status [%d]", - status); - context.fail(Error::Internal); - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_max_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_max_pool2d.cpp deleted file mode 100644 index 181a29c..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_max_pool2d.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2026 Arm Limited and/or its affiliates. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -Tensor& quantized_max_pool2d_out( - KernelRuntimeContext& context, - const Tensor& input, - const Int64ArrayRef kernel_size, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef dilation, - const bool ceil_mode, - const int64_t input_zero_point, - const int64_t output_zero_point, - const int64_t activation_min, - const int64_t activation_max, - Tensor& out) { - CmsisPool2DConfig pool_config; - if (!prepare_cmsis_pool2d_config( - context, - "quantized_max_pool2d_out", - input, - out, - kernel_size, - stride, - padding, - dilation, - ceil_mode, - activation_min, - activation_max, - pool_config)) { - return out; - } - - auto validate_int8_zero_point = [&](int64_t zp, const char* name) -> bool { - if (zp < std::numeric_limits::min() || - zp > std::numeric_limits::max()) { - ET_LOG( - Error, - "quantized_max_pool2d_out: %s must be int8, got %ld", - name, - zp); - context.fail(Error::InvalidArgument); - return false; - } - return true; - }; - - if (!validate_int8_zero_point(input_zero_point, "input zero point") || - !validate_int8_zero_point(output_zero_point, "output zero point")) { - return out; - } - - if (input_zero_point != output_zero_point) { - ET_LOG( - Error, - "quantized_max_pool2d_out: input and output zero points must match"); - context.fail(Error::InvalidArgument); - return out; - } - - cmsis_nn_context cmsis_context; - cmsis_context.buf = nullptr; - cmsis_context.size = 0; - - const int8_t* input_data = input.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - - const arm_cmsis_nn_status status = arm_max_pool_s8( - &cmsis_context, - &pool_config.pool_params, - &pool_config.input_dims, - input_data, - &pool_config.filter_dims, - &pool_config.output_dims, - output_data); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_max_pool2d_out: arm_max_pool_s8 failed with status %d", - status); - context.fail(Error::Internal); - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp deleted file mode 100644 index e3f6135..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/backends/cortex_m/ops/op_quantized_transpose_conv2d.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "cortex_m_ops_common.h" - -namespace cortex_m { -namespace native { - -using KernelRuntimeContext = torch::executor::KernelRuntimeContext; - -namespace { -constexpr int64_t kConvTransposeDim = 4; - -bool validate_transpose_conv2d_arguments( - KernelRuntimeContext& context, - const Tensor& input, - const Tensor& weight, - const torch::executor::optional& bias, - const Tensor& output, - const Tensor& requantize_multipliers, - const Tensor& requantize_shifts) { - if (input.dim() != kConvTransposeDim || weight.dim() != kConvTransposeDim || - output.dim() != kConvTransposeDim) { - ET_LOG(Error, "quantized_transpose_conv2d_out: tensors must be 4-D"); - context.fail(Error::InvalidArgument); - return false; - } - - if (!is_channels_last_tensor(input)) { - ET_LOG( - Error, "quantized_transpose_conv2d_out: input must be channels_last"); - context.fail(Error::InvalidArgument); - return false; - } - - if (!is_channels_last_tensor(output)) { - ET_LOG( - Error, "quantized_transpose_conv2d_out: output must be channels_last"); - context.fail(Error::InvalidArgument); - return false; - } - - if (input.scalar_type() != ScalarType::Char || - output.scalar_type() != ScalarType::Char) { - ET_LOG( - Error, "quantized_transpose_conv2d_out: input and output must be int8"); - context.fail(Error::InvalidArgument); - return false; - } - - if (weight.scalar_type() != ScalarType::Char) { - ET_LOG(Error, "quantized_transpose_conv2d_out: weight must be int8"); - context.fail(Error::InvalidArgument); - return false; - } - - if (bias.has_value() && bias.value().scalar_type() != ScalarType::Int) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: bias must be int32 if provided"); - context.fail(Error::InvalidArgument); - return false; - } - - const int64_t out_channels = output.size(1); - if (requantize_multipliers.size(0) != out_channels || - requantize_shifts.size(0) != out_channels) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: per-channel params must match output channels (%zd)", - out_channels); - context.fail(Error::InvalidArgument); - return false; - } - - return true; -} -} // namespace - -Tensor& quantized_transpose_conv2d_out( - KernelRuntimeContext& context, - const Tensor& input, - const Tensor& weight, - const torch::executor::optional& bias, - const Int64ArrayRef stride, - const Int64ArrayRef padding, - const Int64ArrayRef output_padding, - const Int64ArrayRef dilation, - const int64_t input_offset, - const int64_t output_offset, - const Tensor& requantize_multipliers, - const Tensor& requantize_shifts, - const int64_t activation_min, - const int64_t activation_max, - Tensor& out) { - if (!validate_transpose_conv2d_arguments( - context, - input, - weight, - bias, - out, - requantize_multipliers, - requantize_shifts)) { - return out; - } - - const int32_t batch = static_cast(input.size(0)); - const int32_t input_channels = static_cast(input.size(1)); - const int32_t input_height = static_cast(input.size(2)); - const int32_t input_width = static_cast(input.size(3)); - - const int32_t kernel_output_channels = static_cast(weight.size(0)); - const int32_t kernel_height = static_cast(weight.size(1)); - const int32_t kernel_width = static_cast(weight.size(2)); - const int32_t kernel_input_channels = static_cast(weight.size(3)); - - const int32_t output_channels = static_cast(out.size(1)); - const int32_t output_height = static_cast(out.size(2)); - const int32_t output_width = static_cast(out.size(3)); - - if (kernel_output_channels != output_channels) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: weight output channels (%d) != output channels (%d)", - kernel_output_channels, - output_channels); - context.fail(Error::InvalidArgument); - return out; - } - - const int32_t input_offset_val = static_cast(input_offset); - const int32_t output_offset_val = static_cast(output_offset); - const int32_t activation_min_val = static_cast(activation_min); - const int32_t activation_max_val = static_cast(activation_max); - - const cmsis_nn_dims input_dims{ - batch, input_height, input_width, input_channels}; - const cmsis_nn_dims filter_dims{ - kernel_output_channels, - kernel_height, - kernel_width, - kernel_input_channels}; - const cmsis_nn_dims output_dims{ - batch, output_height, output_width, output_channels}; - const cmsis_nn_dims bias_dims{1, 1, 1, output_channels}; - - // Setup transposed convolution parameters - cmsis_nn_transpose_conv_params transpose_conv_params; - transpose_conv_params.input_offset = input_offset_val; - transpose_conv_params.output_offset = output_offset_val; - transpose_conv_params.stride.h = static_cast(stride[0]); - transpose_conv_params.stride.w = static_cast(stride[1]); - transpose_conv_params.padding.h = static_cast(padding[0]); - transpose_conv_params.padding.w = static_cast(padding[1]); - // padding_offsets corresponds to output_padding in PyTorch - transpose_conv_params.padding_offsets.h = - static_cast(output_padding[0]); - transpose_conv_params.padding_offsets.w = - static_cast(output_padding[1]); - transpose_conv_params.dilation.h = static_cast(dilation[0]); - transpose_conv_params.dilation.w = static_cast(dilation[1]); - transpose_conv_params.activation.min = activation_min_val; - transpose_conv_params.activation.max = activation_max_val; - - cmsis_nn_per_channel_quant_params quant_params; - quant_params.multiplier = requantize_multipliers.data_ptr(); - quant_params.shift = requantize_shifts.data_ptr(); - - const int8_t* input_data = input.const_data_ptr(); - const int8_t* weight_data = weight.const_data_ptr(); - int8_t* output_data = out.mutable_data_ptr(); - const int32_t* bias_data = - bias.has_value() ? bias.value().const_data_ptr() : nullptr; - - cmsis_nn_context cmsis_context; - cmsis_context.buf = nullptr; - cmsis_context.size = 0; - - cmsis_nn_context output_context; - output_context.buf = nullptr; - output_context.size = 0; - - const int32_t buffer_bytes = arm_transpose_conv_s8_get_buffer_size( - &transpose_conv_params, &input_dims, &filter_dims, &output_dims); - auto buffer_or_error = context.allocate_temp( - static_cast(buffer_bytes), kCortexMMveAlignment); - if (!buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: failed to allocate scratch buffer (%d bytes, error %d)", - buffer_bytes, - static_cast(buffer_or_error.error())); - context.fail(buffer_or_error.error()); - return out; - } - cmsis_context.buf = buffer_or_error.get(); - cmsis_context.size = buffer_bytes; - - const int32_t output_buffer_bytes = - arm_transpose_conv_s8_get_reverse_conv_buffer_size( - &transpose_conv_params, &input_dims, &filter_dims); - auto output_buffer_or_error = context.allocate_temp( - static_cast(output_buffer_bytes), kCortexMMveAlignment); - if (!output_buffer_or_error.ok()) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: failed to allocate output scratch buffer (%d bytes, error %d)", - output_buffer_bytes, - static_cast(output_buffer_or_error.error())); - context.fail(output_buffer_or_error.error()); - return out; - } - output_context.buf = output_buffer_or_error.get(); - output_context.size = output_buffer_bytes; - - const arm_cmsis_nn_status status = arm_transpose_conv_wrapper_s8( - &cmsis_context, - &output_context, - &transpose_conv_params, - &quant_params, - &input_dims, - input_data, - &filter_dims, - weight_data, - &bias_dims, - bias_data, - &output_dims, - output_data); - - if (status != ARM_CMSIS_NN_SUCCESS) { - ET_LOG( - Error, - "quantized_transpose_conv2d_out: arm_transpose_conv_wrapper_s8 failed with status %d", - status); - context.fail(Error::Internal); - } - - return out; -} - -} // namespace native -} // namespace cortex_m diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp deleted file mode 100644 index 1ae679a..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__adaptive_avg_pool2d.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include -#include - -namespace torch { -namespace executor { -namespace native { - -using Tensor = executorch::aten::Tensor; -using ScalarType = executorch::aten::ScalarType; -using IntArrayRef = executorch::aten::ArrayRef; - -namespace { - -inline int64_t -adaptive_start_index(int64_t out_idx, int64_t out_size, int64_t in_size) { - return static_cast( - std::floor(static_cast(out_idx * in_size) / out_size)); -} - -inline int64_t -adaptive_end_index(int64_t out_idx, int64_t out_size, int64_t in_size) { - return static_cast( - std::ceil(static_cast((out_idx + 1) * in_size) / out_size)); -} - -} // namespace - -Tensor& _adaptive_avg_pool2d_out( - KernelRuntimeContext& ctx, - const Tensor& in, - IntArrayRef output_size, - Tensor& out) { - ET_KERNEL_CHECK( - ctx, - check_adaptive_avg_pool2d_args(in, output_size, out), - InvalidArgument, - out); - - ET_KERNEL_CHECK( - ctx, tensors_have_same_dim_order(in, out), InvalidArgument, out); - - ET_KERNEL_CHECK(ctx, tensor_is_default_dim_order(in), InvalidArgument, out); - - size_t output_ndim = 0; - executorch::aten::SizesType output_sizes[kTensorDimensionLimit]; - get_adaptive_avg_pool2d_out_target_size( - in, output_size, output_sizes, &output_ndim); - - ET_KERNEL_CHECK( - ctx, - output_size_is_valid({output_sizes, output_ndim}, 2), - InvalidArgument, - out); - - ET_KERNEL_CHECK( - ctx, - resize_tensor(out, {output_sizes, output_ndim}) == Error::Ok, - InvalidArgument, - out); - - ScalarType in_type = in.scalar_type(); - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "_adaptive_avg_pool2d.out"; - - ET_SWITCH_FLOATHBF16_TYPES_AND(Long, in_type, ctx, op_name, CTYPE, [&]() { - const CTYPE* const in_ptr = in.const_data_ptr(); - CTYPE* const out_ptr = out.mutable_data_ptr(); - - const size_t ndim = in.dim(); - const int64_t in_H = in.size(ndim - 2); - const int64_t in_W = in.size(ndim - 1); - const int64_t out_H = output_size[0]; - const int64_t out_W = output_size[1]; - - const size_t channels = in.size(ndim - 3); - const size_t batch_size = ndim == 4 ? in.size(0) : 1; - - const size_t in_plane_size = in_H * in_W; - const size_t out_plane_size = out_H * out_W; - - for (size_t b = 0; b < batch_size; ++b) { - for (size_t c = 0; c < channels; ++c) { - const size_t plane_idx = b * channels + c; - const CTYPE* plane_in = in_ptr + plane_idx * in_plane_size; - CTYPE* plane_out = out_ptr + plane_idx * out_plane_size; - - for (int64_t oh = 0; oh < out_H; ++oh) { - int64_t ih0 = adaptive_start_index(oh, out_H, in_H); - int64_t ih1 = adaptive_end_index(oh, out_H, in_H); - - for (int64_t ow = 0; ow < out_W; ++ow) { - int64_t iw0 = adaptive_start_index(ow, out_W, in_W); - int64_t iw1 = adaptive_end_index(ow, out_W, in_W); - - float sum = 0; - for (int64_t ih = ih0; ih < ih1; ++ih) { - for (int64_t iw = iw0; iw < iw1; ++iw) { - sum += plane_in[ih * in_W + iw]; - } - } - - int64_t count = (ih1 - ih0) * (iw1 - iw0); - plane_out[oh * out_W + ow] = - static_cast(sum / static_cast(count)); - } - } - } - } - }); - - return out; -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__conj_physical.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__conj_physical.cpp deleted file mode 100644 index 4352ab3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__conj_physical.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -namespace torch { -namespace executor { -namespace native { - -using executorch::aten::Tensor; - -Tensor& -_conj_physical_out(KernelRuntimeContext& ctx, const Tensor& in, Tensor& out) { - ET_KERNEL_CHECK_MSG( - ctx, - resize_tensor(out, in.sizes()) == Error::Ok, - InvalidArgument, - out, - "Failed to resize output tensor."); - - ET_KERNEL_CHECK(ctx, tensors_have_same_dtype(in, out), InvalidArgument, out); - - ET_KERNEL_CHECK( - ctx, tensors_have_same_dim_order(in, out), InvalidArgument, out); - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = "_conj_physical.out"; - - ET_SWITCH_COMPLEXH_TYPES(in.scalar_type(), ctx, op_name, CTYPE, [&] { - apply_unary_map_fn( - [](const CTYPE val_in) -> CTYPE { - return CTYPE(val_in.real_, -val_in.imag_); - }, - in.const_data_ptr(), - out.mutable_data_ptr(), - in.numel()); - }); - - return out; -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__to_dim_order_copy.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__to_dim_order_copy.cpp deleted file mode 100644 index 14124d3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op__to_dim_order_copy.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include -#include -#include - -namespace torch { -namespace executor { -namespace native { - -using Tensor = executorch::aten::Tensor; -using SizesArrayRef = executorch::aten::ArrayRef; -using DimOrderArrayRef = - executorch::aten::ArrayRef; -using MemoryFormat = executorch::aten::MemoryFormat; - -template -using OptionalArrayRef = executorch::aten::OptionalArrayRef; - -template -using Optional = std::optional; - -// _to_dim_order_copy.out(Tensor self, *, bool non_blocking=False, int[]? -// dim_order=None, Tensor(a!) out) -> Tensor(a!) -Tensor& _to_dim_order_copy_out( - KernelRuntimeContext& ctx, - const Tensor& self, - bool non_blocking, - OptionalArrayRef dim_order, - Tensor& out) { - (void)ctx; - ET_KERNEL_CHECK( - ctx, - check__to_dim_order_copy_args(self, non_blocking, dim_order, out), - InvalidArgument, - out); - - ET_KERNEL_CHECK( - ctx, - resize_tensor(out, self.sizes()) == torch::executor::Error::Ok, - InvalidArgument, - out); - - if (self.numel() == 0) { - return out; - } - - // @lint-ignore CLANGTIDY facebook-hte-CArray - static constexpr const char op_name[] = - "dim_order_ops::_to_dim_order_copy.out"; - - const bool in_is_complex = - executorch::runtime::isComplexType(self.scalar_type()); - const bool out_is_complex = - executorch::runtime::isComplexType(out.scalar_type()); - - if (in_is_complex && out_is_complex) { - // Complex to complex: same type copy - ET_SWITCH_COMPLEXH_TYPES(self.scalar_type(), ctx, op_name, CTYPE, [&] { - _to_dim_order_copy_impl(self, out); - }); - } else if (!in_is_complex && out_is_complex) { - // Real to complex: convert real value to complex with zero imaginary part - ET_SWITCH_FLOATH_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { - ET_SWITCH_COMPLEXH_TYPES(out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { - auto self_data = self.mutable_data_ptr(); - auto out_data = out.mutable_data_ptr(); - for (const auto [unused_index, self_data_index, out_data_index] : - BroadcastIndexesRange< - 2, - /*support_noncontiguous_input_tensors=*/true>( - /*dummy output*/ self, self, out)) { - (void)unused_index; - out_data[out_data_index].real_ = self_data[self_data_index]; - out_data[out_data_index].imag_ = 0; - } - }); - }); - } else if (in_is_complex && !out_is_complex) { - // Complex to real: take real part - ET_SWITCH_COMPLEXH_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { - ET_SWITCH_FLOATH_TYPES(out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { - auto self_data = self.mutable_data_ptr(); - auto out_data = out.mutable_data_ptr(); - for (const auto [unused_index, self_data_index, out_data_index] : - BroadcastIndexesRange< - 2, - /*support_noncontiguous_input_tensors=*/true>( - /*dummy output*/ self, self, out)) { - (void)unused_index; - out_data[out_data_index] = - static_cast(self_data[self_data_index].real_); - } - }); - }); - } else { - // Real to real - ET_SWITCH_REALHBBF16_TYPES(self.scalar_type(), ctx, op_name, CTYPE_IN, [&] { - ET_SWITCH_REALHBBF16_TYPES( - out.scalar_type(), ctx, op_name, CTYPE_OUT, [&] { - _to_dim_order_copy_impl(self, out); - }); - }); - } - - return out; -} - -Tensor& _to_dim_order_copy_out( - const Tensor& self, - bool non_blocking, - OptionalArrayRef dim_order, - Tensor& out) { - executorch::ET_RUNTIME_NAMESPACE::KernelRuntimeContext context{}; - return _to_dim_order_copy_out(context, self, non_blocking, dim_order, out); -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_var_mean.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_var_mean.cpp deleted file mode 100644 index dbb88f2..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/kernels/portable/cpu/op_var_mean.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -#include -#include -#include - -namespace torch { -namespace executor { -namespace native { -namespace { - -template -void compute_var_mean( - KernelRuntimeContext& ctx, - const Tensor& in, - Tensor& var_out, - Tensor& mean_out, - optional> dim_list, - const size_t num, - const double denominator) { - CTYPE_OUT* var_data = var_out.mutable_data_ptr(); - CTYPE_OUT* mean_data = mean_out.mutable_data_ptr(); - if (num == 0 || denominator <= 0) { - for (const auto out_ix : c10::irange(var_out.numel())) { - var_data[out_ix] = NAN; - mean_data[out_ix] = NAN; - } - } else if (in.numel() > 0) { - // Fast path: contiguous tensor, single innermost dim reduction, same dtype. - bool used_fast_path = false; - if (dim_list.has_value() && dim_list.value().size() == 1 && - in.scalar_type() == var_out.scalar_type()) { - const int64_t d = dim_list.value()[0] < 0 ? dim_list.value()[0] + in.dim() - : dim_list.value()[0]; - if (d >= 0 && d < in.dim() && d == in.dim() - 1 && - tensor_is_contiguous(in)) { - used_fast_path = true; - const int64_t reduce_size = in.size(d); - const int64_t outer_size = in.numel() / reduce_size; - const CTYPE_OUT cnum = static_cast(num); - const CTYPE_OUT cdenom = static_cast(denominator); - const CTYPE_IN* in_data = in.const_data_ptr(); - for (int64_t i = 0; i < outer_size; i++) { - const CTYPE_IN* row = in_data + i * reduce_size; - // Pass 1: compute mean - CTYPE_OUT sum = 0; - for (int64_t j = 0; j < reduce_size; j++) { - sum += static_cast(row[j]); - } - CTYPE_OUT mean = sum / cnum; - mean_data[i] = mean; - // Pass 2: compute variance - CTYPE_OUT sum2 = 0; - for (int64_t j = 0; j < reduce_size; j++) { - CTYPE_OUT diff = static_cast(row[j]) - mean; - sum2 += diff * diff; - } - var_data[i] = sum2 / cdenom; - } - } - } - if (!used_fast_path) { - MapReduceOverDimListPlan plan(in, dim_list); - const bool success = parallel_for_each_reduce_over_dim_list_output_index( - in, dim_list, var_out, [&](const auto begin, const auto end) { - for (const auto out_ix : c10::irange(begin, end)) { - // Pass 1: compute sum -> mean - CTYPE_OUT sum = plan.execute( - [](CTYPE_IN v) { return static_cast(v); }, - [](CTYPE_OUT outv, CTYPE_OUT acc) { return acc + outv; }, - out_ix); - CTYPE_OUT mean = sum / static_cast(num); - mean_data[out_ix] = mean; - // Pass 2: compute sum of squared deviations - CTYPE_OUT sum2 = plan.execute( - [mean](CTYPE_IN v) { - return ( - (static_cast(v) - mean) * - (static_cast(v) - mean)); - }, - [](CTYPE_OUT outv, CTYPE_OUT acc) { return acc + outv; }, - out_ix); - var_data[out_ix] = sum2 / denominator; - } - }); - ET_KERNEL_CHECK_MSG(ctx, success, Internal, , "parallel_for failed"); - } // !used_fast_path - } -} - -} // namespace - -std::tuple var_mean_correction_out( - KernelRuntimeContext& ctx, - const Tensor& in, - optional> dim_list, - const optional& correction, - bool keepdim, - Tensor& out0, - Tensor& out1) { - (void)ctx; - - std::tuple ret_val(out0, out1); - - ET_KERNEL_CHECK( - ctx, - check_reduction_args(in, dim_list, keepdim, {}, out0), - InvalidArgument, - ret_val); - - ET_KERNEL_CHECK( - ctx, - check_reduction_args(in, dim_list, keepdim, {}, out1), - InvalidArgument, - ret_val); - - ET_KERNEL_CHECK( - ctx, - resize_reduction_out(in, dim_list, keepdim, out0) == Error::Ok, - InvalidArgument, - ret_val); - - ET_KERNEL_CHECK( - ctx, - resize_reduction_out(in, dim_list, keepdim, out1) == Error::Ok, - InvalidArgument, - ret_val); - - static constexpr auto name = "var_mean.correction_out"; - - double correction_val = 1; - if (correction.has_value()) { - correction_val = utils::scalar_to(correction.value()); - } - - const size_t num = get_reduced_dim_product(in, dim_list); - const double denom = num - correction_val; - - ET_SWITCH_FLOATHBF16_TYPES(in.scalar_type(), ctx, name, CTYPE_IN, [&] { - ET_SWITCH_FLOATHBF16_TYPES(out0.scalar_type(), ctx, name, CTYPE_OUT, [&] { - compute_var_mean( - ctx, in, out0, out1, dim_list, num, denom); - }); - }); - - return ret_val; -} - -} // namespace native -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/registration/RegisterAllKernels.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/registration/RegisterAllKernels.cpp deleted file mode 100644 index c5c90a8..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/registration/RegisterAllKernels.cpp +++ /dev/null @@ -1,8136 +0,0 @@ -/* - * CMSIS Pack Kernel Registration - * - * Auto-generated by generate_register_all_kernels.py - * - * This file contains all ExecuTorch kernel registrations, with each operator - * guarded by its corresponding RTE_Components_h define. - * - * When a user selects an operator component in the CMSIS pack, that component - * defines RTE_ML_EXECUTORCH_OP__, which enables the - * registration of that operator in this file. - * - * Define naming convention: - * RTE_ML_EXECUTORCH_OP_PORTABLE_ - Portable operators - * RTE_ML_EXECUTORCH_OP_QUANTIZED_ - Quantized operators - * RTE_ML_EXECUTORCH_OP_CORTEX_M_ - Cortex-M operators - * - * This approach allows: - * 1. Only selected operators to be registered (minimizing code size) - * 2. No per-operator registration files needed - * 3. Single static initialization for all selected operators - */ - -#include "RTE_Components.h" - -#include -#include -#include -#include -#include -#include -#include - -using KernelSpan = ::executorch::runtime::Span< - const ::executorch::runtime::Kernel>; - -namespace torch { -namespace executor { - -// Forward declarations for native functions (in torch::executor::native namespace) -namespace native { - -// ===================================================================== -// PORTABLE OPERATOR FORWARD DECLARATIONS -// ===================================================================== - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ABS -torch::executor::Tensor & abs_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOS -torch::executor::Tensor & acos_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOSH -torch::executor::Tensor & acosh_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADAPTIVE_AVG_POOL2D -torch::executor::Tensor & _adaptive_avg_pool2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef output_size, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADD -torch::executor::Tensor & add_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, const torch::executor::Scalar & alpha, torch::executor::Tensor & out); -torch::executor::Tensor & add_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, const torch::executor::Scalar & alpha, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADDMM -torch::executor::Tensor & addmm_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & mat1, const torch::executor::Tensor & mat2, const torch::executor::Scalar & beta, const torch::executor::Scalar & alpha, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALIAS_COPY -torch::executor::Tensor & alias_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALLCLOSE -torch::executor::Tensor & allclose_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, double rtol, double atol, bool equal_nan, bool dummy_param, torch::executor::Tensor & out); -torch::executor::Tensor allclose_tensor(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, double rtol, double atol, bool equal_nan, bool dummy_param); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMAX -torch::executor::Tensor & amax_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef dim, bool keepdim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMIN -torch::executor::Tensor & amin_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef dim, bool keepdim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ANY -torch::executor::Tensor & any_all_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -torch::executor::Tensor & any_dims_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional> dim, bool keepdim, torch::executor::Tensor & out); -torch::executor::Tensor & any_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, bool keepdim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARANGE -torch::executor::Tensor & arange_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Scalar & end, torch::executor::Tensor & out); -torch::executor::Tensor & arange_start_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Scalar & start, const torch::executor::Scalar & end, const torch::executor::Scalar & step, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMAX -torch::executor::Tensor & argmax_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional dim, bool keepdim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMIN -torch::executor::Tensor & argmin_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional dim, bool keepdim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASIN -torch::executor::Tensor & asin_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASINH -torch::executor::Tensor & asinh_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AS_STRIDED_COPY -torch::executor::Tensor & as_strided_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef size, torch::executor::ArrayRef stride, torch::executor::optional storage_offset, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN -torch::executor::Tensor & atan_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN2 -torch::executor::Tensor & atan2_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATANH -torch::executor::Tensor & atanh_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AVG_POOL2D -torch::executor::Tensor & avg_pool2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef kernel_size, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, bool ceil_mode, bool count_include_pad, torch::executor::optional divisor_override, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_AND -torch::executor::Tensor & bitwise_and_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & bitwise_and_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_LEFT_SHIFT -torch::executor::Tensor & bitwise_left_shift_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -torch::executor::Tensor & bitwise_left_shift_Tensor_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_NOT -torch::executor::Tensor & bitwise_not_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_OR -torch::executor::Tensor & bitwise_or_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & bitwise_or_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_RIGHT_SHIFT -torch::executor::Tensor & bitwise_right_shift_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -torch::executor::Tensor & bitwise_right_shift_Tensor_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_XOR -torch::executor::Tensor & bitwise_xor_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & bitwise_xor_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BMM -torch::executor::Tensor & bmm_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & mat2, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CAT -torch::executor::Tensor & cat_out(torch::executor::KernelRuntimeContext & context, torch::executor::TensorList tensors, int64_t dim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CDIST_FORWARD -torch::executor::Tensor & _cdist_forward_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & x1, const torch::executor::Tensor & x2, double p, torch::executor::optional compute_mode, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CEIL -torch::executor::Tensor & ceil_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLAMP -torch::executor::Tensor & clamp_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::optional & min, const torch::executor::optional & max, torch::executor::Tensor & out); -torch::executor::Tensor & clamp_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::optional & min, const torch::executor::optional & max, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE -torch::executor::Tensor & clone_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional memory_format, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE_DIM_ORDER -torch::executor::Tensor & _clone_dim_order_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, bool non_blocking, torch::executor::optional> dim_order, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONJ_PHYSICAL -torch::executor::Tensor & _conj_physical_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONSTANT_PAD_ND -torch::executor::Tensor & constant_pad_nd_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef pad, const torch::executor::Scalar & value, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION -torch::executor::Tensor & convolution_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & weight, const torch::executor::optional & bias, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef dilation, bool transposed, torch::executor::ArrayRef output_padding, int64_t groups, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION_BACKWARD -::std::tuple convolution_backward_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & grad_output, const torch::executor::Tensor & input, const torch::executor::Tensor & weight, torch::executor::optional> bias_sizes, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef dilation, bool transposed, torch::executor::ArrayRef output_padding, int64_t groups, torch::executor::ArrayRef output_mask, torch::executor::Tensor & out0, torch::executor::Tensor & out1, torch::executor::Tensor & out2); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COPY -torch::executor::Tensor & copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & src, bool non_blocking, torch::executor::Tensor & out); -torch::executor::Tensor & copy_(torch::executor::KernelRuntimeContext & context, torch::executor::Tensor & self, const torch::executor::Tensor & src, bool non_blocking); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COS -torch::executor::Tensor & cos_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COSH -torch::executor::Tensor & cosh_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CUMSUM -torch::executor::Tensor & cumsum_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DETACH_COPY -torch::executor::Tensor & detach_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIAGONAL_COPY -torch::executor::Tensor & diagonal_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t offset, int64_t dim1, int64_t dim2, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIV -torch::executor::Tensor & div_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -torch::executor::Tensor & div_scalar_mode_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::optional rounding_mode, torch::executor::Tensor & out); -torch::executor::Tensor & div_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & div_out_mode(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::optional rounding_mode, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ELU -torch::executor::Tensor & elu_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & alpha, const torch::executor::Scalar & scale, const torch::executor::Scalar & input_scale, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMBEDDING -torch::executor::Tensor & embedding_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & weight, const torch::executor::Tensor & indices, int64_t padding_idx, bool scale_grad_by_freq, bool sparse, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY -torch::executor::Tensor & empty_out(torch::executor::KernelRuntimeContext & context, torch::executor::ArrayRef size, torch::executor::optional memory_format, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY_DIM_ORDER -torch::executor::Tensor & _empty_dim_order_out(torch::executor::KernelRuntimeContext & context, torch::executor::ArrayRef size, torch::executor::optional> dim_order, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EQ -torch::executor::Tensor & eq_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & eq_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ERF -torch::executor::Tensor & erf_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXP -torch::executor::Tensor & exp_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPAND_COPY -torch::executor::Tensor & expand_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef size, bool implicit, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPM1 -torch::executor::Tensor & expm1_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FILL -torch::executor::Tensor & fill_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & value, torch::executor::Tensor & out); -torch::executor::Tensor & fill_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & value, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLIP -torch::executor::Tensor & flip_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef dims, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR -torch::executor::Tensor & floor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR_DIVIDE -torch::executor::Tensor & floor_divide_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FMOD -torch::executor::Tensor & fmod_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -torch::executor::Tensor & fmod_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL -torch::executor::Tensor & full_out(torch::executor::KernelRuntimeContext & context, torch::executor::ArrayRef size, const torch::executor::Scalar & fill_value, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL_LIKE -torch::executor::Tensor & full_like_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & fill_value, torch::executor::optional memory_format, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GATHER -torch::executor::Tensor & gather_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, const torch::executor::Tensor & index, bool sparse_grad, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GE -torch::executor::Tensor & ge_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & ge_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GELU -torch::executor::Tensor & gelu_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::string_view approximate, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GLU -torch::executor::Tensor & glu_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GRID_SAMPLER_2D -torch::executor::Tensor & grid_sampler_2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & grid, int64_t interpolation_mode, int64_t padding_mode, bool align_corners, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GT -torch::executor::Tensor & gt_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & gt_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_HARDTANH -torch::executor::Tensor & hardtanh_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & min_val, const torch::executor::Scalar & max_val, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX -torch::executor::Tensor & index_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef> indices, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_PUT -torch::executor::Tensor & index_put_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef> indices, const torch::executor::Tensor & values, bool accumulate, torch::executor::Tensor & out); -torch::executor::Tensor & index_put_(torch::executor::KernelRuntimeContext & context, torch::executor::Tensor & self, torch::executor::ArrayRef> indices, const torch::executor::Tensor & values, bool accumulate); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_SELECT -torch::executor::Tensor & index_select_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, const torch::executor::Tensor & index, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISINF -torch::executor::Tensor & isinf_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISNAN -torch::executor::Tensor & isnan_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LE -torch::executor::Tensor & le_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & le_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LEAKY_RELU -torch::executor::Tensor & leaky_relu_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & negative_slope, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LIFT_FRESH_COPY -torch::executor::Tensor & lift_fresh_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG -torch::executor::Tensor & log_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG10 -torch::executor::Tensor & log10_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG1P -torch::executor::Tensor & log1p_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG2 -torch::executor::Tensor & log2_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_AND -torch::executor::Tensor & logical_and_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_NOT -torch::executor::Tensor & logical_not_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_OR -torch::executor::Tensor & logical_or_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_XOR -torch::executor::Tensor & logical_xor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGIT -torch::executor::Tensor & logit_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional eps, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG_SOFTMAX -torch::executor::Tensor & log_softmax_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, bool half_to_float, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LT -torch::executor::Tensor & lt_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & lt_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_FILL -torch::executor::Tensor & masked_fill_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & mask, const torch::executor::Scalar & value, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SCATTER -torch::executor::Tensor & masked_scatter_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & mask, const torch::executor::Tensor & source, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SELECT -torch::executor::Tensor & masked_select_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & mask, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX -::std::tuple max_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, bool keepdim, torch::executor::Tensor & max, torch::executor::Tensor & max_values); -torch::executor::Tensor & max_unary_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAXIMUM -torch::executor::Tensor & maximum_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES -::std::tuple max_pool2d_with_indices_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef kernel_size, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef dilation, bool ceil_mode, torch::executor::Tensor & out, torch::executor::Tensor & indices); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES_BACKWARD -torch::executor::Tensor & max_pool2d_with_indices_backward_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & grad_output, const torch::executor::Tensor & self, torch::executor::ArrayRef kernel_size, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef dilation, bool ceil_mode, const torch::executor::Tensor & indices, torch::executor::Tensor & grad_input); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MEAN -torch::executor::Tensor & mean_dim_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional> dim, bool keepdim, torch::executor::optional dtype, torch::executor::Tensor & out); -torch::executor::Tensor & mean_dtype_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MIN -::std::tuple min_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, bool keepdim, torch::executor::Tensor & min, torch::executor::Tensor & min_indices); -torch::executor::Tensor & min_unary_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MINIMUM -torch::executor::Tensor & minimum_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MM -torch::executor::Tensor & mm_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & mat2, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MUL -torch::executor::Tensor & mul_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -torch::executor::Tensor & mul_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NARROW_COPY -torch::executor::Tensor & narrow_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, int64_t start, int64_t length, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_BATCH_NORM -::std::tuple _native_batch_norm_legit_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::optional & weight, const torch::executor::optional & bias, torch::executor::Tensor & running_mean, torch::executor::Tensor & running_var, bool training, double momentum, double eps, torch::executor::Tensor & out, torch::executor::Tensor & save_mean, torch::executor::Tensor & save_invstd); -::std::tuple _native_batch_norm_legit_no_stats_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::optional & weight, const torch::executor::optional & bias, bool training, double momentum, double eps, torch::executor::Tensor & out, torch::executor::Tensor & save_mean, torch::executor::Tensor & save_invstd); -::std::tuple _native_batch_norm_legit_no_training_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::optional & weight, const torch::executor::optional & bias, const torch::executor::Tensor & running_mean, const torch::executor::Tensor & running_var, double momentum, double eps, torch::executor::Tensor & out0, torch::executor::Tensor & out1, torch::executor::Tensor & out2); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_DROPOUT -::std::tuple native_dropout_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, double p, torch::executor::optional train, torch::executor::Tensor & out0, torch::executor::Tensor & out1); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_GROUP_NORM -::std::tuple native_group_norm_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::optional & weight, const torch::executor::optional & bias, int64_t N, int64_t C, int64_t HxW, int64_t group, double eps, torch::executor::Tensor & out0, torch::executor::Tensor & out1, torch::executor::Tensor & out2); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_LAYER_NORM -::std::tuple native_layer_norm_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::ArrayRef normalized_shape, const torch::executor::optional & weight, const torch::executor::optional & bias, double eps, torch::executor::Tensor & out0, torch::executor::Tensor & out1, torch::executor::Tensor & out2); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NE -torch::executor::Tensor & ne_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -torch::executor::Tensor & ne_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NEG -torch::executor::Tensor & neg_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NONZERO -torch::executor::Tensor & nonzero_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ONES -torch::executor::Tensor & ones_out(torch::executor::KernelRuntimeContext & context, torch::executor::ArrayRef size, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PDIST_FORWARD -torch::executor::Tensor & _pdist_forward_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, double p, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PERMUTE_COPY -torch::executor::Tensor & permute_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef dims, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_SHUFFLE -torch::executor::Tensor & pixel_shuffle_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t upscale_factor, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_UNSHUFFLE -torch::executor::Tensor & pixel_unshuffle_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t downscale_factor, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_POW -torch::executor::Tensor & pow_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Scalar & self, const torch::executor::Tensor & exponent, torch::executor::Tensor & out); -torch::executor::Tensor & pow_Tensor_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & exponent, torch::executor::Tensor & out); -torch::executor::Tensor & pow_Tensor_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & exponent, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PROD -torch::executor::Tensor & prod_int_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, bool keepdim, torch::executor::optional dtype, torch::executor::Tensor & out); -torch::executor::Tensor & prod_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RAND -torch::executor::Tensor & rand_out(torch::executor::KernelRuntimeContext & context, torch::executor::ArrayRef size, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RANDN -torch::executor::Tensor & randn_out(torch::executor::KernelRuntimeContext & context, torch::executor::ArrayRef size, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RECIPROCAL -torch::executor::Tensor & reciprocal_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD1D -torch::executor::Tensor & reflection_pad1d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef padding, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD2D -torch::executor::Tensor & reflection_pad2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef padding, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD3D -torch::executor::Tensor & reflection_pad3d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef padding, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RELU -torch::executor::Tensor & relu_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REMAINDER -torch::executor::Tensor & remainder_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -torch::executor::Tensor & remainder_Scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT -torch::executor::Tensor & repeat_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef repeats, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT_INTERLEAVE -torch::executor::Tensor & repeat_interleave_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & repeats, torch::executor::optional output_size, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD1D -torch::executor::Tensor & replication_pad1d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef padding, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD2D -torch::executor::Tensor & replication_pad2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef padding, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD3D -torch::executor::Tensor & replication_pad3d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef padding, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROLL -torch::executor::Tensor & roll_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef shifts, torch::executor::ArrayRef dims, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROUND -torch::executor::Tensor & round_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSQRT -torch::executor::Tensor & rsqrt_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSUB -torch::executor::Tensor & rsub_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, const torch::executor::Scalar & alpha, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCALAR_TENSOR -torch::executor::Tensor & scalar_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Scalar & s, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER -torch::executor::Tensor & scatter_src_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, const torch::executor::Tensor & index, const torch::executor::Tensor & src, torch::executor::Tensor & out); -torch::executor::Tensor & scatter_value_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, const torch::executor::Tensor & index, const torch::executor::Scalar & value, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER_ADD -torch::executor::Tensor & scatter_add_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, const torch::executor::Tensor & index, const torch::executor::Tensor & src, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_COPY -torch::executor::Tensor & select_copy_int_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, int64_t index, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_SCATTER -torch::executor::Tensor & select_scatter_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & src, int64_t dim, int64_t index, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGMOID -torch::executor::Tensor & sigmoid_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGN -torch::executor::Tensor & sign_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIN -torch::executor::Tensor & sin_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SINH -torch::executor::Tensor & sinh_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_COPY -torch::executor::Tensor & slice_copy_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, torch::executor::optional start, torch::executor::optional end, int64_t step, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_SCATTER -torch::executor::Tensor & slice_scatter_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & src, int64_t dim, torch::executor::optional start, torch::executor::optional end, int64_t step, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SOFTMAX -torch::executor::Tensor & softmax_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, bool half_to_float, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_COPY -void split_copy_Tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t split_size, int64_t dim, torch::executor::TensorList out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_WITH_SIZES_COPY -void split_with_sizes_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef split_sizes, int64_t dim, torch::executor::TensorList out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQRT -torch::executor::Tensor & sqrt_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQUEEZE_COPY -torch::executor::Tensor & squeeze_copy_dim_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, torch::executor::Tensor & out); -torch::executor::Tensor & squeeze_copy_dims_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef dim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_STACK -torch::executor::Tensor & stack_out(torch::executor::KernelRuntimeContext & context, torch::executor::TensorList tensors, int64_t dim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUB -torch::executor::Tensor & sub_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, const torch::executor::Scalar & alpha, torch::executor::Tensor & out); -torch::executor::Tensor & sub_scalar_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Scalar & other, const torch::executor::Scalar & alpha, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUM -torch::executor::Tensor & sum_dim_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional> dim, bool keepdim, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TAN -torch::executor::Tensor & tan_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TANH -torch::executor::Tensor & tanh_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TOPK -::std::tuple topk_values(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t k, int64_t dim, bool largest, bool sorted, torch::executor::Tensor & values, torch::executor::Tensor & indices); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_COPY -torch::executor::Tensor & to_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, bool non_blocking, torch::executor::optional memory_format, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_DIM_ORDER_COPY -torch::executor::Tensor & _to_dim_order_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, bool non_blocking, torch::executor::optional> dim_order, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRANSPOSE_COPY -torch::executor::Tensor & transpose_copy_int_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim0, int64_t dim1, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRIL -torch::executor::Tensor & tril_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t diagonal, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRUNC -torch::executor::Tensor & trunc_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_T_COPY -torch::executor::Tensor & t_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNBIND_COPY -void unbind_copy_int_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, torch::executor::TensorList out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNFOLD_COPY -torch::executor::Tensor & unfold_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dimension, int64_t size, int64_t step, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNSQUEEZE_COPY -torch::executor::Tensor & unsqueeze_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t dim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D -torch::executor::Tensor & upsample_bilinear2d_vec_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::optional> output_size, bool align_corners, torch::executor::optional> scale_factors, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D_AA -torch::executor::Tensor & _upsample_bilinear2d_aa_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef output_size, bool align_corners, torch::executor::optional scales_h, torch::executor::optional scales_w, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_NEAREST2D -torch::executor::Tensor & upsample_nearest2d_vec_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::optional> output_size, torch::executor::optional> scale_factors, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VAR -torch::executor::Tensor & var_correction_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional> dim, const torch::executor::optional & correction, bool keepdim, torch::executor::Tensor & out); -torch::executor::Tensor & var_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional> dim, bool unbiased, bool keepdim, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VAR_MEAN -::std::tuple var_mean_correction_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::optional> dim, const torch::executor::optional & correction, bool keepdim, torch::executor::Tensor & out0, torch::executor::Tensor & out1); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_AS_REAL_COPY -torch::executor::Tensor & view_as_real_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_COPY -torch::executor::Tensor & view_copy_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, torch::executor::ArrayRef size, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_WHERE -torch::executor::Tensor & where_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & condition, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ZEROS -torch::executor::Tensor & zeros_out(torch::executor::KernelRuntimeContext & context, torch::executor::ArrayRef size, torch::executor::Tensor & out); -#endif - -// ===================================================================== -// QUANTIZED OPERATOR FORWARD DECLARATIONS -// ===================================================================== - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_ADD -torch::executor::Tensor & quantized_add_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & a, double a_scale, int64_t a_zero_point, int64_t a_quant_min, int64_t a_quant_max, const torch::executor::Tensor & b, double b_scale, int64_t b_zero_point, int64_t b_quant_min, int64_t b_quant_max, double out_scale, int64_t out_zero_point, int64_t out_quant_min, int64_t out_quant_max, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_CHOOSE_QPARAMS -::std::tuple choose_qparams_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, int64_t quant_min, int64_t quant_max, double eps, torch::executor::ScalarType dtype, torch::executor::Tensor & scale_out, torch::executor::Tensor & zero_point_out); -::std::tuple choose_qparams_per_token_asymmetric_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::ScalarType dtype, torch::executor::Tensor & scale_out, torch::executor::Tensor & zero_point_out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_DEQUANTIZE -torch::executor::Tensor & dequantize_per_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, double scale, int64_t zero_point, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::optional out_dtype, torch::executor::Tensor & out); -torch::executor::Tensor & dequantize_per_tensor_tensor_args_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & scale, const torch::executor::Tensor & zero_point, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::optional out_dtype, torch::executor::Tensor & out); -torch::executor::Tensor & dequantize_per_channel_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & scales, const torch::executor::optional & zero_points, int64_t axis, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::optional out_dtype, torch::executor::Tensor & out); -torch::executor::Tensor & dequantize_per_token_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & scales, const torch::executor::Tensor & zero_points, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::ScalarType output_dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING -torch::executor::Tensor & quantized_embedding_byte_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const torch::executor::Tensor & indices, torch::executor::Tensor & out); -torch::executor::Tensor & quantized_embedding_byte_dtype_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const torch::executor::Tensor & indices, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING2B -torch::executor::Tensor & quantized_embedding_2bit_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const torch::executor::Tensor & indices, torch::executor::Tensor & out); -torch::executor::Tensor & quantized_embedding_2bit_dtype_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const torch::executor::Tensor & indices, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING4B -torch::executor::Tensor & quantized_embedding_4bit_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const torch::executor::Tensor & indices, torch::executor::Tensor & out); -torch::executor::Tensor & quantized_embedding_4bit_dtype_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, int64_t weight_quant_min, int64_t weight_quant_max, const torch::executor::Tensor & indices, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_LINEAR -torch::executor::Tensor & quantized_mixed_linear_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, torch::executor::optional dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_MM -torch::executor::Tensor & quantized_mixed_mm_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & weight, const torch::executor::Tensor & weight_scales, const torch::executor::optional & weight_zero_points, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_QUANTIZE -torch::executor::Tensor & quantize_per_channel_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & scales, const torch::executor::Tensor & zero_points, int64_t axis, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::Tensor & out); -torch::executor::Tensor & quantize_per_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, double scale, int64_t zero_point, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::Tensor & out); -torch::executor::Tensor & quantize_per_tensor_tensor_args_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & scale, const torch::executor::Tensor & zero_point, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::Tensor & out); -torch::executor::Tensor & quantize_per_token_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & scales, const torch::executor::Tensor & zero_points, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::Tensor & out); -#endif - -} // namespace native -} // namespace executor -} // namespace torch - -namespace cortex_m { -namespace native { -// ===================================================================== -// CORTEX-M OPERATOR FORWARD DECLARATIONS -// ===================================================================== -// Bring kernel-API types into the cortex_m::native scope so the -// forward declarations below resolve. These mirror the file-scope -// using aliases in -// backends/cortex_m/ops/cortex_m_ops_common.h, but without pulling -// in arm_nn_types.h / arm_nnfunctions.h -- RegisterAllKernels.cpp -// only needs the type names, not the CMSIS-NN headers. -using Tensor = ::torch::executor::Tensor; -using ScalarType = ::executorch::aten::ScalarType; -using Int64ArrayRef = ::executorch::aten::ArrayRef; -using KernelRuntimeContext = ::torch::executor::KernelRuntimeContext; - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_DEQUANTIZE_PER_TENSOR -torch::executor::Tensor & dequantize_per_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, double scale, int64_t zero_point, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_MAXIMUM -torch::executor::Tensor & maximum_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_MINIMUM -torch::executor::Tensor & minimum_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, const torch::executor::Tensor & other, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_PAD -torch::executor::Tensor & pad_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::ArrayRef pre_pad, torch::executor::ArrayRef post_pad, int64_t pad_value, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_ADD -torch::executor::Tensor & quantized_add_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t self_zero_point, int64_t self_multiplier, int64_t self_shift, const torch::executor::Tensor & other, int64_t other_zero_point, int64_t other_multiplier, int64_t other_shift, int64_t output_zero_point, int64_t output_multiplier, int64_t output_shift, int64_t activation_min, int64_t activation_max, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_AVG_POOL2D -torch::executor::Tensor & quantized_avg_pool2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::ArrayRef kernel_size, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, int64_t zero_point, int64_t multiplier, int64_t shift, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_BATCH_MATMUL -torch::executor::Tensor & quantized_batch_matmul_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & lhs, int64_t lhs_zero_point, const torch::executor::Tensor & rhs_transposed, int64_t rhs_zero_point, int64_t output_zero_point, int64_t output_multiplier, int64_t output_shift, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_CONV2D -torch::executor::Tensor & quantized_conv2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & weight, const torch::executor::optional & bias, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef dilation, int64_t input_offset, int64_t output_offset, const torch::executor::Tensor & requantize_multipliers, const torch::executor::Tensor & requantize_shifts, int64_t activation_min, int64_t activation_max, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_DEPTHWISE_CONV2D -torch::executor::Tensor & quantized_depthwise_conv2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & weight, const torch::executor::optional & bias, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef dilation, int64_t depth_multiplier, int64_t input_offset, int64_t output_offset, const torch::executor::Tensor & requantize_multipliers, const torch::executor::Tensor & requantize_shifts, int64_t activation_min, int64_t activation_max, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_LINEAR -torch::executor::Tensor & quantized_linear_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & weights, const torch::executor::optional & bias, const torch::executor::optional & kernel_sum, int64_t input_offset, int64_t filter_offset, int64_t output_offset, torch::executor::ArrayRef requantize_multipliers, torch::executor::ArrayRef requantize_shifts, int64_t activation_max, int64_t activation_min, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MAX_POOL2D -torch::executor::Tensor & quantized_max_pool2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::ArrayRef kernel_size, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef dilation, bool ceil_mode, int64_t input_zero_point, int64_t output_zero_point, int64_t activation_min, int64_t activation_max, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MUL -torch::executor::Tensor & quantized_mul_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & self, int64_t self_zero_point, const torch::executor::Tensor & other, int64_t other_zero_point, int64_t output_zero_point, int64_t output_multiplier, int64_t output_shift, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_TRANSPOSE_CONV2D -torch::executor::Tensor & quantized_transpose_conv2d_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, const torch::executor::Tensor & weight, const torch::executor::optional & bias, torch::executor::ArrayRef stride, torch::executor::ArrayRef padding, torch::executor::ArrayRef output_padding, torch::executor::ArrayRef dilation, int64_t input_offset, int64_t output_offset, const torch::executor::Tensor & requantize_multipliers, const torch::executor::Tensor & requantize_shifts, int64_t activation_min, int64_t activation_max, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZE_PER_TENSOR -torch::executor::Tensor & quantize_per_tensor_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, double scale, int64_t zero_point, int64_t quant_min, int64_t quant_max, torch::executor::ScalarType dtype, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_SOFTMAX -torch::executor::Tensor & softmax_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, int64_t dim, int64_t input_zero_point, int64_t output_zero_point, int64_t input_multiplier, int64_t input_shift, int64_t diff_min, torch::executor::Tensor & out); -#endif - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_TRANSPOSE -torch::executor::Tensor & transpose_out(torch::executor::KernelRuntimeContext & context, const torch::executor::Tensor & input, torch::executor::ArrayRef perm, torch::executor::Tensor & out); -#endif - -} // namespace native -} // namespace cortex_m - -// Use fully qualified namespace for kernel registration -namespace { - -// Only the torch::executor umbrella is opened here: the codegen pipeline emits -// the tracer hooks unqualified (internal::EventTracerProfileOpScope, -// internal::event_tracer_log_evalue), and `internal` is a namespace under both -// torch::executor and executorch::runtime, so opening both makes that reference -// ambiguous. torch::executor re-exports the runtime symbols the array needs -// (Kernel, register_kernels, EValue, Span, Error, and internal::*). -using namespace torch::executor; - -// ===================================================================== -// KERNEL REGISTRATION ARRAY -// Each kernel registration is guarded by its operator define. -// ===================================================================== - -static Kernel kernels_to_register[] = { - -// ===================================================================== -// PORTABLE OPERATORS -// ===================================================================== - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ABS - -Kernel( - "aten::abs.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_abs.out"); - EXECUTORCH_SCOPE_PROF("native_call_abs.out"); - torch::executor::native::abs_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ABS - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOS - -Kernel( - "aten::acos.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_acos.out"); - EXECUTORCH_SCOPE_PROF("native_call_acos.out"); - torch::executor::native::acos_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ACOS - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ACOSH - -Kernel( - "aten::acosh.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_acosh.out"); - EXECUTORCH_SCOPE_PROF("native_call_acosh.out"); - torch::executor::native::acosh_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ACOSH - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADAPTIVE_AVG_POOL2D - -Kernel( - "aten::_adaptive_avg_pool2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& output_size = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto output_size_list_out = output_size.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__adaptive_avg_pool2d.out"); - EXECUTORCH_SCOPE_PROF("native_call__adaptive_avg_pool2d.out"); - torch::executor::native::_adaptive_avg_pool2d_out(context, self_base, output_size_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ADAPTIVE_AVG_POOL2D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADD - -Kernel( - "aten::add.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& alpha = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - const torch::executor::Scalar & alpha_base = alpha.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_add.out"); - EXECUTORCH_SCOPE_PROF("native_call_add.out"); - torch::executor::native::add_out(context, self_base, other_base, alpha_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - - -Kernel( - "aten::add.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& alpha = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - const torch::executor::Scalar & alpha_base = alpha.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_add.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_add.Scalar_out"); - torch::executor::native::add_scalar_out(context, self_base, other_base, alpha_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ADD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ADDMM - -Kernel( - "aten::addmm.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& self = *stack[0]; - EValue& mat1 = *stack[1]; - EValue& mat2 = *stack[2]; - EValue& beta = *stack[3]; - EValue& alpha = *stack[4]; - EValue& out = *stack[5]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & mat1_base = mat1.to(); - const torch::executor::Tensor & mat2_base = mat2.to(); - const torch::executor::Scalar & beta_base = beta.to(); - const torch::executor::Scalar & alpha_base = alpha.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_addmm.out"); - EXECUTORCH_SCOPE_PROF("native_call_addmm.out"); - torch::executor::native::addmm_out(context, self_base, mat1_base, mat2_base, beta_base, alpha_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ADDMM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALIAS_COPY - -Kernel( - "aten::alias_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_alias_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_alias_copy.out"); - torch::executor::native::alias_copy_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ALIAS_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ALLCLOSE - -Kernel( - "aten::allclose.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& rtol = *stack[2]; - EValue& atol = *stack[3]; - EValue& equal_nan = *stack[4]; - EValue& dummy_param = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - double rtol_base = rtol.to(); - double atol_base = atol.to(); - bool equal_nan_base = equal_nan.to(); - bool dummy_param_base = dummy_param.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_allclose.out"); - EXECUTORCH_SCOPE_PROF("native_call_allclose.out"); - torch::executor::native::allclose_out(context, self_base, other_base, rtol_base, atol_base, equal_nan_base, dummy_param_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - - -Kernel( - "aten::allclose.Tensor", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& rtol = *stack[2]; - EValue& atol = *stack[3]; - EValue& equal_nan = *stack[4]; - EValue& dummy_param = *stack[5]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - double rtol_base = rtol.to(); - double atol_base = atol.to(); - bool equal_nan_base = equal_nan.to(); - bool dummy_param_base = dummy_param.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_allclose.Tensor"); - EXECUTORCH_SCOPE_PROF("native_call_allclose.Tensor"); - torch::executor::Tensor result_ = torch::executor::native::allclose_tensor(context, self_base, other_base, rtol_base, atol_base, equal_nan_base, dummy_param_base); - *stack[6] = EValue(result_); - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ALLCLOSE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMAX - -Kernel( - "aten::amax.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_list_out = dim.toIntList(); - - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_amax.out"); - EXECUTORCH_SCOPE_PROF("native_call_amax.out"); - torch::executor::native::amax_out(context, self_base, dim_list_out, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AMAX - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AMIN - -Kernel( - "aten::amin.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_list_out = dim.toIntList(); - - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_amin.out"); - EXECUTORCH_SCOPE_PROF("native_call_amin.out"); - torch::executor::native::amin_out(context, self_base, dim_list_out, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AMIN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ANY - -Kernel( - "aten::any.all_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_any.all_out"); - EXECUTORCH_SCOPE_PROF("native_call_any.all_out"); - torch::executor::native::any_all_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - - -Kernel( - "aten::any.dims_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional>(); - - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_any.dims_out"); - EXECUTORCH_SCOPE_PROF("native_call_any.dims_out"); - torch::executor::native::any_dims_out(context, self_base, dim_opt_out, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - - -Kernel( - "aten::any.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_any.out"); - EXECUTORCH_SCOPE_PROF("native_call_any.out"); - torch::executor::native::any_out(context, self_base, dim_base, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ANY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARANGE - -Kernel( - "aten::arange.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& end = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Scalar & end_base = end.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_arange.out"); - EXECUTORCH_SCOPE_PROF("native_call_arange.out"); - torch::executor::native::arange_out(context, end_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - - -Kernel( - "aten::arange.start_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& start = *stack[0]; - EValue& end = *stack[1]; - EValue& step = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Scalar & start_base = start.to(); - const torch::executor::Scalar & end_base = end.to(); - const torch::executor::Scalar & step_base = step.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_arange.start_out"); - EXECUTORCH_SCOPE_PROF("native_call_arange.start_out"); - torch::executor::native::arange_start_out(context, start_base, end_base, step_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ARANGE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMAX - -Kernel( - "aten::argmax.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional(); - - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_argmax.out"); - EXECUTORCH_SCOPE_PROF("native_call_argmax.out"); - torch::executor::native::argmax_out(context, self_base, dim_opt_out, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMAX - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMIN - -Kernel( - "aten::argmin.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional(); - - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_argmin.out"); - EXECUTORCH_SCOPE_PROF("native_call_argmin.out"); - torch::executor::native::argmin_out(context, self_base, dim_opt_out, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ARGMIN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASIN - -Kernel( - "aten::asin.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_asin.out"); - EXECUTORCH_SCOPE_PROF("native_call_asin.out"); - torch::executor::native::asin_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ASIN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ASINH - -Kernel( - "aten::asinh.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_asinh.out"); - EXECUTORCH_SCOPE_PROF("native_call_asinh.out"); - torch::executor::native::asinh_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ASINH - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AS_STRIDED_COPY - -Kernel( - "aten::as_strided_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& size = *stack[1]; - EValue& stride = *stack[2]; - EValue& storage_offset = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - - auto size_list_out = size.toIntList(); - - - auto stride_list_out = stride.toIntList(); - - - auto storage_offset_opt_out = storage_offset.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_as_strided_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_as_strided_copy.out"); - torch::executor::native::as_strided_copy_out(context, self_base, size_list_out, stride_list_out, storage_offset_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AS_STRIDED_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN - -Kernel( - "aten::atan.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_atan.out"); - EXECUTORCH_SCOPE_PROF("native_call_atan.out"); - torch::executor::native::atan_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN2 - -Kernel( - "aten::atan2.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_atan2.out"); - EXECUTORCH_SCOPE_PROF("native_call_atan2.out"); - torch::executor::native::atan2_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ATAN2 - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ATANH - -Kernel( - "aten::atanh.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_atanh.out"); - EXECUTORCH_SCOPE_PROF("native_call_atanh.out"); - torch::executor::native::atanh_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ATANH - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_AVG_POOL2D - -Kernel( - "aten::avg_pool2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& self = *stack[0]; - EValue& kernel_size = *stack[1]; - EValue& stride = *stack[2]; - EValue& padding = *stack[3]; - EValue& ceil_mode = *stack[4]; - EValue& count_include_pad = *stack[5]; - EValue& divisor_override = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & self_base = self.to(); - - auto kernel_size_list_out = kernel_size.toIntList(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - bool ceil_mode_base = ceil_mode.to(); - bool count_include_pad_base = count_include_pad.to(); - - auto divisor_override_opt_out = divisor_override.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_avg_pool2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_avg_pool2d.out"); - torch::executor::native::avg_pool2d_out(context, self_base, kernel_size_list_out, stride_list_out, padding_list_out, ceil_mode_base, count_include_pad_base, divisor_override_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_AVG_POOL2D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_AND - -Kernel( - "aten::bitwise_and.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_and.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_and.Scalar_out"); - torch::executor::native::bitwise_and_Scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::bitwise_and.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_and.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_and.Tensor_out"); - torch::executor::native::bitwise_and_Tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_AND - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_LEFT_SHIFT - -Kernel( - "aten::bitwise_left_shift.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_left_shift.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_left_shift.Tensor_out"); - torch::executor::native::bitwise_left_shift_Tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::bitwise_left_shift.Tensor_Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_left_shift.Tensor_Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_left_shift.Tensor_Scalar_out"); - torch::executor::native::bitwise_left_shift_Tensor_Scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_LEFT_SHIFT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_NOT - -Kernel( - "aten::bitwise_not.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_not.out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_not.out"); - torch::executor::native::bitwise_not_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_NOT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_OR - -Kernel( - "aten::bitwise_or.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_or.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_or.Scalar_out"); - torch::executor::native::bitwise_or_Scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::bitwise_or.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_or.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_or.Tensor_out"); - torch::executor::native::bitwise_or_Tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_OR - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_RIGHT_SHIFT - -Kernel( - "aten::bitwise_right_shift.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_right_shift.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_right_shift.Tensor_out"); - torch::executor::native::bitwise_right_shift_Tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::bitwise_right_shift.Tensor_Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_right_shift.Tensor_Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_right_shift.Tensor_Scalar_out"); - torch::executor::native::bitwise_right_shift_Tensor_Scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_RIGHT_SHIFT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_XOR - -Kernel( - "aten::bitwise_xor.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_xor.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_xor.Scalar_out"); - torch::executor::native::bitwise_xor_Scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::bitwise_xor.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bitwise_xor.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_bitwise_xor.Tensor_out"); - torch::executor::native::bitwise_xor_Tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BITWISE_XOR - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_BMM - -Kernel( - "aten::bmm.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& mat2 = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & mat2_base = mat2.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_bmm.out"); - EXECUTORCH_SCOPE_PROF("native_call_bmm.out"); - torch::executor::native::bmm_out(context, self_base, mat2_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_BMM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CAT - -Kernel( - "aten::cat.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& tensors = *stack[0]; - EValue& dim = *stack[1]; - EValue& out = *stack[2]; - - auto tensors_list_out = tensors.toTensorList(); - - int64_t dim_base = dim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cat.out"); - EXECUTORCH_SCOPE_PROF("native_call_cat.out"); - torch::executor::native::cat_out(context, tensors_list_out, dim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CAT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CDIST_FORWARD - -Kernel( - "aten::_cdist_forward.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& x1 = *stack[0]; - EValue& x2 = *stack[1]; - EValue& p = *stack[2]; - EValue& compute_mode = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & x1_base = x1.to(); - const torch::executor::Tensor & x2_base = x2.to(); - double p_base = p.to(); - - auto compute_mode_opt_out = compute_mode.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__cdist_forward.out"); - EXECUTORCH_SCOPE_PROF("native_call__cdist_forward.out"); - torch::executor::native::_cdist_forward_out(context, x1_base, x2_base, p_base, compute_mode_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CDIST_FORWARD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CEIL - -Kernel( - "aten::ceil.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ceil.out"); - EXECUTORCH_SCOPE_PROF("native_call_ceil.out"); - torch::executor::native::ceil_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CEIL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLAMP - -Kernel( - "aten::clamp.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& min = *stack[1]; - EValue& max = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto min_opt_out = min.toOptional(); - - - auto max_opt_out = max.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_clamp.out"); - EXECUTORCH_SCOPE_PROF("native_call_clamp.out"); - torch::executor::native::clamp_out(context, self_base, min_opt_out, max_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - - -Kernel( - "aten::clamp.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& min = *stack[1]; - EValue& max = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto min_opt_out = min.toOptional(); - - - auto max_opt_out = max.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_clamp.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_clamp.Tensor_out"); - torch::executor::native::clamp_tensor_out(context, self_base, min_opt_out, max_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CLAMP - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE - -Kernel( - "aten::clone.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& memory_format = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto memory_format_opt_out = memory_format.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_clone.out"); - EXECUTORCH_SCOPE_PROF("native_call_clone.out"); - torch::executor::native::clone_out(context, self_base, memory_format_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE_DIM_ORDER - -Kernel( - "dim_order_ops::_clone_dim_order.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& non_blocking = *stack[1]; - EValue& dim_order = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - bool non_blocking_base = non_blocking.to(); - - auto dim_order_opt_out = dim_order.toOptional>(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__clone_dim_order.out"); - EXECUTORCH_SCOPE_PROF("native_call__clone_dim_order.out"); - torch::executor::native::_clone_dim_order_out(context, self_base, non_blocking_base, dim_order_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CLONE_DIM_ORDER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONJ_PHYSICAL - -Kernel( - "aten::_conj_physical.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__conj_physical.out"); - EXECUTORCH_SCOPE_PROF("native_call__conj_physical.out"); - torch::executor::native::_conj_physical_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CONJ_PHYSICAL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONSTANT_PAD_ND - -Kernel( - "aten::constant_pad_nd.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& pad = *stack[1]; - EValue& value = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto pad_list_out = pad.toIntList(); - - const torch::executor::Scalar & value_base = value.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_constant_pad_nd.out"); - EXECUTORCH_SCOPE_PROF("native_call_constant_pad_nd.out"); - torch::executor::native::constant_pad_nd_out(context, self_base, pad_list_out, value_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CONSTANT_PAD_ND - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION - -Kernel( - "aten::convolution.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 11, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)11, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& stride = *stack[3]; - EValue& padding = *stack[4]; - EValue& dilation = *stack[5]; - EValue& transposed = *stack[6]; - EValue& output_padding = *stack[7]; - EValue& groups = *stack[8]; - EValue& out = *stack[9]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weight_base = weight.to(); - - auto bias_opt_out = bias.toOptional(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - bool transposed_base = transposed.to(); - - auto output_padding_list_out = output_padding.toIntList(); - - int64_t groups_base = groups.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_convolution.out"); - EXECUTORCH_SCOPE_PROF("native_call_convolution.out"); - torch::executor::native::convolution_out(context, input_base, weight_base, bias_opt_out, stride_list_out, padding_list_out, dilation_list_out, transposed_base, output_padding_list_out, groups_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION_BACKWARD - -Kernel( - "aten::convolution_backward.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 15, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)15, stack.size()); - EValue& grad_output = *stack[0]; - EValue& input = *stack[1]; - EValue& weight = *stack[2]; - EValue& bias_sizes = *stack[3]; - EValue& stride = *stack[4]; - EValue& padding = *stack[5]; - EValue& dilation = *stack[6]; - EValue& transposed = *stack[7]; - EValue& output_padding = *stack[8]; - EValue& groups = *stack[9]; - EValue& output_mask = *stack[10]; - EValue& out0 = *stack[11]; - EValue& out1 = *stack[12]; - EValue& out2 = *stack[13]; - const torch::executor::Tensor & grad_output_base = grad_output.to(); - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weight_base = weight.to(); - - auto bias_sizes_opt_out = bias_sizes.toOptional>(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - bool transposed_base = transposed.to(); - - auto output_padding_list_out = output_padding.toIntList(); - - int64_t groups_base = groups.to(); - - #ifdef USE_ATEN_LIB - std::array output_mask_list_out; - auto output_mask_list_in = output_mask.toBoolList(); - size_t _i = 0; - for (auto output_mask_elem: output_mask_list_in) { - output_mask_list_out[_i++] = output_mask_elem; - } - #else - auto output_mask_list_out = output_mask.toBoolList(); - #endif - - torch::executor::Tensor & out0_base = out0.to(); - torch::executor::Tensor & out1_base = out1.to(); - torch::executor::Tensor & out2_base = out2.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_convolution_backward.out"); - EXECUTORCH_SCOPE_PROF("native_call_convolution_backward.out"); - torch::executor::native::convolution_backward_out(context, grad_output_base, input_base, weight_base, bias_sizes_opt_out, stride_list_out, padding_list_out, dilation_list_out, transposed_base, output_padding_list_out, groups_base, output_mask_list_out, out0_base, out1_base, out2_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[11]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[12]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[13]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CONVOLUTION_BACKWARD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COPY - -Kernel( - "aten::copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& src = *stack[1]; - EValue& non_blocking = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & src_base = src.to(); - bool non_blocking_base = non_blocking.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_copy.out"); - torch::executor::native::copy_out(context, self_base, src_base, non_blocking_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - - -Kernel( - "aten::copy_", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& src = *stack[1]; - EValue& non_blocking = *stack[2]; - torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & src_base = src.to(); - bool non_blocking_base = non_blocking.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_copy_"); - EXECUTORCH_SCOPE_PROF("native_call_copy_"); - torch::executor::Tensor & result_ = torch::executor::native::copy_(context, self_base, src_base, non_blocking_base); - *stack[3] = EValue(result_); - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COS - -Kernel( - "aten::cos.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cos.out"); - EXECUTORCH_SCOPE_PROF("native_call_cos.out"); - torch::executor::native::cos_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_COS - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_COSH - -Kernel( - "aten::cosh.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cosh.out"); - EXECUTORCH_SCOPE_PROF("native_call_cosh.out"); - torch::executor::native::cosh_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_COSH - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_CUMSUM - -Kernel( - "aten::cumsum.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& dtype = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_cumsum.out"); - EXECUTORCH_SCOPE_PROF("native_call_cumsum.out"); - torch::executor::native::cumsum_out(context, self_base, dim_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_CUMSUM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DETACH_COPY - -Kernel( - "aten::detach_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_detach_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_detach_copy.out"); - torch::executor::native::detach_copy_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_DETACH_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIAGONAL_COPY - -Kernel( - "aten::diagonal_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& offset = *stack[1]; - EValue& dim1 = *stack[2]; - EValue& dim2 = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t offset_base = offset.to(); - int64_t dim1_base = dim1.to(); - int64_t dim2_base = dim2.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_diagonal_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_diagonal_copy.out"); - torch::executor::native::diagonal_copy_out(context, self_base, offset_base, dim1_base, dim2_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_DIAGONAL_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_DIV - -Kernel( - "aten::div.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.out"); - EXECUTORCH_SCOPE_PROF("native_call_div.out"); - torch::executor::native::div_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::div.Scalar_mode_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& rounding_mode = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - - auto rounding_mode_opt_out = rounding_mode.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.Scalar_mode_out"); - EXECUTORCH_SCOPE_PROF("native_call_div.Scalar_mode_out"); - torch::executor::native::div_scalar_mode_out(context, self_base, other_base, rounding_mode_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - - -Kernel( - "aten::div.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_div.Scalar_out"); - torch::executor::native::div_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::div.out_mode", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& rounding_mode = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - - auto rounding_mode_opt_out = rounding_mode.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_div.out_mode"); - EXECUTORCH_SCOPE_PROF("native_call_div.out_mode"); - torch::executor::native::div_out_mode(context, self_base, other_base, rounding_mode_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_DIV - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ELU - -Kernel( - "aten::elu.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& alpha = *stack[1]; - EValue& scale = *stack[2]; - EValue& input_scale = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & alpha_base = alpha.to(); - const torch::executor::Scalar & scale_base = scale.to(); - const torch::executor::Scalar & input_scale_base = input_scale.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_elu.out"); - EXECUTORCH_SCOPE_PROF("native_call_elu.out"); - torch::executor::native::elu_out(context, self_base, alpha_base, scale_base, input_scale_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ELU - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMBEDDING - -Kernel( - "aten::embedding.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& weight = *stack[0]; - EValue& indices = *stack[1]; - EValue& padding_idx = *stack[2]; - EValue& scale_grad_by_freq = *stack[3]; - EValue& sparse = *stack[4]; - EValue& out = *stack[5]; - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & indices_base = indices.to(); - int64_t padding_idx_base = padding_idx.to(); - bool scale_grad_by_freq_base = scale_grad_by_freq.to(); - bool sparse_base = sparse.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding.out"); - EXECUTORCH_SCOPE_PROF("native_call_embedding.out"); - torch::executor::native::embedding_out(context, weight_base, indices_base, padding_idx_base, scale_grad_by_freq_base, sparse_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EMBEDDING - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY - -Kernel( - "aten::empty.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& size = *stack[0]; - EValue& memory_format = *stack[1]; - EValue& out = *stack[2]; - - auto size_list_out = size.toIntList(); - - - auto memory_format_opt_out = memory_format.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_empty.out"); - EXECUTORCH_SCOPE_PROF("native_call_empty.out"); - torch::executor::native::empty_out(context, size_list_out, memory_format_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY_DIM_ORDER - -Kernel( - "dim_order_ops::_empty_dim_order.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& size = *stack[0]; - EValue& dim_order = *stack[1]; - EValue& out = *stack[2]; - - auto size_list_out = size.toIntList(); - - - auto dim_order_opt_out = dim_order.toOptional>(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__empty_dim_order.out"); - EXECUTORCH_SCOPE_PROF("native_call__empty_dim_order.out"); - torch::executor::native::_empty_dim_order_out(context, size_list_out, dim_order_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EMPTY_DIM_ORDER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EQ - -Kernel( - "aten::eq.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_eq.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_eq.Scalar_out"); - torch::executor::native::eq_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::eq.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_eq.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_eq.Tensor_out"); - torch::executor::native::eq_tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EQ - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ERF - -Kernel( - "aten::erf.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_erf.out"); - EXECUTORCH_SCOPE_PROF("native_call_erf.out"); - torch::executor::native::erf_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ERF - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXP - -Kernel( - "aten::exp.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_exp.out"); - EXECUTORCH_SCOPE_PROF("native_call_exp.out"); - torch::executor::native::exp_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EXP - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPAND_COPY - -Kernel( - "aten::expand_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& size = *stack[1]; - EValue& implicit = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto size_list_out = size.toIntList(); - - bool implicit_base = implicit.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_expand_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_expand_copy.out"); - torch::executor::native::expand_copy_out(context, self_base, size_list_out, implicit_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EXPAND_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_EXPM1 - -Kernel( - "aten::expm1.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_expm1.out"); - EXECUTORCH_SCOPE_PROF("native_call_expm1.out"); - torch::executor::native::expm1_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_EXPM1 - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FILL - -Kernel( - "aten::fill.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& value = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & value_base = value.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fill.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_fill.Scalar_out"); - torch::executor::native::fill_scalar_out(context, self_base, value_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::fill.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& value = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & value_base = value.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fill.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_fill.Tensor_out"); - torch::executor::native::fill_tensor_out(context, self_base, value_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FILL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLIP - -Kernel( - "aten::flip.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dims = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto dims_list_out = dims.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_flip.out"); - EXECUTORCH_SCOPE_PROF("native_call_flip.out"); - torch::executor::native::flip_out(context, self_base, dims_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FLIP - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR - -Kernel( - "aten::floor.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_floor.out"); - EXECUTORCH_SCOPE_PROF("native_call_floor.out"); - torch::executor::native::floor_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR_DIVIDE - -Kernel( - "aten::floor_divide.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_floor_divide.out"); - EXECUTORCH_SCOPE_PROF("native_call_floor_divide.out"); - torch::executor::native::floor_divide_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FLOOR_DIVIDE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FMOD - -Kernel( - "aten::fmod.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fmod.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_fmod.Tensor_out"); - torch::executor::native::fmod_Tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::fmod.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_fmod.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_fmod.Scalar_out"); - torch::executor::native::fmod_Scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FMOD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL - -Kernel( - "aten::full.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& size = *stack[0]; - EValue& fill_value = *stack[1]; - EValue& out = *stack[2]; - - auto size_list_out = size.toIntList(); - - const torch::executor::Scalar & fill_value_base = fill_value.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_full.out"); - EXECUTORCH_SCOPE_PROF("native_call_full.out"); - torch::executor::native::full_out(context, size_list_out, fill_value_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FULL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_FULL_LIKE - -Kernel( - "aten::full_like.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& fill_value = *stack[1]; - EValue& memory_format = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & fill_value_base = fill_value.to(); - - auto memory_format_opt_out = memory_format.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_full_like.out"); - EXECUTORCH_SCOPE_PROF("native_call_full_like.out"); - torch::executor::native::full_like_out(context, self_base, fill_value_base, memory_format_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_FULL_LIKE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GATHER - -Kernel( - "aten::gather.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& index = *stack[2]; - EValue& sparse_grad = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - const torch::executor::Tensor & index_base = index.to(); - bool sparse_grad_base = sparse_grad.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gather.out"); - EXECUTORCH_SCOPE_PROF("native_call_gather.out"); - torch::executor::native::gather_out(context, self_base, dim_base, index_base, sparse_grad_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GATHER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GE - -Kernel( - "aten::ge.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ge.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_ge.Scalar_out"); - torch::executor::native::ge_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::ge.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ge.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_ge.Tensor_out"); - torch::executor::native::ge_tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GELU - -Kernel( - "aten::gelu.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& approximate = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::string_view approximate_base = approximate.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gelu.out"); - EXECUTORCH_SCOPE_PROF("native_call_gelu.out"); - torch::executor::native::gelu_out(context, self_base, approximate_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GELU - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GLU - -Kernel( - "aten::glu.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_glu.out"); - EXECUTORCH_SCOPE_PROF("native_call_glu.out"); - torch::executor::native::glu_out(context, self_base, dim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GLU - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GRID_SAMPLER_2D - -Kernel( - "aten::grid_sampler_2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& input = *stack[0]; - EValue& grid = *stack[1]; - EValue& interpolation_mode = *stack[2]; - EValue& padding_mode = *stack[3]; - EValue& align_corners = *stack[4]; - EValue& out = *stack[5]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & grid_base = grid.to(); - int64_t interpolation_mode_base = interpolation_mode.to(); - int64_t padding_mode_base = padding_mode.to(); - bool align_corners_base = align_corners.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_grid_sampler_2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_grid_sampler_2d.out"); - torch::executor::native::grid_sampler_2d_out(context, input_base, grid_base, interpolation_mode_base, padding_mode_base, align_corners_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GRID_SAMPLER_2D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_GT - -Kernel( - "aten::gt.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gt.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_gt.Scalar_out"); - torch::executor::native::gt_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::gt.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_gt.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_gt.Tensor_out"); - torch::executor::native::gt_tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_GT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_HARDTANH - -Kernel( - "aten::hardtanh.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& min_val = *stack[1]; - EValue& max_val = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & min_val_base = min_val.to(); - const torch::executor::Scalar & max_val_base = max_val.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_hardtanh.out"); - EXECUTORCH_SCOPE_PROF("native_call_hardtanh.out"); - torch::executor::native::hardtanh_out(context, self_base, min_val_base, max_val_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_HARDTANH - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX - -Kernel( - "aten::index.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& indices = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - #ifdef USE_ATEN_LIB - auto indices_list_in = indices.toListOptionalTensor(); - c10::List<::std::optional> indices_list_out; - for (auto indices_elem: indices_list_in) { - indices_list_out.push_back(indices_elem); - } - #else - auto indices_list_out = indices.toListOptionalTensor(); - #endif - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_index.Tensor_out"); - torch::executor::native::index_Tensor_out(context, self_base, indices_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_PUT - -Kernel( - "aten::index_put.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& indices = *stack[1]; - EValue& values = *stack[2]; - EValue& accumulate = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - - #ifdef USE_ATEN_LIB - auto indices_list_in = indices.toListOptionalTensor(); - c10::List<::std::optional> indices_list_out; - for (auto indices_elem: indices_list_in) { - indices_list_out.push_back(indices_elem); - } - #else - auto indices_list_out = indices.toListOptionalTensor(); - #endif - - const torch::executor::Tensor & values_base = values.to(); - bool accumulate_base = accumulate.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index_put.out"); - EXECUTORCH_SCOPE_PROF("native_call_index_put.out"); - torch::executor::native::index_put_out(context, self_base, indices_list_out, values_base, accumulate_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - - -Kernel( - "aten::index_put_", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& indices = *stack[1]; - EValue& values = *stack[2]; - EValue& accumulate = *stack[3]; - torch::executor::Tensor & self_base = self.to(); - - #ifdef USE_ATEN_LIB - auto indices_list_in = indices.toListOptionalTensor(); - c10::List<::std::optional> indices_list_out; - for (auto indices_elem: indices_list_in) { - indices_list_out.push_back(indices_elem); - } - #else - auto indices_list_out = indices.toListOptionalTensor(); - #endif - - const torch::executor::Tensor & values_base = values.to(); - bool accumulate_base = accumulate.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index_put_"); - EXECUTORCH_SCOPE_PROF("native_call_index_put_"); - torch::executor::Tensor & result_ = torch::executor::native::index_put_(context, self_base, indices_list_out, values_base, accumulate_base); - *stack[4] = EValue(result_); - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_PUT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_SELECT - -Kernel( - "aten::index_select.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& index = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - const torch::executor::Tensor & index_base = index.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_index_select.out"); - EXECUTORCH_SCOPE_PROF("native_call_index_select.out"); - torch::executor::native::index_select_out(context, self_base, dim_base, index_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_INDEX_SELECT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISINF - -Kernel( - "aten::isinf.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_isinf.out"); - EXECUTORCH_SCOPE_PROF("native_call_isinf.out"); - torch::executor::native::isinf_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ISINF - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ISNAN - -Kernel( - "aten::isnan.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_isnan.out"); - EXECUTORCH_SCOPE_PROF("native_call_isnan.out"); - torch::executor::native::isnan_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ISNAN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LE - -Kernel( - "aten::le.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_le.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_le.Scalar_out"); - torch::executor::native::le_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::le.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_le.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_le.Tensor_out"); - torch::executor::native::le_tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LEAKY_RELU - -Kernel( - "aten::leaky_relu.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& negative_slope = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & negative_slope_base = negative_slope.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_leaky_relu.out"); - EXECUTORCH_SCOPE_PROF("native_call_leaky_relu.out"); - torch::executor::native::leaky_relu_out(context, self_base, negative_slope_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LEAKY_RELU - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LIFT_FRESH_COPY - -Kernel( - "aten::lift_fresh_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_lift_fresh_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_lift_fresh_copy.out"); - torch::executor::native::lift_fresh_copy_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LIFT_FRESH_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG - -Kernel( - "aten::log.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log.out"); - EXECUTORCH_SCOPE_PROF("native_call_log.out"); - torch::executor::native::log_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG10 - -Kernel( - "aten::log10.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log10.out"); - EXECUTORCH_SCOPE_PROF("native_call_log10.out"); - torch::executor::native::log10_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG10 - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG1P - -Kernel( - "aten::log1p.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log1p.out"); - EXECUTORCH_SCOPE_PROF("native_call_log1p.out"); - torch::executor::native::log1p_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG1P - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG2 - -Kernel( - "aten::log2.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_log2.out"); - EXECUTORCH_SCOPE_PROF("native_call_log2.out"); - torch::executor::native::log2_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG2 - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_AND - -Kernel( - "aten::logical_and.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_and.out"); - EXECUTORCH_SCOPE_PROF("native_call_logical_and.out"); - torch::executor::native::logical_and_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_AND - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_NOT - -Kernel( - "aten::logical_not.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_not.out"); - EXECUTORCH_SCOPE_PROF("native_call_logical_not.out"); - torch::executor::native::logical_not_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_NOT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_OR - -Kernel( - "aten::logical_or.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_or.out"); - EXECUTORCH_SCOPE_PROF("native_call_logical_or.out"); - torch::executor::native::logical_or_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_OR - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_XOR - -Kernel( - "aten::logical_xor.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logical_xor.out"); - EXECUTORCH_SCOPE_PROF("native_call_logical_xor.out"); - torch::executor::native::logical_xor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGICAL_XOR - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOGIT - -Kernel( - "aten::logit.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& eps = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto eps_opt_out = eps.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_logit.out"); - EXECUTORCH_SCOPE_PROF("native_call_logit.out"); - torch::executor::native::logit_out(context, self_base, eps_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOGIT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LOG_SOFTMAX - -Kernel( - "aten::_log_softmax.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& half_to_float = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - bool half_to_float_base = half_to_float.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__log_softmax.out"); - EXECUTORCH_SCOPE_PROF("native_call__log_softmax.out"); - torch::executor::native::log_softmax_out(context, self_base, dim_base, half_to_float_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LOG_SOFTMAX - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_LT - -Kernel( - "aten::lt.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_lt.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_lt.Scalar_out"); - torch::executor::native::lt_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::lt.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_lt.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_lt.Tensor_out"); - torch::executor::native::lt_tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_LT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_FILL - -Kernel( - "aten::masked_fill.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& mask = *stack[1]; - EValue& value = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & mask_base = mask.to(); - const torch::executor::Scalar & value_base = value.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_masked_fill.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_masked_fill.Scalar_out"); - torch::executor::native::masked_fill_scalar_out(context, self_base, mask_base, value_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_FILL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SCATTER - -Kernel( - "aten::masked_scatter.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& mask = *stack[1]; - EValue& source = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & mask_base = mask.to(); - const torch::executor::Tensor & source_base = source.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_masked_scatter.out"); - EXECUTORCH_SCOPE_PROF("native_call_masked_scatter.out"); - torch::executor::native::masked_scatter_out(context, self_base, mask_base, source_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SCATTER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SELECT - -Kernel( - "aten::masked_select.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& mask = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & mask_base = mask.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_masked_select.out"); - EXECUTORCH_SCOPE_PROF("native_call_masked_select.out"); - torch::executor::native::masked_select_out(context, self_base, mask_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MASKED_SELECT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX - -Kernel( - "aten::max.dim_max", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& max = *stack[3]; - EValue& max_values = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & max_base = max.to(); - torch::executor::Tensor & max_values_base = max_values.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max.dim_max"); - EXECUTORCH_SCOPE_PROF("native_call_max.dim_max"); - torch::executor::native::max_out(context, self_base, dim_base, keepdim_base, max_base, max_values_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - - -Kernel( - "aten::max.unary_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max.unary_out"); - EXECUTORCH_SCOPE_PROF("native_call_max.unary_out"); - torch::executor::native::max_unary_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAX - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAXIMUM - -Kernel( - "aten::maximum.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_maximum.out"); - EXECUTORCH_SCOPE_PROF("native_call_maximum.out"); - torch::executor::native::maximum_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAXIMUM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES - -Kernel( - "aten::max_pool2d_with_indices.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& self = *stack[0]; - EValue& kernel_size = *stack[1]; - EValue& stride = *stack[2]; - EValue& padding = *stack[3]; - EValue& dilation = *stack[4]; - EValue& ceil_mode = *stack[5]; - EValue& out = *stack[6]; - EValue& indices = *stack[7]; - const torch::executor::Tensor & self_base = self.to(); - - auto kernel_size_list_out = kernel_size.toIntList(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - bool ceil_mode_base = ceil_mode.to(); - torch::executor::Tensor & out_base = out.to(); - torch::executor::Tensor & indices_base = indices.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max_pool2d_with_indices.out"); - EXECUTORCH_SCOPE_PROF("native_call_max_pool2d_with_indices.out"); - torch::executor::native::max_pool2d_with_indices_out(context, self_base, kernel_size_list_out, stride_list_out, padding_list_out, dilation_list_out, ceil_mode_base, out_base, indices_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES_BACKWARD - -Kernel( - "aten::max_pool2d_with_indices_backward.grad_input", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 10, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)10, stack.size()); - EValue& grad_output = *stack[0]; - EValue& self = *stack[1]; - EValue& kernel_size = *stack[2]; - EValue& stride = *stack[3]; - EValue& padding = *stack[4]; - EValue& dilation = *stack[5]; - EValue& ceil_mode = *stack[6]; - EValue& indices = *stack[7]; - EValue& grad_input = *stack[8]; - const torch::executor::Tensor & grad_output_base = grad_output.to(); - const torch::executor::Tensor & self_base = self.to(); - - auto kernel_size_list_out = kernel_size.toIntList(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - bool ceil_mode_base = ceil_mode.to(); - const torch::executor::Tensor & indices_base = indices.to(); - torch::executor::Tensor & grad_input_base = grad_input.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_max_pool2d_with_indices_backward.grad_input"); - EXECUTORCH_SCOPE_PROF("native_call_max_pool2d_with_indices_backward.grad_input"); - torch::executor::native::max_pool2d_with_indices_backward_out(context, grad_output_base, self_base, kernel_size_list_out, stride_list_out, padding_list_out, dilation_list_out, ceil_mode_base, indices_base, grad_input_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MAX_POOL2D_WITH_INDICES_BACKWARD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MEAN - -Kernel( - "aten::mean.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& dtype = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional>(); - - bool keepdim_base = keepdim.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mean.out"); - EXECUTORCH_SCOPE_PROF("native_call_mean.out"); - torch::executor::native::mean_dim_out(context, self_base, dim_opt_out, keepdim_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - - -Kernel( - "aten::mean.dtype_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dtype = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mean.dtype_out"); - EXECUTORCH_SCOPE_PROF("native_call_mean.dtype_out"); - torch::executor::native::mean_dtype_out(context, self_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MEAN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MIN - -Kernel( - "aten::min.dim_min", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& min = *stack[3]; - EValue& min_indices = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & min_base = min.to(); - torch::executor::Tensor & min_indices_base = min_indices.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_min.dim_min"); - EXECUTORCH_SCOPE_PROF("native_call_min.dim_min"); - torch::executor::native::min_out(context, self_base, dim_base, keepdim_base, min_base, min_indices_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - - -Kernel( - "aten::min.unary_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_min.unary_out"); - EXECUTORCH_SCOPE_PROF("native_call_min.unary_out"); - torch::executor::native::min_unary_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MIN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MINIMUM - -Kernel( - "aten::minimum.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_minimum.out"); - EXECUTORCH_SCOPE_PROF("native_call_minimum.out"); - torch::executor::native::minimum_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MINIMUM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MM - -Kernel( - "aten::mm.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& mat2 = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & mat2_base = mat2.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mm.out"); - EXECUTORCH_SCOPE_PROF("native_call_mm.out"); - torch::executor::native::mm_out(context, self_base, mat2_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_MUL - -Kernel( - "aten::mul.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mul.out"); - EXECUTORCH_SCOPE_PROF("native_call_mul.out"); - torch::executor::native::mul_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::mul.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mul.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_mul.Scalar_out"); - torch::executor::native::mul_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_MUL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NARROW_COPY - -Kernel( - "aten::narrow_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& start = *stack[2]; - EValue& length = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - int64_t start_base = start.to(); - int64_t length_base = length.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_narrow_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_narrow_copy.out"); - torch::executor::native::narrow_copy_out(context, self_base, dim_base, start_base, length_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NARROW_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_BATCH_NORM - -Kernel( - "aten::_native_batch_norm_legit.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 12, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)12, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& running_mean = *stack[3]; - EValue& running_var = *stack[4]; - EValue& training = *stack[5]; - EValue& momentum = *stack[6]; - EValue& eps = *stack[7]; - EValue& out = *stack[8]; - EValue& save_mean = *stack[9]; - EValue& save_invstd = *stack[10]; - const torch::executor::Tensor & input_base = input.to(); - - auto weight_opt_out = weight.toOptional(); - - - auto bias_opt_out = bias.toOptional(); - - torch::executor::Tensor & running_mean_base = running_mean.to(); - torch::executor::Tensor & running_var_base = running_var.to(); - bool training_base = training.to(); - double momentum_base = momentum.to(); - double eps_base = eps.to(); - torch::executor::Tensor & out_base = out.to(); - torch::executor::Tensor & save_mean_base = save_mean.to(); - torch::executor::Tensor & save_invstd_base = save_invstd.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__native_batch_norm_legit.out"); - EXECUTORCH_SCOPE_PROF("native_call__native_batch_norm_legit.out"); - torch::executor::native::_native_batch_norm_legit_out(context, input_base, weight_opt_out, bias_opt_out, running_mean_base, running_var_base, training_base, momentum_base, eps_base, out_base, save_mean_base, save_invstd_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[10]); - - - } -), - - -Kernel( - "aten::_native_batch_norm_legit.no_stats_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 10, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)10, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& training = *stack[3]; - EValue& momentum = *stack[4]; - EValue& eps = *stack[5]; - EValue& out = *stack[6]; - EValue& save_mean = *stack[7]; - EValue& save_invstd = *stack[8]; - const torch::executor::Tensor & input_base = input.to(); - - auto weight_opt_out = weight.toOptional(); - - - auto bias_opt_out = bias.toOptional(); - - bool training_base = training.to(); - double momentum_base = momentum.to(); - double eps_base = eps.to(); - torch::executor::Tensor & out_base = out.to(); - torch::executor::Tensor & save_mean_base = save_mean.to(); - torch::executor::Tensor & save_invstd_base = save_invstd.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__native_batch_norm_legit.no_stats_out"); - EXECUTORCH_SCOPE_PROF("native_call__native_batch_norm_legit.no_stats_out"); - torch::executor::native::_native_batch_norm_legit_no_stats_out(context, input_base, weight_opt_out, bias_opt_out, training_base, momentum_base, eps_base, out_base, save_mean_base, save_invstd_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); - - - } -), - - -Kernel( - "aten::_native_batch_norm_legit_no_training.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 11, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)11, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& running_mean = *stack[3]; - EValue& running_var = *stack[4]; - EValue& momentum = *stack[5]; - EValue& eps = *stack[6]; - EValue& out0 = *stack[7]; - EValue& out1 = *stack[8]; - EValue& out2 = *stack[9]; - const torch::executor::Tensor & input_base = input.to(); - - auto weight_opt_out = weight.toOptional(); - - - auto bias_opt_out = bias.toOptional(); - - const torch::executor::Tensor & running_mean_base = running_mean.to(); - const torch::executor::Tensor & running_var_base = running_var.to(); - double momentum_base = momentum.to(); - double eps_base = eps.to(); - torch::executor::Tensor & out0_base = out0.to(); - torch::executor::Tensor & out1_base = out1.to(); - torch::executor::Tensor & out2_base = out2.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__native_batch_norm_legit_no_training.out"); - EXECUTORCH_SCOPE_PROF("native_call__native_batch_norm_legit_no_training.out"); - torch::executor::native::_native_batch_norm_legit_no_training_out(context, input_base, weight_opt_out, bias_opt_out, running_mean_base, running_var_base, momentum_base, eps_base, out0_base, out1_base, out2_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_BATCH_NORM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_DROPOUT - -Kernel( - "aten::native_dropout.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& input = *stack[0]; - EValue& p = *stack[1]; - EValue& train = *stack[2]; - EValue& out0 = *stack[3]; - EValue& out1 = *stack[4]; - const torch::executor::Tensor & input_base = input.to(); - double p_base = p.to(); - - auto train_opt_out = train.toOptional(); - - torch::executor::Tensor & out0_base = out0.to(); - torch::executor::Tensor & out1_base = out1.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_native_dropout.out"); - EXECUTORCH_SCOPE_PROF("native_call_native_dropout.out"); - torch::executor::native::native_dropout_out(context, input_base, p_base, train_opt_out, out0_base, out1_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_DROPOUT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_GROUP_NORM - -Kernel( - "aten::native_group_norm.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 12, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)12, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& N = *stack[3]; - EValue& C = *stack[4]; - EValue& HxW = *stack[5]; - EValue& group = *stack[6]; - EValue& eps = *stack[7]; - EValue& out0 = *stack[8]; - EValue& out1 = *stack[9]; - EValue& out2 = *stack[10]; - const torch::executor::Tensor & input_base = input.to(); - - auto weight_opt_out = weight.toOptional(); - - - auto bias_opt_out = bias.toOptional(); - - int64_t N_base = N.to(); - int64_t C_base = C.to(); - int64_t HxW_base = HxW.to(); - int64_t group_base = group.to(); - double eps_base = eps.to(); - torch::executor::Tensor & out0_base = out0.to(); - torch::executor::Tensor & out1_base = out1.to(); - torch::executor::Tensor & out2_base = out2.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_native_group_norm.out"); - EXECUTORCH_SCOPE_PROF("native_call_native_group_norm.out"); - torch::executor::native::native_group_norm_out(context, input_base, weight_opt_out, bias_opt_out, N_base, C_base, HxW_base, group_base, eps_base, out0_base, out1_base, out2_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[9]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[10]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_GROUP_NORM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_LAYER_NORM - -Kernel( - "aten::native_layer_norm.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& input = *stack[0]; - EValue& normalized_shape = *stack[1]; - EValue& weight = *stack[2]; - EValue& bias = *stack[3]; - EValue& eps = *stack[4]; - EValue& out0 = *stack[5]; - EValue& out1 = *stack[6]; - EValue& out2 = *stack[7]; - const torch::executor::Tensor & input_base = input.to(); - - auto normalized_shape_list_out = normalized_shape.toIntList(); - - - auto weight_opt_out = weight.toOptional(); - - - auto bias_opt_out = bias.toOptional(); - - double eps_base = eps.to(); - torch::executor::Tensor & out0_base = out0.to(); - torch::executor::Tensor & out1_base = out1.to(); - torch::executor::Tensor & out2_base = out2.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_native_layer_norm.out"); - EXECUTORCH_SCOPE_PROF("native_call_native_layer_norm.out"); - torch::executor::native::native_layer_norm_out(context, input_base, normalized_shape_list_out, weight_opt_out, bias_opt_out, eps_base, out0_base, out1_base, out2_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NATIVE_LAYER_NORM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NE - -Kernel( - "aten::ne.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ne.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_ne.Scalar_out"); - torch::executor::native::ne_scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::ne.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ne.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_ne.Tensor_out"); - torch::executor::native::ne_tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NEG - -Kernel( - "aten::neg.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_neg.out"); - EXECUTORCH_SCOPE_PROF("native_call_neg.out"); - torch::executor::native::neg_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NEG - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_NONZERO - -Kernel( - "aten::nonzero.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_nonzero.out"); - EXECUTORCH_SCOPE_PROF("native_call_nonzero.out"); - torch::executor::native::nonzero_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_NONZERO - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ONES - -Kernel( - "aten::ones.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& size = *stack[0]; - EValue& out = *stack[1]; - - auto size_list_out = size.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_ones.out"); - EXECUTORCH_SCOPE_PROF("native_call_ones.out"); - torch::executor::native::ones_out(context, size_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ONES - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PDIST_FORWARD - -Kernel( - "aten::_pdist_forward.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& p = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - double p_base = p.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__pdist_forward.out"); - EXECUTORCH_SCOPE_PROF("native_call__pdist_forward.out"); - torch::executor::native::_pdist_forward_out(context, self_base, p_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PDIST_FORWARD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PERMUTE_COPY - -Kernel( - "aten::permute_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dims = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto dims_list_out = dims.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_permute_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_permute_copy.out"); - torch::executor::native::permute_copy_out(context, self_base, dims_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PERMUTE_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_SHUFFLE - -Kernel( - "aten::pixel_shuffle.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& upscale_factor = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - int64_t upscale_factor_base = upscale_factor.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pixel_shuffle.out"); - EXECUTORCH_SCOPE_PROF("native_call_pixel_shuffle.out"); - torch::executor::native::pixel_shuffle_out(context, self_base, upscale_factor_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_SHUFFLE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_UNSHUFFLE - -Kernel( - "aten::pixel_unshuffle.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& downscale_factor = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - int64_t downscale_factor_base = downscale_factor.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pixel_unshuffle.out"); - EXECUTORCH_SCOPE_PROF("native_call_pixel_unshuffle.out"); - torch::executor::native::pixel_unshuffle_out(context, self_base, downscale_factor_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PIXEL_UNSHUFFLE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_POW - -Kernel( - "aten::pow.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& exponent = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Scalar & self_base = self.to(); - const torch::executor::Tensor & exponent_base = exponent.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pow.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_pow.Scalar_out"); - torch::executor::native::pow_Scalar_out(context, self_base, exponent_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::pow.Tensor_Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& exponent = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & exponent_base = exponent.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pow.Tensor_Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_pow.Tensor_Scalar_out"); - torch::executor::native::pow_Tensor_Scalar_out(context, self_base, exponent_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::pow.Tensor_Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& exponent = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & exponent_base = exponent.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pow.Tensor_Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_pow.Tensor_Tensor_out"); - torch::executor::native::pow_Tensor_Tensor_out(context, self_base, exponent_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_POW - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_PROD - -Kernel( - "aten::prod.int_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& dtype = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - bool keepdim_base = keepdim.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_prod.int_out"); - EXECUTORCH_SCOPE_PROF("native_call_prod.int_out"); - torch::executor::native::prod_int_out(context, self_base, dim_base, keepdim_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - - -Kernel( - "aten::prod.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dtype = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_prod.out"); - EXECUTORCH_SCOPE_PROF("native_call_prod.out"); - torch::executor::native::prod_out(context, self_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_PROD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RAND - -Kernel( - "aten::rand.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& size = *stack[0]; - EValue& out = *stack[1]; - - auto size_list_out = size.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_rand.out"); - EXECUTORCH_SCOPE_PROF("native_call_rand.out"); - torch::executor::native::rand_out(context, size_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RAND - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RANDN - -Kernel( - "aten::randn.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& size = *stack[0]; - EValue& out = *stack[1]; - - auto size_list_out = size.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_randn.out"); - EXECUTORCH_SCOPE_PROF("native_call_randn.out"); - torch::executor::native::randn_out(context, size_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RANDN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RECIPROCAL - -Kernel( - "aten::reciprocal.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reciprocal.out"); - EXECUTORCH_SCOPE_PROF("native_call_reciprocal.out"); - torch::executor::native::reciprocal_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RECIPROCAL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD1D - -Kernel( - "aten::reflection_pad1d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& padding = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto padding_list_out = padding.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reflection_pad1d.out"); - EXECUTORCH_SCOPE_PROF("native_call_reflection_pad1d.out"); - torch::executor::native::reflection_pad1d_out(context, self_base, padding_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD1D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD2D - -Kernel( - "aten::reflection_pad2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& padding = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto padding_list_out = padding.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reflection_pad2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_reflection_pad2d.out"); - torch::executor::native::reflection_pad2d_out(context, self_base, padding_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD2D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD3D - -Kernel( - "aten::reflection_pad3d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& padding = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto padding_list_out = padding.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_reflection_pad3d.out"); - EXECUTORCH_SCOPE_PROF("native_call_reflection_pad3d.out"); - torch::executor::native::reflection_pad3d_out(context, self_base, padding_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REFLECTION_PAD3D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RELU - -Kernel( - "aten::relu.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_relu.out"); - EXECUTORCH_SCOPE_PROF("native_call_relu.out"); - torch::executor::native::relu_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RELU - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REMAINDER - -Kernel( - "aten::remainder.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_remainder.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_remainder.Tensor_out"); - torch::executor::native::remainder_Tensor_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::remainder.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_remainder.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_remainder.Scalar_out"); - torch::executor::native::remainder_Scalar_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REMAINDER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT - -Kernel( - "aten::repeat.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& repeats = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto repeats_list_out = repeats.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_repeat.out"); - EXECUTORCH_SCOPE_PROF("native_call_repeat.out"); - torch::executor::native::repeat_out(context, self_base, repeats_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT_INTERLEAVE - -Kernel( - "aten::repeat_interleave.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& repeats = *stack[0]; - EValue& output_size = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & repeats_base = repeats.to(); - - auto output_size_opt_out = output_size.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_repeat_interleave.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_repeat_interleave.Tensor_out"); - torch::executor::native::repeat_interleave_Tensor_out(context, repeats_base, output_size_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPEAT_INTERLEAVE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD1D - -Kernel( - "aten::replication_pad1d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& padding = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto padding_list_out = padding.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_replication_pad1d.out"); - EXECUTORCH_SCOPE_PROF("native_call_replication_pad1d.out"); - torch::executor::native::replication_pad1d_out(context, self_base, padding_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD1D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD2D - -Kernel( - "aten::replication_pad2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& padding = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto padding_list_out = padding.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_replication_pad2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_replication_pad2d.out"); - torch::executor::native::replication_pad2d_out(context, self_base, padding_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD2D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD3D - -Kernel( - "aten::replication_pad3d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& padding = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto padding_list_out = padding.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_replication_pad3d.out"); - EXECUTORCH_SCOPE_PROF("native_call_replication_pad3d.out"); - torch::executor::native::replication_pad3d_out(context, self_base, padding_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_REPLICATION_PAD3D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROLL - -Kernel( - "aten::roll.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& shifts = *stack[1]; - EValue& dims = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto shifts_list_out = shifts.toIntList(); - - - auto dims_list_out = dims.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_roll.out"); - EXECUTORCH_SCOPE_PROF("native_call_roll.out"); - torch::executor::native::roll_out(context, self_base, shifts_list_out, dims_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ROLL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ROUND - -Kernel( - "aten::round.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_round.out"); - EXECUTORCH_SCOPE_PROF("native_call_round.out"); - torch::executor::native::round_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ROUND - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSQRT - -Kernel( - "aten::rsqrt.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_rsqrt.out"); - EXECUTORCH_SCOPE_PROF("native_call_rsqrt.out"); - torch::executor::native::rsqrt_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RSQRT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_RSUB - -Kernel( - "aten::rsub.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& alpha = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - const torch::executor::Scalar & alpha_base = alpha.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_rsub.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_rsub.Scalar_out"); - torch::executor::native::rsub_scalar_out(context, self_base, other_base, alpha_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_RSUB - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCALAR_TENSOR - -Kernel( - "aten::scalar_tensor.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& s = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Scalar & s_base = s.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scalar_tensor.out"); - EXECUTORCH_SCOPE_PROF("native_call_scalar_tensor.out"); - torch::executor::native::scalar_tensor_out(context, s_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SCALAR_TENSOR - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER - -Kernel( - "aten::scatter.src_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& index = *stack[2]; - EValue& src = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - const torch::executor::Tensor & index_base = index.to(); - const torch::executor::Tensor & src_base = src.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scatter.src_out"); - EXECUTORCH_SCOPE_PROF("native_call_scatter.src_out"); - torch::executor::native::scatter_src_out(context, self_base, dim_base, index_base, src_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - - -Kernel( - "aten::scatter.value_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& index = *stack[2]; - EValue& value = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - const torch::executor::Tensor & index_base = index.to(); - const torch::executor::Scalar & value_base = value.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scatter.value_out"); - EXECUTORCH_SCOPE_PROF("native_call_scatter.value_out"); - torch::executor::native::scatter_value_out(context, self_base, dim_base, index_base, value_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER_ADD - -Kernel( - "aten::scatter_add.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& index = *stack[2]; - EValue& src = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - const torch::executor::Tensor & index_base = index.to(); - const torch::executor::Tensor & src_base = src.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_scatter_add.out"); - EXECUTORCH_SCOPE_PROF("native_call_scatter_add.out"); - torch::executor::native::scatter_add_out(context, self_base, dim_base, index_base, src_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SCATTER_ADD - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_COPY - -Kernel( - "aten::select_copy.int_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& index = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - int64_t index_base = index.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_select_copy.int_out"); - EXECUTORCH_SCOPE_PROF("native_call_select_copy.int_out"); - torch::executor::native::select_copy_int_out(context, self_base, dim_base, index_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_SCATTER - -Kernel( - "aten::select_scatter.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& src = *stack[1]; - EValue& dim = *stack[2]; - EValue& index = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & src_base = src.to(); - int64_t dim_base = dim.to(); - int64_t index_base = index.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_select_scatter.out"); - EXECUTORCH_SCOPE_PROF("native_call_select_scatter.out"); - torch::executor::native::select_scatter_out(context, self_base, src_base, dim_base, index_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SELECT_SCATTER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGMOID - -Kernel( - "aten::sigmoid.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sigmoid.out"); - EXECUTORCH_SCOPE_PROF("native_call_sigmoid.out"); - torch::executor::native::sigmoid_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SIGMOID - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIGN - -Kernel( - "aten::sign.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sign.out"); - EXECUTORCH_SCOPE_PROF("native_call_sign.out"); - torch::executor::native::sign_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SIGN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SIN - -Kernel( - "aten::sin.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sin.out"); - EXECUTORCH_SCOPE_PROF("native_call_sin.out"); - torch::executor::native::sin_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SIN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SINH - -Kernel( - "aten::sinh.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sinh.out"); - EXECUTORCH_SCOPE_PROF("native_call_sinh.out"); - torch::executor::native::sinh_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SINH - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_COPY - -Kernel( - "aten::slice_copy.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& start = *stack[2]; - EValue& end = *stack[3]; - EValue& step = *stack[4]; - EValue& out = *stack[5]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - - auto start_opt_out = start.toOptional(); - - - auto end_opt_out = end.toOptional(); - - int64_t step_base = step.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_slice_copy.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_slice_copy.Tensor_out"); - torch::executor::native::slice_copy_Tensor_out(context, self_base, dim_base, start_opt_out, end_opt_out, step_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_SCATTER - -Kernel( - "aten::slice_scatter.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& self = *stack[0]; - EValue& src = *stack[1]; - EValue& dim = *stack[2]; - EValue& start = *stack[3]; - EValue& end = *stack[4]; - EValue& step = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & src_base = src.to(); - int64_t dim_base = dim.to(); - - auto start_opt_out = start.toOptional(); - - - auto end_opt_out = end.toOptional(); - - int64_t step_base = step.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_slice_scatter.out"); - EXECUTORCH_SCOPE_PROF("native_call_slice_scatter.out"); - torch::executor::native::slice_scatter_out(context, self_base, src_base, dim_base, start_opt_out, end_opt_out, step_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SLICE_SCATTER - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SOFTMAX - -Kernel( - "aten::_softmax.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& half_to_float = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - bool half_to_float_base = half_to_float.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__softmax.out"); - EXECUTORCH_SCOPE_PROF("native_call__softmax.out"); - torch::executor::native::softmax_out(context, self_base, dim_base, half_to_float_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SOFTMAX - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_COPY - -Kernel( - "aten::split_copy.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& split_size = *stack[1]; - EValue& dim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t split_size_base = split_size.to(); - int64_t dim_base = dim.to(); - - auto out_list_out = out.toTensorList(); - - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_split_copy.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_split_copy.Tensor_out"); - torch::executor::native::split_copy_Tensor_out(context, self_base, split_size_base, dim_base, out_list_out); - stack[4] = &out; - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_WITH_SIZES_COPY - -Kernel( - "aten::split_with_sizes_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& split_sizes = *stack[1]; - EValue& dim = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - - auto split_sizes_list_out = split_sizes.toIntList(); - - int64_t dim_base = dim.to(); - - auto out_list_out = out.toTensorList(); - - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_split_with_sizes_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_split_with_sizes_copy.out"); - torch::executor::native::split_with_sizes_copy_out(context, self_base, split_sizes_list_out, dim_base, out_list_out); - stack[4] = &out; - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SPLIT_WITH_SIZES_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQRT - -Kernel( - "aten::sqrt.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sqrt.out"); - EXECUTORCH_SCOPE_PROF("native_call_sqrt.out"); - torch::executor::native::sqrt_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SQRT - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SQUEEZE_COPY - -Kernel( - "aten::squeeze_copy.dim_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_squeeze_copy.dim_out"); - EXECUTORCH_SCOPE_PROF("native_call_squeeze_copy.dim_out"); - torch::executor::native::squeeze_copy_dim_out(context, self_base, dim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - - -Kernel( - "aten::squeeze_copy.dims_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_list_out = dim.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_squeeze_copy.dims_out"); - EXECUTORCH_SCOPE_PROF("native_call_squeeze_copy.dims_out"); - torch::executor::native::squeeze_copy_dims_out(context, self_base, dim_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SQUEEZE_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_STACK - -Kernel( - "aten::stack.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& tensors = *stack[0]; - EValue& dim = *stack[1]; - EValue& out = *stack[2]; - - auto tensors_list_out = tensors.toTensorList(); - - int64_t dim_base = dim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_stack.out"); - EXECUTORCH_SCOPE_PROF("native_call_stack.out"); - torch::executor::native::stack_out(context, tensors_list_out, dim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_STACK - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUB - -Kernel( - "aten::sub.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& alpha = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - const torch::executor::Scalar & alpha_base = alpha.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sub.out"); - EXECUTORCH_SCOPE_PROF("native_call_sub.out"); - torch::executor::native::sub_out(context, self_base, other_base, alpha_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - - -Kernel( - "aten::sub.Scalar_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& alpha = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Scalar & other_base = other.to(); - const torch::executor::Scalar & alpha_base = alpha.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sub.Scalar_out"); - EXECUTORCH_SCOPE_PROF("native_call_sub.Scalar_out"); - torch::executor::native::sub_scalar_out(context, self_base, other_base, alpha_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SUB - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_SUM - -Kernel( - "aten::sum.IntList_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& keepdim = *stack[2]; - EValue& dtype = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional>(); - - bool keepdim_base = keepdim.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_sum.IntList_out"); - EXECUTORCH_SCOPE_PROF("native_call_sum.IntList_out"); - torch::executor::native::sum_dim_out(context, self_base, dim_opt_out, keepdim_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_SUM - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TAN - -Kernel( - "aten::tan.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_tan.out"); - EXECUTORCH_SCOPE_PROF("native_call_tan.out"); - torch::executor::native::tan_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TAN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TANH - -Kernel( - "aten::tanh.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_tanh.out"); - EXECUTORCH_SCOPE_PROF("native_call_tanh.out"); - torch::executor::native::tanh_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TANH - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TOPK - -Kernel( - "aten::topk.values", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& self = *stack[0]; - EValue& k = *stack[1]; - EValue& dim = *stack[2]; - EValue& largest = *stack[3]; - EValue& sorted = *stack[4]; - EValue& values = *stack[5]; - EValue& indices = *stack[6]; - const torch::executor::Tensor & self_base = self.to(); - int64_t k_base = k.to(); - int64_t dim_base = dim.to(); - bool largest_base = largest.to(); - bool sorted_base = sorted.to(); - torch::executor::Tensor & values_base = values.to(); - torch::executor::Tensor & indices_base = indices.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_topk.values"); - EXECUTORCH_SCOPE_PROF("native_call_topk.values"); - torch::executor::native::topk_values(context, self_base, k_base, dim_base, largest_base, sorted_base, values_base, indices_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TOPK - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_COPY - -Kernel( - "aten::_to_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& non_blocking = *stack[1]; - EValue& memory_format = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - bool non_blocking_base = non_blocking.to(); - - auto memory_format_opt_out = memory_format.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__to_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call__to_copy.out"); - torch::executor::native::to_copy_out(context, self_base, non_blocking_base, memory_format_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TO_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TO_DIM_ORDER_COPY - -Kernel( - "dim_order_ops::_to_dim_order_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& non_blocking = *stack[1]; - EValue& dim_order = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - bool non_blocking_base = non_blocking.to(); - - auto dim_order_opt_out = dim_order.toOptional>(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__to_dim_order_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call__to_dim_order_copy.out"); - torch::executor::native::_to_dim_order_copy_out(context, self_base, non_blocking_base, dim_order_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TO_DIM_ORDER_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRANSPOSE_COPY - -Kernel( - "aten::transpose_copy.int_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& self = *stack[0]; - EValue& dim0 = *stack[1]; - EValue& dim1 = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim0_base = dim0.to(); - int64_t dim1_base = dim1.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_transpose_copy.int_out"); - EXECUTORCH_SCOPE_PROF("native_call_transpose_copy.int_out"); - torch::executor::native::transpose_copy_int_out(context, self_base, dim0_base, dim1_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TRANSPOSE_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRIL - -Kernel( - "aten::tril.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& diagonal = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - int64_t diagonal_base = diagonal.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_tril.out"); - EXECUTORCH_SCOPE_PROF("native_call_tril.out"); - torch::executor::native::tril_out(context, self_base, diagonal_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TRIL - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_TRUNC - -Kernel( - "aten::trunc.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_trunc.out"); - EXECUTORCH_SCOPE_PROF("native_call_trunc.out"); - torch::executor::native::trunc_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_TRUNC - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_T_COPY - -Kernel( - "aten::t_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_t_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_t_copy.out"); - torch::executor::native::t_copy_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_T_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNBIND_COPY - -Kernel( - "aten::unbind_copy.int_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - - auto out_list_out = out.toTensorList(); - - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_unbind_copy.int_out"); - EXECUTORCH_SCOPE_PROF("native_call_unbind_copy.int_out"); - torch::executor::native::unbind_copy_int_out(context, self_base, dim_base, out_list_out); - stack[3] = &out; - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UNBIND_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNFOLD_COPY - -Kernel( - "aten::unfold_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dimension = *stack[1]; - EValue& size = *stack[2]; - EValue& step = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dimension_base = dimension.to(); - int64_t size_base = size.to(); - int64_t step_base = step.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_unfold_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_unfold_copy.out"); - torch::executor::native::unfold_copy_out(context, self_base, dimension_base, size_base, step_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UNFOLD_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UNSQUEEZE_COPY - -Kernel( - "aten::unsqueeze_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - int64_t dim_base = dim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_unsqueeze_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_unsqueeze_copy.out"); - torch::executor::native::unsqueeze_copy_out(context, self_base, dim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UNSQUEEZE_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D - -Kernel( - "aten::upsample_bilinear2d.vec_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& input = *stack[0]; - EValue& output_size = *stack[1]; - EValue& align_corners = *stack[2]; - EValue& scale_factors = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & input_base = input.to(); - - auto output_size_opt_out = output_size.toOptional>(); - - bool align_corners_base = align_corners.to(); - - auto scale_factors_opt_out = scale_factors.toOptional>(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_upsample_bilinear2d.vec_out"); - EXECUTORCH_SCOPE_PROF("native_call_upsample_bilinear2d.vec_out"); - torch::executor::native::upsample_bilinear2d_vec_out(context, input_base, output_size_opt_out, align_corners_base, scale_factors_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D_AA - -Kernel( - "aten::_upsample_bilinear2d_aa.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& self = *stack[0]; - EValue& output_size = *stack[1]; - EValue& align_corners = *stack[2]; - EValue& scales_h = *stack[3]; - EValue& scales_w = *stack[4]; - EValue& out = *stack[5]; - const torch::executor::Tensor & self_base = self.to(); - - auto output_size_list_out = output_size.toIntList(); - - bool align_corners_base = align_corners.to(); - - auto scales_h_opt_out = scales_h.toOptional(); - - - auto scales_w_opt_out = scales_w.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call__upsample_bilinear2d_aa.out"); - EXECUTORCH_SCOPE_PROF("native_call__upsample_bilinear2d_aa.out"); - torch::executor::native::_upsample_bilinear2d_aa_out(context, self_base, output_size_list_out, align_corners_base, scales_h_opt_out, scales_w_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_BILINEAR2D_AA - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_NEAREST2D - -Kernel( - "aten::upsample_nearest2d.vec_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& input = *stack[0]; - EValue& output_size = *stack[1]; - EValue& scale_factors = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & input_base = input.to(); - - auto output_size_opt_out = output_size.toOptional>(); - - - auto scale_factors_opt_out = scale_factors.toOptional>(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_upsample_nearest2d.vec_out"); - EXECUTORCH_SCOPE_PROF("native_call_upsample_nearest2d.vec_out"); - torch::executor::native::upsample_nearest2d_vec_out(context, input_base, output_size_opt_out, scale_factors_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_UPSAMPLE_NEAREST2D - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VAR - -Kernel( - "aten::var.correction_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& correction = *stack[2]; - EValue& keepdim = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional>(); - - - auto correction_opt_out = correction.toOptional(); - - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_var.correction_out"); - EXECUTORCH_SCOPE_PROF("native_call_var.correction_out"); - torch::executor::native::var_correction_out(context, self_base, dim_opt_out, correction_opt_out, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - - -Kernel( - "aten::var.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& unbiased = *stack[2]; - EValue& keepdim = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional>(); - - bool unbiased_base = unbiased.to(); - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_var.out"); - EXECUTORCH_SCOPE_PROF("native_call_var.out"); - torch::executor::native::var_out(context, self_base, dim_opt_out, unbiased_base, keepdim_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_VAR - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VAR_MEAN - -Kernel( - "aten::var_mean.correction_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& self = *stack[0]; - EValue& dim = *stack[1]; - EValue& correction = *stack[2]; - EValue& keepdim = *stack[3]; - EValue& out0 = *stack[4]; - EValue& out1 = *stack[5]; - const torch::executor::Tensor & self_base = self.to(); - - auto dim_opt_out = dim.toOptional>(); - - - auto correction_opt_out = correction.toOptional(); - - bool keepdim_base = keepdim.to(); - torch::executor::Tensor & out0_base = out0.to(); - torch::executor::Tensor & out1_base = out1.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_var_mean.correction_out"); - EXECUTORCH_SCOPE_PROF("native_call_var_mean.correction_out"); - torch::executor::native::var_mean_correction_out(context, self_base, dim_opt_out, correction_opt_out, keepdim_base, out0_base, out1_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_VAR_MEAN - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_AS_REAL_COPY - -Kernel( - "aten::view_as_real_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& self = *stack[0]; - EValue& out = *stack[1]; - const torch::executor::Tensor & self_base = self.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_view_as_real_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_view_as_real_copy.out"); - torch::executor::native::view_as_real_copy_out(context, self_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_AS_REAL_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_COPY - -Kernel( - "aten::view_copy.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& size = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - - auto size_list_out = size.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_view_copy.out"); - EXECUTORCH_SCOPE_PROF("native_call_view_copy.out"); - torch::executor::native::view_copy_out(context, self_base, size_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_VIEW_COPY - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_WHERE - -Kernel( - "aten::where.self_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& condition = *stack[0]; - EValue& self = *stack[1]; - EValue& other = *stack[2]; - EValue& out = *stack[3]; - const torch::executor::Tensor & condition_base = condition.to(); - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_where.self_out"); - EXECUTORCH_SCOPE_PROF("native_call_where.self_out"); - torch::executor::native::where_out(context, condition_base, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_WHERE - -#ifdef RTE_ML_EXECUTORCH_OP_PORTABLE_ZEROS - -Kernel( - "aten::zeros.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 3, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)3, stack.size()); - EValue& size = *stack[0]; - EValue& out = *stack[1]; - - auto size_list_out = size.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_zeros.out"); - EXECUTORCH_SCOPE_PROF("native_call_zeros.out"); - torch::executor::native::zeros_out(context, size_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[1]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_PORTABLE_ZEROS - -// ===================================================================== -// QUANTIZED OPERATORS -// ===================================================================== - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_ADD - -Kernel( - "quantized_decomposed::add.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 16, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)16, stack.size()); - EValue& a = *stack[0]; - EValue& a_scale = *stack[1]; - EValue& a_zero_point = *stack[2]; - EValue& a_quant_min = *stack[3]; - EValue& a_quant_max = *stack[4]; - EValue& b = *stack[5]; - EValue& b_scale = *stack[6]; - EValue& b_zero_point = *stack[7]; - EValue& b_quant_min = *stack[8]; - EValue& b_quant_max = *stack[9]; - EValue& out_scale = *stack[10]; - EValue& out_zero_point = *stack[11]; - EValue& out_quant_min = *stack[12]; - EValue& out_quant_max = *stack[13]; - EValue& out = *stack[14]; - const torch::executor::Tensor & a_base = a.to(); - double a_scale_base = a_scale.to(); - int64_t a_zero_point_base = a_zero_point.to(); - int64_t a_quant_min_base = a_quant_min.to(); - int64_t a_quant_max_base = a_quant_max.to(); - const torch::executor::Tensor & b_base = b.to(); - double b_scale_base = b_scale.to(); - int64_t b_zero_point_base = b_zero_point.to(); - int64_t b_quant_min_base = b_quant_min.to(); - int64_t b_quant_max_base = b_quant_max.to(); - double out_scale_base = out_scale.to(); - int64_t out_zero_point_base = out_zero_point.to(); - int64_t out_quant_min_base = out_quant_min.to(); - int64_t out_quant_max_base = out_quant_max.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_add.out"); - EXECUTORCH_SCOPE_PROF("native_call_add.out"); - torch::executor::native::quantized_add_out(context, a_base, a_scale_base, a_zero_point_base, a_quant_min_base, a_quant_max_base, b_base, b_scale_base, b_zero_point_base, b_quant_min_base, b_quant_max_base, out_scale_base, out_zero_point_base, out_quant_min_base, out_quant_max_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[14]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_ADD - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_CHOOSE_QPARAMS - -Kernel( - "quantized_decomposed::choose_qparams.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& input = *stack[0]; - EValue& quant_min = *stack[1]; - EValue& quant_max = *stack[2]; - EValue& eps = *stack[3]; - EValue& dtype = *stack[4]; - EValue& scale_out = *stack[5]; - EValue& zero_point_out = *stack[6]; - const torch::executor::Tensor & input_base = input.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - double eps_base = eps.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & scale_out_base = scale_out.to(); - torch::executor::Tensor & zero_point_out_base = zero_point_out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_choose_qparams.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_choose_qparams.Tensor_out"); - torch::executor::native::choose_qparams_tensor_out(context, input_base, quant_min_base, quant_max_base, eps_base, dtype_base, scale_out_base, zero_point_out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - - -Kernel( - "quantized_decomposed::choose_qparams_per_token_asymmetric.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 5, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)5, stack.size()); - EValue& input = *stack[0]; - EValue& dtype = *stack[1]; - EValue& scale_out = *stack[2]; - EValue& zero_point_out = *stack[3]; - const torch::executor::Tensor & input_base = input.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & scale_out_base = scale_out.to(); - torch::executor::Tensor & zero_point_out_base = zero_point_out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_choose_qparams_per_token_asymmetric.out"); - EXECUTORCH_SCOPE_PROF("native_call_choose_qparams_per_token_asymmetric.out"); - torch::executor::native::choose_qparams_per_token_asymmetric_out(context, input_base, dtype_base, scale_out_base, zero_point_out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); -internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[3]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_CHOOSE_QPARAMS - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_DEQUANTIZE - -Kernel( - "quantized_decomposed::dequantize_per_tensor.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& input = *stack[0]; - EValue& scale = *stack[1]; - EValue& zero_point = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& out_dtype = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & input_base = input.to(); - double scale_base = scale.to(); - int64_t zero_point_base = zero_point.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - - auto out_dtype_opt_out = out_dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_tensor.out"); - EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_tensor.out"); - torch::executor::native::dequantize_per_tensor_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - - -Kernel( - "quantized_decomposed::dequantize_per_tensor.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& input = *stack[0]; - EValue& scale = *stack[1]; - EValue& zero_point = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& out_dtype = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & scale_base = scale.to(); - const torch::executor::Tensor & zero_point_base = zero_point.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - - auto out_dtype_opt_out = out_dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_tensor.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_tensor.Tensor_out"); - torch::executor::native::dequantize_per_tensor_tensor_args_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - - -Kernel( - "quantized_decomposed::dequantize_per_channel.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 10, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)10, stack.size()); - EValue& input = *stack[0]; - EValue& scales = *stack[1]; - EValue& zero_points = *stack[2]; - EValue& axis = *stack[3]; - EValue& quant_min = *stack[4]; - EValue& quant_max = *stack[5]; - EValue& dtype = *stack[6]; - EValue& out_dtype = *stack[7]; - EValue& out = *stack[8]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & scales_base = scales.to(); - - auto zero_points_opt_out = zero_points.toOptional(); - - int64_t axis_base = axis.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - - auto out_dtype_opt_out = out_dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_channel.out"); - EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_channel.out"); - torch::executor::native::dequantize_per_channel_out(context, input_base, scales_base, zero_points_opt_out, axis_base, quant_min_base, quant_max_base, dtype_base, out_dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[8]); - - - } -), - - -Kernel( - "quantized_decomposed::dequantize_per_token.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& input = *stack[0]; - EValue& scales = *stack[1]; - EValue& zero_points = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& output_dtype = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & scales_base = scales.to(); - const torch::executor::Tensor & zero_points_base = zero_points.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::ScalarType output_dtype_base = output_dtype.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_token.out"); - EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_token.out"); - torch::executor::native::dequantize_per_token_out(context, input_base, scales_base, zero_points_base, quant_min_base, quant_max_base, dtype_base, output_dtype_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_DEQUANTIZE - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING - -Kernel( - "quantized_decomposed::embedding_byte.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& weight = *stack[0]; - EValue& weight_scales = *stack[1]; - EValue& weight_zero_points = *stack[2]; - EValue& weight_quant_min = *stack[3]; - EValue& weight_quant_max = *stack[4]; - EValue& indices = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - int64_t weight_quant_min_base = weight_quant_min.to(); - int64_t weight_quant_max_base = weight_quant_max.to(); - const torch::executor::Tensor & indices_base = indices.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_byte.out"); - EXECUTORCH_SCOPE_PROF("native_call_embedding_byte.out"); - torch::executor::native::quantized_embedding_byte_out(context, weight_base, weight_scales_base, weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - - -Kernel( - "quantized_decomposed::embedding_byte.dtype_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& weight = *stack[0]; - EValue& weight_scales = *stack[1]; - EValue& weight_zero_points = *stack[2]; - EValue& weight_quant_min = *stack[3]; - EValue& weight_quant_max = *stack[4]; - EValue& indices = *stack[5]; - EValue& dtype = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - int64_t weight_quant_min_base = weight_quant_min.to(); - int64_t weight_quant_max_base = weight_quant_max.to(); - const torch::executor::Tensor & indices_base = indices.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_byte.dtype_out"); - EXECUTORCH_SCOPE_PROF("native_call_embedding_byte.dtype_out"); - torch::executor::native::quantized_embedding_byte_dtype_out(context, weight_base, weight_scales_base, weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING2B - -Kernel( - "quantized_decomposed::embedding_2bit.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& weight = *stack[0]; - EValue& weight_scales = *stack[1]; - EValue& weight_zero_points = *stack[2]; - EValue& weight_quant_min = *stack[3]; - EValue& weight_quant_max = *stack[4]; - EValue& indices = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - int64_t weight_quant_min_base = weight_quant_min.to(); - int64_t weight_quant_max_base = weight_quant_max.to(); - const torch::executor::Tensor & indices_base = indices.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_2bit.out"); - EXECUTORCH_SCOPE_PROF("native_call_embedding_2bit.out"); - torch::executor::native::quantized_embedding_2bit_out(context, weight_base, weight_scales_base, weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - - -Kernel( - "quantized_decomposed::embedding_2bit.dtype_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& weight = *stack[0]; - EValue& weight_scales = *stack[1]; - EValue& weight_zero_points = *stack[2]; - EValue& weight_quant_min = *stack[3]; - EValue& weight_quant_max = *stack[4]; - EValue& indices = *stack[5]; - EValue& dtype = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - int64_t weight_quant_min_base = weight_quant_min.to(); - int64_t weight_quant_max_base = weight_quant_max.to(); - const torch::executor::Tensor & indices_base = indices.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_2bit.dtype_out"); - EXECUTORCH_SCOPE_PROF("native_call_embedding_2bit.dtype_out"); - torch::executor::native::quantized_embedding_2bit_dtype_out(context, weight_base, weight_scales_base, weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING2B - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING4B - -Kernel( - "quantized_decomposed::embedding_4bit.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& weight = *stack[0]; - EValue& weight_scales = *stack[1]; - EValue& weight_zero_points = *stack[2]; - EValue& weight_quant_min = *stack[3]; - EValue& weight_quant_max = *stack[4]; - EValue& indices = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - int64_t weight_quant_min_base = weight_quant_min.to(); - int64_t weight_quant_max_base = weight_quant_max.to(); - const torch::executor::Tensor & indices_base = indices.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_4bit.out"); - EXECUTORCH_SCOPE_PROF("native_call_embedding_4bit.out"); - torch::executor::native::quantized_embedding_4bit_out(context, weight_base, weight_scales_base, weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - - -Kernel( - "quantized_decomposed::embedding_4bit.dtype_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& weight = *stack[0]; - EValue& weight_scales = *stack[1]; - EValue& weight_zero_points = *stack[2]; - EValue& weight_quant_min = *stack[3]; - EValue& weight_quant_max = *stack[4]; - EValue& indices = *stack[5]; - EValue& dtype = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - int64_t weight_quant_min_base = weight_quant_min.to(); - int64_t weight_quant_max_base = weight_quant_max.to(); - const torch::executor::Tensor & indices_base = indices.to(); - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_embedding_4bit.dtype_out"); - EXECUTORCH_SCOPE_PROF("native_call_embedding_4bit.dtype_out"); - torch::executor::native::quantized_embedding_4bit_dtype_out(context, weight_base, weight_scales_base, weight_zero_points_opt_out, weight_quant_min_base, weight_quant_max_base, indices_base, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_EMBEDDING4B - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_LINEAR - -Kernel( - "quantized_decomposed::mixed_linear.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 7, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)7, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& weight_scales = *stack[2]; - EValue& weight_zero_points = *stack[3]; - EValue& dtype = *stack[4]; - EValue& out = *stack[5]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - - auto dtype_opt_out = dtype.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mixed_linear.out"); - EXECUTORCH_SCOPE_PROF("native_call_mixed_linear.out"); - torch::executor::native::quantized_mixed_linear_out(context, input_base, weight_base, weight_scales_base, weight_zero_points_opt_out, dtype_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[5]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_LINEAR - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_MM - -Kernel( - "quantized_decomposed::mixed_mm.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& weight_scales = *stack[2]; - EValue& weight_zero_points = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weight_base = weight.to(); - const torch::executor::Tensor & weight_scales_base = weight_scales.to(); - - auto weight_zero_points_opt_out = weight_zero_points.toOptional(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_mixed_mm.out"); - EXECUTORCH_SCOPE_PROF("native_call_mixed_mm.out"); - torch::executor::native::quantized_mixed_mm_out(context, input_base, weight_base, weight_scales_base, weight_zero_points_opt_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_MIXED_MM - -#ifdef RTE_ML_EXECUTORCH_OP_QUANTIZED_QUANTIZE - -Kernel( - "quantized_decomposed::quantize_per_channel.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& input = *stack[0]; - EValue& scales = *stack[1]; - EValue& zero_points = *stack[2]; - EValue& axis = *stack[3]; - EValue& quant_min = *stack[4]; - EValue& quant_max = *stack[5]; - EValue& dtype = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & scales_base = scales.to(); - const torch::executor::Tensor & zero_points_base = zero_points.to(); - int64_t axis_base = axis.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_channel.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantize_per_channel.out"); - torch::executor::native::quantize_per_channel_out(context, input_base, scales_base, zero_points_base, axis_base, quant_min_base, quant_max_base, dtype_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - - -Kernel( - "quantized_decomposed::quantize_per_tensor.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& input = *stack[0]; - EValue& scale = *stack[1]; - EValue& zero_point = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & input_base = input.to(); - double scale_base = scale.to(); - int64_t zero_point_base = zero_point.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_tensor.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantize_per_tensor.out"); - torch::executor::native::quantize_per_tensor_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - - -Kernel( - "quantized_decomposed::quantize_per_tensor.Tensor_out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& input = *stack[0]; - EValue& scale = *stack[1]; - EValue& zero_point = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & scale_base = scale.to(); - const torch::executor::Tensor & zero_point_base = zero_point.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_tensor.Tensor_out"); - EXECUTORCH_SCOPE_PROF("native_call_quantize_per_tensor.Tensor_out"); - torch::executor::native::quantize_per_tensor_tensor_args_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - - -Kernel( - "quantized_decomposed::quantize_per_token.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& input = *stack[0]; - EValue& scales = *stack[1]; - EValue& zero_points = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & scales_base = scales.to(); - const torch::executor::Tensor & zero_points_base = zero_points.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_token.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantize_per_token.out"); - torch::executor::native::quantize_per_token_out(context, input_base, scales_base, zero_points_base, quant_min_base, quant_max_base, dtype_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_QUANTIZED_QUANTIZE - -// ===================================================================== -// CORTEX-M OPERATORS -// ===================================================================== - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_DEQUANTIZE_PER_TENSOR - -Kernel( - "cortex_m::dequantize_per_tensor.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& input = *stack[0]; - EValue& scale = *stack[1]; - EValue& zero_point = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & input_base = input.to(); - double scale_base = scale.to(); - int64_t zero_point_base = zero_point.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_dequantize_per_tensor.out"); - EXECUTORCH_SCOPE_PROF("native_call_dequantize_per_tensor.out"); - cortex_m::native::dequantize_per_tensor_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_DEQUANTIZE_PER_TENSOR - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_MAXIMUM - -Kernel( - "cortex_m::maximum.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_maximum.out"); - EXECUTORCH_SCOPE_PROF("native_call_maximum.out"); - cortex_m::native::maximum_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_MAXIMUM - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_MINIMUM - -Kernel( - "cortex_m::minimum.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& self = *stack[0]; - EValue& other = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & self_base = self.to(); - const torch::executor::Tensor & other_base = other.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_minimum.out"); - EXECUTORCH_SCOPE_PROF("native_call_minimum.out"); - cortex_m::native::minimum_out(context, self_base, other_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_MINIMUM - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_PAD - -Kernel( - "cortex_m::pad.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 6, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)6, stack.size()); - EValue& input = *stack[0]; - EValue& pre_pad = *stack[1]; - EValue& post_pad = *stack[2]; - EValue& pad_value = *stack[3]; - EValue& out = *stack[4]; - const torch::executor::Tensor & input_base = input.to(); - - auto pre_pad_list_out = pre_pad.toIntList(); - - - auto post_pad_list_out = post_pad.toIntList(); - - int64_t pad_value_base = pad_value.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_pad.out"); - EXECUTORCH_SCOPE_PROF("native_call_pad.out"); - cortex_m::native::pad_out(context, input_base, pre_pad_list_out, post_pad_list_out, pad_value_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[4]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_PAD - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_ADD - -Kernel( - "cortex_m::quantized_add.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 15, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)15, stack.size()); - EValue& self = *stack[0]; - EValue& self_zero_point = *stack[1]; - EValue& self_multiplier = *stack[2]; - EValue& self_shift = *stack[3]; - EValue& other = *stack[4]; - EValue& other_zero_point = *stack[5]; - EValue& other_multiplier = *stack[6]; - EValue& other_shift = *stack[7]; - EValue& output_zero_point = *stack[8]; - EValue& output_multiplier = *stack[9]; - EValue& output_shift = *stack[10]; - EValue& activation_min = *stack[11]; - EValue& activation_max = *stack[12]; - EValue& out = *stack[13]; - const torch::executor::Tensor & self_base = self.to(); - int64_t self_zero_point_base = self_zero_point.to(); - int64_t self_multiplier_base = self_multiplier.to(); - int64_t self_shift_base = self_shift.to(); - const torch::executor::Tensor & other_base = other.to(); - int64_t other_zero_point_base = other_zero_point.to(); - int64_t other_multiplier_base = other_multiplier.to(); - int64_t other_shift_base = other_shift.to(); - int64_t output_zero_point_base = output_zero_point.to(); - int64_t output_multiplier_base = output_multiplier.to(); - int64_t output_shift_base = output_shift.to(); - int64_t activation_min_base = activation_min.to(); - int64_t activation_max_base = activation_max.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_add.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_add.out"); - cortex_m::native::quantized_add_out(context, self_base, self_zero_point_base, self_multiplier_base, self_shift_base, other_base, other_zero_point_base, other_multiplier_base, other_shift_base, output_zero_point_base, output_multiplier_base, output_shift_base, activation_min_base, activation_max_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[13]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_ADD - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_AVG_POOL2D - -Kernel( - "cortex_m::quantized_avg_pool2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& input = *stack[0]; - EValue& kernel_size = *stack[1]; - EValue& stride = *stack[2]; - EValue& padding = *stack[3]; - EValue& zero_point = *stack[4]; - EValue& multiplier = *stack[5]; - EValue& shift = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & input_base = input.to(); - - auto kernel_size_list_out = kernel_size.toIntList(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - int64_t zero_point_base = zero_point.to(); - int64_t multiplier_base = multiplier.to(); - int64_t shift_base = shift.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_avg_pool2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_avg_pool2d.out"); - cortex_m::native::quantized_avg_pool2d_out(context, input_base, kernel_size_list_out, stride_list_out, padding_list_out, zero_point_base, multiplier_base, shift_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_AVG_POOL2D - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_BATCH_MATMUL - -Kernel( - "cortex_m::quantized_batch_matmul.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& lhs = *stack[0]; - EValue& lhs_zero_point = *stack[1]; - EValue& rhs_transposed = *stack[2]; - EValue& rhs_zero_point = *stack[3]; - EValue& output_zero_point = *stack[4]; - EValue& output_multiplier = *stack[5]; - EValue& output_shift = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & lhs_base = lhs.to(); - int64_t lhs_zero_point_base = lhs_zero_point.to(); - const torch::executor::Tensor & rhs_transposed_base = rhs_transposed.to(); - int64_t rhs_zero_point_base = rhs_zero_point.to(); - int64_t output_zero_point_base = output_zero_point.to(); - int64_t output_multiplier_base = output_multiplier.to(); - int64_t output_shift_base = output_shift.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_batch_matmul.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_batch_matmul.out"); - cortex_m::native::quantized_batch_matmul_out(context, lhs_base, lhs_zero_point_base, rhs_transposed_base, rhs_zero_point_base, output_zero_point_base, output_multiplier_base, output_shift_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_BATCH_MATMUL - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_CONV2D - -Kernel( - "cortex_m::quantized_conv2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 14, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)14, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& stride = *stack[3]; - EValue& padding = *stack[4]; - EValue& dilation = *stack[5]; - EValue& input_offset = *stack[6]; - EValue& output_offset = *stack[7]; - EValue& requantize_multipliers = *stack[8]; - EValue& requantize_shifts = *stack[9]; - EValue& activation_min = *stack[10]; - EValue& activation_max = *stack[11]; - EValue& out = *stack[12]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weight_base = weight.to(); - - auto bias_opt_out = bias.toOptional(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - int64_t input_offset_base = input_offset.to(); - int64_t output_offset_base = output_offset.to(); - const torch::executor::Tensor & requantize_multipliers_base = requantize_multipliers.to(); - const torch::executor::Tensor & requantize_shifts_base = requantize_shifts.to(); - int64_t activation_min_base = activation_min.to(); - int64_t activation_max_base = activation_max.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_conv2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_conv2d.out"); - cortex_m::native::quantized_conv2d_out(context, input_base, weight_base, bias_opt_out, stride_list_out, padding_list_out, dilation_list_out, input_offset_base, output_offset_base, requantize_multipliers_base, requantize_shifts_base, activation_min_base, activation_max_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[12]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_CONV2D - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_DEPTHWISE_CONV2D - -Kernel( - "cortex_m::quantized_depthwise_conv2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 15, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)15, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& stride = *stack[3]; - EValue& padding = *stack[4]; - EValue& dilation = *stack[5]; - EValue& depth_multiplier = *stack[6]; - EValue& input_offset = *stack[7]; - EValue& output_offset = *stack[8]; - EValue& requantize_multipliers = *stack[9]; - EValue& requantize_shifts = *stack[10]; - EValue& activation_min = *stack[11]; - EValue& activation_max = *stack[12]; - EValue& out = *stack[13]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weight_base = weight.to(); - - auto bias_opt_out = bias.toOptional(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - int64_t depth_multiplier_base = depth_multiplier.to(); - int64_t input_offset_base = input_offset.to(); - int64_t output_offset_base = output_offset.to(); - const torch::executor::Tensor & requantize_multipliers_base = requantize_multipliers.to(); - const torch::executor::Tensor & requantize_shifts_base = requantize_shifts.to(); - int64_t activation_min_base = activation_min.to(); - int64_t activation_max_base = activation_max.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_depthwise_conv2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_depthwise_conv2d.out"); - cortex_m::native::quantized_depthwise_conv2d_out(context, input_base, weight_base, bias_opt_out, stride_list_out, padding_list_out, dilation_list_out, depth_multiplier_base, input_offset_base, output_offset_base, requantize_multipliers_base, requantize_shifts_base, activation_min_base, activation_max_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[13]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_DEPTHWISE_CONV2D - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_LINEAR - -Kernel( - "cortex_m::quantized_linear.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 13, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)13, stack.size()); - EValue& input = *stack[0]; - EValue& weights = *stack[1]; - EValue& bias = *stack[2]; - EValue& kernel_sum = *stack[3]; - EValue& input_offset = *stack[4]; - EValue& filter_offset = *stack[5]; - EValue& output_offset = *stack[6]; - EValue& requantize_multipliers = *stack[7]; - EValue& requantize_shifts = *stack[8]; - EValue& activation_max = *stack[9]; - EValue& activation_min = *stack[10]; - EValue& out = *stack[11]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weights_base = weights.to(); - - auto bias_opt_out = bias.toOptional(); - - - auto kernel_sum_opt_out = kernel_sum.toOptional(); - - int64_t input_offset_base = input_offset.to(); - int64_t filter_offset_base = filter_offset.to(); - int64_t output_offset_base = output_offset.to(); - - auto requantize_multipliers_list_out = requantize_multipliers.toIntList(); - - - auto requantize_shifts_list_out = requantize_shifts.toIntList(); - - int64_t activation_max_base = activation_max.to(); - int64_t activation_min_base = activation_min.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_linear.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_linear.out"); - cortex_m::native::quantized_linear_out(context, input_base, weights_base, bias_opt_out, kernel_sum_opt_out, input_offset_base, filter_offset_base, output_offset_base, requantize_multipliers_list_out, requantize_shifts_list_out, activation_max_base, activation_min_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[11]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_LINEAR - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MAX_POOL2D - -Kernel( - "cortex_m::quantized_max_pool2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 12, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)12, stack.size()); - EValue& input = *stack[0]; - EValue& kernel_size = *stack[1]; - EValue& stride = *stack[2]; - EValue& padding = *stack[3]; - EValue& dilation = *stack[4]; - EValue& ceil_mode = *stack[5]; - EValue& input_zero_point = *stack[6]; - EValue& output_zero_point = *stack[7]; - EValue& activation_min = *stack[8]; - EValue& activation_max = *stack[9]; - EValue& out = *stack[10]; - const torch::executor::Tensor & input_base = input.to(); - - auto kernel_size_list_out = kernel_size.toIntList(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - bool ceil_mode_base = ceil_mode.to(); - int64_t input_zero_point_base = input_zero_point.to(); - int64_t output_zero_point_base = output_zero_point.to(); - int64_t activation_min_base = activation_min.to(); - int64_t activation_max_base = activation_max.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_max_pool2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_max_pool2d.out"); - cortex_m::native::quantized_max_pool2d_out(context, input_base, kernel_size_list_out, stride_list_out, padding_list_out, dilation_list_out, ceil_mode_base, input_zero_point_base, output_zero_point_base, activation_min_base, activation_max_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[10]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MAX_POOL2D - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MUL - -Kernel( - "cortex_m::quantized_mul.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& self = *stack[0]; - EValue& self_zero_point = *stack[1]; - EValue& other = *stack[2]; - EValue& other_zero_point = *stack[3]; - EValue& output_zero_point = *stack[4]; - EValue& output_multiplier = *stack[5]; - EValue& output_shift = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & self_base = self.to(); - int64_t self_zero_point_base = self_zero_point.to(); - const torch::executor::Tensor & other_base = other.to(); - int64_t other_zero_point_base = other_zero_point.to(); - int64_t output_zero_point_base = output_zero_point.to(); - int64_t output_multiplier_base = output_multiplier.to(); - int64_t output_shift_base = output_shift.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_mul.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_mul.out"); - cortex_m::native::quantized_mul_out(context, self_base, self_zero_point_base, other_base, other_zero_point_base, output_zero_point_base, output_multiplier_base, output_shift_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_MUL - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_TRANSPOSE_CONV2D - -Kernel( - "cortex_m::quantized_transpose_conv2d.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 15, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)15, stack.size()); - EValue& input = *stack[0]; - EValue& weight = *stack[1]; - EValue& bias = *stack[2]; - EValue& stride = *stack[3]; - EValue& padding = *stack[4]; - EValue& output_padding = *stack[5]; - EValue& dilation = *stack[6]; - EValue& input_offset = *stack[7]; - EValue& output_offset = *stack[8]; - EValue& requantize_multipliers = *stack[9]; - EValue& requantize_shifts = *stack[10]; - EValue& activation_min = *stack[11]; - EValue& activation_max = *stack[12]; - EValue& out = *stack[13]; - const torch::executor::Tensor & input_base = input.to(); - const torch::executor::Tensor & weight_base = weight.to(); - - auto bias_opt_out = bias.toOptional(); - - - auto stride_list_out = stride.toIntList(); - - - auto padding_list_out = padding.toIntList(); - - - auto output_padding_list_out = output_padding.toIntList(); - - - auto dilation_list_out = dilation.toIntList(); - - int64_t input_offset_base = input_offset.to(); - int64_t output_offset_base = output_offset.to(); - const torch::executor::Tensor & requantize_multipliers_base = requantize_multipliers.to(); - const torch::executor::Tensor & requantize_shifts_base = requantize_shifts.to(); - int64_t activation_min_base = activation_min.to(); - int64_t activation_max_base = activation_max.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantized_transpose_conv2d.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantized_transpose_conv2d.out"); - cortex_m::native::quantized_transpose_conv2d_out(context, input_base, weight_base, bias_opt_out, stride_list_out, padding_list_out, output_padding_list_out, dilation_list_out, input_offset_base, output_offset_base, requantize_multipliers_base, requantize_shifts_base, activation_min_base, activation_max_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[13]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZED_TRANSPOSE_CONV2D - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZE_PER_TENSOR - -Kernel( - "cortex_m::quantize_per_tensor.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 8, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)8, stack.size()); - EValue& input = *stack[0]; - EValue& scale = *stack[1]; - EValue& zero_point = *stack[2]; - EValue& quant_min = *stack[3]; - EValue& quant_max = *stack[4]; - EValue& dtype = *stack[5]; - EValue& out = *stack[6]; - const torch::executor::Tensor & input_base = input.to(); - double scale_base = scale.to(); - int64_t zero_point_base = zero_point.to(); - int64_t quant_min_base = quant_min.to(); - int64_t quant_max_base = quant_max.to(); - torch::executor::ScalarType dtype_base = dtype.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_quantize_per_tensor.out"); - EXECUTORCH_SCOPE_PROF("native_call_quantize_per_tensor.out"); - cortex_m::native::quantize_per_tensor_out(context, input_base, scale_base, zero_point_base, quant_min_base, quant_max_base, dtype_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[6]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_QUANTIZE_PER_TENSOR - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_SOFTMAX - -Kernel( - "cortex_m::softmax.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 9, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)9, stack.size()); - EValue& input = *stack[0]; - EValue& dim = *stack[1]; - EValue& input_zero_point = *stack[2]; - EValue& output_zero_point = *stack[3]; - EValue& input_multiplier = *stack[4]; - EValue& input_shift = *stack[5]; - EValue& diff_min = *stack[6]; - EValue& out = *stack[7]; - const torch::executor::Tensor & input_base = input.to(); - int64_t dim_base = dim.to(); - int64_t input_zero_point_base = input_zero_point.to(); - int64_t output_zero_point_base = output_zero_point.to(); - int64_t input_multiplier_base = input_multiplier.to(); - int64_t input_shift_base = input_shift.to(); - int64_t diff_min_base = diff_min.to(); - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_softmax.out"); - EXECUTORCH_SCOPE_PROF("native_call_softmax.out"); - cortex_m::native::softmax_out(context, input_base, dim_base, input_zero_point_base, output_zero_point_base, input_multiplier_base, input_shift_base, diff_min_base, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[7]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_SOFTMAX - -#ifdef RTE_ML_EXECUTORCH_OP_CORTEX_M_TRANSPOSE - -Kernel( - "cortex_m::transpose.out", - [](torch::executor::KernelRuntimeContext & context, Span stack) { - ET_KERNEL_CHECK_MSG(context, stack.size() == 4, InvalidProgram, /*void*/, "Expected %" ET_PRIsize_t "args received %" ET_PRIsize_t, (size_t)4, stack.size()); - EValue& input = *stack[0]; - EValue& perm = *stack[1]; - EValue& out = *stack[2]; - const torch::executor::Tensor & input_base = input.to(); - - auto perm_list_out = perm.toIntList(); - - torch::executor::Tensor & out_base = out.to(); - - - internal::EventTracerProfileOpScope event_tracer_op_scope(context.internal_event_tracer(), "native_call_transpose.out"); - EXECUTORCH_SCOPE_PROF("native_call_transpose.out"); - cortex_m::native::transpose_out(context, input_base, perm_list_out, out_base); - - internal::event_tracer_log_evalue(context.internal_event_tracer(), *stack[2]); - - - } -), - -#endif // RTE_ML_EXECUTORCH_OP_CORTEX_M_TRANSPOSE - -// Sentinel to ensure the array has at least one element -// (Required because all operators might be #ifdef'd out) - Kernel(nullptr, nullptr) -}; - -// Calculate the number of kernels (excluding the sentinel) -static constexpr size_t num_kernels = sizeof(kernels_to_register) / sizeof(Kernel) - 1; - -// Explicitly convert to Span, so that the API can take an empty C array of Kernels. -static KernelSpan kernel_span( - kernels_to_register, - kernels_to_register + num_kernels); - -// Return value not used. Keep the static variable assignment to register -// kernels in static initialization time. -static auto success_with_kernel_reg = (num_kernels > 0) ? register_kernels(kernel_span) : Error::Ok; - -} // namespace diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_options_map.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_options_map.h deleted file mode 100644 index f0c6a68..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/backend/backend_options_map.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include - -#include - -namespace executorch { -namespace runtime { - -/** - * Maps backend IDs to their load-time options. - * - * This class is used to provide per-delegate configuration at Module::load() - * time. Users can set options for multiple backends, and the runtime will - * route the appropriate options to each backend during initialization. - * - * Example usage: - * @code - * BackendOptions<4> coreml_opts; - * coreml_opts.set_option("compute_unit", "cpu_and_gpu"); - * - * LoadBackendOptionsMap map; - * map.set_options("CoreMLBackend", coreml_opts.view()); - * - * // Later, during backend init: - * auto opts = map.get_options("CoreMLBackend"); - * @endcode - * - * Note: This class does NOT take ownership of the option spans. The caller - * must ensure that the BackendOptions objects outlive the LoadBackendOptionsMap - * and any loaded models that use it. - */ -class LoadBackendOptionsMap final { - public: - /** - * Default constructor - creates an empty map. - */ - LoadBackendOptionsMap() : size_(0) { - for (size_t i = 0; i < kMaxBackends; ++i) { - entries_[i].backend_id[0] = '\0'; - } - } - - /** - * Sets options for a specific backend. - * - * If options for the given backend_id already exist, they will be replaced. - * - * @param backend_id The backend identifier (e.g., "CoreMLBackend", - * "XNNPACKBackend"). Must not be null or empty. - * @param options Span of BackendOption to associate with this backend. - * The span's underlying data must outlive this map and any - * models loaded with it. - * @return Error::Ok on success. - * Error::InvalidArgument if backend_id is null/empty or max backends - * exceeded. - */ - Error set_options(const char* backend_id, Span options) { - if (backend_id == nullptr || backend_id[0] == '\0') { - return Error::InvalidArgument; - } - - return set_options_impl(backend_id, options); - } - - /** - * Sets options from a backend options builder. - * - * This convenience overload accepts any builder type that provides - * backend_id() and view() methods, allowing simpler usage: - * - * @code - * ExampleBackendOptions opts; - * opts.setNumThreads(4).setEnableOptimization(true); - * map.set_options(opts); - * @endcode - * - * @param builder A backend options builder with backend_id() and view() - * methods. - * @return Error::Ok on success, Error::InvalidArgument on failure. - */ - template - Error set_options(Builder& builder) { - return set_options_impl(builder.backend_id(), builder.view()); - } - - private: - Error set_options_impl(const char* backend_id, Span options) { - // Check if backend already exists and update it - for (size_t i = 0; i < size_; ++i) { - if (std::strcmp(entries_[i].backend_id, backend_id) == 0) { - entries_[i].options = options; - return Error::Ok; - } - } - - // Add new entry if space available - if (size_ >= kMaxBackends) { - return Error::InvalidArgument; - } - - const size_t id_len = std::strlen(backend_id); - if (id_len >= kMaxBackendIdLength) { - return Error::InvalidArgument; - } - std::memcpy(entries_[size_].backend_id, backend_id, id_len); - entries_[size_].backend_id[id_len] = '\0'; - entries_[size_].options = options; - ++size_; - - return Error::Ok; - } - - public: - /** - * Gets options for a specific backend. - * - * @param backend_id The backend identifier to look up. - * @return Span of options for this backend, or an empty span if the backend - * has no options configured or backend_id is null. - */ - Span get_options(const char* backend_id) const { - if (backend_id == nullptr) { - return Span(nullptr, static_cast(0)); - } - - for (size_t i = 0; i < size_; ++i) { - if (std::strcmp(entries_[i].backend_id, backend_id) == 0) { - return Span( - entries_[i].options.data(), entries_[i].options.size()); - } - } - - return Span(nullptr, static_cast(0)); - } - - /** - * Checks if options have been configured for a specific backend. - * - * @param backend_id The backend identifier to check. - * @return true if options are set for this backend, false otherwise. - */ - bool has_options(const char* backend_id) const { - if (backend_id == nullptr) { - return false; - } - - for (size_t i = 0; i < size_; ++i) { - if (std::strcmp(entries_[i].backend_id, backend_id) == 0) { - return true; - } - } - - return false; - } - - /** - * Returns the number of backends with configured options. - */ - size_t size() const { - return size_; - } - - /** - * Non-owning view of a single (backend_id, options) entry, returned by - * entry_at(). The pointer / span are valid until the map is mutated or - * destroyed. - */ - struct EntryView { - const char* backend_id = nullptr; - Span options; - }; - - /** - * Returns the (backend_id, options) entry at the given index for - * enumeration over the map's contents. - * - * @param index The entry index. Must be < size(); behavior is undefined - * otherwise. Use this together with size() to walk every entry. - * @return EntryView referencing the entry's backend_id and options. The - * view is valid until the next mutation of, or destruction of, this - * map. - * - * Example: - * @code - * for (size_t i = 0; i < map.size(); ++i) { - * const auto entry = map.entry_at(i); - * // use entry.backend_id and entry.options ... - * } - * @endcode - */ - EntryView entry_at(size_t index) const { - ET_DCHECK_MSG( - index < size_, - "entry_at index %zu out of bounds (size=%zu)", - index, - size_); - return EntryView{ - entries_[index].backend_id, - Span( - entries_[index].options.data(), entries_[index].options.size())}; - } - - private: - static constexpr size_t kMaxBackends = 8; - static constexpr size_t kMaxBackendIdLength = 64; - - struct Entry { - char backend_id[kMaxBackendIdLength]; - Span options; - }; - - Entry entries_[kMaxBackends]; - size_t size_; -}; - -} // namespace runtime -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.cpp deleted file mode 100644 index 91b3257..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include - -namespace executorch { -namespace runtime { - -DeviceAllocatorRegistry& DeviceAllocatorRegistry::instance() { - static DeviceAllocatorRegistry registry; - return registry; -} - -void DeviceAllocatorRegistry::register_allocator(DeviceAllocator* alloc) { - ET_CHECK_MSG(alloc != nullptr, "Cannot register a null allocator"); - auto type = alloc->device_type(); - auto index = static_cast(type); - ET_CHECK_MSG( - index < etensor::kNumDeviceTypes, - "Invalid device type: %d", - static_cast(type)); - ET_CHECK_MSG( - allocators_[index] == nullptr, - "Allocator already registered for device type: %d", - static_cast(type)); - allocators_[index] = alloc; -} - -DeviceAllocator* DeviceAllocatorRegistry::get_allocator( - etensor::DeviceType type) { - auto index = static_cast(type); - if (index >= etensor::kNumDeviceTypes) { - return nullptr; - } - return allocators_[index]; -} - -// Convenience free functions - -void register_device_allocator(DeviceAllocator* alloc) { - DeviceAllocatorRegistry::instance().register_allocator(alloc); -} - -DeviceAllocator* get_device_allocator(etensor::DeviceType type) { - return DeviceAllocatorRegistry::instance().get_allocator(type); -} - -} // namespace runtime -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.h deleted file mode 100644 index 259bdb9..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_allocator.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -namespace executorch { -namespace runtime { - -/** - * Abstract interface for device-specific memory allocation. - * - * Each device type (CUDA, etc.) provides a concrete implementation - * that handles memory allocation on that device. Implementations are - * expected to be singletons with static lifetime, registered via - * DeviceAllocatorRegistry. - */ -class DeviceAllocator { - public: - /** - * Default alignment of memory returned by allocate(). Reuses - * MemoryAllocator::kDefaultAlignment so host- and device-side allocations - * share the same baseline contract. Backends whose underlying device APIs - * already provide stronger guarantees (e.g. cudaMalloc returns 256-byte - * aligned pointers) will trivially satisfy this. - */ - static constexpr size_t kDefaultAlignment = - MemoryAllocator::kDefaultAlignment; - - virtual ~DeviceAllocator() = default; - /** - * Allocate device memory. - * - * @param nbytes Number of bytes to allocate. - * @param index The device index. - * @param alignment Minimum alignment of the returned pointer in bytes. - * Must be a power of 2. Defaults to kDefaultAlignment. - * @return A Result containing the device pointer on success, or an error. - */ - virtual Result allocate( - size_t nbytes, - etensor::DeviceIndex index, - size_t alignment = kDefaultAlignment) = 0; - - /** - * Deallocate device memory previously allocated via allocate(). - * - * @param ptr Pointer to the memory to deallocate. - * @param index The device index. - */ - virtual void deallocate(void* ptr, etensor::DeviceIndex index) = 0; - - /** - * Copy data from host memory to device memory. - * - * @param dst Destination pointer (device memory). - * @param src Source pointer (host memory). - * @param nbytes Number of bytes to copy. - * @param index The device index. - * @return Error::Ok on success, or an appropriate error code on failure. - */ - virtual Error copy_host_to_device( - void* dst, - const void* src, - size_t nbytes, - etensor::DeviceIndex index) = 0; - - /** - * Copy data from device memory to host memory. - * - * @param dst Destination pointer (host memory). - * @param src Source pointer (device memory). - * @param nbytes Number of bytes to copy. - * @param index The device index. - * @return Error::Ok on success, or an appropriate error code on failure. - */ - virtual Error copy_device_to_host( - void* dst, - const void* src, - size_t nbytes, - etensor::DeviceIndex index) = 0; - - /** - * Returns the device type this allocator handles. - */ - virtual etensor::DeviceType device_type() const = 0; -}; - -/** - * Registry for device allocators. - * - * Provides a global mapping from DeviceType to DeviceAllocator instances. - * Device allocators register themselves at static initialization time, - * and the runtime queries the registry to find the appropriate allocator - * for a given device type. - * - * Threading contract: - * - Registration is expected to happen once per device type during static - * initialization (single-threaded). The registry itself does not perform - * any locking around register_allocator()/get_allocator(), and concurrent - * registration is not supported. - * - After registration, get_allocator() is safe to call concurrently from - * multiple threads because the underlying array is never mutated again. - * - The DeviceAllocator implementation is responsible for its own - * thread-safety. When multiple Programs are loaded concurrently and each - * needs device memory, the allocator must serialize access to any shared - * state internally (similar to how XNNPACK's weight cache guards its - * internal state). The registry does not provide any synchronization on - * behalf of the allocator. - */ -class DeviceAllocatorRegistry { - public: - /** - * Returns the singleton instance of the registry. - */ - static DeviceAllocatorRegistry& instance(); - - /** - * Register an allocator. The device type is taken from - * alloc->device_type(). Each device type may only be registered once; - * attempting to register a second allocator for the same device type - * will abort. - * - * Not thread-safe. Expected to be called during static initialization. - * - * @param alloc Pointer to the allocator (must have static lifetime). - */ - void register_allocator(DeviceAllocator* alloc); - - /** - * Get the allocator for a specific device type. - * - * Safe to call concurrently with other get_allocator() calls. - * - * @param type The device type. - * @return Pointer to the allocator, or nullptr if not registered. - */ - DeviceAllocator* get_allocator(etensor::DeviceType type); - - private: - DeviceAllocatorRegistry() = default; - - // Singletons must not be copied or moved; instance() returns a reference, - // and silently shallow-copying the registry would lead to confusing bugs - // where modifications to the copy don't affect the real singleton. - DeviceAllocatorRegistry(const DeviceAllocatorRegistry&) = delete; - DeviceAllocatorRegistry& operator=(const DeviceAllocatorRegistry&) = delete; - DeviceAllocatorRegistry(DeviceAllocatorRegistry&&) = delete; - DeviceAllocatorRegistry& operator=(DeviceAllocatorRegistry&&) = delete; - - // Fixed-size array indexed by device type. This avoids dynamic allocation - // and is suitable for embedded environments. - DeviceAllocator* allocators_[etensor::kNumDeviceTypes] = {}; -}; - -// Convenience free functions - -/** - * Register a device allocator. The device type is taken from - * alloc->device_type(). See DeviceAllocatorRegistry::register_allocator() - * for the threading contract. - * - * @param alloc Pointer to the allocator (must have static lifetime). - */ -void register_device_allocator(DeviceAllocator* alloc); - -/** - * Get the device allocator for a specific device type. - * - * @param type The device type. - * @return Pointer to the allocator, or nullptr if not registered. - */ -DeviceAllocator* get_device_allocator(etensor::DeviceType type); - -} // namespace runtime -} // namespace executorch - -namespace torch { -namespace executor { -// TODO(T197294990): Remove these deprecated aliases once all users have moved -// to the new `::executorch` namespaces. -using ::executorch::runtime::DeviceAllocator; -using ::executorch::runtime::DeviceAllocatorRegistry; -using ::executorch::runtime::get_device_allocator; -using ::executorch::runtime::register_device_allocator; -} // namespace executor -} // namespace torch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.cpp deleted file mode 100644 index 26faba3..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -namespace executorch::runtime { - -Result DeviceMemoryBuffer::create( - size_t size, - etensor::DeviceType type, - etensor::DeviceIndex index, - size_t alignment) { - DeviceAllocator* allocator = get_device_allocator(type); - if (allocator == nullptr) { - ET_LOG( - Error, - "No device allocator registered for device type %d", - static_cast(type)); - return Error::NotFound; - } - - auto result = allocator->allocate(size, index, alignment); - if (!result.ok()) { - return result.error(); - } - - return DeviceMemoryBuffer(result.get(), size, allocator, index); -} - -} // namespace executorch::runtime diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.h deleted file mode 100644 index 929460c..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/device_memory_buffer.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -namespace executorch::runtime { - -/** - * RAII wrapper that owns a single device memory allocation. - * - * On destruction, calls DeviceAllocator::deallocate() to free the memory. - * This mirrors the role of std::vector for CPU planned buffers, - * but for device memory (CUDA, etc.). - * - * Move-only: cannot be copied, but can be moved to transfer ownership. - */ -class DeviceMemoryBuffer final { - public: - /** - * Creates a DeviceMemoryBuffer by allocating device memory. - * - * Looks up the DeviceAllocator for the given device type via the - * DeviceAllocatorRegistry. If no allocator is registered for the type, - * returns Error::NotFound. - * - * @param size Number of bytes to allocate. - * @param type The device type (e.g., CUDA). - * @param index The device index (e.g., 0 for cuda:0). - * @param alignment Minimum alignment of the returned pointer in bytes. - * Must be a power of 2. Defaults to DeviceAllocator::kDefaultAlignment. - * @return A Result containing the DeviceMemoryBuffer on success, or an error. - */ - static Result create( - size_t size, - etensor::DeviceType type, - etensor::DeviceIndex index = 0, - size_t alignment = DeviceAllocator::kDefaultAlignment); - - DeviceMemoryBuffer() = default; - - ~DeviceMemoryBuffer() { - if (ptr_ != nullptr && allocator_ != nullptr) { - allocator_->deallocate(ptr_, device_index_); - } - } - - // Move constructor: transfer ownership. - DeviceMemoryBuffer(DeviceMemoryBuffer&& other) noexcept - : ptr_(other.ptr_), - size_(other.size_), - allocator_(other.allocator_), - device_index_(other.device_index_) { - other.ptr_ = nullptr; - other.size_ = 0; - other.allocator_ = nullptr; - } - - // Move assignment: release current, take ownership. - DeviceMemoryBuffer& operator=(DeviceMemoryBuffer&& other) noexcept { - if (this != &other) { - if (ptr_ != nullptr && allocator_ != nullptr) { - allocator_->deallocate(ptr_, device_index_); - } - ptr_ = other.ptr_; - size_ = other.size_; - allocator_ = other.allocator_; - device_index_ = other.device_index_; - other.ptr_ = nullptr; - other.size_ = 0; - other.allocator_ = nullptr; - } - return *this; - } - - // Non-copyable. - DeviceMemoryBuffer(const DeviceMemoryBuffer&) = delete; - DeviceMemoryBuffer& operator=(const DeviceMemoryBuffer&) = delete; - - /// Returns the device pointer, or nullptr if empty/moved-from. - void* data() const { - return ptr_; - } - - /// Returns the size in bytes of the allocation. - size_t size() const { - return size_; - } - - /** - * Returns a Span wrapping the device pointer. - * - * This is intended for use with HierarchicalAllocator, which only performs - * pointer arithmetic on the span data and never dereferences it. Device - * pointers are valid for pointer arithmetic from the CPU side. - */ - Span as_span() const { - return {static_cast(ptr_), size_}; - } - - private: - DeviceMemoryBuffer( - void* ptr, - size_t size, - DeviceAllocator* allocator, - etensor::DeviceIndex device_index) - : ptr_(ptr), - size_(size), - allocator_(allocator), - device_index_(device_index) {} - - void* ptr_ = nullptr; - size_t size_ = 0; - DeviceAllocator* allocator_ = nullptr; - etensor::DeviceIndex device_index_ = 0; -}; - -} // namespace executorch::runtime diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/version.h.in b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/version.h.in deleted file mode 100644 index 4b19f35..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/core/version.h.in +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * @file - * ExecuTorch version information. - * - * This file is auto-generated by CMake from version.h.in. - * Do not edit directly. - */ - -#pragma once - -/// ExecuTorch major version number. -#define ET_VERSION_MAJOR @ET_VERSION_MAJOR@ - -/// ExecuTorch minor version number. -#define ET_VERSION_MINOR @ET_VERSION_MINOR@ - -/// ExecuTorch patch version number. -#define ET_VERSION_PATCH @ET_VERSION_PATCH@ - -/// ExecuTorch version string (e.g., "1.2.0"). -#define ET_VERSION "@ET_VERSION_MAJOR@.@ET_VERSION_MINOR@.@ET_VERSION_PATCH@" - -/** - * ExecuTorch version as an integer. - * Format: (MAJOR << 16) | (MINOR << 8) | PATCH - */ -#define ET_VERSION_CODE \ - ((ET_VERSION_MAJOR << 16) | (ET_VERSION_MINOR << 8) | ET_VERSION_PATCH) - -/** - * Helper macro for version comparisons. - * Usage: #if ET_VERSION_CODE >= ET_VERSION_CHECK(1, 2, 0) - */ -#define ET_VERSION_CHECK(major, minor, patch) \ - (((major) << 16) | ((minor) << 8) | (patch)) diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.cpp b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.cpp deleted file mode 100644 index 448edc6..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include - -#include -#include -#include - -#include - -namespace executorch { -namespace runtime { - -ET_NODISCARD Error -validate_tensor(const executorch_flatbuffer::Tensor* tensor) { - if (tensor == nullptr) { - ET_LOG(Error, "Tensor is null"); - return Error::InvalidProgram; - } - - const auto* sizes = tensor->sizes(); - if (sizes == nullptr) { - ET_LOG(Error, "Tensor has null sizes"); - return Error::InvalidProgram; - } - - ssize_t numel = 1; - bool numel_overflowed = false; - for (flatbuffers::uoffset_t i = 0; i < sizes->size(); i++) { - int32_t size = sizes->Get(i); - - if (size < 0) { - ET_LOG( - Error, - "Size must be non-negative, got %d at dimension %u", - size, - static_cast(i)); - return Error::InvalidProgram; - } - - if (!numel_overflowed) { - numel_overflowed = - c10::mul_overflows(numel, static_cast(size), &numel); - } - } - - auto scalar_type = - static_cast(tensor->scalar_type()); - if (!executorch::runtime::isValid(scalar_type)) { - ET_LOG(Error, "Invalid ScalarType %d", static_cast(scalar_type)); - return Error::InvalidProgram; - } - - if (numel_overflowed) { - return Error::InvalidProgram; - } - - size_t nbytes; - bool nbytes_overflow = c10::mul_overflows( - static_cast(numel), - executorch::runtime::elementSize(scalar_type), - &nbytes); - if (nbytes_overflow) { - return Error::InvalidProgram; - } - - return Error::Ok; -} - -ET_NODISCARD Error -validate_program(const executorch_flatbuffer::Program* program) { - if (program == nullptr) { - ET_LOG(Error, "Program is null"); - return Error::InvalidProgram; - } - - // Validate all execution plans. - const auto* execution_plans = program->execution_plan(); - if (execution_plans == nullptr) { - ET_LOG(Error, "Program has null execution_plan"); - return Error::InvalidProgram; - } - - for (flatbuffers::uoffset_t plan_idx = 0; plan_idx < execution_plans->size(); - plan_idx++) { - const auto* plan = execution_plans->Get(plan_idx); - if (plan == nullptr) { - ET_LOG( - Error, "Execution plan %u is null", static_cast(plan_idx)); - return Error::InvalidProgram; - } - - // Validate all values in the plan. - const auto* values = plan->values(); - if (values == nullptr) { - ET_LOG( - Error, - "Execution plan %u has null values table", - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - const auto* inputs = plan->inputs(); - auto is_dynamic_input = [&](flatbuffers::uoffset_t idx) -> bool { - if (inputs == nullptr) { - return false; - } - for (flatbuffers::uoffset_t i = 0; i < inputs->size(); i++) { - if (inputs->Get(i) == static_cast(idx)) { - const auto* value = values->Get(idx); - if (value == nullptr) { - return false; - } - const auto* tensor = - static_cast(value->val()); - return tensor != nullptr && - tensor->shape_dynamism() != - executorch_flatbuffer::TensorShapeDynamism::STATIC; - } - } - return false; - }; - - for (flatbuffers::uoffset_t value_idx = 0; value_idx < values->size(); - value_idx++) { - const auto* value = values->Get(value_idx); - if (value == nullptr) { - continue; - } - - // Check if this value is a tensor. - if (value->val_type() == executorch_flatbuffer::KernelTypes::Tensor) { - const auto* tensor = - static_cast(value->val()); - - Error err = validate_tensor(tensor); - if (err != Error::Ok) { - // Dynamic input tensors may have upper-bound sizes serialized for - // 64-bit machines that would overflow on 32-bit. Since their actual - // sizes are provided at set_input time, we defer overflow checks - // for those to Method::set_input. - if (is_dynamic_input(value_idx)) { - ET_LOG( - Info, - "Skipping validation failure for dynamic input tensor " - "at value %u in execution plan %u", - static_cast(value_idx), - static_cast(plan_idx)); - } else { - ET_LOG( - Error, - "Tensor validation failed for value %u in execution plan %u", - static_cast(value_idx), - static_cast(plan_idx)); - return err; - } - } - } - - // Check if this value is a TensorList. - if (value->val_type() == executorch_flatbuffer::KernelTypes::TensorList) { - const auto* tensor_list = - static_cast(value->val()); - - if (tensor_list == nullptr) { - ET_LOG( - Error, - "TensorList is null for value %u in execution plan %u", - static_cast(value_idx), - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - const auto* items = tensor_list->items(); - if (items == nullptr) { - ET_LOG(Error, "TensorList items is null"); - return Error::InvalidProgram; - } - - // Validate that each item index points to a Tensor evalue. - for (flatbuffers::uoffset_t item_idx = 0; item_idx < items->size(); - item_idx++) { - int32_t evalue_index = items->Get(item_idx); - - // Check bounds. - if (evalue_index < 0 || - static_cast(evalue_index) >= - values->size()) { - ET_LOG( - Error, - "TensorList item %u has out-of-bounds index %d (values size " - "%u) in execution plan %u", - static_cast(item_idx), - evalue_index, - static_cast(values->size()), - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - // Check that the referenced evalue is actually a Tensor. - const auto* referenced_value = values->Get(evalue_index); - if (referenced_value == nullptr) { - ET_LOG( - Error, - "TensorList item %u references null evalue at index %d in " - "execution plan %u", - static_cast(item_idx), - evalue_index, - static_cast(plan_idx)); - return Error::InvalidProgram; - } - - if (referenced_value->val_type() != - executorch_flatbuffer::KernelTypes::Tensor) { - ET_LOG( - Error, - "TensorList item %u references non-Tensor evalue (type %d) at " - "index %d in execution plan %u", - static_cast(item_idx), - static_cast(referenced_value->val_type()), - evalue_index, - static_cast(plan_idx)); - return Error::InvalidProgram; - } - } - } - } - } - - return Error::Ok; -} - -} // namespace runtime -} // namespace executorch diff --git a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.h b/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.h deleted file mode 100644 index 68e4ff7..0000000 --- a/packs/PyTorch.ExecuTorch.1.3.1-rc8/src/runtime/executor/program_validation.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -// Forward declare flatbuffer types. -namespace executorch_flatbuffer { -struct ExecutionPlan; -struct Program; -struct Tensor; -struct TensorList; -} // namespace executorch_flatbuffer - -namespace executorch { -namespace runtime { - -/** - * Validates that a tensor's metadata is semantically valid: sizes are - * non-negative, scalar type is valid, and computing numel/nbytes will not - * overflow. - * - * @param[in] tensor The flatbuffer Tensor to validate. - * @return Error::Ok if validation passes, Error::InvalidProgram otherwise. - */ -ET_NODISCARD Error validate_tensor(const executorch_flatbuffer::Tensor* tensor); - -/** - * Performs validation of all tensors and lists in the program, checking that - * their metadata is semantically valid and will not cause issues during - * execution. - * - * Currently validates: - * - Tensor numel overflow (all tensors) - * - TensorList element types (all TensorLists) - * - * @param[in] program The flatbuffer Program to validate. - * @return Error::Ok if validation passes, Error::InvalidProgram if any - * validation check fails. - */ -ET_NODISCARD Error -validate_program(const executorch_flatbuffer::Program* program); - -} // namespace runtime -} // namespace executorch